d3d11-shaderprocessor.cpp 7.1 KB

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