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_spirv_context_get_set.cpp5
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp22
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp81
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.h2
-rw-r--r--src/shader_recompiler/environment.h2
-rw-r--r--src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp6
-rw-r--r--src/shader_recompiler/ir_opt/constant_propagation_pass.cpp12
-rw-r--r--src/shader_recompiler/ir_opt/texture_pass.cpp25
-rw-r--r--src/shader_recompiler/profile.h2
-rw-r--r--src/shader_recompiler/shader_info.h107
10 files changed, 221 insertions, 43 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index e5a78a914..feca5105f 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
@@ -74,6 +74,11 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
74 case IR::Attribute::ClipDistance7: { 74 case IR::Attribute::ClipDistance7: {
75 const u32 base{static_cast<u32>(IR::Attribute::ClipDistance0)}; 75 const u32 base{static_cast<u32>(IR::Attribute::ClipDistance0)};
76 const u32 index{static_cast<u32>(attr) - base}; 76 const u32 index{static_cast<u32>(attr) - base};
77 if (index >= ctx.profile.max_user_clip_distances) {
78 LOG_WARNING(Shader, "Ignoring clip distance store {} >= {} supported", index,
79 ctx.profile.max_user_clip_distances);
80 return std::nullopt;
81 }
77 const Id clip_num{ctx.Const(index)}; 82 const Id clip_num{ctx.Const(index)};
78 return OutputAccessChain(ctx, ctx.output_f32, ctx.clip_distances, clip_num); 83 return OutputAccessChain(ctx, ctx.output_f32, ctx.clip_distances, clip_num);
79 } 84 }
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
index 22ceca19c..800754554 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
@@ -214,16 +214,16 @@ Id TextureImage(EmitContext& ctx, IR::TextureInstInfo info, const IR::Value& ind
214 } 214 }
215} 215}
216 216
217Id Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { 217std::pair<Id, bool> Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) {
218 if (!index.IsImmediate() || index.U32() != 0) { 218 if (!index.IsImmediate() || index.U32() != 0) {
219 throw NotImplementedException("Indirect image indexing"); 219 throw NotImplementedException("Indirect image indexing");
220 } 220 }
221 if (info.type == TextureType::Buffer) { 221 if (info.type == TextureType::Buffer) {
222 const ImageBufferDefinition def{ctx.image_buffers.at(info.descriptor_index)}; 222 const ImageBufferDefinition def{ctx.image_buffers.at(info.descriptor_index)};
223 return ctx.OpLoad(def.image_type, def.id); 223 return {ctx.OpLoad(def.image_type, def.id), def.is_integer};
224 } else { 224 } else {
225 const ImageDefinition def{ctx.images.at(info.descriptor_index)}; 225 const ImageDefinition def{ctx.images.at(info.descriptor_index)};
226 return ctx.OpLoad(def.image_type, def.id); 226 return {ctx.OpLoad(def.image_type, def.id), def.is_integer};
227 } 227 }
228} 228}
229 229
@@ -566,13 +566,23 @@ Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id co
566 LOG_WARNING(Shader_SPIRV, "Typeless image read not supported by host"); 566 LOG_WARNING(Shader_SPIRV, "Typeless image read not supported by host");
567 return ctx.ConstantNull(ctx.U32[4]); 567 return ctx.ConstantNull(ctx.U32[4]);
568 } 568 }
569 return Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst, ctx.U32[4], 569 const auto [image, is_integer] = Image(ctx, index, info);
570 Image(ctx, index, info), coords, std::nullopt, std::span<const Id>{}); 570 const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
571 Id color{Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst,
572 result_type, image, coords, std::nullopt, std::span<const Id>{})};
573 if (!is_integer) {
574 color = ctx.OpBitcast(ctx.U32[4], color);
575 }
576 return color;
571} 577}
572 578
573void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color) { 579void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color) {
574 const auto info{inst->Flags<IR::TextureInstInfo>()}; 580 const auto info{inst->Flags<IR::TextureInstInfo>()};
575 ctx.OpImageWrite(Image(ctx, index, info), coords, color); 581 const auto [image, is_integer] = Image(ctx, index, info);
582 if (!is_integer) {
583 color = ctx.OpBitcast(ctx.F32[4], color);
584 }
585 ctx.OpImageWrite(image, coords, color);
576} 586}
577 587
578Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) { 588Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) {
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index eb3cc23cc..0442adc83 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -74,20 +74,19 @@ spv::ImageFormat GetImageFormat(ImageFormat format) {
74 throw InvalidArgument("Invalid image format {}", format); 74 throw InvalidArgument("Invalid image format {}", format);
75} 75}
76 76
77Id ImageType(EmitContext& ctx, const ImageDescriptor& desc) { 77Id ImageType(EmitContext& ctx, const ImageDescriptor& desc, Id sampled_type) {
78 const spv::ImageFormat format{GetImageFormat(desc.format)}; 78 const spv::ImageFormat format{GetImageFormat(desc.format)};
79 const Id type{ctx.U32[1]};
80 switch (desc.type) { 79 switch (desc.type) {
81 case TextureType::Color1D: 80 case TextureType::Color1D:
82 return ctx.TypeImage(type, spv::Dim::Dim1D, false, false, false, 2, format); 81 return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, false, false, 2, format);
83 case TextureType::ColorArray1D: 82 case TextureType::ColorArray1D:
84 return ctx.TypeImage(type, spv::Dim::Dim1D, false, true, false, 2, format); 83 return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, true, false, 2, format);
85 case TextureType::Color2D: 84 case TextureType::Color2D:
86 return ctx.TypeImage(type, spv::Dim::Dim2D, false, false, false, 2, format); 85 return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, false, false, 2, format);
87 case TextureType::ColorArray2D: 86 case TextureType::ColorArray2D:
88 return ctx.TypeImage(type, spv::Dim::Dim2D, false, true, false, 2, format); 87 return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, true, false, 2, format);
89 case TextureType::Color3D: 88 case TextureType::Color3D:
90 return ctx.TypeImage(type, spv::Dim::Dim3D, false, false, false, 2, format); 89 return ctx.TypeImage(sampled_type, spv::Dim::Dim3D, false, false, false, 2, format);
91 case TextureType::Buffer: 90 case TextureType::Buffer:
92 throw NotImplementedException("Image buffer"); 91 throw NotImplementedException("Image buffer");
93 default: 92 default:
@@ -97,9 +96,9 @@ Id ImageType(EmitContext& ctx, const ImageDescriptor& desc) {
97} 96}
98 97
99Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin, 98Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin,
100 spv::StorageClass storage_class) { 99 spv::StorageClass storage_class, std::optional<Id> initializer = std::nullopt) {
101 const Id pointer_type{ctx.TypePointer(storage_class, type)}; 100 const Id pointer_type{ctx.TypePointer(storage_class, type)};
102 const Id id{ctx.AddGlobalVariable(pointer_type, storage_class)}; 101 const Id id{ctx.AddGlobalVariable(pointer_type, storage_class, initializer)};
103 if (builtin) { 102 if (builtin) {
104 ctx.Decorate(id, spv::Decoration::BuiltIn, *builtin); 103 ctx.Decorate(id, spv::Decoration::BuiltIn, *builtin);
105 } 104 }
@@ -145,11 +144,12 @@ Id DefineInput(EmitContext& ctx, Id type, bool per_invocation,
145} 144}
146 145
147Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations, 146Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations,
148 std::optional<spv::BuiltIn> builtin = std::nullopt) { 147 std::optional<spv::BuiltIn> builtin = std::nullopt,
148 std::optional<Id> initializer = std::nullopt) {
149 if (invocations && ctx.stage == Stage::TessellationControl) { 149 if (invocations && ctx.stage == Stage::TessellationControl) {
150 type = ctx.TypeArray(type, ctx.Const(*invocations)); 150 type = ctx.TypeArray(type, ctx.Const(*invocations));
151 } 151 }
152 return DefineVariable(ctx, type, builtin, spv::StorageClass::Output); 152 return DefineVariable(ctx, type, builtin, spv::StorageClass::Output, initializer);
153} 153}
154 154
155void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invocations) { 155void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invocations) {
@@ -812,10 +812,14 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
812 labels.push_back(OpLabel()); 812 labels.push_back(OpLabel());
813 } 813 }
814 if (info.stores.ClipDistances()) { 814 if (info.stores.ClipDistances()) {
815 literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2); 815 if (profile.max_user_clip_distances >= 4) {
816 labels.push_back(OpLabel()); 816 literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2);
817 literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2); 817 labels.push_back(OpLabel());
818 labels.push_back(OpLabel()); 818 }
819 if (profile.max_user_clip_distances >= 8) {
820 literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2);
821 labels.push_back(OpLabel());
822 }
819 } 823 }
820 OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); 824 OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone);
821 OpSwitch(compare_index, default_label, literals, labels); 825 OpSwitch(compare_index, default_label, literals, labels);
@@ -844,17 +848,21 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
844 ++label_index; 848 ++label_index;
845 } 849 }
846 if (info.stores.ClipDistances()) { 850 if (info.stores.ClipDistances()) {
847 AddLabel(labels[label_index]); 851 if (profile.max_user_clip_distances >= 4) {
848 const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)}; 852 AddLabel(labels[label_index]);
849 OpStore(pointer, store_value); 853 const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)};
850 OpReturn(); 854 OpStore(pointer, store_value);
851 ++label_index; 855 OpReturn();
852 AddLabel(labels[label_index]); 856 ++label_index;
853 const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))}; 857 }
854 const Id pointer2{OpAccessChain(output_f32, clip_distances, fixed_index)}; 858 if (profile.max_user_clip_distances >= 8) {
855 OpStore(pointer2, store_value); 859 AddLabel(labels[label_index]);
856 OpReturn(); 860 const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))};
857 ++label_index; 861 const Id pointer{OpAccessChain(output_f32, clip_distances, fixed_index)};
862 OpStore(pointer, store_value);
863 OpReturn();
864 ++label_index;
865 }
858 } 866 }
859 AddLabel(end_block); 867 AddLabel(end_block);
860 OpUnreachable(); 868 OpUnreachable();
@@ -1273,7 +1281,9 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) {
1273 throw NotImplementedException("Array of image buffers"); 1281 throw NotImplementedException("Array of image buffers");
1274 } 1282 }
1275 const spv::ImageFormat format{GetImageFormat(desc.format)}; 1283 const spv::ImageFormat format{GetImageFormat(desc.format)};
1276 const Id image_type{TypeImage(U32[1], spv::Dim::Buffer, false, false, false, 2, format)}; 1284 const Id sampled_type{desc.is_integer ? U32[1] : F32[1]};
1285 const Id image_type{
1286 TypeImage(sampled_type, spv::Dim::Buffer, false, false, false, 2, format)};
1277 const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; 1287 const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)};
1278 const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; 1288 const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)};
1279 Decorate(id, spv::Decoration::Binding, binding); 1289 Decorate(id, spv::Decoration::Binding, binding);
@@ -1283,6 +1293,7 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) {
1283 .id = id, 1293 .id = id,
1284 .image_type = image_type, 1294 .image_type = image_type,
1285 .count = desc.count, 1295 .count = desc.count,
1296 .is_integer = desc.is_integer,
1286 }); 1297 });
1287 if (profile.supported_spirv >= 0x00010400) { 1298 if (profile.supported_spirv >= 0x00010400) {
1288 interfaces.push_back(id); 1299 interfaces.push_back(id);
@@ -1327,7 +1338,8 @@ void EmitContext::DefineImages(const Info& info, u32& binding, u32& scaling_inde
1327 if (desc.count != 1) { 1338 if (desc.count != 1) {
1328 throw NotImplementedException("Array of images"); 1339 throw NotImplementedException("Array of images");
1329 } 1340 }
1330 const Id image_type{ImageType(*this, desc)}; 1341 const Id sampled_type{desc.is_integer ? U32[1] : F32[1]};
1342 const Id image_type{ImageType(*this, desc, sampled_type)};
1331 const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; 1343 const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)};
1332 const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; 1344 const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)};
1333 Decorate(id, spv::Decoration::Binding, binding); 1345 Decorate(id, spv::Decoration::Binding, binding);
@@ -1337,6 +1349,7 @@ void EmitContext::DefineImages(const Info& info, u32& binding, u32& scaling_inde
1337 .id = id, 1349 .id = id,
1338 .image_type = image_type, 1350 .image_type = image_type,
1339 .count = desc.count, 1351 .count = desc.count,
1352 .is_integer = desc.is_integer,
1340 }); 1353 });
1341 if (profile.supported_spirv >= 0x00010400) { 1354 if (profile.supported_spirv >= 0x00010400) {
1342 interfaces.push_back(id); 1355 interfaces.push_back(id);
@@ -1528,8 +1541,16 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
1528 if (stage == Stage::Fragment) { 1541 if (stage == Stage::Fragment) {
1529 throw NotImplementedException("Storing ClipDistance in fragment stage"); 1542 throw NotImplementedException("Storing ClipDistance in fragment stage");
1530 } 1543 }
1531 const Id type{TypeArray(F32[1], Const(8U))}; 1544 if (profile.max_user_clip_distances > 0) {
1532 clip_distances = DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance); 1545 const u32 used{std::min(profile.max_user_clip_distances, 8u)};
1546 const std::array<Id, 8> zero{f32_zero_value, f32_zero_value, f32_zero_value,
1547 f32_zero_value, f32_zero_value, f32_zero_value,
1548 f32_zero_value, f32_zero_value};
1549 const Id type{TypeArray(F32[1], Const(used))};
1550 const Id initializer{ConstantComposite(type, std::span(zero).subspan(0, used))};
1551 clip_distances =
1552 DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance, initializer);
1553 }
1533 } 1554 }
1534 if (info.stores[IR::Attribute::Layer] && 1555 if (info.stores[IR::Attribute::Layer] &&
1535 (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { 1556 (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) {
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h
index 1aa79863d..56019ad89 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h
@@ -47,12 +47,14 @@ struct ImageBufferDefinition {
47 Id id; 47 Id id;
48 Id image_type; 48 Id image_type;
49 u32 count; 49 u32 count;
50 bool is_integer;
50}; 51};
51 52
52struct ImageDefinition { 53struct ImageDefinition {
53 Id id; 54 Id id;
54 Id image_type; 55 Id image_type;
55 u32 count; 56 u32 count;
57 bool is_integer;
56}; 58};
57 59
58struct UniformDefinitions { 60struct UniformDefinitions {
diff --git a/src/shader_recompiler/environment.h b/src/shader_recompiler/environment.h
index 15285ab0a..e30bf094a 100644
--- a/src/shader_recompiler/environment.h
+++ b/src/shader_recompiler/environment.h
@@ -24,6 +24,8 @@ public:
24 24
25 [[nodiscard]] virtual TexturePixelFormat ReadTexturePixelFormat(u32 raw_handle) = 0; 25 [[nodiscard]] virtual TexturePixelFormat ReadTexturePixelFormat(u32 raw_handle) = 0;
26 26
27 [[nodiscard]] virtual bool IsTexturePixelFormatInteger(u32 raw_handle) = 0;
28
27 [[nodiscard]] virtual u32 ReadViewportTransformState() = 0; 29 [[nodiscard]] virtual u32 ReadViewportTransformState() = 0;
28 30
29 [[nodiscard]] virtual u32 TextureBoundBuffer() const = 0; 31 [[nodiscard]] virtual u32 TextureBoundBuffer() const = 0;
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
index 70292686f..cb82a326c 100644
--- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
+++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
@@ -913,7 +913,11 @@ void GatherInfoFromHeader(Environment& env, Info& info) {
913 } 913 }
914 for (size_t index = 0; index < 8; ++index) { 914 for (size_t index = 0; index < 8; ++index) {
915 const u16 mask{header.vtg.omap_systemc.clip_distances}; 915 const u16 mask{header.vtg.omap_systemc.clip_distances};
916 info.stores.Set(IR::Attribute::ClipDistance0 + index, ((mask >> index) & 1) != 0); 916 const bool used{((mask >> index) & 1) != 0};
917 info.stores.Set(IR::Attribute::ClipDistance0 + index, used);
918 if (used) {
919 info.used_clip_distances = static_cast<u32>(index) + 1;
920 }
917 } 921 }
918 info.stores.Set(IR::Attribute::PrimitiveId, 922 info.stores.Set(IR::Attribute::PrimitiveId,
919 header.vtg.omap_systemb.primitive_array_id != 0); 923 header.vtg.omap_systemb.primitive_array_id != 0);
diff --git a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
index ec12c843a..e4a73a360 100644
--- a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
+++ b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
@@ -815,6 +815,15 @@ bool FindGradient3DDerivatives(std::array<IR::Value, 3>& results, IR::Value coor
815 return true; 815 return true;
816} 816}
817 817
818void ConvertDerivatives(std::array<IR::Value, 3>& results, IR::IREmitter& ir) {
819 for (size_t i = 0; i < 3; i++) {
820 if (results[i].Type() == IR::Type::U32) {
821 results[i] = results[i].IsImmediate() ? ir.Imm32(Common::BitCast<f32>(results[i].U32()))
822 : ir.BitCast<IR::F32>(IR::U32(results[i]));
823 }
824 }
825}
826
818void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { 827void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
819 IR::TextureInstInfo info = inst.Flags<IR::TextureInstInfo>(); 828 IR::TextureInstInfo info = inst.Flags<IR::TextureInstInfo>();
820 auto orig_opcode = inst.GetOpcode(); 829 auto orig_opcode = inst.GetOpcode();
@@ -831,12 +840,14 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
831 if (!offset.IsImmediate()) { 840 if (!offset.IsImmediate()) {
832 return; 841 return;
833 } 842 }
843 IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
834 IR::Inst* const inst2 = coords.InstRecursive(); 844 IR::Inst* const inst2 = coords.InstRecursive();
835 std::array<std::array<IR::Value, 3>, 3> results_matrix; 845 std::array<std::array<IR::Value, 3>, 3> results_matrix;
836 for (size_t i = 0; i < 3; i++) { 846 for (size_t i = 0; i < 3; i++) {
837 if (!FindGradient3DDerivatives(results_matrix[i], inst2->Arg(i).Resolve())) { 847 if (!FindGradient3DDerivatives(results_matrix[i], inst2->Arg(i).Resolve())) {
838 return; 848 return;
839 } 849 }
850 ConvertDerivatives(results_matrix[i], ir);
840 } 851 }
841 IR::F32 lod_clamp{}; 852 IR::F32 lod_clamp{};
842 if (info.has_lod_clamp != 0) { 853 if (info.has_lod_clamp != 0) {
@@ -846,7 +857,6 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
846 lod_clamp = IR::F32{bias_lc}; 857 lod_clamp = IR::F32{bias_lc};
847 } 858 }
848 } 859 }
849 IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
850 IR::Value new_coords = 860 IR::Value new_coords =
851 ir.CompositeConstruct(results_matrix[0][0], results_matrix[1][0], results_matrix[2][0]); 861 ir.CompositeConstruct(results_matrix[0][0], results_matrix[1][0], results_matrix[2][0]);
852 IR::Value derivatives_1 = ir.CompositeConstruct(results_matrix[0][1], results_matrix[0][2], 862 IR::Value derivatives_1 = ir.CompositeConstruct(results_matrix[0][1], results_matrix[0][2],
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp
index d374c976a..100437f0e 100644
--- a/src/shader_recompiler/ir_opt/texture_pass.cpp
+++ b/src/shader_recompiler/ir_opt/texture_pass.cpp
@@ -372,6 +372,10 @@ TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAdd
372 return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf)); 372 return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf));
373} 373}
374 374
375bool IsTexturePixelFormatInteger(Environment& env, const ConstBufferAddr& cbuf) {
376 return env.IsTexturePixelFormatInteger(GetTextureHandle(env, cbuf));
377}
378
375class Descriptors { 379class Descriptors {
376public: 380public:
377 explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_, 381 explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_,
@@ -403,6 +407,7 @@ public:
403 })}; 407 })};
404 image_buffer_descriptors[index].is_written |= desc.is_written; 408 image_buffer_descriptors[index].is_written |= desc.is_written;
405 image_buffer_descriptors[index].is_read |= desc.is_read; 409 image_buffer_descriptors[index].is_read |= desc.is_read;
410 image_buffer_descriptors[index].is_integer |= desc.is_integer;
406 return index; 411 return index;
407 } 412 }
408 413
@@ -432,6 +437,7 @@ public:
432 })}; 437 })};
433 image_descriptors[index].is_written |= desc.is_written; 438 image_descriptors[index].is_written |= desc.is_written;
434 image_descriptors[index].is_read |= desc.is_read; 439 image_descriptors[index].is_read |= desc.is_read;
440 image_descriptors[index].is_integer |= desc.is_integer;
435 return index; 441 return index;
436 } 442 }
437 443
@@ -469,6 +475,20 @@ void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
469 ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1)))))); 475 ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1))))));
470} 476}
471 477
478bool IsPixelFormatSNorm(TexturePixelFormat pixel_format) {
479 switch (pixel_format) {
480 case TexturePixelFormat::A8B8G8R8_SNORM:
481 case TexturePixelFormat::R8G8_SNORM:
482 case TexturePixelFormat::R8_SNORM:
483 case TexturePixelFormat::R16G16B16A16_SNORM:
484 case TexturePixelFormat::R16G16_SNORM:
485 case TexturePixelFormat::R16_SNORM:
486 return true;
487 default:
488 return false;
489 }
490}
491
472void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_format) { 492void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_format) {
473 const auto it{IR::Block::InstructionList::s_iterator_to(inst)}; 493 const auto it{IR::Block::InstructionList::s_iterator_to(inst)};
474 IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; 494 IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
@@ -587,11 +607,13 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
587 } 607 }
588 const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead}; 608 const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead};
589 const bool is_read{inst->GetOpcode() != IR::Opcode::ImageWrite}; 609 const bool is_read{inst->GetOpcode() != IR::Opcode::ImageWrite};
610 const bool is_integer{IsTexturePixelFormatInteger(env, cbuf)};
590 if (flags.type == TextureType::Buffer) { 611 if (flags.type == TextureType::Buffer) {
591 index = descriptors.Add(ImageBufferDescriptor{ 612 index = descriptors.Add(ImageBufferDescriptor{
592 .format = flags.image_format, 613 .format = flags.image_format,
593 .is_written = is_written, 614 .is_written = is_written,
594 .is_read = is_read, 615 .is_read = is_read,
616 .is_integer = is_integer,
595 .cbuf_index = cbuf.index, 617 .cbuf_index = cbuf.index,
596 .cbuf_offset = cbuf.offset, 618 .cbuf_offset = cbuf.offset,
597 .count = cbuf.count, 619 .count = cbuf.count,
@@ -603,6 +625,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
603 .format = flags.image_format, 625 .format = flags.image_format,
604 .is_written = is_written, 626 .is_written = is_written,
605 .is_read = is_read, 627 .is_read = is_read,
628 .is_integer = is_integer,
606 .cbuf_index = cbuf.index, 629 .cbuf_index = cbuf.index,
607 .cbuf_offset = cbuf.offset, 630 .cbuf_offset = cbuf.offset,
608 .count = cbuf.count, 631 .count = cbuf.count,
@@ -658,7 +681,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
658 if (!host_info.support_snorm_render_buffer && inst->GetOpcode() == IR::Opcode::ImageFetch && 681 if (!host_info.support_snorm_render_buffer && inst->GetOpcode() == IR::Opcode::ImageFetch &&
659 flags.type == TextureType::Buffer) { 682 flags.type == TextureType::Buffer) {
660 const auto pixel_format = ReadTexturePixelFormat(env, cbuf); 683 const auto pixel_format = ReadTexturePixelFormat(env, cbuf);
661 if (pixel_format != TexturePixelFormat::OTHER) { 684 if (IsPixelFormatSNorm(pixel_format)) {
662 PatchTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format); 685 PatchTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format);
663 } 686 }
664 } 687 }
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h
index 66901a965..7578d41cc 100644
--- a/src/shader_recompiler/profile.h
+++ b/src/shader_recompiler/profile.h
@@ -87,6 +87,8 @@ struct Profile {
87 bool has_broken_robust{}; 87 bool has_broken_robust{};
88 88
89 u64 min_ssbo_alignment{}; 89 u64 min_ssbo_alignment{};
90
91 u32 max_user_clip_distances{};
90}; 92};
91 93
92} // namespace Shader 94} // namespace Shader
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h
index b4b4afd37..ed13e6820 100644
--- a/src/shader_recompiler/shader_info.h
+++ b/src/shader_recompiler/shader_info.h
@@ -35,14 +35,109 @@ enum class TextureType : u32 {
35}; 35};
36constexpr u32 NUM_TEXTURE_TYPES = 9; 36constexpr u32 NUM_TEXTURE_TYPES = 9;
37 37
38enum class TexturePixelFormat : u32 { 38enum class TexturePixelFormat {
39 A8B8G8R8_UNORM,
39 A8B8G8R8_SNORM, 40 A8B8G8R8_SNORM,
41 A8B8G8R8_SINT,
42 A8B8G8R8_UINT,
43 R5G6B5_UNORM,
44 B5G6R5_UNORM,
45 A1R5G5B5_UNORM,
46 A2B10G10R10_UNORM,
47 A2B10G10R10_UINT,
48 A2R10G10B10_UNORM,
49 A1B5G5R5_UNORM,
50 A5B5G5R1_UNORM,
51 R8_UNORM,
40 R8_SNORM, 52 R8_SNORM,
41 R8G8_SNORM, 53 R8_SINT,
54 R8_UINT,
55 R16G16B16A16_FLOAT,
56 R16G16B16A16_UNORM,
42 R16G16B16A16_SNORM, 57 R16G16B16A16_SNORM,
43 R16G16_SNORM, 58 R16G16B16A16_SINT,
59 R16G16B16A16_UINT,
60 B10G11R11_FLOAT,
61 R32G32B32A32_UINT,
62 BC1_RGBA_UNORM,
63 BC2_UNORM,
64 BC3_UNORM,
65 BC4_UNORM,
66 BC4_SNORM,
67 BC5_UNORM,
68 BC5_SNORM,
69 BC7_UNORM,
70 BC6H_UFLOAT,
71 BC6H_SFLOAT,
72 ASTC_2D_4X4_UNORM,
73 B8G8R8A8_UNORM,
74 R32G32B32A32_FLOAT,
75 R32G32B32A32_SINT,
76 R32G32_FLOAT,
77 R32G32_SINT,
78 R32_FLOAT,
79 R16_FLOAT,
80 R16_UNORM,
44 R16_SNORM, 81 R16_SNORM,
45 OTHER 82 R16_UINT,
83 R16_SINT,
84 R16G16_UNORM,
85 R16G16_FLOAT,
86 R16G16_UINT,
87 R16G16_SINT,
88 R16G16_SNORM,
89 R32G32B32_FLOAT,
90 A8B8G8R8_SRGB,
91 R8G8_UNORM,
92 R8G8_SNORM,
93 R8G8_SINT,
94 R8G8_UINT,
95 R32G32_UINT,
96 R16G16B16X16_FLOAT,
97 R32_UINT,
98 R32_SINT,
99 ASTC_2D_8X8_UNORM,
100 ASTC_2D_8X5_UNORM,
101 ASTC_2D_5X4_UNORM,
102 B8G8R8A8_SRGB,
103 BC1_RGBA_SRGB,
104 BC2_SRGB,
105 BC3_SRGB,
106 BC7_SRGB,
107 A4B4G4R4_UNORM,
108 G4R4_UNORM,
109 ASTC_2D_4X4_SRGB,
110 ASTC_2D_8X8_SRGB,
111 ASTC_2D_8X5_SRGB,
112 ASTC_2D_5X4_SRGB,
113 ASTC_2D_5X5_UNORM,
114 ASTC_2D_5X5_SRGB,
115 ASTC_2D_10X8_UNORM,
116 ASTC_2D_10X8_SRGB,
117 ASTC_2D_6X6_UNORM,
118 ASTC_2D_6X6_SRGB,
119 ASTC_2D_10X6_UNORM,
120 ASTC_2D_10X6_SRGB,
121 ASTC_2D_10X5_UNORM,
122 ASTC_2D_10X5_SRGB,
123 ASTC_2D_10X10_UNORM,
124 ASTC_2D_10X10_SRGB,
125 ASTC_2D_12X10_UNORM,
126 ASTC_2D_12X10_SRGB,
127 ASTC_2D_12X12_UNORM,
128 ASTC_2D_12X12_SRGB,
129 ASTC_2D_8X6_UNORM,
130 ASTC_2D_8X6_SRGB,
131 ASTC_2D_6X5_UNORM,
132 ASTC_2D_6X5_SRGB,
133 E5B9G9R9_FLOAT,
134 D32_FLOAT,
135 D16_UNORM,
136 X8_D24_UNORM,
137 S8_UINT,
138 D24_UNORM_S8_UINT,
139 S8_UINT_D24_UNORM,
140 D32_FLOAT_S8_UINT,
46}; 141};
47 142
48enum class ImageFormat : u32 { 143enum class ImageFormat : u32 {
@@ -97,6 +192,7 @@ struct ImageBufferDescriptor {
97 ImageFormat format; 192 ImageFormat format;
98 bool is_written; 193 bool is_written;
99 bool is_read; 194 bool is_read;
195 bool is_integer;
100 u32 cbuf_index; 196 u32 cbuf_index;
101 u32 cbuf_offset; 197 u32 cbuf_offset;
102 u32 count; 198 u32 count;
@@ -129,6 +225,7 @@ struct ImageDescriptor {
129 ImageFormat format; 225 ImageFormat format;
130 bool is_written; 226 bool is_written;
131 bool is_read; 227 bool is_read;
228 bool is_integer;
132 u32 cbuf_index; 229 u32 cbuf_index;
133 u32 cbuf_offset; 230 u32 cbuf_offset;
134 u32 count; 231 u32 count;
@@ -227,6 +324,8 @@ struct Info {
227 bool requires_layer_emulation{}; 324 bool requires_layer_emulation{};
228 IR::Attribute emulated_layer{}; 325 IR::Attribute emulated_layer{};
229 326
327 u32 used_clip_distances{};
328
230 boost::container::static_vector<ConstantBufferDescriptor, MAX_CBUFS> 329 boost::container::static_vector<ConstantBufferDescriptor, MAX_CBUFS>
231 constant_buffer_descriptors; 330 constant_buffer_descriptors;
232 boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors; 331 boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors;