From 04f3fa4b7fe8ceafc933b591924c7cdf89be43ba Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sat, 4 Feb 2023 22:59:42 +0000 Subject: [PATCH] Implement basic indirect draw macro HLE This still requires usagetracker to avoid redundantly performing indirect draws when the memory isn't dirty, and to allow for using it with direct memory, but it's a start. --- .../skyline/soc/gm20b/engines/maxwell_3d.cpp | 6 ++++ .../skyline/soc/gm20b/engines/maxwell_3d.h | 2 ++ .../skyline/soc/gm20b/macro/macro_state.cpp | 33 +++++++++++++------ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp index fb492b0c..fdc3eb9f 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp @@ -499,4 +499,10 @@ namespace skyline::soc::gm20b::engine::maxwell3d { interconnect.Draw(topology, *registers.streamOutputEnable, true, indexBufferCount, indexBufferFirst, instanceCount, globalBaseVertexIndex, globalBaseInstanceIndex); } + + void Maxwell3D::DrawIndexedIndirect(u32 drawTopology, span indirectBuffer, u32 count, u32 stride) { + auto topology{static_cast(drawTopology)}; + interconnect.DrawIndirect(topology, *registers.streamOutputEnable, true, indirectBuffer, count, stride); + } + } diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h index 0814c2fe..655eb254 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h @@ -456,5 +456,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { void DrawInstanced(bool setRegs, u32 drawTopology, u32 vertexArrayCount, u32 instanceCount, u32 vertexArrayStart, u32 globalBaseInstanceIndex) override; void DrawIndexedInstanced(bool setRegs, u32 drawTopology, u32 indexBufferCount, u32 instanceCount, u32 globalBaseVertexIndex, u32 indexBufferFirst, u32 globalBaseInstanceIndex) override; + + void DrawIndexedIndirect(u32 drawTopology, span indirectBuffer, u32 count, u32 stride) override; }; } diff --git a/app/src/main/cpp/skyline/soc/gm20b/macro/macro_state.cpp b/app/src/main/cpp/skyline/soc/gm20b/macro/macro_state.cpp index dafaa4e6..caea1775 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/macro/macro_state.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/macro/macro_state.cpp @@ -2,10 +2,22 @@ // Copyright © 2022 yuzu Emulator Project (https://yuzu-emu.org/) // Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) +#include #include #include "macro_state.h" namespace skyline::soc::gm20b { + static bool TopologyRequiresConversion(engine::maxwell3d::type::DrawTopology topology) { + switch (topology) { + case engine::maxwell3d::type::DrawTopology::Quads: + case engine::maxwell3d::type::DrawTopology::QuadStrip: + case engine::maxwell3d::type::DrawTopology::Polygon: + return true; + default: + return false; + } + } + namespace macro_hle { bool DrawInstanced(size_t offset, span args, engine::MacroEngineBase *targetEngine) { u32 instanceCount{targetEngine->ReadMethodFromMacro(0xD1B) & *args[2]}; @@ -21,16 +33,17 @@ namespace skyline::soc::gm20b { return true; } - void DrawInstancedIndexedWithConstantBuffer(size_t offset, span args, engine::MacroEngineBase *targetEngine) { - // Writes globalBaseVertexIndex and globalBaseInstanceIndex to the bound constant buffer before performing a standard instanced indexed draw - u32 instanceCount{targetEngine->ReadMethodFromMacro(0xD1B) & args[2]}; - targetEngine->CallMethodFromMacro(0x8e3, 0x640); - targetEngine->CallMethodFromMacro(0x8e4, args[4]); - targetEngine->CallMethodFromMacro(0x8e5, args[5]); - targetEngine->DrawIndexedInstanced(false, args[0], args[1], instanceCount, args[4], args[3], args[5]); - targetEngine->CallMethodFromMacro(0x8e3, 0x640); - targetEngine->CallMethodFromMacro(0x8e4, 0x0); - targetEngine->CallMethodFromMacro(0x8e5, 0x0); + bool DrawInstancedIndexedIndirectWithConstantBuffer(size_t offset, span args, engine::MacroEngineBase *targetEngine) { + u32 topology{*args[0]}; + if (TopologyRequiresConversion(static_cast(topology)) || !args[1].argumentPtr) { + // If the passed parameters aren't dirty or the indirect topology isn't supported fallback to a non indirect draw (may wait) + u32 instanceCount{targetEngine->ReadMethodFromMacro(0xD1B) & *args[2]}; + targetEngine->DrawIndexedInstanced(false, topology, *args[1], instanceCount, *args[4], *args[3], *args[5]); + } else { + targetEngine->DrawIndexedIndirect(topology, span(args[1].argumentPtr, 5).cast(), 1, 0); + } + + return true; } struct HleFunctionInfo {