diff options
Diffstat (limited to 'src/shader_recompiler')
| -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 |
7 files changed, 189 insertions, 93 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 | ||