summaryrefslogtreecommitdiff
path: root/src/shader_recompiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler')
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.h4
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp51
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp7
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h4
-rw-r--r--src/shader_recompiler/frontend/ir/modifiers.h1
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc3
-rw-r--r--src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp11
-rw-r--r--src/shader_recompiler/ir_opt/texture_pass.cpp5
8 files changed, 84 insertions, 2 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h
index 105c23745..9c9e0c5dd 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.h
@@ -363,6 +363,7 @@ Id EmitBindlessImageGatherDref(EmitContext&);
363Id EmitBindlessImageFetch(EmitContext&); 363Id EmitBindlessImageFetch(EmitContext&);
364Id EmitBindlessImageQueryDimensions(EmitContext&); 364Id EmitBindlessImageQueryDimensions(EmitContext&);
365Id EmitBindlessImageQueryLod(EmitContext&); 365Id EmitBindlessImageQueryLod(EmitContext&);
366Id EmitBindlessImageGradient(EmitContext&);
366Id EmitBoundImageSampleImplicitLod(EmitContext&); 367Id EmitBoundImageSampleImplicitLod(EmitContext&);
367Id EmitBoundImageSampleExplicitLod(EmitContext&); 368Id EmitBoundImageSampleExplicitLod(EmitContext&);
368Id EmitBoundImageSampleDrefImplicitLod(EmitContext&); 369Id EmitBoundImageSampleDrefImplicitLod(EmitContext&);
@@ -372,6 +373,7 @@ Id EmitBoundImageGatherDref(EmitContext&);
372Id EmitBoundImageFetch(EmitContext&); 373Id EmitBoundImageFetch(EmitContext&);
373Id EmitBoundImageQueryDimensions(EmitContext&); 374Id EmitBoundImageQueryDimensions(EmitContext&);
374Id EmitBoundImageQueryLod(EmitContext&); 375Id EmitBoundImageQueryLod(EmitContext&);
376Id EmitBoundImageGradient(EmitContext&);
375Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 377Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
376 Id bias_lc, Id offset); 378 Id bias_lc, Id offset);
377Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 379Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
@@ -388,6 +390,8 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c
388 Id lod, Id ms); 390 Id lod, Id ms);
389Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod); 391Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod);
390Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); 392Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
393Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
394 Id derivates, Id offset, Id lod_clamp);
391Id EmitVoteAll(EmitContext& ctx, Id pred); 395Id EmitVoteAll(EmitContext& ctx, Id pred);
392Id EmitVoteAny(EmitContext& ctx, Id pred); 396Id EmitVoteAny(EmitContext& ctx, Id pred);
393Id EmitVoteEqual(EmitContext& ctx, Id pred); 397Id EmitVoteEqual(EmitContext& ctx, Id pred);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
index 9f8fe2603..1eba9cc00 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
@@ -69,12 +69,44 @@ public:
69 } 69 }
70 } 70 }
71 71
72 explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivates, u32 num_derivates,
73 Id offset, Id lod_clamp) {
74 if (Sirit::ValidId(derivates)) {
75 boost::container::static_vector<Id, 3> deriv_x_accum;
76 boost::container::static_vector<Id, 3> deriv_y_accum;
77 for (size_t i = 0; i < num_derivates; i++) {
78 deriv_x_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivates, i * 2));
79 deriv_y_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivates, i * 2 + 1));
80 }
81 Id derivates_X = ctx.OpCompositeConstruct(
82 ctx.F32[num_derivates], std::span{deriv_x_accum.data(), deriv_x_accum.size()});
83 Id derivates_Y = ctx.OpCompositeConstruct(
84 ctx.F32[num_derivates], std::span{deriv_y_accum.data(), deriv_y_accum.size()});
85 Add(spv::ImageOperandsMask::Grad, derivates_X, derivates_Y);
86 } else {
87 throw LogicError("Derivates must be present");
88 }
89 if (Sirit::ValidId(offset)) {
90 Add(spv::ImageOperandsMask::Offset, offset);
91 }
92 if (has_lod_clamp) {
93 Add(spv::ImageOperandsMask::MinLod, lod_clamp);
94 }
95 }
96
72 void Add(spv::ImageOperandsMask new_mask, Id value) { 97 void Add(spv::ImageOperandsMask new_mask, Id value) {
73 mask = static_cast<spv::ImageOperandsMask>(static_cast<unsigned>(mask) | 98 mask = static_cast<spv::ImageOperandsMask>(static_cast<unsigned>(mask) |
74 static_cast<unsigned>(new_mask)); 99 static_cast<unsigned>(new_mask));
75 operands.push_back(value); 100 operands.push_back(value);
76 } 101 }
77 102
103 void Add(spv::ImageOperandsMask new_mask, Id value, Id value_2) {
104 mask = static_cast<spv::ImageOperandsMask>(static_cast<unsigned>(mask) |
105 static_cast<unsigned>(new_mask));
106 operands.push_back(value);
107 operands.push_back(value_2);
108 }
109
78 std::span<const Id> Span() const noexcept { 110 std::span<const Id> Span() const noexcept {
79 return std::span{operands.data(), operands.size()}; 111 return std::span{operands.data(), operands.size()};
80 } 112 }
@@ -84,7 +116,7 @@ public:
84 } 116 }
85 117
86private: 118private:
87 boost::container::static_vector<Id, 3> operands; 119 boost::container::static_vector<Id, 4> operands;
88 spv::ImageOperandsMask mask{}; 120 spv::ImageOperandsMask mask{};
89}; 121};
90 122
@@ -165,6 +197,10 @@ Id EmitBindlessImageQueryLod(EmitContext&) {
165 throw LogicError("Unreachable instruction"); 197 throw LogicError("Unreachable instruction");
166} 198}
167 199
200Id EmitBindlessImageGradient(EmitContext&) {
201 throw LogicError("Unreachable instruction");
202}
203
168Id EmitBoundImageSampleImplicitLod(EmitContext&) { 204Id EmitBoundImageSampleImplicitLod(EmitContext&) {
169 throw LogicError("Unreachable instruction"); 205 throw LogicError("Unreachable instruction");
170} 206}
@@ -201,6 +237,10 @@ Id EmitBoundImageQueryLod(EmitContext&) {
201 throw LogicError("Unreachable instruction"); 237 throw LogicError("Unreachable instruction");
202} 238}
203 239
240Id EmitBoundImageGradient(EmitContext&) {
241 throw LogicError("Unreachable instruction");
242}
243
204Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 244Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
205 Id bias_lc, Id offset) { 245 Id bias_lc, Id offset) {
206 const auto info{inst->Flags<IR::TextureInstInfo>()}; 246 const auto info{inst->Flags<IR::TextureInstInfo>()};
@@ -302,4 +342,13 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst*, const IR::Value& index, Id coo
302 zero, zero); 342 zero, zero);
303} 343}
304 344
345Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
346 Id derivates, Id offset, Id lod_clamp) {
347 const auto info{inst->Flags<IR::TextureInstInfo>()};
348 const ImageOperands operands(ctx, info.has_lod_clamp != 0, derivates, info.num_derivates, offset, lod_clamp);
349 return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
350 &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], Texture(ctx, index),
351 coords, operands.Mask(), operands.Span());
352}
353
305} // namespace Shader::Backend::SPIRV 354} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index f6818ec8a..edf8c05d4 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -1573,6 +1573,13 @@ Value IREmitter::ImageQueryLod(const Value& handle, const Value& coords, Texture
1573 return Inst(op, Flags{info}, handle, coords); 1573 return Inst(op, Flags{info}, handle, coords);
1574} 1574}
1575 1575
1576Value IREmitter::ImageGradient(const Value& handle, const Value& coords, const Value& derivates,
1577 const Value& offset, const F32& lod_clamp, TextureInstInfo info) {
1578 const Opcode op{handle.IsImmediate() ? Opcode::BoundImageGradient
1579 : Opcode::BindlessImageGradient};
1580 return Inst(op, Flags{info}, handle, coords, derivates, offset, lod_clamp);
1581}
1582
1576U1 IREmitter::VoteAll(const U1& value) { 1583U1 IREmitter::VoteAll(const U1& value) {
1577 return Inst<U1>(Opcode::VoteAll, value); 1584 return Inst<U1>(Opcode::VoteAll, value);
1578} 1585}
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index 2beeace8f..a4616e247 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -268,6 +268,10 @@ public:
268 [[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const Value& offset, 268 [[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const Value& offset,
269 const U32& lod, const U32& multisampling, TextureInstInfo info); 269 const U32& lod, const U32& multisampling, TextureInstInfo info);
270 270
271 [[nodiscard]] Value ImageGradient(const Value& handle, const Value& coords,
272 const Value& derivates, const Value& offset,
273 const F32& lod_clamp, TextureInstInfo info);
274
271 [[nodiscard]] U1 VoteAll(const U1& value); 275 [[nodiscard]] U1 VoteAll(const U1& value);
272 [[nodiscard]] U1 VoteAny(const U1& value); 276 [[nodiscard]] U1 VoteAny(const U1& value);
273 [[nodiscard]] U1 VoteEqual(const U1& value); 277 [[nodiscard]] U1 VoteEqual(const U1& value);
diff --git a/src/shader_recompiler/frontend/ir/modifiers.h b/src/shader_recompiler/frontend/ir/modifiers.h
index 4f09a4b39..90078f535 100644
--- a/src/shader_recompiler/frontend/ir/modifiers.h
+++ b/src/shader_recompiler/frontend/ir/modifiers.h
@@ -39,6 +39,7 @@ union TextureInstInfo {
39 BitField<9, 1, u32> has_lod_clamp; 39 BitField<9, 1, u32> has_lod_clamp;
40 BitField<10, 1, u32> relaxed_precision; 40 BitField<10, 1, u32> relaxed_precision;
41 BitField<11, 2, u32> gather_component; 41 BitField<11, 2, u32> gather_component;
42 BitField<13, 2, u32> num_derivates;
42}; 43};
43static_assert(sizeof(TextureInstInfo) <= sizeof(u32)); 44static_assert(sizeof(TextureInstInfo) <= sizeof(u32));
44 45
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc
index 49cdcd57f..79baacd08 100644
--- a/src/shader_recompiler/frontend/ir/opcodes.inc
+++ b/src/shader_recompiler/frontend/ir/opcodes.inc
@@ -381,6 +381,7 @@ OPCODE(BindlessImageGatherDref, F32x4, U32,
381OPCODE(BindlessImageFetch, F32x4, U32, Opaque, Opaque, Opaque, Opaque, ) 381OPCODE(BindlessImageFetch, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
382OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, ) 382OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, )
383OPCODE(BindlessImageQueryLod, F32x4, U32, Opaque, ) 383OPCODE(BindlessImageQueryLod, F32x4, U32, Opaque, )
384OPCODE(BindlessImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
384 385
385OPCODE(BoundImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) 386OPCODE(BoundImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
386OPCODE(BoundImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) 387OPCODE(BoundImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
@@ -391,6 +392,7 @@ OPCODE(BoundImageGatherDref, F32x4, U32,
391OPCODE(BoundImageFetch, F32x4, U32, Opaque, Opaque, Opaque, Opaque, ) 392OPCODE(BoundImageFetch, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
392OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, ) 393OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, )
393OPCODE(BoundImageQueryLod, F32x4, U32, Opaque, ) 394OPCODE(BoundImageQueryLod, F32x4, U32, Opaque, )
395OPCODE(BoundImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
394 396
395OPCODE(ImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) 397OPCODE(ImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
396OPCODE(ImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) 398OPCODE(ImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
@@ -401,6 +403,7 @@ OPCODE(ImageGatherDref, F32x4, U32,
401OPCODE(ImageFetch, F32x4, U32, Opaque, Opaque, Opaque, Opaque, ) 403OPCODE(ImageFetch, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
402OPCODE(ImageQueryDimensions, U32x4, U32, U32, ) 404OPCODE(ImageQueryDimensions, U32x4, U32, U32, )
403OPCODE(ImageQueryLod, F32x4, U32, Opaque, ) 405OPCODE(ImageQueryLod, F32x4, U32, Opaque, )
406OPCODE(ImageGradient, F32x4, U32, Opaque, Opaque, Opaque, F32, )
404 407
405// Warp operations 408// Warp operations
406OPCODE(VoteAll, U1, U1, ) 409OPCODE(VoteAll, U1, U1, )
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
index 04e3a4f53..730d3e91e 100644
--- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
+++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
@@ -370,12 +370,20 @@ void VisitUsages(Info& info, IR::Inst& inst) {
370 case IR::Opcode::BindlessImageSampleDrefExplicitLod: 370 case IR::Opcode::BindlessImageSampleDrefExplicitLod:
371 case IR::Opcode::BindlessImageGather: 371 case IR::Opcode::BindlessImageGather:
372 case IR::Opcode::BindlessImageGatherDref: 372 case IR::Opcode::BindlessImageGatherDref:
373 case IR::Opcode::BindlessImageFetch:
374 case IR::Opcode::BindlessImageQueryDimensions:
375 case IR::Opcode::BindlessImageQueryLod:
376 case IR::Opcode::BindlessImageGradient:
373 case IR::Opcode::BoundImageSampleImplicitLod: 377 case IR::Opcode::BoundImageSampleImplicitLod:
374 case IR::Opcode::BoundImageSampleExplicitLod: 378 case IR::Opcode::BoundImageSampleExplicitLod:
375 case IR::Opcode::BoundImageSampleDrefImplicitLod: 379 case IR::Opcode::BoundImageSampleDrefImplicitLod:
376 case IR::Opcode::BoundImageSampleDrefExplicitLod: 380 case IR::Opcode::BoundImageSampleDrefExplicitLod:
377 case IR::Opcode::BoundImageGather: 381 case IR::Opcode::BoundImageGather:
378 case IR::Opcode::BoundImageGatherDref: 382 case IR::Opcode::BoundImageGatherDref:
383 case IR::Opcode::BoundImageFetch:
384 case IR::Opcode::BoundImageQueryDimensions:
385 case IR::Opcode::BoundImageQueryLod:
386 case IR::Opcode::BoundImageGradient:
379 case IR::Opcode::ImageSampleImplicitLod: 387 case IR::Opcode::ImageSampleImplicitLod:
380 case IR::Opcode::ImageSampleExplicitLod: 388 case IR::Opcode::ImageSampleExplicitLod:
381 case IR::Opcode::ImageSampleDrefImplicitLod: 389 case IR::Opcode::ImageSampleDrefImplicitLod:
@@ -384,7 +392,8 @@ void VisitUsages(Info& info, IR::Inst& inst) {
384 case IR::Opcode::ImageGatherDref: 392 case IR::Opcode::ImageGatherDref:
385 case IR::Opcode::ImageFetch: 393 case IR::Opcode::ImageFetch:
386 case IR::Opcode::ImageQueryDimensions: 394 case IR::Opcode::ImageQueryDimensions:
387 case IR::Opcode::ImageQueryLod: { 395 case IR::Opcode::ImageQueryLod:
396 case IR::Opcode::ImageGradient: {
388 const TextureType type{inst.Flags<IR::TextureInstInfo>().type}; 397 const TextureType type{inst.Flags<IR::TextureInstInfo>().type};
389 info.uses_sampled_1d |= type == TextureType::Color1D || type == TextureType::ColorArray1D || 398 info.uses_sampled_1d |= type == TextureType::Color1D || type == TextureType::ColorArray1D ||
390 type == TextureType::Shadow1D || type == TextureType::ShadowArray1D; 399 type == TextureType::Shadow1D || type == TextureType::ShadowArray1D;
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp
index 6eb286b83..da8977b76 100644
--- a/src/shader_recompiler/ir_opt/texture_pass.cpp
+++ b/src/shader_recompiler/ir_opt/texture_pass.cpp
@@ -60,6 +60,9 @@ IR::Opcode IndexedInstruction(const IR::Inst& inst) {
60 case IR::Opcode::BoundImageQueryLod: 60 case IR::Opcode::BoundImageQueryLod:
61 case IR::Opcode::BindlessImageQueryLod: 61 case IR::Opcode::BindlessImageQueryLod:
62 return IR::Opcode::ImageQueryLod; 62 return IR::Opcode::ImageQueryLod;
63 case IR::Opcode::BoundImageGradient:
64 case IR::Opcode::BindlessImageGradient:
65 return IR::Opcode::ImageGradient;
63 default: 66 default:
64 return IR::Opcode::Void; 67 return IR::Opcode::Void;
65 } 68 }
@@ -76,6 +79,7 @@ bool IsBindless(const IR::Inst& inst) {
76 case IR::Opcode::BindlessImageFetch: 79 case IR::Opcode::BindlessImageFetch:
77 case IR::Opcode::BindlessImageQueryDimensions: 80 case IR::Opcode::BindlessImageQueryDimensions:
78 case IR::Opcode::BindlessImageQueryLod: 81 case IR::Opcode::BindlessImageQueryLod:
82 case IR::Opcode::BindlessImageGradient:
79 return true; 83 return true;
80 case IR::Opcode::BoundImageSampleImplicitLod: 84 case IR::Opcode::BoundImageSampleImplicitLod:
81 case IR::Opcode::BoundImageSampleExplicitLod: 85 case IR::Opcode::BoundImageSampleExplicitLod:
@@ -86,6 +90,7 @@ bool IsBindless(const IR::Inst& inst) {
86 case IR::Opcode::BoundImageFetch: 90 case IR::Opcode::BoundImageFetch:
87 case IR::Opcode::BoundImageQueryDimensions: 91 case IR::Opcode::BoundImageQueryDimensions:
88 case IR::Opcode::BoundImageQueryLod: 92 case IR::Opcode::BoundImageQueryLod:
93 case IR::Opcode::BoundImageGradient:
89 return false; 94 return false;
90 default: 95 default:
91 throw InvalidArgument("Invalid opcode {}", inst.Opcode()); 96 throw InvalidArgument("Invalid opcode {}", inst.Opcode());