summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/backend
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-08-01 18:57:45 -0300
committerGravatar Fernando Sahmkow2021-11-16 22:11:29 +0100
commite66d5b88a6f1c2d85c5cd8e351c6ed52c96a0ecf (patch)
tree0107548906df0b9d42e89451489be6a54ed71bf3 /src/shader_recompiler/backend
parentshader: Properly blacklist and scale image loads (diff)
downloadyuzu-e66d5b88a6f1c2d85c5cd8e351c6ed52c96a0ecf.tar.gz
yuzu-e66d5b88a6f1c2d85c5cd8e351c6ed52c96a0ecf.tar.xz
yuzu-e66d5b88a6f1c2d85c5cd8e351c6ed52c96a0ecf.zip
shader: Properly scale image reads and add GL SPIR-V support
Thanks for everything!
Diffstat (limited to 'src/shader_recompiler/backend')
-rw-r--r--src/shader_recompiler/backend/bindings.h2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_context.cpp4
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm.h2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_image.cpp9
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_instructions.h1
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_image.cpp8
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.cpp65
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.h11
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.h16
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp13
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp74
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_instructions.h1
14 files changed, 163 insertions, 47 deletions
diff --git a/src/shader_recompiler/backend/bindings.h b/src/shader_recompiler/backend/bindings.h
index 35503000c..669702553 100644
--- a/src/shader_recompiler/backend/bindings.h
+++ b/src/shader_recompiler/backend/bindings.h
@@ -14,6 +14,8 @@ struct Bindings {
14 u32 storage_buffer{}; 14 u32 storage_buffer{};
15 u32 texture{}; 15 u32 texture{};
16 u32 image{}; 16 u32 image{};
17 u32 texture_scaling_index{};
18 u32 image_scaling_index{};
17}; 19};
18 20
19} // namespace Shader::Backend 21} // namespace Shader::Backend
diff --git a/src/shader_recompiler/backend/glasm/emit_context.cpp b/src/shader_recompiler/backend/glasm/emit_context.cpp
index 069c019ad..8fd459dfe 100644
--- a/src/shader_recompiler/backend/glasm/emit_context.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_context.cpp
@@ -6,6 +6,7 @@
6 6
7#include "shader_recompiler/backend/bindings.h" 7#include "shader_recompiler/backend/bindings.h"
8#include "shader_recompiler/backend/glasm/emit_context.h" 8#include "shader_recompiler/backend/glasm/emit_context.h"
9#include "shader_recompiler/backend/glasm/emit_glasm.h"
9#include "shader_recompiler/frontend/ir/program.h" 10#include "shader_recompiler/frontend/ir/program.h"
10#include "shader_recompiler/profile.h" 11#include "shader_recompiler/profile.h"
11#include "shader_recompiler/runtime_info.h" 12#include "shader_recompiler/runtime_info.h"
@@ -55,7 +56,8 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
55 } 56 }
56 if (!runtime_info.glasm_use_storage_buffers) { 57 if (!runtime_info.glasm_use_storage_buffers) {
57 if (const size_t num = info.storage_buffers_descriptors.size(); num > 0) { 58 if (const size_t num = info.storage_buffers_descriptors.size(); num > 0) {
58 Add("PARAM c[{}]={{program.local[0..{}]}};", num, num - 1); 59 const size_t index{num + PROGRAM_LOCAL_PARAMETER_STORAGE_BUFFER_BASE};
60 Add("PARAM c[{}]={{program.local[0..{}]}};", index, index - 1);
59 } 61 }
60 } 62 }
61 stage = program.stage; 63 stage = program.stage;
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.h b/src/shader_recompiler/backend/glasm/emit_glasm.h
index bcb55f062..292655acb 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm.h
+++ b/src/shader_recompiler/backend/glasm/emit_glasm.h
@@ -13,6 +13,8 @@
13 13
14namespace Shader::Backend::GLASM { 14namespace Shader::Backend::GLASM {
15 15
16constexpr u32 PROGRAM_LOCAL_PARAMETER_STORAGE_BUFFER_BASE = 1;
17
16[[nodiscard]] std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, 18[[nodiscard]] std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info,
17 IR::Program& program, Bindings& bindings); 19 IR::Program& program, Bindings& bindings);
18 20
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
index 05e88cd97..d325d31c7 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
@@ -617,6 +617,15 @@ void EmitIsTextureScaled(EmitContext& ctx, IR::Inst& inst, const IR::Value& inde
617 1u << index.U32(), ctx.reg_alloc.Define(inst)); 617 1u << index.U32(), ctx.reg_alloc.Define(inst));
618} 618}
619 619
620void EmitIsImageScaled(EmitContext& ctx, IR::Inst& inst, const IR::Value& index) {
621 if (!index.IsImmediate()) {
622 throw NotImplementedException("Non-constant texture rescaling");
623 }
624 ctx.Add("AND.U RC.x,scaling[0].y,{};"
625 "SNE.S {},RC.x,0;",
626 1u << index.U32(), ctx.reg_alloc.Define(inst));
627}
628
620void EmitImageAtomicIAdd32(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, Register coord, 629void EmitImageAtomicIAdd32(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, Register coord,
621 ScalarU32 value) { 630 ScalarU32 value) {
622 ImageAtomic(ctx, inst, index, coord, value, "ADD.U32"); 631 ImageAtomic(ctx, inst, index, coord, value, "ADD.U32");
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
index e2b7d601d..1f343bff5 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
@@ -557,6 +557,7 @@ void EmitImageRead(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, Reg
557void EmitImageWrite(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, Register coord, 557void EmitImageWrite(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, Register coord,
558 Register color); 558 Register color);
559void EmitIsTextureScaled(EmitContext& ctx, IR::Inst& inst, const IR::Value& index); 559void EmitIsTextureScaled(EmitContext& ctx, IR::Inst& inst, const IR::Value& index);
560void EmitIsImageScaled(EmitContext& ctx, IR::Inst& inst, const IR::Value& index);
560void EmitBindlessImageAtomicIAdd32(EmitContext&); 561void EmitBindlessImageAtomicIAdd32(EmitContext&);
561void EmitBindlessImageAtomicSMin32(EmitContext&); 562void EmitBindlessImageAtomicSMin32(EmitContext&);
562void EmitBindlessImageAtomicUMin32(EmitContext&); 563void EmitBindlessImageAtomicUMin32(EmitContext&);
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp
index c0f8ddcad..681aeda8d 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp
@@ -211,7 +211,7 @@ void EmitYDirection(EmitContext& ctx, IR::Inst& inst) {
211} 211}
212 212
213void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) { 213void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) {
214 ctx.Add("MOV.F {}.x,scaling[0].y;", inst); 214 ctx.Add("MOV.F {}.x,scaling[0].z;", inst);
215} 215}
216 216
217void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) { 217void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
index 542a79230..4c26f3829 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
@@ -446,7 +446,7 @@ void EmitYDirection(EmitContext& ctx, IR::Inst& inst) {
446} 446}
447 447
448void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) { 448void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) {
449 ctx.AddF32("{}=scaling.y;", inst); 449 ctx.AddF32("{}=scaling.z;", inst);
450} 450}
451 451
452void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, std::string_view word_offset) { 452void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, std::string_view word_offset) {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
index 82b6f0d77..2f78d0267 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
@@ -620,6 +620,14 @@ void EmitIsTextureScaled(EmitContext& ctx, IR::Inst& inst, const IR::Value& inde
620 ctx.AddU1("{}=(ftou(scaling.x)&{})!=0;", inst, 1u << image_index); 620 ctx.AddU1("{}=(ftou(scaling.x)&{})!=0;", inst, 1u << image_index);
621} 621}
622 622
623void EmitIsImageScaled(EmitContext& ctx, IR::Inst& inst, const IR::Value& index) {
624 if (!index.IsImmediate()) {
625 throw NotImplementedException("Non-constant texture rescaling");
626 }
627 const u32 image_index{index.U32()};
628 ctx.AddU1("{}=(ftou(scaling.y)&{})!=0;", inst, 1u << image_index);
629}
630
623void EmitBindlessImageSampleImplicitLod(EmitContext&) { 631void EmitBindlessImageSampleImplicitLod(EmitContext&) {
624 NotImplemented(); 632 NotImplemented();
625} 633}
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp
index 222baa177..8646fe989 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_context.cpp
@@ -14,6 +14,7 @@
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "common/div_ceil.h" 15#include "common/div_ceil.h"
16#include "shader_recompiler/backend/spirv/emit_context.h" 16#include "shader_recompiler/backend/spirv/emit_context.h"
17#include "shader_recompiler/backend/spirv/emit_spirv.h"
17 18
18namespace Shader::Backend::SPIRV { 19namespace Shader::Backend::SPIRV {
19namespace { 20namespace {
@@ -476,8 +477,9 @@ void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_vie
476 477
477EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_info_, 478EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_info_,
478 IR::Program& program, Bindings& bindings) 479 IR::Program& program, Bindings& bindings)
479 : Sirit::Module(profile_.supported_spirv), profile{profile_}, 480 : Sirit::Module(profile_.supported_spirv), profile{profile_}, runtime_info{runtime_info_},
480 runtime_info{runtime_info_}, stage{program.stage} { 481 stage{program.stage}, texture_rescaling_index{bindings.texture_scaling_index},
482 image_rescaling_index{bindings.image_scaling_index} {
481 const bool is_unified{profile.unified_descriptor_binding}; 483 const bool is_unified{profile.unified_descriptor_binding};
482 u32& uniform_binding{is_unified ? bindings.unified : bindings.uniform_buffer}; 484 u32& uniform_binding{is_unified ? bindings.unified : bindings.uniform_buffer};
483 u32& storage_binding{is_unified ? bindings.unified : bindings.storage_buffer}; 485 u32& storage_binding{is_unified ? bindings.unified : bindings.storage_buffer};
@@ -494,8 +496,8 @@ EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_inf
494 DefineStorageBuffers(program.info, storage_binding); 496 DefineStorageBuffers(program.info, storage_binding);
495 DefineTextureBuffers(program.info, texture_binding); 497 DefineTextureBuffers(program.info, texture_binding);
496 DefineImageBuffers(program.info, image_binding); 498 DefineImageBuffers(program.info, image_binding);
497 DefineTextures(program.info, texture_binding); 499 DefineTextures(program.info, texture_binding, bindings.texture_scaling_index);
498 DefineImages(program.info, image_binding); 500 DefineImages(program.info, image_binding, bindings.image_scaling_index);
499 DefineAttributeMemAccess(program.info); 501 DefineAttributeMemAccess(program.info);
500 DefineGlobalMemoryFunctions(program.info); 502 DefineGlobalMemoryFunctions(program.info);
501 DefineRescalingInput(program.info); 503 DefineRescalingInput(program.info);
@@ -1003,25 +1005,49 @@ void EmitContext::DefineRescalingInput(const Info& info) {
1003 if (!info.uses_rescaling_uniform) { 1005 if (!info.uses_rescaling_uniform) {
1004 return; 1006 return;
1005 } 1007 }
1006 boost::container::static_vector<Id, 2> members{F32[1]}; 1008 if (profile.unified_descriptor_binding) {
1009 DefineRescalingInputPushConstant(info);
1010 } else {
1011 DefineRescalingInputUniformConstant();
1012 }
1013}
1014
1015void EmitContext::DefineRescalingInputPushConstant(const Info& info) {
1016 boost::container::static_vector<Id, 3> members{F32[1]};
1007 u32 member_index{0}; 1017 u32 member_index{0};
1008 const u32 num_texture_words{Common::DivCeil(runtime_info.num_textures, 32u)}; 1018 if (!info.texture_descriptors.empty()) {
1009 if (runtime_info.num_textures > 0) { 1019 rescaling_textures_type = TypeArray(U32[1], Const(4u));
1010 rescaling_textures_type = TypeArray(U32[1], Const(num_texture_words));
1011 Decorate(rescaling_textures_type, spv::Decoration::ArrayStride, 4u); 1020 Decorate(rescaling_textures_type, spv::Decoration::ArrayStride, 4u);
1012 members.push_back(rescaling_textures_type); 1021 members.push_back(rescaling_textures_type);
1013 rescaling_textures_member_index = ++member_index; 1022 rescaling_textures_member_index = ++member_index;
1014 } 1023 }
1024 if (!info.image_descriptors.empty()) {
1025 rescaling_images_type = TypeArray(U32[1], Const(NUM_IMAGE_SCALING_WORDS));
1026 if (rescaling_textures_type.value != rescaling_images_type.value) {
1027 Decorate(rescaling_images_type, spv::Decoration::ArrayStride, 4u);
1028 }
1029 members.push_back(rescaling_images_type);
1030 rescaling_images_member_index = ++member_index;
1031 }
1015 const Id push_constant_struct{TypeStruct(std::span(members.data(), members.size()))}; 1032 const Id push_constant_struct{TypeStruct(std::span(members.data(), members.size()))};
1016 Decorate(push_constant_struct, spv::Decoration::Block); 1033 Decorate(push_constant_struct, spv::Decoration::Block);
1017 Name(push_constant_struct, "ResolutionInfo"); 1034 Name(push_constant_struct, "ResolutionInfo");
1035
1018 MemberDecorate(push_constant_struct, 0u, spv::Decoration::Offset, 0u); 1036 MemberDecorate(push_constant_struct, 0u, spv::Decoration::Offset, 0u);
1019 MemberName(push_constant_struct, 0u, "down_factor"); 1037 MemberName(push_constant_struct, 0u, "down_factor");
1020 if (runtime_info.num_textures > 0) { 1038
1021 MemberDecorate(push_constant_struct, rescaling_textures_member_index, 1039 const u32 offset_bias = stage == Stage::Compute ? sizeof(u32) : 0;
1022 spv::Decoration::Offset, 4u); 1040 if (!info.texture_descriptors.empty()) {
1041 MemberDecorate(
1042 push_constant_struct, rescaling_textures_member_index, spv::Decoration::Offset,
1043 static_cast<u32>(offsetof(RescalingLayout, rescaling_textures) - offset_bias));
1023 MemberName(push_constant_struct, rescaling_textures_member_index, "rescaling_textures"); 1044 MemberName(push_constant_struct, rescaling_textures_member_index, "rescaling_textures");
1024 } 1045 }
1046 if (!info.image_descriptors.empty()) {
1047 MemberDecorate(push_constant_struct, rescaling_images_member_index, spv::Decoration::Offset,
1048 static_cast<u32>(offsetof(RescalingLayout, rescaling_images) - offset_bias));
1049 MemberName(push_constant_struct, rescaling_images_member_index, "rescaling_images");
1050 }
1025 const Id pointer_type{TypePointer(spv::StorageClass::PushConstant, push_constant_struct)}; 1051 const Id pointer_type{TypePointer(spv::StorageClass::PushConstant, push_constant_struct)};
1026 rescaling_push_constants = AddGlobalVariable(pointer_type, spv::StorageClass::PushConstant); 1052 rescaling_push_constants = AddGlobalVariable(pointer_type, spv::StorageClass::PushConstant);
1027 Name(rescaling_push_constants, "rescaling_push_constants"); 1053 Name(rescaling_push_constants, "rescaling_push_constants");
@@ -1031,6 +1057,17 @@ void EmitContext::DefineRescalingInput(const Info& info) {
1031 } 1057 }
1032} 1058}
1033 1059
1060void EmitContext::DefineRescalingInputUniformConstant() {
1061 const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, F32[4])};
1062 rescaling_uniform_constant =
1063 AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant);
1064 Decorate(rescaling_uniform_constant, spv::Decoration::Location, 0u);
1065
1066 if (profile.supported_spirv >= 0x00010400) {
1067 interfaces.push_back(rescaling_uniform_constant);
1068 }
1069}
1070
1034void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { 1071void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) {
1035 if (info.constant_buffer_descriptors.empty()) { 1072 if (info.constant_buffer_descriptors.empty()) {
1036 return; 1073 return;
@@ -1219,7 +1256,7 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) {
1219 } 1256 }
1220} 1257}
1221 1258
1222void EmitContext::DefineTextures(const Info& info, u32& binding) { 1259void EmitContext::DefineTextures(const Info& info, u32& binding, u32& scaling_index) {
1223 textures.reserve(info.texture_descriptors.size()); 1260 textures.reserve(info.texture_descriptors.size());
1224 for (const TextureDescriptor& desc : info.texture_descriptors) { 1261 for (const TextureDescriptor& desc : info.texture_descriptors) {
1225 const Id image_type{ImageType(*this, desc)}; 1262 const Id image_type{ImageType(*this, desc)};
@@ -1241,13 +1278,14 @@ void EmitContext::DefineTextures(const Info& info, u32& binding) {
1241 interfaces.push_back(id); 1278 interfaces.push_back(id);
1242 } 1279 }
1243 ++binding; 1280 ++binding;
1281 ++scaling_index;
1244 } 1282 }
1245 if (info.uses_atomic_image_u32) { 1283 if (info.uses_atomic_image_u32) {
1246 image_u32 = TypePointer(spv::StorageClass::Image, U32[1]); 1284 image_u32 = TypePointer(spv::StorageClass::Image, U32[1]);
1247 } 1285 }
1248} 1286}
1249 1287
1250void EmitContext::DefineImages(const Info& info, u32& binding) { 1288void EmitContext::DefineImages(const Info& info, u32& binding, u32& scaling_index) {
1251 images.reserve(info.image_descriptors.size()); 1289 images.reserve(info.image_descriptors.size());
1252 for (const ImageDescriptor& desc : info.image_descriptors) { 1290 for (const ImageDescriptor& desc : info.image_descriptors) {
1253 if (desc.count != 1) { 1291 if (desc.count != 1) {
@@ -1268,6 +1306,7 @@ void EmitContext::DefineImages(const Info& info, u32& binding) {
1268 interfaces.push_back(id); 1306 interfaces.push_back(id);
1269 } 1307 }
1270 ++binding; 1308 ++binding;
1309 ++scaling_index;
1271 } 1310 }
1272} 1311}
1273 1312
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h
index a7917ac51..b67704baa 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.h
+++ b/src/shader_recompiler/backend/spirv/emit_context.h
@@ -238,9 +238,14 @@ public:
238 Id indexed_load_func{}; 238 Id indexed_load_func{};
239 Id indexed_store_func{}; 239 Id indexed_store_func{};
240 240
241 Id rescaling_uniform_constant{};
241 Id rescaling_push_constants{}; 242 Id rescaling_push_constants{};
242 Id rescaling_textures_type{}; 243 Id rescaling_textures_type{};
244 Id rescaling_images_type{};
243 u32 rescaling_textures_member_index{}; 245 u32 rescaling_textures_member_index{};
246 u32 rescaling_images_member_index{};
247 u32 texture_rescaling_index{};
248 u32 image_rescaling_index{};
244 249
245 Id local_memory{}; 250 Id local_memory{};
246 251
@@ -314,11 +319,13 @@ private:
314 void DefineStorageBuffers(const Info& info, u32& binding); 319 void DefineStorageBuffers(const Info& info, u32& binding);
315 void DefineTextureBuffers(const Info& info, u32& binding); 320 void DefineTextureBuffers(const Info& info, u32& binding);
316 void DefineImageBuffers(const Info& info, u32& binding); 321 void DefineImageBuffers(const Info& info, u32& binding);
317 void DefineTextures(const Info& info, u32& binding); 322 void DefineTextures(const Info& info, u32& binding, u32& scaling_index);
318 void DefineImages(const Info& info, u32& binding); 323 void DefineImages(const Info& info, u32& binding, u32& scaling_index);
319 void DefineAttributeMemAccess(const Info& info); 324 void DefineAttributeMemAccess(const Info& info);
320 void DefineGlobalMemoryFunctions(const Info& info); 325 void DefineGlobalMemoryFunctions(const Info& info);
321 void DefineRescalingInput(const Info& info); 326 void DefineRescalingInput(const Info& info);
327 void DefineRescalingInputPushConstant(const Info& info);
328 void DefineRescalingInputUniformConstant();
322 329
323 void DefineInputs(const IR::Program& program); 330 void DefineInputs(const IR::Program& program);
324 void DefineOutputs(const IR::Program& program); 331 void DefineOutputs(const IR::Program& program);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h
index 7b0d8d980..db0998ad6 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.h
@@ -16,15 +16,23 @@
16 16
17namespace Shader::Backend::SPIRV { 17namespace Shader::Backend::SPIRV {
18 18
19constexpr u32 NUM_TEXTURE_SCALING_WORDS = 4;
20constexpr u32 NUM_IMAGE_SCALING_WORDS = 2;
21constexpr u32 NUM_TEXTURE_AND_IMAGE_SCALING_WORDS =
22 NUM_TEXTURE_SCALING_WORDS + NUM_IMAGE_SCALING_WORDS;
23
24struct RescalingLayout {
25 u32 down_factor;
26 std::array<u32, NUM_TEXTURE_SCALING_WORDS> rescaling_textures;
27 std::array<u32, NUM_IMAGE_SCALING_WORDS> rescaling_images;
28};
29
19[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, 30[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info,
20 IR::Program& program, Bindings& bindings); 31 IR::Program& program, Bindings& bindings);
21 32
22[[nodiscard]] inline std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program) { 33[[nodiscard]] inline std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program) {
23 RuntimeInfo runtime_info{};
24 runtime_info.num_textures = Shader::NumDescriptors(program.info.texture_descriptors);
25
26 Bindings binding; 34 Bindings binding;
27 return EmitSPIRV(profile, runtime_info, program, binding); 35 return EmitSPIRV(profile, {}, program, binding);
28} 36}
29 37
30} // namespace Shader::Backend::SPIRV 38} // namespace Shader::Backend::SPIRV
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 6bb791b03..c0db7452f 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
@@ -527,10 +527,15 @@ Id EmitYDirection(EmitContext& ctx) {
527} 527}
528 528
529Id EmitResolutionDownFactor(EmitContext& ctx) { 529Id EmitResolutionDownFactor(EmitContext& ctx) {
530 const Id pointer_type{ctx.TypePointer(spv::StorageClass::PushConstant, ctx.F32[1])}; 530 if (ctx.profile.unified_descriptor_binding) {
531 const Id pointer{ 531 const Id pointer_type{ctx.TypePointer(spv::StorageClass::PushConstant, ctx.F32[1])};
532 ctx.OpAccessChain(pointer_type, ctx.rescaling_push_constants, ctx.u32_zero_value)}; 532 const Id pointer{
533 return ctx.OpLoad(ctx.F32[1], pointer); 533 ctx.OpAccessChain(pointer_type, ctx.rescaling_push_constants, ctx.u32_zero_value)};
534 return ctx.OpLoad(ctx.F32[1], pointer);
535 } else {
536 const Id composite{ctx.OpLoad(ctx.F32[4], ctx.rescaling_uniform_constant)};
537 return ctx.OpCompositeExtract(ctx.F32[1], composite, 2u);
538 }
534} 539}
535 540
536Id EmitLoadLocal(EmitContext& ctx, Id word_offset) { 541Id EmitLoadLocal(EmitContext& ctx, Id word_offset) {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
index 7d7c0627e..519ce8b9b 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
@@ -224,6 +224,40 @@ Id Emit(MethodPtrType sparse_ptr, MethodPtrType non_sparse_ptr, EmitContext& ctx
224 Decorate(ctx, inst, sample); 224 Decorate(ctx, inst, sample);
225 return ctx.OpCompositeExtract(result_type, sample, 1U); 225 return ctx.OpCompositeExtract(result_type, sample, 1U);
226} 226}
227
228Id IsScaled(EmitContext& ctx, const IR::Value& index, Id member_index, u32 base_index) {
229 const Id push_constant_u32{ctx.TypePointer(spv::StorageClass::PushConstant, ctx.U32[1])};
230 Id bit{};
231 if (index.IsImmediate()) {
232 // Use BitwiseAnd instead of BitfieldExtract for better codegen on Nvidia OpenGL.
233 // LOP32I.NZ is used to set the predicate rather than BFE+ISETP.
234 const u32 index_value{index.U32() + base_index};
235 const Id word_index{ctx.Const(index_value / 32)};
236 const Id bit_index_mask{ctx.Const(1u << (index_value % 32))};
237 const Id pointer{ctx.OpAccessChain(push_constant_u32, ctx.rescaling_push_constants,
238 member_index, word_index)};
239 const Id word{ctx.OpLoad(ctx.U32[1], pointer)};
240 bit = ctx.OpBitwiseAnd(ctx.U32[1], word, bit_index_mask);
241 } else {
242 Id index_value{ctx.Def(index)};
243 if (base_index != 0) {
244 index_value = ctx.OpIAdd(ctx.U32[1], index_value, ctx.Const(base_index));
245 }
246 const Id word_index{ctx.OpShiftRightArithmetic(ctx.U32[1], index_value, ctx.Const(5u))};
247 const Id pointer{ctx.OpAccessChain(push_constant_u32, ctx.rescaling_push_constants,
248 member_index, word_index)};
249 const Id word{ctx.OpLoad(ctx.U32[1], pointer)};
250 const Id bit_index{ctx.OpBitwiseAnd(ctx.U32[1], index_value, ctx.Const(31u))};
251 bit = ctx.OpBitFieldUExtract(ctx.U32[1], index_value, bit_index, ctx.Const(1u));
252 }
253 return ctx.OpINotEqual(ctx.U1, bit, ctx.u32_zero_value);
254}
255
256Id BitTest(EmitContext& ctx, Id mask, Id bit) {
257 const Id shifted{ctx.OpShiftRightLogical(ctx.U32[1], mask, bit)};
258 const Id bit_value{ctx.OpBitwiseAnd(ctx.U32[1], shifted, ctx.Const(1u))};
259 return ctx.OpINotEqual(ctx.U1, bit_value, ctx.u32_zero_value);
260}
227} // Anonymous namespace 261} // Anonymous namespace
228 262
229Id EmitBindlessImageSampleImplicitLod(EmitContext&) { 263Id EmitBindlessImageSampleImplicitLod(EmitContext&) {
@@ -471,29 +505,27 @@ void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id
471} 505}
472 506
473Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) { 507Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) {
474 const Id push_constant_u32{ctx.TypePointer(spv::StorageClass::PushConstant, ctx.U32[1])}; 508 if (ctx.profile.unified_descriptor_binding) {
475 const Id member_index{ctx.Const(ctx.rescaling_textures_member_index)}; 509 const Id member_index{ctx.Const(ctx.rescaling_textures_member_index)};
476 Id bit{}; 510 return IsScaled(ctx, index, member_index, ctx.texture_rescaling_index);
477 if (index.IsImmediate()) {
478 // Use BitwiseAnd instead of BitfieldExtract for better codegen on Nvidia OpenGL.
479 // LOP32I.NZ is used to set the predicate rather than BFE+ISETP.
480 const u32 index_value{index.U32()};
481 const Id word_index{ctx.Const(index_value / 32)};
482 const Id bit_index_mask{ctx.Const(1u << (index_value % 32))};
483 const Id pointer{ctx.OpAccessChain(push_constant_u32, ctx.rescaling_push_constants,
484 member_index, word_index)};
485 const Id word{ctx.OpLoad(ctx.U32[1], pointer)};
486 bit = ctx.OpBitwiseAnd(ctx.U32[1], word, bit_index_mask);
487 } else { 511 } else {
488 const Id index_value{ctx.Def(index)}; 512 const Id composite{ctx.OpLoad(ctx.F32[4], ctx.rescaling_uniform_constant)};
489 const Id word_index{ctx.OpShiftRightArithmetic(ctx.U32[1], index_value, ctx.Const(5u))}; 513 const Id mask_f32{ctx.OpCompositeExtract(ctx.F32[1], composite, 0u)};
490 const Id pointer{ctx.OpAccessChain(push_constant_u32, ctx.rescaling_push_constants, 514 const Id mask{ctx.OpBitcast(ctx.U32[1], mask_f32)};
491 member_index, word_index)}; 515 return BitTest(ctx, mask, ctx.Def(index));
492 const Id word{ctx.OpLoad(ctx.U32[1], pointer)}; 516 }
493 const Id bit_index{ctx.OpBitwiseAnd(ctx.U32[1], index_value, ctx.Const(31u))}; 517}
494 bit = ctx.OpBitFieldUExtract(ctx.U32[1], index_value, bit_index, ctx.Const(1u)); 518
519Id EmitIsImageScaled(EmitContext& ctx, const IR::Value& index) {
520 if (ctx.profile.unified_descriptor_binding) {
521 const Id member_index{ctx.Const(ctx.rescaling_images_member_index)};
522 return IsScaled(ctx, index, member_index, ctx.image_rescaling_index);
523 } else {
524 const Id composite{ctx.OpLoad(ctx.F32[4], ctx.rescaling_uniform_constant)};
525 const Id mask_f32{ctx.OpCompositeExtract(ctx.F32[1], composite, 1u)};
526 const Id mask{ctx.OpBitcast(ctx.U32[1], mask_f32)};
527 return BitTest(ctx, mask, ctx.Def(index));
495 } 528 }
496 return ctx.OpINotEqual(ctx.U1, bit, ctx.u32_zero_value);
497} 529}
498 530
499} // namespace Shader::Backend::SPIRV 531} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
index 69fc18f5f..6cd22dd3e 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
@@ -514,6 +514,7 @@ Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
514Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); 514Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
515void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color); 515void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color);
516Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index); 516Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index);
517Id EmitIsImageScaled(EmitContext& ctx, const IR::Value& index);
517Id EmitBindlessImageAtomicIAdd32(EmitContext&); 518Id EmitBindlessImageAtomicIAdd32(EmitContext&);
518Id EmitBindlessImageAtomicSMin32(EmitContext&); 519Id EmitBindlessImageAtomicSMin32(EmitContext&);
519Id EmitBindlessImageAtomicUMin32(EmitContext&); 520Id EmitBindlessImageAtomicUMin32(EmitContext&);