emit_spirv_image.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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. void Add(spv::ImageOperandsMask new_mask, Id value) {
  30. mask = static_cast<spv::ImageOperandsMask>(static_cast<unsigned>(mask) |
  31. static_cast<unsigned>(new_mask));
  32. operands.push_back(value);
  33. }
  34. std::span<const Id> Span() const noexcept {
  35. return std::span{operands.data(), operands.size()};
  36. }
  37. spv::ImageOperandsMask Mask() const noexcept {
  38. return mask;
  39. }
  40. private:
  41. boost::container::static_vector<Id, 3> operands;
  42. spv::ImageOperandsMask mask{};
  43. };
  44. Id Texture(EmitContext& ctx, const IR::Value& index) {
  45. if (index.IsImmediate()) {
  46. const TextureDefinition def{ctx.textures.at(index.U32())};
  47. return ctx.OpLoad(def.type, def.id);
  48. }
  49. throw NotImplementedException("Indirect texture sample");
  50. }
  51. Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) {
  52. const auto info{inst->Flags<IR::TextureInstInfo>()};
  53. if (info.relaxed_precision != 0) {
  54. ctx.Decorate(sample, spv::Decoration::RelaxedPrecision);
  55. }
  56. return sample;
  57. }
  58. template <typename MethodPtrType, typename... Args>
  59. Id Emit(MethodPtrType sparse_ptr, MethodPtrType non_sparse_ptr, EmitContext& ctx, IR::Inst* inst,
  60. Id result_type, Args&&... args) {
  61. IR::Inst* const sparse{inst->GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp)};
  62. if (!sparse) {
  63. return Decorate(ctx, inst, (ctx.*non_sparse_ptr)(result_type, std::forward<Args>(args)...));
  64. }
  65. const Id struct_type{ctx.TypeStruct(ctx.U32[1], result_type)};
  66. const Id sample{(ctx.*sparse_ptr)(struct_type, std::forward<Args>(args)...)};
  67. const Id resident_code{ctx.OpCompositeExtract(ctx.U32[1], sample, 0U)};
  68. sparse->SetDefinition(ctx.OpImageSparseTexelsResident(ctx.U1, resident_code));
  69. sparse->Invalidate();
  70. Decorate(ctx, inst, sample);
  71. return ctx.OpCompositeExtract(result_type, sample, 1U);
  72. }
  73. } // Anonymous namespace
  74. Id EmitBindlessImageSampleImplicitLod(EmitContext&) {
  75. throw LogicError("Unreachable instruction");
  76. }
  77. Id EmitBindlessImageSampleExplicitLod(EmitContext&) {
  78. throw LogicError("Unreachable instruction");
  79. }
  80. Id EmitBindlessImageSampleDrefImplicitLod(EmitContext&) {
  81. throw LogicError("Unreachable instruction");
  82. }
  83. Id EmitBindlessImageSampleDrefExplicitLod(EmitContext&) {
  84. throw LogicError("Unreachable instruction");
  85. }
  86. Id EmitBoundImageSampleImplicitLod(EmitContext&) {
  87. throw LogicError("Unreachable instruction");
  88. }
  89. Id EmitBoundImageSampleExplicitLod(EmitContext&) {
  90. throw LogicError("Unreachable instruction");
  91. }
  92. Id EmitBoundImageSampleDrefImplicitLod(EmitContext&) {
  93. throw LogicError("Unreachable instruction");
  94. }
  95. Id EmitBoundImageSampleDrefExplicitLod(EmitContext&) {
  96. throw LogicError("Unreachable instruction");
  97. }
  98. Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
  99. Id bias_lc, Id offset) {
  100. const auto info{inst->Flags<IR::TextureInstInfo>()};
  101. const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0, bias_lc,
  102. offset);
  103. return Emit(&EmitContext::OpImageSparseSampleImplicitLod,
  104. &EmitContext::OpImageSampleImplicitLod, ctx, inst, ctx.F32[4], Texture(ctx, index),
  105. coords, operands.Mask(), operands.Span());
  106. }
  107. Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
  108. Id lod_lc, Id offset) {
  109. const auto info{inst->Flags<IR::TextureInstInfo>()};
  110. const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod_lc, offset);
  111. return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
  112. &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], Texture(ctx, index),
  113. coords, operands.Mask(), operands.Span());
  114. }
  115. Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
  116. Id coords, Id dref, 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::OpImageSparseSampleDrefImplicitLod,
  121. &EmitContext::OpImageSampleDrefImplicitLod, ctx, inst, ctx.F32[1],
  122. Texture(ctx, index), coords, dref, operands.Mask(), operands.Span());
  123. }
  124. Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
  125. Id coords, Id dref, 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::OpImageSparseSampleDrefExplicitLod,
  129. &EmitContext::OpImageSampleDrefExplicitLod, ctx, inst, ctx.F32[1],
  130. Texture(ctx, index), coords, dref, operands.Mask(), operands.Span());
  131. }
  132. } // namespace Shader::Backend::SPIRV