1
0

d3d11-shaderprocessor.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /******************************************************************************
  2. Copyright (C) 2013 by Hugh Bailey <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #include "d3d11-subsystem.hpp"
  15. #include "d3d11-shaderprocessor.hpp"
  16. #include <sstream>
  17. using namespace std;
  18. static const char *semanticInputNames[] =
  19. {"POSITION", "NORMAL", "COLOR", "TANGENT", "TEXCOORD"};
  20. static const char *semanticOutputNames[] =
  21. {"SV_Position", "NORMAL", "COLOR", "TANGENT", "TEXCOORD"};
  22. static const char *ConvertSemanticName(const char *name)
  23. {
  24. const size_t num = sizeof(semanticInputNames) / sizeof(const char*);
  25. for (size_t i = 0; i < num; i++) {
  26. if (strcmp(name, semanticInputNames[i]) == 0)
  27. return semanticOutputNames[i];
  28. }
  29. throw "Unknown Semantic Name";
  30. }
  31. static void GetSemanticInfo(shader_var *var, const char *&name,
  32. uint32_t &index)
  33. {
  34. const char *mapping = var->mapping;
  35. const char *indexStr = mapping;
  36. while (*indexStr && !isdigit(*indexStr))
  37. indexStr++;
  38. index = (*indexStr) ? strtol(indexStr, NULL, 10) : 0;
  39. string nameStr;
  40. nameStr.assign(mapping, indexStr-mapping);
  41. name = ConvertSemanticName(nameStr.c_str());
  42. }
  43. static void AddInputLayoutVar(shader_var *var,
  44. vector<D3D11_INPUT_ELEMENT_DESC> &layout)
  45. {
  46. D3D11_INPUT_ELEMENT_DESC ied;
  47. const char *semanticName;
  48. uint32_t semanticIndex;
  49. GetSemanticInfo(var, semanticName, semanticIndex);
  50. memset(&ied, 0, sizeof(ied));
  51. ied.SemanticName = semanticName;
  52. ied.SemanticIndex = semanticIndex;
  53. ied.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
  54. if (strcmp(var->mapping, "COLOR") == 0) {
  55. ied.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
  56. } else if (strcmp(var->mapping, "POSITION") == 0 ||
  57. strcmp(var->mapping, "NORMAL") == 0 ||
  58. strcmp(var->mapping, "TANGENT") == 0) {
  59. ied.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
  60. } else if (astrcmp_n(var->mapping, "TEXCOORD", 8) == 0) {
  61. /* type is always a 'float' type */
  62. switch (var->type[5]) {
  63. case 0: ied.Format = DXGI_FORMAT_R32_FLOAT; break;
  64. case '2': ied.Format = DXGI_FORMAT_R32G32_FLOAT; break;
  65. case '3':
  66. case '4': ied.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; break;
  67. }
  68. }
  69. layout.push_back(ied);
  70. }
  71. static inline bool SetSlot(vector<D3D11_INPUT_ELEMENT_DESC> &layout,
  72. const char *name, uint32_t index, uint32_t &slotIdx)
  73. {
  74. for (size_t i = 0; i < layout.size(); i++) {
  75. D3D11_INPUT_ELEMENT_DESC &input = layout[i];
  76. if (input.SemanticIndex == index &&
  77. strcmpi(input.SemanticName, name) == 0) {
  78. layout[i].InputSlot = slotIdx++;
  79. return true;
  80. }
  81. }
  82. return false;
  83. }
  84. static void BuildInputLayoutFromVars(shader_parser *parser, darray *vars,
  85. vector<D3D11_INPUT_ELEMENT_DESC> &layout)
  86. {
  87. shader_var *array = (shader_var*)vars->array;
  88. for (size_t i = 0; i < vars->num; i++) {
  89. shader_var *var = array+i;
  90. if (var->mapping) {
  91. AddInputLayoutVar(var, layout);
  92. } else {
  93. shader_struct *st = shader_parser_getstruct(parser,
  94. var->type);
  95. if (st)
  96. BuildInputLayoutFromVars(parser, &st->vars.da,
  97. layout);
  98. }
  99. }
  100. /*
  101. * Sets the input slot value for each semantic, however we do it in
  102. * a specific order so that it will always match the vertex buffer's
  103. * sub-buffer order (points-> normals-> colors-> tangents-> uvcoords)
  104. */
  105. uint32_t slot = 0;
  106. SetSlot(layout, "SV_Position", 0, slot);
  107. SetSlot(layout, "NORMAL", 0, slot);
  108. SetSlot(layout, "COLOR", 0, slot);
  109. SetSlot(layout, "TANGENT", 0, slot);
  110. uint32_t index = 0;
  111. while (SetSlot(layout, "TEXCOORD", index++, slot));
  112. }
  113. void ShaderProcessor::BuildInputLayout(
  114. vector<D3D11_INPUT_ELEMENT_DESC> &layout)
  115. {
  116. shader_func *func = shader_parser_getfunc(&parser, "main");
  117. if (!func)
  118. throw "Failed to find 'main' shader function";
  119. BuildInputLayoutFromVars(&parser, &func->params.da, layout);
  120. }
  121. gs_shader_param::gs_shader_param(shader_var &var, uint32_t &texCounter)
  122. : name (var.name),
  123. type (get_shader_param_type(var.type)),
  124. textureID (texCounter),
  125. arrayCount (var.array_count),
  126. changed (false)
  127. {
  128. defaultValue.resize(var.default_val.num);
  129. memcpy(defaultValue.data(), var.default_val.array, var.default_val.num);
  130. if (type == GS_SHADER_PARAM_TEXTURE)
  131. texCounter++;
  132. else
  133. textureID = 0;
  134. }
  135. static inline void AddParam(shader_var &var, vector<gs_shader_param> &params,
  136. uint32_t &texCounter)
  137. {
  138. if (var.var_type != SHADER_VAR_UNIFORM ||
  139. strcmp(var.type, "sampler") == 0)
  140. return;
  141. params.push_back(gs_shader_param(var, texCounter));
  142. }
  143. void ShaderProcessor::BuildParams(vector<gs_shader_param> &params)
  144. {
  145. uint32_t texCounter = 0;
  146. for (size_t i = 0; i < parser.params.num; i++)
  147. AddParam(parser.params.array[i], params, texCounter);
  148. }
  149. static inline void AddSampler(gs_device_t *device, shader_sampler &sampler,
  150. vector<unique_ptr<ShaderSampler>> &samplers)
  151. {
  152. gs_sampler_info si;
  153. shader_sampler_convert(&sampler, &si);
  154. samplers.emplace_back(new ShaderSampler(sampler.name, device, &si));
  155. }
  156. void ShaderProcessor::BuildSamplers(vector<unique_ptr<ShaderSampler>> &samplers)
  157. {
  158. for (size_t i = 0; i < parser.samplers.num; i++)
  159. AddSampler(device, parser.samplers.array[i], samplers);
  160. }
  161. void ShaderProcessor::BuildString(string &outputString)
  162. {
  163. stringstream output;
  164. cf_token *token = cf_preprocessor_get_tokens(&parser.cfp.pp);
  165. while (token->type != CFTOKEN_NONE) {
  166. /* cheaply just replace specific tokens */
  167. if (strref_cmp(&token->str, "POSITION") == 0)
  168. output << "SV_Position";
  169. else if (strref_cmp(&token->str, "TARGET") == 0)
  170. output << "SV_Target";
  171. else if (strref_cmp(&token->str, "texture2d") == 0)
  172. output << "Texture2D";
  173. else if (strref_cmp(&token->str, "texture3d") == 0)
  174. output << "Texture3D";
  175. else if (strref_cmp(&token->str, "texture_cube") == 0)
  176. output << "TextureCube";
  177. else if (strref_cmp(&token->str, "texture_rect") == 0)
  178. throw "texture_rect is not supported in D3D";
  179. else if (strref_cmp(&token->str, "sampler_state") == 0)
  180. output << "SamplerState";
  181. else
  182. output.write(token->str.array, token->str.len);
  183. token++;
  184. }
  185. outputString = move(output.str());
  186. }
  187. void ShaderProcessor::Process(const char *shader_string, const char *file)
  188. {
  189. bool success = shader_parse(&parser, shader_string, file);
  190. char *str = shader_parser_geterrors(&parser);
  191. if (str) {
  192. blog(LOG_WARNING, "Shader parser errors/warnings:\n%s\n", str);
  193. bfree(str);
  194. }
  195. if (!success)
  196. throw "Failed to parse shader";
  197. }