shader: Initial support for textures and TEX
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user