mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Perf] (DirectVulkan): skip pending-clear probes through a lock-free empty check
This commit is contained in:
@@ -93,6 +93,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
const std::lock_guard<std::mutex> lock(m_mutex);
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
m_pendingClears.clear();
|
m_pendingClears.clear();
|
||||||
m_aliveObjects.clear();
|
m_aliveObjects.clear();
|
||||||
|
m_pendingCount.store(static_cast<Uint32>(m_pendingClears.size()), std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureIdentity VkClearManager::MakeTextureIdentity(MG_State::GLState::ITextureObject* texture) {
|
TextureIdentity VkClearManager::MakeTextureIdentity(MG_State::GLState::ITextureObject* texture) {
|
||||||
@@ -127,6 +128,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
m_pendingClears.erase(key);
|
m_pendingClears.erase(key);
|
||||||
}
|
}
|
||||||
m_aliveObjects.erase(identity);
|
m_aliveObjects.erase(identity);
|
||||||
|
m_pendingCount.store(static_cast<Uint32>(m_pendingClears.size()), std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VkClearManager::LockTextureIdentityLocked(const TextureIdentity& identity,
|
Bool VkClearManager::LockTextureIdentityLocked(const TextureIdentity& identity,
|
||||||
@@ -221,6 +223,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
m_aliveObjects[MakeTextureIdentity(texture.get())] = texture;
|
m_aliveObjects[MakeTextureIdentity(texture.get())] = texture;
|
||||||
auto& pending = m_pendingClears[key];
|
auto& pending = m_pendingClears[key];
|
||||||
MergeClearPayload(pending, clearPayload);
|
MergeClearPayload(pending, clearPayload);
|
||||||
|
m_pendingCount.store(static_cast<Uint32>(m_pendingClears.size()), std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
|
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
|
||||||
@@ -238,6 +241,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
m_aliveObjects[MakeTextureIdentity(texture.get())] = texture;
|
m_aliveObjects[MakeTextureIdentity(texture.get())] = texture;
|
||||||
auto& pending = m_pendingClears[key];
|
auto& pending = m_pendingClears[key];
|
||||||
MergeClearPayload(pending, clearPayload);
|
MergeClearPayload(pending, clearPayload);
|
||||||
|
m_pendingCount.store(static_cast<Uint32>(m_pendingClears.size()), std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VkClearManager::HasPendingClear(MG_State::GLState::ITextureObject* texture) {
|
Bool VkClearManager::HasPendingClear(MG_State::GLState::ITextureObject* texture) {
|
||||||
@@ -245,6 +249,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_pendingCount.load(std::memory_order_relaxed) == 0) {
|
||||||
|
return false; // per-draw hot path: nothing pending anywhere
|
||||||
|
}
|
||||||
|
|
||||||
const Uint64 lifetimeId = texture->GetLifetimeId();
|
const Uint64 lifetimeId = texture->GetLifetimeId();
|
||||||
const std::lock_guard<std::mutex> lock(m_mutex);
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
for (auto it = m_pendingClears.begin(); it != m_pendingClears.end(); ++it) {
|
for (auto it = m_pendingClears.begin(); it != m_pendingClears.end(); ++it) {
|
||||||
@@ -260,6 +268,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (key.texture == nullptr) {
|
if (key.texture == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (m_pendingCount.load(std::memory_order_relaxed) == 0) {
|
||||||
|
return false; // per-draw hot path: nothing pending anywhere
|
||||||
|
}
|
||||||
|
|
||||||
const std::lock_guard<std::mutex> lock(m_mutex);
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
if (m_pendingClears.find(key) == m_pendingClears.end()) {
|
if (m_pendingClears.find(key) == m_pendingClears.end()) {
|
||||||
@@ -287,6 +298,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (key.texture == nullptr) {
|
if (key.texture == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (m_pendingCount.load(std::memory_order_relaxed) == 0) {
|
||||||
|
return false; // per-draw hot path: nothing pending anywhere
|
||||||
|
}
|
||||||
|
|
||||||
const std::lock_guard<std::mutex> lock(m_mutex);
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
if (!LockTextureLocked(key, outTexture)) {
|
if (!LockTextureLocked(key, outTexture)) {
|
||||||
@@ -325,6 +339,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (texture == nullptr) {
|
if (texture == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (m_pendingCount.load(std::memory_order_relaxed) == 0) {
|
||||||
|
return false; // per-draw hot path: nothing pending anywhere
|
||||||
|
}
|
||||||
|
|
||||||
const Uint64 lifetimeId = texture->GetLifetimeId();
|
const Uint64 lifetimeId = texture->GetLifetimeId();
|
||||||
const std::lock_guard<std::mutex> lock(m_mutex);
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
@@ -345,6 +362,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_pendingCount.load(std::memory_order_relaxed) == 0) {
|
||||||
|
return; // per-draw hot path: nothing pending anywhere
|
||||||
|
}
|
||||||
const TextureIdentity identity = MakeTextureIdentity(texture);
|
const TextureIdentity identity = MakeTextureIdentity(texture);
|
||||||
MGLOG_D("%s: Pop all pending clears for texture %d", __func__, texture->GetExternalIndex());
|
MGLOG_D("%s: Pop all pending clears for texture %d", __func__, texture->GetExternalIndex());
|
||||||
const std::lock_guard<std::mutex> lock(m_mutex);
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
@@ -361,6 +381,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
auto it = m_pendingClears.find(key);
|
auto it = m_pendingClears.find(key);
|
||||||
if (it != m_pendingClears.end()) {
|
if (it != m_pendingClears.end()) {
|
||||||
m_pendingClears.erase(it);
|
m_pendingClears.erase(it);
|
||||||
|
m_pendingCount.store(static_cast<Uint32>(m_pendingClears.size()), std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "MG_Util/Math/VectorTypes.h"
|
#include "MG_Util/Math/VectorTypes.h"
|
||||||
|
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
#include <atomic>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
@@ -121,6 +122,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
Uint8 m_gcCounter = 0;
|
Uint8 m_gcCounter = 0;
|
||||||
mutable std::mutex m_mutex;
|
mutable std::mutex m_mutex;
|
||||||
|
// Lock-free mirror of m_pendingClears.size(), maintained under m_mutex
|
||||||
|
// by every mutation. The per-draw probes (HasPendingClear/GetPending*)
|
||||||
|
// read it before taking the lock: during draw batches the pending set
|
||||||
|
// is almost always empty, so this turns several locked map probes per
|
||||||
|
// draw into one relaxed load.
|
||||||
|
std::atomic<Uint32> m_pendingCount{0};
|
||||||
std::unordered_map<PendingClearKey, ClearAttachmentPayload, PendingClearKeyHash> m_pendingClears;
|
std::unordered_map<PendingClearKey, ClearAttachmentPayload, PendingClearKeyHash> m_pendingClears;
|
||||||
std::unordered_map<TextureIdentity, WeakPtr<MG_State::GLState::ITextureObject>, TextureIdentityHash> m_aliveObjects;
|
std::unordered_map<TextureIdentity, WeakPtr<MG_State::GLState::ITextureObject>, TextureIdentityHash> m_aliveObjects;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user