aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/engines/draw_manager.cpp
diff options
context:
space:
mode:
authorlizzie <lizzie@eden-emu.dev>2026-04-28 17:44:51 +0200
committercrueter <crueter@eden-emu.dev>2026-04-28 17:44:51 +0200
commit77decca678b99b388ddbde3517cb9bd5f065cb80 (patch)
tree9b427872ec0c7e88cde507e64699f121f86dc2a9 /src/video_core/engines/draw_manager.cpp
parented225f8a8b37a061eeb8e4e69858230b89c6ae50 (diff)
[video_core/engines/maxwell3d] memory inline DrawState to reduce indirection on hot paths (#3758)
usual indirection removal helps very slightly to codegen the idea is basically to reduce the amount of pointer deference overall in the code, and use idiomatic std::variant<>-isms to not rely on vtables/unique_ptr overhead this should allow the compiler to emit better code of course it's a tiny optimisation and only CPU side, but allows us to reduce indirection which is almost always a good thing "but youre passing more parameters to the function!!!" its literally memoized into a register my friend Signed-off-by: lizzie <lizzie@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3758 Reviewed-by: crueter <crueter@eden-emu.dev> Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Diffstat (limited to 'src/video_core/engines/draw_manager.cpp')
-rw-r--r--src/video_core/engines/draw_manager.cpp246
1 files changed, 105 insertions, 141 deletions
diff --git a/src/video_core/engines/draw_manager.cpp b/src/video_core/engines/draw_manager.cpp
index 971025cb55..079c7bdc09 100644
--- a/src/video_core/engines/draw_manager.cpp
+++ b/src/video_core/engines/draw_manager.cpp
@@ -1,23 +1,24 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
#include "video_core/dirty_flags.h"
-#include "video_core/engines/draw_manager.h"
+#include "video_core/engines/maxwell_3d.h"
#include "video_core/rasterizer_interface.h"
namespace Tegra::Engines {
-DrawManager::DrawManager(Maxwell3D* maxwell3d_) : maxwell3d(maxwell3d_) {}
-void DrawManager::ProcessMethodCall(u32 method, u32 argument) {
- const auto& regs{maxwell3d->regs};
+void Maxwell3D::DrawManager::ProcessMethodCall(Maxwell3D& maxwell3d, u32 method, u32 argument) {
switch (method) {
case MAXWELL3D_REG_INDEX(clear_surface):
- return Clear(1);
+ return Clear(maxwell3d, 1);
case MAXWELL3D_REG_INDEX(draw.begin):
- return DrawBegin();
+ return DrawBegin(maxwell3d);
case MAXWELL3D_REG_INDEX(draw.end):
- return DrawEnd();
+ return DrawEnd(maxwell3d);
case MAXWELL3D_REG_INDEX(vertex_buffer.first):
case MAXWELL3D_REG_INDEX(vertex_buffer.count):
case MAXWELL3D_REG_INDEX(index_buffer.first):
@@ -33,33 +34,29 @@ void DrawManager::ProcessMethodCall(u32 method, u32 argument) {
case MAXWELL3D_REG_INDEX(index_buffer32_first):
case MAXWELL3D_REG_INDEX(index_buffer16_first):
case MAXWELL3D_REG_INDEX(index_buffer8_first):
- return DrawIndexSmall(argument);
+ return DrawIndexSmall(maxwell3d, argument);
case MAXWELL3D_REG_INDEX(draw_inline_index):
- SetInlineIndexBuffer(argument);
+ SetInlineIndexBuffer(maxwell3d, argument);
break;
case MAXWELL3D_REG_INDEX(inline_index_2x16.even):
- SetInlineIndexBuffer(regs.inline_index_2x16.even);
- SetInlineIndexBuffer(regs.inline_index_2x16.odd);
+ SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_2x16.even);
+ SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_2x16.odd);
break;
case MAXWELL3D_REG_INDEX(inline_index_4x8.index0):
- SetInlineIndexBuffer(regs.inline_index_4x8.index0);
- SetInlineIndexBuffer(regs.inline_index_4x8.index1);
- SetInlineIndexBuffer(regs.inline_index_4x8.index2);
- SetInlineIndexBuffer(regs.inline_index_4x8.index3);
+ SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_4x8.index0);
+ SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_4x8.index1);
+ SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_4x8.index2);
+ SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_4x8.index3);
break;
case MAXWELL3D_REG_INDEX(vertex_array_instance_first):
- DrawArrayInstanced(regs.vertex_array_instance_first.topology.Value(),
- regs.vertex_array_instance_first.start.Value(),
- regs.vertex_array_instance_first.count.Value(), false);
+ DrawArrayInstanced(maxwell3d, maxwell3d.regs.vertex_array_instance_first.topology.Value(), maxwell3d.regs.vertex_array_instance_first.start.Value(), maxwell3d.regs.vertex_array_instance_first.count.Value(), false);
break;
case MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent): {
- DrawArrayInstanced(regs.vertex_array_instance_subsequent.topology.Value(),
- regs.vertex_array_instance_subsequent.start.Value(),
- regs.vertex_array_instance_subsequent.count.Value(), true);
+ DrawArrayInstanced(maxwell3d, maxwell3d.regs.vertex_array_instance_subsequent.topology.Value(), maxwell3d.regs.vertex_array_instance_subsequent.start.Value(), maxwell3d.regs.vertex_array_instance_subsequent.count.Value(), true);
break;
}
case MAXWELL3D_REG_INDEX(draw_texture.src_y0): {
- DrawTexture();
+ DrawTexture(maxwell3d);
break;
}
default:
@@ -67,101 +64,87 @@ void DrawManager::ProcessMethodCall(u32 method, u32 argument) {
}
}
-void DrawManager::Clear(u32 layer_count) {
- if (maxwell3d->ShouldExecute()) {
- maxwell3d->rasterizer->Clear(layer_count);
+void Maxwell3D::DrawManager::Clear(Maxwell3D& maxwell3d, u32 layer_count) {
+ if (maxwell3d.ShouldExecute()) {
+ maxwell3d.rasterizer->Clear(layer_count);
}
}
-void DrawManager::DrawDeferred() {
+void Maxwell3D::DrawManager::DrawDeferred(Maxwell3D& maxwell3d) {
if (draw_state.draw_mode != DrawMode::Instance || draw_state.instance_count == 0) {
return;
}
- DrawEnd(draw_state.instance_count + 1, true);
+ DrawEnd(maxwell3d, draw_state.instance_count + 1, true);
draw_state.instance_count = 0;
}
-void DrawManager::DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count,
- u32 base_instance, u32 num_instances) {
+void Maxwell3D::DrawManager::DrawArray(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, u32 base_instance, u32 num_instances) {
draw_state.topology = topology;
draw_state.vertex_buffer.first = vertex_first;
draw_state.vertex_buffer.count = vertex_count;
draw_state.base_instance = base_instance;
- ProcessDraw(false, num_instances);
+ ProcessDraw(maxwell3d, false, num_instances);
}
-void DrawManager::DrawArrayInstanced(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count,
- bool subsequent) {
+void Maxwell3D::DrawManager::DrawArrayInstanced(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, bool subsequent) {
draw_state.topology = topology;
draw_state.vertex_buffer.first = vertex_first;
draw_state.vertex_buffer.count = vertex_count;
-
if (!subsequent) {
draw_state.instance_count = 1;
}
-
draw_state.base_instance = draw_state.instance_count - 1;
draw_state.draw_mode = DrawMode::Instance;
draw_state.instance_count++;
- ProcessDraw(false, 1);
+ ProcessDraw(maxwell3d, false, 1);
}
-void DrawManager::DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count,
- u32 base_index, u32 base_instance, u32 num_instances) {
- const auto& regs{maxwell3d->regs};
+void Maxwell3D::DrawManager::DrawIndex(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index, u32 base_instance, u32 num_instances) {
draw_state.topology = topology;
- draw_state.index_buffer = regs.index_buffer;
+ draw_state.index_buffer = maxwell3d.regs.index_buffer;
draw_state.index_buffer.first = index_first;
draw_state.index_buffer.count = index_count;
draw_state.base_index = base_index;
draw_state.base_instance = base_instance;
- ProcessDraw(true, num_instances);
+ ProcessDraw(maxwell3d, true, num_instances);
}
-void DrawManager::DrawArrayIndirect(PrimitiveTopology topology) {
+void Maxwell3D::DrawManager::DrawArrayIndirect(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology) {
draw_state.topology = topology;
-
- ProcessDrawIndirect();
+ ProcessDrawIndirect(maxwell3d);
}
-void DrawManager::DrawIndexedIndirect(PrimitiveTopology topology, u32 index_first,
- u32 index_count) {
- const auto& regs{maxwell3d->regs};
+void Maxwell3D::DrawManager::DrawIndexedIndirect(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 index_first, u32 index_count) {
draw_state.topology = topology;
- draw_state.index_buffer = regs.index_buffer;
+ draw_state.index_buffer = maxwell3d.regs.index_buffer;
draw_state.index_buffer.first = index_first;
draw_state.index_buffer.count = index_count;
-
- ProcessDrawIndirect();
+ ProcessDrawIndirect(maxwell3d);
}
-void DrawManager::SetInlineIndexBuffer(u32 index) {
- draw_state.inline_index_draw_indexes.push_back(static_cast<u8>(index & 0x000000ff));
- draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x0000ff00) >> 8));
- draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x00ff0000) >> 16));
- draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0xff000000) >> 24));
+void Maxwell3D::DrawManager::SetInlineIndexBuffer(Maxwell3D& maxwell3d, u32 index) {
+ draw_state.inline_index_draw_indexes.push_back(u8(index & 0x000000ff));
+ draw_state.inline_index_draw_indexes.push_back(u8((index & 0x0000ff00) >> 8));
+ draw_state.inline_index_draw_indexes.push_back(u8((index & 0x00ff0000) >> 16));
+ draw_state.inline_index_draw_indexes.push_back(u8((index & 0xff000000) >> 24));
draw_state.draw_mode = DrawMode::InlineIndex;
}
-void DrawManager::DrawBegin() {
- const auto& regs{maxwell3d->regs};
- auto reset_instance_count = regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First;
- auto increment_instance_count =
- regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent;
+void Maxwell3D::DrawManager::DrawBegin(Maxwell3D& maxwell3d) {
+ auto reset_instance_count = maxwell3d.regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First;
+ auto increment_instance_count = maxwell3d.regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent;
if (reset_instance_count) {
- DrawDeferred();
+ DrawDeferred(maxwell3d);
draw_state.instance_count = 0;
draw_state.draw_mode = DrawMode::General;
} else if (increment_instance_count) {
draw_state.instance_count++;
draw_state.draw_mode = DrawMode::Instance;
}
-
- draw_state.topology = regs.draw.topology;
+ draw_state.topology = maxwell3d.regs.draw.topology;
}
-void DrawManager::DrawEnd(u32 instance_count, bool force_draw) {
- const auto& regs{maxwell3d->regs};
+void Maxwell3D::DrawManager::DrawEnd(Maxwell3D& maxwell3d, u32 instance_count, bool force_draw) {
switch (draw_state.draw_mode) {
case DrawMode::Instance:
if (!force_draw) {
@@ -169,119 +152,100 @@ void DrawManager::DrawEnd(u32 instance_count, bool force_draw) {
}
[[fallthrough]];
case DrawMode::General:
- draw_state.base_instance = regs.global_base_instance_index;
- draw_state.base_index = regs.global_base_vertex_index;
+ draw_state.base_instance = maxwell3d.regs.global_base_instance_index;
+ draw_state.base_index = maxwell3d.regs.global_base_vertex_index;
if (draw_state.draw_indexed) {
- draw_state.index_buffer = regs.index_buffer;
- ProcessDraw(true, instance_count);
+ draw_state.index_buffer = maxwell3d.regs.index_buffer;
+ ProcessDraw(maxwell3d, true, instance_count);
} else {
- draw_state.vertex_buffer = regs.vertex_buffer;
- ProcessDraw(false, instance_count);
+ draw_state.vertex_buffer = maxwell3d.regs.vertex_buffer;
+ ProcessDraw(maxwell3d, false, instance_count);
}
draw_state.draw_indexed = false;
break;
case DrawMode::InlineIndex:
- draw_state.base_instance = regs.global_base_instance_index;
- draw_state.base_index = regs.global_base_vertex_index;
- draw_state.index_buffer = regs.index_buffer;
- draw_state.index_buffer.count =
- static_cast<u32>(draw_state.inline_index_draw_indexes.size() / 4);
+ draw_state.base_instance = maxwell3d.regs.global_base_instance_index;
+ draw_state.base_index = maxwell3d.regs.global_base_vertex_index;
+ draw_state.index_buffer = maxwell3d.regs.index_buffer;
+ draw_state.index_buffer.count = u32(draw_state.inline_index_draw_indexes.size() / 4);
draw_state.index_buffer.format = Maxwell3D::Regs::IndexFormat::UnsignedInt;
- maxwell3d->dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
- ProcessDraw(true, instance_count);
+ maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
+ ProcessDraw(maxwell3d, true, instance_count);
draw_state.inline_index_draw_indexes.clear();
break;
}
}
-void DrawManager::DrawIndexSmall(u32 argument) {
- const auto& regs{maxwell3d->regs};
- IndexBufferSmall index_small_params{argument};
- draw_state.base_instance = regs.global_base_instance_index;
- draw_state.base_index = regs.global_base_vertex_index;
- draw_state.index_buffer = regs.index_buffer;
+void Maxwell3D::DrawManager::DrawIndexSmall(Maxwell3D& maxwell3d, u32 argument) {
+ Maxwell3D::Regs::IndexBufferSmall index_small_params{argument};
+ draw_state.base_instance = maxwell3d.regs.global_base_instance_index;
+ draw_state.base_index = maxwell3d.regs.global_base_vertex_index;
+ draw_state.index_buffer = maxwell3d.regs.index_buffer;
draw_state.index_buffer.first = index_small_params.first;
draw_state.index_buffer.count = index_small_params.count;
draw_state.topology = index_small_params.topology;
- maxwell3d->dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
- ProcessDraw(true, 1);
+ maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
+ ProcessDraw(maxwell3d, true, 1);
}
-void DrawManager::DrawTexture() {
- const auto& regs{maxwell3d->regs};
- draw_texture_state.dst_x0 = static_cast<float>(regs.draw_texture.dst_x0) / 4096.f;
- draw_texture_state.dst_y0 = static_cast<float>(regs.draw_texture.dst_y0) / 4096.f;
- const auto dst_width = static_cast<float>(regs.draw_texture.dst_width) / 4096.f;
- const auto dst_height = static_cast<float>(regs.draw_texture.dst_height) / 4096.f;
- const bool lower_left{regs.window_origin.mode !=
- Maxwell3D::Regs::WindowOrigin::Mode::UpperLeft};
+void Maxwell3D::DrawManager::DrawTexture(Maxwell3D& maxwell3d) {
+ draw_texture_state.dst_x0 = f32(maxwell3d.regs.draw_texture.dst_x0) / 4096.f;
+ draw_texture_state.dst_y0 = f32(maxwell3d.regs.draw_texture.dst_y0) / 4096.f;
+ const auto dst_width = f32(maxwell3d.regs.draw_texture.dst_width) / 4096.f;
+ const auto dst_height = f32(maxwell3d.regs.draw_texture.dst_height) / 4096.f;
+ const bool lower_left{maxwell3d.regs.window_origin.mode != Maxwell3D::Regs::WindowOrigin::Mode::UpperLeft};
if (lower_left) {
- draw_texture_state.dst_y0 =
- static_cast<f32>(regs.surface_clip.height) - draw_texture_state.dst_y0;
+ draw_texture_state.dst_y0 = f32(maxwell3d.regs.surface_clip.height) - draw_texture_state.dst_y0;
}
draw_texture_state.dst_x1 = draw_texture_state.dst_x0 + dst_width;
draw_texture_state.dst_y1 = draw_texture_state.dst_y0 + dst_height;
- draw_texture_state.src_x0 = static_cast<float>(regs.draw_texture.src_x0) / 4096.f;
- draw_texture_state.src_y0 = static_cast<float>(regs.draw_texture.src_y0) / 4096.f;
- draw_texture_state.src_x1 =
- (static_cast<float>(regs.draw_texture.dx_du) / 4294967296.f) * dst_width +
- draw_texture_state.src_x0;
- draw_texture_state.src_y1 =
- (static_cast<float>(regs.draw_texture.dy_dv) / 4294967296.f) * dst_height +
- draw_texture_state.src_y0;
- draw_texture_state.src_sampler = regs.draw_texture.src_sampler;
- draw_texture_state.src_texture = regs.draw_texture.src_texture;
- maxwell3d->rasterizer->DrawTexture();
-}
-
-void DrawManager::UpdateTopology() {
- const auto& regs{maxwell3d->regs};
- switch (regs.primitive_topology_control) {
- case PrimitiveTopologyControl::UseInBeginMethods:
+ draw_texture_state.src_x0 = f32(maxwell3d.regs.draw_texture.src_x0) / 4096.f;
+ draw_texture_state.src_y0 = f32(maxwell3d.regs.draw_texture.src_y0) / 4096.f;
+ draw_texture_state.src_x1 = (f32(maxwell3d.regs.draw_texture.dx_du) / 4294967296.f) * dst_width + draw_texture_state.src_x0;
+ draw_texture_state.src_y1 = (f32(maxwell3d.regs.draw_texture.dy_dv) / 4294967296.f) * dst_height + draw_texture_state.src_y0;
+ draw_texture_state.src_sampler = maxwell3d.regs.draw_texture.src_sampler;
+ draw_texture_state.src_texture = maxwell3d.regs.draw_texture.src_texture;
+ maxwell3d.rasterizer->DrawTexture();
+}
+
+void Maxwell3D::DrawManager::UpdateTopology(Maxwell3D& maxwell3d) {
+ switch (maxwell3d.regs.primitive_topology_control) {
+ case Maxwell3D::Regs::PrimitiveTopologyControl::UseInBeginMethods:
break;
- case PrimitiveTopologyControl::UseSeparateState:
- switch (regs.topology_override) {
- case PrimitiveTopologyOverride::None:
+ case Maxwell3D::Regs::PrimitiveTopologyControl::UseSeparateState:
+ switch (maxwell3d.regs.topology_override) {
+ case Maxwell3D::Regs::PrimitiveTopologyOverride::None:
break;
- case PrimitiveTopologyOverride::Points:
- draw_state.topology = PrimitiveTopology::Points;
+ case Maxwell3D::Regs::PrimitiveTopologyOverride::Points:
+ draw_state.topology = Maxwell3D::Regs::PrimitiveTopology::Points;
break;
- case PrimitiveTopologyOverride::Lines:
- draw_state.topology = PrimitiveTopology::Lines;
+ case Maxwell3D::Regs::PrimitiveTopologyOverride::Lines:
+ draw_state.topology = Maxwell3D::Regs::PrimitiveTopology::Lines;
break;
- case PrimitiveTopologyOverride::LineStrip:
- draw_state.topology = PrimitiveTopology::LineStrip;
+ case Maxwell3D::Regs::PrimitiveTopologyOverride::LineStrip:
+ draw_state.topology = Maxwell3D::Regs::PrimitiveTopology::LineStrip;
break;
default:
- draw_state.topology = static_cast<PrimitiveTopology>(regs.topology_override);
+ draw_state.topology = Maxwell3D::Regs::PrimitiveTopology(maxwell3d.regs.topology_override);
break;
}
break;
}
}
-void DrawManager::ProcessDraw(bool draw_indexed, u32 instance_count) {
- LOG_TRACE(HW_GPU, "called, topology={}, count={}", draw_state.topology,
- draw_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count);
-
- UpdateTopology();
-
- if (maxwell3d->ShouldExecute()) {
- maxwell3d->rasterizer->Draw(draw_indexed, instance_count);
+void Maxwell3D::DrawManager::ProcessDraw(Maxwell3D& maxwell3d, bool draw_indexed, u32 instance_count) {
+ LOG_TRACE(HW_GPU, "called, topology={}, count={}", draw_state.topology, draw_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count);
+ UpdateTopology(maxwell3d);
+ if (maxwell3d.ShouldExecute()) {
+ maxwell3d.rasterizer->Draw(draw_indexed, instance_count);
}
}
-void DrawManager::ProcessDrawIndirect() {
- LOG_TRACE(
- HW_GPU,
- "called, topology={}, is_indexed={}, includes_count={}, buffer_size={}, max_draw_count={}",
- draw_state.topology, indirect_state.is_indexed, indirect_state.include_count,
- indirect_state.buffer_size, indirect_state.max_draw_counts);
-
- UpdateTopology();
-
- if (maxwell3d->ShouldExecute()) {
- maxwell3d->rasterizer->DrawIndirect();
+void Maxwell3D::DrawManager::ProcessDrawIndirect(Maxwell3D& maxwell3d) {
+ LOG_TRACE(HW_GPU, "called, topology={}, is_indexed={}, includes_count={}, buffer_size={}, max_draw_count={}", draw_state.topology, indirect_state.is_indexed, indirect_state.include_count, indirect_state.buffer_size, indirect_state.max_draw_counts);
+ UpdateTopology(maxwell3d);
+ if (maxwell3d.ShouldExecute()) {
+ maxwell3d.rasterizer->DrawIndirect();
}
}
} // namespace Tegra::Engines