summaryrefslogtreecommitdiff
path: root/src/shader_recompiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler')
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp16
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_instructions.h1
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp4
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp51
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp4
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_instructions.h2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp4
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_special.cpp4
-rw-r--r--src/shader_recompiler/backend/glsl/glsl_emit_context.cpp7
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp25
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_instructions.h1
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc1
-rw-r--r--src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp1
-rw-r--r--src/shader_recompiler/ir_opt/constant_propagation_pass.cpp23
-rw-r--r--src/shader_recompiler/profile.h4
15 files changed, 125 insertions, 23 deletions
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
index 6f98d0998..7434a1f92 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
@@ -126,6 +126,22 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal
126 } 126 }
127} 127}
128 128
129void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, ScalarU32) {
130 switch (attr) {
131 case IR::Attribute::PrimitiveId:
132 ctx.Add("MOV.S {}.x,primitive.id;", inst);
133 break;
134 case IR::Attribute::InstanceId:
135 ctx.Add("MOV.S {}.x,{}.instance;", inst, ctx.attrib_name);
136 break;
137 case IR::Attribute::VertexId:
138 ctx.Add("MOV.S {}.x,{}.id;", inst, ctx.attrib_name);
139 break;
140 default:
141 throw NotImplementedException("Get U32 attribute {}", attr);
142 }
143}
144
129void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, ScalarF32 value, 145void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, ScalarF32 value,
130 [[maybe_unused]] ScalarU32 vertex) { 146 [[maybe_unused]] ScalarU32 vertex) {
131 const u32 element{static_cast<u32>(attr) % 4}; 147 const u32 element{static_cast<u32>(attr) % 4};
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
index 1f343bff5..b48007856 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
@@ -50,6 +50,7 @@ void EmitGetCbufU32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
50void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); 50void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
51void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); 51void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
52void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, ScalarU32 vertex); 52void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, ScalarU32 vertex);
53void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, ScalarU32 vertex);
53void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, ScalarF32 value, ScalarU32 vertex); 54void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, ScalarF32 value, ScalarU32 vertex);
54void EmitGetAttributeIndexed(EmitContext& ctx, IR::Inst& inst, ScalarS32 offset, ScalarU32 vertex); 55void EmitGetAttributeIndexed(EmitContext& ctx, IR::Inst& inst, ScalarS32 offset, ScalarU32 vertex);
55void EmitSetAttributeIndexed(EmitContext& ctx, ScalarU32 offset, ScalarF32 value, ScalarU32 vertex); 56void EmitSetAttributeIndexed(EmitContext& ctx, ScalarU32 offset, ScalarF32 value, ScalarU32 vertex);
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
index 0f2668d9e..e0ead7a53 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
@@ -7,6 +7,7 @@
7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 7#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
8#include "shader_recompiler/backend/glsl/glsl_emit_context.h" 8#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
9#include "shader_recompiler/frontend/ir/value.h" 9#include "shader_recompiler/frontend/ir/value.h"
10#include "shader_recompiler/profile.h"
10 11
11namespace Shader::Backend::GLSL { 12namespace Shader::Backend::GLSL {
12namespace { 13namespace {
@@ -30,8 +31,9 @@ void EmitConditionRef(EmitContext& ctx, IR::Inst& inst, const IR::Value& value)
30 inst.DestructiveAddUsage(1); 31 inst.DestructiveAddUsage(1);
31 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U1)}; 32 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U1)};
32 const auto input{ctx.var_alloc.Consume(value)}; 33 const auto input{ctx.var_alloc.Consume(value)};
34 const auto suffix{ctx.profile.has_gl_bool_ref_bug ? "?true:false" : ""};
33 if (ret != input) { 35 if (ret != input) {
34 ctx.Add("{}={};", ret, input); 36 ctx.Add("{}={}{};", ret, input, suffix);
35 } 37 }
36} 38}
37 39
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 6477bd192..0c1fbc7b1 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
@@ -102,39 +102,46 @@ void GetCbuf16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, const
102 102
103void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, 103void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
104 const IR::Value& offset) { 104 const IR::Value& offset) {
105 GetCbuf8(ctx, inst, binding, offset, "ftou"); 105 const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};
106 GetCbuf8(ctx, inst, binding, offset, cast);
106} 107}
107 108
108void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, 109void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
109 const IR::Value& offset) { 110 const IR::Value& offset) {
110 GetCbuf8(ctx, inst, binding, offset, "ftoi"); 111 const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "int" : "ftoi"};
112 GetCbuf8(ctx, inst, binding, offset, cast);
111} 113}
112 114
113void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, 115void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
114 const IR::Value& offset) { 116 const IR::Value& offset) {
115 GetCbuf16(ctx, inst, binding, offset, "ftou"); 117 const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};
118 GetCbuf16(ctx, inst, binding, offset, cast);
116} 119}
117 120
118void EmitGetCbufS16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, 121void EmitGetCbufS16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
119 const IR::Value& offset) { 122 const IR::Value& offset) {
120 GetCbuf16(ctx, inst, binding, offset, "ftoi"); 123 const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "int" : "ftoi"};
124 GetCbuf16(ctx, inst, binding, offset, cast);
121} 125}
122 126
123void EmitGetCbufU32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, 127void EmitGetCbufU32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
124 const IR::Value& offset) { 128 const IR::Value& offset) {
125 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)}; 129 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)};
126 GetCbuf(ctx, ret, binding, offset, 32, "ftou"); 130 const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};
131 GetCbuf(ctx, ret, binding, offset, 32, cast);
127} 132}
128 133
129void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, 134void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
130 const IR::Value& offset) { 135 const IR::Value& offset) {
131 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::F32)}; 136 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::F32)};
132 GetCbuf(ctx, ret, binding, offset, 32); 137 const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "utof" : ""};
138 GetCbuf(ctx, ret, binding, offset, 32, cast);
133} 139}
134 140
135void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, 141void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
136 const IR::Value& offset) { 142 const IR::Value& offset) {
137 const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())}; 143 const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())};
144 const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"};
138 if (offset.IsImmediate()) { 145 if (offset.IsImmediate()) {
139 static constexpr u32 cbuf_size{0x10000}; 146 static constexpr u32 cbuf_size{0x10000};
140 const u32 u32_offset{offset.U32()}; 147 const u32 u32_offset{offset.U32()};
@@ -145,26 +152,26 @@ void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding
145 return; 152 return;
146 } 153 }
147 if (u32_offset % 2 == 0) { 154 if (u32_offset % 2 == 0) {
148 ctx.AddU32x2("{}=ftou({}[{}].{}{});", inst, cbuf, u32_offset / 16, 155 ctx.AddU32x2("{}={}({}[{}].{}{});", inst, cast, cbuf, u32_offset / 16,
149 OffsetSwizzle(u32_offset), OffsetSwizzle(u32_offset + 4)); 156 OffsetSwizzle(u32_offset), OffsetSwizzle(u32_offset + 4));
150 } else { 157 } else {
151 ctx.AddU32x2("{}=uvec2(ftou({}[{}].{}),ftou({}[{}].{}));", inst, cbuf, u32_offset / 16, 158 ctx.AddU32x2("{}=uvec2({}({}[{}].{}),{}({}[{}].{}));", inst, cast, cbuf,
152 OffsetSwizzle(u32_offset), cbuf, (u32_offset + 4) / 16, 159 u32_offset / 16, OffsetSwizzle(u32_offset), cast, cbuf,
153 OffsetSwizzle(u32_offset + 4)); 160 (u32_offset + 4) / 16, OffsetSwizzle(u32_offset + 4));
154 } 161 }
155 return; 162 return;
156 } 163 }
157 const auto offset_var{ctx.var_alloc.Consume(offset)}; 164 const auto offset_var{ctx.var_alloc.Consume(offset)};
158 if (!ctx.profile.has_gl_component_indexing_bug) { 165 if (!ctx.profile.has_gl_component_indexing_bug) {
159 ctx.AddU32x2("{}=uvec2(ftou({}[{}>>4][({}>>2)%4]),ftou({}[({}+4)>>4][(({}+4)>>2)%4]));", 166 ctx.AddU32x2("{}=uvec2({}({}[{}>>4][({}>>2)%4]),{}({}[({}+4)>>4][(({}+4)>>2)%4]));", inst,
160 inst, cbuf, offset_var, offset_var, cbuf, offset_var, offset_var); 167 cast, cbuf, offset_var, offset_var, cast, cbuf, offset_var, offset_var);
161 return; 168 return;
162 } 169 }
163 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32x2)}; 170 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32x2)};
164 const auto cbuf_offset{fmt::format("{}>>2", offset_var)}; 171 const auto cbuf_offset{fmt::format("{}>>2", offset_var)};
165 for (u32 swizzle = 0; swizzle < 4; ++swizzle) { 172 for (u32 swizzle = 0; swizzle < 4; ++swizzle) {
166 ctx.Add("if(({}&3)=={}){}=uvec2(ftou({}[{}>>4].{}),ftou({}[({}+4)>>4].{}));", cbuf_offset, 173 ctx.Add("if(({}&3)=={}){}=uvec2({}({}[{}>>4].{}),{}({}[({}+4)>>4].{}));", cbuf_offset,
167 swizzle, ret, cbuf, offset_var, "xyzw"[swizzle], cbuf, offset_var, 174 swizzle, ret, cast, cbuf, offset_var, "xyzw"[swizzle], cast, cbuf, offset_var,
168 "xyzw"[(swizzle + 1) % 4]); 175 "xyzw"[(swizzle + 1) % 4]);
169 } 176 }
170} 177}
@@ -221,6 +228,22 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
221 } 228 }
222} 229}
223 230
231void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, std::string_view) {
232 switch (attr) {
233 case IR::Attribute::PrimitiveId:
234 ctx.AddU32("{}=uint(gl_PrimitiveID);", inst);
235 break;
236 case IR::Attribute::InstanceId:
237 ctx.AddU32("{}=uint(gl_InstanceID);", inst);
238 break;
239 case IR::Attribute::VertexId:
240 ctx.AddU32("{}=uint(gl_VertexID);", inst);
241 break;
242 default:
243 throw NotImplementedException("Get U32 attribute {}", attr);
244 }
245}
246
224void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view value, 247void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view value,
225 [[maybe_unused]] std::string_view vertex) { 248 [[maybe_unused]] std::string_view vertex) {
226 if (IR::IsGeneric(attr)) { 249 if (IR::IsGeneric(attr)) {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp
index b765a251b..474189d87 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp
@@ -125,11 +125,11 @@ void EmitFPNeg16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& i
125} 125}
126 126
127void EmitFPNeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { 127void EmitFPNeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
128 ctx.AddF32("{}=-({});", inst, value); 128 ctx.AddF32("{}=0.f-({});", inst, value);
129} 129}
130 130
131void EmitFPNeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value) { 131void EmitFPNeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
132 ctx.AddF64("{}=-({});", inst, value); 132 ctx.AddF64("{}=double(0.)-({});", inst, value);
133} 133}
134 134
135void EmitFPSin(EmitContext& ctx, IR::Inst& inst, std::string_view value) { 135void EmitFPSin(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
index f86502e4c..6cabbc717 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
@@ -60,6 +60,8 @@ void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding
60 const IR::Value& offset); 60 const IR::Value& offset);
61void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, 61void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
62 std::string_view vertex); 62 std::string_view vertex);
63void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
64 std::string_view vertex);
63void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view value, 65void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view value,
64 std::string_view vertex); 66 std::string_view vertex);
65void EmitGetAttributeIndexed(EmitContext& ctx, IR::Inst& inst, std::string_view offset, 67void EmitGetAttributeIndexed(EmitContext& ctx, IR::Inst& inst, std::string_view offset,
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp
index 44060df33..b0d85be99 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp
@@ -87,11 +87,11 @@ void EmitUDiv32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::strin
87} 87}
88 88
89void EmitINeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { 89void EmitINeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
90 ctx.AddU32("{}=uint(-({}));", inst, value); 90 ctx.AddU32("{}=uint(int(0)-int({}));", inst, value);
91} 91}
92 92
93void EmitINeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value) { 93void EmitINeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
94 ctx.AddU64("{}=-({});", inst, value); 94 ctx.AddU64("{}=uint64_t(int64_t(0)-int64_t({}));", inst, value);
95} 95}
96 96
97void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { 97void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp
index b8ddafe48..fcf620b79 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp
@@ -90,7 +90,9 @@ void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value&
90 if (phi_reg == val_reg) { 90 if (phi_reg == val_reg) {
91 return; 91 return;
92 } 92 }
93 ctx.Add("{}={};", phi_reg, val_reg); 93 const bool needs_workaround{ctx.profile.has_gl_bool_ref_bug && phi_type == IR::Type::U1};
94 const auto suffix{needs_workaround ? "?true:false" : ""};
95 ctx.Add("{}={}{};", phi_reg, val_reg, suffix);
94} 96}
95 97
96void EmitPrologue(EmitContext& ctx) { 98void EmitPrologue(EmitContext& ctx) {
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
index bc9d2a904..bb7f1a0fd 100644
--- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
+++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
@@ -428,9 +428,10 @@ void EmitContext::DefineConstantBuffers(Bindings& bindings) {
428 return; 428 return;
429 } 429 }
430 for (const auto& desc : info.constant_buffer_descriptors) { 430 for (const auto& desc : info.constant_buffer_descriptors) {
431 header += fmt::format( 431 const auto cbuf_type{profile.has_gl_cbuf_ftou_bug ? "uvec4" : "vec4"};
432 "layout(std140,binding={}) uniform {}_cbuf_{}{{vec4 {}_cbuf{}[{}];}};", 432 header += fmt::format("layout(std140,binding={}) uniform {}_cbuf_{}{{{} {}_cbuf{}[{}];}};",
433 bindings.uniform_buffer, stage_name, desc.index, stage_name, desc.index, 4 * 1024); 433 bindings.uniform_buffer, stage_name, desc.index, cbuf_type,
434 stage_name, desc.index, 4 * 1024);
434 bindings.uniform_buffer += desc.count; 435 bindings.uniform_buffer += desc.count;
435 } 436 }
436} 437}
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 14f470812..8ea730c80 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
@@ -355,6 +355,31 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
355 } 355 }
356} 356}
357 357
358Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, Id) {
359 switch (attr) {
360 case IR::Attribute::PrimitiveId:
361 return ctx.OpLoad(ctx.U32[1], ctx.primitive_id);
362 case IR::Attribute::InstanceId:
363 if (ctx.profile.support_vertex_instance_id) {
364 return ctx.OpLoad(ctx.U32[1], ctx.instance_id);
365 } else {
366 const Id index{ctx.OpLoad(ctx.U32[1], ctx.instance_index)};
367 const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_instance)};
368 return ctx.OpISub(ctx.U32[1], index, base);
369 }
370 case IR::Attribute::VertexId:
371 if (ctx.profile.support_vertex_instance_id) {
372 return ctx.OpLoad(ctx.U32[1], ctx.vertex_id);
373 } else {
374 const Id index{ctx.OpLoad(ctx.U32[1], ctx.vertex_index)};
375 const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)};
376 return ctx.OpISub(ctx.U32[1], index, base);
377 }
378 default:
379 throw NotImplementedException("Read U32 attribute {}", attr);
380 }
381}
382
358void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, [[maybe_unused]] Id vertex) { 383void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, [[maybe_unused]] Id vertex) {
359 const std::optional<OutAttr> output{OutputAttrPointer(ctx, attr)}; 384 const std::optional<OutAttr> output{OutputAttrPointer(ctx, attr)};
360 if (!output) { 385 if (!output) {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
index 6cd22dd3e..887112deb 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
@@ -53,6 +53,7 @@ Id EmitGetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& o
53Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); 53Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
54Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); 54Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
55Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex); 55Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex);
56Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, Id vertex);
56void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, Id vertex); 57void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, Id vertex);
57Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset, Id vertex); 58Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset, Id vertex);
58void EmitSetAttributeIndexed(EmitContext& ctx, Id offset, Id value, Id vertex); 59void EmitSetAttributeIndexed(EmitContext& ctx, Id offset, Id value, Id vertex);
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc
index 6929919df..b94ce7406 100644
--- a/src/shader_recompiler/frontend/ir/opcodes.inc
+++ b/src/shader_recompiler/frontend/ir/opcodes.inc
@@ -40,6 +40,7 @@ OPCODE(GetCbufU32, U32, U32,
40OPCODE(GetCbufF32, F32, U32, U32, ) 40OPCODE(GetCbufF32, F32, U32, U32, )
41OPCODE(GetCbufU32x2, U32x2, U32, U32, ) 41OPCODE(GetCbufU32x2, U32x2, U32, U32, )
42OPCODE(GetAttribute, F32, Attribute, U32, ) 42OPCODE(GetAttribute, F32, Attribute, U32, )
43OPCODE(GetAttributeU32, U32, Attribute, U32, )
43OPCODE(SetAttribute, Void, Attribute, F32, U32, ) 44OPCODE(SetAttribute, Void, Attribute, F32, U32, )
44OPCODE(GetAttributeIndexed, F32, U32, U32, ) 45OPCODE(GetAttributeIndexed, F32, U32, U32, )
45OPCODE(SetAttributeIndexed, Void, U32, F32, U32, ) 46OPCODE(SetAttributeIndexed, Void, U32, F32, U32, )
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 1e476d83d..a78c469be 100644
--- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
+++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
@@ -389,6 +389,7 @@ void VisitUsages(Info& info, IR::Inst& inst) {
389 info.uses_demote_to_helper_invocation = true; 389 info.uses_demote_to_helper_invocation = true;
390 break; 390 break;
391 case IR::Opcode::GetAttribute: 391 case IR::Opcode::GetAttribute:
392 case IR::Opcode::GetAttributeU32:
392 info.loads.mask[static_cast<size_t>(inst.Arg(0).Attribute())] = true; 393 info.loads.mask[static_cast<size_t>(inst.Arg(0).Attribute())] = true;
393 break; 394 break;
394 case IR::Opcode::SetAttribute: 395 case IR::Opcode::SetAttribute:
diff --git a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
index d089fdd12..c134a12bc 100644
--- a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
+++ b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
@@ -505,6 +505,29 @@ void FoldBitCast(IR::Inst& inst, IR::Opcode reverse) {
505 return; 505 return;
506 } 506 }
507 } 507 }
508 if constexpr (op == IR::Opcode::BitCastU32F32) {
509 // Workaround for new NVIDIA driver bug, where:
510 // uint attr = ftou(itof(gl_InstanceID));
511 // always returned 0.
512 // We can instead manually optimize this and work around the driver bug:
513 // uint attr = uint(gl_InstanceID);
514 if (arg_inst->GetOpcode() == IR::Opcode::GetAttribute) {
515 const IR::Attribute attr{arg_inst->Arg(0).Attribute()};
516 switch (attr) {
517 case IR::Attribute::PrimitiveId:
518 case IR::Attribute::InstanceId:
519 case IR::Attribute::VertexId:
520 break;
521 default:
522 return;
523 }
524 // Replace the bitcasts with an integer attribute get
525 inst.ReplaceOpcode(IR::Opcode::GetAttributeU32);
526 inst.SetArg(0, arg_inst->Arg(0));
527 inst.SetArg(1, arg_inst->Arg(1));
528 return;
529 }
530 }
508} 531}
509 532
510void FoldInverseFunc(IR::Inst& inst, IR::Opcode reverse) { 533void FoldInverseFunc(IR::Inst& inst, IR::Opcode reverse) {
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h
index f0c3b3b17..dc4c806ff 100644
--- a/src/shader_recompiler/profile.h
+++ b/src/shader_recompiler/profile.h
@@ -65,6 +65,10 @@ struct Profile {
65 bool has_gl_component_indexing_bug{}; 65 bool has_gl_component_indexing_bug{};
66 /// The precise type qualifier is broken in the fragment stage of some drivers 66 /// The precise type qualifier is broken in the fragment stage of some drivers
67 bool has_gl_precise_bug{}; 67 bool has_gl_precise_bug{};
68 /// Some drivers do not properly support floatBitsToUint when used on cbufs
69 bool has_gl_cbuf_ftou_bug{};
70 /// Some drivers poorly optimize boolean variable references
71 bool has_gl_bool_ref_bug{};
68 /// Ignores SPIR-V ordered vs unordered using GLSL semantics 72 /// Ignores SPIR-V ordered vs unordered using GLSL semantics
69 bool ignore_nan_fp_comparisons{}; 73 bool ignore_nan_fp_comparisons{};
70 74