d3d11-shaderprocessor.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  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", "VERTEXID"};
  20. static const char *semanticOutputNames[] =
  21. {"SV_Position", "NORMAL", "COLOR", "TANGENT", "TEXCOORD", "VERTEXID"};
  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. if (strcmp(var->mapping, "VERTEXID") != 0)
  92. AddInputLayoutVar(var, layout);
  93. } else {
  94. shader_struct *st = shader_parser_getstruct(parser,
  95. var->type);
  96. if (st)
  97. BuildInputLayoutFromVars(parser, &st->vars.da,
  98. layout);
  99. }
  100. }
  101. /*
  102. * Sets the input slot value for each semantic, however we do it in
  103. * a specific order so that it will always match the vertex buffer's
  104. * sub-buffer order (points-> normals-> colors-> tangents-> uvcoords)
  105. */
  106. uint32_t slot = 0;
  107. SetSlot(layout, "SV_Position", 0, slot);
  108. SetSlot(layout, "NORMAL", 0, slot);
  109. SetSlot(layout, "COLOR", 0, slot);
  110. SetSlot(layout, "TANGENT", 0, slot);
  111. uint32_t index = 0;
  112. while (SetSlot(layout, "TEXCOORD", index++, slot));
  113. }
  114. void ShaderProcessor::BuildInputLayout(
  115. vector<D3D11_INPUT_ELEMENT_DESC> &layout)
  116. {
  117. shader_func *func = shader_parser_getfunc(&parser, "main");
  118. if (!func)
  119. throw "Failed to find 'main' shader function";
  120. BuildInputLayoutFromVars(&parser, &func->params.da, layout);
  121. }
  122. gs_shader_param::gs_shader_param(shader_var &var, uint32_t &texCounter)
  123. : name (var.name),
  124. type (get_shader_param_type(var.type)),
  125. textureID (texCounter),
  126. arrayCount (var.array_count),
  127. changed (false)
  128. {
  129. defaultValue.resize(var.default_val.num);
  130. memcpy(defaultValue.data(), var.default_val.array, var.default_val.num);
  131. if (type == GS_SHADER_PARAM_TEXTURE)
  132. texCounter++;
  133. else
  134. textureID = 0;
  135. }
  136. static inline void AddParam(shader_var &var, vector<gs_shader_param> &params,
  137. uint32_t &texCounter)
  138. {
  139. if (var.var_type != SHADER_VAR_UNIFORM ||
  140. strcmp(var.type, "sampler") == 0)
  141. return;
  142. params.push_back(gs_shader_param(var, texCounter));
  143. }
  144. void ShaderProcessor::BuildParams(vector<gs_shader_param> &params)
  145. {
  146. uint32_t texCounter = 0;
  147. for (size_t i = 0; i < parser.params.num; i++)
  148. AddParam(parser.params.array[i], params, texCounter);
  149. }
  150. static inline void AddSampler(gs_device_t *device, shader_sampler &sampler,
  151. vector<unique_ptr<ShaderSampler>> &samplers)
  152. {
  153. gs_sampler_info si;
  154. shader_sampler_convert(&sampler, &si);
  155. samplers.emplace_back(new ShaderSampler(sampler.name, device, &si));
  156. }
  157. void ShaderProcessor::BuildSamplers(vector<unique_ptr<ShaderSampler>> &samplers)
  158. {
  159. for (size_t i = 0; i < parser.samplers.num; i++)
  160. AddSampler(device, parser.samplers.array[i], samplers);
  161. }
  162. void ShaderProcessor::BuildString(string &outputString)
  163. {
  164. stringstream output;
  165. output << "static const bool obs_glsl_compile = false;\n\n";
  166. cf_token *token = cf_preprocessor_get_tokens(&parser.cfp.pp);
  167. while (token->type != CFTOKEN_NONE) {
  168. /* cheaply just replace specific tokens */
  169. if (strref_cmp(&token->str, "POSITION") == 0)
  170. output << "SV_Position";
  171. else if (strref_cmp(&token->str, "TARGET") == 0)
  172. output << "SV_Target";
  173. else if (strref_cmp(&token->str, "texture2d") == 0)
  174. output << "Texture2D";
  175. else if (strref_cmp(&token->str, "texture3d") == 0)
  176. output << "Texture3D";
  177. else if (strref_cmp(&token->str, "texture_cube") == 0)
  178. output << "TextureCube";
  179. else if (strref_cmp(&token->str, "texture_rect") == 0)
  180. throw "texture_rect is not supported in D3D";
  181. else if (strref_cmp(&token->str, "sampler_state") == 0)
  182. output << "SamplerState";
  183. else if (strref_cmp(&token->str, "VERTEXID") == 0)
  184. output << "SV_VertexID";
  185. else
  186. output.write(token->str.array, token->str.len);
  187. token++;
  188. }
  189. outputString = move(output.str());
  190. }
  191. void ShaderProcessor::Process(const char *shader_string, const char *file)
  192. {
  193. bool success = shader_parse(&parser, shader_string, file);
  194. char *str = shader_parser_geterrors(&parser);
  195. if (str) {
  196. blog(LOG_WARNING, "Shader parser errors/warnings:\n%s\n", str);
  197. bfree(str);
  198. }
  199. if (!success)
  200. throw "Failed to parse shader";
  201. }