From c36b8e843e71b9e34c1ef3442b38dfb90ffc7585 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sat, 4 Feb 2023 20:53:21 +0000 Subject: [PATCH] Add index buffer size estimation via mapping size This is useful for indirect draws, where we don't know the underlying index buffer size and also don't know the index count. --- .../interconnect/maxwell_3d/active_state.cpp | 32 ++++++++++--------- .../interconnect/maxwell_3d/active_state.h | 8 +++-- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/active_state.cpp b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/active_state.cpp index 63e496c9..f08c3997 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/active_state.cpp +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/active_state.cpp @@ -3,6 +3,7 @@ // Copyright © 2022 yuzu Team and Contributors (https://github.com/yuzu-emu/) // Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) +#include #include #include #include @@ -116,18 +117,25 @@ namespace skyline::gpu::interconnect::maxwell3d { /* Index Buffer */ void IndexBufferState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const { - manager.Bind(handle, indexBuffer.indexSize, indexBuffer.address); + manager.Bind(handle, indexBuffer.indexSize, indexBuffer.address, indexBuffer.limit); } IndexBufferState::IndexBufferState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine) : engine{manager, dirtyHandle, engine} {} - void IndexBufferState::Flush(InterconnectContext &ctx, StateUpdateBuilder &builder, vk::PipelineStageFlags &srcStageMask, vk::PipelineStageFlags &dstStageMask, bool quadConversion, u32 firstIndex, u32 elementCount) { + void IndexBufferState::Flush(InterconnectContext &ctx, StateUpdateBuilder &builder, vk::PipelineStageFlags &srcStageMask, vk::PipelineStageFlags &dstStageMask, bool quadConversion, bool estimateSize, u32 firstIndex, u32 elementCount) { + didEstimateSize = estimateSize; usedElementCount = elementCount; usedFirstIndex = firstIndex; usedQuadConversion = quadConversion; - size_t size{GetIndexBufferSize(engine->indexBuffer.indexSize, firstIndex + elementCount)}; - view.Update(ctx, engine->indexBuffer.address, size); + size_t size{[&] () { + if (estimateSize) + return engine->indexBuffer.address - engine->indexBuffer.limit + 1; + else + return GetIndexBufferSize(engine->indexBuffer.indexSize, firstIndex + elementCount); + }()}; + + view.Update(ctx, engine->indexBuffer.address, size, !estimateSize); if (!*view) { Logger::Warn("Unmapped index buffer: 0x{:X}", engine->indexBuffer.address); return; @@ -149,17 +157,11 @@ namespace skyline::gpu::interconnect::maxwell3d { builder.SetIndexBuffer(*view, indexType); } - bool IndexBufferState::Refresh(InterconnectContext &ctx, StateUpdateBuilder &builder, vk::PipelineStageFlags &srcStageMask, vk::PipelineStageFlags &dstStageMask, bool quadConversion, u32 firstIndex, u32 elementCount) { + bool IndexBufferState::Refresh(InterconnectContext &ctx, StateUpdateBuilder &builder, vk::PipelineStageFlags &srcStageMask, vk::PipelineStageFlags &dstStageMask, bool quadConversion, bool estimateSize, u32 firstIndex, u32 elementCount) { if (*view) view->GetBuffer()->PopulateReadBarrier(vk::PipelineStageFlagBits::eVertexInput, srcStageMask, dstStageMask); - if (elementCount > usedElementCount) - return true; - - if (quadConversion != usedQuadConversion) - return true; - - if (quadConversion != usedQuadConversion) + if (didEstimateSize != estimateSize || (elementCount + firstIndex > usedElementCount + usedFirstIndex) || quadConversion != usedQuadConversion) return true; // TODO: optimise this to use buffer sequencing to avoid needing to regenerate the quad buffer every time. We can't use as it is rn though because sequences aren't globally unique and may conflict after buffer recreation @@ -431,7 +433,7 @@ namespace skyline::gpu::interconnect::maxwell3d { } void ActiveState::Update(InterconnectContext &ctx, Textures &textures, ConstantBufferSet &constantBuffers, StateUpdateBuilder &builder, - bool indexed, engine::DrawTopology topology, u32 drawFirstIndex, u32 drawElementCount, + bool indexed, engine::DrawTopology topology, bool estimateIndexBufferSize, u32 drawFirstIndex, u32 drawElementCount, vk::PipelineStageFlags &srcStageMask, vk::PipelineStageFlags &dstStageMask) { if (topology != directState.inputAssembly.GetPrimitiveTopology()) { directState.inputAssembly.SetPrimitiveTopology(topology); @@ -444,7 +446,7 @@ namespace skyline::gpu::interconnect::maxwell3d { pipeline.Update(ctx, textures, constantBuffers, builder); ranges::for_each(vertexBuffers, updateFuncBuffer); if (indexed) - updateFuncBuffer(indexBuffer, directState.inputAssembly.NeedsQuadConversion(), drawFirstIndex, drawElementCount); + updateFuncBuffer(indexBuffer, directState.inputAssembly.NeedsQuadConversion(), estimateIndexBufferSize, drawFirstIndex, drawElementCount); ranges::for_each(transformFeedbackBuffers, updateFuncBuffer); ranges::for_each(viewports, updateFunc); ranges::for_each(scissors, updateFunc); @@ -474,4 +476,4 @@ namespace skyline::gpu::interconnect::maxwell3d { std::shared_ptr ActiveState::GetDepthRenderTargetForClear(InterconnectContext &ctx) { return pipeline.Get().GetDepthRenderTargetForClear(ctx); } -} \ No newline at end of file +} diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/active_state.h b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/active_state.h index 70c5aff0..855d73e4 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/active_state.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/active_state.h @@ -47,6 +47,7 @@ namespace skyline::gpu::interconnect::maxwell3d { CachedMappedBufferView view{}; BufferBinding megaBufferBinding{}; vk::IndexType indexType{}; + bool didEstimateSize{}; u32 usedElementCount{}; u32 usedFirstIndex{}; bool usedQuadConversion{}; @@ -54,9 +55,9 @@ namespace skyline::gpu::interconnect::maxwell3d { public: IndexBufferState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine); - void Flush(InterconnectContext &ctx, StateUpdateBuilder &builder, vk::PipelineStageFlags &srcStageMask, vk::PipelineStageFlags &dstStageMask, bool quadConversion, u32 firstIndex, u32 elementCount); + void Flush(InterconnectContext &ctx, StateUpdateBuilder &builder, vk::PipelineStageFlags &srcStageMask, vk::PipelineStageFlags &dstStageMask, bool quadConversion, bool estimateSize, u32 firstIndex, u32 elementCount); - bool Refresh(InterconnectContext &ctx, StateUpdateBuilder &builder, vk::PipelineStageFlags &srcStageMask, vk::PipelineStageFlags &dstStageMask, bool quadConversion, u32 firstIndex, u32 elementCount); + bool Refresh(InterconnectContext &ctx, StateUpdateBuilder &builder, vk::PipelineStageFlags &srcStageMask, vk::PipelineStageFlags &dstStageMask, bool quadConversion, bool estimateSize, u32 firstIndex, u32 elementCount); void PurgeCaches(); }; @@ -259,9 +260,10 @@ namespace skyline::gpu::interconnect::maxwell3d { /** * @brief Updates the active state for a given draw operation, removing the dirtiness of all member states + * @note If `extimateIndexBufferSize` is false and `indexed` is true the `drawFirstIndex` and `drawElementCount` arguments must be populated */ void Update(InterconnectContext &ctx, Textures &textures, ConstantBufferSet &constantBuffers, StateUpdateBuilder &builder, - bool indexed, engine::DrawTopology topology, u32 drawFirstIndex, u32 drawElementCount, + bool indexed, engine::DrawTopology topology, bool estimateIndexBufferSize, u32 drawFirstIndex, u32 drawElementCount, vk::PipelineStageFlags &srcStageMask, vk::PipelineStageFlags &dstStageMask); Pipeline *GetPipeline();