From 0d6a2158f058b384efcdb438908cc8cdd0ed6676 Mon Sep 17 00:00:00 2001 From: simply0001 Date: Sat, 27 Jun 2026 02:52:59 +0200 Subject: [PATCH] [maxwell_3d] append inline index draw streams in bulk (#4083) Inline index draws arrive as a batch but were processed one word at a time, so each index ran through the full per-method path and got appended a byte at a time. Handle the whole batch in one pass instead, updating state once and appending all the indices together. Replay shadow control still goes word by word since it has to reload each one. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4083 Reviewed-by: Lizzie Reviewed-by: MaranBr --- src/video_core/engines/draw_manager.cpp | 40 +++++++++++++++++++++++++ src/video_core/engines/maxwell_3d.cpp | 17 +++++++++++ src/video_core/engines/maxwell_3d.h | 3 ++ 3 files changed, 60 insertions(+) diff --git a/src/video_core/engines/draw_manager.cpp b/src/video_core/engines/draw_manager.cpp index 079c7bdc09..5891c25622 100644 --- a/src/video_core/engines/draw_manager.cpp +++ b/src/video_core/engines/draw_manager.cpp @@ -4,6 +4,8 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include + #include "common/settings.h" #include "video_core/dirty_flags.h" #include "video_core/engines/maxwell_3d.h" @@ -130,6 +132,44 @@ void Maxwell3D::DrawManager::SetInlineIndexBuffer(Maxwell3D& maxwell3d, u32 inde draw_state.draw_mode = DrawMode::InlineIndex; } +void Maxwell3D::DrawManager::SetInlineIndexBuffer(Maxwell3D& maxwell3d, u32 method, + const u32* base_start, u32 amount) { + auto& index_buffer = draw_state.inline_index_draw_indexes; + switch (method) { + case MAXWELL3D_REG_INDEX(draw_inline_index): { + const auto* const bytes = reinterpret_cast(base_start); + index_buffer.insert(index_buffer.end(), bytes, bytes + size_t(amount) * sizeof(u32)); + break; + } + case MAXWELL3D_REG_INDEX(inline_index_2x16.even): { + const size_t offset = index_buffer.size(); + index_buffer.resize(offset + size_t(amount) * 2 * sizeof(u32)); + u8* dst = index_buffer.data() + offset; + for (u32 i = 0; i < amount; ++i) { + const u32 word = base_start[i]; + const u32 indexes[2]{word & 0xFFFF, word >> 16}; + std::memcpy(dst, indexes, sizeof(indexes)); + dst += sizeof(indexes); + } + break; + } + case MAXWELL3D_REG_INDEX(inline_index_4x8.index0): { + const size_t offset = index_buffer.size(); + index_buffer.resize(offset + size_t(amount) * 4 * sizeof(u32)); + u8* dst = index_buffer.data() + offset; + for (u32 i = 0; i < amount; ++i) { + const u32 word = base_start[i]; + const u32 indexes[4]{word & 0xFF, (word >> 8) & 0xFF, (word >> 16) & 0xFF, + word >> 24}; + std::memcpy(dst, indexes, sizeof(indexes)); + dst += sizeof(indexes); + } + break; + } + } + draw_state.draw_mode = DrawMode::InlineIndex; +} + 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; diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 53b75726bd..e7da9d9138 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -436,6 +436,14 @@ void Maxwell3D::CallMultiMethod(Core::System& system, u32 method, const u32* bas upload_state.ProcessData(base_start, amount); return; } + case MAXWELL3D_REG_INDEX(draw_inline_index): + case MAXWELL3D_REG_INDEX(inline_index_2x16.even): + case MAXWELL3D_REG_INDEX(inline_index_4x8.index0): + if (shadow_state.shadow_ram_control != Regs::ShadowRamControl::Replay) { + ProcessInlineIndexMultiData(method, base_start, amount); + break; + } + [[fallthrough]]; default: for (u32 i = 0; i < amount; i++) { CallMethod(system, method, base_start[i], methods_pending - i <= 1); @@ -622,6 +630,15 @@ void Maxwell3D::ProcessCBData(u32 value) { ProcessCBMultiData(&value, 1); } +void Maxwell3D::ProcessInlineIndexMultiData(u32 method, const u32* start_base, u32 amount) { + if (amount == 0) { + return; + } + const u32 argument = ProcessShadowRam(method, start_base[amount - 1]); + ProcessDirtyRegisters(method, argument); + draw_manager.SetInlineIndexBuffer(*this, method, start_base, amount); +} + Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const { const GPUVAddr tic_address_gpu{regs.tex_header.Address() + tic_index * sizeof(Texture::TICEntry)}; diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index bbde8b9986..dd16438d55 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -3077,6 +3077,7 @@ public: void DrawArrayIndirect(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology); void DrawIndexedIndirect(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 index_first, u32 index_count); void SetInlineIndexBuffer(Maxwell3D& maxwell3d, u32 index); + void SetInlineIndexBuffer(Maxwell3D& maxwell3d, u32 method, const u32* base_start, u32 amount); void DrawBegin(Maxwell3D& maxwell3d); void DrawEnd(Maxwell3D& maxwell3d, u32 instance_count = 1, bool force_draw = false); void DrawIndexSmall(Maxwell3D& maxwell3d, u32 argument); @@ -3193,6 +3194,8 @@ public: void ProcessCBData(u32 value); void ProcessCBMultiData(const u32* start_base, u32 amount); + void ProcessInlineIndexMultiData(u32 method, const u32* start_base, u32 amount); + private: void InitializeRegisterDefaults();