diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_context.cpp | 79 | ||||
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_context.h | 11 | ||||
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_spirv_image.cpp | 58 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/modifiers.h | 17 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/opcodes.inc | 24 | ||||
| -rw-r--r-- | src/shader_recompiler/ir_opt/texture_pass.cpp | 89 | ||||
| -rw-r--r-- | src/shader_recompiler/shader_info.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/pipeline_helper.h | 50 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_compute_pipeline.cpp | 46 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | 63 |
10 files changed, 284 insertions, 157 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index 7f16cb0dc..8e625f8fb 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp | |||
| @@ -380,6 +380,24 @@ Id CasLoop(EmitContext& ctx, Operation operation, Id array_pointer, Id element_p | |||
| 380 | ctx.OpFunctionEnd(); | 380 | ctx.OpFunctionEnd(); |
| 381 | return func; | 381 | return func; |
| 382 | } | 382 | } |
| 383 | |||
| 384 | template <typename Desc> | ||
| 385 | std::string NameOf(const Desc& desc, std::string_view prefix) { | ||
| 386 | if (desc.count > 1) { | ||
| 387 | return fmt::format("{}{}_{:02x}x{}", prefix, desc.cbuf_index, desc.cbuf_offset, desc.count); | ||
| 388 | } else { | ||
| 389 | return fmt::format("{}{}_{:02x}", prefix, desc.cbuf_index, desc.cbuf_offset); | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | Id DescType(EmitContext& ctx, Id sampled_type, Id pointer_type, u32 count) { | ||
| 394 | if (count > 1) { | ||
| 395 | const Id array_type{ctx.TypeArray(sampled_type, ctx.Const(count))}; | ||
| 396 | return ctx.TypePointer(spv::StorageClass::UniformConstant, array_type); | ||
| 397 | } else { | ||
| 398 | return pointer_type; | ||
| 399 | } | ||
| 400 | } | ||
| 383 | } // Anonymous namespace | 401 | } // Anonymous namespace |
| 384 | 402 | ||
| 385 | void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { | 403 | void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { |
| @@ -971,12 +989,15 @@ void EmitContext::DefineTextureBuffers(const Info& info, u32& binding) { | |||
| 971 | const Id id{AddGlobalVariable(type, spv::StorageClass::UniformConstant)}; | 989 | const Id id{AddGlobalVariable(type, spv::StorageClass::UniformConstant)}; |
| 972 | Decorate(id, spv::Decoration::Binding, binding); | 990 | Decorate(id, spv::Decoration::Binding, binding); |
| 973 | Decorate(id, spv::Decoration::DescriptorSet, 0U); | 991 | Decorate(id, spv::Decoration::DescriptorSet, 0U); |
| 974 | Name(id, fmt::format("texbuf{}_{:02x}", desc.cbuf_index, desc.cbuf_offset)); | 992 | Name(id, NameOf(desc, "texbuf")); |
| 975 | texture_buffers.insert(texture_buffers.end(), desc.count, id); | 993 | texture_buffers.push_back({ |
| 994 | .id = id, | ||
| 995 | .count = desc.count, | ||
| 996 | }); | ||
| 976 | if (profile.supported_spirv >= 0x00010400) { | 997 | if (profile.supported_spirv >= 0x00010400) { |
| 977 | interfaces.push_back(id); | 998 | interfaces.push_back(id); |
| 978 | } | 999 | } |
| 979 | binding += desc.count; | 1000 | ++binding; |
| 980 | } | 1001 | } |
| 981 | } | 1002 | } |
| 982 | 1003 | ||
| @@ -992,44 +1013,41 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) { | |||
| 992 | const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; | 1013 | const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; |
| 993 | Decorate(id, spv::Decoration::Binding, binding); | 1014 | Decorate(id, spv::Decoration::Binding, binding); |
| 994 | Decorate(id, spv::Decoration::DescriptorSet, 0U); | 1015 | Decorate(id, spv::Decoration::DescriptorSet, 0U); |
| 995 | Name(id, fmt::format("imgbuf{}_{:02x}", desc.cbuf_index, desc.cbuf_offset)); | 1016 | Name(id, NameOf(desc, "imgbuf")); |
| 996 | const ImageBufferDefinition def{ | 1017 | image_buffers.push_back({ |
| 997 | .id = id, | 1018 | .id = id, |
| 998 | .image_type = image_type, | 1019 | .image_type = image_type, |
| 999 | }; | 1020 | .count = desc.count, |
| 1000 | image_buffers.insert(image_buffers.end(), desc.count, def); | 1021 | }); |
| 1001 | if (profile.supported_spirv >= 0x00010400) { | 1022 | if (profile.supported_spirv >= 0x00010400) { |
| 1002 | interfaces.push_back(id); | 1023 | interfaces.push_back(id); |
| 1003 | } | 1024 | } |
| 1004 | binding += desc.count; | 1025 | ++binding; |
| 1005 | } | 1026 | } |
| 1006 | } | 1027 | } |
| 1007 | 1028 | ||
| 1008 | void EmitContext::DefineTextures(const Info& info, u32& binding) { | 1029 | void EmitContext::DefineTextures(const Info& info, u32& binding) { |
| 1009 | textures.reserve(info.texture_descriptors.size()); | 1030 | textures.reserve(info.texture_descriptors.size()); |
| 1010 | for (const TextureDescriptor& desc : info.texture_descriptors) { | 1031 | for (const TextureDescriptor& desc : info.texture_descriptors) { |
| 1011 | if (desc.count != 1) { | ||
| 1012 | throw NotImplementedException("Array of textures"); | ||
| 1013 | } | ||
| 1014 | const Id image_type{ImageType(*this, desc)}; | 1032 | const Id image_type{ImageType(*this, desc)}; |
| 1015 | const Id sampled_type{TypeSampledImage(image_type)}; | 1033 | const Id sampled_type{TypeSampledImage(image_type)}; |
| 1016 | const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, sampled_type)}; | 1034 | const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, sampled_type)}; |
| 1017 | const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; | 1035 | const Id desc_type{DescType(*this, sampled_type, pointer_type, desc.count)}; |
| 1036 | const Id id{AddGlobalVariable(desc_type, spv::StorageClass::UniformConstant)}; | ||
| 1018 | Decorate(id, spv::Decoration::Binding, binding); | 1037 | Decorate(id, spv::Decoration::Binding, binding); |
| 1019 | Decorate(id, spv::Decoration::DescriptorSet, 0U); | 1038 | Decorate(id, spv::Decoration::DescriptorSet, 0U); |
| 1020 | Name(id, fmt::format("tex{}_{:02x}", desc.cbuf_index, desc.cbuf_offset)); | 1039 | Name(id, NameOf(desc, "tex")); |
| 1021 | for (u32 index = 0; index < desc.count; ++index) { | 1040 | textures.push_back({ |
| 1022 | // TODO: Pass count info | 1041 | .id = id, |
| 1023 | textures.push_back(TextureDefinition{ | 1042 | .sampled_type = sampled_type, |
| 1024 | .id{id}, | 1043 | .pointer_type = pointer_type, |
| 1025 | .sampled_type{sampled_type}, | 1044 | .image_type = image_type, |
| 1026 | .image_type{image_type}, | 1045 | .count = desc.count, |
| 1027 | }); | 1046 | }); |
| 1028 | } | ||
| 1029 | if (profile.supported_spirv >= 0x00010400) { | 1047 | if (profile.supported_spirv >= 0x00010400) { |
| 1030 | interfaces.push_back(id); | 1048 | interfaces.push_back(id); |
| 1031 | } | 1049 | } |
| 1032 | binding += desc.count; | 1050 | ++binding; |
| 1033 | } | 1051 | } |
| 1034 | } | 1052 | } |
| 1035 | 1053 | ||
| @@ -1037,24 +1055,23 @@ void EmitContext::DefineImages(const Info& info, u32& binding) { | |||
| 1037 | images.reserve(info.image_descriptors.size()); | 1055 | images.reserve(info.image_descriptors.size()); |
| 1038 | for (const ImageDescriptor& desc : info.image_descriptors) { | 1056 | for (const ImageDescriptor& desc : info.image_descriptors) { |
| 1039 | if (desc.count != 1) { | 1057 | if (desc.count != 1) { |
| 1040 | throw NotImplementedException("Array of textures"); | 1058 | throw NotImplementedException("Array of images"); |
| 1041 | } | 1059 | } |
| 1042 | const Id image_type{ImageType(*this, desc)}; | 1060 | const Id image_type{ImageType(*this, desc)}; |
| 1043 | const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; | 1061 | const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; |
| 1044 | const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; | 1062 | const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; |
| 1045 | Decorate(id, spv::Decoration::Binding, binding); | 1063 | Decorate(id, spv::Decoration::Binding, binding); |
| 1046 | Decorate(id, spv::Decoration::DescriptorSet, 0U); | 1064 | Decorate(id, spv::Decoration::DescriptorSet, 0U); |
| 1047 | Name(id, fmt::format("img{}_{:02x}", desc.cbuf_index, desc.cbuf_offset)); | 1065 | Name(id, NameOf(desc, "img")); |
| 1048 | for (u32 index = 0; index < desc.count; ++index) { | 1066 | images.push_back({ |
| 1049 | images.push_back(ImageDefinition{ | 1067 | .id = id, |
| 1050 | .id{id}, | 1068 | .image_type = image_type, |
| 1051 | .image_type{image_type}, | 1069 | .count = desc.count, |
| 1052 | }); | 1070 | }); |
| 1053 | } | ||
| 1054 | if (profile.supported_spirv >= 0x00010400) { | 1071 | if (profile.supported_spirv >= 0x00010400) { |
| 1055 | interfaces.push_back(id); | 1072 | interfaces.push_back(id); |
| 1056 | } | 1073 | } |
| 1057 | binding += desc.count; | 1074 | ++binding; |
| 1058 | } | 1075 | } |
| 1059 | } | 1076 | } |
| 1060 | 1077 | ||
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h index a4503c7ab..c52544fb7 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.h +++ b/src/shader_recompiler/backend/spirv/emit_context.h | |||
| @@ -32,17 +32,26 @@ private: | |||
| 32 | struct TextureDefinition { | 32 | struct TextureDefinition { |
| 33 | Id id; | 33 | Id id; |
| 34 | Id sampled_type; | 34 | Id sampled_type; |
| 35 | Id pointer_type; | ||
| 35 | Id image_type; | 36 | Id image_type; |
| 37 | u32 count; | ||
| 38 | }; | ||
| 39 | |||
| 40 | struct TextureBufferDefinition { | ||
| 41 | Id id; | ||
| 42 | u32 count; | ||
| 36 | }; | 43 | }; |
| 37 | 44 | ||
| 38 | struct ImageBufferDefinition { | 45 | struct ImageBufferDefinition { |
| 39 | Id id; | 46 | Id id; |
| 40 | Id image_type; | 47 | Id image_type; |
| 48 | u32 count; | ||
| 41 | }; | 49 | }; |
| 42 | 50 | ||
| 43 | struct ImageDefinition { | 51 | struct ImageDefinition { |
| 44 | Id id; | 52 | Id id; |
| 45 | Id image_type; | 53 | Id image_type; |
| 54 | u32 count; | ||
| 46 | }; | 55 | }; |
| 47 | 56 | ||
| 48 | struct UniformDefinitions { | 57 | struct UniformDefinitions { |
| @@ -162,7 +171,7 @@ public: | |||
| 162 | 171 | ||
| 163 | std::array<UniformDefinitions, Info::MAX_CBUFS> cbufs{}; | 172 | std::array<UniformDefinitions, Info::MAX_CBUFS> cbufs{}; |
| 164 | std::array<StorageDefinitions, Info::MAX_SSBOS> ssbos{}; | 173 | std::array<StorageDefinitions, Info::MAX_SSBOS> ssbos{}; |
| 165 | std::vector<Id> texture_buffers; | 174 | std::vector<TextureBufferDefinition> texture_buffers; |
| 166 | std::vector<ImageBufferDefinition> image_buffers; | 175 | std::vector<ImageBufferDefinition> image_buffers; |
| 167 | std::vector<TextureDefinition> textures; | 176 | std::vector<TextureDefinition> textures; |
| 168 | std::vector<ImageDefinition> images; | 177 | std::vector<ImageDefinition> images; |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp index 90817f161..6008980af 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp | |||
| @@ -147,24 +147,31 @@ private: | |||
| 147 | spv::ImageOperandsMask mask{}; | 147 | spv::ImageOperandsMask mask{}; |
| 148 | }; | 148 | }; |
| 149 | 149 | ||
| 150 | Id Texture(EmitContext& ctx, const IR::Value& index) { | 150 | Id Texture(EmitContext& ctx, IR::TextureInstInfo info, [[maybe_unused]] const IR::Value& index) { |
| 151 | if (index.IsImmediate()) { | 151 | const TextureDefinition& def{ctx.textures.at(info.descriptor_index)}; |
| 152 | const TextureDefinition def{ctx.textures.at(index.U32())}; | 152 | if (def.count > 1) { |
| 153 | const Id pointer{ctx.OpAccessChain(def.pointer_type, def.id, ctx.Def(index))}; | ||
| 154 | return ctx.OpLoad(def.sampled_type, pointer); | ||
| 155 | } else { | ||
| 153 | return ctx.OpLoad(def.sampled_type, def.id); | 156 | return ctx.OpLoad(def.sampled_type, def.id); |
| 154 | } | 157 | } |
| 155 | throw NotImplementedException("Indirect texture sample"); | ||
| 156 | } | 158 | } |
| 157 | 159 | ||
| 158 | Id TextureImage(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { | 160 | Id TextureImage(EmitContext& ctx, IR::TextureInstInfo info, |
| 159 | if (!index.IsImmediate()) { | 161 | [[maybe_unused]] const IR::Value& index) { |
| 160 | throw NotImplementedException("Indirect texture sample"); | ||
| 161 | } | ||
| 162 | if (info.type == TextureType::Buffer) { | 162 | if (info.type == TextureType::Buffer) { |
| 163 | const Id sampler_id{ctx.texture_buffers.at(index.U32())}; | 163 | const TextureBufferDefinition& def{ctx.texture_buffers.at(info.descriptor_index)}; |
| 164 | if (def.count > 1) { | ||
| 165 | throw NotImplementedException("Indirect texture sample"); | ||
| 166 | } | ||
| 167 | const Id sampler_id{def.id}; | ||
| 164 | const Id id{ctx.OpLoad(ctx.sampled_texture_buffer_type, sampler_id)}; | 168 | const Id id{ctx.OpLoad(ctx.sampled_texture_buffer_type, sampler_id)}; |
| 165 | return ctx.OpImage(ctx.image_buffer_type, id); | 169 | return ctx.OpImage(ctx.image_buffer_type, id); |
| 166 | } else { | 170 | } else { |
| 167 | const TextureDefinition def{ctx.textures.at(index.U32())}; | 171 | const TextureDefinition& def{ctx.textures.at(info.descriptor_index)}; |
| 172 | if (def.count > 1) { | ||
| 173 | throw NotImplementedException("Indirect texture sample"); | ||
| 174 | } | ||
| 168 | return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, def.id)); | 175 | return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, def.id)); |
| 169 | } | 176 | } |
| 170 | } | 177 | } |
| @@ -311,7 +318,7 @@ Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& | |||
| 311 | bias_lc, offset); | 318 | bias_lc, offset); |
| 312 | return Emit(&EmitContext::OpImageSparseSampleImplicitLod, | 319 | return Emit(&EmitContext::OpImageSparseSampleImplicitLod, |
| 313 | &EmitContext::OpImageSampleImplicitLod, ctx, inst, ctx.F32[4], | 320 | &EmitContext::OpImageSampleImplicitLod, ctx, inst, ctx.F32[4], |
| 314 | Texture(ctx, index), coords, operands.Mask(), operands.Span()); | 321 | Texture(ctx, info, index), coords, operands.Mask(), operands.Span()); |
| 315 | } else { | 322 | } else { |
| 316 | // We can't use implicit lods on non-fragment stages on SPIR-V. Maxwell hardware behaves as | 323 | // We can't use implicit lods on non-fragment stages on SPIR-V. Maxwell hardware behaves as |
| 317 | // if the lod was explicitly zero. This may change on Turing with implicit compute | 324 | // if the lod was explicitly zero. This may change on Turing with implicit compute |
| @@ -320,7 +327,7 @@ Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& | |||
| 320 | const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod, offset); | 327 | const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod, offset); |
| 321 | return Emit(&EmitContext::OpImageSparseSampleExplicitLod, | 328 | return Emit(&EmitContext::OpImageSparseSampleExplicitLod, |
| 322 | &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], | 329 | &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], |
| 323 | Texture(ctx, index), coords, operands.Mask(), operands.Span()); | 330 | Texture(ctx, info, index), coords, operands.Mask(), operands.Span()); |
| 324 | } | 331 | } |
| 325 | } | 332 | } |
| 326 | 333 | ||
| @@ -329,8 +336,8 @@ Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& | |||
| 329 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | 336 | const auto info{inst->Flags<IR::TextureInstInfo>()}; |
| 330 | const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod_lc, offset); | 337 | const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod_lc, offset); |
| 331 | return Emit(&EmitContext::OpImageSparseSampleExplicitLod, | 338 | return Emit(&EmitContext::OpImageSparseSampleExplicitLod, |
| 332 | &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], Texture(ctx, index), | 339 | &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], |
| 333 | coords, operands.Mask(), operands.Span()); | 340 | Texture(ctx, info, index), coords, operands.Mask(), operands.Span()); |
| 334 | } | 341 | } |
| 335 | 342 | ||
| 336 | Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, | 343 | Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, |
| @@ -340,7 +347,7 @@ Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Va | |||
| 340 | offset); | 347 | offset); |
| 341 | return Emit(&EmitContext::OpImageSparseSampleDrefImplicitLod, | 348 | return Emit(&EmitContext::OpImageSparseSampleDrefImplicitLod, |
| 342 | &EmitContext::OpImageSampleDrefImplicitLod, ctx, inst, ctx.F32[1], | 349 | &EmitContext::OpImageSampleDrefImplicitLod, ctx, inst, ctx.F32[1], |
| 343 | Texture(ctx, index), coords, dref, operands.Mask(), operands.Span()); | 350 | Texture(ctx, info, index), coords, dref, operands.Mask(), operands.Span()); |
| 344 | } | 351 | } |
| 345 | 352 | ||
| 346 | Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, | 353 | Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, |
| @@ -349,7 +356,7 @@ Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Va | |||
| 349 | const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod_lc, offset); | 356 | const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod_lc, offset); |
| 350 | return Emit(&EmitContext::OpImageSparseSampleDrefExplicitLod, | 357 | return Emit(&EmitContext::OpImageSparseSampleDrefExplicitLod, |
| 351 | &EmitContext::OpImageSampleDrefExplicitLod, ctx, inst, ctx.F32[1], | 358 | &EmitContext::OpImageSampleDrefExplicitLod, ctx, inst, ctx.F32[1], |
| 352 | Texture(ctx, index), coords, dref, operands.Mask(), operands.Span()); | 359 | Texture(ctx, info, index), coords, dref, operands.Mask(), operands.Span()); |
| 353 | } | 360 | } |
| 354 | 361 | ||
| 355 | Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 362 | Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
| @@ -357,15 +364,17 @@ Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id | |||
| 357 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | 364 | const auto info{inst->Flags<IR::TextureInstInfo>()}; |
| 358 | const ImageOperands operands(ctx, offset, offset2); | 365 | const ImageOperands operands(ctx, offset, offset2); |
| 359 | return Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst, | 366 | return Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst, |
| 360 | ctx.F32[4], Texture(ctx, index), coords, ctx.Const(info.gather_component), | 367 | ctx.F32[4], Texture(ctx, info, index), coords, ctx.Const(info.gather_component), |
| 361 | operands.Mask(), operands.Span()); | 368 | operands.Mask(), operands.Span()); |
| 362 | } | 369 | } |
| 363 | 370 | ||
| 364 | Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 371 | Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
| 365 | const IR::Value& offset, const IR::Value& offset2, Id dref) { | 372 | const IR::Value& offset, const IR::Value& offset2, Id dref) { |
| 373 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | ||
| 366 | const ImageOperands operands(ctx, offset, offset2); | 374 | const ImageOperands operands(ctx, offset, offset2); |
| 367 | return Emit(&EmitContext::OpImageSparseDrefGather, &EmitContext::OpImageDrefGather, ctx, inst, | 375 | return Emit(&EmitContext::OpImageSparseDrefGather, &EmitContext::OpImageDrefGather, ctx, inst, |
| 368 | ctx.F32[4], Texture(ctx, index), coords, dref, operands.Mask(), operands.Span()); | 376 | ctx.F32[4], Texture(ctx, info, index), coords, dref, operands.Mask(), |
| 377 | operands.Span()); | ||
| 369 | } | 378 | } |
| 370 | 379 | ||
| 371 | Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, | 380 | Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, |
| @@ -376,12 +385,12 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c | |||
| 376 | } | 385 | } |
| 377 | const ImageOperands operands(offset, lod, ms); | 386 | const ImageOperands operands(offset, lod, ms); |
| 378 | return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4], | 387 | return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4], |
| 379 | TextureImage(ctx, index, info), coords, operands.Mask(), operands.Span()); | 388 | TextureImage(ctx, info, index), coords, operands.Mask(), operands.Span()); |
| 380 | } | 389 | } |
| 381 | 390 | ||
| 382 | Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod) { | 391 | Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod) { |
| 383 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | 392 | const auto info{inst->Flags<IR::TextureInstInfo>()}; |
| 384 | const Id image{TextureImage(ctx, index, info)}; | 393 | const Id image{TextureImage(ctx, info, index)}; |
| 385 | const Id zero{ctx.u32_zero_value}; | 394 | const Id zero{ctx.u32_zero_value}; |
| 386 | const auto mips{[&] { return ctx.OpImageQueryLevels(ctx.U32[1], image); }}; | 395 | const auto mips{[&] { return ctx.OpImageQueryLevels(ctx.U32[1], image); }}; |
| 387 | switch (info.type) { | 396 | switch (info.type) { |
| @@ -405,9 +414,10 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i | |||
| 405 | throw LogicError("Unspecified image type {}", info.type.Value()); | 414 | throw LogicError("Unspecified image type {}", info.type.Value()); |
| 406 | } | 415 | } |
| 407 | 416 | ||
| 408 | Id EmitImageQueryLod(EmitContext& ctx, IR::Inst*, const IR::Value& index, Id coords) { | 417 | Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) { |
| 418 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | ||
| 409 | const Id zero{ctx.f32_zero_value}; | 419 | const Id zero{ctx.f32_zero_value}; |
| 410 | const Id sampler{Texture(ctx, index)}; | 420 | const Id sampler{Texture(ctx, info, index)}; |
| 411 | return ctx.OpCompositeConstruct(ctx.F32[4], ctx.OpImageQueryLod(ctx.F32[2], sampler, coords), | 421 | return ctx.OpCompositeConstruct(ctx.F32[4], ctx.OpImageQueryLod(ctx.F32[2], sampler, coords), |
| 412 | zero, zero); | 422 | zero, zero); |
| 413 | } | 423 | } |
| @@ -418,8 +428,8 @@ Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I | |||
| 418 | const ImageOperands operands(ctx, info.has_lod_clamp != 0, derivates, info.num_derivates, | 428 | const ImageOperands operands(ctx, info.has_lod_clamp != 0, derivates, info.num_derivates, |
| 419 | offset, lod_clamp); | 429 | offset, lod_clamp); |
| 420 | return Emit(&EmitContext::OpImageSparseSampleExplicitLod, | 430 | return Emit(&EmitContext::OpImageSparseSampleExplicitLod, |
| 421 | &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], Texture(ctx, index), | 431 | &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], |
| 422 | coords, operands.Mask(), operands.Span()); | 432 | Texture(ctx, info, index), coords, operands.Mask(), operands.Span()); |
| 423 | } | 433 | } |
| 424 | 434 | ||
| 425 | Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) { | 435 | Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) { |
diff --git a/src/shader_recompiler/frontend/ir/modifiers.h b/src/shader_recompiler/frontend/ir/modifiers.h index 5d7efa14c..77cda1f8a 100644 --- a/src/shader_recompiler/frontend/ir/modifiers.h +++ b/src/shader_recompiler/frontend/ir/modifiers.h | |||
| @@ -34,14 +34,15 @@ static_assert(sizeof(FpControl) <= sizeof(u32)); | |||
| 34 | 34 | ||
| 35 | union TextureInstInfo { | 35 | union TextureInstInfo { |
| 36 | u32 raw; | 36 | u32 raw; |
| 37 | BitField<0, 8, TextureType> type; | 37 | BitField<0, 16, u32> descriptor_index; |
| 38 | BitField<8, 1, u32> is_depth; | 38 | BitField<16, 3, TextureType> type; |
| 39 | BitField<9, 1, u32> has_bias; | 39 | BitField<19, 1, u32> is_depth; |
| 40 | BitField<10, 1, u32> has_lod_clamp; | 40 | BitField<20, 1, u32> has_bias; |
| 41 | BitField<11, 1, u32> relaxed_precision; | 41 | BitField<21, 1, u32> has_lod_clamp; |
| 42 | BitField<12, 2, u32> gather_component; | 42 | BitField<22, 1, u32> relaxed_precision; |
| 43 | BitField<14, 2, u32> num_derivates; | 43 | BitField<23, 2, u32> gather_component; |
| 44 | BitField<16, 3, ImageFormat> image_format; | 44 | BitField<25, 2, u32> num_derivates; |
| 45 | BitField<27, 3, ImageFormat> image_format; | ||
| 45 | }; | 46 | }; |
| 46 | static_assert(sizeof(TextureInstInfo) <= sizeof(u32)); | 47 | static_assert(sizeof(TextureInstInfo) <= sizeof(u32)); |
| 47 | 48 | ||
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index b6869d4e4..8f32c9e74 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -482,18 +482,18 @@ OPCODE(BoundImageGradient, F32x4, U32, | |||
| 482 | OPCODE(BoundImageRead, U32x4, U32, Opaque, ) | 482 | OPCODE(BoundImageRead, U32x4, U32, Opaque, ) |
| 483 | OPCODE(BoundImageWrite, Void, U32, Opaque, U32x4, ) | 483 | OPCODE(BoundImageWrite, Void, U32, Opaque, U32x4, ) |
| 484 | 484 | ||
| 485 | OPCODE(ImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) | 485 | OPCODE(ImageSampleImplicitLod, F32x4, Opaque, Opaque, Opaque, Opaque, ) |
| 486 | OPCODE(ImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) | 486 | OPCODE(ImageSampleExplicitLod, F32x4, Opaque, Opaque, Opaque, Opaque, ) |
| 487 | OPCODE(ImageSampleDrefImplicitLod, F32, U32, Opaque, F32, Opaque, Opaque, ) | 487 | OPCODE(ImageSampleDrefImplicitLod, F32, Opaque, Opaque, F32, Opaque, Opaque, ) |
| 488 | OPCODE(ImageSampleDrefExplicitLod, F32, U32, Opaque, F32, Opaque, Opaque, ) | 488 | OPCODE(ImageSampleDrefExplicitLod, F32, Opaque, Opaque, F32, Opaque, Opaque, ) |
| 489 | OPCODE(ImageGather, F32x4, U32, Opaque, Opaque, Opaque, ) | 489 | OPCODE(ImageGather, F32x4, Opaque, Opaque, Opaque, Opaque, ) |
| 490 | OPCODE(ImageGatherDref, F32x4, U32, Opaque, Opaque, Opaque, F32, ) | 490 | OPCODE(ImageGatherDref, F32x4, Opaque, Opaque, Opaque, Opaque, F32, ) |
| 491 | OPCODE(ImageFetch, F32x4, U32, Opaque, Opaque, U32, Opaque, ) | 491 | OPCODE(ImageFetch, F32x4, Opaque, Opaque, Opaque, U32, Opaque, ) |
| 492 | OPCODE(ImageQueryDimensions, U32x4, U32, U32, ) | 492 | OPCODE(ImageQueryDimensions, U32x4, Opaque, U32, ) |
| 493 | OPCODE(ImageQueryLod, F32x4, U32, Opaque, ) | 493 | OPCODE(ImageQueryLod, F32x4, Opaque, Opaque, ) |
| 494 | OPCODE(ImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, ) | 494 | OPCODE(ImageGradient, F32x4, Opaque, Opaque, Opaque, Opaque, Opaque, ) |
| 495 | OPCODE(ImageRead, U32x4, U32, Opaque, ) | 495 | OPCODE(ImageRead, U32x4, Opaque, Opaque, ) |
| 496 | OPCODE(ImageWrite, Void, U32, Opaque, U32x4, ) | 496 | OPCODE(ImageWrite, Void, Opaque, Opaque, U32x4, ) |
| 497 | 497 | ||
| 498 | // Warp operations | 498 | // Warp operations |
| 499 | OPCODE(LaneId, U32, ) | 499 | OPCODE(LaneId, U32, ) |
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index 5ac485522..cfa6b34b9 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <bit> | ||
| 6 | #include <optional> | 7 | #include <optional> |
| 7 | 8 | ||
| 8 | #include <boost/container/small_vector.hpp> | 9 | #include <boost/container/small_vector.hpp> |
| @@ -21,6 +22,8 @@ struct ConstBufferAddr { | |||
| 21 | u32 offset; | 22 | u32 offset; |
| 22 | u32 secondary_index; | 23 | u32 secondary_index; |
| 23 | u32 secondary_offset; | 24 | u32 secondary_offset; |
| 25 | IR::U32 dynamic_offset; | ||
| 26 | u32 count; | ||
| 24 | bool has_secondary; | 27 | bool has_secondary; |
| 25 | }; | 28 | }; |
| 26 | 29 | ||
| @@ -32,6 +35,9 @@ struct TextureInst { | |||
| 32 | 35 | ||
| 33 | using TextureInstVector = boost::container::small_vector<TextureInst, 24>; | 36 | using TextureInstVector = boost::container::small_vector<TextureInst, 24>; |
| 34 | 37 | ||
| 38 | constexpr u32 DESCRIPTOR_SIZE = 8; | ||
| 39 | constexpr u32 DESCRIPTOR_SIZE_SHIFT = static_cast<u32>(std::countr_zero(DESCRIPTOR_SIZE)); | ||
| 40 | |||
| 35 | IR::Opcode IndexedInstruction(const IR::Inst& inst) { | 41 | IR::Opcode IndexedInstruction(const IR::Inst& inst) { |
| 36 | switch (inst.GetOpcode()) { | 42 | switch (inst.GetOpcode()) { |
| 37 | case IR::Opcode::BindlessImageSampleImplicitLod: | 43 | case IR::Opcode::BindlessImageSampleImplicitLod: |
| @@ -131,6 +137,9 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) { | |||
| 131 | if (lhs->has_secondary || rhs->has_secondary) { | 137 | if (lhs->has_secondary || rhs->has_secondary) { |
| 132 | return std::nullopt; | 138 | return std::nullopt; |
| 133 | } | 139 | } |
| 140 | if (lhs->count > 1 || rhs->count > 1) { | ||
| 141 | return std::nullopt; | ||
| 142 | } | ||
| 134 | if (lhs->index > rhs->index || lhs->offset > rhs->offset) { | 143 | if (lhs->index > rhs->index || lhs->offset > rhs->offset) { |
| 135 | std::swap(lhs, rhs); | 144 | std::swap(lhs, rhs); |
| 136 | } | 145 | } |
| @@ -139,9 +148,12 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) { | |||
| 139 | .offset = lhs->offset, | 148 | .offset = lhs->offset, |
| 140 | .secondary_index = rhs->index, | 149 | .secondary_index = rhs->index, |
| 141 | .secondary_offset = rhs->offset, | 150 | .secondary_offset = rhs->offset, |
| 151 | .dynamic_offset = {}, | ||
| 152 | .count = 1, | ||
| 142 | .has_secondary = true, | 153 | .has_secondary = true, |
| 143 | }; | 154 | }; |
| 144 | } | 155 | } |
| 156 | case IR::Opcode::GetCbufU32x2: | ||
| 145 | case IR::Opcode::GetCbufU32: | 157 | case IR::Opcode::GetCbufU32: |
| 146 | break; | 158 | break; |
| 147 | } | 159 | } |
| @@ -152,15 +164,39 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) { | |||
| 152 | // but not supported here at the moment | 164 | // but not supported here at the moment |
| 153 | return std::nullopt; | 165 | return std::nullopt; |
| 154 | } | 166 | } |
| 155 | if (!offset.IsImmediate()) { | 167 | if (offset.IsImmediate()) { |
| 156 | // TODO: Support arrays of textures | 168 | return ConstBufferAddr{ |
| 169 | .index = index.U32(), | ||
| 170 | .offset = offset.U32(), | ||
| 171 | .secondary_index = 0, | ||
| 172 | .secondary_offset = 0, | ||
| 173 | .dynamic_offset = {}, | ||
| 174 | .count = 1, | ||
| 175 | .has_secondary = false, | ||
| 176 | }; | ||
| 177 | } | ||
| 178 | IR::Inst* const offset_inst{offset.InstRecursive()}; | ||
| 179 | if (offset_inst->GetOpcode() != IR::Opcode::IAdd32) { | ||
| 180 | return std::nullopt; | ||
| 181 | } | ||
| 182 | u32 base_offset{}; | ||
| 183 | IR::U32 dynamic_offset; | ||
| 184 | if (offset_inst->Arg(0).IsImmediate()) { | ||
| 185 | base_offset = offset_inst->Arg(0).U32(); | ||
| 186 | dynamic_offset = IR::U32{offset_inst->Arg(1)}; | ||
| 187 | } else if (offset_inst->Arg(1).IsImmediate()) { | ||
| 188 | base_offset = offset_inst->Arg(1).U32(); | ||
| 189 | dynamic_offset = IR::U32{offset_inst->Arg(0)}; | ||
| 190 | } else { | ||
| 157 | return std::nullopt; | 191 | return std::nullopt; |
| 158 | } | 192 | } |
| 159 | return ConstBufferAddr{ | 193 | return ConstBufferAddr{ |
| 160 | .index{index.U32()}, | 194 | .index = index.U32(), |
| 161 | .offset{offset.U32()}, | 195 | .offset = base_offset, |
| 162 | .secondary_index = 0, | 196 | .secondary_index = 0, |
| 163 | .secondary_offset = 0, | 197 | .secondary_offset = 0, |
| 198 | .dynamic_offset = dynamic_offset, | ||
| 199 | .count = 8, | ||
| 164 | .has_secondary = false, | 200 | .has_secondary = false, |
| 165 | }; | 201 | }; |
| 166 | } | 202 | } |
| @@ -179,11 +215,13 @@ TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) { | |||
| 179 | .offset = inst.Arg(0).U32(), | 215 | .offset = inst.Arg(0).U32(), |
| 180 | .secondary_index = 0, | 216 | .secondary_index = 0, |
| 181 | .secondary_offset = 0, | 217 | .secondary_offset = 0, |
| 218 | .dynamic_offset = {}, | ||
| 219 | .count = 1, | ||
| 182 | .has_secondary = false, | 220 | .has_secondary = false, |
| 183 | }; | 221 | }; |
| 184 | } | 222 | } |
| 185 | return TextureInst{ | 223 | return TextureInst{ |
| 186 | .cbuf{addr}, | 224 | .cbuf = addr, |
| 187 | .inst = &inst, | 225 | .inst = &inst, |
| 188 | .block = block, | 226 | .block = block, |
| 189 | }; | 227 | }; |
| @@ -209,18 +247,20 @@ public: | |||
| 209 | 247 | ||
| 210 | u32 Add(const TextureBufferDescriptor& desc) { | 248 | u32 Add(const TextureBufferDescriptor& desc) { |
| 211 | return Add(texture_buffer_descriptors, desc, [&desc](const auto& existing) { | 249 | return Add(texture_buffer_descriptors, desc, [&desc](const auto& existing) { |
| 212 | return desc.has_secondary == existing.has_secondary && | 250 | return desc.cbuf_index == existing.cbuf_index && |
| 213 | desc.cbuf_index == existing.cbuf_index && | ||
| 214 | desc.cbuf_offset == existing.cbuf_offset && | 251 | desc.cbuf_offset == existing.cbuf_offset && |
| 215 | desc.secondary_cbuf_index == existing.secondary_cbuf_index && | 252 | desc.secondary_cbuf_index == existing.secondary_cbuf_index && |
| 216 | desc.secondary_cbuf_offset == existing.secondary_cbuf_offset; | 253 | desc.secondary_cbuf_offset == existing.secondary_cbuf_offset && |
| 254 | desc.count == existing.count && desc.size_shift == existing.size_shift && | ||
| 255 | desc.has_secondary == existing.has_secondary; | ||
| 217 | }); | 256 | }); |
| 218 | } | 257 | } |
| 219 | 258 | ||
| 220 | u32 Add(const ImageBufferDescriptor& desc) { | 259 | u32 Add(const ImageBufferDescriptor& desc) { |
| 221 | return Add(image_buffer_descriptors, desc, [&desc](const auto& existing) { | 260 | return Add(image_buffer_descriptors, desc, [&desc](const auto& existing) { |
| 222 | return desc.format == existing.format && desc.cbuf_index == existing.cbuf_index && | 261 | return desc.format == existing.format && desc.cbuf_index == existing.cbuf_index && |
| 223 | desc.cbuf_offset == existing.cbuf_offset; | 262 | desc.cbuf_offset == existing.cbuf_offset && desc.count == existing.count && |
| 263 | desc.size_shift == existing.size_shift; | ||
| 224 | }); | 264 | }); |
| 225 | } | 265 | } |
| 226 | 266 | ||
| @@ -231,7 +271,8 @@ public: | |||
| 231 | desc.cbuf_index == existing.cbuf_index && | 271 | desc.cbuf_index == existing.cbuf_index && |
| 232 | desc.cbuf_offset == existing.cbuf_offset && | 272 | desc.cbuf_offset == existing.cbuf_offset && |
| 233 | desc.secondary_cbuf_index == existing.secondary_cbuf_index && | 273 | desc.secondary_cbuf_index == existing.secondary_cbuf_index && |
| 234 | desc.secondary_cbuf_offset == existing.secondary_cbuf_offset; | 274 | desc.secondary_cbuf_offset == existing.secondary_cbuf_offset && |
| 275 | desc.count == existing.count && desc.size_shift == existing.size_shift; | ||
| 235 | }); | 276 | }); |
| 236 | } | 277 | } |
| 237 | 278 | ||
| @@ -239,7 +280,8 @@ public: | |||
| 239 | const u32 index{Add(image_descriptors, desc, [&desc](const auto& existing) { | 280 | const u32 index{Add(image_descriptors, desc, [&desc](const auto& existing) { |
| 240 | return desc.type == existing.type && desc.format == existing.format && | 281 | return desc.type == existing.type && desc.format == existing.format && |
| 241 | desc.cbuf_index == existing.cbuf_index && | 282 | desc.cbuf_index == existing.cbuf_index && |
| 242 | desc.cbuf_offset == existing.cbuf_offset; | 283 | desc.cbuf_offset == existing.cbuf_offset && desc.count == existing.count && |
| 284 | desc.size_shift == existing.size_shift; | ||
| 243 | })}; | 285 | })}; |
| 244 | image_descriptors[index].is_written |= desc.is_written; | 286 | image_descriptors[index].is_written |= desc.is_written; |
| 245 | return index; | 287 | return index; |
| @@ -310,7 +352,6 @@ void TexturePass(Environment& env, IR::Program& program) { | |||
| 310 | // This happens on Fire Emblem: Three Houses | 352 | // This happens on Fire Emblem: Three Houses |
| 311 | flags.type.Assign(TextureType::Buffer); | 353 | flags.type.Assign(TextureType::Buffer); |
| 312 | } | 354 | } |
| 313 | inst->SetFlags(flags); | ||
| 314 | break; | 355 | break; |
| 315 | default: | 356 | default: |
| 316 | break; | 357 | break; |
| @@ -329,7 +370,8 @@ void TexturePass(Environment& env, IR::Program& program) { | |||
| 329 | .is_written = is_written, | 370 | .is_written = is_written, |
| 330 | .cbuf_index = cbuf.index, | 371 | .cbuf_index = cbuf.index, |
| 331 | .cbuf_offset = cbuf.offset, | 372 | .cbuf_offset = cbuf.offset, |
| 332 | .count = 1, | 373 | .count = cbuf.count, |
| 374 | .size_shift = DESCRIPTOR_SIZE_SHIFT, | ||
| 333 | }); | 375 | }); |
| 334 | } else { | 376 | } else { |
| 335 | index = descriptors.Add(ImageDescriptor{ | 377 | index = descriptors.Add(ImageDescriptor{ |
| @@ -338,7 +380,8 @@ void TexturePass(Environment& env, IR::Program& program) { | |||
| 338 | .is_written = is_written, | 380 | .is_written = is_written, |
| 339 | .cbuf_index = cbuf.index, | 381 | .cbuf_index = cbuf.index, |
| 340 | .cbuf_offset = cbuf.offset, | 382 | .cbuf_offset = cbuf.offset, |
| 341 | .count = 1, | 383 | .count = cbuf.count, |
| 384 | .size_shift = DESCRIPTOR_SIZE_SHIFT, | ||
| 342 | }); | 385 | }); |
| 343 | } | 386 | } |
| 344 | break; | 387 | break; |
| @@ -351,7 +394,8 @@ void TexturePass(Environment& env, IR::Program& program) { | |||
| 351 | .cbuf_offset = cbuf.offset, | 394 | .cbuf_offset = cbuf.offset, |
| 352 | .secondary_cbuf_index = cbuf.secondary_index, | 395 | .secondary_cbuf_index = cbuf.secondary_index, |
| 353 | .secondary_cbuf_offset = cbuf.secondary_offset, | 396 | .secondary_cbuf_offset = cbuf.secondary_offset, |
| 354 | .count = 1, | 397 | .count = cbuf.count, |
| 398 | .size_shift = DESCRIPTOR_SIZE_SHIFT, | ||
| 355 | }); | 399 | }); |
| 356 | } else { | 400 | } else { |
| 357 | index = descriptors.Add(TextureDescriptor{ | 401 | index = descriptors.Add(TextureDescriptor{ |
| @@ -362,12 +406,23 @@ void TexturePass(Environment& env, IR::Program& program) { | |||
| 362 | .cbuf_offset = cbuf.offset, | 406 | .cbuf_offset = cbuf.offset, |
| 363 | .secondary_cbuf_index = cbuf.secondary_index, | 407 | .secondary_cbuf_index = cbuf.secondary_index, |
| 364 | .secondary_cbuf_offset = cbuf.secondary_offset, | 408 | .secondary_cbuf_offset = cbuf.secondary_offset, |
| 365 | .count = 1, | 409 | .count = cbuf.count, |
| 410 | .size_shift = DESCRIPTOR_SIZE_SHIFT, | ||
| 366 | }); | 411 | }); |
| 367 | } | 412 | } |
| 368 | break; | 413 | break; |
| 369 | } | 414 | } |
| 370 | inst->SetArg(0, IR::Value{index}); | 415 | flags.descriptor_index.Assign(index); |
| 416 | inst->SetFlags(flags); | ||
| 417 | |||
| 418 | if (cbuf.count > 1) { | ||
| 419 | const auto insert_point{IR::Block::InstructionList::s_iterator_to(*inst)}; | ||
| 420 | IR::IREmitter ir{*texture_inst.block, insert_point}; | ||
| 421 | const IR::U32 shift{ir.Imm32(std::countr_zero(DESCRIPTOR_SIZE))}; | ||
| 422 | inst->SetArg(0, ir.ShiftRightArithmetic(cbuf.dynamic_offset, shift)); | ||
| 423 | } else { | ||
| 424 | inst->SetArg(0, IR::Value{}); | ||
| 425 | } | ||
| 371 | } | 426 | } |
| 372 | } | 427 | } |
| 373 | 428 | ||
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index 0f45bdfb6..0f28ae07b 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -67,6 +67,7 @@ struct TextureBufferDescriptor { | |||
| 67 | u32 secondary_cbuf_index; | 67 | u32 secondary_cbuf_index; |
| 68 | u32 secondary_cbuf_offset; | 68 | u32 secondary_cbuf_offset; |
| 69 | u32 count; | 69 | u32 count; |
| 70 | u32 size_shift; | ||
| 70 | }; | 71 | }; |
| 71 | using TextureBufferDescriptors = boost::container::small_vector<TextureBufferDescriptor, 6>; | 72 | using TextureBufferDescriptors = boost::container::small_vector<TextureBufferDescriptor, 6>; |
| 72 | 73 | ||
| @@ -76,6 +77,7 @@ struct ImageBufferDescriptor { | |||
| 76 | u32 cbuf_index; | 77 | u32 cbuf_index; |
| 77 | u32 cbuf_offset; | 78 | u32 cbuf_offset; |
| 78 | u32 count; | 79 | u32 count; |
| 80 | u32 size_shift; | ||
| 79 | }; | 81 | }; |
| 80 | using ImageBufferDescriptors = boost::container::small_vector<ImageBufferDescriptor, 2>; | 82 | using ImageBufferDescriptors = boost::container::small_vector<ImageBufferDescriptor, 2>; |
| 81 | 83 | ||
| @@ -88,6 +90,7 @@ struct TextureDescriptor { | |||
| 88 | u32 secondary_cbuf_index; | 90 | u32 secondary_cbuf_index; |
| 89 | u32 secondary_cbuf_offset; | 91 | u32 secondary_cbuf_offset; |
| 90 | u32 count; | 92 | u32 count; |
| 93 | u32 size_shift; | ||
| 91 | }; | 94 | }; |
| 92 | using TextureDescriptors = boost::container::small_vector<TextureDescriptor, 12>; | 95 | using TextureDescriptors = boost::container::small_vector<TextureDescriptor, 12>; |
| 93 | 96 | ||
| @@ -98,6 +101,7 @@ struct ImageDescriptor { | |||
| 98 | u32 cbuf_index; | 101 | u32 cbuf_index; |
| 99 | u32 cbuf_offset; | 102 | u32 cbuf_offset; |
| 100 | u32 count; | 103 | u32 count; |
| 104 | u32 size_shift; | ||
| 101 | }; | 105 | }; |
| 102 | using ImageDescriptors = boost::container::small_vector<ImageDescriptor, 4>; | 106 | using ImageDescriptors = boost::container::small_vector<ImageDescriptor, 4>; |
| 103 | 107 | ||
diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index aaf9a735e..dd7d2cc0c 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h | |||
| @@ -85,28 +85,30 @@ public: | |||
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | void Add(const Shader::Info& info, VkShaderStageFlags stage) { | 87 | void Add(const Shader::Info& info, VkShaderStageFlags stage) { |
| 88 | Add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, stage, info.constant_buffer_descriptors.size()); | 88 | Add(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, stage, info.constant_buffer_descriptors); |
| 89 | Add(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stage, info.storage_buffers_descriptors.size()); | 89 | Add(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stage, info.storage_buffers_descriptors); |
| 90 | Add(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, stage, info.texture_buffer_descriptors.size()); | 90 | Add(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, stage, info.texture_buffer_descriptors); |
| 91 | Add(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, stage, info.image_buffer_descriptors.size()); | 91 | Add(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, stage, info.image_buffer_descriptors); |
| 92 | Add(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, stage, info.texture_descriptors.size()); | 92 | Add(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, stage, info.texture_descriptors); |
| 93 | Add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, stage, info.image_descriptors.size()); | 93 | Add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, stage, info.image_descriptors); |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | private: | 96 | private: |
| 97 | void Add(VkDescriptorType type, VkShaderStageFlags stage, size_t num) { | 97 | template <typename Descriptors> |
| 98 | void Add(VkDescriptorType type, VkShaderStageFlags stage, const Descriptors& descriptors) { | ||
| 99 | const size_t num{descriptors.size()}; | ||
| 98 | for (size_t i = 0; i < num; ++i) { | 100 | for (size_t i = 0; i < num; ++i) { |
| 99 | bindings.push_back({ | 101 | bindings.push_back({ |
| 100 | .binding = binding, | 102 | .binding = binding, |
| 101 | .descriptorType = type, | 103 | .descriptorType = type, |
| 102 | .descriptorCount = 1, | 104 | .descriptorCount = descriptors[i].count, |
| 103 | .stageFlags = stage, | 105 | .stageFlags = stage, |
| 104 | .pImmutableSamplers = nullptr, | 106 | .pImmutableSamplers = nullptr, |
| 105 | }); | 107 | }); |
| 106 | entries.push_back({ | 108 | entries.push_back({ |
| 107 | .dstBinding = binding, | 109 | .dstBinding = binding, |
| 108 | .dstArrayElement = 0, | 110 | .dstArrayElement = 0, |
| 109 | .descriptorCount = 1, | 111 | .descriptorCount = descriptors[i].count, |
| 110 | .descriptorType = type, | 112 | .descriptorType = type, |
| 111 | .offset = offset, | 113 | .offset = offset, |
| 112 | .stride = sizeof(DescriptorUpdateEntry), | 114 | .stride = sizeof(DescriptorUpdateEntry), |
| @@ -126,21 +128,29 @@ private: | |||
| 126 | inline void PushImageDescriptors(const Shader::Info& info, const VkSampler*& samplers, | 128 | inline void PushImageDescriptors(const Shader::Info& info, const VkSampler*& samplers, |
| 127 | const ImageId*& image_view_ids, TextureCache& texture_cache, | 129 | const ImageId*& image_view_ids, TextureCache& texture_cache, |
| 128 | VKUpdateDescriptorQueue& update_descriptor_queue) { | 130 | VKUpdateDescriptorQueue& update_descriptor_queue) { |
| 129 | image_view_ids += info.texture_buffer_descriptors.size(); | 131 | for (const auto& desc : info.texture_buffer_descriptors) { |
| 130 | image_view_ids += info.image_buffer_descriptors.size(); | 132 | image_view_ids += desc.count; |
| 133 | } | ||
| 134 | for (const auto& desc : info.image_buffer_descriptors) { | ||
| 135 | image_view_ids += desc.count; | ||
| 136 | } | ||
| 131 | for (const auto& desc : info.texture_descriptors) { | 137 | for (const auto& desc : info.texture_descriptors) { |
| 132 | const VkSampler sampler{*(samplers++)}; | 138 | for (u32 index = 0; index < desc.count; ++index) { |
| 133 | ImageView& image_view{texture_cache.GetImageView(*(image_view_ids++))}; | 139 | const VkSampler sampler{*(samplers++)}; |
| 134 | const VkImageView vk_image_view{image_view.Handle(desc.type)}; | 140 | ImageView& image_view{texture_cache.GetImageView(*(image_view_ids++))}; |
| 135 | update_descriptor_queue.AddSampledImage(vk_image_view, sampler); | 141 | const VkImageView vk_image_view{image_view.Handle(desc.type)}; |
| 142 | update_descriptor_queue.AddSampledImage(vk_image_view, sampler); | ||
| 143 | } | ||
| 136 | } | 144 | } |
| 137 | for (const auto& desc : info.image_descriptors) { | 145 | for (const auto& desc : info.image_descriptors) { |
| 138 | ImageView& image_view{texture_cache.GetImageView(*(image_view_ids++))}; | 146 | for (u32 index = 0; index < desc.count; ++index) { |
| 139 | if (desc.is_written) { | 147 | ImageView& image_view{texture_cache.GetImageView(*(image_view_ids++))}; |
| 140 | texture_cache.MarkModification(image_view.image_id); | 148 | if (desc.is_written) { |
| 149 | texture_cache.MarkModification(image_view.image_id); | ||
| 150 | } | ||
| 151 | const VkImageView vk_image_view{image_view.StorageView(desc.type, desc.format)}; | ||
| 152 | update_descriptor_queue.AddImage(vk_image_view); | ||
| 141 | } | 153 | } |
| 142 | const VkImageView vk_image_view{image_view.StorageView(desc.type, desc.format)}; | ||
| 143 | update_descriptor_queue.AddImage(vk_image_view); | ||
| 144 | } | 154 | } |
| 145 | } | 155 | } |
| 146 | 156 | ||
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 45d837ca4..6e9f66262 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp | |||
| @@ -91,35 +91,41 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, | |||
| 91 | const auto& qmd{kepler_compute.launch_description}; | 91 | const auto& qmd{kepler_compute.launch_description}; |
| 92 | const auto& cbufs{qmd.const_buffer_config}; | 92 | const auto& cbufs{qmd.const_buffer_config}; |
| 93 | const bool via_header_index{qmd.linked_tsc != 0}; | 93 | const bool via_header_index{qmd.linked_tsc != 0}; |
| 94 | const auto read_handle{[&](const auto& desc) { | 94 | const auto read_handle{[&](const auto& desc, u32 index) { |
| 95 | ASSERT(((qmd.const_buffer_enable_mask >> desc.cbuf_index) & 1) != 0); | 95 | ASSERT(((qmd.const_buffer_enable_mask >> desc.cbuf_index) & 1) != 0); |
| 96 | const u32 index_offset{index << desc.size_shift}; | ||
| 97 | const u32 offset{desc.cbuf_offset + index_offset}; | ||
| 96 | const GPUVAddr addr{cbufs[desc.cbuf_index].Address() + desc.cbuf_offset}; | 98 | const GPUVAddr addr{cbufs[desc.cbuf_index].Address() + desc.cbuf_offset}; |
| 97 | if constexpr (std::is_same_v<decltype(desc), const Shader::TextureDescriptor&> || | 99 | if constexpr (std::is_same_v<decltype(desc), const Shader::TextureDescriptor&> || |
| 98 | std::is_same_v<decltype(desc), const Shader::TextureBufferDescriptor&>) { | 100 | std::is_same_v<decltype(desc), const Shader::TextureBufferDescriptor&>) { |
| 99 | if (desc.has_secondary) { | 101 | if (desc.has_secondary) { |
| 100 | ASSERT(((qmd.const_buffer_enable_mask >> desc.secondary_cbuf_index) & 1) != 0); | 102 | ASSERT(((qmd.const_buffer_enable_mask >> desc.secondary_cbuf_index) & 1) != 0); |
| 103 | const u32 secondary_offset{desc.secondary_cbuf_offset + index_offset}; | ||
| 101 | const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].Address() + | 104 | const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].Address() + |
| 102 | desc.secondary_cbuf_offset}; | 105 | secondary_offset}; |
| 103 | const u32 lhs_raw{gpu_memory.Read<u32>(addr)}; | 106 | const u32 lhs_raw{gpu_memory.Read<u32>(addr)}; |
| 104 | const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr)}; | 107 | const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr)}; |
| 105 | const u32 raw{lhs_raw | rhs_raw}; | 108 | return TextureHandle{lhs_raw | rhs_raw, via_header_index}; |
| 106 | return TextureHandle{raw, via_header_index}; | ||
| 107 | } | 109 | } |
| 108 | } | 110 | } |
| 109 | return TextureHandle{gpu_memory.Read<u32>(addr), via_header_index}; | 111 | return TextureHandle{gpu_memory.Read<u32>(addr), via_header_index}; |
| 110 | }}; | 112 | }}; |
| 111 | const auto add_image{[&](const auto& desc) { | 113 | const auto add_image{[&](const auto& desc) { |
| 112 | const TextureHandle handle{read_handle(desc)}; | 114 | for (u32 index = 0; index < desc.count; ++index) { |
| 113 | image_view_indices.push_back(handle.image); | 115 | const TextureHandle handle{read_handle(desc, index)}; |
| 116 | image_view_indices.push_back(handle.image); | ||
| 117 | } | ||
| 114 | }}; | 118 | }}; |
| 115 | std::ranges::for_each(info.texture_buffer_descriptors, add_image); | 119 | std::ranges::for_each(info.texture_buffer_descriptors, add_image); |
| 116 | std::ranges::for_each(info.image_buffer_descriptors, add_image); | 120 | std::ranges::for_each(info.image_buffer_descriptors, add_image); |
| 117 | for (const auto& desc : info.texture_descriptors) { | 121 | for (const auto& desc : info.texture_descriptors) { |
| 118 | const TextureHandle handle{read_handle(desc)}; | 122 | for (u32 index = 0; index < desc.count; ++index) { |
| 119 | image_view_indices.push_back(handle.image); | 123 | const TextureHandle handle{read_handle(desc, index)}; |
| 124 | image_view_indices.push_back(handle.image); | ||
| 120 | 125 | ||
| 121 | Sampler* const sampler = texture_cache.GetComputeSampler(handle.sampler); | 126 | Sampler* const sampler = texture_cache.GetComputeSampler(handle.sampler); |
| 122 | samplers.push_back(sampler->Handle()); | 127 | samplers.push_back(sampler->Handle()); |
| 128 | } | ||
| 123 | } | 129 | } |
| 124 | std::ranges::for_each(info.image_descriptors, add_image); | 130 | std::ranges::for_each(info.image_descriptors, add_image); |
| 125 | 131 | ||
| @@ -130,16 +136,18 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, | |||
| 130 | ImageId* texture_buffer_ids{image_view_ids.data()}; | 136 | ImageId* texture_buffer_ids{image_view_ids.data()}; |
| 131 | size_t index{}; | 137 | size_t index{}; |
| 132 | const auto add_buffer{[&](const auto& desc) { | 138 | const auto add_buffer{[&](const auto& desc) { |
| 133 | ASSERT(desc.count == 1); | 139 | for (u32 index = 0; index < desc.count; ++index) { |
| 134 | bool is_written{false}; | 140 | bool is_written{false}; |
| 135 | if constexpr (std::is_same_v<decltype(desc), const Shader::ImageBufferDescriptor&>) { | 141 | if constexpr (std::is_same_v<decltype(desc), const Shader::ImageBufferDescriptor&>) { |
| 136 | is_written = desc.is_written; | 142 | is_written = desc.is_written; |
| 143 | } | ||
| 144 | ImageView& image_view = texture_cache.GetImageView(*texture_buffer_ids); | ||
| 145 | buffer_cache.BindComputeTextureBuffer(index, image_view.GpuAddr(), | ||
| 146 | image_view.BufferSize(), image_view.format, | ||
| 147 | is_written); | ||
| 148 | ++texture_buffer_ids; | ||
| 149 | ++index; | ||
| 137 | } | 150 | } |
| 138 | ImageView& image_view = texture_cache.GetImageView(*texture_buffer_ids); | ||
| 139 | buffer_cache.BindComputeTextureBuffer(index, image_view.GpuAddr(), image_view.BufferSize(), | ||
| 140 | image_view.format, is_written); | ||
| 141 | ++texture_buffer_ids; | ||
| 142 | ++index; | ||
| 143 | }}; | 151 | }}; |
| 144 | std::ranges::for_each(info.texture_buffer_descriptors, add_buffer); | 152 | std::ranges::for_each(info.texture_buffer_descriptors, add_buffer); |
| 145 | std::ranges::for_each(info.image_buffer_descriptors, add_buffer); | 153 | std::ranges::for_each(info.image_buffer_descriptors, add_buffer); |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 08f00b9ce..b7688aef9 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -161,23 +161,26 @@ void GraphicsPipeline::Configure(bool is_indexed) { | |||
| 161 | const Shader::Info& info{stage_infos[stage]}; | 161 | const Shader::Info& info{stage_infos[stage]}; |
| 162 | buffer_cache.SetEnabledUniformBuffers(stage, info.constant_buffer_mask); | 162 | buffer_cache.SetEnabledUniformBuffers(stage, info.constant_buffer_mask); |
| 163 | buffer_cache.UnbindGraphicsStorageBuffers(stage); | 163 | buffer_cache.UnbindGraphicsStorageBuffers(stage); |
| 164 | size_t index{}; | 164 | size_t ssbo_index{}; |
| 165 | for (const auto& desc : info.storage_buffers_descriptors) { | 165 | for (const auto& desc : info.storage_buffers_descriptors) { |
| 166 | ASSERT(desc.count == 1); | 166 | ASSERT(desc.count == 1); |
| 167 | buffer_cache.BindGraphicsStorageBuffer(stage, index, desc.cbuf_index, desc.cbuf_offset, | 167 | buffer_cache.BindGraphicsStorageBuffer(stage, ssbo_index, desc.cbuf_index, |
| 168 | desc.is_written); | 168 | desc.cbuf_offset, desc.is_written); |
| 169 | ++index; | 169 | ++ssbo_index; |
| 170 | } | 170 | } |
| 171 | const auto& cbufs{maxwell3d.state.shader_stages[stage].const_buffers}; | 171 | const auto& cbufs{maxwell3d.state.shader_stages[stage].const_buffers}; |
| 172 | const auto read_handle{[&](const auto& desc) { | 172 | const auto read_handle{[&](const auto& desc, u32 index) { |
| 173 | ASSERT(cbufs[desc.cbuf_index].enabled); | 173 | ASSERT(cbufs[desc.cbuf_index].enabled); |
| 174 | const GPUVAddr addr{cbufs[desc.cbuf_index].address + desc.cbuf_offset}; | 174 | const u32 index_offset{index << desc.size_shift}; |
| 175 | const u32 offset{desc.cbuf_offset + index_offset}; | ||
| 176 | const GPUVAddr addr{cbufs[desc.cbuf_index].address + offset}; | ||
| 175 | if constexpr (std::is_same_v<decltype(desc), const Shader::TextureDescriptor&> || | 177 | if constexpr (std::is_same_v<decltype(desc), const Shader::TextureDescriptor&> || |
| 176 | std::is_same_v<decltype(desc), const Shader::TextureBufferDescriptor&>) { | 178 | std::is_same_v<decltype(desc), const Shader::TextureBufferDescriptor&>) { |
| 177 | if (desc.has_secondary) { | 179 | if (desc.has_secondary) { |
| 178 | ASSERT(cbufs[desc.secondary_cbuf_index].enabled); | 180 | ASSERT(cbufs[desc.secondary_cbuf_index].enabled); |
| 181 | const u32 second_offset{desc.secondary_cbuf_offset + index_offset}; | ||
| 179 | const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].address + | 182 | const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].address + |
| 180 | desc.secondary_cbuf_offset}; | 183 | second_offset}; |
| 181 | const u32 lhs_raw{gpu_memory.Read<u32>(addr)}; | 184 | const u32 lhs_raw{gpu_memory.Read<u32>(addr)}; |
| 182 | const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr)}; | 185 | const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr)}; |
| 183 | const u32 raw{lhs_raw | rhs_raw}; | 186 | const u32 raw{lhs_raw | rhs_raw}; |
| @@ -187,17 +190,21 @@ void GraphicsPipeline::Configure(bool is_indexed) { | |||
| 187 | return TextureHandle{gpu_memory.Read<u32>(addr), via_header_index}; | 190 | return TextureHandle{gpu_memory.Read<u32>(addr), via_header_index}; |
| 188 | }}; | 191 | }}; |
| 189 | const auto add_image{[&](const auto& desc) { | 192 | const auto add_image{[&](const auto& desc) { |
| 190 | const TextureHandle handle{read_handle(desc)}; | 193 | for (u32 index = 0; index < desc.count; ++index) { |
| 191 | image_view_indices.push_back(handle.image); | 194 | const TextureHandle handle{read_handle(desc, index)}; |
| 195 | image_view_indices.push_back(handle.image); | ||
| 196 | } | ||
| 192 | }}; | 197 | }}; |
| 193 | std::ranges::for_each(info.texture_buffer_descriptors, add_image); | 198 | std::ranges::for_each(info.texture_buffer_descriptors, add_image); |
| 194 | std::ranges::for_each(info.image_buffer_descriptors, add_image); | 199 | std::ranges::for_each(info.image_buffer_descriptors, add_image); |
| 195 | for (const auto& desc : info.texture_descriptors) { | 200 | for (const auto& desc : info.texture_descriptors) { |
| 196 | const TextureHandle handle{read_handle(desc)}; | 201 | for (u32 index = 0; index < desc.count; ++index) { |
| 197 | image_view_indices.push_back(handle.image); | 202 | const TextureHandle handle{read_handle(desc, index)}; |
| 203 | image_view_indices.push_back(handle.image); | ||
| 198 | 204 | ||
| 199 | Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.sampler)}; | 205 | Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.sampler)}; |
| 200 | samplers.push_back(sampler->Handle()); | 206 | samplers.push_back(sampler->Handle()); |
| 207 | } | ||
| 201 | } | 208 | } |
| 202 | std::ranges::for_each(info.image_descriptors, add_image); | 209 | std::ranges::for_each(info.image_descriptors, add_image); |
| 203 | } | 210 | } |
| @@ -208,24 +215,30 @@ void GraphicsPipeline::Configure(bool is_indexed) { | |||
| 208 | for (size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) { | 215 | for (size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) { |
| 209 | size_t index{}; | 216 | size_t index{}; |
| 210 | const auto add_buffer{[&](const auto& desc) { | 217 | const auto add_buffer{[&](const auto& desc) { |
| 211 | ASSERT(desc.count == 1); | 218 | for (u32 index = 0; index < desc.count; ++index) { |
| 212 | bool is_written{false}; | 219 | bool is_written{false}; |
| 213 | if constexpr (std::is_same_v<decltype(desc), const Shader::ImageBufferDescriptor&>) { | 220 | if constexpr (std::is_same_v<decltype(desc), |
| 214 | is_written = desc.is_written; | 221 | const Shader::ImageBufferDescriptor&>) { |
| 222 | is_written = desc.is_written; | ||
| 223 | } | ||
| 224 | ImageView& image_view{texture_cache.GetImageView(*texture_buffer_index)}; | ||
| 225 | buffer_cache.BindGraphicsTextureBuffer(stage, index, image_view.GpuAddr(), | ||
| 226 | image_view.BufferSize(), image_view.format, | ||
| 227 | is_written); | ||
| 228 | ++index; | ||
| 229 | ++texture_buffer_index; | ||
| 215 | } | 230 | } |
| 216 | ImageView& image_view{texture_cache.GetImageView(*texture_buffer_index)}; | ||
| 217 | buffer_cache.BindGraphicsTextureBuffer(stage, index, image_view.GpuAddr(), | ||
| 218 | image_view.BufferSize(), image_view.format, | ||
| 219 | is_written); | ||
| 220 | ++index; | ||
| 221 | ++texture_buffer_index; | ||
| 222 | }}; | 231 | }}; |
| 223 | const Shader::Info& info{stage_infos[stage]}; | 232 | const Shader::Info& info{stage_infos[stage]}; |
| 224 | buffer_cache.UnbindGraphicsTextureBuffers(stage); | 233 | buffer_cache.UnbindGraphicsTextureBuffers(stage); |
| 225 | std::ranges::for_each(info.texture_buffer_descriptors, add_buffer); | 234 | std::ranges::for_each(info.texture_buffer_descriptors, add_buffer); |
| 226 | std::ranges::for_each(info.image_buffer_descriptors, add_buffer); | 235 | std::ranges::for_each(info.image_buffer_descriptors, add_buffer); |
| 227 | texture_buffer_index += info.texture_descriptors.size(); | 236 | for (const auto& desc : info.texture_descriptors) { |
| 228 | texture_buffer_index += info.image_descriptors.size(); | 237 | texture_buffer_index += desc.count; |
| 238 | } | ||
| 239 | for (const auto& desc : info.image_descriptors) { | ||
| 240 | texture_buffer_index += desc.count; | ||
| 241 | } | ||
| 229 | } | 242 | } |
| 230 | buffer_cache.UpdateGraphicsBuffers(is_indexed); | 243 | buffer_cache.UpdateGraphicsBuffers(is_indexed); |
| 231 | 244 | ||