emit_context.cpp 14 KB

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