summaryrefslogtreecommitdiff
path: root/src/shader_recompiler
diff options
context:
space:
mode:
authorGravatar Billy Laws2023-02-18 18:23:36 +0000
committerGravatar bunnei2023-06-03 00:05:31 -0700
commit158a1896ec91c46a43fa3172fa472e6fc7c9eb05 (patch)
treec9fefdf4e2a3f948d08bc32211675f19d936139e /src/shader_recompiler
parentDisable push descriptors on adreno drivers (diff)
downloadyuzu-158a1896ec91c46a43fa3172fa472e6fc7c9eb05.tar.gz
yuzu-158a1896ec91c46a43fa3172fa472e6fc7c9eb05.tar.xz
yuzu-158a1896ec91c46a43fa3172fa472e6fc7c9eb05.zip
Implement scaled vertex buffer format emulation
These formats are unsupported by mobile GPUs so they need to be emulated in shaders instead.
Diffstat (limited to '')
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp44
-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.h1
-rw-r--r--src/shader_recompiler/runtime_info.h2
5 files changed, 75 insertions, 49 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index 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/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..3bb4a7e6f 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
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