shader: Implement SULD and SUST
This commit is contained in:
		| @@ -18,41 +18,70 @@ namespace { | ||||
| Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) { | ||||
|     const spv::ImageFormat format{spv::ImageFormat::Unknown}; | ||||
|     const Id type{ctx.F32[1]}; | ||||
|     const bool depth{desc.is_depth}; | ||||
|     switch (desc.type) { | ||||
|     case TextureType::Color1D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim1D, false, false, false, 1, format); | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim1D, depth, false, false, 1, format); | ||||
|     case TextureType::ColorArray1D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim1D, false, true, false, 1, format); | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim1D, depth, true, false, 1, format); | ||||
|     case TextureType::Color2D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim2D, false, false, false, 1, format); | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim2D, depth, false, false, 1, format); | ||||
|     case TextureType::ColorArray2D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim2D, false, true, false, 1, format); | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim2D, depth, true, false, 1, format); | ||||
|     case TextureType::Color3D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim3D, false, false, false, 1, format); | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim3D, depth, false, false, 1, format); | ||||
|     case TextureType::ColorCube: | ||||
|         return ctx.TypeImage(type, spv::Dim::Cube, false, false, false, 1, format); | ||||
|         return ctx.TypeImage(type, spv::Dim::Cube, depth, 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, true, true, false, 1, format); | ||||
|         return ctx.TypeImage(type, spv::Dim::Cube, depth, true, false, 1, format); | ||||
|     case TextureType::Buffer: | ||||
|         break; | ||||
|     } | ||||
|     throw InvalidArgument("Invalid texture type {}", desc.type); | ||||
| } | ||||
|  | ||||
| Id ImageType(EmitContext& ctx, const ImageDescriptor& desc) { | ||||
|     const spv::ImageFormat format{[&] { | ||||
|         switch (desc.format) { | ||||
|         case ImageFormat::Typeless: | ||||
|             return spv::ImageFormat::Unknown; | ||||
|         case ImageFormat::R8_UINT: | ||||
|             return spv::ImageFormat::R8ui; | ||||
|         case ImageFormat::R8_SINT: | ||||
|             return spv::ImageFormat::R8i; | ||||
|         case ImageFormat::R16_UINT: | ||||
|             return spv::ImageFormat::R16ui; | ||||
|         case ImageFormat::R16_SINT: | ||||
|             return spv::ImageFormat::R16i; | ||||
|         case ImageFormat::R32_UINT: | ||||
|             return spv::ImageFormat::R32ui; | ||||
|         case ImageFormat::R32G32_UINT: | ||||
|             return spv::ImageFormat::Rg32ui; | ||||
|         case ImageFormat::R32G32B32A32_UINT: | ||||
|             return spv::ImageFormat::Rgba32ui; | ||||
|         } | ||||
|         throw InvalidArgument("Invalid image format {}", desc.format); | ||||
|     }()}; | ||||
|     const Id type{ctx.U32[1]}; | ||||
|     switch (desc.type) { | ||||
|     case TextureType::Color1D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim1D, false, false, false, 2, format); | ||||
|     case TextureType::ColorArray1D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim1D, false, true, false, 2, format); | ||||
|     case TextureType::Color2D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim2D, false, false, false, 2, format); | ||||
|     case TextureType::ColorArray2D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim2D, false, true, false, 2, format); | ||||
|     case TextureType::Color3D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim3D, false, false, false, 2, format); | ||||
|     case TextureType::Buffer: | ||||
|         throw NotImplementedException("Image buffer"); | ||||
|     default: | ||||
|         break; | ||||
|     } | ||||
|     throw InvalidArgument("Invalid texture type {}", desc.type); | ||||
| } | ||||
|  | ||||
| Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin, | ||||
|                   spv::StorageClass storage_class) { | ||||
|     const Id pointer_type{ctx.TypePointer(storage_class, type)}; | ||||
| @@ -134,6 +163,7 @@ EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& bin | ||||
|     DefineStorageBuffers(program.info, binding); | ||||
|     DefineTextureBuffers(program.info, binding); | ||||
|     DefineTextures(program.info, binding); | ||||
|     DefineImages(program.info, binding); | ||||
|     DefineAttributeMemAccess(program.info); | ||||
|     DefineLabels(program); | ||||
| } | ||||
| @@ -572,6 +602,31 @@ void EmitContext::DefineTextures(const Info& info, u32& binding) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| void EmitContext::DefineImages(const Info& info, u32& binding) { | ||||
|     images.reserve(info.image_descriptors.size()); | ||||
|     for (const ImageDescriptor& desc : info.image_descriptors) { | ||||
|         if (desc.count != 1) { | ||||
|             throw NotImplementedException("Array of textures"); | ||||
|         } | ||||
|         const Id image_type{ImageType(*this, desc)}; | ||||
|         const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_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("img{}_{:02x}", desc.cbuf_index, desc.cbuf_offset)); | ||||
|         for (u32 index = 0; index < desc.count; ++index) { | ||||
|             images.push_back(ImageDefinition{ | ||||
|                 .id{id}, | ||||
|                 .image_type{image_type}, | ||||
|             }); | ||||
|         } | ||||
|         if (profile.supported_spirv >= 0x00010400) { | ||||
|             interfaces.push_back(id); | ||||
|         } | ||||
|         binding += desc.count; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void EmitContext::DefineLabels(IR::Program& program) { | ||||
|     for (IR::Block* const block : program.blocks) { | ||||
|         block->SetDefinition(OpLabel()); | ||||
|   | ||||
| @@ -35,6 +35,11 @@ struct TextureDefinition { | ||||
|     Id image_type; | ||||
| }; | ||||
|  | ||||
| struct ImageDefinition { | ||||
|     Id id; | ||||
|     Id image_type; | ||||
| }; | ||||
|  | ||||
| struct UniformDefinitions { | ||||
|     Id U8{}; | ||||
|     Id S8{}; | ||||
| @@ -95,8 +100,9 @@ public: | ||||
|  | ||||
|     std::array<UniformDefinitions, Info::MAX_CBUFS> cbufs{}; | ||||
|     std::array<Id, Info::MAX_SSBOS> ssbos{}; | ||||
|     std::vector<TextureDefinition> textures; | ||||
|     std::vector<Id> texture_buffers; | ||||
|     std::vector<TextureDefinition> textures; | ||||
|     std::vector<ImageDefinition> images; | ||||
|  | ||||
|     Id workgroup_id{}; | ||||
|     Id local_invocation_id{}; | ||||
| @@ -156,6 +162,7 @@ private: | ||||
|     void DefineStorageBuffers(const Info& info, u32& binding); | ||||
|     void DefineTextureBuffers(const Info& info, u32& binding); | ||||
|     void DefineTextures(const Info& info, u32& binding); | ||||
|     void DefineImages(const Info& info, u32& binding); | ||||
|     void DefineAttributeMemAccess(const Info& info); | ||||
|     void DefineLabels(IR::Program& program); | ||||
|  | ||||
|   | ||||
| @@ -253,6 +253,7 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct | ||||
|     ctx.AddCapability(spv::Capability::ImageGatherExtended); | ||||
|     ctx.AddCapability(spv::Capability::ImageQuery); | ||||
|     ctx.AddCapability(spv::Capability::SampledBuffer); | ||||
|     ctx.AddCapability(spv::Capability::StorageImageReadWithoutFormat); | ||||
| } | ||||
|  | ||||
| Id PhiArgDef(EmitContext& ctx, IR::Inst* inst, size_t index) { | ||||
|   | ||||
| @@ -369,6 +369,8 @@ Id EmitBindlessImageFetch(EmitContext&); | ||||
| Id EmitBindlessImageQueryDimensions(EmitContext&); | ||||
| Id EmitBindlessImageQueryLod(EmitContext&); | ||||
| Id EmitBindlessImageGradient(EmitContext&); | ||||
| Id EmitBindlessImageRead(EmitContext&); | ||||
| Id EmitBindlessImageWrite(EmitContext&); | ||||
| Id EmitBoundImageSampleImplicitLod(EmitContext&); | ||||
| Id EmitBoundImageSampleExplicitLod(EmitContext&); | ||||
| Id EmitBoundImageSampleDrefImplicitLod(EmitContext&); | ||||
| @@ -379,6 +381,8 @@ Id EmitBoundImageFetch(EmitContext&); | ||||
| Id EmitBoundImageQueryDimensions(EmitContext&); | ||||
| Id EmitBoundImageQueryLod(EmitContext&); | ||||
| Id EmitBoundImageGradient(EmitContext&); | ||||
| Id EmitBoundImageRead(EmitContext&); | ||||
| Id EmitBoundImageWrite(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, | ||||
| @@ -397,6 +401,8 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i | ||||
| 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 EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); | ||||
| void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color); | ||||
| Id EmitVoteAll(EmitContext& ctx, Id pred); | ||||
| Id EmitVoteAny(EmitContext& ctx, Id pred); | ||||
| Id EmitVoteEqual(EmitContext& ctx, Id pred); | ||||
|   | ||||
| @@ -144,6 +144,18 @@ Id TextureImage(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo in | ||||
|     } | ||||
| } | ||||
|  | ||||
| Id Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { | ||||
|     if (!index.IsImmediate()) { | ||||
|         throw NotImplementedException("Indirect image indexing"); | ||||
|     } | ||||
|     if (info.type == TextureType::Buffer) { | ||||
|         throw NotImplementedException("Image buffer"); | ||||
|     } else { | ||||
|         const ImageDefinition def{ctx.images.at(index.U32())}; | ||||
|         return ctx.OpLoad(def.image_type, def.id); | ||||
|     } | ||||
| } | ||||
|  | ||||
| Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) { | ||||
|     const auto info{inst->Flags<IR::TextureInstInfo>()}; | ||||
|     if (info.relaxed_precision != 0) { | ||||
| @@ -209,6 +221,14 @@ Id EmitBindlessImageGradient(EmitContext&) { | ||||
|     throw LogicError("Unreachable instruction"); | ||||
| } | ||||
|  | ||||
| Id EmitBindlessImageRead(EmitContext&) { | ||||
|     throw LogicError("Unreachable instruction"); | ||||
| } | ||||
|  | ||||
| Id EmitBindlessImageWrite(EmitContext&) { | ||||
|     throw LogicError("Unreachable instruction"); | ||||
| } | ||||
|  | ||||
| Id EmitBoundImageSampleImplicitLod(EmitContext&) { | ||||
|     throw LogicError("Unreachable instruction"); | ||||
| } | ||||
| @@ -249,6 +269,14 @@ Id EmitBoundImageGradient(EmitContext&) { | ||||
|     throw LogicError("Unreachable instruction"); | ||||
| } | ||||
|  | ||||
| Id EmitBoundImageRead(EmitContext&) { | ||||
|     throw LogicError("Unreachable instruction"); | ||||
| } | ||||
|  | ||||
| Id EmitBoundImageWrite(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>()}; | ||||
| @@ -322,23 +350,16 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i | ||||
|     const auto mips{[&] { return ctx.OpImageQueryLevels(ctx.U32[1], image); }}; | ||||
|     switch (info.type) { | ||||
|     case TextureType::Color1D: | ||||
|     case TextureType::Shadow1D: | ||||
|         return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[1], image, lod), | ||||
|                                         zero, zero, mips()); | ||||
|     case TextureType::ColorArray1D: | ||||
|     case TextureType::Color2D: | ||||
|     case TextureType::ColorCube: | ||||
|     case TextureType::ShadowArray1D: | ||||
|     case TextureType::Shadow2D: | ||||
|     case TextureType::ShadowCube: | ||||
|         return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[2], image, lod), | ||||
|                                         zero, mips()); | ||||
|     case TextureType::ColorArray2D: | ||||
|     case TextureType::Color3D: | ||||
|     case TextureType::ColorArrayCube: | ||||
|     case TextureType::ShadowArray2D: | ||||
|     case TextureType::Shadow3D: | ||||
|     case TextureType::ShadowArrayCube: | ||||
|         return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[3], image, lod), | ||||
|                                         mips()); | ||||
|     case TextureType::Buffer: | ||||
| @@ -365,4 +386,15 @@ Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I | ||||
|                 coords, operands.Mask(), operands.Span()); | ||||
| } | ||||
|  | ||||
| Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) { | ||||
|     const auto info{inst->Flags<IR::TextureInstInfo>()}; | ||||
|     return Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst, ctx.U32[4], | ||||
|                 Image(ctx, index, info), coords, std::nullopt, std::span<const Id>{}); | ||||
| } | ||||
|  | ||||
| void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color) { | ||||
|     const auto info{inst->Flags<IR::TextureInstInfo>()}; | ||||
|     ctx.OpImageWrite(Image(ctx, index, info), coords, color); | ||||
| } | ||||
|  | ||||
| } // namespace Shader::Backend::SPIRV | ||||
|   | ||||
		Reference in New Issue
	
	Block a user