mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 06:00:25 +02:00
Merge kart draws again while the native steering wheel is animated
The animated copy is registered for the vehicle's whole position array, and a race frame has 228 primitives that bind it. Suppressing draw merging for all of them turned the kart's display list back into hundreds of separate draw calls, each recorded once and replayed in the mono pass and both eyes: on a Quest 3 the app frame went from 15.7 ms to 21.7 ms with the GPU pinned at 97 %, which past the 72 Hz deadline reads as 56 FPS against 42. Merging is unsafe only between draws that resolved the array differently, since the merged whole renders through the binding of the draw it folds into. So resolve the replacement once per draw, before the merge test, and merge into a draw that reached the same decision. Draws of an opponent sharing the asset merge with each other again too, and with no set registered the test is exactly what it was before the feature. Measured at the same place on a Quest 3: 60 FPS against 42, the app frame back to 13.9 ms, 564 draw calls a frame with 11808 primitives merged away. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3d240c890e
commit
fd42edf303
4 files changed
+143
-30
No files matched your search
@@ -4,7 +4,9 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "gx_test_common.hpp"
|
||||
#include "gx/native_wheel.hpp"
|
||||
|
||||
namespace {
|
||||
@@ -133,4 +135,73 @@ TEST_F(NativeWheelArrayTest, NonFiniteMatrixNeverMatches) {
|
||||
EXPECT_EQ(aurora::gx::native_wheel_array(array, nullptr, 0, 0, 0), nullptr);
|
||||
}
|
||||
|
||||
// Draw merging around an animated array. A merged draw appends its vertices to the previous draw's range and renders
|
||||
// through that draw's array binding, so two draws may merge only when they resolved the same replacement. The kart's
|
||||
// display list is hundreds of same-state primitives, and merging them is worth several ms an eye on a tiler.
|
||||
class NativeWheelMergeTest : public GXFifoTest {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
GXFifoTest::SetUp();
|
||||
aurora::gfx::testing::use_draw_command_tracking(true);
|
||||
aurora::gx::nativeWheelArrays.clear();
|
||||
aurora::gx::nativeWheelLastDecision = nullptr;
|
||||
aurora::gx::nativeWheelLastDrawCommand = nullptr;
|
||||
aurora::gx::NativeWheelArray replacement;
|
||||
replacement.source = source.data();
|
||||
replacement.bytes.assign(source.size(), 0);
|
||||
replacement.bytes[12] = 1; // one animated position
|
||||
aurora::gx::nativeWheelArrays.push_back(replacement);
|
||||
auto& state = aurora::gx::g_gxState;
|
||||
state.lastVtxFmt = GX_VTXFMT0;
|
||||
state.lastVtxSize = 1;
|
||||
state.vtxDesc[GX_VA_POS] = GX_INDEX8;
|
||||
state.arrays[GX_VA_POS].data = source.data();
|
||||
state.arrays[GX_VA_POS].size = static_cast<u32>(source.size());
|
||||
state.arrays[GX_VA_POS].stride = 12;
|
||||
state.stateDirty = true;
|
||||
}
|
||||
void TearDown() override {
|
||||
aurora::gx::nativeWheelArrays.clear();
|
||||
aurora::gx::nativeWheelLastDecision = nullptr;
|
||||
aurora::gx::nativeWheelLastDrawCommand = nullptr;
|
||||
}
|
||||
void draw() {
|
||||
std::vector<u8> fifo{static_cast<u8>(GX_TRIANGLES) | static_cast<u8>(GX_VTXFMT0), 0, 3, 0, 1, 2};
|
||||
decode_fifo(fifo);
|
||||
}
|
||||
// The local vehicle's matrix: the replacement's model-view is all zeroes, and so is a default palette slot.
|
||||
void makeOpponent() { reinterpret_cast<float*>(&aurora::gx::g_gxState.pnMtx[0].pos)[3] = 100.f; }
|
||||
std::array<uint8_t, 36> source{};
|
||||
};
|
||||
|
||||
TEST_F(NativeWheelMergeTest, PrimitivesSharingTheAnimatedArrayStillMerge) {
|
||||
draw();
|
||||
ASSERT_EQ(aurora::gx::nativeWheelLastDecision, &aurora::gx::nativeWheelArrays.front());
|
||||
draw();
|
||||
EXPECT_EQ(aurora::gfx::g_mergedDrawCallCount, 1u);
|
||||
}
|
||||
|
||||
TEST_F(NativeWheelMergeTest, PrimitivesThatTakeTheOriginalArrayAlsoStillMerge) {
|
||||
makeOpponent();
|
||||
draw();
|
||||
ASSERT_EQ(aurora::gx::nativeWheelLastDecision, nullptr);
|
||||
draw();
|
||||
EXPECT_EQ(aurora::gfx::g_mergedDrawCallCount, 1u);
|
||||
}
|
||||
|
||||
TEST_F(NativeWheelMergeTest, OpponentPrimitiveNeverFoldsIntoAnAnimatedDraw) {
|
||||
draw();
|
||||
makeOpponent();
|
||||
draw();
|
||||
EXPECT_EQ(aurora::gfx::g_mergedDrawCallCount, 0u) << "the merged whole would render the opponent animated";
|
||||
}
|
||||
|
||||
TEST_F(NativeWheelMergeTest, AnimatedPrimitiveNeverFoldsIntoAnOpponentDraw) {
|
||||
makeOpponent();
|
||||
draw();
|
||||
reinterpret_cast<float*>(&aurora::gx::g_gxState.pnMtx[0].pos)[3] = 0.f;
|
||||
draw();
|
||||
EXPECT_EQ(aurora::gfx::g_mergedDrawCallCount, 0u) << "the wheel would render on the original vertices";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
Reference in new issue
Block a user