emit_glsl_context_get_set.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
  2. // SPDX-FileCopyrightText: 2024 sudachi Emulator Project
  3. // SPDX-License-Identifier: GPL-2.0-or-later
  4. #include <string_view>
  5. #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
  6. #include "shader_recompiler/backend/glsl/glsl_emit_context.h"
  7. #include "shader_recompiler/frontend/ir/value.h"
  8. #include "shader_recompiler/profile.h"
  9. #include "shader_recompiler/runtime_info.h"
  10. namespace Shader::Backend::GLSL {
  11. namespace {
  12. constexpr char SWIZZLE[]{"xyzw"};
  13. u32 CbufIndex(u32 offset) {
  14. return (offset / 4) % 4;
  15. }
  16. char OffsetSwizzle(u32 offset) {
  17. return SWIZZLE[CbufIndex(offset)];
  18. }
  19. bool IsInputArray(Stage stage) {
  20. return stage == Stage::Geometry || stage == Stage::TessellationControl ||
  21. stage == Stage::TessellationEval;
  22. }
  23. std::string InputVertexIndex(EmitContext& ctx, std::string_view vertex) {
  24. return IsInputArray(ctx.stage) ? fmt::format("[{}]", vertex) : "";
  25. }
  26. std::string_view OutputVertexIndex(EmitContext& ctx) {
  27. return ctx.stage == Stage::TessellationControl ? "[gl_InvocationID]" : "";
  28. }
  29. std::string ChooseCbuf(EmitContext& ctx, const IR::Value& binding, std::string_view index) {
  30. if (binding.IsImmediate()) {
  31. return fmt::format("{}_cbuf{}[{}]", ctx.stage_name, binding.U32(), index);
  32. } else {
  33. const auto binding_var{ctx.var_alloc.Consume(binding)};
  34. return fmt::format("GetCbufIndirect({},{})", binding_var, index);
  35. }
  36. }
  37. void GetCbuf(EmitContext& ctx, std::string_view ret, const IR::Value& binding,
  38. const IR::Value& offset, u32 num_bits, std::string_view cast = {},
  39. std::string_view bit_offset = {}) {
  40. const bool is_immediate{offset.IsImmediate()};
  41. const bool component_indexing_bug{!is_immediate && ctx.profile.has_gl_component_indexing_bug};
  42. if (is_immediate) {
  43. const s32 signed_offset{static_cast<s32>(offset.U32())};
  44. static constexpr u32 cbuf_size{0x10000};
  45. if (signed_offset < 0 || offset.U32() > cbuf_size) {
  46. LOG_WARNING(Shader_GLSL, "Immediate constant buffer offset is out of bounds");
  47. ctx.Add("{}=0u;", ret);
  48. return;
  49. }
  50. }
  51. const auto offset_var{ctx.var_alloc.Consume(offset)};
  52. const auto index{is_immediate ? fmt::format("{}", offset.U32() / 16)
  53. : fmt::format("{}>>4", offset_var)};
  54. const auto swizzle{is_immediate ? fmt::format(".{}", OffsetSwizzle(offset.U32()))
  55. : fmt::format("[({}>>2)%4]", offset_var)};
  56. const auto cbuf{ChooseCbuf(ctx, binding, index)};
  57. const auto cbuf_cast{fmt::format("{}({}{{}})", cast, cbuf)};
  58. const auto extraction{num_bits == 32 ? cbuf_cast
  59. : fmt::format("bitfieldExtract({},int({}),{})", cbuf_cast,
  60. bit_offset, num_bits)};
  61. if (!component_indexing_bug) {
  62. const auto result{fmt::format(fmt::runtime(extraction), swizzle)};
  63. ctx.Add("{}={};", ret, result);
  64. return;
  65. }
  66. const auto cbuf_offset{fmt::format("{}>>2", offset_var)};
  67. for (u32 i = 0; i < 4; ++i) {
  68. const auto swizzle_string{fmt::format(".{}", "xyzw"[i])};
  69. const auto result{fmt::format(fmt::runtime(extraction), swizzle_string)};
  70. ctx.Add("if(({}&3)=={}){}={};", cbuf_offset, i, ret, result);
  71. }
  72. }
  73. void GetCbuf8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, const IR::Value& offset,
  74. std::string_view cast) {
  75. const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)};
  76. if (offset.IsImmediate()) {
  77. const auto bit_offset{fmt::format("{}", (offset.U32() % 4) * 8)};
  78. GetCbuf(ctx, ret, binding, offset, 8, cast, bit_offset);
  79. } else {
  80. const auto offset_var{ctx.var_alloc.Consume(offset)};
  81. const auto bit_offset{fmt::format("({}%4)*8", offset_var)};
  82. GetCbuf(ctx, ret, binding, offset, 8, cast, bit_offset);
  83. }
  84. }
  85. void GetCbuf16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, const IR::Value& offset,
  86. std::string_view cast) {
  87. const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)};
  88. if (offset.IsImmediate()) {
  89. const auto bit_offset{fmt::format("{}", ((offset.U32() / 2) % 2) * 16)};
  90. GetCbuf(ctx, ret, binding, offset, 16, cast, bit_offset);
  91. } else {
  92. const auto offset_var{ctx.var_alloc.Consume(offset)};
  93. const auto bit_offset{fmt::format("(({}>>1)%2)*16", offset_var)};
  94. GetCbuf(ctx, ret, binding, offset, 16, cast, bit_offset);
  95. }
  96. }
  97. } // Anonymous namespace
  98. void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  99. const IR::Value& offset) {
  100. const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};
  101. GetCbuf8(ctx, inst, binding, offset, cast);
  102. }
  103. void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  104. const IR::Value& offset) {
  105. const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "int" : "ftoi"};
  106. GetCbuf8(ctx, inst, binding, offset, cast);
  107. }
  108. void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  109. const IR::Value& offset) {
  110. const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};
  111. GetCbuf16(ctx, inst, binding, offset, cast);
  112. }
  113. void EmitGetCbufS16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  114. const IR::Value& offset) {
  115. const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "int" : "ftoi"};
  116. GetCbuf16(ctx, inst, binding, offset, cast);
  117. }
  118. void EmitGetCbufU32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  119. const IR::Value& offset) {
  120. const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)};
  121. const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};
  122. GetCbuf(ctx, ret, binding, offset, 32, cast);
  123. }
  124. void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  125. const IR::Value& offset) {
  126. const auto ret{ctx.var_alloc.Define(inst, GlslVarType::F32)};
  127. const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "utof" : ""};
  128. GetCbuf(ctx, ret, binding, offset, 32, cast);
  129. }
  130. void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  131. const IR::Value& offset) {
  132. const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};
  133. if (offset.IsImmediate()) {
  134. const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())};
  135. static constexpr u32 cbuf_size{0x10000};
  136. const u32 u32_offset{offset.U32()};
  137. const s32 signed_offset{static_cast<s32>(offset.U32())};
  138. if (signed_offset < 0 || u32_offset > cbuf_size) {
  139. LOG_WARNING(Shader_GLSL, "Immediate constant buffer offset is out of bounds");
  140. ctx.AddU32x2("{}=uvec2(0u);", inst);
  141. return;
  142. }
  143. if (u32_offset % 2 == 0) {
  144. ctx.AddU32x2("{}={}({}[{}].{}{});", inst, cast, cbuf, u32_offset / 16,
  145. OffsetSwizzle(u32_offset), OffsetSwizzle(u32_offset + 4));
  146. } else {
  147. ctx.AddU32x2("{}=uvec2({}({}[{}].{}),{}({}[{}].{}));", inst, cast, cbuf,
  148. u32_offset / 16, OffsetSwizzle(u32_offset), cast, cbuf,
  149. (u32_offset + 4) / 16, OffsetSwizzle(u32_offset + 4));
  150. }
  151. return;
  152. }
  153. const auto offset_var{ctx.var_alloc.Consume(offset)};
  154. const auto cbuf{ChooseCbuf(ctx, binding, fmt::format("{}>>4", offset_var))};
  155. if (!ctx.profile.has_gl_component_indexing_bug) {
  156. ctx.AddU32x2("{}=uvec2({}({}[({}>>2)%4]),{}({}[(({}+4)>>2)%4]));", inst, cast, cbuf,
  157. offset_var, cast, cbuf, offset_var);
  158. return;
  159. }
  160. const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32x2)};
  161. const auto cbuf_offset{fmt::format("{}>>2", offset_var)};
  162. for (u32 swizzle = 0; swizzle < 4; ++swizzle) {
  163. ctx.Add("if(({}&3)=={}){}=uvec2({}({}.{}),{}({}.{}));", cbuf_offset, swizzle, ret, cast,
  164. cbuf, "xyzw"[swizzle], cast, cbuf, "xyzw"[(swizzle + 1) % 4]);
  165. }
  166. }
  167. void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
  168. std::string_view vertex) {
  169. const u32 element{static_cast<u32>(attr) % 4};
  170. const char swizzle{"xyzw"[element]};
  171. if (IR::IsGeneric(attr)) {
  172. const u32 index{IR::GenericAttributeIndex(attr)};
  173. if (!ctx.runtime_info.previous_stage_stores.Generic(index, element)) {
  174. if (element == 3) {
  175. ctx.AddF32("{}=1.f;", inst, attr);
  176. } else {
  177. ctx.AddF32("{}=0.f;", inst, attr);
  178. }
  179. return;
  180. }
  181. ctx.AddF32("{}=in_attr{}{}.{};", inst, index, InputVertexIndex(ctx, vertex), swizzle);
  182. return;
  183. }
  184. switch (attr) {
  185. case IR::Attribute::PrimitiveId:
  186. ctx.AddF32("{}=itof(gl_PrimitiveID);", inst);
  187. break;
  188. case IR::Attribute::Layer:
  189. ctx.AddF32("{}=itof(gl_Layer);", inst);
  190. break;
  191. case IR::Attribute::PositionX:
  192. case IR::Attribute::PositionY:
  193. case IR::Attribute::PositionZ:
  194. case IR::Attribute::PositionW: {
  195. const bool is_array{IsInputArray(ctx.stage)};
  196. const auto input_decorator{is_array ? fmt::format("gl_in[{}].", vertex) : ""};
  197. ctx.AddF32("{}={}{}.{};", inst, input_decorator, ctx.position_name, swizzle);
  198. break;
  199. }
  200. case IR::Attribute::PointSpriteS:
  201. case IR::Attribute::PointSpriteT:
  202. ctx.AddF32("{}=gl_PointCoord.{};", inst, swizzle);
  203. break;
  204. case IR::Attribute::TessellationEvaluationPointU:
  205. case IR::Attribute::TessellationEvaluationPointV:
  206. ctx.AddF32("{}=gl_TessCoord.{};", inst, swizzle);
  207. break;
  208. case IR::Attribute::InstanceId:
  209. ctx.AddF32("{}=itof(gl_InstanceID);", inst);
  210. break;
  211. case IR::Attribute::VertexId:
  212. ctx.AddF32("{}=itof(gl_VertexID);", inst);
  213. break;
  214. case IR::Attribute::FrontFace:
  215. ctx.AddF32("{}=itof(gl_FrontFacing?-1:0);", inst);
  216. break;
  217. case IR::Attribute::BaseInstance:
  218. ctx.AddF32("{}=itof(gl_BaseInstance);", inst);
  219. break;
  220. case IR::Attribute::BaseVertex:
  221. ctx.AddF32("{}=itof(gl_BaseVertex);", inst);
  222. break;
  223. case IR::Attribute::DrawID:
  224. ctx.AddF32("{}=itof(gl_DrawID);", inst);
  225. break;
  226. default:
  227. throw NotImplementedException("Get attribute {}", attr);
  228. }
  229. }
  230. void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, std::string_view) {
  231. switch (attr) {
  232. case IR::Attribute::PrimitiveId:
  233. ctx.AddU32("{}=uint(gl_PrimitiveID);", inst);
  234. break;
  235. case IR::Attribute::InstanceId:
  236. ctx.AddU32("{}=uint(gl_InstanceID);", inst);
  237. break;
  238. case IR::Attribute::VertexId:
  239. ctx.AddU32("{}=uint(gl_VertexID);", inst);
  240. break;
  241. case IR::Attribute::BaseInstance:
  242. ctx.AddU32("{}=uint(gl_BaseInstance);", inst);
  243. break;
  244. case IR::Attribute::BaseVertex:
  245. ctx.AddU32("{}=uint(gl_BaseVertex);", inst);
  246. break;
  247. case IR::Attribute::DrawID:
  248. ctx.AddU32("{}=uint(gl_DrawID);", inst);
  249. break;
  250. default:
  251. throw NotImplementedException("Get U32 attribute {}", attr);
  252. }
  253. }
  254. void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view value,
  255. [[maybe_unused]] std::string_view vertex) {
  256. if (IR::IsGeneric(attr)) {
  257. const u32 index{IR::GenericAttributeIndex(attr)};
  258. const u32 attr_element{IR::GenericAttributeElement(attr)};
  259. const GenericElementInfo& info{ctx.output_generics.at(index).at(attr_element)};
  260. const auto output_decorator{OutputVertexIndex(ctx)};
  261. if (info.num_components == 1) {
  262. ctx.Add("{}{}={};", info.name, output_decorator, value);
  263. } else {
  264. const u32 index_element{attr_element - info.first_element};
  265. ctx.Add("{}{}.{}={};", info.name, output_decorator, "xyzw"[index_element], value);
  266. }
  267. return;
  268. }
  269. const u32 element{static_cast<u32>(attr) % 4};
  270. const char swizzle{"xyzw"[element]};
  271. switch (attr) {
  272. case IR::Attribute::Layer:
  273. if (ctx.stage != Stage::Geometry &&
  274. !ctx.profile.support_viewport_index_layer_non_geometry) {
  275. LOG_WARNING(Shader_GLSL, "Shader stores viewport layer but device does not support "
  276. "viewport layer extension");
  277. break;
  278. }
  279. ctx.Add("gl_Layer=ftoi({});", value);
  280. break;
  281. case IR::Attribute::ViewportIndex:
  282. if (ctx.stage != Stage::Geometry &&
  283. !ctx.profile.support_viewport_index_layer_non_geometry) {
  284. LOG_WARNING(Shader_GLSL, "Shader stores viewport index but device does not support "
  285. "viewport layer extension");
  286. break;
  287. }
  288. ctx.Add("gl_ViewportIndex=ftoi({});", value);
  289. break;
  290. case IR::Attribute::ViewportMask:
  291. if (ctx.stage != Stage::Geometry && !ctx.profile.support_viewport_mask) {
  292. LOG_WARNING(
  293. Shader_GLSL,
  294. "Shader stores viewport mask but device does not support viewport mask extension");
  295. break;
  296. }
  297. ctx.Add("gl_ViewportMask[0]=ftoi({});", value);
  298. break;
  299. case IR::Attribute::PointSize:
  300. ctx.Add("gl_PointSize={};", value);
  301. break;
  302. case IR::Attribute::PositionX:
  303. case IR::Attribute::PositionY:
  304. case IR::Attribute::PositionZ:
  305. case IR::Attribute::PositionW:
  306. ctx.Add("gl_Position.{}={};", swizzle, value);
  307. break;
  308. case IR::Attribute::ClipDistance0:
  309. case IR::Attribute::ClipDistance1:
  310. case IR::Attribute::ClipDistance2:
  311. case IR::Attribute::ClipDistance3:
  312. case IR::Attribute::ClipDistance4:
  313. case IR::Attribute::ClipDistance5:
  314. case IR::Attribute::ClipDistance6:
  315. case IR::Attribute::ClipDistance7: {
  316. const u32 index{static_cast<u32>(attr) - static_cast<u32>(IR::Attribute::ClipDistance0)};
  317. ctx.Add("gl_ClipDistance[{}]={};", index, value);
  318. break;
  319. }
  320. default:
  321. throw NotImplementedException("Set attribute {}", attr);
  322. }
  323. }
  324. void EmitGetAttributeIndexed(EmitContext& ctx, IR::Inst& inst, std::string_view offset,
  325. std::string_view vertex) {
  326. const bool is_array{ctx.stage == Stage::Geometry};
  327. const auto vertex_arg{is_array ? fmt::format(",{}", vertex) : ""};
  328. ctx.AddF32("{}=IndexedAttrLoad(int({}){});", inst, offset, vertex_arg);
  329. }
  330. void EmitSetAttributeIndexed([[maybe_unused]] EmitContext& ctx,
  331. [[maybe_unused]] std::string_view offset,
  332. [[maybe_unused]] std::string_view value,
  333. [[maybe_unused]] std::string_view vertex) {
  334. NotImplemented();
  335. }
  336. void EmitGetPatch(EmitContext& ctx, IR::Inst& inst, IR::Patch patch) {
  337. if (!IR::IsGeneric(patch)) {
  338. throw NotImplementedException("Non-generic patch load");
  339. }
  340. const u32 index{IR::GenericPatchIndex(patch)};
  341. const u32 element{IR::GenericPatchElement(patch)};
  342. const char swizzle{"xyzw"[element]};
  343. ctx.AddF32("{}=patch{}.{};", inst, index, swizzle);
  344. }
  345. void EmitSetPatch(EmitContext& ctx, IR::Patch patch, std::string_view value) {
  346. if (IR::IsGeneric(patch)) {
  347. const u32 index{IR::GenericPatchIndex(patch)};
  348. const u32 element{IR::GenericPatchElement(patch)};
  349. ctx.Add("patch{}.{}={};", index, "xyzw"[element], value);
  350. return;
  351. }
  352. switch (patch) {
  353. case IR::Patch::TessellationLodLeft:
  354. case IR::Patch::TessellationLodRight:
  355. case IR::Patch::TessellationLodTop:
  356. case IR::Patch::TessellationLodBottom: {
  357. const u32 index{static_cast<u32>(patch) - u32(IR::Patch::TessellationLodLeft)};
  358. ctx.Add("gl_TessLevelOuter[{}]={};", index, value);
  359. break;
  360. }
  361. case IR::Patch::TessellationLodInteriorU:
  362. ctx.Add("gl_TessLevelInner[0]={};", value);
  363. break;
  364. case IR::Patch::TessellationLodInteriorV:
  365. ctx.Add("gl_TessLevelInner[1]={};", value);
  366. break;
  367. default:
  368. throw NotImplementedException("Patch {}", patch);
  369. }
  370. }
  371. void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, std::string_view value) {
  372. const char swizzle{"xyzw"[component]};
  373. ctx.Add("frag_color{}.{}={};", index, swizzle, value);
  374. }
  375. void EmitSetSampleMask(EmitContext& ctx, std::string_view value) {
  376. ctx.Add("gl_SampleMask[0]=int({});", value);
  377. }
  378. void EmitSetFragDepth(EmitContext& ctx, std::string_view value) {
  379. ctx.Add("gl_FragDepth={};", value);
  380. }
  381. void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst) {
  382. ctx.AddU32x3("{}=gl_LocalInvocationID;", inst);
  383. }
  384. void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst) {
  385. ctx.AddU32x3("{}=gl_WorkGroupID;", inst);
  386. }
  387. void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) {
  388. ctx.AddU32("{}=uint(gl_InvocationID);", inst);
  389. }
  390. void EmitInvocationInfo(EmitContext& ctx, IR::Inst& inst) {
  391. switch (ctx.stage) {
  392. case Stage::TessellationControl:
  393. case Stage::TessellationEval:
  394. ctx.AddU32("{}=uint(gl_PatchVerticesIn)<<16;", inst);
  395. break;
  396. case Stage::Geometry:
  397. ctx.AddU32("{}=uint({}<<16);", inst,
  398. InputTopologyVertices::vertices(ctx.runtime_info.input_topology));
  399. break;
  400. default:
  401. LOG_WARNING(Shader, "(STUBBED) called");
  402. ctx.AddU32("{}=uint(0x00ff0000);", inst);
  403. }
  404. }
  405. void EmitSampleId(EmitContext& ctx, IR::Inst& inst) {
  406. ctx.AddU32("{}=uint(gl_SampleID);", inst);
  407. }
  408. void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst) {
  409. ctx.AddU1("{}=gl_HelperInvocation;", inst);
  410. }
  411. void EmitYDirection(EmitContext& ctx, IR::Inst& inst) {
  412. ctx.uses_y_direction = true;
  413. ctx.AddF32("{}=gl_FrontMaterial.ambient.a;", inst);
  414. }
  415. void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) {
  416. ctx.AddF32("{}=scaling.z;", inst);
  417. }
  418. void EmitRenderArea(EmitContext& ctx, IR::Inst& inst) {
  419. ctx.AddF32x4("{}=render_area;", inst);
  420. }
  421. void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, std::string_view word_offset) {
  422. ctx.AddU32("{}=lmem[{}];", inst, word_offset);
  423. }
  424. void EmitWriteLocal(EmitContext& ctx, std::string_view word_offset, std::string_view value) {
  425. ctx.Add("lmem[{}]={};", word_offset, value);
  426. }
  427. } // namespace Shader::Backend::GLSL