summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h32
-rw-r--r--src/video_core/engines/draw_manager.cpp191
-rw-r--r--src/video_core/engines/draw_manager.h69
-rw-r--r--src/video_core/engines/maxwell_3d.cpp171
-rw-r--r--src/video_core/engines/maxwell_3d.h25
-rw-r--r--src/video_core/macro/macro_hle.cpp69
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp16
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp6
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.cpp6
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp18
12 files changed, 341 insertions, 267 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index b9bad63ac..33bdae748 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -33,6 +33,8 @@ add_library(video_core STATIC
33 engines/sw_blitter/converter.cpp 33 engines/sw_blitter/converter.cpp
34 engines/sw_blitter/converter.h 34 engines/sw_blitter/converter.h
35 engines/const_buffer_info.h 35 engines/const_buffer_info.h
36 engines/draw_manager.cpp
37 engines/draw_manager.h
36 engines/engine_interface.h 38 engines/engine_interface.h
37 engines/engine_upload.cpp 39 engines/engine_upload.cpp
38 engines/engine_upload.h 40 engines/engine_upload.h
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 6881b34c4..502b4d90a 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -26,6 +26,7 @@
26#include "video_core/control/channel_state_cache.h" 26#include "video_core/control/channel_state_cache.h"
27#include "video_core/delayed_destruction_ring.h" 27#include "video_core/delayed_destruction_ring.h"
28#include "video_core/dirty_flags.h" 28#include "video_core/dirty_flags.h"
29#include "video_core/engines/draw_manager.h"
29#include "video_core/engines/kepler_compute.h" 30#include "video_core/engines/kepler_compute.h"
30#include "video_core/engines/maxwell_3d.h" 31#include "video_core/engines/maxwell_3d.h"
31#include "video_core/memory_manager.h" 32#include "video_core/memory_manager.h"
@@ -664,9 +665,10 @@ void BufferCache<P>::BindHostGeometryBuffers(bool is_indexed) {
664 if (is_indexed) { 665 if (is_indexed) {
665 BindHostIndexBuffer(); 666 BindHostIndexBuffer();
666 } else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { 667 } else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
667 const auto& regs = maxwell3d->regs; 668 const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
668 if (regs.draw.topology == Maxwell::PrimitiveTopology::Quads) { 669 if (draw_state.topology == Maxwell::PrimitiveTopology::Quads) {
669 runtime.BindQuadArrayIndexBuffer(regs.vertex_buffer.first, regs.vertex_buffer.count); 670 runtime.BindQuadArrayIndexBuffer(draw_state.vertex_buffer.first,
671 draw_state.vertex_buffer.count);
670 } 672 }
671 } 673 }
672 BindHostVertexBuffers(); 674 BindHostVertexBuffers();
@@ -993,28 +995,29 @@ void BufferCache<P>::BindHostIndexBuffer() {
993 TouchBuffer(buffer, index_buffer.buffer_id); 995 TouchBuffer(buffer, index_buffer.buffer_id);
994 const u32 offset = buffer.Offset(index_buffer.cpu_addr); 996 const u32 offset = buffer.Offset(index_buffer.cpu_addr);
995 const u32 size = index_buffer.size; 997 const u32 size = index_buffer.size;
996 if (maxwell3d->inline_index_draw_indexes.size()) { 998 const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
999 if (!draw_state.inline_index_draw_indexes.empty()) {
997 if constexpr (USE_MEMORY_MAPS) { 1000 if constexpr (USE_MEMORY_MAPS) {
998 auto upload_staging = runtime.UploadStagingBuffer(size); 1001 auto upload_staging = runtime.UploadStagingBuffer(size);
999 std::array<BufferCopy, 1> copies{ 1002 std::array<BufferCopy, 1> copies{
1000 {BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}}; 1003 {BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}};
1001 std::memcpy(upload_staging.mapped_span.data(), 1004 std::memcpy(upload_staging.mapped_span.data(),
1002 maxwell3d->inline_index_draw_indexes.data(), size); 1005 draw_state.inline_index_draw_indexes.data(), size);
1003 runtime.CopyBuffer(buffer, upload_staging.buffer, copies); 1006 runtime.CopyBuffer(buffer, upload_staging.buffer, copies);
1004 } else { 1007 } else {
1005 buffer.ImmediateUpload(0, maxwell3d->inline_index_draw_indexes); 1008 buffer.ImmediateUpload(0, draw_state.inline_index_draw_indexes);
1006 } 1009 }
1007 } else { 1010 } else {
1008 SynchronizeBuffer(buffer, index_buffer.cpu_addr, size); 1011 SynchronizeBuffer(buffer, index_buffer.cpu_addr, size);
1009 } 1012 }
1010 if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { 1013 if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
1011 const u32 new_offset = offset + maxwell3d->regs.index_buffer.first * 1014 const u32 new_offset =
1012 maxwell3d->regs.index_buffer.FormatSizeInBytes(); 1015 offset + draw_state.index_buffer.first * draw_state.index_buffer.FormatSizeInBytes();
1013 runtime.BindIndexBuffer(buffer, new_offset, size); 1016 runtime.BindIndexBuffer(buffer, new_offset, size);
1014 } else { 1017 } else {
1015 runtime.BindIndexBuffer(maxwell3d->regs.draw.topology, maxwell3d->regs.index_buffer.format, 1018 runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format,
1016 maxwell3d->regs.index_buffer.first, 1019 draw_state.index_buffer.first, draw_state.index_buffer.count,
1017 maxwell3d->regs.index_buffer.count, buffer, offset, size); 1020 buffer, offset, size);
1018 } 1021 }
1019} 1022}
1020 1023
@@ -1282,15 +1285,16 @@ template <class P>
1282void BufferCache<P>::UpdateIndexBuffer() { 1285void BufferCache<P>::UpdateIndexBuffer() {
1283 // We have to check for the dirty flags and index count 1286 // We have to check for the dirty flags and index count
1284 // The index count is currently changed without updating the dirty flags 1287 // The index count is currently changed without updating the dirty flags
1285 const auto& index_array = maxwell3d->regs.index_buffer; 1288 const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
1289 const auto& index_array = draw_state.index_buffer;
1286 auto& flags = maxwell3d->dirty.flags; 1290 auto& flags = maxwell3d->dirty.flags;
1287 if (!flags[Dirty::IndexBuffer] && last_index_count == index_array.count) { 1291 if (!flags[Dirty::IndexBuffer] && last_index_count == index_array.count) {
1288 return; 1292 return;
1289 } 1293 }
1290 flags[Dirty::IndexBuffer] = false; 1294 flags[Dirty::IndexBuffer] = false;
1291 last_index_count = index_array.count; 1295 last_index_count = index_array.count;
1292 if (maxwell3d->inline_index_draw_indexes.size()) { 1296 if (!draw_state.inline_index_draw_indexes.empty()) {
1293 auto inline_index_size = static_cast<u32>(maxwell3d->inline_index_draw_indexes.size()); 1297 auto inline_index_size = static_cast<u32>(draw_state.inline_index_draw_indexes.size());
1294 index_buffer = Binding{ 1298 index_buffer = Binding{
1295 .cpu_addr = 0, 1299 .cpu_addr = 0,
1296 .size = inline_index_size, 1300 .size = inline_index_size,
diff --git a/src/video_core/engines/draw_manager.cpp b/src/video_core/engines/draw_manager.cpp
new file mode 100644
index 000000000..c59524e58
--- /dev/null
+++ b/src/video_core/engines/draw_manager.cpp
@@ -0,0 +1,191 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "video_core/dirty_flags.h"
5#include "video_core/engines/draw_manager.h"
6#include "video_core/rasterizer_interface.h"
7
8namespace Tegra::Engines {
9DrawManager::DrawManager(Maxwell3D* maxwell3d_) : maxwell3d(maxwell3d_) {}
10
11void DrawManager::ProcessMethodCall(u32 method, u32 argument) {
12 const auto& regs{maxwell3d->regs};
13 switch (method) {
14 case MAXWELL3D_REG_INDEX(clear_surface):
15 return Clear(1);
16 case MAXWELL3D_REG_INDEX(draw.begin):
17 return DrawBegin();
18 case MAXWELL3D_REG_INDEX(draw.end):
19 return DrawEnd();
20 case MAXWELL3D_REG_INDEX(vertex_buffer.first):
21 case MAXWELL3D_REG_INDEX(vertex_buffer.count):
22 case MAXWELL3D_REG_INDEX(index_buffer.first):
23 break;
24 case MAXWELL3D_REG_INDEX(index_buffer.count):
25 draw_state.draw_indexed = true;
26 break;
27 case MAXWELL3D_REG_INDEX(index_buffer32_subsequent):
28 case MAXWELL3D_REG_INDEX(index_buffer16_subsequent):
29 case MAXWELL3D_REG_INDEX(index_buffer8_subsequent):
30 draw_state.instance_count++;
31 [[fallthrough]];
32 case MAXWELL3D_REG_INDEX(index_buffer32_first):
33 case MAXWELL3D_REG_INDEX(index_buffer16_first):
34 case MAXWELL3D_REG_INDEX(index_buffer8_first):
35 return DrawIndexSmall(argument);
36 case MAXWELL3D_REG_INDEX(draw_inline_index):
37 SetInlineIndexBuffer(argument);
38 break;
39 case MAXWELL3D_REG_INDEX(inline_index_2x16.even):
40 SetInlineIndexBuffer(regs.inline_index_2x16.even);
41 SetInlineIndexBuffer(regs.inline_index_2x16.odd);
42 break;
43 case MAXWELL3D_REG_INDEX(inline_index_4x8.index0):
44 SetInlineIndexBuffer(regs.inline_index_4x8.index0);
45 SetInlineIndexBuffer(regs.inline_index_4x8.index1);
46 SetInlineIndexBuffer(regs.inline_index_4x8.index2);
47 SetInlineIndexBuffer(regs.inline_index_4x8.index3);
48 break;
49 case MAXWELL3D_REG_INDEX(topology_override):
50 use_topology_override = true;
51 break;
52 default:
53 break;
54 }
55}
56
57void DrawManager::Clear(u32 layer_count) {
58 maxwell3d->rasterizer->Clear(layer_count);
59}
60
61void DrawManager::DrawDeferred() {
62 if (draw_state.draw_mode != DrawMode::Instance || draw_state.instance_count == 0)
63 return;
64 DrawEnd(draw_state.instance_count + 1, true);
65 draw_state.instance_count = 0;
66}
67
68void DrawManager::DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count,
69 u32 base_instance, u32 num_instances) {
70 draw_state.topology = topology;
71 draw_state.vertex_buffer.first = vertex_first;
72 draw_state.vertex_buffer.count = vertex_count;
73 draw_state.base_instance = base_instance;
74 ProcessDraw(false, num_instances);
75}
76
77void DrawManager::DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count,
78 u32 base_index, u32 base_instance, u32 num_instances) {
79 const auto& regs{maxwell3d->regs};
80 draw_state.topology = topology;
81 draw_state.index_buffer = regs.index_buffer;
82 draw_state.index_buffer.first = index_first;
83 draw_state.index_buffer.count = index_count;
84 draw_state.base_index = base_index;
85 draw_state.base_instance = base_instance;
86 ProcessDraw(true, num_instances);
87}
88
89void DrawManager::SetInlineIndexBuffer(u32 index) {
90 draw_state.inline_index_draw_indexes.push_back(static_cast<u8>(index & 0x000000ff));
91 draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x0000ff00) >> 8));
92 draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x00ff0000) >> 16));
93 draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0xff000000) >> 24));
94 draw_state.draw_mode = DrawMode::InlineIndex;
95}
96
97void DrawManager::DrawBegin() {
98 const auto& regs{maxwell3d->regs};
99 auto reset_instance_count = regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First;
100 auto increment_instance_count =
101 regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent;
102 if (reset_instance_count) {
103 DrawDeferred();
104 draw_state.instance_count = 0;
105 draw_state.draw_mode = DrawMode::General;
106 } else if (increment_instance_count) {
107 draw_state.instance_count++;
108 draw_state.draw_mode = DrawMode::Instance;
109 }
110
111 draw_state.topology = regs.draw.topology;
112}
113
114void DrawManager::DrawEnd(u32 instance_count, bool force_draw) {
115 const auto& regs{maxwell3d->regs};
116 switch (draw_state.draw_mode) {
117 case DrawMode::Instance:
118 if (!force_draw)
119 break;
120 [[fallthrough]];
121 case DrawMode::General:
122 draw_state.base_instance = regs.global_base_instance_index;
123 draw_state.base_index = regs.global_base_vertex_index;
124 if (draw_state.draw_indexed) {
125 draw_state.index_buffer = regs.index_buffer;
126 ProcessDraw(true, instance_count);
127 } else {
128 draw_state.vertex_buffer = regs.vertex_buffer;
129 ProcessDraw(false, instance_count);
130 }
131 draw_state.draw_indexed = false;
132 break;
133 case DrawMode::InlineIndex:
134 draw_state.base_instance = regs.global_base_instance_index;
135 draw_state.base_index = regs.global_base_vertex_index;
136 draw_state.index_buffer = regs.index_buffer;
137 draw_state.index_buffer.count =
138 static_cast<u32>(draw_state.inline_index_draw_indexes.size() / 4);
139 draw_state.index_buffer.format = Maxwell3D::Regs::IndexFormat::UnsignedInt;
140 ProcessDraw(true, instance_count);
141 draw_state.inline_index_draw_indexes.clear();
142 break;
143 }
144}
145
146void DrawManager::DrawIndexSmall(u32 argument) {
147 const auto& regs{maxwell3d->regs};
148 IndexBufferSmall index_small_params{argument};
149 draw_state.base_instance = regs.global_base_instance_index;
150 draw_state.base_index = regs.global_base_vertex_index;
151 draw_state.index_buffer = regs.index_buffer;
152 draw_state.index_buffer.first = index_small_params.first;
153 draw_state.index_buffer.count = index_small_params.count;
154 draw_state.topology = index_small_params.topology;
155 maxwell3d->dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
156 ProcessDraw(true, 1);
157}
158
159void DrawManager::ProcessTopologyOverride() {
160 if (!use_topology_override)
161 return;
162
163 const auto& regs{maxwell3d->regs};
164 switch (regs.topology_override) {
165 case PrimitiveTopologyOverride::None:
166 break;
167 case PrimitiveTopologyOverride::Points:
168 draw_state.topology = PrimitiveTopology::Points;
169 break;
170 case PrimitiveTopologyOverride::Lines:
171 draw_state.topology = PrimitiveTopology::Lines;
172 break;
173 case PrimitiveTopologyOverride::LineStrip:
174 draw_state.topology = PrimitiveTopology::LineStrip;
175 break;
176 default:
177 draw_state.topology = static_cast<PrimitiveTopology>(regs.topology_override);
178 break;
179 }
180}
181
182void DrawManager::ProcessDraw(bool draw_indexed, u32 instance_count) {
183 LOG_TRACE(HW_GPU, "called, topology={}, count={}", draw_state.topology.Value(),
184 draw_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count);
185
186 ProcessTopologyOverride();
187
188 if (maxwell3d->ShouldExecute())
189 maxwell3d->rasterizer->Draw(draw_indexed, instance_count);
190}
191} // namespace Tegra::Engines
diff --git a/src/video_core/engines/draw_manager.h b/src/video_core/engines/draw_manager.h
new file mode 100644
index 000000000..4f67027ca
--- /dev/null
+++ b/src/video_core/engines/draw_manager.h
@@ -0,0 +1,69 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5#include "common/common_types.h"
6#include "video_core/engines/maxwell_3d.h"
7
8namespace VideoCore {
9class RasterizerInterface;
10}
11
12namespace Tegra::Engines {
13using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology;
14using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride;
15using IndexBuffer = Maxwell3D::Regs::IndexBuffer;
16using VertexBuffer = Maxwell3D::Regs::VertexBuffer;
17using IndexBufferSmall = Maxwell3D::Regs::IndexBufferSmall;
18
19class DrawManager {
20public:
21 enum class DrawMode : u32 { General = 0, Instance, InlineIndex };
22 struct State {
23 PrimitiveTopology topology{};
24 DrawMode draw_mode{};
25 bool draw_indexed{};
26 u32 base_index{};
27 VertexBuffer vertex_buffer;
28 IndexBuffer index_buffer;
29 u32 base_instance{};
30 u32 instance_count{};
31 std::vector<u8> inline_index_draw_indexes;
32 };
33
34 explicit DrawManager(Maxwell3D* maxwell_3d);
35
36 void ProcessMethodCall(u32 method, u32 argument);
37
38 void Clear(u32 layer_count);
39
40 void DrawDeferred();
41
42 void DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count,
43 u32 base_instance, u32 num_instances);
44
45 void DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index,
46 u32 base_instance, u32 num_instances);
47
48 const State& GetDrawState() const {
49 return draw_state;
50 }
51
52private:
53 void SetInlineIndexBuffer(u32 index);
54
55 void DrawBegin();
56
57 void DrawEnd(u32 instance_count = 1, bool force_draw = false);
58
59 void DrawIndexSmall(u32 argument);
60
61 void ProcessTopologyOverride();
62
63 void ProcessDraw(bool draw_indexed, u32 instance_count);
64
65 Maxwell3D* maxwell3d{};
66 State draw_state{};
67 bool use_topology_override{};
68};
69} // namespace Tegra::Engines
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 34bbc72cf..d4ef8d7c5 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -7,6 +7,7 @@
7#include "core/core.h" 7#include "core/core.h"
8#include "core/core_timing.h" 8#include "core/core_timing.h"
9#include "video_core/dirty_flags.h" 9#include "video_core/dirty_flags.h"
10#include "video_core/engines/draw_manager.h"
10#include "video_core/engines/maxwell_3d.h" 11#include "video_core/engines/maxwell_3d.h"
11#include "video_core/gpu.h" 12#include "video_core/gpu.h"
12#include "video_core/memory_manager.h" 13#include "video_core/memory_manager.h"
@@ -21,8 +22,10 @@ using VideoCore::QueryType;
21constexpr u32 MacroRegistersStart = 0xE00; 22constexpr u32 MacroRegistersStart = 0xE00;
22 23
23Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_) 24Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_)
24 : system{system_}, memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)}, 25 : draw_manager{std::make_unique<DrawManager>(this)}, system{system_},
25 upload_state{memory_manager, regs.upload} { 26 memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)}, upload_state{
27 memory_manager,
28 regs.upload} {
26 dirty.flags.flip(); 29 dirty.flags.flip();
27 InitializeRegisterDefaults(); 30 InitializeRegisterDefaults();
28} 31}
@@ -116,16 +119,6 @@ void Maxwell3D::InitializeRegisterDefaults() {
116 regs.polygon_mode_front = Maxwell3D::Regs::PolygonMode::Fill; 119 regs.polygon_mode_front = Maxwell3D::Regs::PolygonMode::Fill;
117 120
118 shadow_state = regs; 121 shadow_state = regs;
119
120 draw_command[MAXWELL3D_REG_INDEX(draw.end)] = true;
121 draw_command[MAXWELL3D_REG_INDEX(draw.begin)] = true;
122 draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.first)] = true;
123 draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true;
124 draw_command[MAXWELL3D_REG_INDEX(index_buffer.first)] = true;
125 draw_command[MAXWELL3D_REG_INDEX(index_buffer.count)] = true;
126 draw_command[MAXWELL3D_REG_INDEX(draw_inline_index)] = true;
127 draw_command[MAXWELL3D_REG_INDEX(inline_index_2x16.even)] = true;
128 draw_command[MAXWELL3D_REG_INDEX(inline_index_4x8.index0)] = true;
129} 122}
130 123
131void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) { 124void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) {
@@ -213,29 +206,6 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume
213 return ProcessCBBind(3); 206 return ProcessCBBind(3);
214 case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config): 207 case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config):
215 return ProcessCBBind(4); 208 return ProcessCBBind(4);
216 case MAXWELL3D_REG_INDEX(index_buffer32_first):
217 regs.index_buffer.count = regs.index_buffer32_first.count;
218 regs.index_buffer.first = regs.index_buffer32_first.first;
219 dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
220 draw_indexed = true;
221 return ProcessDraw();
222 case MAXWELL3D_REG_INDEX(index_buffer16_first):
223 regs.index_buffer.count = regs.index_buffer16_first.count;
224 regs.index_buffer.first = regs.index_buffer16_first.first;
225 dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
226 draw_indexed = true;
227 return ProcessDraw();
228 case MAXWELL3D_REG_INDEX(index_buffer8_first):
229 regs.index_buffer.count = regs.index_buffer8_first.count;
230 regs.index_buffer.first = regs.index_buffer8_first.first;
231 dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
232 draw_indexed = true;
233 return ProcessDraw();
234 case MAXWELL3D_REG_INDEX(topology_override):
235 use_topology_override = true;
236 return;
237 case MAXWELL3D_REG_INDEX(clear_surface):
238 return ProcessClearBuffers(1);
239 case MAXWELL3D_REG_INDEX(report_semaphore.query): 209 case MAXWELL3D_REG_INDEX(report_semaphore.query):
240 return ProcessQueryGet(); 210 return ProcessQueryGet();
241 case MAXWELL3D_REG_INDEX(render_enable.mode): 211 case MAXWELL3D_REG_INDEX(render_enable.mode):
@@ -254,6 +224,9 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume
254 return rasterizer->FragmentBarrier(); 224 return rasterizer->FragmentBarrier();
255 case MAXWELL3D_REG_INDEX(tiled_cache_barrier): 225 case MAXWELL3D_REG_INDEX(tiled_cache_barrier):
256 return rasterizer->TiledCacheBarrier(); 226 return rasterizer->TiledCacheBarrier();
227 default:
228 draw_manager->ProcessMethodCall(method, argument);
229 break;
257 } 230 }
258} 231}
259 232
@@ -268,7 +241,7 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters)
268 // Execute the current macro. 241 // Execute the current macro.
269 macro_engine->Execute(macro_positions[entry], parameters); 242 macro_engine->Execute(macro_positions[entry], parameters);
270 243
271 ProcessDeferredDraw(); 244 draw_manager->DrawDeferred();
272} 245}
273 246
274void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { 247void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
@@ -291,62 +264,7 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
291 const u32 argument = ProcessShadowRam(method, method_argument); 264 const u32 argument = ProcessShadowRam(method, method_argument);
292 ProcessDirtyRegisters(method, argument); 265 ProcessDirtyRegisters(method, argument);
293 266
294 if (draw_command[method]) { 267 ProcessMethodCall(method, argument, method_argument, is_last_call);
295 regs.reg_array[method] = method_argument;
296 deferred_draw_method.push_back(method);
297 auto update_inline_index = [&](const u32 index) {
298 inline_index_draw_indexes.push_back(static_cast<u8>(index & 0x000000ff));
299 inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x0000ff00) >> 8));
300 inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x00ff0000) >> 16));
301 inline_index_draw_indexes.push_back(static_cast<u8>((index & 0xff000000) >> 24));
302 draw_mode = DrawMode::InlineIndex;
303 };
304 switch (method) {
305 case MAXWELL3D_REG_INDEX(draw.begin): {
306 draw_mode =
307 (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) ||
308 (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged)
309 ? DrawMode::Instance
310 : DrawMode::General;
311 break;
312 }
313 case MAXWELL3D_REG_INDEX(draw.end):
314 switch (draw_mode) {
315 case DrawMode::General:
316 ProcessDraw();
317 break;
318 case DrawMode::InlineIndex:
319 regs.index_buffer.count = static_cast<u32>(inline_index_draw_indexes.size() / 4);
320 regs.index_buffer.format = Regs::IndexFormat::UnsignedInt;
321 draw_indexed = true;
322 ProcessDraw();
323 inline_index_draw_indexes.clear();
324 break;
325 case DrawMode::Instance:
326 break;
327 }
328 break;
329 case MAXWELL3D_REG_INDEX(index_buffer.count):
330 draw_indexed = true;
331 break;
332 case MAXWELL3D_REG_INDEX(draw_inline_index):
333 update_inline_index(method_argument);
334 break;
335 case MAXWELL3D_REG_INDEX(inline_index_2x16.even):
336 update_inline_index(regs.inline_index_2x16.even);
337 update_inline_index(regs.inline_index_2x16.odd);
338 break;
339 case MAXWELL3D_REG_INDEX(inline_index_4x8.index0):
340 update_inline_index(regs.inline_index_4x8.index0);
341 update_inline_index(regs.inline_index_4x8.index1);
342 update_inline_index(regs.inline_index_4x8.index2);
343 update_inline_index(regs.inline_index_4x8.index3);
344 break;
345 }
346 } else {
347 ProcessDeferredDraw();
348 ProcessMethodCall(method, argument, method_argument, is_last_call);
349 }
350} 268}
351 269
352void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, 270void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
@@ -387,35 +305,6 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
387 } 305 }
388} 306}
389 307
390void Maxwell3D::ProcessTopologyOverride() {
391 using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology;
392 using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride;
393
394 PrimitiveTopology topology{};
395
396 switch (regs.topology_override) {
397 case PrimitiveTopologyOverride::None:
398 topology = regs.draw.topology;
399 break;
400 case PrimitiveTopologyOverride::Points:
401 topology = PrimitiveTopology::Points;
402 break;
403 case PrimitiveTopologyOverride::Lines:
404 topology = PrimitiveTopology::Lines;
405 break;
406 case PrimitiveTopologyOverride::LineStrip:
407 topology = PrimitiveTopology::LineStrip;
408 break;
409 default:
410 topology = static_cast<PrimitiveTopology>(regs.topology_override);
411 break;
412 }
413
414 if (use_topology_override) {
415 regs.draw.topology.Assign(topology);
416 }
417}
418
419void Maxwell3D::ProcessMacroUpload(u32 data) { 308void Maxwell3D::ProcessMacroUpload(u32 data) {
420 macro_engine->AddCode(regs.load_mme.instruction_ptr++, data); 309 macro_engine->AddCode(regs.load_mme.instruction_ptr++, data);
421} 310}
@@ -625,44 +514,4 @@ u32 Maxwell3D::GetRegisterValue(u32 method) const {
625 return regs.reg_array[method]; 514 return regs.reg_array[method];
626} 515}
627 516
628void Maxwell3D::ProcessClearBuffers(u32 layer_count) {
629 rasterizer->Clear(layer_count);
630}
631
632void Maxwell3D::ProcessDraw(u32 instance_count) {
633 LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(),
634 draw_indexed ? regs.index_buffer.count : regs.vertex_buffer.count);
635
636 ProcessTopologyOverride();
637
638 if (ShouldExecute()) {
639 rasterizer->Draw(draw_indexed, instance_count);
640 }
641
642 draw_indexed = false;
643 deferred_draw_method.clear();
644}
645
646void Maxwell3D::ProcessDeferredDraw() {
647 if (draw_mode != DrawMode::Instance || deferred_draw_method.empty()) {
648 return;
649 }
650
651 const auto method_count = deferred_draw_method.size();
652 u32 instance_count = 1;
653 u32 vertex_buffer_count = 0;
654 u32 index_buffer_count = 0;
655 for (size_t index = 0; index < method_count; ++index) {
656 const u32 method = deferred_draw_method[index];
657 if (method == MAXWELL3D_REG_INDEX(vertex_buffer.count)) {
658 instance_count = ++vertex_buffer_count;
659 } else if (method == MAXWELL3D_REG_INDEX(index_buffer.count)) {
660 instance_count = ++index_buffer_count;
661 }
662 }
663 ASSERT_MSG(!(vertex_buffer_count && index_buffer_count), "Instance both indexed and direct?");
664
665 ProcessDraw(instance_count);
666}
667
668} // namespace Tegra::Engines 517} // namespace Tegra::Engines
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index a541cd95f..22b904319 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -37,6 +37,8 @@ class RasterizerInterface;
37 37
38namespace Tegra::Engines { 38namespace Tegra::Engines {
39 39
40class DrawManager;
41
40/** 42/**
41 * This Engine is known as GF100_3D. Documentation can be found in: 43 * This Engine is known as GF100_3D. Documentation can be found in:
42 * https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/3d/clb197.h 44 * https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/3d/clb197.h
@@ -2223,6 +2225,7 @@ public:
2223 2225
2224 struct IndexBufferSmall { 2226 struct IndexBufferSmall {
2225 union { 2227 union {
2228 u32 raw;
2226 BitField<0, 16, u32> first; 2229 BitField<0, 16, u32> first;
2227 BitField<16, 12, u32> count; 2230 BitField<16, 12, u32> count;
2228 BitField<28, 4, PrimitiveTopology> topology; 2231 BitField<28, 4, PrimitiveTopology> topology;
@@ -3061,10 +3064,8 @@ public:
3061 Tables tables{}; 3064 Tables tables{};
3062 } dirty; 3065 } dirty;
3063 3066
3064 std::vector<u8> inline_index_draw_indexes; 3067 std::unique_ptr<DrawManager> draw_manager;
3065 3068 friend class DrawManager;
3066 /// Handles a write to the CLEAR_BUFFERS register.
3067 void ProcessClearBuffers(u32 layer_count);
3068 3069
3069private: 3070private:
3070 void InitializeRegisterDefaults(); 3071 void InitializeRegisterDefaults();
@@ -3122,15 +3123,6 @@ private:
3122 /// Handles a write to the CB_BIND register. 3123 /// Handles a write to the CB_BIND register.
3123 void ProcessCBBind(size_t stage_index); 3124 void ProcessCBBind(size_t stage_index);
3124 3125
3125 /// Handles use of topology overrides (e.g., to avoid using a topology assigned from a macro)
3126 void ProcessTopologyOverride();
3127
3128 /// Handles deferred draw(e.g., instance draw).
3129 void ProcessDeferredDraw();
3130
3131 /// Handles a draw.
3132 void ProcessDraw(u32 instance_count = 1);
3133
3134 /// Returns a query's value or an empty object if the value will be deferred through a cache. 3126 /// Returns a query's value or an empty object if the value will be deferred through a cache.
3135 std::optional<u64> GetQueryResult(); 3127 std::optional<u64> GetQueryResult();
3136 3128
@@ -3153,13 +3145,6 @@ private:
3153 Upload::State upload_state; 3145 Upload::State upload_state;
3154 3146
3155 bool execute_on{true}; 3147 bool execute_on{true};
3156 bool use_topology_override{false};
3157
3158 std::array<bool, Regs::NUM_REGS> draw_command{};
3159 std::vector<u32> deferred_draw_method;
3160 enum class DrawMode : u32 { General = 0, Instance, InlineIndex };
3161 DrawMode draw_mode{DrawMode::General};
3162 bool draw_indexed{};
3163}; 3148};
3164 3149
3165#define ASSERT_REG_POSITION(field_name, position) \ 3150#define ASSERT_REG_POSITION(field_name, position) \
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp
index 0f3262edb..8549db2e4 100644
--- a/src/video_core/macro/macro_hle.cpp
+++ b/src/video_core/macro/macro_hle.cpp
@@ -5,6 +5,7 @@
5#include <vector> 5#include <vector>
6#include "common/scope_exit.h" 6#include "common/scope_exit.h"
7#include "video_core/dirty_flags.h" 7#include "video_core/dirty_flags.h"
8#include "video_core/engines/draw_manager.h"
8#include "video_core/engines/maxwell_3d.h" 9#include "video_core/engines/maxwell_3d.h"
9#include "video_core/macro/macro.h" 10#include "video_core/macro/macro.h"
10#include "video_core/macro/macro_hle.h" 11#include "video_core/macro/macro_hle.h"
@@ -18,57 +19,33 @@ using HLEFunction = void (*)(Engines::Maxwell3D& maxwell3d, const std::vector<u3
18// HLE'd functions 19// HLE'd functions
19void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { 20void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
20 const u32 instance_count = parameters[2] & maxwell3d.GetRegisterValue(0xD1B); 21 const u32 instance_count = parameters[2] & maxwell3d.GetRegisterValue(0xD1B);
21 22 maxwell3d.draw_manager->DrawIndex(
22 maxwell3d.regs.draw.topology.Assign( 23 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff),
23 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff)); 24 parameters[4], parameters[1], parameters[3], parameters[5], instance_count);
24 maxwell3d.regs.global_base_instance_index = parameters[5];
25 maxwell3d.regs.global_base_vertex_index = parameters[3];
26 maxwell3d.regs.index_buffer.count = parameters[1];
27 maxwell3d.regs.index_buffer.first = parameters[4];
28
29 if (maxwell3d.ShouldExecute()) {
30 maxwell3d.Rasterizer().Draw(true, instance_count);
31 }
32 maxwell3d.regs.index_buffer.count = 0;
33} 25}
34 26
35void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { 27void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
36 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); 28 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
37 29 maxwell3d.draw_manager->DrawArray(
38 maxwell3d.regs.vertex_buffer.first = parameters[3]; 30 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]),
39 maxwell3d.regs.vertex_buffer.count = parameters[1]; 31 parameters[3], parameters[1], parameters[4], instance_count);
40 maxwell3d.regs.global_base_instance_index = parameters[4];
41 maxwell3d.regs.draw.topology.Assign(
42 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]));
43
44 if (maxwell3d.ShouldExecute()) {
45 maxwell3d.Rasterizer().Draw(false, instance_count);
46 }
47 maxwell3d.regs.vertex_buffer.count = 0;
48} 32}
49 33
50void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { 34void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
51 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); 35 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
52 const u32 element_base = parameters[4]; 36 const u32 element_base = parameters[4];
53 const u32 base_instance = parameters[5]; 37 const u32 base_instance = parameters[5];
54 maxwell3d.regs.index_buffer.first = parameters[3];
55 maxwell3d.regs.vertex_id_base = element_base; 38 maxwell3d.regs.vertex_id_base = element_base;
56 maxwell3d.regs.index_buffer.count = parameters[1];
57 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; 39 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
58 maxwell3d.regs.global_base_vertex_index = element_base;
59 maxwell3d.regs.global_base_instance_index = base_instance;
60 maxwell3d.CallMethod(0x8e3, 0x640, true); 40 maxwell3d.CallMethod(0x8e3, 0x640, true);
61 maxwell3d.CallMethod(0x8e4, element_base, true); 41 maxwell3d.CallMethod(0x8e4, element_base, true);
62 maxwell3d.CallMethod(0x8e5, base_instance, true); 42 maxwell3d.CallMethod(0x8e5, base_instance, true);
63 maxwell3d.regs.draw.topology.Assign( 43
64 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0])); 44 maxwell3d.draw_manager->DrawIndex(
65 if (maxwell3d.ShouldExecute()) { 45 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]),
66 maxwell3d.Rasterizer().Draw(true, instance_count); 46 parameters[3], parameters[1], element_base, base_instance, instance_count);
67 } 47
68 maxwell3d.regs.vertex_id_base = 0x0; 48 maxwell3d.regs.vertex_id_base = 0x0;
69 maxwell3d.regs.index_buffer.count = 0;
70 maxwell3d.regs.global_base_vertex_index = 0x0;
71 maxwell3d.regs.global_base_instance_index = 0x0;
72 maxwell3d.CallMethod(0x8e3, 0x640, true); 49 maxwell3d.CallMethod(0x8e3, 0x640, true);
73 maxwell3d.CallMethod(0x8e4, 0x0, true); 50 maxwell3d.CallMethod(0x8e4, 0x0, true);
74 maxwell3d.CallMethod(0x8e5, 0x0, true); 51 maxwell3d.CallMethod(0x8e5, 0x0, true);
@@ -79,9 +56,6 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
79 SCOPE_EXIT({ 56 SCOPE_EXIT({
80 // Clean everything. 57 // Clean everything.
81 maxwell3d.regs.vertex_id_base = 0x0; 58 maxwell3d.regs.vertex_id_base = 0x0;
82 maxwell3d.regs.index_buffer.count = 0;
83 maxwell3d.regs.global_base_vertex_index = 0x0;
84 maxwell3d.regs.global_base_instance_index = 0x0;
85 maxwell3d.CallMethod(0x8e3, 0x640, true); 59 maxwell3d.CallMethod(0x8e3, 0x640, true);
86 maxwell3d.CallMethod(0x8e4, 0x0, true); 60 maxwell3d.CallMethod(0x8e4, 0x0, true);
87 maxwell3d.CallMethod(0x8e5, 0x0, true); 61 maxwell3d.CallMethod(0x8e5, 0x0, true);
@@ -93,9 +67,6 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
93 // Nothing to do. 67 // Nothing to do.
94 return; 68 return;
95 } 69 }
96 const auto topology =
97 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[2]);
98 maxwell3d.regs.draw.topology.Assign(topology);
99 const u32 padding = parameters[3]; 70 const u32 padding = parameters[3];
100 const std::size_t max_draws = parameters[4]; 71 const std::size_t max_draws = parameters[4];
101 72
@@ -106,23 +77,17 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
106 77
107 for (std::size_t index = first_draw; index < last_draw; index++) { 78 for (std::size_t index = first_draw; index < last_draw; index++) {
108 const std::size_t base = index * indirect_words + 5; 79 const std::size_t base = index * indirect_words + 5;
109 const u32 num_vertices = parameters[base];
110 const u32 instance_count = parameters[base + 1];
111 const u32 first_index = parameters[base + 2];
112 const u32 base_vertex = parameters[base + 3]; 80 const u32 base_vertex = parameters[base + 3];
113 const u32 base_instance = parameters[base + 4]; 81 const u32 base_instance = parameters[base + 4];
114 maxwell3d.regs.index_buffer.first = first_index;
115 maxwell3d.regs.vertex_id_base = base_vertex; 82 maxwell3d.regs.vertex_id_base = base_vertex;
116 maxwell3d.regs.index_buffer.count = num_vertices;
117 maxwell3d.regs.global_base_vertex_index = base_vertex;
118 maxwell3d.regs.global_base_instance_index = base_instance;
119 maxwell3d.CallMethod(0x8e3, 0x640, true); 83 maxwell3d.CallMethod(0x8e3, 0x640, true);
120 maxwell3d.CallMethod(0x8e4, base_vertex, true); 84 maxwell3d.CallMethod(0x8e4, base_vertex, true);
121 maxwell3d.CallMethod(0x8e5, base_instance, true); 85 maxwell3d.CallMethod(0x8e5, base_instance, true);
122 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; 86 maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
123 if (maxwell3d.ShouldExecute()) { 87 maxwell3d.draw_manager->DrawIndex(
124 maxwell3d.Rasterizer().Draw(true, instance_count); 88 static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[2]),
125 } 89 parameters[base + 2], parameters[base], base_vertex, base_instance,
90 parameters[base + 1]);
126 } 91 }
127} 92}
128 93
@@ -136,7 +101,7 @@ void HLE_EAD26C3E2109B06B(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
136 ASSERT(clear_params.layer == 0); 101 ASSERT(clear_params.layer == 0);
137 102
138 maxwell3d.regs.clear_surface.raw = clear_params.raw; 103 maxwell3d.regs.clear_surface.raw = clear_params.raw;
139 maxwell3d.ProcessClearBuffers(num_layers); 104 maxwell3d.draw_manager->Clear(num_layers);
140} 105}
141 106
142constexpr std::array<std::pair<u64, HLEFunction>, 5> hle_funcs{{ 107constexpr std::array<std::pair<u64, HLEFunction>, 5> hle_funcs{{
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index f71a316b6..64ed6f628 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -224,16 +224,18 @@ void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) {
224 224
225 SyncState(); 225 SyncState();
226 226
227 const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d->regs.draw.topology); 227 const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
228
229 const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(draw_state.topology);
228 BeginTransformFeedback(pipeline, primitive_mode); 230 BeginTransformFeedback(pipeline, primitive_mode);
229 231
230 const GLuint base_instance = static_cast<GLuint>(maxwell3d->regs.global_base_instance_index); 232 const GLuint base_instance = static_cast<GLuint>(draw_state.base_instance);
231 const GLsizei num_instances = static_cast<GLsizei>(instance_count); 233 const GLsizei num_instances = static_cast<GLsizei>(instance_count);
232 if (is_indexed) { 234 if (is_indexed) {
233 const GLint base_vertex = static_cast<GLint>(maxwell3d->regs.global_base_vertex_index); 235 const GLint base_vertex = static_cast<GLint>(draw_state.base_index);
234 const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d->regs.index_buffer.count); 236 const GLsizei num_vertices = static_cast<GLsizei>(draw_state.index_buffer.count);
235 const GLvoid* const offset = buffer_cache_runtime.IndexOffset(); 237 const GLvoid* const offset = buffer_cache_runtime.IndexOffset();
236 const GLenum format = MaxwellToGL::IndexFormat(maxwell3d->regs.index_buffer.format); 238 const GLenum format = MaxwellToGL::IndexFormat(draw_state.index_buffer.format);
237 if (num_instances == 1 && base_instance == 0 && base_vertex == 0) { 239 if (num_instances == 1 && base_instance == 0 && base_vertex == 0) {
238 glDrawElements(primitive_mode, num_vertices, format, offset); 240 glDrawElements(primitive_mode, num_vertices, format, offset);
239 } else if (num_instances == 1 && base_instance == 0) { 241 } else if (num_instances == 1 && base_instance == 0) {
@@ -252,8 +254,8 @@ void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) {
252 base_instance); 254 base_instance);
253 } 255 }
254 } else { 256 } else {
255 const GLint base_vertex = static_cast<GLint>(maxwell3d->regs.vertex_buffer.first); 257 const GLint base_vertex = static_cast<GLint>(draw_state.vertex_buffer.first);
256 const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d->regs.vertex_buffer.count); 258 const GLsizei num_vertices = static_cast<GLsizei>(draw_state.vertex_buffer.count);
257 if (num_instances == 1 && base_instance == 0) { 259 if (num_instances == 1 && base_instance == 0) {
258 glDrawArrays(primitive_mode, base_vertex, num_vertices); 260 glDrawArrays(primitive_mode, base_vertex, num_vertices);
259 } else if (base_instance == 0) { 261 } else if (base_instance == 0) {
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index a38060100..a59d0d24e 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -22,6 +22,7 @@
22#include "shader_recompiler/frontend/maxwell/control_flow.h" 22#include "shader_recompiler/frontend/maxwell/control_flow.h"
23#include "shader_recompiler/frontend/maxwell/translate_program.h" 23#include "shader_recompiler/frontend/maxwell/translate_program.h"
24#include "shader_recompiler/profile.h" 24#include "shader_recompiler/profile.h"
25#include "video_core/engines/draw_manager.h"
25#include "video_core/engines/kepler_compute.h" 26#include "video_core/engines/kepler_compute.h"
26#include "video_core/engines/maxwell_3d.h" 27#include "video_core/engines/maxwell_3d.h"
27#include "video_core/memory_manager.h" 28#include "video_core/memory_manager.h"
@@ -327,7 +328,7 @@ GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() {
327 const auto& regs{maxwell3d->regs}; 328 const auto& regs{maxwell3d->regs};
328 graphics_key.raw = 0; 329 graphics_key.raw = 0;
329 graphics_key.early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0); 330 graphics_key.early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0);
330 graphics_key.gs_input_topology.Assign(regs.draw.topology.Value()); 331 graphics_key.gs_input_topology.Assign(maxwell3d->draw_manager->GetDrawState().topology);
331 graphics_key.tessellation_primitive.Assign(regs.tessellation.params.domain_type.Value()); 332 graphics_key.tessellation_primitive.Assign(regs.tessellation.params.domain_type.Value());
332 graphics_key.tessellation_spacing.Assign(regs.tessellation.params.spacing.Value()); 333 graphics_key.tessellation_spacing.Assign(regs.tessellation.params.spacing.Value());
333 graphics_key.tessellation_clockwise.Assign( 334 graphics_key.tessellation_clockwise.Assign(
@@ -371,7 +372,8 @@ GraphicsPipeline* ShaderCache::BuiltPipeline(GraphicsPipeline* pipeline) const n
371 // If games are using a small index count, we can assume these are full screen quads. 372 // If games are using a small index count, we can assume these are full screen quads.
372 // Usually these shaders are only used once for building textures so we can assume they 373 // Usually these shaders are only used once for building textures so we can assume they
373 // can't be built async 374 // can't be built async
374 if (maxwell3d->regs.index_buffer.count <= 6 || maxwell3d->regs.vertex_buffer.count <= 6) { 375 const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
376 if (draw_state.index_buffer.count <= 6 || draw_state.vertex_buffer.count <= 6) {
375 return pipeline; 377 return pipeline;
376 } 378 }
377 return nullptr; 379 return nullptr;
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
index f3f08b42c..24529c80f 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
@@ -8,6 +8,7 @@
8#include "common/cityhash.h" 8#include "common/cityhash.h"
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/polyfill_ranges.h" 10#include "common/polyfill_ranges.h"
11#include "video_core/engines/draw_manager.h"
11#include "video_core/renderer_vulkan/fixed_pipeline_state.h" 12#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
12#include "video_core/renderer_vulkan/vk_state_tracker.h" 13#include "video_core/renderer_vulkan/vk_state_tracker.h"
13 14
@@ -50,12 +51,13 @@ void RefreshXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell&
50void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, 51void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d,
51 bool has_extended_dynamic_state, bool has_dynamic_vertex_input) { 52 bool has_extended_dynamic_state, bool has_dynamic_vertex_input) {
52 const Maxwell& regs = maxwell3d.regs; 53 const Maxwell& regs = maxwell3d.regs;
54 const auto topology_ = maxwell3d.draw_manager->GetDrawState().topology;
53 const std::array enabled_lut{ 55 const std::array enabled_lut{
54 regs.polygon_offset_point_enable, 56 regs.polygon_offset_point_enable,
55 regs.polygon_offset_line_enable, 57 regs.polygon_offset_line_enable,
56 regs.polygon_offset_fill_enable, 58 regs.polygon_offset_fill_enable,
57 }; 59 };
58 const u32 topology_index = static_cast<u32>(regs.draw.topology.Value()); 60 const u32 topology_index = static_cast<u32>(topology_);
59 61
60 raw1 = 0; 62 raw1 = 0;
61 extended_dynamic_state.Assign(has_extended_dynamic_state ? 1 : 0); 63 extended_dynamic_state.Assign(has_extended_dynamic_state ? 1 : 0);
@@ -78,7 +80,7 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d,
78 Maxwell::Tessellation::OutputPrimitives::Triangles_CW); 80 Maxwell::Tessellation::OutputPrimitives::Triangles_CW);
79 logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); 81 logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0);
80 logic_op.Assign(PackLogicOp(regs.logic_op.op)); 82 logic_op.Assign(PackLogicOp(regs.logic_op.op));
81 topology.Assign(regs.draw.topology); 83 topology.Assign(topology_);
82 msaa_mode.Assign(regs.anti_alias_samples_mode); 84 msaa_mode.Assign(regs.anti_alias_samples_mode);
83 85
84 raw2 = 0; 86 raw2 = 0;
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 38a6b7488..81f5f3e11 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -507,7 +507,8 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const
507 // If games are using a small index count, we can assume these are full screen quads. 507 // If games are using a small index count, we can assume these are full screen quads.
508 // Usually these shaders are only used once for building textures so we can assume they 508 // Usually these shaders are only used once for building textures so we can assume they
509 // can't be built async 509 // can't be built async
510 if (maxwell3d->regs.index_buffer.count <= 6 || maxwell3d->regs.vertex_buffer.count <= 6) { 510 const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
511 if (draw_state.index_buffer.count <= 6 || draw_state.vertex_buffer.count <= 6) {
511 return pipeline; 512 return pipeline;
512 } 513 }
513 return nullptr; 514 return nullptr;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index d8ad8815c..8d7a5e400 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -12,6 +12,7 @@
12#include "common/scope_exit.h" 12#include "common/scope_exit.h"
13#include "common/settings.h" 13#include "common/settings.h"
14#include "video_core/control/channel_state.h" 14#include "video_core/control/channel_state.h"
15#include "video_core/engines/draw_manager.h"
15#include "video_core/engines/kepler_compute.h" 16#include "video_core/engines/kepler_compute.h"
16#include "video_core/engines/maxwell_3d.h" 17#include "video_core/engines/maxwell_3d.h"
17#include "video_core/renderer_vulkan/blit_image.h" 18#include "video_core/renderer_vulkan/blit_image.h"
@@ -36,6 +37,7 @@
36namespace Vulkan { 37namespace Vulkan {
37 38
38using Maxwell = Tegra::Engines::Maxwell3D::Regs; 39using Maxwell = Tegra::Engines::Maxwell3D::Regs;
40using MaxwellDrawState = Tegra::Engines::DrawManager::State;
39using VideoCommon::ImageViewId; 41using VideoCommon::ImageViewId;
40using VideoCommon::ImageViewType; 42using VideoCommon::ImageViewType;
41 43
@@ -127,16 +129,16 @@ VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u3
127 return scissor; 129 return scissor;
128} 130}
129 131
130DrawParams MakeDrawParams(const Maxwell& regs, u32 num_instances, bool is_indexed) { 132DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances, bool is_indexed) {
131 DrawParams params{ 133 DrawParams params{
132 .base_instance = regs.global_base_instance_index, 134 .base_instance = draw_state.base_instance,
133 .num_instances = num_instances, 135 .num_instances = num_instances,
134 .base_vertex = is_indexed ? regs.global_base_vertex_index : regs.vertex_buffer.first, 136 .base_vertex = is_indexed ? draw_state.base_index : draw_state.vertex_buffer.first,
135 .num_vertices = is_indexed ? regs.index_buffer.count : regs.vertex_buffer.count, 137 .num_vertices = is_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count,
136 .first_index = is_indexed ? regs.index_buffer.first : 0, 138 .first_index = is_indexed ? draw_state.index_buffer.first : 0,
137 .is_indexed = is_indexed, 139 .is_indexed = is_indexed,
138 }; 140 };
139 if (regs.draw.topology == Maxwell::PrimitiveTopology::Quads) { 141 if (draw_state.topology == Maxwell::PrimitiveTopology::Quads) {
140 // 6 triangle vertices per quad, base vertex is part of the index 142 // 6 triangle vertices per quad, base vertex is part of the index
141 // See BindQuadArrayIndexBuffer for more details 143 // See BindQuadArrayIndexBuffer for more details
142 params.num_vertices = (params.num_vertices / 4) * 6; 144 params.num_vertices = (params.num_vertices / 4) * 6;
@@ -195,9 +197,9 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) {
195 197
196 UpdateDynamicStates(); 198 UpdateDynamicStates();
197 199
198 const auto& regs{maxwell3d->regs}; 200 const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
199 const u32 num_instances{instance_count}; 201 const u32 num_instances{instance_count};
200 const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_indexed)}; 202 const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed)};
201 scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) { 203 scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) {
202 if (draw_params.is_indexed) { 204 if (draw_params.is_indexed) {
203 cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances, 205 cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances,