shader: Implement ImageGradient
This commit is contained in:
parent
be3e94ae55
commit
d5bfc63088
8 changed files with 84 additions and 2 deletions
|
@ -363,6 +363,7 @@ Id EmitBindlessImageGatherDref(EmitContext&);
|
||||||
Id EmitBindlessImageFetch(EmitContext&);
|
Id EmitBindlessImageFetch(EmitContext&);
|
||||||
Id EmitBindlessImageQueryDimensions(EmitContext&);
|
Id EmitBindlessImageQueryDimensions(EmitContext&);
|
||||||
Id EmitBindlessImageQueryLod(EmitContext&);
|
Id EmitBindlessImageQueryLod(EmitContext&);
|
||||||
|
Id EmitBindlessImageGradient(EmitContext&);
|
||||||
Id EmitBoundImageSampleImplicitLod(EmitContext&);
|
Id EmitBoundImageSampleImplicitLod(EmitContext&);
|
||||||
Id EmitBoundImageSampleExplicitLod(EmitContext&);
|
Id EmitBoundImageSampleExplicitLod(EmitContext&);
|
||||||
Id EmitBoundImageSampleDrefImplicitLod(EmitContext&);
|
Id EmitBoundImageSampleDrefImplicitLod(EmitContext&);
|
||||||
|
@ -372,6 +373,7 @@ Id EmitBoundImageGatherDref(EmitContext&);
|
||||||
Id EmitBoundImageFetch(EmitContext&);
|
Id EmitBoundImageFetch(EmitContext&);
|
||||||
Id EmitBoundImageQueryDimensions(EmitContext&);
|
Id EmitBoundImageQueryDimensions(EmitContext&);
|
||||||
Id EmitBoundImageQueryLod(EmitContext&);
|
Id EmitBoundImageQueryLod(EmitContext&);
|
||||||
|
Id EmitBoundImageGradient(EmitContext&);
|
||||||
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||||
Id bias_lc, Id offset);
|
Id bias_lc, Id offset);
|
||||||
Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
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 lod, Id ms);
|
||||||
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod);
|
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 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 EmitVoteAll(EmitContext& ctx, Id pred);
|
||||||
Id EmitVoteAny(EmitContext& ctx, Id pred);
|
Id EmitVoteAny(EmitContext& ctx, Id pred);
|
||||||
Id EmitVoteEqual(EmitContext& ctx, Id pred);
|
Id EmitVoteEqual(EmitContext& ctx, Id pred);
|
||||||
|
|
|
@ -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) {
|
void Add(spv::ImageOperandsMask new_mask, Id value) {
|
||||||
mask = static_cast<spv::ImageOperandsMask>(static_cast<unsigned>(mask) |
|
mask = static_cast<spv::ImageOperandsMask>(static_cast<unsigned>(mask) |
|
||||||
static_cast<unsigned>(new_mask));
|
static_cast<unsigned>(new_mask));
|
||||||
operands.push_back(value);
|
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 {
|
std::span<const Id> Span() const noexcept {
|
||||||
return std::span{operands.data(), operands.size()};
|
return std::span{operands.data(), operands.size()};
|
||||||
}
|
}
|
||||||
|
@ -84,7 +116,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
boost::container::static_vector<Id, 3> operands;
|
boost::container::static_vector<Id, 4> operands;
|
||||||
spv::ImageOperandsMask mask{};
|
spv::ImageOperandsMask mask{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -165,6 +197,10 @@ Id EmitBindlessImageQueryLod(EmitContext&) {
|
||||||
throw LogicError("Unreachable instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Id EmitBindlessImageGradient(EmitContext&) {
|
||||||
|
throw LogicError("Unreachable instruction");
|
||||||
|
}
|
||||||
|
|
||||||
Id EmitBoundImageSampleImplicitLod(EmitContext&) {
|
Id EmitBoundImageSampleImplicitLod(EmitContext&) {
|
||||||
throw LogicError("Unreachable instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
@ -201,6 +237,10 @@ Id EmitBoundImageQueryLod(EmitContext&) {
|
||||||
throw LogicError("Unreachable instruction");
|
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 EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||||
Id bias_lc, Id offset) {
|
Id bias_lc, Id offset) {
|
||||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
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);
|
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
|
} // namespace Shader::Backend::SPIRV
|
||||||
|
|
|
@ -1573,6 +1573,13 @@ Value IREmitter::ImageQueryLod(const Value& handle, const Value& coords, Texture
|
||||||
return Inst(op, Flags{info}, handle, coords);
|
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) {
|
U1 IREmitter::VoteAll(const U1& value) {
|
||||||
return Inst<U1>(Opcode::VoteAll, value);
|
return Inst<U1>(Opcode::VoteAll, value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,6 +268,10 @@ public:
|
||||||
[[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const Value& offset,
|
[[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const Value& offset,
|
||||||
const U32& lod, const U32& multisampling, TextureInstInfo info);
|
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 VoteAll(const U1& value);
|
||||||
[[nodiscard]] U1 VoteAny(const U1& value);
|
[[nodiscard]] U1 VoteAny(const U1& value);
|
||||||
[[nodiscard]] U1 VoteEqual(const U1& value);
|
[[nodiscard]] U1 VoteEqual(const U1& value);
|
||||||
|
|
|
@ -39,6 +39,7 @@ union TextureInstInfo {
|
||||||
BitField<9, 1, u32> has_lod_clamp;
|
BitField<9, 1, u32> has_lod_clamp;
|
||||||
BitField<10, 1, u32> relaxed_precision;
|
BitField<10, 1, u32> relaxed_precision;
|
||||||
BitField<11, 2, u32> gather_component;
|
BitField<11, 2, u32> gather_component;
|
||||||
|
BitField<13, 2, u32> num_derivates;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(TextureInstInfo) <= sizeof(u32));
|
static_assert(sizeof(TextureInstInfo) <= sizeof(u32));
|
||||||
|
|
||||||
|
|
|
@ -381,6 +381,7 @@ OPCODE(BindlessImageGatherDref, F32x4, U32,
|
||||||
OPCODE(BindlessImageFetch, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
|
OPCODE(BindlessImageFetch, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
|
||||||
OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, )
|
OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, )
|
||||||
OPCODE(BindlessImageQueryLod, F32x4, U32, Opaque, )
|
OPCODE(BindlessImageQueryLod, F32x4, U32, Opaque, )
|
||||||
|
OPCODE(BindlessImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
|
||||||
|
|
||||||
OPCODE(BoundImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
|
OPCODE(BoundImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
|
||||||
OPCODE(BoundImageSampleExplicitLod, 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(BoundImageFetch, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
|
||||||
OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, )
|
OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, )
|
||||||
OPCODE(BoundImageQueryLod, F32x4, U32, Opaque, )
|
OPCODE(BoundImageQueryLod, F32x4, U32, Opaque, )
|
||||||
|
OPCODE(BoundImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
|
||||||
|
|
||||||
OPCODE(ImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
|
OPCODE(ImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
|
||||||
OPCODE(ImageSampleExplicitLod, 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(ImageFetch, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
|
||||||
OPCODE(ImageQueryDimensions, U32x4, U32, U32, )
|
OPCODE(ImageQueryDimensions, U32x4, U32, U32, )
|
||||||
OPCODE(ImageQueryLod, F32x4, U32, Opaque, )
|
OPCODE(ImageQueryLod, F32x4, U32, Opaque, )
|
||||||
|
OPCODE(ImageGradient, F32x4, U32, Opaque, Opaque, Opaque, F32, )
|
||||||
|
|
||||||
// Warp operations
|
// Warp operations
|
||||||
OPCODE(VoteAll, U1, U1, )
|
OPCODE(VoteAll, U1, U1, )
|
||||||
|
|
|
@ -370,12 +370,20 @@ void VisitUsages(Info& info, IR::Inst& inst) {
|
||||||
case IR::Opcode::BindlessImageSampleDrefExplicitLod:
|
case IR::Opcode::BindlessImageSampleDrefExplicitLod:
|
||||||
case IR::Opcode::BindlessImageGather:
|
case IR::Opcode::BindlessImageGather:
|
||||||
case IR::Opcode::BindlessImageGatherDref:
|
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::BoundImageSampleImplicitLod:
|
||||||
case IR::Opcode::BoundImageSampleExplicitLod:
|
case IR::Opcode::BoundImageSampleExplicitLod:
|
||||||
case IR::Opcode::BoundImageSampleDrefImplicitLod:
|
case IR::Opcode::BoundImageSampleDrefImplicitLod:
|
||||||
case IR::Opcode::BoundImageSampleDrefExplicitLod:
|
case IR::Opcode::BoundImageSampleDrefExplicitLod:
|
||||||
case IR::Opcode::BoundImageGather:
|
case IR::Opcode::BoundImageGather:
|
||||||
case IR::Opcode::BoundImageGatherDref:
|
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::ImageSampleImplicitLod:
|
||||||
case IR::Opcode::ImageSampleExplicitLod:
|
case IR::Opcode::ImageSampleExplicitLod:
|
||||||
case IR::Opcode::ImageSampleDrefImplicitLod:
|
case IR::Opcode::ImageSampleDrefImplicitLod:
|
||||||
|
@ -384,7 +392,8 @@ void VisitUsages(Info& info, IR::Inst& inst) {
|
||||||
case IR::Opcode::ImageGatherDref:
|
case IR::Opcode::ImageGatherDref:
|
||||||
case IR::Opcode::ImageFetch:
|
case IR::Opcode::ImageFetch:
|
||||||
case IR::Opcode::ImageQueryDimensions:
|
case IR::Opcode::ImageQueryDimensions:
|
||||||
case IR::Opcode::ImageQueryLod: {
|
case IR::Opcode::ImageQueryLod:
|
||||||
|
case IR::Opcode::ImageGradient: {
|
||||||
const TextureType type{inst.Flags<IR::TextureInstInfo>().type};
|
const TextureType type{inst.Flags<IR::TextureInstInfo>().type};
|
||||||
info.uses_sampled_1d |= type == TextureType::Color1D || type == TextureType::ColorArray1D ||
|
info.uses_sampled_1d |= type == TextureType::Color1D || type == TextureType::ColorArray1D ||
|
||||||
type == TextureType::Shadow1D || type == TextureType::ShadowArray1D;
|
type == TextureType::Shadow1D || type == TextureType::ShadowArray1D;
|
||||||
|
|
|
@ -60,6 +60,9 @@ IR::Opcode IndexedInstruction(const IR::Inst& inst) {
|
||||||
case IR::Opcode::BoundImageQueryLod:
|
case IR::Opcode::BoundImageQueryLod:
|
||||||
case IR::Opcode::BindlessImageQueryLod:
|
case IR::Opcode::BindlessImageQueryLod:
|
||||||
return IR::Opcode::ImageQueryLod;
|
return IR::Opcode::ImageQueryLod;
|
||||||
|
case IR::Opcode::BoundImageGradient:
|
||||||
|
case IR::Opcode::BindlessImageGradient:
|
||||||
|
return IR::Opcode::ImageGradient;
|
||||||
default:
|
default:
|
||||||
return IR::Opcode::Void;
|
return IR::Opcode::Void;
|
||||||
}
|
}
|
||||||
|
@ -76,6 +79,7 @@ bool IsBindless(const IR::Inst& inst) {
|
||||||
case IR::Opcode::BindlessImageFetch:
|
case IR::Opcode::BindlessImageFetch:
|
||||||
case IR::Opcode::BindlessImageQueryDimensions:
|
case IR::Opcode::BindlessImageQueryDimensions:
|
||||||
case IR::Opcode::BindlessImageQueryLod:
|
case IR::Opcode::BindlessImageQueryLod:
|
||||||
|
case IR::Opcode::BindlessImageGradient:
|
||||||
return true;
|
return true;
|
||||||
case IR::Opcode::BoundImageSampleImplicitLod:
|
case IR::Opcode::BoundImageSampleImplicitLod:
|
||||||
case IR::Opcode::BoundImageSampleExplicitLod:
|
case IR::Opcode::BoundImageSampleExplicitLod:
|
||||||
|
@ -86,6 +90,7 @@ bool IsBindless(const IR::Inst& inst) {
|
||||||
case IR::Opcode::BoundImageFetch:
|
case IR::Opcode::BoundImageFetch:
|
||||||
case IR::Opcode::BoundImageQueryDimensions:
|
case IR::Opcode::BoundImageQueryDimensions:
|
||||||
case IR::Opcode::BoundImageQueryLod:
|
case IR::Opcode::BoundImageQueryLod:
|
||||||
|
case IR::Opcode::BoundImageGradient:
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
throw InvalidArgument("Invalid opcode {}", inst.Opcode());
|
throw InvalidArgument("Invalid opcode {}", inst.Opcode());
|
||||||
|
|
Loading…
Reference in a new issue