summaryrefslogtreecommitdiff
path: root/src/shader_recompiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler')
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.cpp79
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.h11
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp58
-rw-r--r--src/shader_recompiler/frontend/ir/modifiers.h17
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc24
-rw-r--r--src/shader_recompiler/ir_opt/texture_pass.cpp89
-rw-r--r--src/shader_recompiler/shader_info.h4
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
384template <typename Desc>
385std::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
393Id 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
385void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { 403void 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
1008void EmitContext::DefineTextures(const Info& info, u32& binding) { 1029void 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:
32struct TextureDefinition { 32struct 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
40struct TextureBufferDefinition {
41 Id id;
42 u32 count;
36}; 43};
37 44
38struct ImageBufferDefinition { 45struct ImageBufferDefinition {
39 Id id; 46 Id id;
40 Id image_type; 47 Id image_type;
48 u32 count;
41}; 49};
42 50
43struct ImageDefinition { 51struct ImageDefinition {
44 Id id; 52 Id id;
45 Id image_type; 53 Id image_type;
54 u32 count;
46}; 55};
47 56
48struct UniformDefinitions { 57struct 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
150Id Texture(EmitContext& ctx, const IR::Value& index) { 150Id 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
158Id TextureImage(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { 160Id 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
336Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, 343Id 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
346Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, 353Id 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
355Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 362Id 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
364Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 371Id 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
371Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, 380Id 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
382Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod) { 391Id 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
408Id EmitImageQueryLod(EmitContext& ctx, IR::Inst*, const IR::Value& index, Id coords) { 417Id 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
425Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) { 435Id 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
35union TextureInstInfo { 35union 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};
46static_assert(sizeof(TextureInstInfo) <= sizeof(u32)); 47static_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,
482OPCODE(BoundImageRead, U32x4, U32, Opaque, ) 482OPCODE(BoundImageRead, U32x4, U32, Opaque, )
483OPCODE(BoundImageWrite, Void, U32, Opaque, U32x4, ) 483OPCODE(BoundImageWrite, Void, U32, Opaque, U32x4, )
484 484
485OPCODE(ImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) 485OPCODE(ImageSampleImplicitLod, F32x4, Opaque, Opaque, Opaque, Opaque, )
486OPCODE(ImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) 486OPCODE(ImageSampleExplicitLod, F32x4, Opaque, Opaque, Opaque, Opaque, )
487OPCODE(ImageSampleDrefImplicitLod, F32, U32, Opaque, F32, Opaque, Opaque, ) 487OPCODE(ImageSampleDrefImplicitLod, F32, Opaque, Opaque, F32, Opaque, Opaque, )
488OPCODE(ImageSampleDrefExplicitLod, F32, U32, Opaque, F32, Opaque, Opaque, ) 488OPCODE(ImageSampleDrefExplicitLod, F32, Opaque, Opaque, F32, Opaque, Opaque, )
489OPCODE(ImageGather, F32x4, U32, Opaque, Opaque, Opaque, ) 489OPCODE(ImageGather, F32x4, Opaque, Opaque, Opaque, Opaque, )
490OPCODE(ImageGatherDref, F32x4, U32, Opaque, Opaque, Opaque, F32, ) 490OPCODE(ImageGatherDref, F32x4, Opaque, Opaque, Opaque, Opaque, F32, )
491OPCODE(ImageFetch, F32x4, U32, Opaque, Opaque, U32, Opaque, ) 491OPCODE(ImageFetch, F32x4, Opaque, Opaque, Opaque, U32, Opaque, )
492OPCODE(ImageQueryDimensions, U32x4, U32, U32, ) 492OPCODE(ImageQueryDimensions, U32x4, Opaque, U32, )
493OPCODE(ImageQueryLod, F32x4, U32, Opaque, ) 493OPCODE(ImageQueryLod, F32x4, Opaque, Opaque, )
494OPCODE(ImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, ) 494OPCODE(ImageGradient, F32x4, Opaque, Opaque, Opaque, Opaque, Opaque, )
495OPCODE(ImageRead, U32x4, U32, Opaque, ) 495OPCODE(ImageRead, U32x4, Opaque, Opaque, )
496OPCODE(ImageWrite, Void, U32, Opaque, U32x4, ) 496OPCODE(ImageWrite, Void, Opaque, Opaque, U32x4, )
497 497
498// Warp operations 498// Warp operations
499OPCODE(LaneId, U32, ) 499OPCODE(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
33using TextureInstVector = boost::container::small_vector<TextureInst, 24>; 36using TextureInstVector = boost::container::small_vector<TextureInst, 24>;
34 37
38constexpr u32 DESCRIPTOR_SIZE = 8;
39constexpr u32 DESCRIPTOR_SIZE_SHIFT = static_cast<u32>(std::countr_zero(DESCRIPTOR_SIZE));
40
35IR::Opcode IndexedInstruction(const IR::Inst& inst) { 41IR::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};
71using TextureBufferDescriptors = boost::container::small_vector<TextureBufferDescriptor, 6>; 72using 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};
80using ImageBufferDescriptors = boost::container::small_vector<ImageBufferDescriptor, 2>; 82using 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};
92using TextureDescriptors = boost::container::small_vector<TextureDescriptor, 12>; 95using 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};
102using ImageDescriptors = boost::container::small_vector<ImageDescriptor, 4>; 106using ImageDescriptors = boost::container::small_vector<ImageDescriptor, 4>;
103 107