summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.cpp199
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.h101
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp12
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp6
4 files changed, 155 insertions, 163 deletions
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
index 8734045e5..1a23de07f 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
@@ -2,6 +2,7 @@
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 <cstring>
5#include <tuple> 6#include <tuple>
6 7
7#include <boost/functional/hash.hpp> 8#include <boost/functional/hash.hpp>
@@ -12,6 +13,31 @@
12 13
13namespace Vulkan { 14namespace Vulkan {
14 15
16namespace {
17
18constexpr std::size_t POINT = 0;
19constexpr std::size_t LINE = 1;
20constexpr std::size_t POLYGON = 2;
21constexpr std::array POLYGON_OFFSET_ENABLE_LUT = {
22 POINT, // Points
23 LINE, // Lines
24 LINE, // LineLoop
25 LINE, // LineStrip
26 POLYGON, // Triangles
27 POLYGON, // TriangleStrip
28 POLYGON, // TriangleFan
29 POLYGON, // Quads
30 POLYGON, // QuadStrip
31 POLYGON, // Polygon
32 LINE, // LinesAdjacency
33 LINE, // LineStripAdjacency
34 POLYGON, // TrianglesAdjacency
35 POLYGON, // TriangleStripAdjacency
36 POLYGON, // Patches
37};
38
39} // Anonymous namespace
40
15void FixedPipelineState::DepthStencil::Fill(const Maxwell& regs) noexcept { 41void FixedPipelineState::DepthStencil::Fill(const Maxwell& regs) noexcept {
16 raw = 0; 42 raw = 0;
17 front.action_stencil_fail.Assign(PackStencilOp(regs.stencil_front_op_fail)); 43 front.action_stencil_fail.Assign(PackStencilOp(regs.stencil_front_op_fail));
@@ -36,14 +62,41 @@ void FixedPipelineState::DepthStencil::Fill(const Maxwell& regs) noexcept {
36 depth_test_func.Assign(PackComparisonOp(regs.depth_test_func)); 62 depth_test_func.Assign(PackComparisonOp(regs.depth_test_func));
37} 63}
38 64
39namespace { 65void FixedPipelineState::Rasterizer::Fill(const Maxwell& regs) noexcept {
66 const auto& clip = regs.view_volume_clip_control;
67 const std::array enabled_lut = {regs.polygon_offset_point_enable,
68 regs.polygon_offset_line_enable,
69 regs.polygon_offset_fill_enable};
70 const u32 topology_index = static_cast<u32>(regs.draw.topology.Value());
71
72 u32 packed_front_face = PackFrontFace(regs.front_face);
73 if (regs.screen_y_control.triangle_rast_flip != 0 &&
74 regs.viewport_transform[0].scale_y > 0.0f) {
75 // Flip front face
76 packed_front_face = 1 - packed_front_face;
77 }
40 78
41constexpr FixedPipelineState::InputAssembly GetInputAssemblyState(const Maxwell& regs) { 79 raw = 0;
42 return FixedPipelineState::InputAssembly( 80 topology.Assign(topology_index);
43 regs.draw.topology, regs.primitive_restart.enabled, 81 primitive_restart_enable.Assign(regs.primitive_restart.enabled != 0 ? 1 : 0);
44 regs.draw.topology == Maxwell::PrimitiveTopology::Points ? regs.point_size : 0.0f); 82 cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0);
83 depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0);
84 depth_clamp_enable.Assign(clip.depth_clamp_near == 1 || clip.depth_clamp_far == 1 ? 1 : 0);
85 ndc_minus_one_to_one.Assign(regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1 : 0);
86 cull_face.Assign(PackCullFace(regs.cull_face));
87 front_face.Assign(packed_front_face);
88 polygon_mode.Assign(PackPolygonMode(regs.polygon_mode_front));
89 patch_control_points_minus_one.Assign(regs.patch_vertices - 1);
90 tessellation_primitive.Assign(static_cast<u32>(regs.tess_mode.prim.Value()));
91 tessellation_spacing.Assign(static_cast<u32>(regs.tess_mode.spacing.Value()));
92 tessellation_clockwise.Assign(regs.tess_mode.cw.Value());
93 logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0);
94 logic_op.Assign(PackLogicOp(regs.logic_op.operation));
95 std::memcpy(&point_size, &regs.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast
45} 96}
46 97
98namespace {
99
47constexpr FixedPipelineState::BlendingAttachment GetBlendingAttachmentState( 100constexpr FixedPipelineState::BlendingAttachment GetBlendingAttachmentState(
48 const Maxwell& regs, std::size_t render_target) { 101 const Maxwell& regs, std::size_t render_target) {
49 const auto& mask = regs.color_mask[regs.color_mask_common ? 0 : render_target]; 102 const auto& mask = regs.color_mask[regs.color_mask_common ? 0 : render_target];
@@ -86,56 +139,6 @@ constexpr FixedPipelineState::ColorBlending GetColorBlendingState(const Maxwell&
86 GetBlendingAttachmentState(regs, 6), GetBlendingAttachmentState(regs, 7)}); 139 GetBlendingAttachmentState(regs, 6), GetBlendingAttachmentState(regs, 7)});
87} 140}
88 141
89constexpr FixedPipelineState::Tessellation GetTessellationState(const Maxwell& regs) {
90 return FixedPipelineState::Tessellation(regs.patch_vertices, regs.tess_mode.prim,
91 regs.tess_mode.spacing, regs.tess_mode.cw != 0);
92}
93
94constexpr std::size_t Point = 0;
95constexpr std::size_t Line = 1;
96constexpr std::size_t Polygon = 2;
97constexpr std::array PolygonOffsetEnableLUT = {
98 Point, // Points
99 Line, // Lines
100 Line, // LineLoop
101 Line, // LineStrip
102 Polygon, // Triangles
103 Polygon, // TriangleStrip
104 Polygon, // TriangleFan
105 Polygon, // Quads
106 Polygon, // QuadStrip
107 Polygon, // Polygon
108 Line, // LinesAdjacency
109 Line, // LineStripAdjacency
110 Polygon, // TrianglesAdjacency
111 Polygon, // TriangleStripAdjacency
112 Polygon, // Patches
113};
114
115constexpr FixedPipelineState::Rasterizer GetRasterizerState(const Maxwell& regs) {
116 const std::array enabled_lut = {regs.polygon_offset_point_enable,
117 regs.polygon_offset_line_enable,
118 regs.polygon_offset_fill_enable};
119 const auto topology = static_cast<std::size_t>(regs.draw.topology.Value());
120 const bool depth_bias_enabled = enabled_lut[PolygonOffsetEnableLUT[topology]];
121
122 const auto& clip = regs.view_volume_clip_control;
123 const bool depth_clamp_enabled = clip.depth_clamp_near == 1 || clip.depth_clamp_far == 1;
124
125 Maxwell::FrontFace front_face = regs.front_face;
126 if (regs.screen_y_control.triangle_rast_flip != 0 &&
127 regs.viewport_transform[0].scale_y > 0.0f) {
128 if (front_face == Maxwell::FrontFace::CounterClockWise)
129 front_face = Maxwell::FrontFace::ClockWise;
130 else if (front_face == Maxwell::FrontFace::ClockWise)
131 front_face = Maxwell::FrontFace::CounterClockWise;
132 }
133
134 const bool gl_ndc = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne;
135 return FixedPipelineState::Rasterizer(regs.cull_test_enabled, depth_bias_enabled,
136 depth_clamp_enabled, gl_ndc, regs.cull_face, front_face);
137}
138
139} // Anonymous namespace 142} // Anonymous namespace
140 143
141std::size_t FixedPipelineState::BlendingAttachment::Hash() const noexcept { 144std::size_t FixedPipelineState::BlendingAttachment::Hash() const noexcept {
@@ -168,43 +171,14 @@ bool FixedPipelineState::VertexInput::operator==(const VertexInput& rhs) const n
168 return std::memcmp(this, &rhs, sizeof *this) == 0; 171 return std::memcmp(this, &rhs, sizeof *this) == 0;
169} 172}
170 173
171std::size_t FixedPipelineState::InputAssembly::Hash() const noexcept {
172 std::size_t point_size_int = 0;
173 std::memcpy(&point_size_int, &point_size, sizeof(point_size));
174 return (static_cast<std::size_t>(topology) << 24) ^ (point_size_int << 32) ^
175 static_cast<std::size_t>(primitive_restart_enable);
176}
177
178bool FixedPipelineState::InputAssembly::operator==(const InputAssembly& rhs) const noexcept {
179 return std::tie(topology, primitive_restart_enable, point_size) ==
180 std::tie(rhs.topology, rhs.primitive_restart_enable, rhs.point_size);
181}
182
183std::size_t FixedPipelineState::Tessellation::Hash() const noexcept {
184 return static_cast<std::size_t>(patch_control_points) ^
185 (static_cast<std::size_t>(primitive) << 6) ^ (static_cast<std::size_t>(spacing) << 8) ^
186 (static_cast<std::size_t>(clockwise) << 10);
187}
188
189bool FixedPipelineState::Tessellation::operator==(const Tessellation& rhs) const noexcept {
190 return std::tie(patch_control_points, primitive, spacing, clockwise) ==
191 std::tie(rhs.patch_control_points, rhs.primitive, rhs.spacing, rhs.clockwise);
192}
193
194std::size_t FixedPipelineState::Rasterizer::Hash() const noexcept { 174std::size_t FixedPipelineState::Rasterizer::Hash() const noexcept {
195 return static_cast<std::size_t>(cull_enable) ^ 175 u64 hash = static_cast<u64>(raw) << 32;
196 (static_cast<std::size_t>(depth_bias_enable) << 1) ^ 176 std::memcpy(&hash, &point_size, sizeof(u32));
197 (static_cast<std::size_t>(depth_clamp_enable) << 2) ^ 177 return static_cast<std::size_t>(hash);
198 (static_cast<std::size_t>(ndc_minus_one_to_one) << 3) ^
199 (static_cast<std::size_t>(cull_face) << 24) ^
200 (static_cast<std::size_t>(front_face) << 48);
201} 178}
202 179
203bool FixedPipelineState::Rasterizer::operator==(const Rasterizer& rhs) const noexcept { 180bool FixedPipelineState::Rasterizer::operator==(const Rasterizer& rhs) const noexcept {
204 return std::tie(cull_enable, depth_bias_enable, depth_clamp_enable, ndc_minus_one_to_one, 181 return raw == rhs.raw && point_size == rhs.point_size;
205 cull_face, front_face) ==
206 std::tie(rhs.cull_enable, rhs.depth_bias_enable, rhs.depth_clamp_enable,
207 rhs.ndc_minus_one_to_one, rhs.cull_face, rhs.front_face);
208} 182}
209 183
210std::size_t FixedPipelineState::DepthStencil::Hash() const noexcept { 184std::size_t FixedPipelineState::DepthStencil::Hash() const noexcept {
@@ -231,8 +205,6 @@ bool FixedPipelineState::ColorBlending::operator==(const ColorBlending& rhs) con
231std::size_t FixedPipelineState::Hash() const noexcept { 205std::size_t FixedPipelineState::Hash() const noexcept {
232 std::size_t hash = 0; 206 std::size_t hash = 0;
233 boost::hash_combine(hash, vertex_input.Hash()); 207 boost::hash_combine(hash, vertex_input.Hash());
234 boost::hash_combine(hash, input_assembly.Hash());
235 boost::hash_combine(hash, tessellation.Hash());
236 boost::hash_combine(hash, rasterizer.Hash()); 208 boost::hash_combine(hash, rasterizer.Hash());
237 boost::hash_combine(hash, depth_stencil.Hash()); 209 boost::hash_combine(hash, depth_stencil.Hash());
238 boost::hash_combine(hash, color_blending.Hash()); 210 boost::hash_combine(hash, color_blending.Hash());
@@ -240,17 +212,13 @@ std::size_t FixedPipelineState::Hash() const noexcept {
240} 212}
241 213
242bool FixedPipelineState::operator==(const FixedPipelineState& rhs) const noexcept { 214bool FixedPipelineState::operator==(const FixedPipelineState& rhs) const noexcept {
243 return std::tie(vertex_input, input_assembly, tessellation, rasterizer, depth_stencil, 215 return std::tie(vertex_input, rasterizer, depth_stencil, color_blending) ==
244 color_blending) == std::tie(rhs.vertex_input, rhs.input_assembly, 216 std::tie(rhs.vertex_input, rhs.rasterizer, rhs.depth_stencil, rhs.color_blending);
245 rhs.tessellation, rhs.rasterizer, rhs.depth_stencil,
246 rhs.color_blending);
247} 217}
248 218
249FixedPipelineState GetFixedPipelineState(const Maxwell& regs) { 219FixedPipelineState GetFixedPipelineState(const Maxwell& regs) {
250 FixedPipelineState fixed_state; 220 FixedPipelineState fixed_state;
251 fixed_state.input_assembly = GetInputAssemblyState(regs); 221 fixed_state.rasterizer.Fill(regs);
252 fixed_state.tessellation = GetTessellationState(regs);
253 fixed_state.rasterizer = GetRasterizerState(regs);
254 fixed_state.depth_stencil.Fill(regs); 222 fixed_state.depth_stencil.Fill(regs);
255 fixed_state.color_blending = GetColorBlendingState(regs); 223 fixed_state.color_blending = GetColorBlendingState(regs);
256 return fixed_state; 224 return fixed_state;
@@ -307,4 +275,41 @@ Maxwell::StencilOp FixedPipelineState::UnpackStencilOp(u32 packed) noexcept {
307 return LUT[packed]; 275 return LUT[packed];
308} 276}
309 277
278u32 FixedPipelineState::PackCullFace(Maxwell::CullFace cull) noexcept {
279 // FrontAndBack is 0x408, by substracting 0x406 in it we get 2.
280 // Individual cull faces are in 0x404 and 0x405, substracting 0x404 we get 0 and 1.
281 const u32 value = static_cast<u32>(cull);
282 return value - (value == 0x408 ? 0x406 : 0x404);
283}
284
285Maxwell::CullFace FixedPipelineState::UnpackCullFace(u32 packed) noexcept {
286 static constexpr std::array LUT = {Maxwell::CullFace::Front, Maxwell::CullFace::Back,
287 Maxwell::CullFace::FrontAndBack};
288 return LUT[packed];
289}
290
291u32 FixedPipelineState::PackFrontFace(Maxwell::FrontFace face) noexcept {
292 return static_cast<u32>(face) - 0x900;
293}
294
295Maxwell::FrontFace FixedPipelineState::UnpackFrontFace(u32 packed) noexcept {
296 return static_cast<Maxwell::FrontFace>(packed + 0x900);
297}
298
299u32 FixedPipelineState::PackPolygonMode(Maxwell::PolygonMode mode) noexcept {
300 return static_cast<u32>(mode) - 0x1B00;
301}
302
303Maxwell::PolygonMode FixedPipelineState::UnpackPolygonMode(u32 packed) noexcept {
304 return static_cast<Maxwell::PolygonMode>(packed + 0x1B00);
305}
306
307u32 FixedPipelineState::PackLogicOp(Maxwell::LogicOperation op) noexcept {
308 return static_cast<u32>(op) - 0x1500;
309}
310
311Maxwell::LogicOperation FixedPipelineState::UnpackLogicOp(u32 packed) noexcept {
312 return static_cast<Maxwell::LogicOperation>(packed + 0x1500);
313}
314
310} // namespace Vulkan 315} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
index e30877e77..75b093e90 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
@@ -30,6 +30,18 @@ struct FixedPipelineState {
30 static u32 PackStencilOp(Maxwell::StencilOp op) noexcept; 30 static u32 PackStencilOp(Maxwell::StencilOp op) noexcept;
31 static Maxwell::StencilOp UnpackStencilOp(u32 packed) noexcept; 31 static Maxwell::StencilOp UnpackStencilOp(u32 packed) noexcept;
32 32
33 static u32 PackCullFace(Maxwell::CullFace cull) noexcept;
34 static Maxwell::CullFace UnpackCullFace(u32 packed) noexcept;
35
36 static u32 PackFrontFace(Maxwell::FrontFace face) noexcept;
37 static Maxwell::FrontFace UnpackFrontFace(u32 packed) noexcept;
38
39 static u32 PackPolygonMode(Maxwell::PolygonMode mode) noexcept;
40 static Maxwell::PolygonMode UnpackPolygonMode(u32 packed) noexcept;
41
42 static u32 PackLogicOp(Maxwell::LogicOperation op) noexcept;
43 static Maxwell::LogicOperation UnpackLogicOp(u32 packed) noexcept;
44
33 struct BlendingAttachment { 45 struct BlendingAttachment {
34 constexpr BlendingAttachment(bool enable, Maxwell::Blend::Equation rgb_equation, 46 constexpr BlendingAttachment(bool enable, Maxwell::Blend::Equation rgb_equation,
35 Maxwell::Blend::Factor src_rgb_func, 47 Maxwell::Blend::Factor src_rgb_func,
@@ -119,71 +131,52 @@ struct FixedPipelineState {
119 }; 131 };
120 static_assert(IsHashable<VertexInput>); 132 static_assert(IsHashable<VertexInput>);
121 133
122 struct InputAssembly { 134 struct Rasterizer {
123 constexpr InputAssembly(Maxwell::PrimitiveTopology topology, bool primitive_restart_enable, 135 union {
124 float point_size) 136 u32 raw;
125 : topology{topology}, primitive_restart_enable{primitive_restart_enable}, 137 BitField<0, 4, u32> topology;
126 point_size{point_size} {} 138 BitField<4, 1, u32> primitive_restart_enable;
127 InputAssembly() = default; 139 BitField<5, 1, u32> cull_enable;
128 140 BitField<6, 1, u32> depth_bias_enable;
129 Maxwell::PrimitiveTopology topology; 141 BitField<7, 1, u32> depth_clamp_enable;
130 bool primitive_restart_enable; 142 BitField<8, 1, u32> ndc_minus_one_to_one;
131 float point_size; 143 BitField<9, 2, u32> cull_face;
132 144 BitField<11, 1, u32> front_face;
133 std::size_t Hash() const noexcept; 145 BitField<12, 2, u32> polygon_mode;
134 146 BitField<14, 5, u32> patch_control_points_minus_one;
135 bool operator==(const InputAssembly& rhs) const noexcept; 147 BitField<19, 2, u32> tessellation_primitive;
136 148 BitField<21, 2, u32> tessellation_spacing;
137 bool operator!=(const InputAssembly& rhs) const noexcept { 149 BitField<23, 1, u32> tessellation_clockwise;
138 return !operator==(rhs); 150 BitField<24, 1, u32> logic_op_enable;
139 } 151 BitField<25, 4, u32> logic_op;
140 }; 152 };
141 153
142 struct Tessellation { 154 // TODO(Rodrigo): Move this to push constants
143 constexpr Tessellation(u32 patch_control_points, Maxwell::TessellationPrimitive primitive, 155 u32 point_size;
144 Maxwell::TessellationSpacing spacing, bool clockwise)
145 : patch_control_points{patch_control_points}, primitive{primitive}, spacing{spacing},
146 clockwise{clockwise} {}
147 Tessellation() = default;
148 156
149 u32 patch_control_points; 157 void Fill(const Maxwell& regs) noexcept;
150 Maxwell::TessellationPrimitive primitive;
151 Maxwell::TessellationSpacing spacing;
152 bool clockwise;
153 158
154 std::size_t Hash() const noexcept; 159 std::size_t Hash() const noexcept;
155 160
156 bool operator==(const Tessellation& rhs) const noexcept; 161 bool operator==(const Rasterizer& rhs) const noexcept;
157 162
158 bool operator!=(const Tessellation& rhs) const noexcept { 163 bool operator!=(const Rasterizer& rhs) const noexcept {
159 return !operator==(rhs); 164 return !operator==(rhs);
160 } 165 }
161 };
162
163 struct Rasterizer {
164 constexpr Rasterizer(bool cull_enable, bool depth_bias_enable, bool depth_clamp_enable,
165 bool ndc_minus_one_to_one, Maxwell::CullFace cull_face,
166 Maxwell::FrontFace front_face)
167 : cull_enable{cull_enable}, depth_bias_enable{depth_bias_enable},
168 depth_clamp_enable{depth_clamp_enable}, ndc_minus_one_to_one{ndc_minus_one_to_one},
169 cull_face{cull_face}, front_face{front_face} {}
170 Rasterizer() = default;
171
172 bool cull_enable;
173 bool depth_bias_enable;
174 bool depth_clamp_enable;
175 bool ndc_minus_one_to_one;
176 Maxwell::CullFace cull_face;
177 Maxwell::FrontFace front_face;
178 166
179 std::size_t Hash() const noexcept; 167 constexpr Maxwell::PrimitiveTopology Topology() const noexcept {
168 return static_cast<Maxwell::PrimitiveTopology>(topology.Value());
169 }
180 170
181 bool operator==(const Rasterizer& rhs) const noexcept; 171 Maxwell::CullFace CullFace() const noexcept {
172 return UnpackCullFace(cull_face.Value());
173 }
182 174
183 bool operator!=(const Rasterizer& rhs) const noexcept { 175 Maxwell::FrontFace FrontFace() const noexcept {
184 return !operator==(rhs); 176 return UnpackFrontFace(front_face.Value());
185 } 177 }
186 }; 178 };
179 static_assert(IsHashable<Rasterizer>);
187 180
188 struct DepthStencil { 181 struct DepthStencil {
189 template <std::size_t Position> 182 template <std::size_t Position>
@@ -257,8 +250,6 @@ struct FixedPipelineState {
257 }; 250 };
258 251
259 VertexInput vertex_input; 252 VertexInput vertex_input;
260 InputAssembly input_assembly;
261 Tessellation tessellation;
262 Rasterizer rasterizer; 253 Rasterizer rasterizer;
263 DepthStencil depth_stencil; 254 DepthStencil depth_stencil;
264 ColorBlending color_blending; 255 ColorBlending color_blending;
@@ -273,8 +264,6 @@ struct FixedPipelineState {
273}; 264};
274static_assert(std::is_trivially_copyable_v<FixedPipelineState::BlendingAttachment>); 265static_assert(std::is_trivially_copyable_v<FixedPipelineState::BlendingAttachment>);
275static_assert(std::is_trivially_copyable_v<FixedPipelineState::VertexInput>); 266static_assert(std::is_trivially_copyable_v<FixedPipelineState::VertexInput>);
276static_assert(std::is_trivially_copyable_v<FixedPipelineState::InputAssembly>);
277static_assert(std::is_trivially_copyable_v<FixedPipelineState::Tessellation>);
278static_assert(std::is_trivially_copyable_v<FixedPipelineState::Rasterizer>); 267static_assert(std::is_trivially_copyable_v<FixedPipelineState::Rasterizer>);
279static_assert(std::is_trivially_copyable_v<FixedPipelineState::DepthStencil>); 268static_assert(std::is_trivially_copyable_v<FixedPipelineState::DepthStencil>);
280static_assert(std::is_trivially_copyable_v<FixedPipelineState::ColorBlending>); 269static_assert(std::is_trivially_copyable_v<FixedPipelineState::ColorBlending>);
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 0dd3ea5bc..e12c26076 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -158,10 +158,8 @@ std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules(
158vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpass_params, 158vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpass_params,
159 const SPIRVProgram& program) const { 159 const SPIRVProgram& program) const {
160 const auto& vi = fixed_state.vertex_input; 160 const auto& vi = fixed_state.vertex_input;
161 const auto& ia = fixed_state.input_assembly;
162 const auto& ds = fixed_state.depth_stencil; 161 const auto& ds = fixed_state.depth_stencil;
163 const auto& cd = fixed_state.color_blending; 162 const auto& cd = fixed_state.color_blending;
164 const auto& ts = fixed_state.tessellation;
165 const auto& rs = fixed_state.rasterizer; 163 const auto& rs = fixed_state.rasterizer;
166 164
167 std::vector<VkVertexInputBindingDescription> vertex_bindings; 165 std::vector<VkVertexInputBindingDescription> vertex_bindings;
@@ -226,15 +224,15 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
226 input_assembly_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; 224 input_assembly_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
227 input_assembly_ci.pNext = nullptr; 225 input_assembly_ci.pNext = nullptr;
228 input_assembly_ci.flags = 0; 226 input_assembly_ci.flags = 0;
229 input_assembly_ci.topology = MaxwellToVK::PrimitiveTopology(device, ia.topology); 227 input_assembly_ci.topology = MaxwellToVK::PrimitiveTopology(device, rs.Topology());
230 input_assembly_ci.primitiveRestartEnable = 228 input_assembly_ci.primitiveRestartEnable =
231 ia.primitive_restart_enable && SupportsPrimitiveRestart(input_assembly_ci.topology); 229 rs.primitive_restart_enable != 0 && SupportsPrimitiveRestart(input_assembly_ci.topology);
232 230
233 VkPipelineTessellationStateCreateInfo tessellation_ci; 231 VkPipelineTessellationStateCreateInfo tessellation_ci;
234 tessellation_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; 232 tessellation_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
235 tessellation_ci.pNext = nullptr; 233 tessellation_ci.pNext = nullptr;
236 tessellation_ci.flags = 0; 234 tessellation_ci.flags = 0;
237 tessellation_ci.patchControlPoints = ts.patch_control_points; 235 tessellation_ci.patchControlPoints = rs.patch_control_points_minus_one.Value() + 1;
238 236
239 VkPipelineViewportStateCreateInfo viewport_ci; 237 VkPipelineViewportStateCreateInfo viewport_ci;
240 viewport_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; 238 viewport_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
@@ -253,8 +251,8 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
253 rasterization_ci.rasterizerDiscardEnable = VK_FALSE; 251 rasterization_ci.rasterizerDiscardEnable = VK_FALSE;
254 rasterization_ci.polygonMode = VK_POLYGON_MODE_FILL; 252 rasterization_ci.polygonMode = VK_POLYGON_MODE_FILL;
255 rasterization_ci.cullMode = 253 rasterization_ci.cullMode =
256 rs.cull_enable ? MaxwellToVK::CullFace(rs.cull_face) : VK_CULL_MODE_NONE; 254 rs.cull_enable ? MaxwellToVK::CullFace(rs.CullFace()) : VK_CULL_MODE_NONE;
257 rasterization_ci.frontFace = MaxwellToVK::FrontFace(rs.front_face); 255 rasterization_ci.frontFace = MaxwellToVK::FrontFace(rs.FrontFace());
258 rasterization_ci.depthBiasEnable = rs.depth_bias_enable; 256 rasterization_ci.depthBiasEnable = rs.depth_bias_enable;
259 rasterization_ci.depthBiasConstantFactor = 0.0f; 257 rasterization_ci.depthBiasConstantFactor = 0.0f;
260 rasterization_ci.depthBiasClamp = 0.0f; 258 rasterization_ci.depthBiasClamp = 0.0f;
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 083da9999..8fdc6400d 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -329,9 +329,9 @@ VKPipelineCache::DecompileShaders(const GraphicsPipelineCacheKey& key) {
329 const auto& gpu = system.GPU().Maxwell3D(); 329 const auto& gpu = system.GPU().Maxwell3D();
330 330
331 Specialization specialization; 331 Specialization specialization;
332 if (fixed_state.input_assembly.topology == Maxwell::PrimitiveTopology::Points) { 332 if (fixed_state.rasterizer.Topology() == Maxwell::PrimitiveTopology::Points) {
333 ASSERT(fixed_state.input_assembly.point_size != 0.0f); 333 ASSERT(fixed_state.rasterizer.point_size != 0);
334 specialization.point_size = fixed_state.input_assembly.point_size; 334 std::memcpy(&specialization.point_size, &fixed_state.rasterizer.point_size, sizeof(u32));
335 } 335 }
336 for (std::size_t i = 0; i < Maxwell::NumVertexAttributes; ++i) { 336 for (std::size_t i = 0; i < Maxwell::NumVertexAttributes; ++i) {
337 specialization.attribute_types[i] = fixed_state.vertex_input.attributes[i].Type(); 337 specialization.attribute_types[i] = fixed_state.vertex_input.attributes[i].Type();