d3d11-shaderprocessor.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /******************************************************************************
  2. Copyright (C) 2023 by Lain 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[] = {"POSITION", "NORMAL", "COLOR", "TANGENT", "TEXCOORD", "VERTEXID"};
  19. static const char *semanticOutputNames[] = {"SV_Position", "NORMAL", "COLOR", "TANGENT", "TEXCOORD", "VERTEXID"};
  20. static const char *ConvertSemanticName(const char *name)
  21. {
  22. const size_t num = sizeof(semanticInputNames) / sizeof(const char *);
  23. for (size_t i = 0; i < num; i++) {
  24. if (strcmp(name, semanticInputNames[i]) == 0)
  25. return semanticOutputNames[i];
  26. }
  27. throw "Unknown Semantic Name";
  28. }
  29. static void GetSemanticInfo(shader_var *var, const char *&name, uint32_t &index)
  30. {
  31. const char *mapping = var->mapping;
  32. const char *indexStr = mapping;
  33. while (*indexStr && !isdigit(*indexStr))
  34. indexStr++;
  35. index = (*indexStr) ? strtol(indexStr, NULL, 10) : 0;
  36. string nameStr;
  37. nameStr.assign(mapping, indexStr - mapping);
  38. name = ConvertSemanticName(nameStr.c_str());
  39. }
  40. static void AddInputLayoutVar(shader_var *var, vector<D3D11_INPUT_ELEMENT_DESC> &layout)
  41. {
  42. D3D11_INPUT_ELEMENT_DESC ied;
  43. const char *semanticName;
  44. uint32_t semanticIndex;
  45. GetSemanticInfo(var, semanticName, semanticIndex);
  46. memset(&ied, 0, sizeof(ied));
  47. ied.SemanticName = semanticName;
  48. ied.SemanticIndex = semanticIndex;
  49. ied.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
  50. if (strcmp(var->mapping, "COLOR") == 0) {
  51. ied.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
  52. } else if (strcmp(var->mapping, "POSITION") == 0 || strcmp(var->mapping, "NORMAL") == 0 ||
  53. strcmp(var->mapping, "TANGENT") == 0) {
  54. ied.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
  55. } else if (astrcmp_n(var->mapping, "TEXCOORD", 8) == 0) {
  56. /* type is always a 'float' type */
  57. switch (var->type[5]) {
  58. case 0:
  59. ied.Format = DXGI_FORMAT_R32_FLOAT;
  60. break;
  61. case '2':
  62. ied.Format = DXGI_FORMAT_R32G32_FLOAT;
  63. break;
  64. case '3':
  65. case '4':
  66. ied.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
  67. break;
  68. }
  69. }
  70. layout.push_back(ied);
  71. }
  72. static inline bool SetSlot(vector<D3D11_INPUT_ELEMENT_DESC> &layout, const char *name, uint32_t index,
  73. uint32_t &slotIdx)
  74. {
  75. for (size_t i = 0; i < layout.size(); i++) {
  76. D3D11_INPUT_ELEMENT_DESC &input = layout[i];
  77. if (input.SemanticIndex == index && 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, vector<D3D11_INPUT_ELEMENT_DESC> &layout)
  85. {
  86. shader_var *array = (shader_var *)vars->array;
  87. for (size_t i = 0; i < vars->num; i++) {
  88. shader_var *var = array + i;
  89. if (var->mapping) {
  90. if (strcmp(var->mapping, "VERTEXID") != 0)
  91. AddInputLayoutVar(var, layout);
  92. } else {
  93. shader_struct *st = shader_parser_getstruct(parser, var->type);
  94. if (st)
  95. BuildInputLayoutFromVars(parser, &st->vars.da, layout);
  96. }
  97. }
  98. /*
  99. * Sets the input slot value for each semantic, however we do it in
  100. * a specific order so that it will always match the vertex buffer's
  101. * sub-buffer order (points-> normals-> colors-> tangents-> uvcoords)
  102. */
  103. uint32_t slot = 0;
  104. SetSlot(layout, "SV_Position", 0, slot);
  105. SetSlot(layout, "NORMAL", 0, slot);
  106. SetSlot(layout, "COLOR", 0, slot);
  107. SetSlot(layout, "TANGENT", 0, slot);
  108. uint32_t index = 0;
  109. while (SetSlot(layout, "TEXCOORD", index++, slot))
  110. ;
  111. }
  112. void ShaderProcessor::BuildInputLayout(vector<D3D11_INPUT_ELEMENT_DESC> &layout)
  113. {
  114. shader_func *func = shader_parser_getfunc(&parser, "main");
  115. if (!func)
  116. throw "Failed to find 'main' shader function";
  117. BuildInputLayoutFromVars(&parser, &func->params.da, layout);
  118. }
  119. gs_shader_param::gs_shader_param(shader_var &var, uint32_t &texCounter)
  120. : name(var.name),
  121. type(get_shader_param_type(var.type)),
  122. textureID(texCounter),
  123. arrayCount(var.array_count),
  124. changed(false)
  125. {
  126. defaultValue.resize(var.default_val.num);
  127. memcpy(defaultValue.data(), var.default_val.array, var.default_val.num);
  128. if (type == GS_SHADER_PARAM_TEXTURE)
  129. texCounter++;
  130. else
  131. textureID = 0;
  132. }
  133. static inline void AddParam(shader_var &var, vector<gs_shader_param> &params, uint32_t &texCounter)
  134. {
  135. if (var.var_type != SHADER_VAR_UNIFORM || strcmp(var.type, "sampler") == 0)
  136. return;
  137. params.push_back(gs_shader_param(var, texCounter));
  138. }
  139. void ShaderProcessor::BuildParams(vector<gs_shader_param> &params)
  140. {
  141. uint32_t texCounter = 0;
  142. for (size_t i = 0; i < parser.params.num; i++)
  143. AddParam(parser.params.array[i], params, texCounter);
  144. }
  145. static inline void AddSampler(gs_device_t *device, shader_sampler &sampler, vector<unique_ptr<ShaderSampler>> &samplers)
  146. {
  147. gs_sampler_info si;
  148. shader_sampler_convert(&sampler, &si);
  149. samplers.emplace_back(new ShaderSampler(sampler.name, device, &si));
  150. }
  151. void ShaderProcessor::BuildSamplers(vector<unique_ptr<ShaderSampler>> &samplers)
  152. {
  153. for (size_t i = 0; i < parser.samplers.num; i++)
  154. AddSampler(device, parser.samplers.array[i], samplers);
  155. }
  156. void ShaderProcessor::BuildString(string &outputString)
  157. {
  158. stringstream output;
  159. output << "static const bool obs_glsl_compile = false;\n\n";
  160. cf_token *token = cf_preprocessor_get_tokens(&parser.cfp.pp);
  161. while (token->type != CFTOKEN_NONE) {
  162. /* cheaply just replace specific tokens */
  163. if (strref_cmp(&token->str, "POSITION") == 0)
  164. output << "SV_Position";
  165. else if (strref_cmp(&token->str, "TARGET") == 0)
  166. output << "SV_Target";
  167. else if (strref_cmp(&token->str, "texture2d") == 0)
  168. output << "Texture2D";
  169. else if (strref_cmp(&token->str, "texture3d") == 0)
  170. output << "Texture3D";
  171. else if (strref_cmp(&token->str, "texture_cube") == 0)
  172. output << "TextureCube";
  173. else if (strref_cmp(&token->str, "texture_rect") == 0)
  174. throw "texture_rect is not supported in D3D";
  175. else if (strref_cmp(&token->str, "sampler_state") == 0)
  176. output << "SamplerState";
  177. else if (strref_cmp(&token->str, "VERTEXID") == 0)
  178. output << "SV_VertexID";
  179. else
  180. output.write(token->str.array, token->str.len);
  181. token++;
  182. }
  183. outputString = move(output.str());
  184. }
  185. void ShaderProcessor::Process(const char *shader_string, const char *file)
  186. {
  187. bool success = shader_parse(&parser, shader_string, file);
  188. char *str = shader_parser_geterrors(&parser);
  189. if (str) {
  190. blog(LOG_WARNING, "Shader parser errors/warnings:\n%s\n", str);
  191. bfree(str);
  192. }
  193. if (!success)
  194. throw "Failed to parse shader";
  195. }