shader: Initial support for textures and TEX
This commit is contained in:
parent
7d6ba5b984
commit
ab46371247
33 changed files with 1489 additions and 342 deletions
|
@ -12,6 +12,43 @@
|
|||
#include "shader_recompiler/backend/spirv/emit_context.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
namespace {
|
||||
Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) {
|
||||
const spv::ImageFormat format{spv::ImageFormat::Unknown};
|
||||
const Id type{ctx.F32[1]};
|
||||
switch (desc.type) {
|
||||
case TextureType::Color1D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim1D, false, false, false, 1, format);
|
||||
case TextureType::ColorArray1D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim1D, false, true, false, 1, format);
|
||||
case TextureType::Color2D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim2D, false, false, false, 1, format);
|
||||
case TextureType::ColorArray2D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim2D, false, true, false, 1, format);
|
||||
case TextureType::Color3D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim3D, false, false, false, 1, format);
|
||||
case TextureType::ColorCube:
|
||||
return ctx.TypeImage(type, spv::Dim::Cube, false, false, false, 1, format);
|
||||
case TextureType::ColorArrayCube:
|
||||
return ctx.TypeImage(type, spv::Dim::Cube, false, true, false, 1, format);
|
||||
case TextureType::Shadow1D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim1D, true, false, false, 1, format);
|
||||
case TextureType::ShadowArray1D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim1D, true, true, false, 1, format);
|
||||
case TextureType::Shadow2D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim2D, true, false, false, 1, format);
|
||||
case TextureType::ShadowArray2D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim2D, true, true, false, 1, format);
|
||||
case TextureType::Shadow3D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim3D, true, false, false, 1, format);
|
||||
case TextureType::ShadowCube:
|
||||
return ctx.TypeImage(type, spv::Dim::Cube, true, false, false, 1, format);
|
||||
case TextureType::ShadowArrayCube:
|
||||
return ctx.TypeImage(type, spv::Dim::Cube, false, true, false, 1, format);
|
||||
}
|
||||
throw InvalidArgument("Invalid texture type {}", desc.type);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) {
|
||||
defs[0] = sirit_ctx.Name(base_type, name);
|
||||
|
@ -35,6 +72,7 @@ EmitContext::EmitContext(const Profile& profile_, IR::Program& program)
|
|||
u32 binding{};
|
||||
DefineConstantBuffers(program.info, binding);
|
||||
DefineStorageBuffers(program.info, binding);
|
||||
DefineTextures(program.info, binding);
|
||||
|
||||
DefineLabels(program);
|
||||
}
|
||||
|
@ -46,6 +84,10 @@ Id EmitContext::Def(const IR::Value& value) {
|
|||
return value.Inst()->Definition<Id>();
|
||||
}
|
||||
switch (value.Type()) {
|
||||
case IR::Type::Void:
|
||||
// Void instructions are used for optional arguments (e.g. texture offsets)
|
||||
// They are not meant to be used in the SPIR-V module
|
||||
return Id{};
|
||||
case IR::Type::U1:
|
||||
return value.U1() ? true_value : false_value;
|
||||
case IR::Type::U32:
|
||||
|
@ -122,7 +164,7 @@ void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) {
|
|||
uniform_u32 = TypePointer(spv::StorageClass::Uniform, U32[1]);
|
||||
|
||||
u32 index{};
|
||||
for (const Info::ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) {
|
||||
for (const ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) {
|
||||
const Id id{AddGlobalVariable(uniform_type, spv::StorageClass::Uniform)};
|
||||
Decorate(id, spv::Decoration::Binding, binding);
|
||||
Decorate(id, spv::Decoration::DescriptorSet, 0U);
|
||||
|
@ -152,7 +194,7 @@ void EmitContext::DefineStorageBuffers(const Info& info, u32& binding) {
|
|||
storage_u32 = TypePointer(spv::StorageClass::StorageBuffer, U32[1]);
|
||||
|
||||
u32 index{};
|
||||
for (const Info::StorageBufferDescriptor& desc : info.storage_buffers_descriptors) {
|
||||
for (const StorageBufferDescriptor& desc : info.storage_buffers_descriptors) {
|
||||
const Id id{AddGlobalVariable(storage_type, spv::StorageClass::StorageBuffer)};
|
||||
Decorate(id, spv::Decoration::Binding, binding);
|
||||
Decorate(id, spv::Decoration::DescriptorSet, 0U);
|
||||
|
@ -163,6 +205,29 @@ void EmitContext::DefineStorageBuffers(const Info& info, u32& binding) {
|
|||
}
|
||||
}
|
||||
|
||||
void EmitContext::DefineTextures(const Info& info, u32& binding) {
|
||||
textures.reserve(info.texture_descriptors.size());
|
||||
for (const TextureDescriptor& desc : info.texture_descriptors) {
|
||||
if (desc.count != 1) {
|
||||
throw NotImplementedException("Array of textures");
|
||||
}
|
||||
const Id type{TypeSampledImage(ImageType(*this, desc))};
|
||||
const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, type)};
|
||||
const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)};
|
||||
Decorate(id, spv::Decoration::Binding, binding);
|
||||
Decorate(id, spv::Decoration::DescriptorSet, 0U);
|
||||
Name(id, fmt::format("tex{}_{:02x}", desc.cbuf_index, desc.cbuf_offset));
|
||||
for (u32 index = 0; index < desc.count; ++index) {
|
||||
// TODO: Pass count info
|
||||
textures.push_back(TextureDefinition{
|
||||
.id{id},
|
||||
.type{type},
|
||||
});
|
||||
}
|
||||
binding += desc.count;
|
||||
}
|
||||
}
|
||||
|
||||
void EmitContext::DefineLabels(IR::Program& program) {
|
||||
for (const IR::Function& function : program.functions) {
|
||||
for (IR::Block* const block : function.blocks) {
|
||||
|
|
|
@ -29,6 +29,11 @@ private:
|
|||
std::array<Id, 4> defs{};
|
||||
};
|
||||
|
||||
struct TextureDefinition {
|
||||
Id id;
|
||||
Id type;
|
||||
};
|
||||
|
||||
class EmitContext final : public Sirit::Module {
|
||||
public:
|
||||
explicit EmitContext(const Profile& profile, IR::Program& program);
|
||||
|
@ -56,6 +61,7 @@ public:
|
|||
|
||||
std::array<Id, Info::MAX_CBUFS> cbufs{};
|
||||
std::array<Id, Info::MAX_SSBOS> ssbos{};
|
||||
std::vector<TextureDefinition> textures;
|
||||
|
||||
Id workgroup_id{};
|
||||
Id local_invocation_id{};
|
||||
|
@ -66,6 +72,7 @@ private:
|
|||
void DefineSpecialVariables(const Info& info);
|
||||
void DefineConstantBuffers(const Info& info, u32& binding);
|
||||
void DefineStorageBuffers(const Info& info, u32& binding);
|
||||
void DefineTextures(const Info& info, u32& binding);
|
||||
void DefineLabels(IR::Program& program);
|
||||
};
|
||||
|
||||
|
|
|
@ -221,6 +221,14 @@ std::vector<u32> EmitSPIRV(const Profile& profile, Environment& env, IR::Program
|
|||
workgroup_size[2]);
|
||||
|
||||
SetupDenormControl(profile, program, ctx, func);
|
||||
if (info.uses_sampled_1d) {
|
||||
ctx.AddCapability(spv::Capability::Sampled1D);
|
||||
}
|
||||
if (info.uses_sparse_residency) {
|
||||
ctx.AddCapability(spv::Capability::SparseResidency);
|
||||
}
|
||||
// TODO: Track this usage
|
||||
ctx.AddCapability(spv::Capability::ImageGatherExtended);
|
||||
|
||||
return ctx.Assemble();
|
||||
}
|
||||
|
@ -259,4 +267,8 @@ void EmitGetOverflowFromOp(EmitContext&) {
|
|||
throw LogicError("Unreachable instruction");
|
||||
}
|
||||
|
||||
void EmitGetSparseFromOp(EmitContext&) {
|
||||
throw LogicError("Unreachable instruction");
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::SPIRV
|
||||
|
|
|
@ -83,7 +83,8 @@ void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Va
|
|||
Id value);
|
||||
void EmitWriteStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value);
|
||||
void EmitWriteStorage128(EmitContext& ctx);
|
||||
void EmitWriteStorage128(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value);
|
||||
Id EmitCompositeConstructU32x2(EmitContext& ctx, Id e1, Id e2);
|
||||
Id EmitCompositeConstructU32x3(EmitContext& ctx, Id e1, Id e2, Id e3);
|
||||
Id EmitCompositeConstructU32x4(EmitContext& ctx, Id e1, Id e2, Id e3, Id e4);
|
||||
|
@ -145,6 +146,7 @@ void EmitGetZeroFromOp(EmitContext& ctx);
|
|||
void EmitGetSignFromOp(EmitContext& ctx);
|
||||
void EmitGetCarryFromOp(EmitContext& ctx);
|
||||
void EmitGetOverflowFromOp(EmitContext& ctx);
|
||||
void EmitGetSparseFromOp(EmitContext& ctx);
|
||||
Id EmitFPAbs16(EmitContext& ctx, Id value);
|
||||
Id EmitFPAbs32(EmitContext& ctx, Id value);
|
||||
Id EmitFPAbs64(EmitContext& ctx, Id value);
|
||||
|
@ -291,5 +293,33 @@ Id EmitConvertF16F32(EmitContext& ctx, Id value);
|
|||
Id EmitConvertF32F16(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF32F64(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF64F32(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF16S32(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF16S64(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF16U32(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF16U64(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF32S32(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF32S64(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF32U32(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF32U64(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF64S32(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF64S64(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF64U32(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF64U64(EmitContext& ctx, Id value);
|
||||
Id EmitBindlessImageSampleImplicitLod(EmitContext&);
|
||||
Id EmitBindlessImageSampleExplicitLod(EmitContext&);
|
||||
Id EmitBindlessImageSampleDrefImplicitLod(EmitContext&);
|
||||
Id EmitBindlessImageSampleDrefExplicitLod(EmitContext&);
|
||||
Id EmitBoundImageSampleImplicitLod(EmitContext&);
|
||||
Id EmitBoundImageSampleExplicitLod(EmitContext&);
|
||||
Id EmitBoundImageSampleDrefImplicitLod(EmitContext&);
|
||||
Id EmitBoundImageSampleDrefExplicitLod(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,
|
||||
Id lod_lc, Id offset);
|
||||
Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
|
||||
Id coords, Id dref, Id bias_lc, Id offset);
|
||||
Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
|
||||
Id coords, Id dref, Id lod_lc, Id offset);
|
||||
|
||||
} // namespace Shader::Backend::SPIRV
|
||||
|
|
|
@ -102,4 +102,52 @@ Id EmitConvertF64F32(EmitContext& ctx, Id value) {
|
|||
return ctx.OpFConvert(ctx.F64[1], value);
|
||||
}
|
||||
|
||||
Id EmitConvertF16S32(EmitContext& ctx, Id value) {
|
||||
return ctx.OpConvertSToF(ctx.F16[1], value);
|
||||
}
|
||||
|
||||
Id EmitConvertF16S64(EmitContext& ctx, Id value) {
|
||||
return ctx.OpConvertSToF(ctx.F16[1], value);
|
||||
}
|
||||
|
||||
Id EmitConvertF16U32(EmitContext& ctx, Id value) {
|
||||
return ctx.OpConvertUToF(ctx.F16[1], value);
|
||||
}
|
||||
|
||||
Id EmitConvertF16U64(EmitContext& ctx, Id value) {
|
||||
return ctx.OpConvertUToF(ctx.F16[1], value);
|
||||
}
|
||||
|
||||
Id EmitConvertF32S32(EmitContext& ctx, Id value) {
|
||||
return ctx.OpConvertSToF(ctx.F32[1], value);
|
||||
}
|
||||
|
||||
Id EmitConvertF32S64(EmitContext& ctx, Id value) {
|
||||
return ctx.OpConvertSToF(ctx.F32[1], value);
|
||||
}
|
||||
|
||||
Id EmitConvertF32U32(EmitContext& ctx, Id value) {
|
||||
return ctx.OpConvertUToF(ctx.F32[1], value);
|
||||
}
|
||||
|
||||
Id EmitConvertF32U64(EmitContext& ctx, Id value) {
|
||||
return ctx.OpConvertUToF(ctx.F32[1], value);
|
||||
}
|
||||
|
||||
Id EmitConvertF64S32(EmitContext& ctx, Id value) {
|
||||
return ctx.OpConvertSToF(ctx.F64[1], value);
|
||||
}
|
||||
|
||||
Id EmitConvertF64S64(EmitContext& ctx, Id value) {
|
||||
return ctx.OpConvertSToF(ctx.F64[1], value);
|
||||
}
|
||||
|
||||
Id EmitConvertF64U32(EmitContext& ctx, Id value) {
|
||||
return ctx.OpConvertUToF(ctx.F64[1], value);
|
||||
}
|
||||
|
||||
Id EmitConvertF64U64(EmitContext& ctx, Id value) {
|
||||
return ctx.OpConvertUToF(ctx.F64[1], value);
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::SPIRV
|
||||
|
|
146
src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
Normal file
146
src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
Normal file
|
@ -0,0 +1,146 @@
|
|||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <boost/container/static_vector.hpp>
|
||||
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/frontend/ir/modifiers.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
namespace {
|
||||
class ImageOperands {
|
||||
public:
|
||||
explicit ImageOperands(EmitContext& ctx, bool has_bias, bool has_lod, bool has_lod_clamp,
|
||||
Id lod, Id offset) {
|
||||
if (has_bias) {
|
||||
const Id bias{has_lod_clamp ? ctx.OpCompositeExtract(ctx.F32[1], lod, 0) : lod};
|
||||
Add(spv::ImageOperandsMask::Bias, bias);
|
||||
}
|
||||
if (has_lod) {
|
||||
const Id lod_value{has_lod_clamp ? ctx.OpCompositeExtract(ctx.F32[1], lod, 0) : lod};
|
||||
Add(spv::ImageOperandsMask::Lod, lod_value);
|
||||
}
|
||||
if (Sirit::ValidId(offset)) {
|
||||
Add(spv::ImageOperandsMask::Offset, offset);
|
||||
}
|
||||
if (has_lod_clamp) {
|
||||
const Id lod_clamp{has_bias ? ctx.OpCompositeExtract(ctx.F32[1], lod, 1) : lod};
|
||||
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);
|
||||
}
|
||||
|
||||
std::span<const Id> Span() const noexcept {
|
||||
return std::span{operands.data(), operands.size()};
|
||||
}
|
||||
|
||||
spv::ImageOperandsMask Mask() const noexcept {
|
||||
return mask;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::container::static_vector<Id, 3> operands;
|
||||
spv::ImageOperandsMask mask{};
|
||||
};
|
||||
|
||||
Id Texture(EmitContext& ctx, const IR::Value& index) {
|
||||
if (index.IsImmediate()) {
|
||||
const TextureDefinition def{ctx.textures.at(index.U32())};
|
||||
return ctx.OpLoad(def.type, def.id);
|
||||
}
|
||||
throw NotImplementedException("Indirect texture sample");
|
||||
}
|
||||
|
||||
template <typename MethodPtrType, typename... Args>
|
||||
Id Emit(MethodPtrType sparse_ptr, MethodPtrType non_sparse_ptr, EmitContext& ctx, IR::Inst* inst,
|
||||
Id result_type, Args&&... args) {
|
||||
IR::Inst* const sparse{inst->GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp)};
|
||||
if (!sparse) {
|
||||
return (ctx.*non_sparse_ptr)(result_type, std::forward<Args>(args)...);
|
||||
}
|
||||
const Id struct_type{ctx.TypeStruct(ctx.U32[1], result_type)};
|
||||
const Id sample{(ctx.*sparse_ptr)(struct_type, std::forward<Args>(args)...)};
|
||||
const Id resident_code{ctx.OpCompositeExtract(ctx.U32[1], sample, 0U)};
|
||||
sparse->SetDefinition(ctx.OpImageSparseTexelsResident(ctx.U1, resident_code));
|
||||
sparse->Invalidate();
|
||||
return ctx.OpCompositeExtract(result_type, sample, 1U);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
Id EmitBindlessImageSampleImplicitLod(EmitContext&) {
|
||||
throw LogicError("Unreachable instruction");
|
||||
}
|
||||
|
||||
Id EmitBindlessImageSampleExplicitLod(EmitContext&) {
|
||||
throw LogicError("Unreachable instruction");
|
||||
}
|
||||
|
||||
Id EmitBindlessImageSampleDrefImplicitLod(EmitContext&) {
|
||||
throw LogicError("Unreachable instruction");
|
||||
}
|
||||
|
||||
Id EmitBindlessImageSampleDrefExplicitLod(EmitContext&) {
|
||||
throw LogicError("Unreachable instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageSampleImplicitLod(EmitContext&) {
|
||||
throw LogicError("Unreachable instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageSampleExplicitLod(EmitContext&) {
|
||||
throw LogicError("Unreachable instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageSampleDrefImplicitLod(EmitContext&) {
|
||||
throw LogicError("Unreachable instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageSampleDrefExplicitLod(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>()};
|
||||
const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0, bias_lc,
|
||||
offset);
|
||||
return Emit(&EmitContext::OpImageSparseSampleImplicitLod,
|
||||
&EmitContext::OpImageSampleImplicitLod, ctx, inst, ctx.F32[4], Texture(ctx, index),
|
||||
coords, operands.Mask(), operands.Span());
|
||||
}
|
||||
|
||||
Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id lod_lc, Id offset) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod_lc, offset);
|
||||
return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
|
||||
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], Texture(ctx, index),
|
||||
coords, operands.Mask(), operands.Span());
|
||||
}
|
||||
|
||||
Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
|
||||
Id coords, Id dref, Id bias_lc, Id offset) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0, bias_lc,
|
||||
offset);
|
||||
return Emit(&EmitContext::OpImageSparseSampleDrefImplicitLod,
|
||||
&EmitContext::OpImageSampleDrefImplicitLod, ctx, inst, ctx.F32[1],
|
||||
Texture(ctx, index), coords, dref, operands.Mask(), operands.Span());
|
||||
}
|
||||
|
||||
Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
|
||||
Id coords, Id dref, Id lod_lc, Id offset) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod_lc, offset);
|
||||
return Emit(&EmitContext::OpImageSparseSampleDrefExplicitLod,
|
||||
&EmitContext::OpImageSampleDrefExplicitLod, ctx, inst, ctx.F32[1],
|
||||
Texture(ctx, index), coords, dref, operands.Mask(), operands.Span());
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::SPIRV
|
|
@ -154,8 +154,22 @@ void EmitWriteStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Va
|
|||
ctx.OpStore(high_pointer, ctx.OpCompositeExtract(ctx.U32[1], value, 1U));
|
||||
}
|
||||
|
||||
void EmitWriteStorage128(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
void EmitWriteStorage128(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||
Id value) {
|
||||
if (!binding.IsImmediate()) {
|
||||
throw NotImplementedException("Dynamic storage buffer indexing");
|
||||
}
|
||||
// TODO: Support reinterpreting bindings, guaranteed to be aligned
|
||||
const Id ssbo{ctx.ssbos[binding.U32()]};
|
||||
const Id base_index{StorageIndex(ctx, offset, sizeof(u32))};
|
||||
for (u32 element = 0; element < 4; ++element) {
|
||||
Id index = base_index;
|
||||
if (element > 0) {
|
||||
index = ctx.OpIAdd(ctx.U32[1], base_index, ctx.Constant(ctx.U32[1], element));
|
||||
}
|
||||
const Id pointer{ctx.OpAccessChain(ctx.storage_u32, ssbo, ctx.u32_zero_value, index)};
|
||||
ctx.OpStore(pointer, ctx.OpCompositeExtract(ctx.U32[1], value, element));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::SPIRV
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue