mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
Magma: wire-store rename spares 4 -> 12 with one fence question per rename, and a 50 us quiet window on unsignaled fence polls (FCL monolith GL CPU 2.44 -> 2.38 ms, 272 -> 278 fps at cpuhunt).
This commit is contained in:
@@ -308,12 +308,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return false;
|
||||
VkBufferObject old = std::move(resource.buffer);
|
||||
Bool reused = false;
|
||||
for (SizeT i = 0; pVulkanRenderer != nullptr && i < resource.renameSpares.size(); ++i) {
|
||||
if (!pVulkanRenderer->IsSubmitIndexComplete(resource.renameSpares[i].submitIndex)) continue;
|
||||
resource.buffer = std::move(resource.renameSpares[i].buffer);
|
||||
resource.renameSpares.erase(resource.renameSpares.begin() + static_cast<std::ptrdiff_t>(i));
|
||||
// Spares are queued in rename order, so their sync points only grow: when the oldest is not
|
||||
// complete, no later one is (one fence question instead of one per spare).
|
||||
if (pVulkanRenderer != nullptr && !resource.renameSpares.empty() &&
|
||||
pVulkanRenderer->IsSubmitIndexComplete(resource.renameSpares.front().submitIndex)) {
|
||||
resource.buffer = std::move(resource.renameSpares.front().buffer);
|
||||
resource.renameSpares.erase(resource.renameSpares.begin());
|
||||
reused = true;
|
||||
break;
|
||||
}
|
||||
if (!reused) {
|
||||
if (!CreateWireStoreBuffer(resource)) {
|
||||
@@ -332,7 +333,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// Busy means a GPU command recorded so far may name the old buffer: it waits behind this
|
||||
// frame's serial and the current sync point, whatever its own stamps said - as a spare
|
||||
// for the next rename, or (past the bound) through DeferWireRelease.
|
||||
constexpr SizeT kRenameSpares = 4;
|
||||
// P15: 4 spares recycled too few for frames in flight x renames per frame (FCL MC 1.21.5:
|
||||
// VkBufferObject::Create 0.031 + the retired stores' Destroy 0.014 ms/frame). Only shadowed
|
||||
// stores rename, and those are at most kWireShadowMaxStore (64 KiB), so 12 spares bound a
|
||||
// resource's extra memory at 768 KiB.
|
||||
constexpr SizeT kRenameSpares = 12;
|
||||
if (resource.renameSpares.size() >= kRenameSpares) {
|
||||
auto& oldest = resource.renameSpares.front();
|
||||
DeferWireRelease(std::move(oldest.buffer), oldest.lastUseSerial);
|
||||
|
||||
@@ -5837,8 +5837,24 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
if (submitIndex > m_submitCounter) {
|
||||
return false; // not even submitted; no point polling fences
|
||||
}
|
||||
// P15: a fence just seen unsignaled is not polled again for a short while. Callers ask per
|
||||
// buffer write (FCL MC 1.21.5: vkGetFenceStatus was 0.020 ms/frame), and every one of them
|
||||
// treats "not yet" as "still busy" - rename, defer, report unsignaled - so a late "yes" costs
|
||||
// at most kUnsignaledPollQuietNs of extra caution, never correctness.
|
||||
constexpr Uint64 kUnsignaledPollQuietNs = 50000;
|
||||
const Uint64 now = static_cast<Uint64>(std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch()).count());
|
||||
if (!m_inFlightSubmits.empty() && m_unsignaledPollFront == m_inFlightSubmits.front().submitIndex &&
|
||||
now - m_unsignaledPollNs < kUnsignaledPollQuietNs) {
|
||||
return false;
|
||||
}
|
||||
RefreshCompletedSubmits();
|
||||
return submitIndex <= m_completedSubmitCounter;
|
||||
if (submitIndex <= m_completedSubmitCounter) return true;
|
||||
if (!m_inFlightSubmits.empty()) {
|
||||
m_unsignaledPollFront = m_inFlightSubmits.front().submitIndex;
|
||||
m_unsignaledPollNs = now;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void VulkanRenderer::RegisterSubmit(VkFence fence, Bool pooledFence) {
|
||||
|
||||
@@ -1018,6 +1018,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Vector<VkFence> m_freeSubmitFences;
|
||||
Uint64 m_submitCounter = 0;
|
||||
Uint64 m_completedSubmitCounter = 0;
|
||||
// IsSubmitIndexComplete's quiet window: the in-flight front last seen unsignaled, and when.
|
||||
Uint64 m_unsignaledPollFront = 0;
|
||||
Uint64 m_unsignaledPollNs = 0;
|
||||
// Drains since the last Present, gating the drain's frame-boundary-equivalent
|
||||
// work (arena rewind + cache aging): a presenting app's mid-frame
|
||||
// readbacks/waits must neither churn the transient caches nor accelerate the
|
||||
|
||||
Reference in New Issue
Block a user