summaryrefslogtreecommitdiff
path: root/src/shader_recompiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler')
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp10
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp44
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp17
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp61
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.h16
-rw-r--r--src/shader_recompiler/profile.h3
-rw-r--r--src/shader_recompiler/runtime_info.h2
7 files changed, 103 insertions, 50 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp
index 4b3043b65..0ce73f289 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp
@@ -69,6 +69,11 @@ Id StorageAtomicU32(EmitContext& ctx, const IR::Value& binding, const IR::Value&
69Id StorageAtomicU64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value, 69Id StorageAtomicU64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value,
70 Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id), 70 Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id),
71 Id (Sirit::Module::*non_atomic_func)(Id, Id, Id)) { 71 Id (Sirit::Module::*non_atomic_func)(Id, Id, Id)) {
72 if (!ctx.profile.support_descriptor_aliasing) {
73 LOG_WARNING(Shader_SPIRV, "Descriptor aliasing not supported, this cannot be atomic.");
74 return ctx.ConstantNull(ctx.U64);
75 }
76
72 if (ctx.profile.support_int64_atomics) { 77 if (ctx.profile.support_int64_atomics) {
73 const Id pointer{StoragePointer(ctx, ctx.storage_types.U64, &StorageDefinitions::U64, 78 const Id pointer{StoragePointer(ctx, ctx.storage_types.U64, &StorageDefinitions::U64,
74 binding, offset, sizeof(u64))}; 79 binding, offset, sizeof(u64))};
@@ -86,6 +91,11 @@ Id StorageAtomicU64(EmitContext& ctx, const IR::Value& binding, const IR::Value&
86 91
87Id StorageAtomicU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value, 92Id StorageAtomicU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value,
88 Id (Sirit::Module::*non_atomic_func)(Id, Id, Id)) { 93 Id (Sirit::Module::*non_atomic_func)(Id, Id, Id)) {
94 if (!ctx.profile.support_descriptor_aliasing) {
95 LOG_WARNING(Shader_SPIRV, "Descriptor aliasing not supported, this cannot be atomic.");
96 return ctx.ConstantNull(ctx.U32[2]);
97 }
98
89 LOG_WARNING(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic"); 99 LOG_WARNING(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic");
90 const Id pointer{StoragePointer(ctx, ctx.storage_types.U32x2, &StorageDefinitions::U32x2, 100 const Id pointer{StoragePointer(ctx, ctx.storage_types.U32x2, &StorageDefinitions::U32x2,
91 binding, offset, sizeof(u32[2]))}; 101 binding, offset, sizeof(u32[2]))};
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 07c2b7b8a..2868fc57d 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
@@ -10,27 +10,6 @@
10 10
11namespace Shader::Backend::SPIRV { 11namespace Shader::Backend::SPIRV {
12namespace { 12namespace {
13struct AttrInfo {
14 Id pointer;
15 Id id;
16 bool needs_cast;
17};
18
19std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) {
20 const AttributeType type{ctx.runtime_info.generic_input_types.at(index)};
21 switch (type) {
22 case AttributeType::Float:
23 return AttrInfo{ctx.input_f32, ctx.F32[1], false};
24 case AttributeType::UnsignedInt:
25 return AttrInfo{ctx.input_u32, ctx.U32[1], true};
26 case AttributeType::SignedInt:
27 return AttrInfo{ctx.input_s32, ctx.TypeInt(32, true), true};
28 case AttributeType::Disabled:
29 return std::nullopt;
30 }
31 throw InvalidArgument("Invalid attribute type {}", type);
32}
33
34template <typename... Args> 13template <typename... Args>
35Id AttrPointer(EmitContext& ctx, Id pointer_type, Id vertex, Id base, Args&&... args) { 14Id AttrPointer(EmitContext& ctx, Id pointer_type, Id vertex, Id base, Args&&... args) {
36 switch (ctx.stage) { 15 switch (ctx.stage) {
@@ -302,15 +281,26 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
302 const u32 element{static_cast<u32>(attr) % 4}; 281 const u32 element{static_cast<u32>(attr) % 4};
303 if (IR::IsGeneric(attr)) { 282 if (IR::IsGeneric(attr)) {
304 const u32 index{IR::GenericAttributeIndex(attr)}; 283 const u32 index{IR::GenericAttributeIndex(attr)};
305 const std::optional<AttrInfo> type{AttrTypes(ctx, index)}; 284 const auto& generic{ctx.input_generics.at(index)};
306 if (!type || !ctx.runtime_info.previous_stage_stores.Generic(index, element)) { 285 if (!ValidId(generic.id)) {
307 // Attribute is disabled or varying component is not written 286 // Attribute is disabled or varying component is not written
308 return ctx.Const(element == 3 ? 1.0f : 0.0f); 287 return ctx.Const(element == 3 ? 1.0f : 0.0f);
309 } 288 }
310 const Id generic_id{ctx.input_generics.at(index)}; 289 const Id pointer{
311 const Id pointer{AttrPointer(ctx, type->pointer, vertex, generic_id, ctx.Const(element))}; 290 AttrPointer(ctx, generic.pointer_type, vertex, generic.id, ctx.Const(element))};
312 const Id value{ctx.OpLoad(type->id, pointer)}; 291 const Id value{ctx.OpLoad(generic.component_type, pointer)};
313 return type->needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value; 292 return [&ctx, generic, value]() {
293 switch (generic.load_op) {
294 case InputGenericLoadOp::Bitcast:
295 return ctx.OpBitcast(ctx.F32[1], value);
296 case InputGenericLoadOp::SToF:
297 return ctx.OpConvertSToF(ctx.F32[1], value);
298 case InputGenericLoadOp::UToF:
299 return ctx.OpConvertUToF(ctx.F32[1], value);
300 default:
301 return value;
302 };
303 }();
314 } 304 }
315 switch (attr) { 305 switch (attr) {
316 case IR::Attribute::PrimitiveId: 306 case IR::Attribute::PrimitiveId:
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
index c5db19d09..77ff8c573 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
@@ -17,7 +17,22 @@ Id GetThreadId(EmitContext& ctx) {
17Id WarpExtract(EmitContext& ctx, Id value) { 17Id WarpExtract(EmitContext& ctx, Id value) {
18 const Id thread_id{GetThreadId(ctx)}; 18 const Id thread_id{GetThreadId(ctx)};
19 const Id local_index{ctx.OpShiftRightArithmetic(ctx.U32[1], thread_id, ctx.Const(5U))}; 19 const Id local_index{ctx.OpShiftRightArithmetic(ctx.U32[1], thread_id, ctx.Const(5U))};
20 return ctx.OpVectorExtractDynamic(ctx.U32[1], value, local_index); 20 if (ctx.profile.has_broken_spirv_subgroup_mask_vector_extract_dynamic) {
21 const Id c0_sel{ctx.OpSelect(ctx.U32[1], ctx.OpIEqual(ctx.U1, local_index, ctx.Const(0U)),
22 ctx.OpCompositeExtract(ctx.U32[1], value, 0U), ctx.Const(0U))};
23 const Id c1_sel{ctx.OpSelect(ctx.U32[1], ctx.OpIEqual(ctx.U1, local_index, ctx.Const(1U)),
24 ctx.OpCompositeExtract(ctx.U32[1], value, 1U), ctx.Const(0U))};
25 const Id c2_sel{ctx.OpSelect(ctx.U32[1], ctx.OpIEqual(ctx.U1, local_index, ctx.Const(2U)),
26 ctx.OpCompositeExtract(ctx.U32[1], value, 2U), ctx.Const(0U))};
27 const Id c3_sel{ctx.OpSelect(ctx.U32[1], ctx.OpIEqual(ctx.U1, local_index, ctx.Const(3U)),
28 ctx.OpCompositeExtract(ctx.U32[1], value, 3U), ctx.Const(0U))};
29 const Id c0_or_c1{ctx.OpBitwiseOr(ctx.U32[1], c0_sel, c1_sel)};
30 const Id c2_or_c3{ctx.OpBitwiseOr(ctx.U32[1], c2_sel, c3_sel)};
31 const Id c0_or_c1_or_c2_or_c3{ctx.OpBitwiseOr(ctx.U32[1], c0_or_c1, c2_or_c3)};
32 return c0_or_c1_or_c2_or_c3;
33 } else {
34 return ctx.OpVectorExtractDynamic(ctx.U32[1], value, local_index);
35 }
21} 36}
22 37
23Id LoadMask(EmitContext& ctx, Id mask) { 38Id LoadMask(EmitContext& ctx, Id mask) {
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index 47739794f..fd15f47ea 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -25,12 +25,6 @@ enum class Operation {
25 FPMax, 25 FPMax,
26}; 26};
27 27
28struct AttrInfo {
29 Id pointer;
30 Id id;
31 bool needs_cast;
32};
33
34Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) { 28Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) {
35 const spv::ImageFormat format{spv::ImageFormat::Unknown}; 29 const spv::ImageFormat format{spv::ImageFormat::Unknown};
36 const Id type{ctx.F32[1]}; 30 const Id type{ctx.F32[1]};
@@ -206,23 +200,37 @@ Id GetAttributeType(EmitContext& ctx, AttributeType type) {
206 return ctx.TypeVector(ctx.TypeInt(32, true), 4); 200 return ctx.TypeVector(ctx.TypeInt(32, true), 4);
207 case AttributeType::UnsignedInt: 201 case AttributeType::UnsignedInt:
208 return ctx.U32[4]; 202 return ctx.U32[4];
203 case AttributeType::SignedScaled:
204 return ctx.profile.support_scaled_attributes ? ctx.F32[4]
205 : ctx.TypeVector(ctx.TypeInt(32, true), 4);
206 case AttributeType::UnsignedScaled:
207 return ctx.profile.support_scaled_attributes ? ctx.F32[4] : ctx.U32[4];
209 case AttributeType::Disabled: 208 case AttributeType::Disabled:
210 break; 209 break;
211 } 210 }
212 throw InvalidArgument("Invalid attribute type {}", type); 211 throw InvalidArgument("Invalid attribute type {}", type);
213} 212}
214 213
215std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) { 214InputGenericInfo GetAttributeInfo(EmitContext& ctx, AttributeType type, Id id) {
216 const AttributeType type{ctx.runtime_info.generic_input_types.at(index)};
217 switch (type) { 215 switch (type) {
218 case AttributeType::Float: 216 case AttributeType::Float:
219 return AttrInfo{ctx.input_f32, ctx.F32[1], false}; 217 return InputGenericInfo{id, ctx.input_f32, ctx.F32[1], InputGenericLoadOp::None};
220 case AttributeType::UnsignedInt: 218 case AttributeType::UnsignedInt:
221 return AttrInfo{ctx.input_u32, ctx.U32[1], true}; 219 return InputGenericInfo{id, ctx.input_u32, ctx.U32[1], InputGenericLoadOp::Bitcast};
222 case AttributeType::SignedInt: 220 case AttributeType::SignedInt:
223 return AttrInfo{ctx.input_s32, ctx.TypeInt(32, true), true}; 221 return InputGenericInfo{id, ctx.input_s32, ctx.TypeInt(32, true),
222 InputGenericLoadOp::Bitcast};
223 case AttributeType::SignedScaled:
224 return ctx.profile.support_scaled_attributes
225 ? InputGenericInfo{id, ctx.input_f32, ctx.F32[1], InputGenericLoadOp::None}
226 : InputGenericInfo{id, ctx.input_s32, ctx.TypeInt(32, true),
227 InputGenericLoadOp::SToF};
228 case AttributeType::UnsignedScaled:
229 return ctx.profile.support_scaled_attributes
230 ? InputGenericInfo{id, ctx.input_f32, ctx.F32[1], InputGenericLoadOp::None}
231 : InputGenericInfo{id, ctx.input_u32, ctx.U32[1], InputGenericLoadOp::UToF};
224 case AttributeType::Disabled: 232 case AttributeType::Disabled:
225 return std::nullopt; 233 return InputGenericInfo{};
226 } 234 }
227 throw InvalidArgument("Invalid attribute type {}", type); 235 throw InvalidArgument("Invalid attribute type {}", type);
228} 236}
@@ -746,18 +754,29 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
746 continue; 754 continue;
747 } 755 }
748 AddLabel(labels[label_index]); 756 AddLabel(labels[label_index]);
749 const auto type{AttrTypes(*this, static_cast<u32>(index))}; 757 const auto& generic{input_generics.at(index)};
750 if (!type) { 758 const Id generic_id{generic.id};
759 if (!ValidId(generic_id)) {
751 OpReturnValue(Const(0.0f)); 760 OpReturnValue(Const(0.0f));
752 ++label_index; 761 ++label_index;
753 continue; 762 continue;
754 } 763 }
755 const Id generic_id{input_generics.at(index)}; 764 const Id pointer{
756 const Id pointer{is_array 765 is_array ? OpAccessChain(generic.pointer_type, generic_id, vertex, masked_index)
757 ? OpAccessChain(type->pointer, generic_id, vertex, masked_index) 766 : OpAccessChain(generic.pointer_type, generic_id, masked_index)};
758 : OpAccessChain(type->pointer, generic_id, masked_index)}; 767 const Id value{OpLoad(generic.component_type, pointer)};
759 const Id value{OpLoad(type->id, pointer)}; 768 const Id result{[this, generic, value]() {
760 const Id result{type->needs_cast ? OpBitcast(F32[1], value) : value}; 769 switch (generic.load_op) {
770 case InputGenericLoadOp::Bitcast:
771 return OpBitcast(F32[1], value);
772 case InputGenericLoadOp::SToF:
773 return OpConvertSToF(F32[1], value);
774 case InputGenericLoadOp::UToF:
775 return OpConvertUToF(F32[1], value);
776 default:
777 return value;
778 };
779 }()};
761 OpReturnValue(result); 780 OpReturnValue(result);
762 ++label_index; 781 ++label_index;
763 } 782 }
@@ -1457,7 +1476,7 @@ void EmitContext::DefineInputs(const IR::Program& program) {
1457 const Id id{DefineInput(*this, type, true)}; 1476 const Id id{DefineInput(*this, type, true)};
1458 Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); 1477 Decorate(id, spv::Decoration::Location, static_cast<u32>(index));
1459 Name(id, fmt::format("in_attr{}", index)); 1478 Name(id, fmt::format("in_attr{}", index));
1460 input_generics[index] = id; 1479 input_generics[index] = GetAttributeInfo(*this, input_type, id);
1461 1480
1462 if (info.passthrough.Generic(index) && profile.support_geometry_shader_passthrough) { 1481 if (info.passthrough.Generic(index) && profile.support_geometry_shader_passthrough) {
1463 Decorate(id, spv::Decoration::PassthroughNV); 1482 Decorate(id, spv::Decoration::PassthroughNV);
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h
index 768a4fbb5..e63330f11 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h
@@ -95,6 +95,20 @@ struct StorageDefinitions {
95 Id U32x4{}; 95 Id U32x4{};
96}; 96};
97 97
98enum class InputGenericLoadOp {
99 None,
100 Bitcast,
101 SToF,
102 UToF,
103};
104
105struct InputGenericInfo {
106 Id id;
107 Id pointer_type;
108 Id component_type;
109 InputGenericLoadOp load_op;
110};
111
98struct GenericElementInfo { 112struct GenericElementInfo {
99 Id id{}; 113 Id id{};
100 u32 first_element{}; 114 u32 first_element{};
@@ -283,7 +297,7 @@ public:
283 297
284 bool need_input_position_indirect{}; 298 bool need_input_position_indirect{};
285 Id input_position{}; 299 Id input_position{};
286 std::array<Id, 32> input_generics{}; 300 std::array<InputGenericInfo, 32> input_generics{};
287 301
288 Id output_point_size{}; 302 Id output_point_size{};
289 Id output_position{}; 303 Id output_position{};
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h
index 9f88fb440..9ca97f6a4 100644
--- a/src/shader_recompiler/profile.h
+++ b/src/shader_recompiler/profile.h
@@ -43,6 +43,7 @@ struct Profile {
43 bool support_gl_variable_aoffi{}; 43 bool support_gl_variable_aoffi{};
44 bool support_gl_sparse_textures{}; 44 bool support_gl_sparse_textures{};
45 bool support_gl_derivative_control{}; 45 bool support_gl_derivative_control{};
46 bool support_scaled_attributes{};
46 47
47 bool warp_size_potentially_larger_than_guest{}; 48 bool warp_size_potentially_larger_than_guest{};
48 49
@@ -77,6 +78,8 @@ struct Profile {
77 bool has_gl_bool_ref_bug{}; 78 bool has_gl_bool_ref_bug{};
78 /// Ignores SPIR-V ordered vs unordered using GLSL semantics 79 /// Ignores SPIR-V ordered vs unordered using GLSL semantics
79 bool ignore_nan_fp_comparisons{}; 80 bool ignore_nan_fp_comparisons{};
81 /// Some drivers have broken support for OpVectorExtractDynamic on subgroup mask inputs
82 bool has_broken_spirv_subgroup_mask_vector_extract_dynamic{};
80 83
81 u32 gl_max_compute_smem_size{}; 84 u32 gl_max_compute_smem_size{};
82}; 85};
diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h
index 549b81ef7..3b63c249f 100644
--- a/src/shader_recompiler/runtime_info.h
+++ b/src/shader_recompiler/runtime_info.h
@@ -17,6 +17,8 @@ enum class AttributeType : u8 {
17 Float, 17 Float,
18 SignedInt, 18 SignedInt,
19 UnsignedInt, 19 UnsignedInt,
20 SignedScaled,
21 UnsignedScaled,
20 Disabled, 22 Disabled,
21}; 23};
22 24