diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp index c07a778958..4bff810547 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp @@ -197,33 +197,41 @@ Id Texture(EmitContext& ctx, IR::TextureInstInfo info, [[maybe_unused]] const IR } Id TextureImage(EmitContext& ctx, IR::TextureInstInfo info, const IR::Value& index) { - if (!index.IsImmediate() || index.U32() != 0) { - throw NotImplementedException("Indirect image indexing"); - } if (info.type == TextureType::Buffer) { const TextureBufferDefinition& def{ctx.texture_buffers.at(info.descriptor_index)}; if (def.count > 1) { - throw NotImplementedException("Indirect texture sample"); + const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)}; + const Id ptr{ctx.OpAccessChain(ctx.image_buffer_type, def.id, idx)}; + return ctx.OpLoad(ctx.image_buffer_type, ptr); } return ctx.OpLoad(ctx.image_buffer_type, def.id); } else { const TextureDefinition& def{ctx.textures.at(info.descriptor_index)}; if (def.count > 1) { - throw NotImplementedException("Indirect texture sample"); + const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)}; + const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx)}; + return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, ptr)); } return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, def.id)); } } std::pair Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { - if (!index.IsImmediate() || index.U32() != 0) { - throw NotImplementedException("Indirect image indexing"); - } if (info.type == TextureType::Buffer) { const ImageBufferDefinition def{ctx.image_buffers.at(info.descriptor_index)}; + if (def.count > 1) { + const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)}; + const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx)}; + return {ctx.OpLoad(def.image_type, ptr), def.is_integer}; + } return {ctx.OpLoad(def.image_type, def.id), def.is_integer}; } else { const ImageDefinition def{ctx.images.at(info.descriptor_index)}; + if (def.count > 1) { + const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)}; + const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx)}; + return {ctx.OpLoad(def.image_type, ptr), def.is_integer}; + } return {ctx.OpLoad(def.image_type, def.id), def.is_integer}; } } diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index c70f9ae934..cd3394bdf0 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -1331,9 +1331,6 @@ void EmitContext::DefineTextureBuffers(const Info& info, u32& binding) { void EmitContext::DefineImageBuffers(const Info& info, u32& binding) { image_buffers.reserve(info.image_buffer_descriptors.size()); for (const ImageBufferDescriptor& desc : info.image_buffer_descriptors) { - if (desc.count != 1) { - throw NotImplementedException("Array of image buffers"); - } const spv::ImageFormat format{GetImageFormat(desc.format)}; const Id sampled_type{desc.is_integer ? U32[1] : F32[1]}; const Id image_type{ @@ -1346,6 +1343,7 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) { image_buffers.push_back({ .id = id, .image_type = image_type, + .pointer_type = pointer_type, .count = desc.count, .is_integer = desc.is_integer, }); @@ -1389,9 +1387,6 @@ void EmitContext::DefineTextures(const Info& info, u32& binding, u32& scaling_in void EmitContext::DefineImages(const Info& info, u32& binding, u32& scaling_index) { images.reserve(info.image_descriptors.size()); for (const ImageDescriptor& desc : info.image_descriptors) { - if (desc.count != 1) { - throw NotImplementedException("Array of images"); - } const Id sampled_type{desc.is_integer ? U32[1] : F32[1]}; const Id image_type{ImageType(*this, desc, sampled_type)}; const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; @@ -1402,6 +1397,7 @@ void EmitContext::DefineImages(const Info& info, u32& binding, u32& scaling_inde images.push_back({ .id = id, .image_type = image_type, + .pointer_type = pointer_type, .count = desc.count, .is_integer = desc.is_integer, }); diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index 80ac79f2d6..de56809a98 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h @@ -51,6 +51,7 @@ struct TextureBufferDefinition { struct ImageBufferDefinition { Id id; Id image_type; + Id pointer_type; u32 count; bool is_integer; }; @@ -58,6 +59,7 @@ struct ImageBufferDefinition { struct ImageDefinition { Id id; Id image_type; + Id pointer_type; u32 count; bool is_integer; };