emit_context.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "shader_recompiler/backend/bindings.h"
  5. #include "shader_recompiler/backend/glsl/emit_context.h"
  6. #include "shader_recompiler/frontend/ir/program.h"
  7. #include "shader_recompiler/profile.h"
  8. namespace Shader::Backend::GLSL {
  9. namespace {
  10. std::string_view InterpDecorator(Interpolation interp) {
  11. switch (interp) {
  12. case Interpolation::Smooth:
  13. return "";
  14. case Interpolation::Flat:
  15. return "flat";
  16. case Interpolation::NoPerspective:
  17. return "noperspective";
  18. }
  19. throw InvalidArgument("Invalid interpolation {}", interp);
  20. }
  21. std::string_view InputArrayDecorator(Stage stage) {
  22. switch (stage) {
  23. case Stage::Geometry:
  24. case Stage::TessellationControl:
  25. case Stage::TessellationEval:
  26. return "[]";
  27. default:
  28. return "";
  29. }
  30. }
  31. bool StoresPerVertexAttributes(Stage stage) {
  32. switch (stage) {
  33. case Stage::VertexA:
  34. case Stage::VertexB:
  35. case Stage::Geometry:
  36. case Stage::TessellationControl:
  37. case Stage::TessellationEval:
  38. return true;
  39. default:
  40. return false;
  41. }
  42. }
  43. std::string OutputDecorator(Stage stage, u32 size) {
  44. switch (stage) {
  45. case Stage::TessellationControl:
  46. return fmt::format("[{}]", size);
  47. default:
  48. return "";
  49. }
  50. }
  51. std::string_view SamplerType(TextureType type, bool is_depth) {
  52. if (is_depth) {
  53. switch (type) {
  54. case TextureType::Color1D:
  55. return "sampler1DShadow";
  56. case TextureType::ColorArray1D:
  57. return "sampler1DArrayShadow";
  58. case TextureType::Color2D:
  59. return "sampler2DShadow";
  60. case TextureType::ColorArray2D:
  61. return "sampler2DArrayShadow";
  62. case TextureType::ColorCube:
  63. return "samplerCubeShadow";
  64. case TextureType::ColorArrayCube:
  65. return "samplerCubeArrayShadow";
  66. default:
  67. fmt::print("Texture type: {}", type);
  68. throw NotImplementedException("Texture type: {}", type);
  69. }
  70. }
  71. switch (type) {
  72. case TextureType::Color1D:
  73. return "sampler1D";
  74. case TextureType::ColorArray1D:
  75. return "sampler1DArray";
  76. case TextureType::Color2D:
  77. return "sampler2D";
  78. case TextureType::ColorArray2D:
  79. return "sampler2DArray";
  80. case TextureType::Color3D:
  81. return "sampler3D";
  82. case TextureType::ColorCube:
  83. return "samplerCube";
  84. case TextureType::ColorArrayCube:
  85. return "samplerCubeArray";
  86. case TextureType::Buffer:
  87. return "samplerBuffer";
  88. default:
  89. fmt::print("Texture type: {}", type);
  90. throw NotImplementedException("Texture type: {}", type);
  91. }
  92. }
  93. std::string_view GetTessMode(TessPrimitive primitive) {
  94. switch (primitive) {
  95. case TessPrimitive::Triangles:
  96. return "triangles";
  97. case TessPrimitive::Quads:
  98. return "quads";
  99. case TessPrimitive::Isolines:
  100. return "isolines";
  101. }
  102. throw InvalidArgument("Invalid tessellation primitive {}", primitive);
  103. }
  104. std::string_view GetTessSpacing(TessSpacing spacing) {
  105. switch (spacing) {
  106. case TessSpacing::Equal:
  107. return "equal_spacing";
  108. case TessSpacing::FractionalOdd:
  109. return "fractional_odd_spacing";
  110. case TessSpacing::FractionalEven:
  111. return "fractional_even_spacing";
  112. }
  113. throw InvalidArgument("Invalid tessellation spacing {}", spacing);
  114. }
  115. std::string_view InputPrimitive(InputTopology topology) {
  116. switch (topology) {
  117. case InputTopology::Points:
  118. return "points";
  119. case InputTopology::Lines:
  120. return "lines";
  121. case InputTopology::LinesAdjacency:
  122. return "lines_adjacency";
  123. case InputTopology::Triangles:
  124. return "triangles";
  125. case InputTopology::TrianglesAdjacency:
  126. return "triangles_adjacency";
  127. }
  128. throw InvalidArgument("Invalid input topology {}", topology);
  129. }
  130. std::string_view OutputPrimitive(OutputTopology topology) {
  131. switch (topology) {
  132. case OutputTopology::PointList:
  133. return "points";
  134. case OutputTopology::LineStrip:
  135. return "line_strip";
  136. case OutputTopology::TriangleStrip:
  137. return "triangle_strip";
  138. }
  139. throw InvalidArgument("Invalid output topology {}", topology);
  140. }
  141. void SetupOutPerVertex(Stage stage, const Info& info, std::string& header) {
  142. if (!StoresPerVertexAttributes(stage)) {
  143. return;
  144. }
  145. header += "out gl_PerVertex{";
  146. if (info.stores_position) {
  147. header += "vec4 gl_Position;";
  148. }
  149. if (info.stores_point_size) {
  150. header += "float gl_PointSize;";
  151. }
  152. if (info.stores_clip_distance) {
  153. header += "float gl_ClipDistance[];";
  154. }
  155. if (info.stores_viewport_index && stage != Stage::Geometry) {
  156. header += "int gl_ViewportIndex;";
  157. }
  158. header += "};\n";
  159. if (info.stores_viewport_index && stage == Stage::Geometry) {
  160. header += "out int gl_ViewportIndex;";
  161. }
  162. }
  163. } // namespace
  164. EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
  165. const RuntimeInfo& runtime_info_)
  166. : info{program.info}, profile{profile_}, runtime_info{runtime_info_} {
  167. SetupExtensions(header);
  168. stage = program.stage;
  169. switch (program.stage) {
  170. case Stage::VertexA:
  171. case Stage::VertexB:
  172. stage_name = "vs";
  173. break;
  174. case Stage::TessellationControl:
  175. stage_name = "tsc";
  176. header += fmt::format("layout(vertices={})out;\n", program.invocations);
  177. break;
  178. case Stage::TessellationEval:
  179. stage_name = "tse";
  180. header += fmt::format("layout({},{},{})in;\n", GetTessMode(runtime_info.tess_primitive),
  181. GetTessSpacing(runtime_info.tess_spacing),
  182. runtime_info.tess_clockwise ? "cw" : "ccw");
  183. break;
  184. case Stage::Geometry:
  185. stage_name = "gs";
  186. header += fmt::format("layout({})in;layout({},max_vertices={})out;\n",
  187. InputPrimitive(runtime_info.input_topology),
  188. OutputPrimitive(program.output_topology), program.output_vertices);
  189. break;
  190. case Stage::Fragment:
  191. stage_name = "fs";
  192. break;
  193. case Stage::Compute:
  194. stage_name = "cs";
  195. header += fmt::format("layout(local_size_x={},local_size_y={},local_size_z={}) in;\n",
  196. program.workgroup_size[0], program.workgroup_size[1],
  197. program.workgroup_size[2]);
  198. break;
  199. }
  200. SetupOutPerVertex(stage, info, header);
  201. for (size_t index = 0; index < info.input_generics.size(); ++index) {
  202. const auto& generic{info.input_generics[index]};
  203. if (generic.used) {
  204. header += fmt::format("layout(location={}){} in vec4 in_attr{}{};", index,
  205. InterpDecorator(generic.interpolation), index,
  206. InputArrayDecorator(stage));
  207. }
  208. }
  209. for (size_t index = 0; index < info.uses_patches.size(); ++index) {
  210. if (!info.uses_patches[index]) {
  211. continue;
  212. }
  213. if (stage == Stage::TessellationControl) {
  214. header += fmt::format("layout(location={})patch out vec4 patch{};", index, index);
  215. } else {
  216. header += fmt::format("layout(location={})patch in vec4 patch{};", index, index);
  217. }
  218. }
  219. for (size_t index = 0; index < info.stores_frag_color.size(); ++index) {
  220. if (!info.stores_frag_color[index]) {
  221. continue;
  222. }
  223. header += fmt::format("layout(location={})out vec4 frag_color{};", index, index);
  224. }
  225. for (size_t index = 0; index < info.stores_generics.size(); ++index) {
  226. // TODO: Properly resolve attribute issues
  227. const auto declaration{fmt::format("layout(location={}) out vec4 out_attr{}{};", index,
  228. index, OutputDecorator(stage, program.invocations))};
  229. if (info.stores_generics[index] || stage == Stage::VertexA || stage == Stage::VertexB) {
  230. header += declaration;
  231. }
  232. }
  233. header += "\n";
  234. DefineConstantBuffers(bindings);
  235. DefineStorageBuffers(bindings);
  236. SetupImages(bindings);
  237. DefineHelperFunctions();
  238. }
  239. void EmitContext::SetupExtensions(std::string&) {
  240. // TODO: track this usage
  241. header += "#extension GL_ARB_sparse_texture2 : enable\n";
  242. header += "#extension GL_EXT_texture_shadow_lod : enable\n";
  243. if (info.uses_int64) {
  244. header += "#extension GL_ARB_gpu_shader_int64 : enable\n";
  245. }
  246. if (info.uses_int64_bit_atomics) {
  247. header += "#extension GL_NV_shader_atomic_int64 : enable\n";
  248. }
  249. if (info.uses_atomic_f32_add) {
  250. header += "#extension GL_NV_shader_atomic_float : enable\n";
  251. }
  252. if (info.uses_atomic_f16x2_add || info.uses_atomic_f16x2_min || info.uses_atomic_f16x2_max) {
  253. header += "#extension NV_shader_atomic_fp16_vector : enable\n";
  254. }
  255. if (info.uses_fp16) {
  256. if (profile.support_gl_nv_gpu_shader_5) {
  257. header += "#extension GL_NV_gpu_shader5 : enable\n";
  258. }
  259. if (profile.support_gl_amd_gpu_shader_half_float) {
  260. header += "#extension GL_AMD_gpu_shader_half_float : enable\n";
  261. }
  262. }
  263. if (info.uses_subgroup_invocation_id || info.uses_subgroup_mask || info.uses_subgroup_vote ||
  264. info.uses_subgroup_shuffles || info.uses_fswzadd) {
  265. header += "#extension GL_ARB_shader_ballot : enable\n";
  266. header += "#extension GL_ARB_shader_group_vote : enable\n";
  267. if (!info.uses_int64) {
  268. header += "#extension GL_ARB_gpu_shader_int64 : enable\n";
  269. }
  270. }
  271. if (info.stores_viewport_index && stage != Stage::Geometry) {
  272. header += "#extension GL_ARB_shader_viewport_layer_array : enable\n";
  273. }
  274. }
  275. void EmitContext::DefineConstantBuffers(Bindings& bindings) {
  276. if (info.constant_buffer_descriptors.empty()) {
  277. return;
  278. }
  279. for (const auto& desc : info.constant_buffer_descriptors) {
  280. header += fmt::format(
  281. "layout(std140,binding={}) uniform {}_cbuf_{}{{vec4 {}_cbuf{}[{}];}};",
  282. bindings.uniform_buffer, stage_name, desc.index, stage_name, desc.index, 4 * 1024);
  283. bindings.uniform_buffer += desc.count;
  284. }
  285. }
  286. void EmitContext::DefineStorageBuffers(Bindings& bindings) {
  287. if (info.storage_buffers_descriptors.empty()) {
  288. return;
  289. }
  290. u32 index{};
  291. for (const auto& desc : info.storage_buffers_descriptors) {
  292. header += fmt::format("layout(std430,binding={}) buffer {}_ssbo_{}{{uint {}_ssbo{}[];}};",
  293. bindings.storage_buffer, stage_name, bindings.storage_buffer,
  294. stage_name, index);
  295. bindings.storage_buffer += desc.count;
  296. index += desc.count;
  297. }
  298. }
  299. void EmitContext::DefineHelperFunctions() {
  300. if (info.uses_global_increment || info.uses_shared_increment) {
  301. header += "uint CasIncrement(uint op_a,uint op_b){return(op_a>=op_b)?0u:(op_a+1u);}\n";
  302. }
  303. if (info.uses_global_decrement || info.uses_shared_decrement) {
  304. header +=
  305. "uint CasDecrement(uint op_a,uint op_b){return(op_a==0||op_a>op_b)?op_b:(op_a-1u);}\n";
  306. }
  307. if (info.uses_atomic_f32_add) {
  308. header += "uint CasFloatAdd(uint op_a,float op_b){return "
  309. "floatBitsToUint(uintBitsToFloat(op_a)+op_b);}\n";
  310. }
  311. if (info.uses_atomic_f32x2_add) {
  312. header += "uint CasFloatAdd32x2(uint op_a,vec2 op_b){return "
  313. "packHalf2x16(unpackHalf2x16(op_a)+op_b);}\n";
  314. }
  315. if (info.uses_atomic_f32x2_min) {
  316. header += "uint CasFloatMin32x2(uint op_a,vec2 op_b){return "
  317. "packHalf2x16(min(unpackHalf2x16(op_a),op_b));}\n";
  318. }
  319. if (info.uses_atomic_f32x2_max) {
  320. header += "uint CasFloatMax32x2(uint op_a,vec2 op_b){return "
  321. "packHalf2x16(max(unpackHalf2x16(op_a),op_b));}\n";
  322. }
  323. if (info.uses_atomic_f16x2_add) {
  324. header += "uint CasFloatAdd16x2(uint op_a,f16vec2 op_b){return "
  325. "packFloat2x16(unpackFloat2x16(op_a)+op_b);}\n";
  326. }
  327. if (info.uses_atomic_f16x2_min) {
  328. header += "uint CasFloatMin16x2(uint op_a,f16vec2 op_b){return "
  329. "packFloat2x16(min(unpackFloat2x16(op_a),op_b));}\n";
  330. }
  331. if (info.uses_atomic_f16x2_max) {
  332. header += "uint CasFloatMax16x2(uint op_a,f16vec2 op_b){return "
  333. "packFloat2x16(max(unpackFloat2x16(op_a),op_b));}\n";
  334. }
  335. if (info.uses_atomic_s32_min) {
  336. header += "uint CasMinS32(uint op_a,uint op_b){return uint(min(int(op_a),int(op_b)));}";
  337. }
  338. if (info.uses_atomic_s32_max) {
  339. header += "uint CasMaxS32(uint op_a,uint op_b){return uint(max(int(op_a),int(op_b)));}";
  340. }
  341. }
  342. void EmitContext::SetupImages(Bindings& bindings) {
  343. image_buffer_bindings.reserve(info.image_buffer_descriptors.size());
  344. for (const auto& desc : info.image_buffer_descriptors) {
  345. throw NotImplementedException("image_buffer_descriptors");
  346. image_buffer_bindings.push_back(bindings.image);
  347. bindings.image += desc.count;
  348. }
  349. image_bindings.reserve(info.image_descriptors.size());
  350. for (const auto& desc : info.image_descriptors) {
  351. throw NotImplementedException("image_bindings");
  352. image_bindings.push_back(bindings.image);
  353. bindings.image += desc.count;
  354. }
  355. texture_buffer_bindings.reserve(info.texture_buffer_descriptors.size());
  356. for (const auto& desc : info.texture_buffer_descriptors) {
  357. texture_buffer_bindings.push_back(bindings.texture);
  358. const auto sampler_type{SamplerType(TextureType::Buffer, false)};
  359. const auto indices{bindings.texture + desc.count};
  360. for (u32 index = bindings.texture; index < indices; ++index) {
  361. header += fmt::format("layout(binding={}) uniform {} tex{};", bindings.texture,
  362. sampler_type, index);
  363. }
  364. bindings.texture += desc.count;
  365. }
  366. texture_bindings.reserve(info.texture_descriptors.size());
  367. for (const auto& desc : info.texture_descriptors) {
  368. const auto sampler_type{SamplerType(desc.type, desc.is_depth)};
  369. texture_bindings.push_back(bindings.texture);
  370. const auto indices{bindings.texture + desc.count};
  371. for (u32 index = bindings.texture; index < indices; ++index) {
  372. header += fmt::format("layout(binding={}) uniform {} tex{};", bindings.texture,
  373. sampler_type, index);
  374. }
  375. bindings.texture += desc.count;
  376. }
  377. }
  378. } // namespace Shader::Backend::GLSL