summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/backend')
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.cpp69
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.h7
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp12
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.h32
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp48
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp146
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp18
7 files changed, 327 insertions, 5 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp
index d2dbd56d4..21900d387 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_context.cpp
@@ -12,6 +12,43 @@
12#include "shader_recompiler/backend/spirv/emit_context.h" 12#include "shader_recompiler/backend/spirv/emit_context.h"
13 13
14namespace Shader::Backend::SPIRV { 14namespace Shader::Backend::SPIRV {
15namespace {
16Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) {
17 const spv::ImageFormat format{spv::ImageFormat::Unknown};
18 const Id type{ctx.F32[1]};
19 switch (desc.type) {
20 case TextureType::Color1D:
21 return ctx.TypeImage(type, spv::Dim::Dim1D, false, false, false, 1, format);
22 case TextureType::ColorArray1D:
23 return ctx.TypeImage(type, spv::Dim::Dim1D, false, true, false, 1, format);
24 case TextureType::Color2D:
25 return ctx.TypeImage(type, spv::Dim::Dim2D, false, false, false, 1, format);
26 case TextureType::ColorArray2D:
27 return ctx.TypeImage(type, spv::Dim::Dim2D, false, true, false, 1, format);
28 case TextureType::Color3D:
29 return ctx.TypeImage(type, spv::Dim::Dim3D, false, false, false, 1, format);
30 case TextureType::ColorCube:
31 return ctx.TypeImage(type, spv::Dim::Cube, false, false, false, 1, format);
32 case TextureType::ColorArrayCube:
33 return ctx.TypeImage(type, spv::Dim::Cube, false, true, false, 1, format);
34 case TextureType::Shadow1D:
35 return ctx.TypeImage(type, spv::Dim::Dim1D, true, false, false, 1, format);
36 case TextureType::ShadowArray1D:
37 return ctx.TypeImage(type, spv::Dim::Dim1D, true, true, false, 1, format);
38 case TextureType::Shadow2D:
39 return ctx.TypeImage(type, spv::Dim::Dim2D, true, false, false, 1, format);
40 case TextureType::ShadowArray2D:
41 return ctx.TypeImage(type, spv::Dim::Dim2D, true, true, false, 1, format);
42 case TextureType::Shadow3D:
43 return ctx.TypeImage(type, spv::Dim::Dim3D, true, false, false, 1, format);
44 case TextureType::ShadowCube:
45 return ctx.TypeImage(type, spv::Dim::Cube, true, false, false, 1, format);
46 case TextureType::ShadowArrayCube:
47 return ctx.TypeImage(type, spv::Dim::Cube, false, true, false, 1, format);
48 }
49 throw InvalidArgument("Invalid texture type {}", desc.type);
50}
51} // Anonymous namespace
15 52
16void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { 53void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) {
17 defs[0] = sirit_ctx.Name(base_type, name); 54 defs[0] = sirit_ctx.Name(base_type, name);
@@ -35,6 +72,7 @@ EmitContext::EmitContext(const Profile& profile_, IR::Program& program)
35 u32 binding{}; 72 u32 binding{};
36 DefineConstantBuffers(program.info, binding); 73 DefineConstantBuffers(program.info, binding);
37 DefineStorageBuffers(program.info, binding); 74 DefineStorageBuffers(program.info, binding);
75 DefineTextures(program.info, binding);
38 76
39 DefineLabels(program); 77 DefineLabels(program);
40} 78}
@@ -46,6 +84,10 @@ Id EmitContext::Def(const IR::Value& value) {
46 return value.Inst()->Definition<Id>(); 84 return value.Inst()->Definition<Id>();
47 } 85 }
48 switch (value.Type()) { 86 switch (value.Type()) {
87 case IR::Type::Void:
88 // Void instructions are used for optional arguments (e.g. texture offsets)
89 // They are not meant to be used in the SPIR-V module
90 return Id{};
49 case IR::Type::U1: 91 case IR::Type::U1:
50 return value.U1() ? true_value : false_value; 92 return value.U1() ? true_value : false_value;
51 case IR::Type::U32: 93 case IR::Type::U32:
@@ -122,7 +164,7 @@ void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) {
122 uniform_u32 = TypePointer(spv::StorageClass::Uniform, U32[1]); 164 uniform_u32 = TypePointer(spv::StorageClass::Uniform, U32[1]);
123 165
124 u32 index{}; 166 u32 index{};
125 for (const Info::ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) { 167 for (const ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) {
126 const Id id{AddGlobalVariable(uniform_type, spv::StorageClass::Uniform)}; 168 const Id id{AddGlobalVariable(uniform_type, spv::StorageClass::Uniform)};
127 Decorate(id, spv::Decoration::Binding, binding); 169 Decorate(id, spv::Decoration::Binding, binding);
128 Decorate(id, spv::Decoration::DescriptorSet, 0U); 170 Decorate(id, spv::Decoration::DescriptorSet, 0U);
@@ -152,7 +194,7 @@ void EmitContext::DefineStorageBuffers(const Info& info, u32& binding) {
152 storage_u32 = TypePointer(spv::StorageClass::StorageBuffer, U32[1]); 194 storage_u32 = TypePointer(spv::StorageClass::StorageBuffer, U32[1]);
153 195
154 u32 index{}; 196 u32 index{};
155 for (const Info::StorageBufferDescriptor& desc : info.storage_buffers_descriptors) { 197 for (const StorageBufferDescriptor& desc : info.storage_buffers_descriptors) {
156 const Id id{AddGlobalVariable(storage_type, spv::StorageClass::StorageBuffer)}; 198 const Id id{AddGlobalVariable(storage_type, spv::StorageClass::StorageBuffer)};
157 Decorate(id, spv::Decoration::Binding, binding); 199 Decorate(id, spv::Decoration::Binding, binding);
158 Decorate(id, spv::Decoration::DescriptorSet, 0U); 200 Decorate(id, spv::Decoration::DescriptorSet, 0U);
@@ -163,6 +205,29 @@ void EmitContext::DefineStorageBuffers(const Info& info, u32& binding) {
163 } 205 }
164} 206}
165 207
208void EmitContext::DefineTextures(const Info& info, u32& binding) {
209 textures.reserve(info.texture_descriptors.size());
210 for (const TextureDescriptor& desc : info.texture_descriptors) {
211 if (desc.count != 1) {
212 throw NotImplementedException("Array of textures");
213 }
214 const Id type{TypeSampledImage(ImageType(*this, desc))};
215 const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, type)};
216 const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)};
217 Decorate(id, spv::Decoration::Binding, binding);
218 Decorate(id, spv::Decoration::DescriptorSet, 0U);
219 Name(id, fmt::format("tex{}_{:02x}", desc.cbuf_index, desc.cbuf_offset));
220 for (u32 index = 0; index < desc.count; ++index) {
221 // TODO: Pass count info
222 textures.push_back(TextureDefinition{
223 .id{id},
224 .type{type},
225 });
226 }
227 binding += desc.count;
228 }
229}
230
166void EmitContext::DefineLabels(IR::Program& program) { 231void EmitContext::DefineLabels(IR::Program& program) {
167 for (const IR::Function& function : program.functions) { 232 for (const IR::Function& function : program.functions) {
168 for (IR::Block* const block : function.blocks) { 233 for (IR::Block* const block : function.blocks) {
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h
index d20cf387e..8b3109eb8 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.h
+++ b/src/shader_recompiler/backend/spirv/emit_context.h
@@ -29,6 +29,11 @@ private:
29 std::array<Id, 4> defs{}; 29 std::array<Id, 4> defs{};
30}; 30};
31 31
32struct TextureDefinition {
33 Id id;
34 Id type;
35};
36
32class EmitContext final : public Sirit::Module { 37class EmitContext final : public Sirit::Module {
33public: 38public:
34 explicit EmitContext(const Profile& profile, IR::Program& program); 39 explicit EmitContext(const Profile& profile, IR::Program& program);
@@ -56,6 +61,7 @@ public:
56 61
57 std::array<Id, Info::MAX_CBUFS> cbufs{}; 62 std::array<Id, Info::MAX_CBUFS> cbufs{};
58 std::array<Id, Info::MAX_SSBOS> ssbos{}; 63 std::array<Id, Info::MAX_SSBOS> ssbos{};
64 std::vector<TextureDefinition> textures;
59 65
60 Id workgroup_id{}; 66 Id workgroup_id{};
61 Id local_invocation_id{}; 67 Id local_invocation_id{};
@@ -66,6 +72,7 @@ private:
66 void DefineSpecialVariables(const Info& info); 72 void DefineSpecialVariables(const Info& info);
67 void DefineConstantBuffers(const Info& info, u32& binding); 73 void DefineConstantBuffers(const Info& info, u32& binding);
68 void DefineStorageBuffers(const Info& info, u32& binding); 74 void DefineStorageBuffers(const Info& info, u32& binding);
75 void DefineTextures(const Info& info, u32& binding);
69 void DefineLabels(IR::Program& program); 76 void DefineLabels(IR::Program& program);
70}; 77};
71 78
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index 8097fe82d..a94e9cb2d 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -221,6 +221,14 @@ std::vector<u32> EmitSPIRV(const Profile& profile, Environment& env, IR::Program
221 workgroup_size[2]); 221 workgroup_size[2]);
222 222
223 SetupDenormControl(profile, program, ctx, func); 223 SetupDenormControl(profile, program, ctx, func);
224 if (info.uses_sampled_1d) {
225 ctx.AddCapability(spv::Capability::Sampled1D);
226 }
227 if (info.uses_sparse_residency) {
228 ctx.AddCapability(spv::Capability::SparseResidency);
229 }
230 // TODO: Track this usage
231 ctx.AddCapability(spv::Capability::ImageGatherExtended);
224 232
225 return ctx.Assemble(); 233 return ctx.Assemble();
226} 234}
@@ -259,4 +267,8 @@ void EmitGetOverflowFromOp(EmitContext&) {
259 throw LogicError("Unreachable instruction"); 267 throw LogicError("Unreachable instruction");
260} 268}
261 269
270void EmitGetSparseFromOp(EmitContext&) {
271 throw LogicError("Unreachable instruction");
272}
273
262} // namespace Shader::Backend::SPIRV 274} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h
index 92387ca28..69698c478 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.h
@@ -83,7 +83,8 @@ void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Va
83 Id value); 83 Id value);
84void EmitWriteStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, 84void EmitWriteStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
85 Id value); 85 Id value);
86void EmitWriteStorage128(EmitContext& ctx); 86void EmitWriteStorage128(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
87 Id value);
87Id EmitCompositeConstructU32x2(EmitContext& ctx, Id e1, Id e2); 88Id EmitCompositeConstructU32x2(EmitContext& ctx, Id e1, Id e2);
88Id EmitCompositeConstructU32x3(EmitContext& ctx, Id e1, Id e2, Id e3); 89Id EmitCompositeConstructU32x3(EmitContext& ctx, Id e1, Id e2, Id e3);
89Id EmitCompositeConstructU32x4(EmitContext& ctx, Id e1, Id e2, Id e3, Id e4); 90Id EmitCompositeConstructU32x4(EmitContext& ctx, Id e1, Id e2, Id e3, Id e4);
@@ -145,6 +146,7 @@ void EmitGetZeroFromOp(EmitContext& ctx);
145void EmitGetSignFromOp(EmitContext& ctx); 146void EmitGetSignFromOp(EmitContext& ctx);
146void EmitGetCarryFromOp(EmitContext& ctx); 147void EmitGetCarryFromOp(EmitContext& ctx);
147void EmitGetOverflowFromOp(EmitContext& ctx); 148void EmitGetOverflowFromOp(EmitContext& ctx);
149void EmitGetSparseFromOp(EmitContext& ctx);
148Id EmitFPAbs16(EmitContext& ctx, Id value); 150Id EmitFPAbs16(EmitContext& ctx, Id value);
149Id EmitFPAbs32(EmitContext& ctx, Id value); 151Id EmitFPAbs32(EmitContext& ctx, Id value);
150Id EmitFPAbs64(EmitContext& ctx, Id value); 152Id EmitFPAbs64(EmitContext& ctx, Id value);
@@ -291,5 +293,33 @@ Id EmitConvertF16F32(EmitContext& ctx, Id value);
291Id EmitConvertF32F16(EmitContext& ctx, Id value); 293Id EmitConvertF32F16(EmitContext& ctx, Id value);
292Id EmitConvertF32F64(EmitContext& ctx, Id value); 294Id EmitConvertF32F64(EmitContext& ctx, Id value);
293Id EmitConvertF64F32(EmitContext& ctx, Id value); 295Id EmitConvertF64F32(EmitContext& ctx, Id value);
296Id EmitConvertF16S32(EmitContext& ctx, Id value);
297Id EmitConvertF16S64(EmitContext& ctx, Id value);
298Id EmitConvertF16U32(EmitContext& ctx, Id value);
299Id EmitConvertF16U64(EmitContext& ctx, Id value);
300Id EmitConvertF32S32(EmitContext& ctx, Id value);
301Id EmitConvertF32S64(EmitContext& ctx, Id value);
302Id EmitConvertF32U32(EmitContext& ctx, Id value);
303Id EmitConvertF32U64(EmitContext& ctx, Id value);
304Id EmitConvertF64S32(EmitContext& ctx, Id value);
305Id EmitConvertF64S64(EmitContext& ctx, Id value);
306Id EmitConvertF64U32(EmitContext& ctx, Id value);
307Id EmitConvertF64U64(EmitContext& ctx, Id value);
308Id EmitBindlessImageSampleImplicitLod(EmitContext&);
309Id EmitBindlessImageSampleExplicitLod(EmitContext&);
310Id EmitBindlessImageSampleDrefImplicitLod(EmitContext&);
311Id EmitBindlessImageSampleDrefExplicitLod(EmitContext&);
312Id EmitBoundImageSampleImplicitLod(EmitContext&);
313Id EmitBoundImageSampleExplicitLod(EmitContext&);
314Id EmitBoundImageSampleDrefImplicitLod(EmitContext&);
315Id EmitBoundImageSampleDrefExplicitLod(EmitContext&);
316Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
317 Id bias_lc, Id offset);
318Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
319 Id lod_lc, Id offset);
320Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
321 Id coords, Id dref, Id bias_lc, Id offset);
322Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
323 Id coords, Id dref, Id lod_lc, Id offset);
294 324
295} // namespace Shader::Backend::SPIRV 325} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp
index edcc2a1cc..2aff673aa 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp
@@ -102,4 +102,52 @@ Id EmitConvertF64F32(EmitContext& ctx, Id value) {
102 return ctx.OpFConvert(ctx.F64[1], value); 102 return ctx.OpFConvert(ctx.F64[1], value);
103} 103}
104 104
105Id EmitConvertF16S32(EmitContext& ctx, Id value) {
106 return ctx.OpConvertSToF(ctx.F16[1], value);
107}
108
109Id EmitConvertF16S64(EmitContext& ctx, Id value) {
110 return ctx.OpConvertSToF(ctx.F16[1], value);
111}
112
113Id EmitConvertF16U32(EmitContext& ctx, Id value) {
114 return ctx.OpConvertUToF(ctx.F16[1], value);
115}
116
117Id EmitConvertF16U64(EmitContext& ctx, Id value) {
118 return ctx.OpConvertUToF(ctx.F16[1], value);
119}
120
121Id EmitConvertF32S32(EmitContext& ctx, Id value) {
122 return ctx.OpConvertSToF(ctx.F32[1], value);
123}
124
125Id EmitConvertF32S64(EmitContext& ctx, Id value) {
126 return ctx.OpConvertSToF(ctx.F32[1], value);
127}
128
129Id EmitConvertF32U32(EmitContext& ctx, Id value) {
130 return ctx.OpConvertUToF(ctx.F32[1], value);
131}
132
133Id EmitConvertF32U64(EmitContext& ctx, Id value) {
134 return ctx.OpConvertUToF(ctx.F32[1], value);
135}
136
137Id EmitConvertF64S32(EmitContext& ctx, Id value) {
138 return ctx.OpConvertSToF(ctx.F64[1], value);
139}
140
141Id EmitConvertF64S64(EmitContext& ctx, Id value) {
142 return ctx.OpConvertSToF(ctx.F64[1], value);
143}
144
145Id EmitConvertF64U32(EmitContext& ctx, Id value) {
146 return ctx.OpConvertUToF(ctx.F64[1], value);
147}
148
149Id EmitConvertF64U64(EmitContext& ctx, Id value) {
150 return ctx.OpConvertUToF(ctx.F64[1], value);
151}
152
105} // namespace Shader::Backend::SPIRV 153} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
new file mode 100644
index 000000000..5f4783c95
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
@@ -0,0 +1,146 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <boost/container/static_vector.hpp>
6
7#include "shader_recompiler/backend/spirv/emit_spirv.h"
8#include "shader_recompiler/frontend/ir/modifiers.h"
9
10namespace Shader::Backend::SPIRV {
11namespace {
12class ImageOperands {
13public:
14 explicit ImageOperands(EmitContext& ctx, bool has_bias, bool has_lod, bool has_lod_clamp,
15 Id lod, Id offset) {
16 if (has_bias) {
17 const Id bias{has_lod_clamp ? ctx.OpCompositeExtract(ctx.F32[1], lod, 0) : lod};
18 Add(spv::ImageOperandsMask::Bias, bias);
19 }
20 if (has_lod) {
21 const Id lod_value{has_lod_clamp ? ctx.OpCompositeExtract(ctx.F32[1], lod, 0) : lod};
22 Add(spv::ImageOperandsMask::Lod, lod_value);
23 }
24 if (Sirit::ValidId(offset)) {
25 Add(spv::ImageOperandsMask::Offset, offset);
26 }
27 if (has_lod_clamp) {
28 const Id lod_clamp{has_bias ? ctx.OpCompositeExtract(ctx.F32[1], lod, 1) : lod};
29 Add(spv::ImageOperandsMask::MinLod, lod_clamp);
30 }
31 }
32
33 void Add(spv::ImageOperandsMask new_mask, Id value) {
34 mask = static_cast<spv::ImageOperandsMask>(static_cast<unsigned>(mask) |
35 static_cast<unsigned>(new_mask));
36 operands.push_back(value);
37 }
38
39 std::span<const Id> Span() const noexcept {
40 return std::span{operands.data(), operands.size()};
41 }
42
43 spv::ImageOperandsMask Mask() const noexcept {
44 return mask;
45 }
46
47private:
48 boost::container::static_vector<Id, 3> operands;
49 spv::ImageOperandsMask mask{};
50};
51
52Id Texture(EmitContext& ctx, const IR::Value& index) {
53 if (index.IsImmediate()) {
54 const TextureDefinition def{ctx.textures.at(index.U32())};
55 return ctx.OpLoad(def.type, def.id);
56 }
57 throw NotImplementedException("Indirect texture sample");
58}
59
60template <typename MethodPtrType, typename... Args>
61Id Emit(MethodPtrType sparse_ptr, MethodPtrType non_sparse_ptr, EmitContext& ctx, IR::Inst* inst,
62 Id result_type, Args&&... args) {
63 IR::Inst* const sparse{inst->GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp)};
64 if (!sparse) {
65 return (ctx.*non_sparse_ptr)(result_type, std::forward<Args>(args)...);
66 }
67 const Id struct_type{ctx.TypeStruct(ctx.U32[1], result_type)};
68 const Id sample{(ctx.*sparse_ptr)(struct_type, std::forward<Args>(args)...)};
69 const Id resident_code{ctx.OpCompositeExtract(ctx.U32[1], sample, 0U)};
70 sparse->SetDefinition(ctx.OpImageSparseTexelsResident(ctx.U1, resident_code));
71 sparse->Invalidate();
72 return ctx.OpCompositeExtract(result_type, sample, 1U);
73}
74} // Anonymous namespace
75
76Id EmitBindlessImageSampleImplicitLod(EmitContext&) {
77 throw LogicError("Unreachable instruction");
78}
79
80Id EmitBindlessImageSampleExplicitLod(EmitContext&) {
81 throw LogicError("Unreachable instruction");
82}
83
84Id EmitBindlessImageSampleDrefImplicitLod(EmitContext&) {
85 throw LogicError("Unreachable instruction");
86}
87
88Id EmitBindlessImageSampleDrefExplicitLod(EmitContext&) {
89 throw LogicError("Unreachable instruction");
90}
91
92Id EmitBoundImageSampleImplicitLod(EmitContext&) {
93 throw LogicError("Unreachable instruction");
94}
95
96Id EmitBoundImageSampleExplicitLod(EmitContext&) {
97 throw LogicError("Unreachable instruction");
98}
99
100Id EmitBoundImageSampleDrefImplicitLod(EmitContext&) {
101 throw LogicError("Unreachable instruction");
102}
103
104Id EmitBoundImageSampleDrefExplicitLod(EmitContext&) {
105 throw LogicError("Unreachable instruction");
106}
107
108Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
109 Id bias_lc, Id offset) {
110 const auto info{inst->Flags<IR::TextureInstInfo>()};
111 const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0, bias_lc,
112 offset);
113 return Emit(&EmitContext::OpImageSparseSampleImplicitLod,
114 &EmitContext::OpImageSampleImplicitLod, ctx, inst, ctx.F32[4], Texture(ctx, index),
115 coords, operands.Mask(), operands.Span());
116}
117
118Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
119 Id lod_lc, Id offset) {
120 const auto info{inst->Flags<IR::TextureInstInfo>()};
121 const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod_lc, offset);
122 return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
123 &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], Texture(ctx, index),
124 coords, operands.Mask(), operands.Span());
125}
126
127Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
128 Id coords, Id dref, Id bias_lc, Id offset) {
129 const auto info{inst->Flags<IR::TextureInstInfo>()};
130 const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0, bias_lc,
131 offset);
132 return Emit(&EmitContext::OpImageSparseSampleDrefImplicitLod,
133 &EmitContext::OpImageSampleDrefImplicitLod, ctx, inst, ctx.F32[1],
134 Texture(ctx, index), coords, dref, operands.Mask(), operands.Span());
135}
136
137Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
138 Id coords, Id dref, Id lod_lc, Id offset) {
139 const auto info{inst->Flags<IR::TextureInstInfo>()};
140 const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod_lc, offset);
141 return Emit(&EmitContext::OpImageSparseSampleDrefExplicitLod,
142 &EmitContext::OpImageSampleDrefExplicitLod, ctx, inst, ctx.F32[1],
143 Texture(ctx, index), coords, dref, operands.Mask(), operands.Span());
144}
145
146} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
index 808c1b401..7d3efc741 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
@@ -154,8 +154,22 @@ void EmitWriteStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Va
154 ctx.OpStore(high_pointer, ctx.OpCompositeExtract(ctx.U32[1], value, 1U)); 154 ctx.OpStore(high_pointer, ctx.OpCompositeExtract(ctx.U32[1], value, 1U));
155} 155}
156 156
157void EmitWriteStorage128(EmitContext&) { 157void EmitWriteStorage128(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
158 throw NotImplementedException("SPIR-V Instruction"); 158 Id value) {
159 if (!binding.IsImmediate()) {
160 throw NotImplementedException("Dynamic storage buffer indexing");
161 }
162 // TODO: Support reinterpreting bindings, guaranteed to be aligned
163 const Id ssbo{ctx.ssbos[binding.U32()]};
164 const Id base_index{StorageIndex(ctx, offset, sizeof(u32))};
165 for (u32 element = 0; element < 4; ++element) {
166 Id index = base_index;
167 if (element > 0) {
168 index = ctx.OpIAdd(ctx.U32[1], base_index, ctx.Constant(ctx.U32[1], element));
169 }
170 const Id pointer{ctx.OpAccessChain(ctx.storage_u32, ssbo, ctx.u32_zero_value, index)};
171 ctx.OpStore(pointer, ctx.OpCompositeExtract(ctx.U32[1], value, element));
172 }
159} 173}
160 174
161} // namespace Shader::Backend::SPIRV 175} // namespace Shader::Backend::SPIRV