mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Fix] (MG_Backend/DirectVulkan, MG_State/TextureState, MG_Test): harden default-fbo clear lifetime tracking
This commit is contained in:
@@ -17,6 +17,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
target <= TextureUploadTarget::CubeMapNegativeZ;
|
target <= TextureUploadTarget::CubeMapNegativeZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Bool PendingClearMatchesTextureIdentity(const PendingClearKey& key, const TextureIdentity& identity) {
|
||||||
|
return key.texture == identity.texture && key.textureLifetimeId == identity.lifetimeId;
|
||||||
|
}
|
||||||
|
|
||||||
static Uint32 ResolveAttachmentBaseArrayLayer(TextureUploadTarget target) {
|
static Uint32 ResolveAttachmentBaseArrayLayer(TextureUploadTarget target) {
|
||||||
if (!IsCubeMapFaceUploadTarget(target)) {
|
if (!IsCubeMapFaceUploadTarget(target)) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -42,6 +46,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Uint32 baseArrayLayer, Uint32 layerCount) {
|
Uint32 baseArrayLayer, Uint32 layerCount) {
|
||||||
return PendingClearKey {
|
return PendingClearKey {
|
||||||
.texture = texture,
|
.texture = texture,
|
||||||
|
.textureLifetimeId = texture ? texture->GetLifetimeId() : 0,
|
||||||
.mipLevel = mipLevel,
|
.mipLevel = mipLevel,
|
||||||
.baseArrayLayer = baseArrayLayer,
|
.baseArrayLayer = baseArrayLayer,
|
||||||
.layerCount = layerCount,
|
.layerCount = layerCount,
|
||||||
@@ -66,7 +71,74 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VkClearManager::Shutdown() {
|
void VkClearManager::Shutdown() {
|
||||||
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
m_pendingClears.clear();
|
||||||
|
m_aliveObjects.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureIdentity VkClearManager::MakeTextureIdentity(MG_State::GLState::ITextureObject* texture) {
|
||||||
|
return TextureIdentity {
|
||||||
|
.texture = texture,
|
||||||
|
.lifetimeId = texture ? texture->GetLifetimeId() : 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkClearManager::MergeClearPayload(ClearAttachmentPayload& dst, const ClearAttachmentPayload& src) {
|
||||||
|
dst.mask |= src.mask;
|
||||||
|
if ((src.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||||
|
dst.color = src.color;
|
||||||
|
}
|
||||||
|
if ((src.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||||
|
dst.depth = src.depth;
|
||||||
|
}
|
||||||
|
if ((src.mask & GL_STENCIL_BUFFER_BIT) != 0) {
|
||||||
|
dst.stencil = src.stencil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkClearManager::ErasePendingClearsForTextureLocked(const TextureIdentity& identity) {
|
||||||
|
Vector<PendingClearKey> keysToErase;
|
||||||
|
keysToErase.reserve(m_pendingClears.size());
|
||||||
|
for (auto it = m_pendingClears.begin(); it != m_pendingClears.end(); ++it) {
|
||||||
|
if (PendingClearMatchesTextureIdentity(it->first, identity)) {
|
||||||
|
keysToErase.emplace_back(it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto& key : keysToErase) {
|
||||||
|
m_pendingClears.erase(key);
|
||||||
|
}
|
||||||
|
m_aliveObjects.erase(identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkClearManager::LockTextureIdentityLocked(const TextureIdentity& identity,
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) {
|
||||||
|
outTexture.reset();
|
||||||
|
if (identity.texture == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto aliveIt = m_aliveObjects.find(identity);
|
||||||
|
if (aliveIt == m_aliveObjects.end()) {
|
||||||
|
ErasePendingClearsForTextureLocked(identity);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outTexture = aliveIt->second.lock();
|
||||||
|
if (!outTexture || outTexture.get() != identity.texture || outTexture->GetLifetimeId() != identity.lifetimeId) {
|
||||||
|
ErasePendingClearsForTextureLocked(identity);
|
||||||
|
outTexture.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkClearManager::LockTextureLocked(const PendingClearKey& key,
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) {
|
||||||
|
return LockTextureIdentityLocked(TextureIdentity{
|
||||||
|
.texture = key.texture,
|
||||||
|
.lifetimeId = key.textureLifetimeId,
|
||||||
|
}, outTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkClearManager::QueueClear(GLbitfield mask, const ClearFramebufferPayload& clearPayload,
|
void VkClearManager::QueueClear(GLbitfield mask, const ClearFramebufferPayload& clearPayload,
|
||||||
@@ -121,25 +193,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
|
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
|
||||||
const SharedPtr<MG_State::GLState::ITextureObject>& texture) {
|
const SharedPtr<MG_State::GLState::ITextureObject>& texture) {
|
||||||
if (clearPayload.mask == 0) {
|
if (clearPayload.mask == 0 || !texture) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
WeakPtr<MG_State::GLState::ITextureObject> weakTexturePtr = texture;
|
|
||||||
if (weakTexturePtr.expired())
|
const PendingClearKey key = MakePendingClearKey(texture.get());
|
||||||
return;
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
auto* pTexture = weakTexturePtr.lock().get();
|
m_aliveObjects[MakeTextureIdentity(texture.get())] = texture;
|
||||||
m_aliveObjects[pTexture] = weakTexturePtr;
|
auto& pending = m_pendingClears[key];
|
||||||
auto& pending = m_pendingClears[MakePendingClearKey(pTexture)];
|
MergeClearPayload(pending, clearPayload);
|
||||||
pending.mask |= clearPayload.mask;
|
|
||||||
if (clearPayload.mask & GL_COLOR_BUFFER_BIT) {
|
|
||||||
pending.color = clearPayload.color;
|
|
||||||
}
|
|
||||||
if (clearPayload.mask & GL_DEPTH_BUFFER_BIT) {
|
|
||||||
pending.depth = clearPayload.depth;
|
|
||||||
}
|
|
||||||
if (clearPayload.mask & GL_STENCIL_BUFFER_BIT) {
|
|
||||||
pending.stencil = clearPayload.stencil;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
|
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
|
||||||
@@ -151,35 +213,42 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (!texture) {
|
if (!texture) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
WeakPtr<MG_State::GLState::ITextureObject> weakTexturePtr = texture;
|
|
||||||
if (weakTexturePtr.expired()) {
|
const PendingClearKey key = MakePendingClearKey(attachment);
|
||||||
return;
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
}
|
m_aliveObjects[MakeTextureIdentity(texture.get())] = texture;
|
||||||
auto* pTexture = weakTexturePtr.lock().get();
|
auto& pending = m_pendingClears[key];
|
||||||
m_aliveObjects[pTexture] = weakTexturePtr;
|
MergeClearPayload(pending, clearPayload);
|
||||||
auto& pending = m_pendingClears[MakePendingClearKey(attachment)];
|
|
||||||
pending.mask |= clearPayload.mask;
|
|
||||||
if (clearPayload.mask & GL_COLOR_BUFFER_BIT) {
|
|
||||||
pending.color = clearPayload.color;
|
|
||||||
}
|
|
||||||
if (clearPayload.mask & GL_DEPTH_BUFFER_BIT) {
|
|
||||||
pending.depth = clearPayload.depth;
|
|
||||||
}
|
|
||||||
if (clearPayload.mask & GL_STENCIL_BUFFER_BIT) {
|
|
||||||
pending.stencil = clearPayload.stencil;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VkClearManager::HasPendingClear(MG_State::GLState::ITextureObject* texture) {
|
Bool VkClearManager::HasPendingClear(MG_State::GLState::ITextureObject* texture) {
|
||||||
if (texture == nullptr) {
|
if (texture == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return std::any_of(m_pendingClears.begin(), m_pendingClears.end(),
|
|
||||||
[texture](const auto& item) { return item.first.texture == texture; });
|
const Uint64 lifetimeId = texture->GetLifetimeId();
|
||||||
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
for (auto it = m_pendingClears.begin(); it != m_pendingClears.end(); ++it) {
|
||||||
|
if (it->first.texture == texture && it->first.textureLifetimeId == lifetimeId) {
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject> liveTexture;
|
||||||
|
return LockTextureLocked(it->first, liveTexture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VkClearManager::HasPendingClear(const PendingClearKey& key) {
|
Bool VkClearManager::HasPendingClear(const PendingClearKey& key) {
|
||||||
return key.texture != nullptr && m_pendingClears.find(key) != m_pendingClears.end();
|
if (key.texture == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
if (m_pendingClears.find(key) == m_pendingClears.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject> liveTexture;
|
||||||
|
return LockTextureLocked(key, liveTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VkClearManager::HasPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
Bool VkClearManager::HasPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
||||||
@@ -190,20 +259,30 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Bool VkClearManager::GetPendingClear(const PendingClearKey& key, ClearAttachmentPayload& outPayload) {
|
Bool VkClearManager::GetPendingClear(const PendingClearKey& key, ClearAttachmentPayload& outPayload) {
|
||||||
if (key.texture == nullptr || m_aliveObjects.find(key.texture) == m_aliveObjects.end()) {
|
SharedPtr<MG_State::GLState::ITextureObject> liveTexture;
|
||||||
|
return GetPendingClear(key, outPayload, liveTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkClearManager::GetPendingClear(const PendingClearKey& key, ClearAttachmentPayload& outPayload,
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) {
|
||||||
|
if (key.texture == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
if (!LockTextureLocked(key, outTexture)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto it = m_pendingClears.find(key);
|
auto it = m_pendingClears.find(key);
|
||||||
if (it == m_pendingClears.end()) {
|
if (it == m_pendingClears.end()) {
|
||||||
MGLOG_D("%s: Failed getting pending clear for texture %d mip=%u layer=%u count=%u", __func__,
|
outTexture.reset();
|
||||||
key.texture ? key.texture->GetExternalIndex() : 0, key.mipLevel, key.baseArrayLayer, key.layerCount);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
outPayload = it->second;
|
outPayload = it->second;
|
||||||
MGLOG_D("%s: Got pending clear for texture %d (%s), mip=%u layer=%u count=%u mask=0x%x clear value: color = (%.2f, %.2f, %.2f, %.2f), depth = (%.2f), stencil = (%u)", __func__,
|
MGLOG_D("%s: Got pending clear for texture@%p lifetime=%llu, mip=%u layer=%u count=%u mask=0x%x clear value: color = (%.2f, %.2f, %.2f, %.2f), depth = (%.2f), stencil = (%u)", __func__,
|
||||||
key.texture->GetExternalIndex(),
|
static_cast<void*>(key.texture),
|
||||||
MG_Util::ConvertTextureInternalFormatToString(key.texture->GetFormat()).c_str(),
|
static_cast<unsigned long long>(key.textureLifetimeId),
|
||||||
key.mipLevel, key.baseArrayLayer, key.layerCount,
|
key.mipLevel, key.baseArrayLayer, key.layerCount,
|
||||||
static_cast<Uint32>(outPayload.mask),
|
static_cast<Uint32>(outPayload.mask),
|
||||||
outPayload.color[0], outPayload.color[1], outPayload.color[2], outPayload.color[3],
|
outPayload.color[0], outPayload.color[1], outPayload.color[2], outPayload.color[3],
|
||||||
@@ -224,14 +303,20 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Bool VkClearManager::GetPendingClears(MG_State::GLState::ITextureObject* texture,
|
Bool VkClearManager::GetPendingClears(MG_State::GLState::ITextureObject* texture,
|
||||||
Vector<PendingClearEntry>& outEntries) {
|
Vector<PendingClearEntry>& outEntries) {
|
||||||
outEntries.clear();
|
outEntries.clear();
|
||||||
if (texture == nullptr || m_aliveObjects.find(texture) == m_aliveObjects.end()) {
|
if (texture == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (const auto& [key, payload] : m_pendingClears) {
|
|
||||||
if (key.texture != texture) {
|
const Uint64 lifetimeId = texture->GetLifetimeId();
|
||||||
continue;
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject> liveTexture;
|
||||||
|
if (!LockTextureIdentityLocked(MakeTextureIdentity(texture), liveTexture)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (auto it = m_pendingClears.begin(); it != m_pendingClears.end(); ++it) {
|
||||||
|
if (it->first.texture == texture && it->first.textureLifetimeId == lifetimeId) {
|
||||||
|
outEntries.emplace_back(PendingClearEntry{.key = it->first, .payload = it->second});
|
||||||
}
|
}
|
||||||
outEntries.emplace_back(PendingClearEntry{.key = key, .payload = payload});
|
|
||||||
}
|
}
|
||||||
return !outEntries.empty();
|
return !outEntries.empty();
|
||||||
}
|
}
|
||||||
@@ -240,24 +325,29 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (texture == nullptr) {
|
if (texture == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
m_aliveObjects.erase(texture);
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
for (auto it = m_pendingClears.begin(); it != m_pendingClears.end();) {
|
ErasePendingClearsForTextureLocked(identity);
|
||||||
if (it->first.texture == texture) {
|
|
||||||
it = m_pendingClears.erase(it);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkClearManager::PopPendingClear(const PendingClearKey& key) {
|
void VkClearManager::PopPendingClear(const PendingClearKey& key) {
|
||||||
if (key.texture == nullptr) {
|
if (key.texture == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MGLOG_D("%s: Pop pending clear for texture %d mip=%u layer=%u count=%u", __func__,
|
|
||||||
key.texture->GetExternalIndex(), key.mipLevel, key.baseArrayLayer, key.layerCount);
|
{
|
||||||
m_pendingClears.erase(key);
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
auto it = m_pendingClears.find(key);
|
||||||
|
if (it != m_pendingClears.end()) {
|
||||||
|
m_pendingClears.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MGLOG_D("%s: Pop pending clear for texture@%p lifetime=%llu mip=%u layer=%u count=%u", __func__,
|
||||||
|
static_cast<void*>(key.texture), static_cast<unsigned long long>(key.textureLifetimeId),
|
||||||
|
key.mipLevel, key.baseArrayLayer, key.layerCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkClearManager::PopPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
void VkClearManager::PopPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
||||||
@@ -268,26 +358,26 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SizeT VkClearManager::CollectGarbage() {
|
SizeT VkClearManager::CollectGarbage() {
|
||||||
|
const std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
m_gcCounter++;
|
m_gcCounter++;
|
||||||
if (m_gcCounter != 0) {
|
if (m_gcCounter != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SizeT count = 0;
|
Vector<TextureIdentity> expiredTextures;
|
||||||
for (auto it = m_aliveObjects.begin(); it != m_aliveObjects.end();) {
|
expiredTextures.reserve(m_aliveObjects.size());
|
||||||
auto current = it++;
|
for (auto it = m_aliveObjects.begin(); it != m_aliveObjects.end(); ++it) {
|
||||||
if (current->second.expired()) {
|
if (it->second.expired()) {
|
||||||
for (auto clearIt = m_pendingClears.begin(); clearIt != m_pendingClears.end();) {
|
expiredTextures.emplace_back(it->first);
|
||||||
if (clearIt->first.texture == current->first) {
|
|
||||||
clearIt = m_pendingClears.erase(clearIt);
|
|
||||||
} else {
|
|
||||||
++clearIt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_aliveObjects.erase(current);
|
|
||||||
++count;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return count;
|
if (expiredTextures.empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& identity : expiredTextures) {
|
||||||
|
ErasePendingClearsForTextureLocked(identity);
|
||||||
|
}
|
||||||
|
return expiredTextures.size();
|
||||||
}
|
}
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "MG_Util/Math/VectorTypes.h"
|
#include "MG_Util/Math/VectorTypes.h"
|
||||||
|
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
struct ClearFramebufferPayload {
|
struct ClearFramebufferPayload {
|
||||||
@@ -31,16 +32,27 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
struct PendingClearKey {
|
struct PendingClearKey {
|
||||||
MG_State::GLState::ITextureObject* texture = nullptr;
|
MG_State::GLState::ITextureObject* texture = nullptr;
|
||||||
|
Uint64 textureLifetimeId = 0;
|
||||||
Uint32 mipLevel = 0;
|
Uint32 mipLevel = 0;
|
||||||
Uint32 baseArrayLayer = 0;
|
Uint32 baseArrayLayer = 0;
|
||||||
Uint32 layerCount = 1;
|
Uint32 layerCount = 1;
|
||||||
|
|
||||||
Bool operator==(const PendingClearKey& other) const {
|
Bool operator==(const PendingClearKey& other) const {
|
||||||
return texture == other.texture && mipLevel == other.mipLevel &&
|
return texture == other.texture && textureLifetimeId == other.textureLifetimeId &&
|
||||||
|
mipLevel == other.mipLevel &&
|
||||||
baseArrayLayer == other.baseArrayLayer && layerCount == other.layerCount;
|
baseArrayLayer == other.baseArrayLayer && layerCount == other.layerCount;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TextureIdentity {
|
||||||
|
MG_State::GLState::ITextureObject* texture = nullptr;
|
||||||
|
Uint64 lifetimeId = 0;
|
||||||
|
|
||||||
|
Bool operator==(const TextureIdentity& other) const {
|
||||||
|
return texture == other.texture && lifetimeId == other.lifetimeId;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct PendingClearEntry {
|
struct PendingClearEntry {
|
||||||
PendingClearKey key{};
|
PendingClearKey key{};
|
||||||
ClearAttachmentPayload payload{};
|
ClearAttachmentPayload payload{};
|
||||||
@@ -49,10 +61,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
struct PendingClearKeyHash {
|
struct PendingClearKeyHash {
|
||||||
SizeT operator()(const PendingClearKey& key) const {
|
SizeT operator()(const PendingClearKey& key) const {
|
||||||
const SizeT textureHash = std::hash<MG_State::GLState::ITextureObject*>{}(key.texture);
|
const SizeT textureHash = std::hash<MG_State::GLState::ITextureObject*>{}(key.texture);
|
||||||
|
const SizeT textureLifetimeHash = std::hash<Uint64>{}(key.textureLifetimeId);
|
||||||
const SizeT mipHash = std::hash<Uint32>{}(key.mipLevel);
|
const SizeT mipHash = std::hash<Uint32>{}(key.mipLevel);
|
||||||
const SizeT layerHash = std::hash<Uint32>{}(key.baseArrayLayer);
|
const SizeT layerHash = std::hash<Uint32>{}(key.baseArrayLayer);
|
||||||
const SizeT layerCountHash = std::hash<Uint32>{}(key.layerCount);
|
const SizeT layerCountHash = std::hash<Uint32>{}(key.layerCount);
|
||||||
SizeT hash = textureHash;
|
SizeT hash = textureHash;
|
||||||
|
hash ^= textureLifetimeHash + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
hash ^= mipHash + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
hash ^= mipHash + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
hash ^= layerHash + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
hash ^= layerHash + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
hash ^= layerCountHash + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
hash ^= layerCountHash + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
@@ -60,6 +74,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TextureIdentityHash {
|
||||||
|
SizeT operator()(const TextureIdentity& key) const {
|
||||||
|
SizeT hash = std::hash<MG_State::GLState::ITextureObject*>{}(key.texture);
|
||||||
|
hash ^= std::hash<Uint64>{}(key.lifetimeId) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class VkClearManager {
|
class VkClearManager {
|
||||||
public:
|
public:
|
||||||
static PendingClearKey MakePendingClearKey(const MG_State::GLState::FramebufferAttachmentObject& attachment);
|
static PendingClearKey MakePendingClearKey(const MG_State::GLState::FramebufferAttachmentObject& attachment);
|
||||||
@@ -79,6 +101,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Bool HasPendingClear(const PendingClearKey& key);
|
Bool HasPendingClear(const PendingClearKey& key);
|
||||||
Bool HasPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment);
|
Bool HasPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment);
|
||||||
Bool GetPendingClear(const PendingClearKey& key, ClearAttachmentPayload& outPayload);
|
Bool GetPendingClear(const PendingClearKey& key, ClearAttachmentPayload& outPayload);
|
||||||
|
Bool GetPendingClear(const PendingClearKey& key, ClearAttachmentPayload& outPayload,
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject>& outTexture);
|
||||||
Bool GetPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment,
|
Bool GetPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment,
|
||||||
ClearAttachmentPayload& outPayload);
|
ClearAttachmentPayload& outPayload);
|
||||||
Bool GetPendingClears(MG_State::GLState::ITextureObject* texture, Vector<PendingClearEntry>& outEntries);
|
Bool GetPendingClears(MG_State::GLState::ITextureObject* texture, Vector<PendingClearEntry>& outEntries);
|
||||||
@@ -87,8 +111,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
void PopPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment);
|
void PopPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment);
|
||||||
SizeT CollectGarbage();
|
SizeT CollectGarbage();
|
||||||
private:
|
private:
|
||||||
|
static TextureIdentity MakeTextureIdentity(MG_State::GLState::ITextureObject* texture);
|
||||||
|
static void MergeClearPayload(ClearAttachmentPayload& dst, const ClearAttachmentPayload& src);
|
||||||
|
void ErasePendingClearsForTextureLocked(const TextureIdentity& identity);
|
||||||
|
Bool LockTextureIdentityLocked(const TextureIdentity& identity,
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject>& outTexture);
|
||||||
|
Bool LockTextureLocked(const PendingClearKey& key,
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject>& outTexture);
|
||||||
|
|
||||||
Uint8 m_gcCounter = 0;
|
Uint8 m_gcCounter = 0;
|
||||||
UnorderedMap<PendingClearKey, ClearAttachmentPayload, PendingClearKeyHash> m_pendingClears;
|
mutable std::mutex m_mutex;
|
||||||
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
|
std::unordered_map<PendingClearKey, ClearAttachmentPayload, PendingClearKeyHash> m_pendingClears;
|
||||||
|
std::unordered_map<TextureIdentity, WeakPtr<MG_State::GLState::ITextureObject>, TextureIdentityHash> m_aliveObjects;
|
||||||
};
|
};
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
|
|||||||
@@ -104,6 +104,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IntVec2 ResolveRenderPassFramebufferExtent(Bool isDefaultFbo, const TextureSize& attachmentExtent,
|
||||||
|
VkExtent2D swapchainExtent) {
|
||||||
|
if (isDefaultFbo) {
|
||||||
|
return {static_cast<Int>(swapchainExtent.width), static_cast<Int>(swapchainExtent.height)};
|
||||||
|
}
|
||||||
|
return {attachmentExtent.x(), attachmentExtent.y()};
|
||||||
|
}
|
||||||
|
|
||||||
VkRenderPassManager::VkRenderPassManager(VkDevice device,
|
VkRenderPassManager::VkRenderPassManager(VkDevice device,
|
||||||
const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager,
|
const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager,
|
||||||
SwapchainObject& swapchainObject):
|
SwapchainObject& swapchainObject):
|
||||||
@@ -131,7 +139,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VkRenderPassManager::HashType VkRenderPassManager::ComputeHash(
|
VkRenderPassManager::HashType VkRenderPassManager::ComputeHash(
|
||||||
const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex, Bool includePendingClear) const {
|
const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex, Bool includePendingClear) const {
|
||||||
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion));
|
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion));
|
||||||
const Bool isDefaultFbo = (&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
|
const Bool isDefaultFbo = fbo.IsDefaultFramebuffer();
|
||||||
if (isDefaultFbo) {
|
if (isDefaultFbo) {
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &swapchainImageIndex, sizeof(swapchainImageIndex)));
|
XXHASH_VERIFY(XXH64_update(m_hashState, &swapchainImageIndex, sizeof(swapchainImageIndex)));
|
||||||
}
|
}
|
||||||
@@ -162,6 +170,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
contentPtr = att.GetRenderbuffer().get();
|
contentPtr = att.GetRenderbuffer().get();
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &contentPtr, sizeof(contentPtr)));
|
XXHASH_VERIFY(XXH64_update(m_hashState, &contentPtr, sizeof(contentPtr)));
|
||||||
if (att.IsTexture()) {
|
if (att.IsTexture()) {
|
||||||
|
const Uint64 textureLifetimeId = att.GetTexture()->GetLifetimeId();
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &textureLifetimeId, sizeof(textureLifetimeId)));
|
||||||
const Int textureLevel = att.GetTextureLevel();
|
const Int textureLevel = att.GetTextureLevel();
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &textureLevel, sizeof(textureLevel)));
|
XXHASH_VERIFY(XXH64_update(m_hashState, &textureLevel, sizeof(textureLevel)));
|
||||||
const TextureUploadTarget textureUploadTarget = att.GetTextureUploadTarget();
|
const TextureUploadTarget textureUploadTarget = att.GetTextureUploadTarget();
|
||||||
@@ -196,8 +206,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
VkImageLayout currentLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
VkImageLayout currentLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
if (isDefaultFbo) {
|
if (isDefaultFbo) {
|
||||||
if (attachment >= FramebufferAttachmentType::Color0 &&
|
const Bool isDefaultColorAttachment =
|
||||||
attachment <= FramebufferAttachmentType::Color31) {
|
attachment == FramebufferAttachmentType::Color0 ||
|
||||||
|
(attachment >= FramebufferAttachmentType::FrontLeft &&
|
||||||
|
attachment <= FramebufferAttachmentType::BackRight);
|
||||||
|
if (isDefaultColorAttachment) {
|
||||||
currentLayout = m_swapchainObject.GetImageLayout(swapchainImageIndex);
|
currentLayout = m_swapchainObject.GetImageLayout(swapchainImageIndex);
|
||||||
} else if (attachment == FramebufferAttachmentType::Depth ||
|
} else if (attachment == FramebufferAttachmentType::Depth ||
|
||||||
attachment == FramebufferAttachmentType::Stencil) {
|
attachment == FramebufferAttachmentType::Stencil) {
|
||||||
@@ -269,13 +282,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (it != m_renderPasses.end())
|
if (it != m_renderPasses.end())
|
||||||
return it->second;
|
return it->second;
|
||||||
|
|
||||||
Bool isDefaultFbo = (&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
|
Bool isDefaultFbo = fbo.IsDefaultFramebuffer();
|
||||||
// Color attachment
|
// Color attachment
|
||||||
auto& drawbufs = fbo.GetDrawBuffers();
|
auto& drawbufs = fbo.GetDrawBuffers();
|
||||||
const Uint32 colorAttachmentSlotCount = static_cast<Uint32>(drawbufs.size());
|
const Uint32 colorAttachmentSlotCount = static_cast<Uint32>(drawbufs.size());
|
||||||
|
|
||||||
Int width = 0;
|
const VkExtent2D swapchainExtent = m_swapchainObject.GetExtent();
|
||||||
Int height = 0;
|
// Default framebuffer attachments are frontend placeholders; Vulkan framebuffer extent must match the swapchain.
|
||||||
|
const IntVec2 defaultFramebufferExtent =
|
||||||
|
ResolveRenderPassFramebufferExtent(isDefaultFbo, {0, 0, 0}, swapchainExtent);
|
||||||
|
Int width = defaultFramebufferExtent.x();
|
||||||
|
Int height = defaultFramebufferExtent.y();
|
||||||
Vector<VkAttachmentDescription> attachmentDescriptions;
|
Vector<VkAttachmentDescription> attachmentDescriptions;
|
||||||
attachmentDescriptions.reserve(colorAttachmentSlotCount + 1);
|
attachmentDescriptions.reserve(colorAttachmentSlotCount + 1);
|
||||||
// Keep the full GL draw buffer slot span so fragment outputs targeting GL_NONE map to VK_ATTACHMENT_UNUSED.
|
// Keep the full GL draw buffer slot span so fragment outputs targeting GL_NONE map to VK_ATTACHMENT_UNUSED.
|
||||||
@@ -351,10 +368,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
.key = VkClearManager::MakePendingClearKey(att)
|
.key = VkClearManager::MakePendingClearKey(att)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const IntVec2 attachmentExtent =
|
||||||
|
ResolveRenderPassFramebufferExtent(isDefaultFbo, att.GetSize(), swapchainExtent);
|
||||||
if (width == 0)
|
if (width == 0)
|
||||||
width = att.GetSize().x();
|
width = attachmentExtent.x();
|
||||||
if (height == 0)
|
if (height == 0)
|
||||||
height = att.GetSize().y();
|
height = attachmentExtent.y();
|
||||||
|
|
||||||
if (isDefaultFbo) {
|
if (isDefaultFbo) {
|
||||||
const auto& swapchainViews = m_swapchainObject.GetImageViews();
|
const auto& swapchainViews = m_swapchainObject.GetImageViews();
|
||||||
@@ -379,7 +398,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
trackedColorLayout = textureResource->layout;
|
trackedColorLayout = textureResource->layout;
|
||||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||||
.target = TrackedAttachmentTarget::Texture,
|
.target = TrackedAttachmentTarget::Texture,
|
||||||
.texture = texture,
|
.texture = att.GetTexture(),
|
||||||
.textureMipLevel = attachmentMipLevel,
|
.textureMipLevel = attachmentMipLevel,
|
||||||
.finalLayout = desc.finalLayout,
|
.finalLayout = desc.finalLayout,
|
||||||
});
|
});
|
||||||
@@ -505,7 +524,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
texture.GetExternalIndex());
|
texture.GetExternalIndex());
|
||||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||||
.target = TrackedAttachmentTarget::Texture,
|
.target = TrackedAttachmentTarget::Texture,
|
||||||
.texture = &texture,
|
.texture = selectedDepthStencilAttachment->GetTexture(),
|
||||||
.textureMipLevel = attachmentMipLevel,
|
.textureMipLevel = attachmentMipLevel,
|
||||||
.finalLayout = depthAttachmentDescription.finalLayout,
|
.finalLayout = depthAttachmentDescription.finalLayout,
|
||||||
});
|
});
|
||||||
@@ -519,9 +538,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
texture, attachmentMipLevel, baseArrayLayer, layerCount, attachmentViewType));
|
texture, attachmentMipLevel, baseArrayLayer, layerCount, attachmentViewType));
|
||||||
MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE,
|
MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE,
|
||||||
"GetOrCreateRenderPass: GetOrCreateAttachmentView failed at depth attachment");
|
"GetOrCreateRenderPass: GetOrCreateAttachmentView failed at depth attachment");
|
||||||
|
const IntVec2 attachmentExtent =
|
||||||
|
ResolveRenderPassFramebufferExtent(isDefaultFbo, selectedDepthStencilAttachment->GetSize(),
|
||||||
|
swapchainExtent);
|
||||||
if (width == 0 || height == 0) {
|
if (width == 0 || height == 0) {
|
||||||
width = selectedDepthStencilAttachment->GetSize().x();
|
width = attachmentExtent.x();
|
||||||
height = selectedDepthStencilAttachment->GetSize().y();
|
height = attachmentExtent.y();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
attachmentDescriptions.emplace_back(depthAttachmentDescription);
|
attachmentDescriptions.emplace_back(depthAttachmentDescription);
|
||||||
@@ -617,7 +639,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ClearAttachmentPayload clearPayload{};
|
ClearAttachmentPayload clearPayload{};
|
||||||
if (!s_clearManager->GetPendingClear(pending.key, clearPayload)) {
|
SharedPtr<MG_State::GLState::ITextureObject> liveTexture;
|
||||||
|
if (!s_clearManager->GetPendingClear(pending.key, clearPayload, liveTexture)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((clearPayload.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
if ((clearPayload.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||||
@@ -625,7 +648,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
clearPayload.color.x(),
|
clearPayload.color.x(),
|
||||||
clearPayload.color.y(),
|
clearPayload.color.y(),
|
||||||
clearPayload.color.z(),
|
clearPayload.color.z(),
|
||||||
ResolveColorClearAlpha(pending.key.texture, clearPayload.color.w())
|
ResolveColorClearAlpha(liveTexture.get(), clearPayload.color.w())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||||
@@ -660,11 +683,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
switch (trackedAttachment.target) {
|
switch (trackedAttachment.target) {
|
||||||
case TrackedAttachmentTarget::Texture:
|
case TrackedAttachmentTarget::Texture:
|
||||||
MOBILEGL_ASSERT(s_textureManager != nullptr, "EndRenderPass: texture manager is null");
|
MOBILEGL_ASSERT(s_textureManager != nullptr, "EndRenderPass: texture manager is null");
|
||||||
s_textureManager->UpdateTrackedImageLayoutAfterAttachmentWrite(
|
if (const auto texture = trackedAttachment.texture.lock()) {
|
||||||
commandBuffer,
|
s_textureManager->UpdateTrackedImageLayoutAfterAttachmentWrite(
|
||||||
trackedAttachment.texture,
|
commandBuffer,
|
||||||
trackedAttachment.textureMipLevel,
|
texture.get(),
|
||||||
trackedAttachment.finalLayout);
|
trackedAttachment.textureMipLevel,
|
||||||
|
trackedAttachment.finalLayout);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TrackedAttachmentTarget::SwapchainColor:
|
case TrackedAttachmentTarget::SwapchainColor:
|
||||||
MOBILEGL_ASSERT(s_swapchainObject != nullptr, "EndRenderPass: swapchain object is null");
|
MOBILEGL_ASSERT(s_swapchainObject != nullptr, "EndRenderPass: swapchain object is null");
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
struct TrackedAttachmentLayoutInfo {
|
struct TrackedAttachmentLayoutInfo {
|
||||||
TrackedAttachmentTarget target = TrackedAttachmentTarget::Texture;
|
TrackedAttachmentTarget target = TrackedAttachmentTarget::Texture;
|
||||||
MG_State::GLState::ITextureObject* texture = nullptr;
|
WeakPtr<MG_State::GLState::ITextureObject> texture;
|
||||||
Uint32 textureMipLevel = 0;
|
Uint32 textureMipLevel = 0;
|
||||||
Uint32 swapchainImageIndex = 0;
|
Uint32 swapchainImageIndex = 0;
|
||||||
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
@@ -45,6 +45,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
DepthStencilAttachmentLoadInfo ResolveDepthStencilAttachmentLoadInfo(
|
DepthStencilAttachmentLoadInfo ResolveDepthStencilAttachmentLoadInfo(
|
||||||
VkImageLayout trackedLayout, Bool clearDepth, Bool clearStencil);
|
VkImageLayout trackedLayout, Bool clearDepth, Bool clearStencil);
|
||||||
|
IntVec2 ResolveRenderPassFramebufferExtent(Bool isDefaultFbo, const TextureSize& attachmentExtent,
|
||||||
|
VkExtent2D swapchainExtent);
|
||||||
|
|
||||||
struct RenderPassEntry {
|
struct RenderPassEntry {
|
||||||
static inline VkDevice s_device;
|
static inline VkDevice s_device;
|
||||||
|
|||||||
@@ -156,6 +156,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkTextureManager::TextureIdentity VkTextureManager::MakeTextureIdentity(
|
||||||
|
MG_State::GLState::ITextureObject* texture) {
|
||||||
|
return TextureIdentity{
|
||||||
|
.texture = texture,
|
||||||
|
.lifetimeId = texture ? texture->GetLifetimeId() : 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static void GetImageTransitionDestinationState(VkImageLayout newLayout,
|
static void GetImageTransitionDestinationState(VkImageLayout newLayout,
|
||||||
VkPipelineStageFlags& outDstStageMask,
|
VkPipelineStageFlags& outDstStageMask,
|
||||||
VkAccessFlags& outDstAccessMask) {
|
VkAccessFlags& outDstAccessMask) {
|
||||||
@@ -580,6 +588,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
void VkTextureManager::Shutdown() {
|
void VkTextureManager::Shutdown() {
|
||||||
DestroyDeferredReleases();
|
DestroyDeferredReleases();
|
||||||
m_textureResources.clear();
|
m_textureResources.clear();
|
||||||
|
m_aliveObjects.clear();
|
||||||
|
|
||||||
m_device = VK_NULL_HANDLE;
|
m_device = VK_NULL_HANDLE;
|
||||||
m_physicalDevice = VK_NULL_HANDLE;
|
m_physicalDevice = VK_NULL_HANDLE;
|
||||||
@@ -600,28 +609,56 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
CollectDeferredReleases(frameIndex);
|
CollectDeferredReleases(frameIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VkTextureManager::EraseTrackedTexture(const TextureIdentity& identity) {
|
||||||
|
auto resourceIt = m_textureResources.find(identity);
|
||||||
|
if (resourceIt != m_textureResources.end()) {
|
||||||
|
DeferResourceRelease(Move(resourceIt->second));
|
||||||
|
m_textureResources.erase(resourceIt);
|
||||||
|
}
|
||||||
|
m_aliveObjects.erase(identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkTextureManager::PruneStaleTextureAliases(MG_State::GLState::ITextureObject* texture) {
|
||||||
|
if (texture == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<TextureIdentity> staleAliases;
|
||||||
|
staleAliases.reserve(m_aliveObjects.size());
|
||||||
|
for (auto it = m_aliveObjects.begin(); it != m_aliveObjects.end(); ++it) {
|
||||||
|
if (it->first.texture != texture) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto liveTexture = it->second.lock();
|
||||||
|
if (!liveTexture || liveTexture.get() != texture ||
|
||||||
|
liveTexture->GetLifetimeId() != it->first.lifetimeId) {
|
||||||
|
staleAliases.emplace_back(it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto& identity : staleAliases) {
|
||||||
|
EraseTrackedTexture(identity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VkTextureManager::TextureResource* VkTextureManager::SyncTextureAndGetDescriptor(MG_State::GLState::ITextureObject& texture) {
|
VkTextureManager::TextureResource* VkTextureManager::SyncTextureAndGetDescriptor(MG_State::GLState::ITextureObject& texture) {
|
||||||
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "SyncTextureAndGetDescriptor: m_device == VK_NULL_HANDLE");
|
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "SyncTextureAndGetDescriptor: m_device == VK_NULL_HANDLE");
|
||||||
|
|
||||||
auto aliveIt = m_aliveObjects.find(&texture);
|
const TextureIdentity identity = MakeTextureIdentity(&texture);
|
||||||
|
auto aliveIt = m_aliveObjects.find(identity);
|
||||||
if (aliveIt != m_aliveObjects.end() && aliveIt->second.expired()) {
|
if (aliveIt != m_aliveObjects.end() && aliveIt->second.expired()) {
|
||||||
auto resourceIt = m_textureResources.find(&texture);
|
EraseTrackedTexture(aliveIt->first);
|
||||||
if (resourceIt != m_textureResources.end()) {
|
|
||||||
DeferResourceRelease(Move(resourceIt->second));
|
|
||||||
m_textureResources.erase(resourceIt);
|
|
||||||
}
|
|
||||||
m_aliveObjects.erase(aliveIt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& liveTexture = MG_State::pGLContext->GetTextureObject(texture.GetExternalIndex());
|
const auto& liveTexture = MG_State::pGLContext->GetTextureObject(texture.GetExternalIndex());
|
||||||
if (liveTexture && liveTexture.get() == &texture) {
|
if (liveTexture && liveTexture.get() == &texture) {
|
||||||
m_aliveObjects[&texture] = WeakPtr<MG_State::GLState::ITextureObject>(liveTexture);
|
m_aliveObjects[identity] = WeakPtr<MG_State::GLState::ITextureObject>(liveTexture);
|
||||||
|
PruneStaleTextureAliases(&texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto it = m_textureResources.find(&texture);
|
auto it = m_textureResources.find(identity);
|
||||||
if (it == m_textureResources.end()) {
|
if (it == m_textureResources.end()) {
|
||||||
TextureResource initial{};
|
TextureResource initial{};
|
||||||
auto [insertIt, _] = m_textureResources.emplace(&texture, Move(initial));
|
auto [insertIt, _] = m_textureResources.emplace(identity, Move(initial));
|
||||||
it = insertIt;
|
it = insertIt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -737,7 +774,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
void VkTextureManager::UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout) {
|
void VkTextureManager::UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout) {
|
||||||
MOBILEGL_ASSERT(texture != nullptr, "UpdateTrackedImageLayout: texture is null");
|
MOBILEGL_ASSERT(texture != nullptr, "UpdateTrackedImageLayout: texture is null");
|
||||||
auto it = m_textureResources.find(texture);
|
auto it = m_textureResources.find(MakeTextureIdentity(texture));
|
||||||
MOBILEGL_ASSERT(it != m_textureResources.end(),
|
MOBILEGL_ASSERT(it != m_textureResources.end(),
|
||||||
"UpdateTrackedImageLayout: textureId=%d has no tracked resource", texture->GetExternalIndex());
|
"UpdateTrackedImageLayout: textureId=%d has no tracked resource", texture->GetExternalIndex());
|
||||||
MOBILEGL_ASSERT(it->second.image != VK_NULL_HANDLE,
|
MOBILEGL_ASSERT(it->second.image != VK_NULL_HANDLE,
|
||||||
@@ -750,7 +787,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Uint32 writtenMipLevel,
|
Uint32 writtenMipLevel,
|
||||||
VkImageLayout newLayout) {
|
VkImageLayout newLayout) {
|
||||||
MOBILEGL_ASSERT(texture != nullptr, "UpdateTrackedImageLayoutAfterAttachmentWrite: texture is null");
|
MOBILEGL_ASSERT(texture != nullptr, "UpdateTrackedImageLayoutAfterAttachmentWrite: texture is null");
|
||||||
auto it = m_textureResources.find(texture);
|
auto it = m_textureResources.find(MakeTextureIdentity(texture));
|
||||||
MOBILEGL_ASSERT(it != m_textureResources.end(),
|
MOBILEGL_ASSERT(it != m_textureResources.end(),
|
||||||
"UpdateTrackedImageLayoutAfterAttachmentWrite: textureId=%d has no tracked resource",
|
"UpdateTrackedImageLayoutAfterAttachmentWrite: textureId=%d has no tracked resource",
|
||||||
texture->GetExternalIndex());
|
texture->GetExternalIndex());
|
||||||
@@ -920,20 +957,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (m_gcCounter != 0) {
|
if (m_gcCounter != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
SizeT count = 0;
|
|
||||||
for (auto it = m_aliveObjects.begin(); it != m_aliveObjects.end();) {
|
Vector<MG_State::GLState::ITextureObject*> expiredTextures;
|
||||||
auto current = it++;
|
expiredTextures.reserve(m_aliveObjects.size());
|
||||||
if (current->second.expired()) {
|
for (auto it = m_aliveObjects.begin(); it != m_aliveObjects.end(); ++it) {
|
||||||
auto resourceIt = m_textureResources.find(current->first);
|
if (it->second.expired()) {
|
||||||
if (resourceIt != m_textureResources.end()) {
|
expiredTextures.emplace_back(it->first.texture);
|
||||||
DeferResourceRelease(Move(resourceIt->second));
|
|
||||||
m_textureResources.erase(resourceIt);
|
|
||||||
}
|
|
||||||
m_aliveObjects.erase(current);
|
|
||||||
++count;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return count;
|
for (auto* texture : expiredTextures) {
|
||||||
|
PruneStaleTextureAliases(texture);
|
||||||
|
}
|
||||||
|
return expiredTextures.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VkTextureManager::SyncTexture(MG_State::GLState::ITextureObject &texture,
|
Bool VkTextureManager::SyncTexture(MG_State::GLState::ITextureObject &texture,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include <MG_State/GLState/TextureState/TextureObject.h>
|
#include <MG_State/GLState/TextureState/TextureObject.h>
|
||||||
#include <vk_mem_alloc.h>
|
#include <vk_mem_alloc.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace MobileGL::MG_State::GLState {
|
namespace MobileGL::MG_State::GLState {
|
||||||
class ITextureObject;
|
class ITextureObject;
|
||||||
@@ -20,6 +21,23 @@ class ITextureObject;
|
|||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
class VkTextureManager {
|
class VkTextureManager {
|
||||||
public:
|
public:
|
||||||
|
struct TextureIdentity {
|
||||||
|
MG_State::GLState::ITextureObject* texture = nullptr;
|
||||||
|
Uint64 lifetimeId = 0;
|
||||||
|
|
||||||
|
Bool operator==(const TextureIdentity& other) const {
|
||||||
|
return texture == other.texture && lifetimeId == other.lifetimeId;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextureIdentityHash {
|
||||||
|
SizeT operator()(const TextureIdentity& key) const {
|
||||||
|
SizeT hash = std::hash<MG_State::GLState::ITextureObject*>{}(key.texture);
|
||||||
|
hash ^= std::hash<Uint64>{}(key.lifetimeId) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct InitInfo {
|
struct InitInfo {
|
||||||
VkDevice device = VK_NULL_HANDLE;
|
VkDevice device = VK_NULL_HANDLE;
|
||||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||||
@@ -212,6 +230,9 @@ private:
|
|||||||
void DeferViewRelease(VkImageView view);
|
void DeferViewRelease(VkImageView view);
|
||||||
void CollectDeferredReleases(Uint32 frameIndex);
|
void CollectDeferredReleases(Uint32 frameIndex);
|
||||||
void DestroyDeferredReleases();
|
void DestroyDeferredReleases();
|
||||||
|
static TextureIdentity MakeTextureIdentity(MG_State::GLState::ITextureObject* texture);
|
||||||
|
void EraseTrackedTexture(const TextureIdentity& identity);
|
||||||
|
void PruneStaleTextureAliases(MG_State::GLState::ITextureObject* texture);
|
||||||
|
|
||||||
VkDevice m_device = VK_NULL_HANDLE;
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
||||||
@@ -221,8 +242,8 @@ private:
|
|||||||
Uint32 m_currentFrameIndex = 0;
|
Uint32 m_currentFrameIndex = 0;
|
||||||
|
|
||||||
Uint8 m_gcCounter = 0;
|
Uint8 m_gcCounter = 0;
|
||||||
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
|
std::unordered_map<TextureIdentity, WeakPtr<MG_State::GLState::ITextureObject>, TextureIdentityHash> m_aliveObjects;
|
||||||
UnorderedMap<MG_State::GLState::ITextureObject*, TextureResource> m_textureResources;
|
std::unordered_map<TextureIdentity, TextureResource, TextureIdentityHash> m_textureResources;
|
||||||
Vector<Vector<TextureResource>> m_deferredReleases;
|
Vector<Vector<TextureResource>> m_deferredReleases;
|
||||||
Vector<Vector<VkImageView>> m_deferredViewReleases;
|
Vector<Vector<VkImageView>> m_deferredViewReleases;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -689,7 +689,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (trackedAttachment.target != TrackedAttachmentTarget::Texture) {
|
if (trackedAttachment.target != TrackedAttachmentTarget::Texture) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (trackedAttachment.texture == &texture) {
|
const auto trackedTexture = trackedAttachment.texture.lock();
|
||||||
|
if (trackedTexture && trackedTexture.get() == &texture) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1064,9 +1065,33 @@ void main() {
|
|||||||
static Bool ResolveColorBlitBinding(MG_State::GLState::FramebufferObject& fbo, Bool isReadFramebuffer,
|
static Bool ResolveColorBlitBinding(MG_State::GLState::FramebufferObject& fbo, Bool isReadFramebuffer,
|
||||||
Uint32 swapchainImageIndex, SwapchainObject& swapchainObject,
|
Uint32 swapchainImageIndex, SwapchainObject& swapchainObject,
|
||||||
VkTextureManager& textureManager, BlitImageBinding& outBinding) {
|
VkTextureManager& textureManager, BlitImageBinding& outBinding) {
|
||||||
const Bool isDefaultFbo = (&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
|
const Bool isDefaultFbo = fbo.IsDefaultFramebuffer();
|
||||||
const FramebufferAttachmentType attachmentType =
|
const FramebufferAttachmentType attachmentType =
|
||||||
isReadFramebuffer ? fbo.GetReadBuffer() : fbo.GetDrawBuffers()[0];
|
isReadFramebuffer ? fbo.GetReadBuffer() : fbo.GetDrawBuffers()[0];
|
||||||
|
outBinding.label = isReadFramebuffer ? "read" : "draw";
|
||||||
|
|
||||||
|
if (isDefaultFbo) {
|
||||||
|
const Bool defaultColorAttachment =
|
||||||
|
attachmentType == FramebufferAttachmentType::Color0 ||
|
||||||
|
(attachmentType >= FramebufferAttachmentType::FrontLeft &&
|
||||||
|
attachmentType <= FramebufferAttachmentType::BackRight);
|
||||||
|
if (!defaultColorAttachment) {
|
||||||
|
MGLOG_E("BlitFramebuffer skipped: default framebuffer color attachment %d is not supported",
|
||||||
|
static_cast<Int>(attachmentType));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
outBinding.image = swapchainObject.GetImage(swapchainImageIndex);
|
||||||
|
outBinding.trackedLayout = nullptr;
|
||||||
|
outBinding.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
const auto extent = swapchainObject.GetExtent();
|
||||||
|
outBinding.extent = {static_cast<Int>(extent.width), static_cast<Int>(extent.height)};
|
||||||
|
outBinding.mipLevel = 0;
|
||||||
|
outBinding.mipLevelCount = 1;
|
||||||
|
outBinding.baseArrayLayer = 0;
|
||||||
|
outBinding.layerCount = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (attachmentType < FramebufferAttachmentType::Color0 || attachmentType > FramebufferAttachmentType::Color31) {
|
if (attachmentType < FramebufferAttachmentType::Color0 || attachmentType > FramebufferAttachmentType::Color31) {
|
||||||
MGLOG_E("BlitFramebuffer only supports color attachments right now (attachment=%d)",
|
MGLOG_E("BlitFramebuffer only supports color attachments right now (attachment=%d)",
|
||||||
static_cast<Int>(attachmentType));
|
static_cast<Int>(attachmentType));
|
||||||
@@ -1090,20 +1115,6 @@ void main() {
|
|||||||
|
|
||||||
auto* texture = attachment.GetTexture().get();
|
auto* texture = attachment.GetTexture().get();
|
||||||
MOBILEGL_ASSERT(texture != nullptr, "ResolveColorBlitBinding: texture attachment is null");
|
MOBILEGL_ASSERT(texture != nullptr, "ResolveColorBlitBinding: texture attachment is null");
|
||||||
outBinding.label = isReadFramebuffer ? "read" : "draw";
|
|
||||||
|
|
||||||
if (isDefaultFbo) {
|
|
||||||
outBinding.image = swapchainObject.GetImage(swapchainImageIndex);
|
|
||||||
outBinding.trackedLayout = nullptr;
|
|
||||||
outBinding.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
const auto extent = swapchainObject.GetExtent();
|
|
||||||
outBinding.extent = {static_cast<Int>(extent.width), static_cast<Int>(extent.height)};
|
|
||||||
outBinding.mipLevel = 0;
|
|
||||||
outBinding.mipLevelCount = 1;
|
|
||||||
outBinding.baseArrayLayer = 0;
|
|
||||||
outBinding.layerCount = 1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* resource = textureManager.SyncTextureAndGetDescriptor(*texture);
|
auto* resource = textureManager.SyncTextureAndGetDescriptor(*texture);
|
||||||
if (resource == nullptr) {
|
if (resource == nullptr) {
|
||||||
@@ -1134,8 +1145,7 @@ void main() {
|
|||||||
VkTextureManager& textureManager,
|
VkTextureManager& textureManager,
|
||||||
VkImageAspectFlags requiredAspectMask,
|
VkImageAspectFlags requiredAspectMask,
|
||||||
BlitImageBinding& outBinding) {
|
BlitImageBinding& outBinding) {
|
||||||
const Bool isDefaultFbo =
|
const Bool isDefaultFbo = fbo.IsDefaultFramebuffer();
|
||||||
(&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
|
|
||||||
const auto attachmentType = ResolveFramebufferCopyAttachmentType(fbo, isReadFramebuffer, requiredAspectMask);
|
const auto attachmentType = ResolveFramebufferCopyAttachmentType(fbo, isReadFramebuffer, requiredAspectMask);
|
||||||
if (attachmentType == FramebufferAttachmentType::None) {
|
if (attachmentType == FramebufferAttachmentType::None) {
|
||||||
MGLOG_E("BlitFramebuffer skipped: unsupported aspect mask=0x%x",
|
MGLOG_E("BlitFramebuffer skipped: unsupported aspect mask=0x%x",
|
||||||
@@ -1250,8 +1260,7 @@ void main() {
|
|||||||
VkTextureManager& textureManager,
|
VkTextureManager& textureManager,
|
||||||
VkImageAspectFlags requiredAspectMask,
|
VkImageAspectFlags requiredAspectMask,
|
||||||
BlitImageBinding& outBinding) {
|
BlitImageBinding& outBinding) {
|
||||||
const Bool isDefaultFbo =
|
const Bool isDefaultFbo = fbo.IsDefaultFramebuffer();
|
||||||
(&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
|
|
||||||
const auto attachmentType = ResolveFramebufferCopyAttachmentType(fbo, true, requiredAspectMask);
|
const auto attachmentType = ResolveFramebufferCopyAttachmentType(fbo, true, requiredAspectMask);
|
||||||
if (attachmentType == FramebufferAttachmentType::None) {
|
if (attachmentType == FramebufferAttachmentType::None) {
|
||||||
MGLOG_E("CopyTexSubImage2D skipped: unsupported source aspect mask=0x%x",
|
MGLOG_E("CopyTexSubImage2D skipped: unsupported source aspect mask=0x%x",
|
||||||
@@ -1545,7 +1554,7 @@ void main() {
|
|||||||
ProgramFactory::CompileOptionFlags flags = ProgramFactory::CompileOptionBit::PositionZRemap;
|
ProgramFactory::CompileOptionFlags flags = ProgramFactory::CompileOptionBit::PositionZRemap;
|
||||||
const auto& currentDrawFBO =
|
const auto& currentDrawFBO =
|
||||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||||
if (currentDrawFBO == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO) {
|
if (currentDrawFBO != nullptr && currentDrawFBO->IsDefaultFramebuffer()) {
|
||||||
flags |= ProgramFactory::CompileOptionBit::PositionYFlip;
|
flags |= ProgramFactory::CompileOptionBit::PositionYFlip;
|
||||||
switch (preTransform) {
|
switch (preTransform) {
|
||||||
case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
|
case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
|
||||||
@@ -2703,8 +2712,7 @@ void main() {
|
|||||||
const auto& drawFboBinding =
|
const auto& drawFboBinding =
|
||||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||||
MOBILEGL_ASSERT(drawFboBinding != nullptr, "GetOrCreatePipeline: draw framebuffer is null");
|
MOBILEGL_ASSERT(drawFboBinding != nullptr, "GetOrCreatePipeline: draw framebuffer is null");
|
||||||
const Bool isDefaultDrawFbo =
|
const Bool isDefaultDrawFbo = drawFboBinding->IsDefaultFramebuffer();
|
||||||
drawFboBinding.get() == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get();
|
|
||||||
const auto& drawBuffers = drawFboBinding->GetDrawBuffers();
|
const auto& drawBuffers = drawFboBinding->GetDrawBuffers();
|
||||||
auto resolveCompleteColorAttachmentTexture = [&](Uint32 drawBufferIndex) -> MG_State::GLState::ITextureObject* {
|
auto resolveCompleteColorAttachmentTexture = [&](Uint32 drawBufferIndex) -> MG_State::GLState::ITextureObject* {
|
||||||
if (isDefaultDrawFbo || drawBufferIndex >= drawBuffers.size()) {
|
if (isDefaultDrawFbo || drawBufferIndex >= drawBuffers.size()) {
|
||||||
@@ -3430,8 +3438,7 @@ void main() {
|
|||||||
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||||
GLenum filter) {
|
GLenum filter) {
|
||||||
const Bool drawIsDefaultFbo =
|
const Bool drawIsDefaultFbo = drawFbo.IsDefaultFramebuffer();
|
||||||
(&drawFbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
|
|
||||||
if (!drawIsDefaultFbo) {
|
if (!drawIsDefaultFbo) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -3607,10 +3614,8 @@ void main() {
|
|||||||
VkRenderPassManager::EndRenderPass(frame.commandBuffer);
|
VkRenderPassManager::EndRenderPass(frame.commandBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Bool readIsDefaultFbo =
|
const Bool readIsDefaultFbo = readFbo->IsDefaultFramebuffer();
|
||||||
(readFbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
|
const Bool drawIsDefaultFbo = drawFbo->IsDefaultFramebuffer();
|
||||||
const Bool drawIsDefaultFbo =
|
|
||||||
(drawFbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
|
|
||||||
if (isColorBlit && drawIsDefaultFbo &&
|
if (isColorBlit && drawIsDefaultFbo &&
|
||||||
RequiresShaderBlitToDefaultFramebuffer(m_swapchainObject.GetPreTransform())) {
|
RequiresShaderBlitToDefaultFramebuffer(m_swapchainObject.GetPreTransform())) {
|
||||||
if (TryBlitToDefaultFramebufferWithShader(frame, *readFbo, *drawFbo,
|
if (TryBlitToDefaultFramebufferWithShader(frame, *readFbo, *drawFbo,
|
||||||
@@ -3959,8 +3964,7 @@ void main() {
|
|||||||
VkRenderPassManager::EndRenderPass(frame.commandBuffer);
|
VkRenderPassManager::EndRenderPass(frame.commandBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Bool readIsDefaultFbo =
|
const Bool readIsDefaultFbo = readFbo->IsDefaultFramebuffer();
|
||||||
(readFbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
|
|
||||||
|
|
||||||
BlitImageBinding dstBinding{};
|
BlitImageBinding dstBinding{};
|
||||||
if (!ResolveTextureCopyDestinationBinding(*destinationTexture, static_cast<Uint32>(level), *m_textureManager,
|
if (!ResolveTextureCopyDestinationBinding(*destinationTexture, static_cast<Uint32>(level), *m_textureManager,
|
||||||
@@ -4161,8 +4165,7 @@ void main() {
|
|||||||
VkRenderPassManager::EndRenderPass(frame.commandBuffer);
|
VkRenderPassManager::EndRenderPass(frame.commandBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Bool readIsDefaultFbo =
|
const Bool readIsDefaultFbo = readFbo->IsDefaultFramebuffer();
|
||||||
(readFbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
|
|
||||||
BlitImageBinding srcBinding{};
|
BlitImageBinding srcBinding{};
|
||||||
if (!ResolveColorBlitBinding(*readFbo, true, m_imageIndexAcquired, m_swapchainObject, *m_textureManager,
|
if (!ResolveColorBlitBinding(*readFbo, true, m_imageIndexAcquired, m_swapchainObject, *m_textureManager,
|
||||||
srcBinding)) {
|
srcBinding)) {
|
||||||
@@ -5582,7 +5585,8 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClearAttachmentPayload clearPayload{};
|
ClearAttachmentPayload clearPayload{};
|
||||||
if (!m_clearManager->GetPendingClear(pending.key, clearPayload)) {
|
SharedPtr<MG_State::GLState::ITextureObject> liveTexture;
|
||||||
|
if (!m_clearManager->GetPendingClear(pending.key, clearPayload, liveTexture)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5595,7 +5599,7 @@ void main() {
|
|||||||
clearPayload.color.x(),
|
clearPayload.color.x(),
|
||||||
clearPayload.color.y(),
|
clearPayload.color.y(),
|
||||||
clearPayload.color.z(),
|
clearPayload.color.z(),
|
||||||
ResolveColorClearAlpha(pending.key.texture, clearPayload.color.w())
|
ResolveColorClearAlpha(liveTexture.get(), clearPayload.color.w())
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||||
|
|||||||
@@ -35,7 +35,10 @@ namespace MobileGL::MG_Impl {
|
|||||||
stencilTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, {{512, 512, 1}, 0});
|
stencilTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, {{512, 512, 1}, 0});
|
||||||
// stencilTex->SetMipmapLevel({{512, 512, 1}, 0, false, 0, {nullptr, 0}});
|
// stencilTex->SetMipmapLevel({{512, 512, 1}, 0, false, 0, {nullptr, 0}});
|
||||||
fbo0->AttachTexture(FramebufferAttachmentType::Color0, colorTex);
|
fbo0->AttachTexture(FramebufferAttachmentType::Color0, colorTex);
|
||||||
|
fbo0->AttachTexture(FramebufferAttachmentType::FrontLeft, colorTex);
|
||||||
|
fbo0->AttachTexture(FramebufferAttachmentType::FrontRight, colorTex);
|
||||||
fbo0->AttachTexture(FramebufferAttachmentType::BackLeft, colorTex);
|
fbo0->AttachTexture(FramebufferAttachmentType::BackLeft, colorTex);
|
||||||
|
fbo0->AttachTexture(FramebufferAttachmentType::BackRight, colorTex);
|
||||||
fbo0->AttachTexture(FramebufferAttachmentType::Depth, depthTex);
|
fbo0->AttachTexture(FramebufferAttachmentType::Depth, depthTex);
|
||||||
fbo0->AttachTexture(FramebufferAttachmentType::Stencil, stencilTex);
|
fbo0->AttachTexture(FramebufferAttachmentType::Stencil, stencilTex);
|
||||||
GLImpl::FramebufferImpl::pDefaultFramebufferInfo =
|
GLImpl::FramebufferImpl::pDefaultFramebufferInfo =
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ namespace MobileGL {
|
|||||||
Uint16 GetObjectVersion() const { return m_objectVersion; }
|
Uint16 GetObjectVersion() const { return m_objectVersion; }
|
||||||
|
|
||||||
Uint GetExternalIndex() const;
|
Uint GetExternalIndex() const;
|
||||||
|
Bool IsDefaultFramebuffer() const { return m_externalIndex == 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void BumpAttachmentVersion(FramebufferAttachmentType type);
|
void BumpAttachmentVersion(FramebufferAttachmentType type);
|
||||||
|
|||||||
@@ -13,9 +13,15 @@
|
|||||||
namespace MobileGL {
|
namespace MobileGL {
|
||||||
namespace MG_State {
|
namespace MG_State {
|
||||||
namespace GLState {
|
namespace GLState {
|
||||||
|
static std::atomic<Uint64> s_nextTextureLifetimeId = 1;
|
||||||
|
|
||||||
// TextureObjectBase implementations
|
// TextureObjectBase implementations
|
||||||
|
Uint64 TextureObjectBase::AllocateLifetimeId() {
|
||||||
|
return s_nextTextureLifetimeId.fetch_add(1, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
TextureObjectBase::TextureObjectBase(TextureTarget target, Uint externalIndex)
|
TextureObjectBase::TextureObjectBase(TextureTarget target, Uint externalIndex)
|
||||||
: m_target(target), m_externalIndex(externalIndex) {
|
: m_externalIndex(externalIndex), m_lifetimeId(AllocateLifetimeId()), m_target(target) {
|
||||||
m_sampler = MakeShared<SamplerObject>(0);
|
m_sampler = MakeShared<SamplerObject>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,6 +161,10 @@ namespace MobileGL {
|
|||||||
m_fixedSampleLocations = fixedSampleLocations;
|
m_fixedSampleLocations = fixedSampleLocations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Uint64 TextureObjectBase::GetLifetimeId() const {
|
||||||
|
return m_lifetimeId;
|
||||||
|
}
|
||||||
|
|
||||||
Uint TextureObjectWithOneMipmap::GetMipmapLevelCount() const {
|
Uint TextureObjectWithOneMipmap::GetMipmapLevelCount() const {
|
||||||
return m_textureStorage.GetLevelCount();
|
return m_textureStorage.GetLevelCount();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ namespace MobileGL::MG_State::GLState {
|
|||||||
virtual void SetSamples(Int samples) = 0;
|
virtual void SetSamples(Int samples) = 0;
|
||||||
virtual Bool HasFixedSampleLocations() const = 0;
|
virtual Bool HasFixedSampleLocations() const = 0;
|
||||||
virtual void SetFixedSampleLocations(Bool fixedSampleLocations) = 0;
|
virtual void SetFixedSampleLocations(Bool fixedSampleLocations) = 0;
|
||||||
|
virtual Uint64 GetLifetimeId() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const = 0;
|
virtual Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const = 0;
|
||||||
@@ -75,9 +76,13 @@ namespace MobileGL::MG_State::GLState {
|
|||||||
void SetSamples(Int samples) override;
|
void SetSamples(Int samples) override;
|
||||||
Bool HasFixedSampleLocations() const override;
|
Bool HasFixedSampleLocations() const override;
|
||||||
void SetFixedSampleLocations(Bool fixedSampleLocations) override;
|
void SetFixedSampleLocations(Bool fixedSampleLocations) override;
|
||||||
|
Uint64 GetLifetimeId() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
static Uint64 AllocateLifetimeId();
|
||||||
|
|
||||||
const Uint m_externalIndex;
|
const Uint m_externalIndex;
|
||||||
|
const Uint64 m_lifetimeId;
|
||||||
const TextureTarget m_target = TextureTarget::Unknown;
|
const TextureTarget m_target = TextureTarget::Unknown;
|
||||||
TextureInternalFormat m_internalFormat = TextureInternalFormat::Unknown;
|
TextureInternalFormat m_internalFormat = TextureInternalFormat::Unknown;
|
||||||
SharedPtr<SamplerObject> m_sampler = nullptr;
|
SharedPtr<SamplerObject> m_sampler = nullptr;
|
||||||
|
|||||||
@@ -105,6 +105,20 @@ TEST_F(FramebufferTest, CreateFramebuffersCreatesObjectsImmediately) {
|
|||||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(FramebufferTest, DefaultFramebufferIdentityTracksFramebufferNameZero) {
|
||||||
|
const auto defaultFramebuffer = MG_State::pGLContext->GetFramebufferObject(0);
|
||||||
|
ASSERT_NE(defaultFramebuffer, nullptr);
|
||||||
|
EXPECT_TRUE(defaultFramebuffer->IsDefaultFramebuffer());
|
||||||
|
const auto defaultFramebufferCopy = *defaultFramebuffer;
|
||||||
|
EXPECT_TRUE(defaultFramebufferCopy.IsDefaultFramebuffer());
|
||||||
|
|
||||||
|
GLuint framebuffer = 0;
|
||||||
|
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
|
||||||
|
const auto userFramebuffer = MG_State::pGLContext->GetFramebufferObject(framebuffer);
|
||||||
|
ASSERT_NE(userFramebuffer, nullptr);
|
||||||
|
EXPECT_FALSE(userFramebuffer->IsDefaultFramebuffer());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(FramebufferTest, NamedFramebufferTextureAttachesWithoutChangingBindings) {
|
TEST_F(FramebufferTest, NamedFramebufferTextureAttachesWithoutChangingBindings) {
|
||||||
GLuint framebuffer = 0;
|
GLuint framebuffer = 0;
|
||||||
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
|
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
|
||||||
@@ -259,6 +273,46 @@ TEST_F(FramebufferTest, NamedFramebufferDrawBuffersDoNotModifyDefaultFramebuffer
|
|||||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(FramebufferTest, DefaultFramebufferReadBufferAcceptsGLBackAlias) {
|
||||||
|
const auto defaultRead =
|
||||||
|
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
|
||||||
|
|
||||||
|
MG_Impl::GLImpl::ReadBuffer(GL_BACK);
|
||||||
|
|
||||||
|
EXPECT_EQ(defaultRead->GetReadBuffer(), FramebufferAttachmentType::BackLeft);
|
||||||
|
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FramebufferTest, DefaultFramebufferDrawBufferAcceptsGLFrontAlias) {
|
||||||
|
const auto defaultDraw =
|
||||||
|
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||||
|
|
||||||
|
MG_Impl::GLImpl::DrawBuffer(GL_FRONT);
|
||||||
|
|
||||||
|
EXPECT_EQ(defaultDraw->GetDrawBuffers()[0], FramebufferAttachmentType::FrontLeft);
|
||||||
|
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FramebufferTest, DefaultFramebufferProvidesTextureAttachmentsForFrontAndBackAliases) {
|
||||||
|
const auto defaultFramebuffer =
|
||||||
|
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||||
|
ASSERT_NE(defaultFramebuffer, nullptr);
|
||||||
|
|
||||||
|
const auto& frontLeft = defaultFramebuffer->GetAttachment(FramebufferAttachmentType::FrontLeft);
|
||||||
|
const auto& frontRight = defaultFramebuffer->GetAttachment(FramebufferAttachmentType::FrontRight);
|
||||||
|
const auto& backLeft = defaultFramebuffer->GetAttachment(FramebufferAttachmentType::BackLeft);
|
||||||
|
const auto& backRight = defaultFramebuffer->GetAttachment(FramebufferAttachmentType::BackRight);
|
||||||
|
|
||||||
|
EXPECT_TRUE(frontLeft.IsTexture());
|
||||||
|
EXPECT_TRUE(frontRight.IsTexture());
|
||||||
|
EXPECT_TRUE(backLeft.IsTexture());
|
||||||
|
EXPECT_TRUE(backRight.IsTexture());
|
||||||
|
EXPECT_TRUE(frontLeft.IsComplete());
|
||||||
|
EXPECT_TRUE(frontRight.IsComplete());
|
||||||
|
EXPECT_TRUE(backLeft.IsComplete());
|
||||||
|
EXPECT_TRUE(backRight.IsComplete());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(FramebufferTest, ClearNamedFramebufferfvUsesNamedObjectWithoutChangingBindings) {
|
TEST_F(FramebufferTest, ClearNamedFramebufferfvUsesNamedObjectWithoutChangingBindings) {
|
||||||
GLuint framebuffer = 0;
|
GLuint framebuffer = 0;
|
||||||
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
|
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
|
||||||
|
|||||||
@@ -165,6 +165,18 @@ TEST(DirectVulkanSanity, AdvertisesTextureStorageForDirectStateAccess) {
|
|||||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_texture_storage), extensions.end());
|
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_texture_storage), extensions.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(DirectVulkanSanity, RenderPassExtentUsesSwapchainSizeOnlyForDefaultFramebuffer) {
|
||||||
|
using MobileGL::MG_Backend::DirectVulkan::ResolveRenderPassFramebufferExtent;
|
||||||
|
|
||||||
|
const MobileGL::TextureSize attachmentExtent = {512, 512, 1};
|
||||||
|
const VkExtent2D swapchainExtent = {3200u, 1440u};
|
||||||
|
|
||||||
|
EXPECT_EQ(ResolveRenderPassFramebufferExtent(true, attachmentExtent, swapchainExtent),
|
||||||
|
MobileGL::IntVec2(3200, 1440));
|
||||||
|
EXPECT_EQ(ResolveRenderPassFramebufferExtent(false, attachmentExtent, swapchainExtent),
|
||||||
|
MobileGL::IntVec2(512, 512));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(DirectVulkanSanity, AdvertisesVoxyRequiredRenderingExtensionsWithoutRaisingGLVersion) {
|
TEST(DirectVulkanSanity, AdvertisesVoxyRequiredRenderingExtensionsWithoutRaisingGLVersion) {
|
||||||
MobileGL::MG_Backend::DirectVulkan::BackendObject_DirectVulkan backend;
|
MobileGL::MG_Backend::DirectVulkan::BackendObject_DirectVulkan backend;
|
||||||
const auto& rendererInfo = backend.GetRendererInfo().RendererGLInfo;
|
const auto& rendererInfo = backend.GetRendererInfo().RendererGLInfo;
|
||||||
|
|||||||
@@ -18,3 +18,21 @@ target_link_libraries(
|
|||||||
|
|
||||||
include(GoogleTest)
|
include(GoogleTest)
|
||||||
gtest_discover_tests(TextureTest)
|
gtest_discover_tests(TextureTest)
|
||||||
|
|
||||||
|
add_executable(
|
||||||
|
VkClearManagerTest
|
||||||
|
VkClearManagerTest.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(VkClearManagerTest PRIVATE
|
||||||
|
${MGL_ROOT}/include
|
||||||
|
${MGL_ROOT}/MobileGL
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
VkClearManagerTest PRIVATE
|
||||||
|
GTest::gtest_main
|
||||||
|
${LINK_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
gtest_discover_tests(VkClearManagerTest)
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Test/Texture/VkClearManagerTest.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "Includes.h"
|
||||||
|
#include "Init.h"
|
||||||
|
#include <MG_Backend/DirectVulkan/Renderer/VkClearManager.h>
|
||||||
|
#include <MG_Impl/GLImpl/Texture/GL_Texture.h>
|
||||||
|
#include <MG_State/GLState/Core.h>
|
||||||
|
|
||||||
|
using namespace MobileGL;
|
||||||
|
using namespace MobileGL::MG_Backend::DirectVulkan;
|
||||||
|
|
||||||
|
class VkClearManagerTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
void SetUp() override { MobileGL::Initialize(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(VkClearManagerTest, CollectGarbageRemovesExpiredTexturesAndTheirPendingClears) {
|
||||||
|
VkClearManager clearManager;
|
||||||
|
ASSERT_TRUE(clearManager.Initialize());
|
||||||
|
|
||||||
|
constexpr SizeT kTextureCount = 64;
|
||||||
|
Vector<GLuint> textureNames(kTextureCount, 0);
|
||||||
|
Vector<PendingClearKey> pendingKeys;
|
||||||
|
pendingKeys.reserve(kTextureCount);
|
||||||
|
|
||||||
|
const ClearAttachmentPayload clearPayload{
|
||||||
|
.mask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,
|
||||||
|
.color = FloatVec4(0.25f, 0.5f, 0.75f, 1.0f),
|
||||||
|
.depth = 0.5f,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (SizeT i = 0; i < kTextureCount; ++i) {
|
||||||
|
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &textureNames[i]);
|
||||||
|
ASSERT_NE(textureNames[i], 0u);
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto textureObject = MG_State::pGLContext->GetTextureObject(textureNames[i]);
|
||||||
|
ASSERT_NE(textureObject, nullptr);
|
||||||
|
|
||||||
|
const PendingClearKey key = VkClearManager::MakePendingClearKey(textureObject.get());
|
||||||
|
clearManager.QueueClear(clearPayload, textureObject);
|
||||||
|
|
||||||
|
EXPECT_TRUE(clearManager.HasPendingClear(key));
|
||||||
|
pendingKeys.emplace_back(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_Impl::GLImpl::DeleteTextures(static_cast<GLsizei>(textureNames.size()), textureNames.data());
|
||||||
|
|
||||||
|
for (Int i = 0; i < 255; ++i) {
|
||||||
|
EXPECT_EQ(clearManager.CollectGarbage(), 0u);
|
||||||
|
}
|
||||||
|
EXPECT_EQ(clearManager.CollectGarbage(), kTextureCount);
|
||||||
|
|
||||||
|
ClearAttachmentPayload outPayload{};
|
||||||
|
for (const auto& key : pendingKeys) {
|
||||||
|
EXPECT_FALSE(clearManager.HasPendingClear(key));
|
||||||
|
EXPECT_FALSE(clearManager.GetPendingClear(key, outPayload));
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint freshTexture = 0;
|
||||||
|
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &freshTexture);
|
||||||
|
ASSERT_NE(freshTexture, 0u);
|
||||||
|
|
||||||
|
const auto freshTextureObject = MG_State::pGLContext->GetTextureObject(freshTexture);
|
||||||
|
ASSERT_NE(freshTextureObject, nullptr);
|
||||||
|
EXPECT_FALSE(clearManager.HasPendingClear(freshTextureObject.get()));
|
||||||
|
|
||||||
|
MG_Impl::GLImpl::DeleteTextures(1, &freshTexture);
|
||||||
|
clearManager.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VkClearManagerTest, StalePendingClearsAreRejectedBeforePeriodicGarbageCollection) {
|
||||||
|
VkClearManager clearManager;
|
||||||
|
ASSERT_TRUE(clearManager.Initialize());
|
||||||
|
|
||||||
|
GLuint texture = 0;
|
||||||
|
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
|
||||||
|
ASSERT_NE(texture, 0u);
|
||||||
|
|
||||||
|
PendingClearKey key{};
|
||||||
|
{
|
||||||
|
const auto textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||||
|
ASSERT_NE(textureObject, nullptr);
|
||||||
|
|
||||||
|
key = VkClearManager::MakePendingClearKey(textureObject.get());
|
||||||
|
clearManager.QueueClear(ClearAttachmentPayload{
|
||||||
|
.mask = GL_COLOR_BUFFER_BIT,
|
||||||
|
.color = FloatVec4(1.0f, 0.25f, 0.5f, 0.75f),
|
||||||
|
}, textureObject);
|
||||||
|
EXPECT_TRUE(clearManager.HasPendingClear(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_Impl::GLImpl::DeleteTextures(1, &texture);
|
||||||
|
|
||||||
|
ClearAttachmentPayload outPayload{};
|
||||||
|
EXPECT_FALSE(clearManager.HasPendingClear(key));
|
||||||
|
EXPECT_FALSE(clearManager.GetPendingClear(key, outPayload));
|
||||||
|
EXPECT_FALSE(clearManager.HasPendingClear(key));
|
||||||
|
|
||||||
|
clearManager.Shutdown();
|
||||||
|
}
|
||||||
@@ -36,10 +36,12 @@ namespace MobileGL {
|
|||||||
return FramebufferAttachmentType::Depth;
|
return FramebufferAttachmentType::Depth;
|
||||||
case GL_STENCIL_ATTACHMENT:
|
case GL_STENCIL_ATTACHMENT:
|
||||||
return FramebufferAttachmentType::Stencil;
|
return FramebufferAttachmentType::Stencil;
|
||||||
|
case GL_FRONT:
|
||||||
case GL_FRONT_LEFT:
|
case GL_FRONT_LEFT:
|
||||||
return FramebufferAttachmentType::FrontLeft;
|
return FramebufferAttachmentType::FrontLeft;
|
||||||
case GL_FRONT_RIGHT:
|
case GL_FRONT_RIGHT:
|
||||||
return FramebufferAttachmentType::FrontRight;
|
return FramebufferAttachmentType::FrontRight;
|
||||||
|
case GL_BACK:
|
||||||
case GL_BACK_LEFT:
|
case GL_BACK_LEFT:
|
||||||
return FramebufferAttachmentType::BackLeft;
|
return FramebufferAttachmentType::BackLeft;
|
||||||
case GL_BACK_RIGHT:
|
case GL_BACK_RIGHT:
|
||||||
|
|||||||
Reference in New Issue
Block a user