summaryrefslogtreecommitdiffstats
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&);
Id EmitBindlessImageFetch(EmitContext&);
Id EmitBindlessImageQueryDimensions(EmitContext&);
Id EmitBindlessImageQueryLod(EmitContext&);
+Id EmitBindlessImageGradient(EmitContext&);
Id EmitBoundImageSampleImplicitLod(EmitContext&);
Id EmitBoundImageSampleExplicitLod(EmitContext&);
Id EmitBoundImageSampleDrefImplicitLod(EmitContext&);
@@ -372,6 +373,7 @@ Id EmitBoundImageGatherDref(EmitContext&);
Id EmitBoundImageFetch(EmitContext&);
Id EmitBoundImageQueryDimensions(EmitContext&);
Id EmitBoundImageQueryLod(EmitContext&);
+Id EmitBoundImageGradient(EmitContext&);
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id bias_lc, Id offset);
Id 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
Id lod, Id ms);
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod);
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
+Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
+ Id derivates, Id offset, Id lod_clamp);
Id EmitVoteAll(EmitContext& ctx, Id pred);
Id EmitVoteAny(EmitContext& ctx, Id pred);
Id 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:
}
}
+ explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivates, u32 num_derivates,
+ Id offset, Id lod_clamp) {
+ if (Sirit::ValidId(derivates)) {
+ boost::container::static_vector<Id, 3> deriv_x_accum;
+ boost::container::static_vector<Id, 3> deriv_y_accum;
+ for (size_t i = 0; i < num_derivates; i++) {
+ deriv_x_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivates, i * 2));
+ deriv_y_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivates, i * 2 + 1));
+ }
+ Id derivates_X = ctx.OpCompositeConstruct(
+ ctx.F32[num_derivates], std::span{deriv_x_accum.data(), deriv_x_accum.size()});
+ Id derivates_Y = ctx.OpCompositeConstruct(
+ ctx.F32[num_derivates], std::span{deriv_y_accum.data(), deriv_y_accum.size()});
+ Add(spv::ImageOperandsMask::Grad, derivates_X, derivates_Y);
+ } else {
+ throw LogicError("Derivates must be present");
+ }
+ if (Sirit::ValidId(offset)) {
+ Add(spv::ImageOperandsMask::Offset, offset);
+ }
+ if (has_lod_clamp) {
+ Add(spv::ImageOperandsMask::MinLod, lod_clamp);
+ }
+ }
+
void Add(spv::ImageOperandsMask new_mask, Id value) {
mask = static_cast<spv::ImageOperandsMask>(static_cast<unsigned>(mask) |
static_cast<unsigned>(new_mask));
operands.push_back(value);
}
+ void Add(spv::ImageOperandsMask new_mask, Id value, Id value_2) {
+ mask = static_cast<spv::ImageOperandsMask>(static_cast<unsigned>(mask) |
+ static_cast<unsigned>(new_mask));
+ operands.push_back(value);
+ operands.push_back(value_2);
+ }
+
std::span<const Id> Span() const noexcept {
return std::span{operands.data(), operands.size()};
}
@@ -84,7 +116,7 @@ public:
}
private:
- boost::container::static_vector<Id, 3> operands;
+ boost::container::static_vector<Id, 4> operands;
spv::ImageOperandsMask mask{};
};
@@ -165,6 +197,10 @@ Id EmitBindlessImageQueryLod(EmitContext&) {
throw LogicError("Unreachable instruction");
}
+Id EmitBindlessImageGradient(EmitContext&) {
+ throw LogicError("Unreachable instruction");
+}
+
Id EmitBoundImageSampleImplicitLod(EmitContext&) {
throw LogicError("Unreachable instruction");
}
@@ -201,6 +237,10 @@ Id EmitBoundImageQueryLod(EmitContext&) {
throw LogicError("Unreachable instruction");
}
+Id EmitBoundImageGradient(EmitContext&) {
+ throw LogicError("Unreachable instruction");
+}
+
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id bias_lc, Id offset) {
const auto info{inst->Flags<IR::TextureInstInfo>()};
@@ -302,4 +342,13 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst*, const IR::Value& index, Id coo
zero, zero);
}
+Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
+ Id derivates, Id offset, Id lod_clamp) {
+ const auto info{inst->Flags<IR::TextureInstInfo>()};
+ const ImageOperands operands(ctx, info.has_lod_clamp != 0, derivates, info.num_derivates, offset, lod_clamp);
+ return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
+ &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], Texture(ctx, index),
+ coords, operands.Mask(), operands.Span());
+}
+
} // 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
return Inst(op, Flags{info}, handle, coords);
}
+Value IREmitter::ImageGradient(const Value& handle, const Value& coords, const Value& derivates,
+ const Value& offset, const F32& lod_clamp, TextureInstInfo info) {
+ const Opcode op{handle.IsImmediate() ? Opcode::BoundImageGradient
+ : Opcode::BindlessImageGradient};
+ return Inst(op, Flags{info}, handle, coords, derivates, offset, lod_clamp);
+}
+
U1 IREmitter::VoteAll(const U1& value) {
return Inst<U1>(Opcode::VoteAll, value);
}
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:
[[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const Value& offset,
const U32& lod, const U32& multisampling, TextureInstInfo info);
+ [[nodiscard]] Value ImageGradient(const Value& handle, const Value& coords,
+ const Value& derivates, const Value& offset,
+ const F32& lod_clamp, TextureInstInfo info);
+
[[nodiscard]] U1 VoteAll(const U1& value);
[[nodiscard]] U1 VoteAny(const U1& value);
[[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 {
BitField<9, 1, u32> has_lod_clamp;
BitField<10, 1, u32> relaxed_precision;
BitField<11, 2, u32> gather_component;
+ BitField<13, 2, u32> num_derivates;
};
static_assert(sizeof(TextureInstInfo) <= sizeof(u32));
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,
OPCODE(BindlessImageFetch, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, )
OPCODE(BindlessImageQueryLod, F32x4, U32, Opaque, )
+OPCODE(BindlessImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
OPCODE(BoundImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
OPCODE(BoundImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
@@ -391,6 +392,7 @@ OPCODE(BoundImageGatherDref, F32x4, U32,
OPCODE(BoundImageFetch, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, )
OPCODE(BoundImageQueryLod, F32x4, U32, Opaque, )
+OPCODE(BoundImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
OPCODE(ImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
OPCODE(ImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
@@ -401,6 +403,7 @@ OPCODE(ImageGatherDref, F32x4, U32,
OPCODE(ImageFetch, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
OPCODE(ImageQueryDimensions, U32x4, U32, U32, )
OPCODE(ImageQueryLod, F32x4, U32, Opaque, )
+OPCODE(ImageGradient, F32x4, U32, Opaque, Opaque, Opaque, F32, )
// Warp operations
OPCODE(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) {
case IR::Opcode::BindlessImageSampleDrefExplicitLod:
case IR::Opcode::BindlessImageGather:
case IR::Opcode::BindlessImageGatherDref:
+ case IR::Opcode::BindlessImageFetch:
+ case IR::Opcode::BindlessImageQueryDimensions:
+ case IR::Opcode::BindlessImageQueryLod:
+ case IR::Opcode::BindlessImageGradient:
case IR::Opcode::BoundImageSampleImplicitLod:
case IR::Opcode::BoundImageSampleExplicitLod:
case IR::Opcode::BoundImageSampleDrefImplicitLod:
case IR::Opcode::BoundImageSampleDrefExplicitLod:
case IR::Opcode::BoundImageGather:
case IR::Opcode::BoundImageGatherDref:
+ case IR::Opcode::BoundImageFetch:
+ case IR::Opcode::BoundImageQueryDimensions:
+ case IR::Opcode::BoundImageQueryLod:
+ case IR::Opcode::BoundImageGradient:
case IR::Opcode::ImageSampleImplicitLod:
case IR::Opcode::ImageSampleExplicitLod:
case IR::Opcode::ImageSampleDrefImplicitLod:
@@ -384,7 +392,8 @@ void VisitUsages(Info& info, IR::Inst& inst) {
case IR::Opcode::ImageGatherDref:
case IR::Opcode::ImageFetch:
case IR::Opcode::ImageQueryDimensions:
- case IR::Opcode::ImageQueryLod: {
+ case IR::Opcode::ImageQueryLod:
+ case IR::Opcode::ImageGradient: {
const TextureType type{inst.Flags<IR::TextureInstInfo>().type};
info.uses_sampled_1d |= type == TextureType::Color1D || type == TextureType::ColorArray1D ||
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) {
case IR::Opcode::BoundImageQueryLod:
case IR::Opcode::BindlessImageQueryLod:
return IR::Opcode::ImageQueryLod;
+ case IR::Opcode::BoundImageGradient:
+ case IR::Opcode::BindlessImageGradient:
+ return IR::Opcode::ImageGradient;
default:
return IR::Opcode::Void;
}
@@ -76,6 +79,7 @@ bool IsBindless(const IR::Inst& inst) {
case IR::Opcode::BindlessImageFetch:
case IR::Opcode::BindlessImageQueryDimensions:
case IR::Opcode::BindlessImageQueryLod:
+ case IR::Opcode::BindlessImageGradient:
return true;
case IR::Opcode::BoundImageSampleImplicitLod:
case IR::Opcode::BoundImageSampleExplicitLod:
@@ -86,6 +90,7 @@ bool IsBindless(const IR::Inst& inst) {
case IR::Opcode::BoundImageFetch:
case IR::Opcode::BoundImageQueryDimensions:
case IR::Opcode::BoundImageQueryLod:
+ case IR::Opcode::BoundImageGradient:
return false;
default:
throw InvalidArgument("Invalid opcode {}", inst.Opcode());