texture_fetch_swizzled.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <utility>
  5. #include "common/bit_field.h"
  6. #include "common/common_types.h"
  7. #include "shader_recompiler/frontend/ir/modifiers.h"
  8. #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
  9. namespace Shader::Maxwell {
  10. namespace {
  11. enum class Precision : u64 {
  12. F16,
  13. F32,
  14. };
  15. union Encoding {
  16. u64 raw;
  17. BitField<59, 1, Precision> precision;
  18. BitField<53, 4, u64> encoding;
  19. BitField<49, 1, u64> nodep;
  20. BitField<28, 8, IR::Reg> dest_reg_b;
  21. BitField<0, 8, IR::Reg> dest_reg_a;
  22. BitField<8, 8, IR::Reg> src_reg_a;
  23. BitField<20, 8, IR::Reg> src_reg_b;
  24. BitField<36, 13, u64> cbuf_offset;
  25. BitField<50, 3, u64> swizzle;
  26. };
  27. constexpr unsigned R = 1;
  28. constexpr unsigned G = 2;
  29. constexpr unsigned B = 4;
  30. constexpr unsigned A = 8;
  31. constexpr std::array RG_LUT{
  32. R, //
  33. G, //
  34. B, //
  35. A, //
  36. R | G, //
  37. R | A, //
  38. G | A, //
  39. B | A, //
  40. };
  41. constexpr std::array RGBA_LUT{
  42. R | G | B, //
  43. R | G | A, //
  44. R | B | A, //
  45. G | B | A, //
  46. R | G | B | A, //
  47. };
  48. void CheckAlignment(IR::Reg reg, size_t alignment) {
  49. if (!IR::IsAligned(reg, alignment)) {
  50. throw NotImplementedException("Unaligned source register {}", reg);
  51. }
  52. }
  53. template <typename... Args>
  54. IR::Value Composite(TranslatorVisitor& v, Args... regs) {
  55. return v.ir.CompositeConstruct(v.F(regs)...);
  56. }
  57. IR::F32 ReadArray(TranslatorVisitor& v, const IR::U32& value) {
  58. return v.ir.ConvertUToF(32, 16, v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(16)));
  59. }
  60. IR::Value Sample(TranslatorVisitor& v, u64 insn) {
  61. const Encoding texs{insn};
  62. const IR::U32 handle{v.ir.Imm32(static_cast<u32>(texs.cbuf_offset * 4))};
  63. const IR::F32 zero{v.ir.Imm32(0.0f)};
  64. const IR::Reg reg_a{texs.src_reg_a};
  65. const IR::Reg reg_b{texs.src_reg_b};
  66. IR::TextureInstInfo info{};
  67. if (texs.precision == Precision::F16) {
  68. info.relaxed_precision.Assign(1);
  69. }
  70. switch (texs.encoding) {
  71. case 0: // 1D.LZ
  72. info.type.Assign(TextureType::Color1D);
  73. return v.ir.ImageSampleExplicitLod(handle, v.F(reg_a), zero, {}, {}, info);
  74. case 1: // 2D
  75. info.type.Assign(TextureType::Color2D);
  76. return v.ir.ImageSampleImplicitLod(handle, Composite(v, reg_a, reg_b), {}, {}, {}, info);
  77. case 2: // 2D.LZ
  78. info.type.Assign(TextureType::Color2D);
  79. return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_b), zero, {}, {}, info);
  80. case 3: // 2D.LL
  81. CheckAlignment(reg_a, 2);
  82. info.type.Assign(TextureType::Color2D);
  83. return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b), {},
  84. {}, info);
  85. case 4: // 2D.DC
  86. CheckAlignment(reg_a, 2);
  87. info.type.Assign(TextureType::Color2D);
  88. info.is_depth.Assign(1);
  89. return v.ir.ImageSampleDrefImplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b),
  90. {}, {}, {}, info);
  91. case 5: // 2D.LL.DC
  92. CheckAlignment(reg_a, 2);
  93. CheckAlignment(reg_b, 2);
  94. info.type.Assign(TextureType::Color2D);
  95. info.is_depth.Assign(1);
  96. return v.ir.ImageSampleDrefExplicitLod(handle, Composite(v, reg_a, reg_a + 1),
  97. v.F(reg_b + 1), v.F(reg_b), {}, {}, info);
  98. case 6: // 2D.LZ.DC
  99. CheckAlignment(reg_a, 2);
  100. info.type.Assign(TextureType::Color2D);
  101. info.is_depth.Assign(1);
  102. return v.ir.ImageSampleDrefExplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b),
  103. zero, {}, {}, info);
  104. case 7: // ARRAY_2D
  105. CheckAlignment(reg_a, 2);
  106. info.type.Assign(TextureType::ColorArray2D);
  107. return v.ir.ImageSampleImplicitLod(
  108. handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))),
  109. {}, {}, {}, info);
  110. case 8: // ARRAY_2D.LZ
  111. CheckAlignment(reg_a, 2);
  112. info.type.Assign(TextureType::ColorArray2D);
  113. return v.ir.ImageSampleExplicitLod(
  114. handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))),
  115. zero, {}, {}, info);
  116. case 9: // ARRAY_2D.LZ.DC
  117. CheckAlignment(reg_a, 2);
  118. CheckAlignment(reg_b, 2);
  119. info.type.Assign(TextureType::ColorArray2D);
  120. info.is_depth.Assign(1);
  121. return v.ir.ImageSampleDrefExplicitLod(
  122. handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))),
  123. v.F(reg_b + 1), zero, {}, {}, info);
  124. case 10: // 3D
  125. CheckAlignment(reg_a, 2);
  126. info.type.Assign(TextureType::Color3D);
  127. return v.ir.ImageSampleImplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), {}, {},
  128. {}, info);
  129. case 11: // 3D.LZ
  130. CheckAlignment(reg_a, 2);
  131. info.type.Assign(TextureType::Color3D);
  132. return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), zero, {},
  133. {}, info);
  134. case 12: // CUBE
  135. CheckAlignment(reg_a, 2);
  136. info.type.Assign(TextureType::ColorCube);
  137. return v.ir.ImageSampleImplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), {}, {},
  138. {}, info);
  139. case 13: // CUBE.LL
  140. CheckAlignment(reg_a, 2);
  141. CheckAlignment(reg_b, 2);
  142. info.type.Assign(TextureType::ColorCube);
  143. return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b),
  144. v.F(reg_b + 1), {}, {}, info);
  145. default:
  146. throw NotImplementedException("Illegal encoding {}", texs.encoding.Value());
  147. }
  148. }
  149. unsigned Swizzle(u64 insn) {
  150. const Encoding texs{insn};
  151. const size_t encoding{texs.swizzle};
  152. if (texs.dest_reg_b == IR::Reg::RZ) {
  153. if (encoding >= RG_LUT.size()) {
  154. throw NotImplementedException("Illegal RG encoding {}", encoding);
  155. }
  156. return RG_LUT[encoding];
  157. } else {
  158. if (encoding >= RGBA_LUT.size()) {
  159. throw NotImplementedException("Illegal RGBA encoding {}", encoding);
  160. }
  161. return RGBA_LUT[encoding];
  162. }
  163. }
  164. IR::F32 Extract(TranslatorVisitor& v, const IR::Value& sample, unsigned component) {
  165. const bool is_shadow{sample.Type() == IR::Type::F32};
  166. if (is_shadow) {
  167. const bool is_alpha{component == 3};
  168. return is_alpha ? v.ir.Imm32(1.0f) : IR::F32{sample};
  169. } else {
  170. return IR::F32{v.ir.CompositeExtract(sample, component)};
  171. }
  172. }
  173. IR::Reg RegStoreComponent32(u64 insn, unsigned index) {
  174. const Encoding texs{insn};
  175. switch (index) {
  176. case 0:
  177. return texs.dest_reg_a;
  178. case 1:
  179. CheckAlignment(texs.dest_reg_a, 2);
  180. return texs.dest_reg_a + 1;
  181. case 2:
  182. return texs.dest_reg_b;
  183. case 3:
  184. CheckAlignment(texs.dest_reg_b, 2);
  185. return texs.dest_reg_b + 1;
  186. }
  187. throw LogicError("Invalid store index {}", index);
  188. }
  189. void Store32(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
  190. const unsigned swizzle{Swizzle(insn)};
  191. unsigned store_index{0};
  192. for (unsigned component = 0; component < 4; ++component) {
  193. if (((swizzle >> component) & 1) == 0) {
  194. continue;
  195. }
  196. const IR::Reg dest{RegStoreComponent32(insn, store_index)};
  197. v.F(dest, Extract(v, sample, component));
  198. ++store_index;
  199. }
  200. }
  201. IR::U32 Pack(TranslatorVisitor& v, const IR::F32& lhs, const IR::F32& rhs) {
  202. return v.ir.PackHalf2x16(v.ir.CompositeConstruct(lhs, rhs));
  203. }
  204. void Store16(TranslatorVisitor& v, u64 insn, const IR::Value& sample) {
  205. const unsigned swizzle{Swizzle(insn)};
  206. unsigned store_index{0};
  207. std::array<IR::F32, 4> swizzled;
  208. for (unsigned component = 0; component < 4; ++component) {
  209. if (((swizzle >> component) & 1) == 0) {
  210. continue;
  211. }
  212. swizzled[store_index] = Extract(v, sample, component);
  213. ++store_index;
  214. }
  215. const IR::F32 zero{v.ir.Imm32(0.0f)};
  216. const Encoding texs{insn};
  217. switch (store_index) {
  218. case 1:
  219. v.X(texs.dest_reg_a, Pack(v, swizzled[0], zero));
  220. break;
  221. case 2:
  222. case 3:
  223. case 4:
  224. v.X(texs.dest_reg_a, Pack(v, swizzled[0], swizzled[1]));
  225. switch (store_index) {
  226. case 2:
  227. break;
  228. case 3:
  229. v.X(texs.dest_reg_b, Pack(v, swizzled[2], zero));
  230. break;
  231. case 4:
  232. v.X(texs.dest_reg_b, Pack(v, swizzled[2], swizzled[3]));
  233. break;
  234. }
  235. break;
  236. }
  237. }
  238. } // Anonymous namespace
  239. void TranslatorVisitor::TEXS(u64 insn) {
  240. const IR::Value sample{Sample(*this, insn)};
  241. if (Encoding{insn}.precision == Precision::F32) {
  242. Store32(*this, insn, sample);
  243. } else {
  244. Store16(*this, insn, sample);
  245. }
  246. }
  247. } // namespace Shader::Maxwell