emit_context.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  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 SetupOutPerVertex(EmitContext& ctx, std::string& header) {
  189. if (!StoresPerVertexAttributes(ctx.stage)) {
  190. return;
  191. }
  192. header += "out gl_PerVertex{vec4 gl_Position;";
  193. if (ctx.info.stores_point_size) {
  194. header += "float gl_PointSize;";
  195. }
  196. if (ctx.info.stores_clip_distance) {
  197. header += "float gl_ClipDistance[];";
  198. }
  199. if (ctx.info.stores_viewport_index && ctx.profile.support_viewport_index_layer_non_geometry &&
  200. ctx.stage != Stage::Geometry) {
  201. header += "int gl_ViewportIndex;";
  202. }
  203. header += "};";
  204. if (ctx.info.stores_viewport_index && ctx.stage == Stage::Geometry) {
  205. header += "out int gl_ViewportIndex;";
  206. }
  207. }
  208. } // Anonymous namespace
  209. EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
  210. const RuntimeInfo& runtime_info_)
  211. : info{program.info}, profile{profile_}, runtime_info{runtime_info_} {
  212. header += "#pragma optionNV(fastmath off)\n";
  213. SetupExtensions(header);
  214. stage = program.stage;
  215. switch (program.stage) {
  216. case Stage::VertexA:
  217. case Stage::VertexB:
  218. stage_name = "vs";
  219. break;
  220. case Stage::TessellationControl:
  221. stage_name = "tcs";
  222. header += fmt::format("layout(vertices={})out;", program.invocations);
  223. break;
  224. case Stage::TessellationEval:
  225. stage_name = "tes";
  226. header += fmt::format("layout({},{},{})in;", GetTessMode(runtime_info.tess_primitive),
  227. GetTessSpacing(runtime_info.tess_spacing),
  228. runtime_info.tess_clockwise ? "cw" : "ccw");
  229. break;
  230. case Stage::Geometry:
  231. stage_name = "gs";
  232. header += fmt::format("layout({})in;layout({},max_vertices={})out;"
  233. "in gl_PerVertex{{vec4 gl_Position;}}gl_in[];",
  234. InputPrimitive(runtime_info.input_topology),
  235. OutputPrimitive(program.output_topology), program.output_vertices);
  236. break;
  237. case Stage::Fragment:
  238. stage_name = "fs";
  239. position_name = "gl_FragCoord";
  240. if (runtime_info.force_early_z) {
  241. header += "layout(early_fragment_tests)in;";
  242. }
  243. if (info.uses_sample_id) {
  244. header += "in int gl_SampleID;";
  245. }
  246. if (info.stores_sample_mask) {
  247. header += "out int gl_SampleMask[];";
  248. }
  249. break;
  250. case Stage::Compute:
  251. stage_name = "cs";
  252. header += fmt::format("layout(local_size_x={},local_size_y={},local_size_z={}) in;",
  253. program.workgroup_size[0], program.workgroup_size[1],
  254. program.workgroup_size[2]);
  255. break;
  256. }
  257. SetupOutPerVertex(*this, header);
  258. for (size_t index = 0; index < info.input_generics.size(); ++index) {
  259. const auto& generic{info.input_generics[index]};
  260. if (generic.used) {
  261. header += fmt::format("layout(location={}){}in vec4 in_attr{}{};", index,
  262. InterpDecorator(generic.interpolation), index,
  263. InputArrayDecorator(stage));
  264. }
  265. }
  266. for (size_t index = 0; index < info.uses_patches.size(); ++index) {
  267. if (!info.uses_patches[index]) {
  268. continue;
  269. }
  270. const auto qualifier{stage == Stage::TessellationControl ? "out" : "in"};
  271. header += fmt::format("layout(location={})patch {} vec4 patch{};", index, qualifier, index);
  272. }
  273. for (size_t index = 0; index < info.stores_frag_color.size(); ++index) {
  274. if (!info.stores_frag_color[index]) {
  275. continue;
  276. }
  277. header += fmt::format("layout(location={})out vec4 frag_color{};", index, index);
  278. }
  279. for (size_t index = 0; index < info.stores_generics.size(); ++index) {
  280. // TODO: Properly resolve attribute issues
  281. if (info.stores_generics[index] || stage == Stage::VertexA || stage == Stage::VertexB) {
  282. DefineGenericOutput(index, program.invocations);
  283. }
  284. }
  285. DefineConstantBuffers(bindings);
  286. DefineStorageBuffers(bindings);
  287. SetupImages(bindings);
  288. SetupTextures(bindings);
  289. DefineHelperFunctions();
  290. DefineConstants();
  291. }
  292. void EmitContext::SetupExtensions(std::string&) {
  293. if (profile.support_gl_texture_shadow_lod) {
  294. header += "#extension GL_EXT_texture_shadow_lod : enable\n";
  295. }
  296. if (info.uses_int64) {
  297. header += "#extension GL_ARB_gpu_shader_int64 : enable\n";
  298. }
  299. if (info.uses_int64_bit_atomics) {
  300. header += "#extension GL_NV_shader_atomic_int64 : enable\n";
  301. }
  302. if (info.uses_atomic_f32_add) {
  303. header += "#extension GL_NV_shader_atomic_float : enable\n";
  304. }
  305. if (info.uses_atomic_f16x2_add || info.uses_atomic_f16x2_min || info.uses_atomic_f16x2_max) {
  306. header += "#extension NV_shader_atomic_fp16_vector : enable\n";
  307. }
  308. if (info.uses_fp16) {
  309. if (profile.support_gl_nv_gpu_shader_5) {
  310. header += "#extension GL_NV_gpu_shader5 : enable\n";
  311. }
  312. if (profile.support_gl_amd_gpu_shader_half_float) {
  313. header += "#extension GL_AMD_gpu_shader_half_float : enable\n";
  314. }
  315. }
  316. if (info.uses_subgroup_invocation_id || info.uses_subgroup_mask || info.uses_subgroup_vote ||
  317. info.uses_subgroup_shuffles || info.uses_fswzadd) {
  318. header += "#extension GL_ARB_shader_ballot : enable\n"
  319. "#extension GL_ARB_shader_group_vote : enable\n";
  320. if (!info.uses_int64) {
  321. header += "#extension GL_ARB_gpu_shader_int64 : enable\n";
  322. }
  323. if (profile.support_gl_warp_intrinsics) {
  324. header += "#extension GL_NV_shader_thread_shuffle : enable\n";
  325. }
  326. }
  327. if ((info.stores_viewport_index || info.stores_layer) &&
  328. profile.support_viewport_index_layer_non_geometry && stage != Stage::Geometry) {
  329. header += "#extension GL_ARB_shader_viewport_layer_array : enable\n";
  330. }
  331. if (info.uses_sparse_residency) {
  332. header += "#extension GL_ARB_sparse_texture2 : enable\n";
  333. }
  334. if (info.stores_viewport_mask && profile.support_viewport_mask) {
  335. header += "#extension GL_NV_viewport_array2 : enable\n";
  336. }
  337. if (info.uses_typeless_image_reads || info.uses_typeless_image_writes) {
  338. header += "#extension GL_EXT_shader_image_load_formatted : enable\n";
  339. }
  340. }
  341. void EmitContext::DefineConstantBuffers(Bindings& bindings) {
  342. if (info.constant_buffer_descriptors.empty()) {
  343. return;
  344. }
  345. for (const auto& desc : info.constant_buffer_descriptors) {
  346. header += fmt::format(
  347. "layout(std140,binding={}) uniform {}_cbuf_{}{{vec4 {}_cbuf{}[{}];}};",
  348. bindings.uniform_buffer, stage_name, desc.index, stage_name, desc.index, 4 * 1024);
  349. bindings.uniform_buffer += desc.count;
  350. }
  351. }
  352. void EmitContext::DefineStorageBuffers(Bindings& bindings) {
  353. if (info.storage_buffers_descriptors.empty()) {
  354. return;
  355. }
  356. u32 index{};
  357. for (const auto& desc : info.storage_buffers_descriptors) {
  358. header += fmt::format("layout(std430,binding={}) buffer {}_ssbo_{}{{uint {}_ssbo{}[];}};",
  359. bindings.storage_buffer, stage_name, bindings.storage_buffer,
  360. stage_name, index);
  361. bindings.storage_buffer += desc.count;
  362. index += desc.count;
  363. }
  364. }
  365. void EmitContext::DefineGenericOutput(size_t index, u32 invocations) {
  366. static constexpr std::string_view swizzle{"xyzw"};
  367. const size_t base_index{static_cast<size_t>(IR::Attribute::Generic0X) + index * 4};
  368. u32 element{0};
  369. while (element < 4) {
  370. std::string definition{fmt::format("layout(location={}", index)};
  371. const u32 remainder{4 - element};
  372. const TransformFeedbackVarying* xfb_varying{};
  373. if (!runtime_info.xfb_varyings.empty()) {
  374. xfb_varying = &runtime_info.xfb_varyings[base_index + element];
  375. xfb_varying = xfb_varying && xfb_varying->components > 0 ? xfb_varying : nullptr;
  376. }
  377. const u32 num_components{xfb_varying ? xfb_varying->components : remainder};
  378. if (element > 0) {
  379. definition += fmt::format(",component={}", element);
  380. }
  381. if (xfb_varying) {
  382. definition +=
  383. fmt::format(",xfb_buffer={},xfb_stride={},xfb_offset={}", xfb_varying->buffer,
  384. xfb_varying->stride, xfb_varying->offset);
  385. }
  386. std::string name{fmt::format("out_attr{}", index)};
  387. if (num_components < 4 || element > 0) {
  388. name += fmt::format("_{}", swizzle.substr(element, num_components));
  389. }
  390. const auto type{num_components == 1 ? "float" : fmt::format("vec{}", num_components)};
  391. definition += fmt::format(")out {} {}{};", type, name, OutputDecorator(stage, invocations));
  392. header += definition;
  393. const GenericElementInfo element_info{
  394. .name = name,
  395. .first_element = element,
  396. .num_components = num_components,
  397. };
  398. std::fill_n(output_generics[index].begin() + element, num_components, element_info);
  399. element += num_components;
  400. }
  401. }
  402. void EmitContext::DefineHelperFunctions() {
  403. header += "\n#define ftoi floatBitsToInt\n#define ftou floatBitsToUint\n"
  404. "#define itof intBitsToFloat\n#define utof uintBitsToFloat\n";
  405. if (info.uses_global_increment || info.uses_shared_increment) {
  406. header += "uint CasIncrement(uint op_a,uint op_b){return op_a>=op_b?0u:(op_a+1u);}";
  407. }
  408. if (info.uses_global_decrement || info.uses_shared_decrement) {
  409. header += "uint CasDecrement(uint op_a,uint op_b){"
  410. "return op_a==0||op_a>op_b?op_b:(op_a-1u);}";
  411. }
  412. if (info.uses_atomic_f32_add) {
  413. header += "uint CasFloatAdd(uint op_a,float op_b){"
  414. "return ftou(utof(op_a)+op_b);}";
  415. }
  416. if (info.uses_atomic_f32x2_add) {
  417. header += "uint CasFloatAdd32x2(uint op_a,vec2 op_b){"
  418. "return packHalf2x16(unpackHalf2x16(op_a)+op_b);}";
  419. }
  420. if (info.uses_atomic_f32x2_min) {
  421. header += "uint CasFloatMin32x2(uint op_a,vec2 op_b){return "
  422. "packHalf2x16(min(unpackHalf2x16(op_a),op_b));}";
  423. }
  424. if (info.uses_atomic_f32x2_max) {
  425. header += "uint CasFloatMax32x2(uint op_a,vec2 op_b){return "
  426. "packHalf2x16(max(unpackHalf2x16(op_a),op_b));}";
  427. }
  428. if (info.uses_atomic_f16x2_add) {
  429. header += "uint CasFloatAdd16x2(uint op_a,f16vec2 op_b){return "
  430. "packFloat2x16(unpackFloat2x16(op_a)+op_b);}";
  431. }
  432. if (info.uses_atomic_f16x2_min) {
  433. header += "uint CasFloatMin16x2(uint op_a,f16vec2 op_b){return "
  434. "packFloat2x16(min(unpackFloat2x16(op_a),op_b));}";
  435. }
  436. if (info.uses_atomic_f16x2_max) {
  437. header += "uint CasFloatMax16x2(uint op_a,f16vec2 op_b){return "
  438. "packFloat2x16(max(unpackFloat2x16(op_a),op_b));}";
  439. }
  440. if (info.uses_atomic_s32_min) {
  441. header += "uint CasMinS32(uint op_a,uint op_b){return uint(min(int(op_a),int(op_b)));}";
  442. }
  443. if (info.uses_atomic_s32_max) {
  444. header += "uint CasMaxS32(uint op_a,uint op_b){return uint(max(int(op_a),int(op_b)));}";
  445. }
  446. if (info.uses_global_memory) {
  447. header += DefineGlobalMemoryFunctions();
  448. }
  449. if (info.loads_indexed_attributes) {
  450. const bool is_array{stage == Stage::Geometry};
  451. const auto vertex_arg{is_array ? ",uint vertex" : ""};
  452. std::string func{
  453. fmt::format("float IndexedAttrLoad(int offset{}){{int base_index=offset>>2;uint "
  454. "masked_index=uint(base_index)&3u;switch(base_index>>2){{",
  455. vertex_arg)};
  456. if (info.loads_position) {
  457. const auto position_idx{is_array ? "gl_in[vertex]." : ""};
  458. func += fmt::format("case {}:return {}{}[masked_index];",
  459. static_cast<u32>(IR::Attribute::PositionX) >> 2, position_idx,
  460. position_name);
  461. }
  462. const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2;
  463. for (u32 i = 0; i < info.input_generics.size(); ++i) {
  464. if (!info.input_generics[i].used) {
  465. continue;
  466. }
  467. const auto vertex_idx{is_array ? "[vertex]" : ""};
  468. func += fmt::format("case {}:return in_attr{}{}[masked_index];",
  469. base_attribute_value + i, i, vertex_idx);
  470. }
  471. func += "default: return 0.0;}}";
  472. header += func;
  473. }
  474. if (info.stores_indexed_attributes) {
  475. // TODO
  476. }
  477. }
  478. std::string EmitContext::DefineGlobalMemoryFunctions() {
  479. const auto define_body{[&](std::string& func, size_t index, std::string_view return_statement) {
  480. const auto& ssbo{info.storage_buffers_descriptors[index]};
  481. const u32 size_cbuf_offset{ssbo.cbuf_offset + 8};
  482. const auto ssbo_addr{fmt::format("ssbo_addr{}", index)};
  483. const auto cbuf{fmt::format("{}_cbuf{}", stage_name, ssbo.cbuf_index)};
  484. std::array<std::string, 2> addr_xy;
  485. std::array<std::string, 2> size_xy;
  486. for (size_t i = 0; i < addr_xy.size(); ++i) {
  487. const auto addr_loc{ssbo.cbuf_offset + 4 * i};
  488. const auto size_loc{size_cbuf_offset + 4 * i};
  489. addr_xy[i] = fmt::format("ftou({}[{}].{})", cbuf, addr_loc / 16, Swizzle(addr_loc));
  490. size_xy[i] = fmt::format("ftou({}[{}].{})", cbuf, size_loc / 16, Swizzle(size_loc));
  491. }
  492. const auto addr_pack{fmt::format("packUint2x32(uvec2({},{}))", addr_xy[0], addr_xy[1])};
  493. const auto addr_statment{fmt::format("uint64_t {}={};", ssbo_addr, addr_pack)};
  494. func += addr_statment;
  495. const auto size_vec{fmt::format("uvec2({},{})", size_xy[0], size_xy[1])};
  496. const auto comp_lhs{fmt::format("(addr>={})", ssbo_addr)};
  497. const auto comp_rhs{fmt::format("(addr<({}+uint64_t({})))", ssbo_addr, size_vec)};
  498. const auto comparison{fmt::format("if({}&&{}){{", comp_lhs, comp_rhs)};
  499. func += comparison;
  500. const auto ssbo_name{fmt::format("{}_ssbo{}", stage_name, index)};
  501. func += fmt::format(return_statement, ssbo_name, ssbo_addr);
  502. }};
  503. std::string write_func{"void WriteGlobal32(uint64_t addr,uint data){"};
  504. std::string write_func_64{"void WriteGlobal64(uint64_t addr,uvec2 data){"};
  505. std::string write_func_128{"void WriteGlobal128(uint64_t addr,uvec4 data){"};
  506. std::string load_func{"uint LoadGlobal32(uint64_t addr){"};
  507. std::string load_func_64{"uvec2 LoadGlobal64(uint64_t addr){"};
  508. std::string load_func_128{"uvec4 LoadGlobal128(uint64_t addr){"};
  509. const size_t num_buffers{info.storage_buffers_descriptors.size()};
  510. for (size_t index = 0; index < num_buffers; ++index) {
  511. if (!info.nvn_buffer_used[index]) {
  512. continue;
  513. }
  514. define_body(write_func, index, "{0}[uint(addr-{1})>>2]=data;return;}}");
  515. define_body(write_func_64, index,
  516. "{0}[uint(addr-{1})>>2]=data.x;{0}[uint(addr-{1}+4)>>2]=data.y;return;}}");
  517. define_body(write_func_128, index,
  518. "{0}[uint(addr-{1})>>2]=data.x;{0}[uint(addr-{1}+4)>>2]=data.y;{0}[uint("
  519. "addr-{1}+8)>>2]=data.z;{0}[uint(addr-{1}+12)>>2]=data.w;return;}}");
  520. define_body(load_func, index, "return {0}[uint(addr-{1})>>2];}}");
  521. define_body(load_func_64, index,
  522. "return uvec2({0}[uint(addr-{1})>>2],{0}[uint(addr-{1}+4)>>2]);}}");
  523. define_body(load_func_128, index,
  524. "return uvec4({0}[uint(addr-{1})>>2],{0}[uint(addr-{1}+4)>>2],{0}["
  525. "uint(addr-{1}+8)>>2],{0}[uint(addr-{1}+12)>>2]);}}");
  526. }
  527. write_func += "}";
  528. write_func_64 += "}";
  529. write_func_128 += "}";
  530. load_func += "return 0u;}";
  531. load_func_64 += "return uvec2(0);}";
  532. load_func_128 += "return uvec4(0);}";
  533. return write_func + write_func_64 + write_func_128 + load_func + load_func_64 + load_func_128;
  534. }
  535. void EmitContext::SetupImages(Bindings& bindings) {
  536. image_buffers.reserve(info.image_buffer_descriptors.size());
  537. for (const auto& desc : info.image_buffer_descriptors) {
  538. image_buffers.push_back({bindings.image, desc.count});
  539. const auto format{ImageFormatString(desc.format)};
  540. const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""};
  541. header += fmt::format("layout(binding={}{}) uniform uimageBuffer img{}{};", bindings.image,
  542. format, bindings.image, array_decorator);
  543. bindings.image += desc.count;
  544. }
  545. images.reserve(info.image_descriptors.size());
  546. for (const auto& desc : info.image_descriptors) {
  547. images.push_back({bindings.image, desc.count});
  548. const auto format{ImageFormatString(desc.format)};
  549. const auto image_type{ImageType(desc.type)};
  550. const auto qualifier{desc.is_written ? "" : "readonly "};
  551. const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""};
  552. header += fmt::format("layout(binding={}{})uniform {}{} img{}{};", bindings.image, format,
  553. qualifier, image_type, bindings.image, array_decorator);
  554. bindings.image += desc.count;
  555. }
  556. }
  557. void EmitContext::SetupTextures(Bindings& bindings) {
  558. texture_buffers.reserve(info.texture_buffer_descriptors.size());
  559. for (const auto& desc : info.texture_buffer_descriptors) {
  560. texture_buffers.push_back({bindings.texture, desc.count});
  561. const auto sampler_type{SamplerType(TextureType::Buffer, false)};
  562. const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""};
  563. header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture,
  564. sampler_type, bindings.texture, array_decorator);
  565. bindings.texture += desc.count;
  566. }
  567. textures.reserve(info.texture_descriptors.size());
  568. for (const auto& desc : info.texture_descriptors) {
  569. textures.push_back({bindings.texture, desc.count});
  570. const auto sampler_type{SamplerType(desc.type, desc.is_depth)};
  571. const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""};
  572. header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture,
  573. sampler_type, bindings.texture, array_decorator);
  574. bindings.texture += desc.count;
  575. }
  576. }
  577. void EmitContext::DefineConstants() {
  578. if (info.uses_fswzadd) {
  579. header += "const float FSWZ_A[]=float[4](-1.f,1.f,-1.f,0.f);"
  580. "const float FSWZ_B[]=float[4](-1.f,-1.f,1.f,-1.f);";
  581. }
  582. }
  583. } // namespace Shader::Backend::GLSL