summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-03-24 01:33:45 -0300
committerGravatar ameerj2021-07-22 21:51:24 -0400
commit68a9505d8a1d00c6ba2739bc0af3069cf87b9b84 (patch)
treeb9a78497cd8af1d73a7eda34cd0df08b3dc324e6
parentshader: Fix use-after-free bug in object_pool (diff)
downloadyuzu-68a9505d8a1d00c6ba2739bc0af3069cf87b9b84.tar.gz
yuzu-68a9505d8a1d00c6ba2739bc0af3069cf87b9b84.tar.xz
yuzu-68a9505d8a1d00c6ba2739bc0af3069cf87b9b84.zip
shader: Implement NDC [-1, 1], attribute types and default varying initialization
Diffstat (limited to '')
-rw-r--r--src/shader_recompiler/CMakeLists.txt1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.cpp35
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.h10
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.h2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp69
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_special.cpp35
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp8
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h3
-rw-r--r--src/shader_recompiler/frontend/ir/microinstruction.cpp2
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc4
-rw-r--r--src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp7
-rw-r--r--src/shader_recompiler/profile.h13
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp33
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h4
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 =
67Id DefineOutput(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin = std::nullopt) { 67Id 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
71Id 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
72void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { 84void 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
84EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& binding) 96EmitContext::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
165void EmitContext::DefineInterfaces(const Info& info, Stage stage) { 180void EmitContext::DefineInterfaces(const Info& info) {
166 DefineInputs(info, stage); 181 DefineInputs(info);
167 DefineOutputs(info, stage); 182 DefineOutputs(info);
168} 183}
169 184
170void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { 185void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) {
@@ -252,7 +267,7 @@ void EmitContext::DefineLabels(IR::Program& program) {
252 } 267 }
253} 268}
254 269
255void EmitContext::DefineInputs(const Info& info, Stage stage) { 270void 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
326void EmitContext::DefineOutputs(const Info& info, Stage stage) { 341void 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:
104private: 108private:
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);
28void EmitSelectionMerge(EmitContext& ctx, Id merge_label); 28void EmitSelectionMerge(EmitContext& ctx, Id merge_label);
29void EmitReturn(EmitContext& ctx); 29void EmitReturn(EmitContext& ctx);
30void EmitDemoteToHelperInvocation(EmitContext& ctx, Id continue_label); 30void EmitDemoteToHelperInvocation(EmitContext& ctx, Id continue_label);
31void EmitPrologue(EmitContext& ctx);
32void EmitEpilogue(EmitContext& ctx);
31void EmitGetRegister(EmitContext& ctx); 33void EmitGetRegister(EmitContext& ctx);
32void EmitSetRegister(EmitContext& ctx); 34void EmitSetRegister(EmitContext& ctx);
33void EmitGetPred(EmitContext& ctx); 35void 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
7namespace Shader::Backend::SPIRV { 11namespace Shader::Backend::SPIRV {
8namespace { 12namespace {
9Id InputAttrPointer(EmitContext& ctx, IR::Attribute attr) { 13std::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
31Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { 27Id 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
131Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr) { 127Id 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
147void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value) { 164void 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
7namespace Shader::Backend::SPIRV {
8
9void 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
23void 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
95void IREmitter::Prologue() {
96 Inst(Opcode::Prologue);
97}
98
99void IREmitter::Epilogue() {
100 Inst(Opcode::Epilogue);
101}
102
95U32 IREmitter::GetReg(IR::Reg reg) { 103U32 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
15OPCODE(Return, Void, ) 15OPCODE(Return, Void, )
16OPCODE(DemoteToHelperInvocation, Void, Label, ) 16OPCODE(DemoteToHelperInvocation, Void, Label, )
17 17
18// Special operations
19OPCODE(Prologue, Void, )
20OPCODE(Epilogue, Void, )
21
18// Context getters/setters 22// Context getters/setters
19OPCODE(GetRegister, U32, Reg, ) 23OPCODE(GetRegister, U32, Reg, )
20OPCODE(SetRegister, Void, Reg, U32, ) 24OPCODE(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
639private: 642private:
@@ -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
7namespace Shader { 11namespace Shader {
8 12
13enum class AttributeType : u8 {
14 Float,
15 SignedInt,
16 UnsignedInt,
17};
18
9struct Profile { 19struct 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
655static 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
671Shader::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