emit_spirv_image.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <boost/container/static_vector.hpp>
  5. #include "shader_recompiler/backend/spirv/emit_spirv.h"
  6. #include "shader_recompiler/frontend/ir/modifiers.h"
  7. namespace Shader::Backend::SPIRV {
  8. namespace {
  9. class ImageOperands {
  10. public:
  11. explicit ImageOperands(EmitContext& ctx, bool has_bias, bool has_lod, bool has_lod_clamp,
  12. Id lod, Id offset) {
  13. if (has_bias) {
  14. const Id bias{has_lod_clamp ? ctx.OpCompositeExtract(ctx.F32[1], lod, 0) : lod};
  15. Add(spv::ImageOperandsMask::Bias, bias);
  16. }
  17. if (has_lod) {
  18. const Id lod_value{has_lod_clamp ? ctx.OpCompositeExtract(ctx.F32[1], lod, 0) : lod};
  19. Add(spv::ImageOperandsMask::Lod, lod_value);
  20. }
  21. if (Sirit::ValidId(offset)) {
  22. Add(spv::ImageOperandsMask::Offset, offset);
  23. }
  24. if (has_lod_clamp) {
  25. const Id lod_clamp{has_bias ? ctx.OpCompositeExtract(ctx.F32[1], lod, 1) : lod};
  26. Add(spv::ImageOperandsMask::MinLod, lod_clamp);
  27. }
  28. }
  29. explicit ImageOperands([[maybe_unused]] EmitContext& ctx, Id offset) {
  30. if (Sirit::ValidId(offset)) {
  31. Add(spv::ImageOperandsMask::Offset, offset);
  32. }
  33. }
  34. void Add(spv::ImageOperandsMask new_mask, Id value) {
  35. mask = static_cast<spv::ImageOperandsMask>(static_cast<unsigned>(mask) |
  36. static_cast<unsigned>(new_mask));
  37. operands.push_back(value);
  38. }
  39. std::span<const Id> Span() const noexcept {
  40. return std::span{operands.data(), operands.size()};
  41. }
  42. spv::ImageOperandsMask Mask() const noexcept {
  43. return mask;
  44. }
  45. private:
  46. boost::container::static_vector<Id, 3> operands;
  47. spv::ImageOperandsMask mask{};
  48. };
  49. Id Texture(EmitContext& ctx, const IR::Value& index) {
  50. if (index.IsImmediate()) {
  51. const TextureDefinition def{ctx.textures.at(index.U32())};
  52. return ctx.OpLoad(def.type, def.id);
  53. }
  54. throw NotImplementedException("Indirect texture sample");
  55. }
  56. Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) {
  57. const auto info{inst->Flags<IR::TextureInstInfo>()};
  58. if (info.relaxed_precision != 0) {
  59. ctx.Decorate(sample, spv::Decoration::RelaxedPrecision);
  60. }
  61. return sample;
  62. }
  63. template <typename MethodPtrType, typename... Args>
  64. Id Emit(MethodPtrType sparse_ptr, MethodPtrType non_sparse_ptr, EmitContext& ctx, IR::Inst* inst,
  65. Id result_type, Args&&... args) {
  66. IR::Inst* const sparse{inst->GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp)};
  67. if (!sparse) {
  68. return Decorate(ctx, inst, (ctx.*non_sparse_ptr)(result_type, std::forward<Args>(args)...));
  69. }
  70. const Id struct_type{ctx.TypeStruct(ctx.U32[1], result_type)};
  71. const Id sample{(ctx.*sparse_ptr)(struct_type, std::forward<Args>(args)...)};
  72. const Id resident_code{ctx.OpCompositeExtract(ctx.U32[1], sample, 0U)};
  73. sparse->SetDefinition(ctx.OpImageSparseTexelsResident(ctx.U1, resident_code));
  74. sparse->Invalidate();
  75. Decorate(ctx, inst, sample);
  76. return ctx.OpCompositeExtract(result_type, sample, 1U);
  77. }
  78. } // Anonymous namespace
  79. Id EmitBindlessImageSampleImplicitLod(EmitContext&) {
  80. throw LogicError("Unreachable instruction");
  81. }
  82. Id EmitBindlessImageSampleExplicitLod(EmitContext&) {
  83. throw LogicError("Unreachable instruction");
  84. }
  85. Id EmitBindlessImageSampleDrefImplicitLod(EmitContext&) {
  86. throw LogicError("Unreachable instruction");
  87. }
  88. Id EmitBindlessImageSampleDrefExplicitLod(EmitContext&) {
  89. throw LogicError("Unreachable instruction");
  90. }
  91. Id EmitBindlessImageGather(EmitContext&) {
  92. throw LogicError("Unreachable instruction");
  93. }
  94. Id EmitBindlessImageGatherDref(EmitContext&) {
  95. throw LogicError("Unreachable instruction");
  96. }
  97. Id EmitBoundImageSampleImplicitLod(EmitContext&) {
  98. throw LogicError("Unreachable instruction");
  99. }
  100. Id EmitBoundImageSampleExplicitLod(EmitContext&) {
  101. throw LogicError("Unreachable instruction");
  102. }
  103. Id EmitBoundImageSampleDrefImplicitLod(EmitContext&) {
  104. throw LogicError("Unreachable instruction");
  105. }
  106. Id EmitBoundImageSampleDrefExplicitLod(EmitContext&) {
  107. throw LogicError("Unreachable instruction");
  108. }
  109. Id EmitBoundImageGather(EmitContext&) {
  110. throw LogicError("Unreachable instruction");
  111. }
  112. Id EmitBoundImageGatherDref(EmitContext&) {
  113. throw LogicError("Unreachable instruction");
  114. }
  115. Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
  116. Id bias_lc, Id offset) {
  117. const auto info{inst->Flags<IR::TextureInstInfo>()};
  118. const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0, bias_lc,
  119. offset);
  120. return Emit(&EmitContext::OpImageSparseSampleImplicitLod,
  121. &EmitContext::OpImageSampleImplicitLod, ctx, inst, ctx.F32[4], Texture(ctx, index),
  122. coords, operands.Mask(), operands.Span());
  123. }
  124. Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
  125. Id lod_lc, Id offset) {
  126. const auto info{inst->Flags<IR::TextureInstInfo>()};
  127. const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod_lc, offset);
  128. return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
  129. &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], Texture(ctx, index),
  130. coords, operands.Mask(), operands.Span());
  131. }
  132. Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
  133. Id coords, Id dref, Id bias_lc, Id offset) {
  134. const auto info{inst->Flags<IR::TextureInstInfo>()};
  135. const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0, bias_lc,
  136. offset);
  137. return Emit(&EmitContext::OpImageSparseSampleDrefImplicitLod,
  138. &EmitContext::OpImageSampleDrefImplicitLod, ctx, inst, ctx.F32[1],
  139. Texture(ctx, index), coords, dref, operands.Mask(), operands.Span());
  140. }
  141. Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
  142. Id coords, Id dref, Id lod_lc, Id offset) {
  143. const auto info{inst->Flags<IR::TextureInstInfo>()};
  144. const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod_lc, offset);
  145. return Emit(&EmitContext::OpImageSparseSampleDrefExplicitLod,
  146. &EmitContext::OpImageSampleDrefExplicitLod, ctx, inst, ctx.F32[1],
  147. Texture(ctx, index), coords, dref, operands.Mask(), operands.Span());
  148. }
  149. Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
  150. [[maybe_unused]] Id offset2) {
  151. const auto info{inst->Flags<IR::TextureInstInfo>()};
  152. const ImageOperands operands(ctx, offset);
  153. return Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst,
  154. ctx.F32[4], Texture(ctx, index), coords,
  155. ctx.Constant(ctx.U32[1], info.gather_component.Value()), operands.Mask(),
  156. operands.Span());
  157. }
  158. Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
  159. Id offset, [[maybe_unused]] Id offset2, Id dref) {
  160. const auto info{inst->Flags<IR::TextureInstInfo>()};
  161. const ImageOperands operands(ctx, offset);
  162. return Emit(&EmitContext::OpImageSparseDrefGather, &EmitContext::OpImageDrefGather, ctx, inst,
  163. ctx.F32[4], Texture(ctx, index), coords, dref, operands.Mask(), operands.Span());
  164. }
  165. } // namespace Shader::Backend::SPIRV