diff options
| author | 2021-03-24 01:33:45 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:24 -0400 | |
| commit | 68a9505d8a1d00c6ba2739bc0af3069cf87b9b84 (patch) | |
| tree | b9a78497cd8af1d73a7eda34cd0df08b3dc324e6 | |
| parent | shader: Fix use-after-free bug in object_pool (diff) | |
| download | yuzu-68a9505d8a1d00c6ba2739bc0af3069cf87b9b84.tar.gz yuzu-68a9505d8a1d00c6ba2739bc0af3069cf87b9b84.tar.xz yuzu-68a9505d8a1d00c6ba2739bc0af3069cf87b9b84.zip | |
shader: Implement NDC [-1, 1], attribute types and default varying initialization
Diffstat (limited to '')
15 files changed, 186 insertions, 43 deletions
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 086bdf8d0..028e8b2d2 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -14,6 +14,7 @@ add_library(shader_recompiler STATIC | |||
| 14 | backend/spirv/emit_spirv_logical.cpp | 14 | backend/spirv/emit_spirv_logical.cpp |
| 15 | backend/spirv/emit_spirv_memory.cpp | 15 | backend/spirv/emit_spirv_memory.cpp |
| 16 | backend/spirv/emit_spirv_select.cpp | 16 | backend/spirv/emit_spirv_select.cpp |
| 17 | backend/spirv/emit_spirv_special.cpp | ||
| 17 | backend/spirv/emit_spirv_undefined.cpp | 18 | backend/spirv/emit_spirv_undefined.cpp |
| 18 | backend/spirv/emit_spirv_vote.cpp | 19 | backend/spirv/emit_spirv_vote.cpp |
| 19 | environment.h | 20 | environment.h |
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index 36f130781..ea46af244 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp | |||
| @@ -67,6 +67,18 @@ Id DefineInput(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin = | |||
| 67 | Id DefineOutput(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin = std::nullopt) { | 67 | Id DefineOutput(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin = std::nullopt) { |
| 68 | return DefineVariable(ctx, type, builtin, spv::StorageClass::Output); | 68 | return DefineVariable(ctx, type, builtin, spv::StorageClass::Output); |
| 69 | } | 69 | } |
| 70 | |||
| 71 | Id GetAttributeType(EmitContext& ctx, AttributeType type) { | ||
| 72 | switch (type) { | ||
| 73 | case AttributeType::Float: | ||
| 74 | return ctx.F32[4]; | ||
| 75 | case AttributeType::SignedInt: | ||
| 76 | return ctx.TypeVector(ctx.TypeInt(32, true), 4); | ||
| 77 | case AttributeType::UnsignedInt: | ||
| 78 | return ctx.U32[4]; | ||
| 79 | } | ||
| 80 | throw InvalidArgument("Invalid attribute type {}", type); | ||
| 81 | } | ||
| 70 | } // Anonymous namespace | 82 | } // Anonymous namespace |
| 71 | 83 | ||
| 72 | void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { | 84 | void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { |
| @@ -82,11 +94,11 @@ void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_vie | |||
| 82 | } | 94 | } |
| 83 | 95 | ||
| 84 | EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& binding) | 96 | EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& binding) |
| 85 | : Sirit::Module(0x00010000), profile{profile_} { | 97 | : Sirit::Module(0x00010000), profile{profile_}, stage{program.stage} { |
| 86 | AddCapability(spv::Capability::Shader); | 98 | AddCapability(spv::Capability::Shader); |
| 87 | DefineCommonTypes(program.info); | 99 | DefineCommonTypes(program.info); |
| 88 | DefineCommonConstants(); | 100 | DefineCommonConstants(); |
| 89 | DefineInterfaces(program.info, program.stage); | 101 | DefineInterfaces(program.info); |
| 90 | DefineConstantBuffers(program.info, binding); | 102 | DefineConstantBuffers(program.info, binding); |
| 91 | DefineStorageBuffers(program.info, binding); | 103 | DefineStorageBuffers(program.info, binding); |
| 92 | DefineTextures(program.info, binding); | 104 | DefineTextures(program.info, binding); |
| @@ -130,6 +142,9 @@ void EmitContext::DefineCommonTypes(const Info& info) { | |||
| 130 | U32.Define(*this, TypeInt(32, false), "u32"); | 142 | U32.Define(*this, TypeInt(32, false), "u32"); |
| 131 | 143 | ||
| 132 | input_f32 = Name(TypePointer(spv::StorageClass::Input, F32[1]), "input_f32"); | 144 | input_f32 = Name(TypePointer(spv::StorageClass::Input, F32[1]), "input_f32"); |
| 145 | input_u32 = Name(TypePointer(spv::StorageClass::Input, U32[1]), "input_u32"); | ||
| 146 | input_s32 = Name(TypePointer(spv::StorageClass::Input, TypeInt(32, true)), "input_s32"); | ||
| 147 | |||
| 133 | output_f32 = Name(TypePointer(spv::StorageClass::Output, F32[1]), "output_f32"); | 148 | output_f32 = Name(TypePointer(spv::StorageClass::Output, F32[1]), "output_f32"); |
| 134 | 149 | ||
| 135 | if (info.uses_int8) { | 150 | if (info.uses_int8) { |
| @@ -162,9 +177,9 @@ void EmitContext::DefineCommonConstants() { | |||
| 162 | u32_zero_value = Constant(U32[1], 0U); | 177 | u32_zero_value = Constant(U32[1], 0U); |
| 163 | } | 178 | } |
| 164 | 179 | ||
| 165 | void EmitContext::DefineInterfaces(const Info& info, Stage stage) { | 180 | void EmitContext::DefineInterfaces(const Info& info) { |
| 166 | DefineInputs(info, stage); | 181 | DefineInputs(info); |
| 167 | DefineOutputs(info, stage); | 182 | DefineOutputs(info); |
| 168 | } | 183 | } |
| 169 | 184 | ||
| 170 | void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { | 185 | void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { |
| @@ -252,7 +267,7 @@ void EmitContext::DefineLabels(IR::Program& program) { | |||
| 252 | } | 267 | } |
| 253 | } | 268 | } |
| 254 | 269 | ||
| 255 | void EmitContext::DefineInputs(const Info& info, Stage stage) { | 270 | void EmitContext::DefineInputs(const Info& info) { |
| 256 | if (info.uses_workgroup_id) { | 271 | if (info.uses_workgroup_id) { |
| 257 | workgroup_id = DefineInput(*this, U32[3], spv::BuiltIn::WorkgroupId); | 272 | workgroup_id = DefineInput(*this, U32[3], spv::BuiltIn::WorkgroupId); |
| 258 | } | 273 | } |
| @@ -288,8 +303,8 @@ void EmitContext::DefineInputs(const Info& info, Stage stage) { | |||
| 288 | if (!info.loads_generics[index]) { | 303 | if (!info.loads_generics[index]) { |
| 289 | continue; | 304 | continue; |
| 290 | } | 305 | } |
| 291 | // FIXME: Declare size from input | 306 | const Id type{GetAttributeType(*this, profile.generic_input_types[index])}; |
| 292 | const Id id{DefineInput(*this, F32[4])}; | 307 | const Id id{DefineInput(*this, type)}; |
| 293 | Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); | 308 | Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); |
| 294 | Name(id, fmt::format("in_attr{}", index)); | 309 | Name(id, fmt::format("in_attr{}", index)); |
| 295 | input_generics[index] = id; | 310 | input_generics[index] = id; |
| @@ -323,8 +338,8 @@ void EmitContext::DefineConstantBuffers(const Info& info, Id UniformDefinitions: | |||
| 323 | } | 338 | } |
| 324 | } | 339 | } |
| 325 | 340 | ||
| 326 | void EmitContext::DefineOutputs(const Info& info, Stage stage) { | 341 | void EmitContext::DefineOutputs(const Info& info) { |
| 327 | if (info.stores_position) { | 342 | if (info.stores_position || stage == Stage::VertexB) { |
| 328 | output_position = DefineOutput(*this, F32[4], spv::BuiltIn::Position); | 343 | output_position = DefineOutput(*this, F32[4], spv::BuiltIn::Position); |
| 329 | } | 344 | } |
| 330 | for (size_t i = 0; i < info.stores_generics.size(); ++i) { | 345 | for (size_t i = 0; i < info.stores_generics.size(); ++i) { |
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h index 6e64360bf..5ed815c06 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.h +++ b/src/shader_recompiler/backend/spirv/emit_context.h | |||
| @@ -52,6 +52,7 @@ public: | |||
| 52 | [[nodiscard]] Id Def(const IR::Value& value); | 52 | [[nodiscard]] Id Def(const IR::Value& value); |
| 53 | 53 | ||
| 54 | const Profile& profile; | 54 | const Profile& profile; |
| 55 | Stage stage{}; | ||
| 55 | 56 | ||
| 56 | Id void_id{}; | 57 | Id void_id{}; |
| 57 | Id U1{}; | 58 | Id U1{}; |
| @@ -72,6 +73,9 @@ public: | |||
| 72 | UniformDefinitions uniform_types; | 73 | UniformDefinitions uniform_types; |
| 73 | 74 | ||
| 74 | Id input_f32{}; | 75 | Id input_f32{}; |
| 76 | Id input_u32{}; | ||
| 77 | Id input_s32{}; | ||
| 78 | |||
| 75 | Id output_f32{}; | 79 | Id output_f32{}; |
| 76 | 80 | ||
| 77 | Id storage_u32{}; | 81 | Id storage_u32{}; |
| @@ -104,7 +108,7 @@ public: | |||
| 104 | private: | 108 | private: |
| 105 | void DefineCommonTypes(const Info& info); | 109 | void DefineCommonTypes(const Info& info); |
| 106 | void DefineCommonConstants(); | 110 | void DefineCommonConstants(); |
| 107 | void DefineInterfaces(const Info& info, Stage stage); | 111 | void DefineInterfaces(const Info& info); |
| 108 | void DefineConstantBuffers(const Info& info, u32& binding); | 112 | void DefineConstantBuffers(const Info& info, u32& binding); |
| 109 | void DefineStorageBuffers(const Info& info, u32& binding); | 113 | void DefineStorageBuffers(const Info& info, u32& binding); |
| 110 | void DefineTextures(const Info& info, u32& binding); | 114 | void DefineTextures(const Info& info, u32& binding); |
| @@ -113,8 +117,8 @@ private: | |||
| 113 | void DefineConstantBuffers(const Info& info, Id UniformDefinitions::*member_type, u32 binding, | 117 | void DefineConstantBuffers(const Info& info, Id UniformDefinitions::*member_type, u32 binding, |
| 114 | Id type, char type_char, u32 element_size); | 118 | Id type, char type_char, u32 element_size); |
| 115 | 119 | ||
| 116 | void DefineInputs(const Info& info, Stage stage); | 120 | void DefineInputs(const Info& info); |
| 117 | void DefineOutputs(const Info& info, Stage stage); | 121 | void DefineOutputs(const Info& info); |
| 118 | }; | 122 | }; |
| 119 | 123 | ||
| 120 | } // namespace Shader::Backend::SPIRV | 124 | } // namespace Shader::Backend::SPIRV |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index ce23200f2..7fefcf2f2 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h | |||
| @@ -28,6 +28,8 @@ void EmitLoopMerge(EmitContext& ctx, Id merge_label, Id continue_label); | |||
| 28 | void EmitSelectionMerge(EmitContext& ctx, Id merge_label); | 28 | void EmitSelectionMerge(EmitContext& ctx, Id merge_label); |
| 29 | void EmitReturn(EmitContext& ctx); | 29 | void EmitReturn(EmitContext& ctx); |
| 30 | void EmitDemoteToHelperInvocation(EmitContext& ctx, Id continue_label); | 30 | void EmitDemoteToHelperInvocation(EmitContext& ctx, Id continue_label); |
| 31 | void EmitPrologue(EmitContext& ctx); | ||
| 32 | void EmitEpilogue(EmitContext& ctx); | ||
| 31 | void EmitGetRegister(EmitContext& ctx); | 33 | void EmitGetRegister(EmitContext& ctx); |
| 32 | void EmitSetRegister(EmitContext& ctx); | 34 | void EmitSetRegister(EmitContext& ctx); |
| 33 | void EmitGetPred(EmitContext& ctx); | 35 | void EmitGetPred(EmitContext& ctx); |
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 052b84151..8fc040f8b 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 | |||
| @@ -2,30 +2,26 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <tuple> | ||
| 6 | |||
| 5 | #include "shader_recompiler/backend/spirv/emit_spirv.h" | 7 | #include "shader_recompiler/backend/spirv/emit_spirv.h" |
| 6 | 8 | ||
| 9 | #pragma optimize("", off) | ||
| 10 | |||
| 7 | namespace Shader::Backend::SPIRV { | 11 | namespace Shader::Backend::SPIRV { |
| 8 | namespace { | 12 | namespace { |
| 9 | Id InputAttrPointer(EmitContext& ctx, IR::Attribute attr) { | 13 | std::tuple<Id, Id, bool> AttrTypes(EmitContext& ctx, u32 index) { |
| 10 | const u32 element{static_cast<u32>(attr) % 4}; | 14 | const bool is_first_reader{ctx.stage == Stage::VertexB}; |
| 11 | const auto element_id{[&] { return ctx.Constant(ctx.U32[1], element); }}; | 15 | const AttributeType type{ctx.profile.generic_input_types.at(index)}; |
| 12 | if (IR::IsGeneric(attr)) { | 16 | switch (type) { |
| 13 | const u32 index{IR::GenericAttributeIndex(attr)}; | 17 | case AttributeType::Float: |
| 14 | return ctx.OpAccessChain(ctx.input_f32, ctx.input_generics.at(index), element_id()); | 18 | return {ctx.input_f32, ctx.F32[1], false}; |
| 15 | } | 19 | case AttributeType::UnsignedInt: |
| 16 | switch (attr) { | 20 | return {ctx.input_u32, ctx.U32[1], true}; |
| 17 | case IR::Attribute::PositionX: | 21 | case AttributeType::SignedInt: |
| 18 | case IR::Attribute::PositionY: | 22 | return {ctx.input_s32, ctx.TypeInt(32, true), true}; |
| 19 | case IR::Attribute::PositionZ: | ||
| 20 | case IR::Attribute::PositionW: | ||
| 21 | return ctx.OpAccessChain(ctx.input_f32, ctx.input_position, element_id()); | ||
| 22 | case IR::Attribute::InstanceId: | ||
| 23 | return ctx.OpLoad(ctx.U32[1], ctx.instance_id); | ||
| 24 | case IR::Attribute::VertexId: | ||
| 25 | return ctx.OpLoad(ctx.U32[1], ctx.vertex_id); | ||
| 26 | default: | ||
| 27 | throw NotImplementedException("Read attribute {}", attr); | ||
| 28 | } | 23 | } |
| 24 | throw InvalidArgument("Invalid attribute type {}", type); | ||
| 29 | } | 25 | } |
| 30 | 26 | ||
| 31 | Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { | 27 | Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { |
| @@ -129,19 +125,40 @@ Id EmitGetCbufU64(EmitContext& ctx, const IR::Value& binding, const IR::Value& o | |||
| 129 | } | 125 | } |
| 130 | 126 | ||
| 131 | Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr) { | 127 | Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr) { |
| 132 | if (!ctx.profile.support_vertex_instance_id) { | 128 | const u32 element{static_cast<u32>(attr) % 4}; |
| 133 | switch (attr) { | 129 | const auto element_id{[&] { return ctx.Constant(ctx.U32[1], element); }}; |
| 134 | case IR::Attribute::InstanceId: | 130 | if (IR::IsGeneric(attr)) { |
| 131 | const u32 index{IR::GenericAttributeIndex(attr)}; | ||
| 132 | const auto [pointer_type, type, needs_cast]{AttrTypes(ctx, index)}; | ||
| 133 | const Id generic_id{ctx.input_generics.at(index)}; | ||
| 134 | const Id pointer{ctx.OpAccessChain(pointer_type, generic_id, element_id())}; | ||
| 135 | const Id value{ctx.OpLoad(type, pointer)}; | ||
| 136 | return needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value; | ||
| 137 | } | ||
| 138 | switch (attr) { | ||
| 139 | case IR::Attribute::PositionX: | ||
| 140 | case IR::Attribute::PositionY: | ||
| 141 | case IR::Attribute::PositionZ: | ||
| 142 | case IR::Attribute::PositionW: | ||
| 143 | return ctx.OpLoad(ctx.F32[1], | ||
| 144 | ctx.OpAccessChain(ctx.input_f32, ctx.input_position, element_id())); | ||
| 145 | case IR::Attribute::InstanceId: | ||
| 146 | if (ctx.profile.support_vertex_instance_id) { | ||
| 147 | return ctx.OpLoad(ctx.U32[1], ctx.instance_id); | ||
| 148 | } else { | ||
| 135 | return ctx.OpISub(ctx.U32[1], ctx.OpLoad(ctx.U32[1], ctx.instance_index), | 149 | return ctx.OpISub(ctx.U32[1], ctx.OpLoad(ctx.U32[1], ctx.instance_index), |
| 136 | ctx.OpLoad(ctx.U32[1], ctx.base_instance)); | 150 | ctx.OpLoad(ctx.U32[1], ctx.base_instance)); |
| 137 | case IR::Attribute::VertexId: | 151 | } |
| 152 | case IR::Attribute::VertexId: | ||
| 153 | if (ctx.profile.support_vertex_instance_id) { | ||
| 154 | return ctx.OpLoad(ctx.U32[1], ctx.vertex_id); | ||
| 155 | } else { | ||
| 138 | return ctx.OpISub(ctx.U32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_index), | 156 | return ctx.OpISub(ctx.U32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_index), |
| 139 | ctx.OpLoad(ctx.U32[1], ctx.base_vertex)); | 157 | ctx.OpLoad(ctx.U32[1], ctx.base_vertex)); |
| 140 | default: | ||
| 141 | break; | ||
| 142 | } | 158 | } |
| 159 | default: | ||
| 160 | throw NotImplementedException("Read attribute {}", attr); | ||
| 143 | } | 161 | } |
| 144 | return ctx.OpLoad(ctx.F32[1], InputAttrPointer(ctx, attr)); | ||
| 145 | } | 162 | } |
| 146 | 163 | ||
| 147 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value) { | 164 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value) { |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp new file mode 100644 index 000000000..70ae7b51e --- /dev/null +++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "shader_recompiler/backend/spirv/emit_spirv.h" | ||
| 6 | |||
| 7 | namespace Shader::Backend::SPIRV { | ||
| 8 | |||
| 9 | void EmitPrologue(EmitContext& ctx) { | ||
| 10 | if (ctx.stage == Stage::VertexB) { | ||
| 11 | const Id zero{ctx.Constant(ctx.F32[1], 0.0f)}; | ||
| 12 | const Id one{ctx.Constant(ctx.F32[1], 1.0f)}; | ||
| 13 | const Id null_vector{ctx.ConstantComposite(ctx.F32[4], zero, zero, zero, zero)}; | ||
| 14 | ctx.OpStore(ctx.output_position, ctx.ConstantComposite(ctx.F32[4], zero, zero, zero, one)); | ||
| 15 | for (const Id generic_id : ctx.output_generics) { | ||
| 16 | if (Sirit::ValidId(generic_id)) { | ||
| 17 | ctx.OpStore(generic_id, null_vector); | ||
| 18 | } | ||
| 19 | } | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | void EmitEpilogue(EmitContext& ctx) { | ||
| 24 | if (ctx.profile.convert_depth_mode) { | ||
| 25 | const Id type{ctx.F32[1]}; | ||
| 26 | const Id position{ctx.OpLoad(ctx.F32[4], ctx.output_position)}; | ||
| 27 | const Id z{ctx.OpCompositeExtract(type, position, 2u)}; | ||
| 28 | const Id w{ctx.OpCompositeExtract(type, position, 3u)}; | ||
| 29 | const Id screen_depth{ctx.OpFMul(type, ctx.OpFAdd(type, z, w), ctx.Constant(type, 0.5f))}; | ||
| 30 | const Id vector{ctx.OpCompositeInsert(ctx.F32[4], screen_depth, position, 2u)}; | ||
| 31 | ctx.OpStore(ctx.output_position, vector); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | } // namespace Shader::Backend::SPIRV | ||
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index ff2970125..ce610799a 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -92,6 +92,14 @@ void IREmitter::DemoteToHelperInvocation(Block* continue_label) { | |||
| 92 | Inst(Opcode::DemoteToHelperInvocation, continue_label); | 92 | Inst(Opcode::DemoteToHelperInvocation, continue_label); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | void IREmitter::Prologue() { | ||
| 96 | Inst(Opcode::Prologue); | ||
| 97 | } | ||
| 98 | |||
| 99 | void IREmitter::Epilogue() { | ||
| 100 | Inst(Opcode::Epilogue); | ||
| 101 | } | ||
| 102 | |||
| 95 | U32 IREmitter::GetReg(IR::Reg reg) { | 103 | U32 IREmitter::GetReg(IR::Reg reg) { |
| 96 | return Inst<U32>(Opcode::GetRegister, reg); | 104 | return Inst<U32>(Opcode::GetRegister, reg); |
| 97 | } | 105 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index 1708be3ef..39109b0de 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -39,6 +39,9 @@ public: | |||
| 39 | void Return(); | 39 | void Return(); |
| 40 | void DemoteToHelperInvocation(Block* continue_label); | 40 | void DemoteToHelperInvocation(Block* continue_label); |
| 41 | 41 | ||
| 42 | void Prologue(); | ||
| 43 | void Epilogue(); | ||
| 44 | |||
| 42 | [[nodiscard]] U32 GetReg(IR::Reg reg); | 45 | [[nodiscard]] U32 GetReg(IR::Reg reg); |
| 43 | void SetReg(IR::Reg reg, const U32& value); | 46 | void SetReg(IR::Reg reg, const U32& value); |
| 44 | 47 | ||
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp index 21b7d8a9f..ba3968056 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.cpp +++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp | |||
| @@ -56,6 +56,8 @@ bool Inst::MayHaveSideEffects() const noexcept { | |||
| 56 | case Opcode::SelectionMerge: | 56 | case Opcode::SelectionMerge: |
| 57 | case Opcode::Return: | 57 | case Opcode::Return: |
| 58 | case Opcode::DemoteToHelperInvocation: | 58 | case Opcode::DemoteToHelperInvocation: |
| 59 | case Opcode::Prologue: | ||
| 60 | case Opcode::Epilogue: | ||
| 59 | case Opcode::SetAttribute: | 61 | case Opcode::SetAttribute: |
| 60 | case Opcode::SetAttributeIndexed: | 62 | case Opcode::SetAttributeIndexed: |
| 61 | case Opcode::SetFragColor: | 63 | case Opcode::SetFragColor: |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index fe888b8b2..8945c7b04 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -15,6 +15,10 @@ OPCODE(SelectionMerge, Void, Labe | |||
| 15 | OPCODE(Return, Void, ) | 15 | OPCODE(Return, Void, ) |
| 16 | OPCODE(DemoteToHelperInvocation, Void, Label, ) | 16 | OPCODE(DemoteToHelperInvocation, Void, Label, ) |
| 17 | 17 | ||
| 18 | // Special operations | ||
| 19 | OPCODE(Prologue, Void, ) | ||
| 20 | OPCODE(Epilogue, Void, ) | ||
| 21 | |||
| 18 | // Context getters/setters | 22 | // Context getters/setters |
| 19 | OPCODE(GetRegister, U32, Reg, ) | 23 | OPCODE(GetRegister, U32, Reg, ) |
| 20 | OPCODE(SetRegister, Void, Reg, U32, ) | 24 | OPCODE(SetRegister, Void, Reg, U32, ) |
diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp index cec03e73e..fdac1c95a 100644 --- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp +++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp | |||
| @@ -634,6 +634,9 @@ public: | |||
| 634 | : stmt_pool{stmt_pool_}, inst_pool{inst_pool_}, block_pool{block_pool_}, env{env_}, | 634 | : stmt_pool{stmt_pool_}, inst_pool{inst_pool_}, block_pool{block_pool_}, env{env_}, |
| 635 | block_list{block_list_} { | 635 | block_list{block_list_} { |
| 636 | Visit(root_stmt, nullptr, nullptr); | 636 | Visit(root_stmt, nullptr, nullptr); |
| 637 | |||
| 638 | IR::IREmitter ir{*block_list.front()}; | ||
| 639 | ir.Prologue(); | ||
| 637 | } | 640 | } |
| 638 | 641 | ||
| 639 | private: | 642 | private: |
| @@ -734,7 +737,9 @@ private: | |||
| 734 | current_block = block_pool.Create(inst_pool); | 737 | current_block = block_pool.Create(inst_pool); |
| 735 | block_list.push_back(current_block); | 738 | block_list.push_back(current_block); |
| 736 | } | 739 | } |
| 737 | IR::IREmitter{*current_block}.Return(); | 740 | IR::IREmitter ir{*current_block}; |
| 741 | ir.Epilogue(); | ||
| 742 | ir.Return(); | ||
| 738 | current_block = nullptr; | 743 | current_block = nullptr; |
| 739 | break; | 744 | break; |
| 740 | } | 745 | } |
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h index b57cbc310..41550bfc6 100644 --- a/src/shader_recompiler/profile.h +++ b/src/shader_recompiler/profile.h | |||
| @@ -4,8 +4,18 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 7 | namespace Shader { | 11 | namespace Shader { |
| 8 | 12 | ||
| 13 | enum class AttributeType : u8 { | ||
| 14 | Float, | ||
| 15 | SignedInt, | ||
| 16 | UnsignedInt, | ||
| 17 | }; | ||
| 18 | |||
| 9 | struct Profile { | 19 | struct Profile { |
| 10 | bool unified_descriptor_binding{}; | 20 | bool unified_descriptor_binding{}; |
| 11 | bool support_vertex_instance_id{}; | 21 | bool support_vertex_instance_id{}; |
| @@ -24,6 +34,9 @@ struct Profile { | |||
| 24 | 34 | ||
| 25 | // FClamp is broken and OpFMax + OpFMin should be used instead | 35 | // FClamp is broken and OpFMax + OpFMin should be used instead |
| 26 | bool has_broken_spirv_clamp{}; | 36 | bool has_broken_spirv_clamp{}; |
| 37 | |||
| 38 | std::array<AttributeType, 32> generic_input_types{}; | ||
| 39 | bool convert_depth_mode{}; | ||
| 27 | }; | 40 | }; |
| 28 | 41 | ||
| 29 | } // namespace Shader | 42 | } // namespace Shader |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index a2ec418b1..a87ed1976 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -181,6 +181,9 @@ void GraphicsPipeline::Configure(bool is_indexed) { | |||
| 181 | PushImageDescriptors(stage_infos[stage], samplers.data(), image_view_ids.data(), | 181 | PushImageDescriptors(stage_infos[stage], samplers.data(), image_view_ids.data(), |
| 182 | *texture_cache, *update_descriptor_queue, index); | 182 | *texture_cache, *update_descriptor_queue, index); |
| 183 | } | 183 | } |
| 184 | if (!descriptor_set_layout) { | ||
| 185 | return; | ||
| 186 | } | ||
| 184 | const VkDescriptorSet descriptor_set{descriptor_allocator.Commit()}; | 187 | const VkDescriptorSet descriptor_set{descriptor_allocator.Commit()}; |
| 185 | update_descriptor_queue->Send(*descriptor_update_template, descriptor_set); | 188 | update_descriptor_queue->Send(*descriptor_update_template, descriptor_set); |
| 186 | 189 | ||
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index bdbc8dd1e..504b8c9d6 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -437,7 +437,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_, | |||
| 437 | buffer_cache{buffer_cache_}, texture_cache{texture_cache_} { | 437 | buffer_cache{buffer_cache_}, texture_cache{texture_cache_} { |
| 438 | const auto& float_control{device.FloatControlProperties()}; | 438 | const auto& float_control{device.FloatControlProperties()}; |
| 439 | const VkDriverIdKHR driver_id{device.GetDriverID()}; | 439 | const VkDriverIdKHR driver_id{device.GetDriverID()}; |
| 440 | profile = Shader::Profile{ | 440 | base_profile = Shader::Profile{ |
| 441 | .unified_descriptor_binding = true, | 441 | .unified_descriptor_binding = true, |
| 442 | .support_vertex_instance_id = false, | 442 | .support_vertex_instance_id = false, |
| 443 | .support_float_controls = true, | 443 | .support_float_controls = true, |
| @@ -458,6 +458,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_, | |||
| 458 | .support_vote = true, | 458 | .support_vote = true, |
| 459 | .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), | 459 | .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), |
| 460 | .has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR, | 460 | .has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR, |
| 461 | .generic_input_types{}, | ||
| 461 | }; | 462 | }; |
| 462 | } | 463 | } |
| 463 | 464 | ||
| @@ -589,6 +590,7 @@ GraphicsPipeline PipelineCache::CreateGraphicsPipeline(ShaderPools& pools, | |||
| 589 | Shader::Environment& env{*envs[env_index]}; | 590 | Shader::Environment& env{*envs[env_index]}; |
| 590 | ++env_index; | 591 | ++env_index; |
| 591 | 592 | ||
| 593 | const Shader::Profile profile{MakeProfile(key, env.ShaderStage())}; | ||
| 592 | const std::vector<u32> code{EmitSPIRV(profile, env, program, binding)}; | 594 | const std::vector<u32> code{EmitSPIRV(profile, env, program, binding)}; |
| 593 | modules[stage_index] = BuildShader(device, code); | 595 | modules[stage_index] = BuildShader(device, code); |
| 594 | } | 596 | } |
| @@ -645,9 +647,36 @@ ComputePipeline PipelineCache::CreateComputePipeline(ShaderPools& pools, | |||
| 645 | Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; | 647 | Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; |
| 646 | Shader::IR::Program program{TranslateProgram(pools.inst, pools.block, env, cfg)}; | 648 | Shader::IR::Program program{TranslateProgram(pools.inst, pools.block, env, cfg)}; |
| 647 | u32 binding{0}; | 649 | u32 binding{0}; |
| 648 | std::vector<u32> code{EmitSPIRV(profile, env, program, binding)}; | 650 | std::vector<u32> code{EmitSPIRV(base_profile, env, program, binding)}; |
| 649 | return ComputePipeline{device, descriptor_pool, update_descriptor_queue, program.info, | 651 | return ComputePipeline{device, descriptor_pool, update_descriptor_queue, program.info, |
| 650 | BuildShader(device, code)}; | 652 | BuildShader(device, code)}; |
| 651 | } | 653 | } |
| 652 | 654 | ||
| 655 | static Shader::AttributeType CastAttributeType(const FixedPipelineState::VertexAttribute& attr) { | ||
| 656 | switch (attr.Type()) { | ||
| 657 | case Maxwell::VertexAttribute::Type::SignedNorm: | ||
| 658 | case Maxwell::VertexAttribute::Type::UnsignedNorm: | ||
| 659 | case Maxwell::VertexAttribute::Type::UnsignedScaled: | ||
| 660 | case Maxwell::VertexAttribute::Type::SignedScaled: | ||
| 661 | case Maxwell::VertexAttribute::Type::Float: | ||
| 662 | return Shader::AttributeType::Float; | ||
| 663 | case Maxwell::VertexAttribute::Type::SignedInt: | ||
| 664 | return Shader::AttributeType::SignedInt; | ||
| 665 | case Maxwell::VertexAttribute::Type::UnsignedInt: | ||
| 666 | return Shader::AttributeType::UnsignedInt; | ||
| 667 | } | ||
| 668 | return Shader::AttributeType::Float; | ||
| 669 | } | ||
| 670 | |||
| 671 | Shader::Profile PipelineCache::MakeProfile(const GraphicsPipelineCacheKey& key, | ||
| 672 | Shader::Stage stage) { | ||
| 673 | Shader::Profile profile{base_profile}; | ||
| 674 | if (stage == Shader::Stage::VertexB) { | ||
| 675 | profile.convert_depth_mode = key.state.ndc_minus_one_to_one != 0; | ||
| 676 | std::ranges::transform(key.state.attributes, profile.generic_input_types.begin(), | ||
| 677 | &CastAttributeType); | ||
| 678 | } | ||
| 679 | return profile; | ||
| 680 | } | ||
| 681 | |||
| 653 | } // namespace Vulkan | 682 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index d481f56f9..e09d78063 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h | |||
| @@ -156,6 +156,8 @@ private: | |||
| 156 | ComputePipeline CreateComputePipeline(ShaderPools& pools, const ComputePipelineCacheKey& key, | 156 | ComputePipeline CreateComputePipeline(ShaderPools& pools, const ComputePipelineCacheKey& key, |
| 157 | Shader::Environment& env) const; | 157 | Shader::Environment& env) const; |
| 158 | 158 | ||
| 159 | Shader::Profile MakeProfile(const GraphicsPipelineCacheKey& key, Shader::Stage stage); | ||
| 160 | |||
| 159 | Tegra::GPU& gpu; | 161 | Tegra::GPU& gpu; |
| 160 | Tegra::Engines::Maxwell3D& maxwell3d; | 162 | Tegra::Engines::Maxwell3D& maxwell3d; |
| 161 | Tegra::Engines::KeplerCompute& kepler_compute; | 163 | Tegra::Engines::KeplerCompute& kepler_compute; |
| @@ -176,7 +178,7 @@ private: | |||
| 176 | 178 | ||
| 177 | ShaderPools main_pools; | 179 | ShaderPools main_pools; |
| 178 | 180 | ||
| 179 | Shader::Profile profile; | 181 | Shader::Profile base_profile; |
| 180 | std::string pipeline_cache_filename; | 182 | std::string pipeline_cache_filename; |
| 181 | }; | 183 | }; |
| 182 | 184 | ||