diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-11-01 15:17:58 -0500 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-11-01 15:17:58 -0500 |
| commit | e5e28e1b794985e464e6bd4028a85f6a7eb97f2c (patch) | |
| tree | 86ea087f6e23198bd3c0a300467ee095378e834a /src/video_core/engines | |
| parent | 16192ca6e25ec406ac951e2bc48ff5f38a7b80e1 (diff) | |
| parent | 2ad0830d2f044bc536155ae666f4477ba6d1f65f (diff) | |
Merge remote-tracking branch 'origin/fix/deferred-instance-state' into test/linux-all-prs-plus
Diffstat (limited to 'src/video_core/engines')
| -rw-r--r-- | src/video_core/engines/draw_manager.cpp | 27 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 10 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 6 |
3 files changed, 43 insertions, 0 deletions
diff --git a/src/video_core/engines/draw_manager.cpp b/src/video_core/engines/draw_manager.cpp index 5891c25622..038e5a2e69 100644 --- a/src/video_core/engines/draw_manager.cpp +++ b/src/video_core/engines/draw_manager.cpp @@ -80,6 +80,33 @@ void Maxwell3D::DrawManager::DrawDeferred(Maxwell3D& maxwell3d) { draw_state.instance_count = 0; } +bool Maxwell3D::DrawManager::IsInstanceLoopMethod(u32 method) noexcept { + switch (method) { + case MAXWELL3D_REG_INDEX(draw.begin): + case MAXWELL3D_REG_INDEX(draw.end): + case MAXWELL3D_REG_INDEX(vertex_buffer.first): + case MAXWELL3D_REG_INDEX(vertex_buffer.count): + case MAXWELL3D_REG_INDEX(index_buffer.first): + case MAXWELL3D_REG_INDEX(index_buffer.count): + case MAXWELL3D_REG_INDEX(index_buffer32_first): + case MAXWELL3D_REG_INDEX(index_buffer16_first): + case MAXWELL3D_REG_INDEX(index_buffer8_first): + case MAXWELL3D_REG_INDEX(index_buffer32_subsequent): + case MAXWELL3D_REG_INDEX(index_buffer16_subsequent): + case MAXWELL3D_REG_INDEX(index_buffer8_subsequent): + case MAXWELL3D_REG_INDEX(draw_inline_index): + case MAXWELL3D_REG_INDEX(inline_index_2x16.count): + case MAXWELL3D_REG_INDEX(inline_index_2x16.even): + case MAXWELL3D_REG_INDEX(inline_index_4x8.count): + case MAXWELL3D_REG_INDEX(inline_index_4x8.index0): + case MAXWELL3D_REG_INDEX(vertex_array_instance_first): + case MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent): + return true; + default: + return false; + } +} + 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; diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 6adfcf89b8..b344514bc6 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -336,6 +336,12 @@ void Maxwell3D::ConsumeSinkImpl(Core::System& system) { } void Maxwell3D::ProcessDirtyRegisters(u32 method, u32 argument) { + // The instances after the first are drawn together once their loop ends, and they must see + // the state they were begun with: NVN's draw macros reset the base instance (and its copy in + // c[0][0x644]) right after the loop, before the macro returns. + if (draw_manager.HasDeferredDraw() && !DrawManager::IsInstanceLoopMethod(method)) [[unlikely]] { + draw_manager.DrawDeferred(*this); + } regs.reg_array[method] = argument; for (auto const& table : dirty.tables) dirty.flags[table[method]] = true; @@ -516,6 +522,10 @@ void Maxwell3D::CallMultiMethod(Core::System& system, u32 method, const u32* bas ProcessMacro(system, method, base_start, amount, amount == methods_pending); return; } + // As in ProcessDirtyRegisters: the paths below write without it. + if (draw_manager.HasDeferredDraw() && !DrawManager::IsInstanceLoopMethod(method)) [[unlikely]] { + draw_manager.DrawDeferred(*this); + } switch (method) { case MAXWELL3D_REG_INDEX(const_buffer.buffer): case MAXWELL3D_REG_INDEX(const_buffer.buffer) + 1: diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 3e946db1fe..246274c897 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -3096,6 +3096,12 @@ public: void ProcessMethodCall(Maxwell3D& maxwell3d, u32 method, u32 argument); void Clear(Maxwell3D& maxwell3d, u32 layer_count); void DrawDeferred(Maxwell3D& maxwell3d); + /// Instances after the first wait to be drawn together (DrawDeferred). + [[nodiscard]] bool HasDeferredDraw() const noexcept { + return draw_state.draw_mode == DrawMode::Instance && draw_state.instance_count != 0; + } + /// Methods an instance loop writes between its draws; any other write ends the loop. + [[nodiscard]] static bool IsInstanceLoopMethod(u32 method) noexcept; void DrawArray(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, u32 base_instance, u32 num_instances); void DrawArrayInstanced(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, bool subsequent); void DrawIndex(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index, u32 base_instance, u32 num_instances); |
