summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/backend
diff options
context:
space:
mode:
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.cpp3
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm.h2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_image.cpp18
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_instructions.h5
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp8
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp4
-rw-r--r--src/shader_recompiler/backend/glsl/emit_context.cpp3
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp4
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_image.cpp16
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_instructions.h5
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp8
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.cpp86
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.h17
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.h13
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp12
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp54
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_instructions.h5
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp8
20 files changed, 268 insertions, 9 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.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
index 4ce1c4f54..004658546 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
@@ -448,6 +448,9 @@ std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, I
448 header += fmt::format("SHARED_MEMORY {};", program.shared_memory_size); 448 header += fmt::format("SHARED_MEMORY {};", program.shared_memory_size);
449 header += fmt::format("SHARED shared_mem[]={{program.sharedmem}};"); 449 header += fmt::format("SHARED shared_mem[]={{program.sharedmem}};");
450 } 450 }
451 if (program.info.uses_rescaling_uniform) {
452 header += "PARAM scaling[1]={program.local[0..0]};";
453 }
451 header += "TEMP "; 454 header += "TEMP ";
452 for (size_t index = 0; index < ctx.reg_alloc.NumUsedRegisters(); ++index) { 455 for (size_t index = 0; index < ctx.reg_alloc.NumUsedRegisters(); ++index) {
453 header += fmt::format("R{},", index); 456 header += fmt::format("R{},", index);
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 09e3a9b82..d325d31c7 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
@@ -608,6 +608,24 @@ void EmitImageWrite(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, Re
608 ctx.Add("STOREIM.{} {},{},{},{};", format, image, color, coord, type); 608 ctx.Add("STOREIM.{} {},{},{},{};", format, image, color, coord, type);
609} 609}
610 610
611void EmitIsTextureScaled(EmitContext& ctx, IR::Inst& inst, const IR::Value& index) {
612 if (!index.IsImmediate()) {
613 throw NotImplementedException("Non-constant texture rescaling");
614 }
615 ctx.Add("AND.U RC.x,scaling[0].x,{};"
616 "SNE.S {},RC.x,0;",
617 1u << index.U32(), ctx.reg_alloc.Define(inst));
618}
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
611void 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,
612 ScalarU32 value) { 630 ScalarU32 value) {
613 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 12afda43b..1f343bff5 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
@@ -72,6 +72,7 @@ void EmitInvocationId(EmitContext& ctx, IR::Inst& inst);
72void EmitSampleId(EmitContext& ctx, IR::Inst& inst); 72void EmitSampleId(EmitContext& ctx, IR::Inst& inst);
73void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst); 73void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst);
74void EmitYDirection(EmitContext& ctx, IR::Inst& inst); 74void EmitYDirection(EmitContext& ctx, IR::Inst& inst);
75void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst);
75void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, ScalarU32 word_offset); 76void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, ScalarU32 word_offset);
76void EmitWriteLocal(EmitContext& ctx, ScalarU32 word_offset, ScalarU32 value); 77void EmitWriteLocal(EmitContext& ctx, ScalarU32 word_offset, ScalarU32 value);
77void EmitUndefU1(EmitContext& ctx, IR::Inst& inst); 78void EmitUndefU1(EmitContext& ctx, IR::Inst& inst);
@@ -303,6 +304,8 @@ void EmitIAdd64(EmitContext& ctx, IR::Inst& inst, Register a, Register b);
303void EmitISub32(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b); 304void EmitISub32(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b);
304void EmitISub64(EmitContext& ctx, IR::Inst& inst, Register a, Register b); 305void EmitISub64(EmitContext& ctx, IR::Inst& inst, Register a, Register b);
305void EmitIMul32(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b); 306void EmitIMul32(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b);
307void EmitSDiv32(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b);
308void EmitUDiv32(EmitContext& ctx, IR::Inst& inst, ScalarU32 a, ScalarU32 b);
306void EmitINeg32(EmitContext& ctx, IR::Inst& inst, ScalarS32 value); 309void EmitINeg32(EmitContext& ctx, IR::Inst& inst, ScalarS32 value);
307void EmitINeg64(EmitContext& ctx, IR::Inst& inst, Register value); 310void EmitINeg64(EmitContext& ctx, IR::Inst& inst, Register value);
308void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, ScalarS32 value); 311void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, ScalarS32 value);
@@ -553,6 +556,8 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
553void EmitImageRead(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, Register coord); 556void EmitImageRead(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, Register coord);
554void 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,
555 Register color); 558 Register color);
559void EmitIsTextureScaled(EmitContext& ctx, IR::Inst& inst, const IR::Value& index);
560void EmitIsImageScaled(EmitContext& ctx, IR::Inst& inst, const IR::Value& index);
556void EmitBindlessImageAtomicIAdd32(EmitContext&); 561void EmitBindlessImageAtomicIAdd32(EmitContext&);
557void EmitBindlessImageAtomicSMin32(EmitContext&); 562void EmitBindlessImageAtomicSMin32(EmitContext&);
558void EmitBindlessImageAtomicUMin32(EmitContext&); 563void EmitBindlessImageAtomicUMin32(EmitContext&);
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp
index f55c26b76..8aa494a4d 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp
@@ -90,6 +90,14 @@ void EmitIMul32(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) {
90 ctx.Add("MUL.S {}.x,{},{};", inst, a, b); 90 ctx.Add("MUL.S {}.x,{},{};", inst, a, b);
91} 91}
92 92
93void EmitSDiv32(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) {
94 ctx.Add("DIV.S {}.x,{},{};", inst, a, b);
95}
96
97void EmitUDiv32(EmitContext& ctx, IR::Inst& inst, ScalarU32 a, ScalarU32 b) {
98 ctx.Add("DIV.U {}.x,{},{};", inst, a, b);
99}
100
93void EmitINeg32(EmitContext& ctx, IR::Inst& inst, ScalarS32 value) { 101void EmitINeg32(EmitContext& ctx, IR::Inst& inst, ScalarS32 value) {
94 if (value.type != Type::Register && static_cast<s32>(value.imm_u32) < 0) { 102 if (value.type != Type::Register && static_cast<s32>(value.imm_u32) < 0) {
95 ctx.Add("MOV.S {},{};", inst, -static_cast<s32>(value.imm_u32)); 103 ctx.Add("MOV.S {},{};", inst, -static_cast<s32>(value.imm_u32));
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 e537f6073..681aeda8d 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp
@@ -210,6 +210,10 @@ void EmitYDirection(EmitContext& ctx, IR::Inst& inst) {
210 ctx.Add("MOV.F {}.x,y_direction[0].w;", inst); 210 ctx.Add("MOV.F {}.x,y_direction[0].w;", inst);
211} 211}
212 212
213void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) {
214 ctx.Add("MOV.F {}.x,scaling[0].z;", inst);
215}
216
213void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) { 217void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) {
214 ctx.Add("MOV.S {}.x,0;", inst); 218 ctx.Add("MOV.S {}.x,0;", inst);
215} 219}
diff --git a/src/shader_recompiler/backend/glsl/emit_context.cpp b/src/shader_recompiler/backend/glsl/emit_context.cpp
index 4e6f2c0fe..97bd59302 100644
--- a/src/shader_recompiler/backend/glsl/emit_context.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_context.cpp
@@ -393,6 +393,9 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
393 DefineGenericOutput(index, program.invocations); 393 DefineGenericOutput(index, program.invocations);
394 } 394 }
395 } 395 }
396 if (info.uses_rescaling_uniform) {
397 header += "layout(location=0) uniform vec4 scaling;";
398 }
396 DefineConstantBuffers(bindings); 399 DefineConstantBuffers(bindings);
397 DefineStorageBuffers(bindings); 400 DefineStorageBuffers(bindings);
398 SetupImages(bindings); 401 SetupImages(bindings);
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 170db269a..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
@@ -445,6 +445,10 @@ void EmitYDirection(EmitContext& ctx, IR::Inst& inst) {
445 ctx.AddF32("{}=gl_FrontMaterial.ambient.a;", inst); 445 ctx.AddF32("{}=gl_FrontMaterial.ambient.a;", inst);
446} 446}
447 447
448void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) {
449 ctx.AddF32("{}=scaling.z;", inst);
450}
451
448void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, std::string_view word_offset) { 452void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, std::string_view word_offset) {
449 ctx.AddU32("{}=lmem[{}];", inst, word_offset); 453 ctx.AddU32("{}=lmem[{}];", inst, word_offset);
450} 454}
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
index 447eb8e0a..2f78d0267 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
@@ -612,6 +612,22 @@ void EmitImageAtomicExchange32(EmitContext& ctx, IR::Inst& inst, const IR::Value
612 value); 612 value);
613} 613}
614 614
615void EmitIsTextureScaled(EmitContext& ctx, IR::Inst& inst, const IR::Value& index) {
616 if (!index.IsImmediate()) {
617 throw NotImplementedException("Non-constant texture rescaling");
618 }
619 const u32 image_index{index.U32()};
620 ctx.AddU1("{}=(ftou(scaling.x)&{})!=0;", inst, 1u << image_index);
621}
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
615void EmitBindlessImageSampleImplicitLod(EmitContext&) { 631void EmitBindlessImageSampleImplicitLod(EmitContext&) {
616 NotImplemented(); 632 NotImplemented();
617} 633}
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
index 5936d086f..f86502e4c 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
@@ -85,6 +85,7 @@ void EmitInvocationId(EmitContext& ctx, IR::Inst& inst);
85void EmitSampleId(EmitContext& ctx, IR::Inst& inst); 85void EmitSampleId(EmitContext& ctx, IR::Inst& inst);
86void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst); 86void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst);
87void EmitYDirection(EmitContext& ctx, IR::Inst& inst); 87void EmitYDirection(EmitContext& ctx, IR::Inst& inst);
88void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst);
88void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, std::string_view word_offset); 89void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, std::string_view word_offset);
89void EmitWriteLocal(EmitContext& ctx, std::string_view word_offset, std::string_view value); 90void EmitWriteLocal(EmitContext& ctx, std::string_view word_offset, std::string_view value);
90void EmitUndefU1(EmitContext& ctx, IR::Inst& inst); 91void EmitUndefU1(EmitContext& ctx, IR::Inst& inst);
@@ -362,6 +363,8 @@ void EmitIAdd64(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::strin
362void EmitISub32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b); 363void EmitISub32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b);
363void EmitISub64(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b); 364void EmitISub64(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b);
364void EmitIMul32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b); 365void EmitIMul32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b);
366void EmitSDiv32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b);
367void EmitUDiv32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b);
365void EmitINeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value); 368void EmitINeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value);
366void EmitINeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value); 369void EmitINeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value);
367void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, std::string_view value); 370void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, std::string_view value);
@@ -627,6 +630,8 @@ void EmitImageRead(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
627 std::string_view coords); 630 std::string_view coords);
628void EmitImageWrite(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, 631void EmitImageWrite(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
629 std::string_view coords, std::string_view color); 632 std::string_view coords, std::string_view color);
633void EmitIsTextureScaled(EmitContext& ctx, IR::Inst& inst, const IR::Value& index);
634void EmitIsImageScaled(EmitContext& ctx, IR::Inst& inst, const IR::Value& index);
630void EmitBindlessImageAtomicIAdd32(EmitContext&); 635void EmitBindlessImageAtomicIAdd32(EmitContext&);
631void EmitBindlessImageAtomicSMin32(EmitContext&); 636void EmitBindlessImageAtomicSMin32(EmitContext&);
632void EmitBindlessImageAtomicUMin32(EmitContext&); 637void EmitBindlessImageAtomicUMin32(EmitContext&);
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp
index 38419f88f..88c1d4c5e 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp
@@ -78,6 +78,14 @@ void EmitIMul32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::strin
78 ctx.AddU32("{}=uint({}*{});", inst, a, b); 78 ctx.AddU32("{}=uint({}*{});", inst, a, b);
79} 79}
80 80
81void EmitSDiv32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
82 ctx.AddU32("{}=uint(int({})/int({}));", inst, a, b);
83}
84
85void EmitUDiv32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
86 ctx.AddU32("{}={}/{};", inst, a, b);
87}
88
81void EmitINeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { 89void EmitINeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
82 ctx.AddU32("{}=uint(-({}));", inst, value); 90 ctx.AddU32("{}=uint(-({}));", inst, value);
83} 91}
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp
index 3c84e6466..723455462 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_context.cpp
@@ -7,11 +7,14 @@
7#include <climits> 7#include <climits>
8#include <string_view> 8#include <string_view>
9 9
10#include <boost/container/static_vector.hpp>
11
10#include <fmt/format.h> 12#include <fmt/format.h>
11 13
12#include "common/common_types.h" 14#include "common/common_types.h"
13#include "common/div_ceil.h" 15#include "common/div_ceil.h"
14#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"
15 18
16namespace Shader::Backend::SPIRV { 19namespace Shader::Backend::SPIRV {
17namespace { 20namespace {
@@ -474,8 +477,9 @@ void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_vie
474 477
475EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_info_, 478EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_info_,
476 IR::Program& program, Bindings& bindings) 479 IR::Program& program, Bindings& bindings)
477 : Sirit::Module(profile_.supported_spirv), profile{profile_}, 480 : Sirit::Module(profile_.supported_spirv), profile{profile_}, runtime_info{runtime_info_},
478 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} {
479 const bool is_unified{profile.unified_descriptor_binding}; 483 const bool is_unified{profile.unified_descriptor_binding};
480 u32& uniform_binding{is_unified ? bindings.unified : bindings.uniform_buffer}; 484 u32& uniform_binding{is_unified ? bindings.unified : bindings.uniform_buffer};
481 u32& storage_binding{is_unified ? bindings.unified : bindings.storage_buffer}; 485 u32& storage_binding{is_unified ? bindings.unified : bindings.storage_buffer};
@@ -492,10 +496,11 @@ EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_inf
492 DefineStorageBuffers(program.info, storage_binding); 496 DefineStorageBuffers(program.info, storage_binding);
493 DefineTextureBuffers(program.info, texture_binding); 497 DefineTextureBuffers(program.info, texture_binding);
494 DefineImageBuffers(program.info, image_binding); 498 DefineImageBuffers(program.info, image_binding);
495 DefineTextures(program.info, texture_binding); 499 DefineTextures(program.info, texture_binding, bindings.texture_scaling_index);
496 DefineImages(program.info, image_binding); 500 DefineImages(program.info, image_binding, bindings.image_scaling_index);
497 DefineAttributeMemAccess(program.info); 501 DefineAttributeMemAccess(program.info);
498 DefineGlobalMemoryFunctions(program.info); 502 DefineGlobalMemoryFunctions(program.info);
503 DefineRescalingInput(program.info);
499} 504}
500 505
501EmitContext::~EmitContext() = default; 506EmitContext::~EmitContext() = default;
@@ -996,6 +1001,73 @@ void EmitContext::DefineGlobalMemoryFunctions(const Info& info) {
996 define(&StorageDefinitions::U32x4, storage_types.U32x4, U32[4], sizeof(u32[4])); 1001 define(&StorageDefinitions::U32x4, storage_types.U32x4, U32[4], sizeof(u32[4]));
997} 1002}
998 1003
1004void EmitContext::DefineRescalingInput(const Info& info) {
1005 if (!info.uses_rescaling_uniform) {
1006 return;
1007 }
1008 if (profile.unified_descriptor_binding) {
1009 DefineRescalingInputPushConstant();
1010 } else {
1011 DefineRescalingInputUniformConstant();
1012 }
1013}
1014
1015void EmitContext::DefineRescalingInputPushConstant() {
1016 boost::container::static_vector<Id, 3> members{};
1017 u32 member_index{0};
1018
1019 rescaling_textures_type = TypeArray(U32[1], Const(4u));
1020 Decorate(rescaling_textures_type, spv::Decoration::ArrayStride, 4u);
1021 members.push_back(rescaling_textures_type);
1022 rescaling_textures_member_index = member_index++;
1023
1024 rescaling_images_type = TypeArray(U32[1], Const(NUM_IMAGE_SCALING_WORDS));
1025 Decorate(rescaling_images_type, spv::Decoration::ArrayStride, 4u);
1026 members.push_back(rescaling_images_type);
1027 rescaling_images_member_index = member_index++;
1028
1029 if (stage != Stage::Compute) {
1030 members.push_back(F32[1]);
1031 rescaling_downfactor_member_index = member_index++;
1032 }
1033 const Id push_constant_struct{TypeStruct(std::span(members.data(), members.size()))};
1034 Decorate(push_constant_struct, spv::Decoration::Block);
1035 Name(push_constant_struct, "ResolutionInfo");
1036
1037 MemberDecorate(push_constant_struct, rescaling_textures_member_index, spv::Decoration::Offset,
1038 static_cast<u32>(offsetof(RescalingLayout, rescaling_textures)));
1039 MemberName(push_constant_struct, rescaling_textures_member_index, "rescaling_textures");
1040
1041 MemberDecorate(push_constant_struct, rescaling_images_member_index, spv::Decoration::Offset,
1042 static_cast<u32>(offsetof(RescalingLayout, rescaling_images)));
1043 MemberName(push_constant_struct, rescaling_images_member_index, "rescaling_images");
1044
1045 if (stage != Stage::Compute) {
1046 MemberDecorate(push_constant_struct, rescaling_downfactor_member_index,
1047 spv::Decoration::Offset,
1048 static_cast<u32>(offsetof(RescalingLayout, down_factor)));
1049 MemberName(push_constant_struct, rescaling_downfactor_member_index, "down_factor");
1050 }
1051 const Id pointer_type{TypePointer(spv::StorageClass::PushConstant, push_constant_struct)};
1052 rescaling_push_constants = AddGlobalVariable(pointer_type, spv::StorageClass::PushConstant);
1053 Name(rescaling_push_constants, "rescaling_push_constants");
1054
1055 if (profile.supported_spirv >= 0x00010400) {
1056 interfaces.push_back(rescaling_push_constants);
1057 }
1058}
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
999void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { 1071void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) {
1000 if (info.constant_buffer_descriptors.empty()) { 1072 if (info.constant_buffer_descriptors.empty()) {
1001 return; 1073 return;
@@ -1184,7 +1256,7 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) {
1184 } 1256 }
1185} 1257}
1186 1258
1187void EmitContext::DefineTextures(const Info& info, u32& binding) { 1259void EmitContext::DefineTextures(const Info& info, u32& binding, u32& scaling_index) {
1188 textures.reserve(info.texture_descriptors.size()); 1260 textures.reserve(info.texture_descriptors.size());
1189 for (const TextureDescriptor& desc : info.texture_descriptors) { 1261 for (const TextureDescriptor& desc : info.texture_descriptors) {
1190 const Id image_type{ImageType(*this, desc)}; 1262 const Id image_type{ImageType(*this, desc)};
@@ -1206,13 +1278,14 @@ void EmitContext::DefineTextures(const Info& info, u32& binding) {
1206 interfaces.push_back(id); 1278 interfaces.push_back(id);
1207 } 1279 }
1208 ++binding; 1280 ++binding;
1281 ++scaling_index;
1209 } 1282 }
1210 if (info.uses_atomic_image_u32) { 1283 if (info.uses_atomic_image_u32) {
1211 image_u32 = TypePointer(spv::StorageClass::Image, U32[1]); 1284 image_u32 = TypePointer(spv::StorageClass::Image, U32[1]);
1212 } 1285 }
1213} 1286}
1214 1287
1215void EmitContext::DefineImages(const Info& info, u32& binding) { 1288void EmitContext::DefineImages(const Info& info, u32& binding, u32& scaling_index) {
1216 images.reserve(info.image_descriptors.size()); 1289 images.reserve(info.image_descriptors.size());
1217 for (const ImageDescriptor& desc : info.image_descriptors) { 1290 for (const ImageDescriptor& desc : info.image_descriptors) {
1218 if (desc.count != 1) { 1291 if (desc.count != 1) {
@@ -1233,6 +1306,7 @@ void EmitContext::DefineImages(const Info& info, u32& binding) {
1233 interfaces.push_back(id); 1306 interfaces.push_back(id);
1234 } 1307 }
1235 ++binding; 1308 ++binding;
1309 ++scaling_index;
1236 } 1310 }
1237} 1311}
1238 1312
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h
index 112c52382..63f8185d9 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.h
+++ b/src/shader_recompiler/backend/spirv/emit_context.h
@@ -238,6 +238,16 @@ 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{};
242 Id rescaling_push_constants{};
243 Id rescaling_textures_type{};
244 Id rescaling_images_type{};
245 u32 rescaling_textures_member_index{};
246 u32 rescaling_images_member_index{};
247 u32 rescaling_downfactor_member_index{};
248 u32 texture_rescaling_index{};
249 u32 image_rescaling_index{};
250
241 Id local_memory{}; 251 Id local_memory{};
242 252
243 Id shared_memory_u8{}; 253 Id shared_memory_u8{};
@@ -310,10 +320,13 @@ private:
310 void DefineStorageBuffers(const Info& info, u32& binding); 320 void DefineStorageBuffers(const Info& info, u32& binding);
311 void DefineTextureBuffers(const Info& info, u32& binding); 321 void DefineTextureBuffers(const Info& info, u32& binding);
312 void DefineImageBuffers(const Info& info, u32& binding); 322 void DefineImageBuffers(const Info& info, u32& binding);
313 void DefineTextures(const Info& info, u32& binding); 323 void DefineTextures(const Info& info, u32& binding, u32& scaling_index);
314 void DefineImages(const Info& info, u32& binding); 324 void DefineImages(const Info& info, u32& binding, u32& scaling_index);
315 void DefineAttributeMemAccess(const Info& info); 325 void DefineAttributeMemAccess(const Info& info);
316 void DefineGlobalMemoryFunctions(const Info& info); 326 void DefineGlobalMemoryFunctions(const Info& info);
327 void DefineRescalingInput(const Info& info);
328 void DefineRescalingInputPushConstant();
329 void DefineRescalingInputUniformConstant();
317 330
318 void DefineInputs(const IR::Program& program); 331 void DefineInputs(const IR::Program& program);
319 void DefineOutputs(const IR::Program& program); 332 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 db0c935fe..4b25534ce 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.h
@@ -16,6 +16,19 @@
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 alignas(16) std::array<u32, NUM_TEXTURE_SCALING_WORDS> rescaling_textures;
26 alignas(16) std::array<u32, NUM_IMAGE_SCALING_WORDS> rescaling_images;
27 alignas(16) u32 down_factor;
28};
29constexpr u32 RESCALING_LAYOUT_WORDS_OFFSET = offsetof(RescalingLayout, rescaling_textures);
30constexpr u32 RESCALING_LAYOUT_DOWN_FACTOR_OFFSET = offsetof(RescalingLayout, down_factor);
31
19[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, 32[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info,
20 IR::Program& program, Bindings& bindings); 33 IR::Program& program, Bindings& bindings);
21 34
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 d3a93d5f4..bac683ae1 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
@@ -526,6 +526,18 @@ Id EmitYDirection(EmitContext& ctx) {
526 return ctx.Const(ctx.runtime_info.y_negate ? -1.0f : 1.0f); 526 return ctx.Const(ctx.runtime_info.y_negate ? -1.0f : 1.0f);
527} 527}
528 528
529Id EmitResolutionDownFactor(EmitContext& ctx) {
530 if (ctx.profile.unified_descriptor_binding) {
531 const Id pointer_type{ctx.TypePointer(spv::StorageClass::PushConstant, ctx.F32[1])};
532 const Id index{ctx.Const(ctx.rescaling_downfactor_member_index)};
533 const Id pointer{ctx.OpAccessChain(pointer_type, ctx.rescaling_push_constants, index)};
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 }
539}
540
529Id EmitLoadLocal(EmitContext& ctx, Id word_offset) { 541Id EmitLoadLocal(EmitContext& ctx, Id word_offset) {
530 const Id pointer{ctx.OpAccessChain(ctx.private_u32, ctx.local_memory, word_offset)}; 542 const Id pointer{ctx.OpAccessChain(ctx.private_u32, ctx.local_memory, word_offset)};
531 return ctx.OpLoad(ctx.U32[1], pointer); 543 return ctx.OpLoad(ctx.U32[1], pointer);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
index 1d5364309..4d168a96d 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
@@ -224,6 +224,36 @@ 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 bit_index{ctx.OpBitwiseAnd(ctx.U32[1], index_value, ctx.Const(31u))};
247 bit = ctx.OpBitFieldUExtract(ctx.U32[1], index_value, bit_index, ctx.Const(1u));
248 }
249 return ctx.OpINotEqual(ctx.U1, bit, ctx.u32_zero_value);
250}
251
252Id BitTest(EmitContext& ctx, Id mask, Id bit) {
253 const Id shifted{ctx.OpShiftRightLogical(ctx.U32[1], mask, bit)};
254 const Id bit_value{ctx.OpBitwiseAnd(ctx.U32[1], shifted, ctx.Const(1u))};
255 return ctx.OpINotEqual(ctx.U1, bit_value, ctx.u32_zero_value);
256}
227} // Anonymous namespace 257} // Anonymous namespace
228 258
229Id EmitBindlessImageSampleImplicitLod(EmitContext&) { 259Id EmitBindlessImageSampleImplicitLod(EmitContext&) {
@@ -470,4 +500,28 @@ void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id
470 ctx.OpImageWrite(Image(ctx, index, info), coords, color); 500 ctx.OpImageWrite(Image(ctx, index, info), coords, color);
471} 501}
472 502
503Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) {
504 if (ctx.profile.unified_descriptor_binding) {
505 const Id member_index{ctx.Const(ctx.rescaling_textures_member_index)};
506 return IsScaled(ctx, index, member_index, ctx.texture_rescaling_index);
507 } else {
508 const Id composite{ctx.OpLoad(ctx.F32[4], ctx.rescaling_uniform_constant)};
509 const Id mask_f32{ctx.OpCompositeExtract(ctx.F32[1], composite, 0u)};
510 const Id mask{ctx.OpBitcast(ctx.U32[1], mask_f32)};
511 return BitTest(ctx, mask, ctx.Def(index));
512 }
513}
514
515Id EmitIsImageScaled(EmitContext& ctx, const IR::Value& index) {
516 if (ctx.profile.unified_descriptor_binding) {
517 const Id member_index{ctx.Const(ctx.rescaling_images_member_index)};
518 return IsScaled(ctx, index, member_index, ctx.image_rescaling_index);
519 } else {
520 const Id composite{ctx.OpLoad(ctx.F32[4], ctx.rescaling_uniform_constant)};
521 const Id mask_f32{ctx.OpCompositeExtract(ctx.F32[1], composite, 1u)};
522 const Id mask{ctx.OpBitcast(ctx.U32[1], mask_f32)};
523 return BitTest(ctx, mask, ctx.Def(index));
524 }
525}
526
473} // namespace Shader::Backend::SPIRV 527} // 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 c9db1c164..6cd22dd3e 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
@@ -75,6 +75,7 @@ Id EmitInvocationId(EmitContext& ctx);
75Id EmitSampleId(EmitContext& ctx); 75Id EmitSampleId(EmitContext& ctx);
76Id EmitIsHelperInvocation(EmitContext& ctx); 76Id EmitIsHelperInvocation(EmitContext& ctx);
77Id EmitYDirection(EmitContext& ctx); 77Id EmitYDirection(EmitContext& ctx);
78Id EmitResolutionDownFactor(EmitContext& ctx);
78Id EmitLoadLocal(EmitContext& ctx, Id word_offset); 79Id EmitLoadLocal(EmitContext& ctx, Id word_offset);
79void EmitWriteLocal(EmitContext& ctx, Id word_offset, Id value); 80void EmitWriteLocal(EmitContext& ctx, Id word_offset, Id value);
80Id EmitUndefU1(EmitContext& ctx); 81Id EmitUndefU1(EmitContext& ctx);
@@ -283,6 +284,8 @@ Id EmitIAdd64(EmitContext& ctx, Id a, Id b);
283Id EmitISub32(EmitContext& ctx, Id a, Id b); 284Id EmitISub32(EmitContext& ctx, Id a, Id b);
284Id EmitISub64(EmitContext& ctx, Id a, Id b); 285Id EmitISub64(EmitContext& ctx, Id a, Id b);
285Id EmitIMul32(EmitContext& ctx, Id a, Id b); 286Id EmitIMul32(EmitContext& ctx, Id a, Id b);
287Id EmitSDiv32(EmitContext& ctx, Id a, Id b);
288Id EmitUDiv32(EmitContext& ctx, Id a, Id b);
286Id EmitINeg32(EmitContext& ctx, Id value); 289Id EmitINeg32(EmitContext& ctx, Id value);
287Id EmitINeg64(EmitContext& ctx, Id value); 290Id EmitINeg64(EmitContext& ctx, Id value);
288Id EmitIAbs32(EmitContext& ctx, Id value); 291Id EmitIAbs32(EmitContext& ctx, Id value);
@@ -510,6 +513,8 @@ Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
510 Id derivates, Id offset, Id lod_clamp); 513 Id derivates, Id offset, Id lod_clamp);
511Id 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);
512void 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);
517Id EmitIsImageScaled(EmitContext& ctx, const IR::Value& index);
513Id EmitBindlessImageAtomicIAdd32(EmitContext&); 518Id EmitBindlessImageAtomicIAdd32(EmitContext&);
514Id EmitBindlessImageAtomicSMin32(EmitContext&); 519Id EmitBindlessImageAtomicSMin32(EmitContext&);
515Id EmitBindlessImageAtomicUMin32(EmitContext&); 520Id EmitBindlessImageAtomicUMin32(EmitContext&);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
index 3501d7495..50277eec3 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
@@ -72,6 +72,14 @@ Id EmitIMul32(EmitContext& ctx, Id a, Id b) {
72 return ctx.OpIMul(ctx.U32[1], a, b); 72 return ctx.OpIMul(ctx.U32[1], a, b);
73} 73}
74 74
75Id EmitSDiv32(EmitContext& ctx, Id a, Id b) {
76 return ctx.OpSDiv(ctx.U32[1], a, b);
77}
78
79Id EmitUDiv32(EmitContext& ctx, Id a, Id b) {
80 return ctx.OpUDiv(ctx.U32[1], a, b);
81}
82
75Id EmitINeg32(EmitContext& ctx, Id value) { 83Id EmitINeg32(EmitContext& ctx, Id value) {
76 return ctx.OpSNegate(ctx.U32[1], value); 84 return ctx.OpSNegate(ctx.U32[1], value);
77} 85}