emit_glasm_context_get_set.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <string_view>
  5. #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
  6. #include "shader_recompiler/backend/glasm/glasm_emit_context.h"
  7. #include "shader_recompiler/frontend/ir/value.h"
  8. #include "shader_recompiler/profile.h"
  9. #include "shader_recompiler/shader_info.h"
  10. namespace Shader::Backend::GLASM {
  11. namespace {
  12. void GetCbuf(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset,
  13. std::string_view size) {
  14. if (!binding.IsImmediate()) {
  15. throw NotImplementedException("Indirect constant buffer loading");
  16. }
  17. const Register ret{ctx.reg_alloc.Define(inst)};
  18. if (offset.type == Type::U32) {
  19. // Avoid reading arrays out of bounds, matching hardware's behavior
  20. if (offset.imm_u32 >= 0x10'000) {
  21. ctx.Add("MOV.S {},0;", ret);
  22. return;
  23. }
  24. }
  25. ctx.Add("LDC.{} {},c{}[{}];", size, ret, binding.U32(), offset);
  26. }
  27. bool IsInputArray(Stage stage) {
  28. return stage == Stage::Geometry || stage == Stage::TessellationControl ||
  29. stage == Stage::TessellationEval;
  30. }
  31. std::string VertexIndex(EmitContext& ctx, ScalarU32 vertex) {
  32. return IsInputArray(ctx.stage) ? fmt::format("[{}]", vertex) : "";
  33. }
  34. u32 TexCoordIndex(IR::Attribute attr) {
  35. return (static_cast<u32>(attr) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4;
  36. }
  37. } // Anonymous namespace
  38. void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset) {
  39. GetCbuf(ctx, inst, binding, offset, "U8");
  40. }
  41. void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset) {
  42. GetCbuf(ctx, inst, binding, offset, "S8");
  43. }
  44. void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset) {
  45. GetCbuf(ctx, inst, binding, offset, "U16");
  46. }
  47. void EmitGetCbufS16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset) {
  48. GetCbuf(ctx, inst, binding, offset, "S16");
  49. }
  50. void EmitGetCbufU32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset) {
  51. GetCbuf(ctx, inst, binding, offset, "U32");
  52. }
  53. void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset) {
  54. GetCbuf(ctx, inst, binding, offset, "F32");
  55. }
  56. void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  57. ScalarU32 offset) {
  58. GetCbuf(ctx, inst, binding, offset, "U32X2");
  59. }
  60. void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, ScalarU32 vertex) {
  61. const u32 element{static_cast<u32>(attr) % 4};
  62. const char swizzle{"xyzw"[element]};
  63. if (IR::IsGeneric(attr)) {
  64. const u32 index{IR::GenericAttributeIndex(attr)};
  65. ctx.Add("MOV.F {}.x,in_attr{}{}[0].{};", inst, index, VertexIndex(ctx, vertex), swizzle);
  66. return;
  67. }
  68. if (attr >= IR::Attribute::FixedFncTexture0S && attr <= IR::Attribute::FixedFncTexture9Q) {
  69. const u32 index{TexCoordIndex(attr)};
  70. ctx.Add("MOV.F {}.x,{}.texcoord[{}].{};", inst, ctx.attrib_name, index, swizzle);
  71. return;
  72. }
  73. switch (attr) {
  74. case IR::Attribute::PrimitiveId:
  75. ctx.Add("MOV.S {}.x,primitive.id;", inst);
  76. break;
  77. case IR::Attribute::PositionX:
  78. case IR::Attribute::PositionY:
  79. case IR::Attribute::PositionZ:
  80. case IR::Attribute::PositionW:
  81. if (IsInputArray(ctx.stage)) {
  82. ctx.Add("MOV.F {}.x,vertex_position{}.{};", inst, VertexIndex(ctx, vertex), swizzle);
  83. } else {
  84. ctx.Add("MOV.F {}.x,{}.position.{};", inst, ctx.attrib_name, swizzle);
  85. }
  86. break;
  87. case IR::Attribute::ColorFrontDiffuseR:
  88. case IR::Attribute::ColorFrontDiffuseG:
  89. case IR::Attribute::ColorFrontDiffuseB:
  90. case IR::Attribute::ColorFrontDiffuseA:
  91. ctx.Add("MOV.F {}.x,{}.color.{};", inst, ctx.attrib_name, swizzle);
  92. break;
  93. case IR::Attribute::PointSpriteS:
  94. case IR::Attribute::PointSpriteT:
  95. ctx.Add("MOV.F {}.x,{}.pointcoord.{};", inst, ctx.attrib_name, swizzle);
  96. break;
  97. case IR::Attribute::TessellationEvaluationPointU:
  98. case IR::Attribute::TessellationEvaluationPointV:
  99. ctx.Add("MOV.F {}.x,vertex.tesscoord.{};", inst, swizzle);
  100. break;
  101. case IR::Attribute::InstanceId:
  102. ctx.Add("MOV.S {}.x,{}.instance;", inst, ctx.attrib_name);
  103. break;
  104. case IR::Attribute::VertexId:
  105. ctx.Add("MOV.S {}.x,{}.id;", inst, ctx.attrib_name);
  106. break;
  107. case IR::Attribute::FrontFace:
  108. ctx.Add("CMP.S {}.x,{}.facing.x,0,-1;", inst, ctx.attrib_name);
  109. break;
  110. default:
  111. throw NotImplementedException("Get attribute {}", attr);
  112. }
  113. }
  114. void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, ScalarF32 value,
  115. [[maybe_unused]] ScalarU32 vertex) {
  116. const u32 element{static_cast<u32>(attr) % 4};
  117. const char swizzle{"xyzw"[element]};
  118. if (IR::IsGeneric(attr)) {
  119. const u32 index{IR::GenericAttributeIndex(attr)};
  120. ctx.Add("MOV.F out_attr{}[0].{},{};", index, swizzle, value);
  121. return;
  122. }
  123. if (attr >= IR::Attribute::FixedFncTexture0S && attr <= IR::Attribute::FixedFncTexture9R) {
  124. const u32 index{TexCoordIndex(attr)};
  125. ctx.Add("MOV.F result.texcoord[{}].{},{};", index, swizzle, value);
  126. return;
  127. }
  128. switch (attr) {
  129. case IR::Attribute::Layer:
  130. if (ctx.stage == Stage::Geometry || ctx.profile.support_viewport_index_layer_non_geometry) {
  131. ctx.Add("MOV.F result.layer.x,{};", value);
  132. } else {
  133. LOG_WARNING(Shader_GLASM,
  134. "Layer stored outside of geometry shader not supported by device");
  135. }
  136. break;
  137. case IR::Attribute::ViewportIndex:
  138. if (ctx.stage == Stage::Geometry || ctx.profile.support_viewport_index_layer_non_geometry) {
  139. ctx.Add("MOV.F result.viewport.x,{};", value);
  140. } else {
  141. LOG_WARNING(Shader_GLASM,
  142. "Viewport stored outside of geometry shader not supported by device");
  143. }
  144. break;
  145. case IR::Attribute::ViewportMask:
  146. // NV_viewport_array2 is required to access result.viewportmask, regardless of shader stage.
  147. if (ctx.profile.support_viewport_index_layer_non_geometry) {
  148. ctx.Add("MOV.F result.viewportmask[0].x,{};", value);
  149. } else {
  150. LOG_WARNING(Shader_GLASM, "Device does not support storing to ViewportMask");
  151. }
  152. break;
  153. case IR::Attribute::PointSize:
  154. ctx.Add("MOV.F result.pointsize.x,{};", value);
  155. break;
  156. case IR::Attribute::PositionX:
  157. case IR::Attribute::PositionY:
  158. case IR::Attribute::PositionZ:
  159. case IR::Attribute::PositionW:
  160. ctx.Add("MOV.F result.position.{},{};", swizzle, value);
  161. break;
  162. case IR::Attribute::ColorFrontDiffuseR:
  163. case IR::Attribute::ColorFrontDiffuseG:
  164. case IR::Attribute::ColorFrontDiffuseB:
  165. case IR::Attribute::ColorFrontDiffuseA:
  166. ctx.Add("MOV.F result.color.{},{};", swizzle, value);
  167. break;
  168. case IR::Attribute::ColorFrontSpecularR:
  169. case IR::Attribute::ColorFrontSpecularG:
  170. case IR::Attribute::ColorFrontSpecularB:
  171. case IR::Attribute::ColorFrontSpecularA:
  172. ctx.Add("MOV.F result.color.secondary.{},{};", swizzle, value);
  173. break;
  174. case IR::Attribute::ColorBackDiffuseR:
  175. case IR::Attribute::ColorBackDiffuseG:
  176. case IR::Attribute::ColorBackDiffuseB:
  177. case IR::Attribute::ColorBackDiffuseA:
  178. ctx.Add("MOV.F result.color.back.{},{};", swizzle, value);
  179. break;
  180. case IR::Attribute::ColorBackSpecularR:
  181. case IR::Attribute::ColorBackSpecularG:
  182. case IR::Attribute::ColorBackSpecularB:
  183. case IR::Attribute::ColorBackSpecularA:
  184. ctx.Add("MOV.F result.color.back.secondary.{},{};", swizzle, value);
  185. break;
  186. case IR::Attribute::FogCoordinate:
  187. ctx.Add("MOV.F result.fogcoord.x,{};", value);
  188. break;
  189. case IR::Attribute::ClipDistance0:
  190. case IR::Attribute::ClipDistance1:
  191. case IR::Attribute::ClipDistance2:
  192. case IR::Attribute::ClipDistance3:
  193. case IR::Attribute::ClipDistance4:
  194. case IR::Attribute::ClipDistance5:
  195. case IR::Attribute::ClipDistance6:
  196. case IR::Attribute::ClipDistance7: {
  197. const u32 index{static_cast<u32>(attr) - static_cast<u32>(IR::Attribute::ClipDistance0)};
  198. ctx.Add("MOV.F result.clip[{}].x,{};", index, value);
  199. break;
  200. }
  201. default:
  202. throw NotImplementedException("Set attribute {}", attr);
  203. }
  204. }
  205. void EmitGetAttributeIndexed(EmitContext& ctx, IR::Inst& inst, ScalarS32 offset, ScalarU32 vertex) {
  206. // RC.x = base_index
  207. // RC.y = masked_index
  208. // RC.z = compare_index
  209. ctx.Add("SHR.S RC.x,{},2;"
  210. "AND.S RC.y,RC.x,3;"
  211. "SHR.S RC.z,{},4;",
  212. offset, offset);
  213. const Register ret{ctx.reg_alloc.Define(inst)};
  214. u32 num_endifs{};
  215. const auto read{[&](u32 compare_index, const std::array<std::string, 4>& values) {
  216. ++num_endifs;
  217. ctx.Add("SEQ.S.CC RC.w,RC.z,{};" // compare_index
  218. "IF NE.w;"
  219. // X
  220. "SEQ.S.CC RC.w,RC.y,0;"
  221. "IF NE.w;"
  222. "MOV {}.x,{};"
  223. "ELSE;"
  224. // Y
  225. "SEQ.S.CC RC.w,RC.y,1;"
  226. "IF NE.w;"
  227. "MOV {}.x,{};"
  228. "ELSE;"
  229. // Z
  230. "SEQ.S.CC RC.w,RC.y,2;"
  231. "IF NE.w;"
  232. "MOV {}.x,{};"
  233. "ELSE;"
  234. // W
  235. "MOV {}.x,{};"
  236. "ENDIF;"
  237. "ENDIF;"
  238. "ENDIF;"
  239. "ELSE;",
  240. compare_index, ret, values[0], ret, values[1], ret, values[2], ret, values[3]);
  241. }};
  242. const auto read_swizzled{[&](u32 compare_index, std::string_view value) {
  243. const std::array values{fmt::format("{}.x", value), fmt::format("{}.y", value),
  244. fmt::format("{}.z", value), fmt::format("{}.w", value)};
  245. read(compare_index, values);
  246. }};
  247. if (ctx.info.loads.AnyComponent(IR::Attribute::PositionX)) {
  248. const u32 index{static_cast<u32>(IR::Attribute::PositionX)};
  249. if (IsInputArray(ctx.stage)) {
  250. read_swizzled(index, fmt::format("vertex_position{}", VertexIndex(ctx, vertex)));
  251. } else {
  252. read_swizzled(index, fmt::format("{}.position", ctx.attrib_name));
  253. }
  254. }
  255. for (u32 index = 0; index < static_cast<u32>(IR::NUM_GENERICS); ++index) {
  256. if (!ctx.info.loads.Generic(index)) {
  257. continue;
  258. }
  259. read_swizzled(index, fmt::format("in_attr{}{}[0]", index, VertexIndex(ctx, vertex)));
  260. }
  261. for (u32 i = 0; i < num_endifs; ++i) {
  262. ctx.Add("ENDIF;");
  263. }
  264. }
  265. void EmitSetAttributeIndexed([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] ScalarU32 offset,
  266. [[maybe_unused]] ScalarF32 value, [[maybe_unused]] ScalarU32 vertex) {
  267. throw NotImplementedException("GLASM instruction");
  268. }
  269. void EmitGetPatch(EmitContext& ctx, IR::Inst& inst, IR::Patch patch) {
  270. if (!IR::IsGeneric(patch)) {
  271. throw NotImplementedException("Non-generic patch load");
  272. }
  273. const u32 index{IR::GenericPatchIndex(patch)};
  274. const u32 element{IR::GenericPatchElement(patch)};
  275. const char swizzle{"xyzw"[element]};
  276. const std::string_view out{ctx.stage == Stage::TessellationControl ? ".out" : ""};
  277. ctx.Add("MOV.F {},primitive{}.patch.attrib[{}].{};", inst, out, index, swizzle);
  278. }
  279. void EmitSetPatch(EmitContext& ctx, IR::Patch patch, ScalarF32 value) {
  280. if (IR::IsGeneric(patch)) {
  281. const u32 index{IR::GenericPatchIndex(patch)};
  282. const u32 element{IR::GenericPatchElement(patch)};
  283. ctx.Add("MOV.F result.patch.attrib[{}].{},{};", index, "xyzw"[element], value);
  284. return;
  285. }
  286. switch (patch) {
  287. case IR::Patch::TessellationLodLeft:
  288. case IR::Patch::TessellationLodRight:
  289. case IR::Patch::TessellationLodTop:
  290. case IR::Patch::TessellationLodBottom: {
  291. const u32 index{static_cast<u32>(patch) - u32(IR::Patch::TessellationLodLeft)};
  292. ctx.Add("MOV.F result.patch.tessouter[{}].x,{};", index, value);
  293. break;
  294. }
  295. case IR::Patch::TessellationLodInteriorU:
  296. ctx.Add("MOV.F result.patch.tessinner[0].x,{};", value);
  297. break;
  298. case IR::Patch::TessellationLodInteriorV:
  299. ctx.Add("MOV.F result.patch.tessinner[1].x,{};", value);
  300. break;
  301. default:
  302. throw NotImplementedException("Patch {}", patch);
  303. }
  304. }
  305. void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, ScalarF32 value) {
  306. ctx.Add("MOV.F frag_color{}.{},{};", index, "xyzw"[component], value);
  307. }
  308. void EmitSetSampleMask(EmitContext& ctx, ScalarS32 value) {
  309. ctx.Add("MOV.S result.samplemask.x,{};", value);
  310. }
  311. void EmitSetFragDepth(EmitContext& ctx, ScalarF32 value) {
  312. ctx.Add("MOV.F result.depth.z,{};", value);
  313. }
  314. void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst) {
  315. ctx.Add("MOV.S {},invocation.groupid;", inst);
  316. }
  317. void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst) {
  318. ctx.Add("MOV.S {},invocation.localid;", inst);
  319. }
  320. void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) {
  321. ctx.Add("MOV.S {}.x,primitive_invocation.x;", inst);
  322. }
  323. void EmitSampleId(EmitContext& ctx, IR::Inst& inst) {
  324. ctx.Add("MOV.S {}.x,fragment.sampleid.x;", inst);
  325. }
  326. void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst) {
  327. ctx.Add("MOV.S {}.x,fragment.helperthread.x;", inst);
  328. }
  329. void EmitYDirection(EmitContext& ctx, IR::Inst& inst) {
  330. ctx.uses_y_direction = true;
  331. ctx.Add("MOV.F {}.x,y_direction[0].w;", inst);
  332. }
  333. void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) {
  334. ctx.Add("MOV.F {}.x,scaling[0].z;", inst);
  335. }
  336. void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, ScalarU32 word_offset) {
  337. ctx.Add("MOV.U {},lmem[{}].x;", inst, word_offset);
  338. }
  339. void EmitWriteLocal(EmitContext& ctx, ScalarU32 word_offset, ScalarU32 value) {
  340. ctx.Add("MOV.U lmem[{}].x,{};", word_offset, value);
  341. }
  342. } // namespace Shader::Backend::GLASM