emit_context.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  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. u32 CbufIndex(size_t offset) {
  11. return (offset / 4) % 4;
  12. }
  13. char Swizzle(size_t offset) {
  14. return "xyzw"[CbufIndex(offset)];
  15. }
  16. std::string_view InterpDecorator(Interpolation interp) {
  17. switch (interp) {
  18. case Interpolation::Smooth:
  19. return "";
  20. case Interpolation::Flat:
  21. return "flat ";
  22. case Interpolation::NoPerspective:
  23. return "noperspective ";
  24. }
  25. throw InvalidArgument("Invalid interpolation {}", interp);
  26. }
  27. std::string_view InputArrayDecorator(Stage stage) {
  28. switch (stage) {
  29. case Stage::Geometry:
  30. case Stage::TessellationControl:
  31. case Stage::TessellationEval:
  32. return "[]";
  33. default:
  34. return "";
  35. }
  36. }
  37. bool StoresPerVertexAttributes(Stage stage) {
  38. switch (stage) {
  39. case Stage::VertexA:
  40. case Stage::VertexB:
  41. case Stage::Geometry:
  42. case Stage::TessellationEval:
  43. return true;
  44. default:
  45. return false;
  46. }
  47. }
  48. std::string OutputDecorator(Stage stage, u32 size) {
  49. switch (stage) {
  50. case Stage::TessellationControl:
  51. return fmt::format("[{}]", size);
  52. default:
  53. return "";
  54. }
  55. }
  56. std::string_view SamplerType(TextureType type, bool is_depth) {
  57. if (is_depth) {
  58. switch (type) {
  59. case TextureType::Color1D:
  60. return "sampler1DShadow";
  61. case TextureType::ColorArray1D:
  62. return "sampler1DArrayShadow";
  63. case TextureType::Color2D:
  64. return "sampler2DShadow";
  65. case TextureType::ColorArray2D:
  66. return "sampler2DArrayShadow";
  67. case TextureType::ColorCube:
  68. return "samplerCubeShadow";
  69. case TextureType::ColorArrayCube:
  70. return "samplerCubeArrayShadow";
  71. default:
  72. throw NotImplementedException("Texture type: {}", type);
  73. }
  74. }
  75. switch (type) {
  76. case TextureType::Color1D:
  77. return "sampler1D";
  78. case TextureType::ColorArray1D:
  79. return "sampler1DArray";
  80. case TextureType::Color2D:
  81. return "sampler2D";
  82. case TextureType::ColorArray2D:
  83. return "sampler2DArray";
  84. case TextureType::Color3D:
  85. return "sampler3D";
  86. case TextureType::ColorCube:
  87. return "samplerCube";
  88. case TextureType::ColorArrayCube:
  89. return "samplerCubeArray";
  90. case TextureType::Buffer:
  91. return "samplerBuffer";
  92. default:
  93. throw NotImplementedException("Texture type: {}", type);
  94. }
  95. }
  96. std::string_view ImageType(TextureType type) {
  97. switch (type) {
  98. case TextureType::Color1D:
  99. return "uimage1D";
  100. case TextureType::ColorArray1D:
  101. return "uimage1DArray";
  102. case TextureType::Color2D:
  103. return "uimage2D";
  104. case TextureType::ColorArray2D:
  105. return "uimage2DArray";
  106. case TextureType::Color3D:
  107. return "uimage3D";
  108. case TextureType::ColorCube:
  109. return "uimageCube";
  110. case TextureType::ColorArrayCube:
  111. return "uimageCubeArray";
  112. case TextureType::Buffer:
  113. return "uimageBuffer";
  114. default:
  115. throw NotImplementedException("Image type: {}", type);
  116. }
  117. }
  118. std::string_view ImageFormatString(ImageFormat format) {
  119. switch (format) {
  120. case ImageFormat::Typeless:
  121. return "";
  122. case ImageFormat::R8_UINT:
  123. return ",r8ui";
  124. case ImageFormat::R8_SINT:
  125. return ",r8i";
  126. case ImageFormat::R16_UINT:
  127. return ",r16ui";
  128. case ImageFormat::R16_SINT:
  129. return ",r16i";
  130. case ImageFormat::R32_UINT:
  131. return ",r32ui";
  132. case ImageFormat::R32G32_UINT:
  133. return ",rg32ui";
  134. case ImageFormat::R32G32B32A32_UINT:
  135. return ",rgba32ui";
  136. default:
  137. throw NotImplementedException("Image format: {}", format);
  138. }
  139. }
  140. std::string_view GetTessMode(TessPrimitive primitive) {
  141. switch (primitive) {
  142. case TessPrimitive::Triangles:
  143. return "triangles";
  144. case TessPrimitive::Quads:
  145. return "quads";
  146. case TessPrimitive::Isolines:
  147. return "isolines";
  148. }
  149. throw InvalidArgument("Invalid tessellation primitive {}", primitive);
  150. }
  151. std::string_view GetTessSpacing(TessSpacing spacing) {
  152. switch (spacing) {
  153. case TessSpacing::Equal:
  154. return "equal_spacing";
  155. case TessSpacing::FractionalOdd:
  156. return "fractional_odd_spacing";
  157. case TessSpacing::FractionalEven:
  158. return "fractional_even_spacing";
  159. }
  160. throw InvalidArgument("Invalid tessellation spacing {}", spacing);
  161. }
  162. std::string_view InputPrimitive(InputTopology topology) {
  163. switch (topology) {
  164. case InputTopology::Points:
  165. return "points";
  166. case InputTopology::Lines:
  167. return "lines";
  168. case InputTopology::LinesAdjacency:
  169. return "lines_adjacency";
  170. case InputTopology::Triangles:
  171. return "triangles";
  172. case InputTopology::TrianglesAdjacency:
  173. return "triangles_adjacency";
  174. }
  175. throw InvalidArgument("Invalid input topology {}", topology);
  176. }
  177. std::string_view OutputPrimitive(OutputTopology topology) {
  178. switch (topology) {
  179. case OutputTopology::PointList:
  180. return "points";
  181. case OutputTopology::LineStrip:
  182. return "line_strip";
  183. case OutputTopology::TriangleStrip:
  184. return "triangle_strip";
  185. }
  186. throw InvalidArgument("Invalid output topology {}", topology);
  187. }
  188. void SetupLegacyOutPerVertex(EmitContext& ctx, std::string& header) {
  189. if (!ctx.info.stores_legacy_varyings) {
  190. return;
  191. }
  192. if (ctx.info.stores_fixed_fnc_textures) {
  193. header += "vec4 gl_TexCoord[8];";
  194. }
  195. if (ctx.info.stores_color_front_diffuse) {
  196. header += "vec4 gl_FrontColor;";
  197. }
  198. if (ctx.info.stores_color_front_specular) {
  199. header += "vec4 gl_FrontSecondaryColor;";
  200. }
  201. if (ctx.info.stores_color_back_diffuse) {
  202. header += "vec4 gl_BackColor;";
  203. }
  204. if (ctx.info.stores_color_back_specular) {
  205. header += "vec4 gl_BackSecondaryColor;";
  206. }
  207. }
  208. void SetupOutPerVertex(EmitContext& ctx, std::string& header) {
  209. if (!StoresPerVertexAttributes(ctx.stage)) {
  210. return;
  211. }
  212. header += "out gl_PerVertex{vec4 gl_Position;";
  213. if (ctx.info.stores_point_size) {
  214. header += "float gl_PointSize;";
  215. }
  216. if (ctx.info.stores_clip_distance) {
  217. header += "float gl_ClipDistance[];";
  218. }
  219. if (ctx.info.stores_viewport_index && ctx.profile.support_viewport_index_layer_non_geometry &&
  220. ctx.stage != Stage::Geometry) {
  221. header += "int gl_ViewportIndex;";
  222. }
  223. SetupLegacyOutPerVertex(ctx, header);
  224. header += "};";
  225. if (ctx.info.stores_viewport_index && ctx.stage == Stage::Geometry) {
  226. header += "out int gl_ViewportIndex;";
  227. }
  228. }
  229. void SetupLegacyInPerFragment(EmitContext& ctx, std::string& header) {
  230. if (!ctx.info.loads_legacy_varyings) {
  231. return;
  232. }
  233. header += "in gl_PerFragment{";
  234. if (ctx.info.loads_fixed_fnc_textures) {
  235. header += "vec4 gl_TexCoord[8];";
  236. }
  237. if (ctx.info.loads_color_front_diffuse) {
  238. header += "vec4 gl_Color;";
  239. }
  240. header += "};";
  241. }
  242. } // Anonymous namespace
  243. EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
  244. const RuntimeInfo& runtime_info_)
  245. : info{program.info}, profile{profile_}, runtime_info{runtime_info_} {
  246. header += "#pragma optionNV(fastmath off)\n";
  247. SetupExtensions();
  248. stage = program.stage;
  249. switch (program.stage) {
  250. case Stage::VertexA:
  251. case Stage::VertexB:
  252. stage_name = "vs";
  253. break;
  254. case Stage::TessellationControl:
  255. stage_name = "tcs";
  256. header += fmt::format("layout(vertices={})out;", program.invocations);
  257. break;
  258. case Stage::TessellationEval:
  259. stage_name = "tes";
  260. header += fmt::format("layout({},{},{})in;", GetTessMode(runtime_info.tess_primitive),
  261. GetTessSpacing(runtime_info.tess_spacing),
  262. runtime_info.tess_clockwise ? "cw" : "ccw");
  263. break;
  264. case Stage::Geometry:
  265. stage_name = "gs";
  266. header += fmt::format("layout({})in;layout({},max_vertices={})out;"
  267. "in gl_PerVertex{{vec4 gl_Position;}}gl_in[];",
  268. InputPrimitive(runtime_info.input_topology),
  269. OutputPrimitive(program.output_topology), program.output_vertices);
  270. break;
  271. case Stage::Fragment:
  272. stage_name = "fs";
  273. position_name = "gl_FragCoord";
  274. if (runtime_info.force_early_z) {
  275. header += "layout(early_fragment_tests)in;";
  276. }
  277. if (info.uses_sample_id) {
  278. header += "in int gl_SampleID;";
  279. }
  280. if (info.stores_sample_mask) {
  281. header += "out int gl_SampleMask[];";
  282. }
  283. break;
  284. case Stage::Compute:
  285. stage_name = "cs";
  286. header += fmt::format("layout(local_size_x={},local_size_y={},local_size_z={}) in;",
  287. program.workgroup_size[0], program.workgroup_size[1],
  288. program.workgroup_size[2]);
  289. break;
  290. }
  291. SetupOutPerVertex(*this, header);
  292. SetupLegacyInPerFragment(*this, header);
  293. for (size_t index = 0; index < info.input_generics.size(); ++index) {
  294. const auto& generic{info.input_generics[index]};
  295. if (generic.used) {
  296. header += fmt::format("layout(location={}){}in vec4 in_attr{}{};", index,
  297. InterpDecorator(generic.interpolation), index,
  298. InputArrayDecorator(stage));
  299. }
  300. }
  301. for (size_t index = 0; index < info.uses_patches.size(); ++index) {
  302. if (!info.uses_patches[index]) {
  303. continue;
  304. }
  305. const auto qualifier{stage == Stage::TessellationControl ? "out" : "in"};
  306. header += fmt::format("layout(location={})patch {} vec4 patch{};", index, qualifier, index);
  307. }
  308. for (size_t index = 0; index < info.stores_frag_color.size(); ++index) {
  309. if (!info.stores_frag_color[index]) {
  310. continue;
  311. }
  312. header += fmt::format("layout(location={})out vec4 frag_color{};", index, index);
  313. }
  314. for (size_t index = 0; index < info.stores_generics.size(); ++index) {
  315. // TODO: Properly resolve attribute issues
  316. if (info.stores_generics[index] || stage == Stage::VertexA || stage == Stage::VertexB) {
  317. DefineGenericOutput(index, program.invocations);
  318. }
  319. }
  320. DefineConstantBuffers(bindings);
  321. DefineStorageBuffers(bindings);
  322. SetupImages(bindings);
  323. SetupTextures(bindings);
  324. DefineHelperFunctions();
  325. DefineConstants();
  326. }
  327. void EmitContext::SetupExtensions() {
  328. if (profile.support_gl_texture_shadow_lod) {
  329. header += "#extension GL_EXT_texture_shadow_lod : enable\n";
  330. }
  331. if (info.uses_int64) {
  332. header += "#extension GL_ARB_gpu_shader_int64 : enable\n";
  333. }
  334. if (info.uses_int64_bit_atomics) {
  335. header += "#extension GL_NV_shader_atomic_int64 : enable\n";
  336. }
  337. if (info.uses_atomic_f32_add) {
  338. header += "#extension GL_NV_shader_atomic_float : enable\n";
  339. }
  340. if (info.uses_atomic_f16x2_add || info.uses_atomic_f16x2_min || info.uses_atomic_f16x2_max) {
  341. header += "#extension NV_shader_atomic_fp16_vector : enable\n";
  342. }
  343. if (info.uses_fp16) {
  344. if (profile.support_gl_nv_gpu_shader_5) {
  345. header += "#extension GL_NV_gpu_shader5 : enable\n";
  346. }
  347. if (profile.support_gl_amd_gpu_shader_half_float) {
  348. header += "#extension GL_AMD_gpu_shader_half_float : enable\n";
  349. }
  350. }
  351. if (info.uses_subgroup_invocation_id || info.uses_subgroup_mask || info.uses_subgroup_vote ||
  352. info.uses_subgroup_shuffles || info.uses_fswzadd) {
  353. header += "#extension GL_ARB_shader_ballot : enable\n"
  354. "#extension GL_ARB_shader_group_vote : enable\n";
  355. if (!info.uses_int64) {
  356. header += "#extension GL_ARB_gpu_shader_int64 : enable\n";
  357. }
  358. if (profile.support_gl_warp_intrinsics) {
  359. header += "#extension GL_NV_shader_thread_shuffle : enable\n";
  360. }
  361. }
  362. if ((info.stores_viewport_index || info.stores_layer) &&
  363. profile.support_viewport_index_layer_non_geometry && stage != Stage::Geometry) {
  364. header += "#extension GL_ARB_shader_viewport_layer_array : enable\n";
  365. }
  366. if (info.uses_sparse_residency && profile.support_gl_sparse_textures) {
  367. header += "#extension GL_ARB_sparse_texture2 : enable\n";
  368. }
  369. if (info.stores_viewport_mask && profile.support_viewport_mask) {
  370. header += "#extension GL_NV_viewport_array2 : enable\n";
  371. }
  372. if (info.uses_typeless_image_reads || info.uses_typeless_image_writes) {
  373. header += "#extension GL_EXT_shader_image_load_formatted : enable\n";
  374. }
  375. }
  376. void EmitContext::DefineConstantBuffers(Bindings& bindings) {
  377. if (info.constant_buffer_descriptors.empty()) {
  378. return;
  379. }
  380. for (const auto& desc : info.constant_buffer_descriptors) {
  381. header += fmt::format(
  382. "layout(std140,binding={}) uniform {}_cbuf_{}{{vec4 {}_cbuf{}[{}];}};",
  383. bindings.uniform_buffer, stage_name, desc.index, stage_name, desc.index, 4 * 1024);
  384. bindings.uniform_buffer += desc.count;
  385. }
  386. }
  387. void EmitContext::DefineStorageBuffers(Bindings& bindings) {
  388. if (info.storage_buffers_descriptors.empty()) {
  389. return;
  390. }
  391. u32 index{};
  392. for (const auto& desc : info.storage_buffers_descriptors) {
  393. header += fmt::format("layout(std430,binding={}) buffer {}_ssbo_{}{{uint {}_ssbo{}[];}};",
  394. bindings.storage_buffer, stage_name, bindings.storage_buffer,
  395. stage_name, index);
  396. bindings.storage_buffer += desc.count;
  397. index += desc.count;
  398. }
  399. }
  400. void EmitContext::DefineGenericOutput(size_t index, u32 invocations) {
  401. static constexpr std::string_view swizzle{"xyzw"};
  402. const size_t base_index{static_cast<size_t>(IR::Attribute::Generic0X) + index * 4};
  403. u32 element{0};
  404. while (element < 4) {
  405. std::string definition{fmt::format("layout(location={}", index)};
  406. const u32 remainder{4 - element};
  407. const TransformFeedbackVarying* xfb_varying{};
  408. if (!runtime_info.xfb_varyings.empty()) {
  409. xfb_varying = &runtime_info.xfb_varyings[base_index + element];
  410. xfb_varying = xfb_varying && xfb_varying->components > 0 ? xfb_varying : nullptr;
  411. }
  412. const u32 num_components{xfb_varying ? xfb_varying->components : remainder};
  413. if (element > 0) {
  414. definition += fmt::format(",component={}", element);
  415. }
  416. if (xfb_varying) {
  417. definition +=
  418. fmt::format(",xfb_buffer={},xfb_stride={},xfb_offset={}", xfb_varying->buffer,
  419. xfb_varying->stride, xfb_varying->offset);
  420. }
  421. std::string name{fmt::format("out_attr{}", index)};
  422. if (num_components < 4 || element > 0) {
  423. name += fmt::format("_{}", swizzle.substr(element, num_components));
  424. }
  425. const auto type{num_components == 1 ? "float" : fmt::format("vec{}", num_components)};
  426. definition += fmt::format(")out {} {}{};", type, name, OutputDecorator(stage, invocations));
  427. header += definition;
  428. const GenericElementInfo element_info{
  429. .name = name,
  430. .first_element = element,
  431. .num_components = num_components,
  432. };
  433. std::fill_n(output_generics[index].begin() + element, num_components, element_info);
  434. element += num_components;
  435. }
  436. }
  437. void EmitContext::DefineHelperFunctions() {
  438. header += "\n#define ftoi floatBitsToInt\n#define ftou floatBitsToUint\n"
  439. "#define itof intBitsToFloat\n#define utof uintBitsToFloat\n";
  440. if (info.uses_global_increment || info.uses_shared_increment) {
  441. header += "uint CasIncrement(uint op_a,uint op_b){return op_a>=op_b?0u:(op_a+1u);}";
  442. }
  443. if (info.uses_global_decrement || info.uses_shared_decrement) {
  444. header += "uint CasDecrement(uint op_a,uint op_b){"
  445. "return op_a==0||op_a>op_b?op_b:(op_a-1u);}";
  446. }
  447. if (info.uses_atomic_f32_add) {
  448. header += "uint CasFloatAdd(uint op_a,float op_b){"
  449. "return ftou(utof(op_a)+op_b);}";
  450. }
  451. if (info.uses_atomic_f32x2_add) {
  452. header += "uint CasFloatAdd32x2(uint op_a,vec2 op_b){"
  453. "return packHalf2x16(unpackHalf2x16(op_a)+op_b);}";
  454. }
  455. if (info.uses_atomic_f32x2_min) {
  456. header += "uint CasFloatMin32x2(uint op_a,vec2 op_b){return "
  457. "packHalf2x16(min(unpackHalf2x16(op_a),op_b));}";
  458. }
  459. if (info.uses_atomic_f32x2_max) {
  460. header += "uint CasFloatMax32x2(uint op_a,vec2 op_b){return "
  461. "packHalf2x16(max(unpackHalf2x16(op_a),op_b));}";
  462. }
  463. if (info.uses_atomic_f16x2_add) {
  464. header += "uint CasFloatAdd16x2(uint op_a,f16vec2 op_b){return "
  465. "packFloat2x16(unpackFloat2x16(op_a)+op_b);}";
  466. }
  467. if (info.uses_atomic_f16x2_min) {
  468. header += "uint CasFloatMin16x2(uint op_a,f16vec2 op_b){return "
  469. "packFloat2x16(min(unpackFloat2x16(op_a),op_b));}";
  470. }
  471. if (info.uses_atomic_f16x2_max) {
  472. header += "uint CasFloatMax16x2(uint op_a,f16vec2 op_b){return "
  473. "packFloat2x16(max(unpackFloat2x16(op_a),op_b));}";
  474. }
  475. if (info.uses_atomic_s32_min) {
  476. header += "uint CasMinS32(uint op_a,uint op_b){return uint(min(int(op_a),int(op_b)));}";
  477. }
  478. if (info.uses_atomic_s32_max) {
  479. header += "uint CasMaxS32(uint op_a,uint op_b){return uint(max(int(op_a),int(op_b)));}";
  480. }
  481. if (info.uses_global_memory) {
  482. header += DefineGlobalMemoryFunctions();
  483. }
  484. if (info.loads_indexed_attributes) {
  485. const bool is_array{stage == Stage::Geometry};
  486. const auto vertex_arg{is_array ? ",uint vertex" : ""};
  487. std::string func{
  488. fmt::format("float IndexedAttrLoad(int offset{}){{int base_index=offset>>2;uint "
  489. "masked_index=uint(base_index)&3u;switch(base_index>>2){{",
  490. vertex_arg)};
  491. if (info.loads_position) {
  492. const auto position_idx{is_array ? "gl_in[vertex]." : ""};
  493. func += fmt::format("case {}:return {}{}[masked_index];",
  494. static_cast<u32>(IR::Attribute::PositionX) >> 2, position_idx,
  495. position_name);
  496. }
  497. const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2;
  498. for (u32 i = 0; i < info.input_generics.size(); ++i) {
  499. if (!info.input_generics[i].used) {
  500. continue;
  501. }
  502. const auto vertex_idx{is_array ? "[vertex]" : ""};
  503. func += fmt::format("case {}:return in_attr{}{}[masked_index];",
  504. base_attribute_value + i, i, vertex_idx);
  505. }
  506. func += "default: return 0.0;}}";
  507. header += func;
  508. }
  509. if (info.stores_indexed_attributes) {
  510. // TODO
  511. }
  512. }
  513. std::string EmitContext::DefineGlobalMemoryFunctions() {
  514. const auto define_body{[&](std::string& func, size_t index, std::string_view return_statement) {
  515. const auto& ssbo{info.storage_buffers_descriptors[index]};
  516. const u32 size_cbuf_offset{ssbo.cbuf_offset + 8};
  517. const auto ssbo_addr{fmt::format("ssbo_addr{}", index)};
  518. const auto cbuf{fmt::format("{}_cbuf{}", stage_name, ssbo.cbuf_index)};
  519. std::array<std::string, 2> addr_xy;
  520. std::array<std::string, 2> size_xy;
  521. for (size_t i = 0; i < addr_xy.size(); ++i) {
  522. const auto addr_loc{ssbo.cbuf_offset + 4 * i};
  523. const auto size_loc{size_cbuf_offset + 4 * i};
  524. addr_xy[i] = fmt::format("ftou({}[{}].{})", cbuf, addr_loc / 16, Swizzle(addr_loc));
  525. size_xy[i] = fmt::format("ftou({}[{}].{})", cbuf, size_loc / 16, Swizzle(size_loc));
  526. }
  527. const auto addr_pack{fmt::format("packUint2x32(uvec2({},{}))", addr_xy[0], addr_xy[1])};
  528. const auto addr_statment{fmt::format("uint64_t {}={};", ssbo_addr, addr_pack)};
  529. func += addr_statment;
  530. const auto size_vec{fmt::format("uvec2({},{})", size_xy[0], size_xy[1])};
  531. const auto comp_lhs{fmt::format("(addr>={})", ssbo_addr)};
  532. const auto comp_rhs{fmt::format("(addr<({}+uint64_t({})))", ssbo_addr, size_vec)};
  533. const auto comparison{fmt::format("if({}&&{}){{", comp_lhs, comp_rhs)};
  534. func += comparison;
  535. const auto ssbo_name{fmt::format("{}_ssbo{}", stage_name, index)};
  536. func += fmt::format(return_statement, ssbo_name, ssbo_addr);
  537. }};
  538. std::string write_func{"void WriteGlobal32(uint64_t addr,uint data){"};
  539. std::string write_func_64{"void WriteGlobal64(uint64_t addr,uvec2 data){"};
  540. std::string write_func_128{"void WriteGlobal128(uint64_t addr,uvec4 data){"};
  541. std::string load_func{"uint LoadGlobal32(uint64_t addr){"};
  542. std::string load_func_64{"uvec2 LoadGlobal64(uint64_t addr){"};
  543. std::string load_func_128{"uvec4 LoadGlobal128(uint64_t addr){"};
  544. const size_t num_buffers{info.storage_buffers_descriptors.size()};
  545. for (size_t index = 0; index < num_buffers; ++index) {
  546. if (!info.nvn_buffer_used[index]) {
  547. continue;
  548. }
  549. define_body(write_func, index, "{0}[uint(addr-{1})>>2]=data;return;}}");
  550. define_body(write_func_64, index,
  551. "{0}[uint(addr-{1})>>2]=data.x;{0}[uint(addr-{1}+4)>>2]=data.y;return;}}");
  552. define_body(write_func_128, index,
  553. "{0}[uint(addr-{1})>>2]=data.x;{0}[uint(addr-{1}+4)>>2]=data.y;{0}[uint("
  554. "addr-{1}+8)>>2]=data.z;{0}[uint(addr-{1}+12)>>2]=data.w;return;}}");
  555. define_body(load_func, index, "return {0}[uint(addr-{1})>>2];}}");
  556. define_body(load_func_64, index,
  557. "return uvec2({0}[uint(addr-{1})>>2],{0}[uint(addr-{1}+4)>>2]);}}");
  558. define_body(load_func_128, index,
  559. "return uvec4({0}[uint(addr-{1})>>2],{0}[uint(addr-{1}+4)>>2],{0}["
  560. "uint(addr-{1}+8)>>2],{0}[uint(addr-{1}+12)>>2]);}}");
  561. }
  562. write_func += "}";
  563. write_func_64 += "}";
  564. write_func_128 += "}";
  565. load_func += "return 0u;}";
  566. load_func_64 += "return uvec2(0);}";
  567. load_func_128 += "return uvec4(0);}";
  568. return write_func + write_func_64 + write_func_128 + load_func + load_func_64 + load_func_128;
  569. }
  570. void EmitContext::SetupImages(Bindings& bindings) {
  571. image_buffers.reserve(info.image_buffer_descriptors.size());
  572. for (const auto& desc : info.image_buffer_descriptors) {
  573. image_buffers.push_back({bindings.image, desc.count});
  574. const auto format{ImageFormatString(desc.format)};
  575. const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""};
  576. header += fmt::format("layout(binding={}{}) uniform uimageBuffer img{}{};", bindings.image,
  577. format, bindings.image, array_decorator);
  578. bindings.image += desc.count;
  579. }
  580. images.reserve(info.image_descriptors.size());
  581. for (const auto& desc : info.image_descriptors) {
  582. images.push_back({bindings.image, desc.count});
  583. const auto format{ImageFormatString(desc.format)};
  584. const auto image_type{ImageType(desc.type)};
  585. const auto qualifier{desc.is_written ? "" : "readonly "};
  586. const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""};
  587. header += fmt::format("layout(binding={}{})uniform {}{} img{}{};", bindings.image, format,
  588. qualifier, image_type, bindings.image, array_decorator);
  589. bindings.image += desc.count;
  590. }
  591. }
  592. void EmitContext::SetupTextures(Bindings& bindings) {
  593. texture_buffers.reserve(info.texture_buffer_descriptors.size());
  594. for (const auto& desc : info.texture_buffer_descriptors) {
  595. texture_buffers.push_back({bindings.texture, desc.count});
  596. const auto sampler_type{SamplerType(TextureType::Buffer, false)};
  597. const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""};
  598. header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture,
  599. sampler_type, bindings.texture, array_decorator);
  600. bindings.texture += desc.count;
  601. }
  602. textures.reserve(info.texture_descriptors.size());
  603. for (const auto& desc : info.texture_descriptors) {
  604. textures.push_back({bindings.texture, desc.count});
  605. const auto sampler_type{SamplerType(desc.type, desc.is_depth)};
  606. const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""};
  607. header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture,
  608. sampler_type, bindings.texture, array_decorator);
  609. bindings.texture += desc.count;
  610. }
  611. }
  612. void EmitContext::DefineConstants() {
  613. if (info.uses_fswzadd) {
  614. header += "const float FSWZ_A[]=float[4](-1.f,1.f,-1.f,0.f);"
  615. "const float FSWZ_B[]=float[4](-1.f,-1.f,1.f,-1.f);";
  616. }
  617. }
  618. } // namespace Shader::Backend::GLSL