mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 22:28:32 +09:00
[Fix] (MG_Backend/DirectVulkan): use hash to save active render pass
This commit is contained in:
@@ -99,7 +99,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
auto* activeRenderPass = GetActiveRenderPass();
|
auto* activeRenderPass = GetActiveRenderPass();
|
||||||
auto compatibilityHash = ComputeHash(fbo, swapchainImageIndex, false);
|
auto compatibilityHash = ComputeHash(fbo, swapchainImageIndex, false);
|
||||||
if (activeRenderPass != nullptr && activeRenderPass->CompatibleWith(compatibilityHash)) {
|
if (activeRenderPass != nullptr && activeRenderPass->CompatibleWith(compatibilityHash)) {
|
||||||
return *activeRenderPass;
|
auto activeIt = m_renderPasses.find(activeRenderPass->hash);
|
||||||
|
MOBILEGL_ASSERT(activeIt != m_renderPasses.end(),
|
||||||
|
"GetOrCreateRenderPass: active render pass hash=0x%llx is missing from cache",
|
||||||
|
static_cast<unsigned long long>(activeRenderPass->hash));
|
||||||
|
return activeIt->second;
|
||||||
}
|
}
|
||||||
auto hash = ComputeHash(fbo, swapchainImageIndex, true);
|
auto hash = ComputeHash(fbo, swapchainImageIndex, true);
|
||||||
auto it = m_renderPasses.find(hash);
|
auto it = m_renderPasses.find(hash);
|
||||||
@@ -157,9 +161,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
desc.initialLayout = hasClear ?
|
|
||||||
VK_IMAGE_LAYOUT_UNDEFINED :
|
|
||||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
|
||||||
desc.finalLayout = isDefaultFbo ?
|
desc.finalLayout = isDefaultFbo ?
|
||||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR :
|
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR :
|
||||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
@@ -178,6 +179,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
const auto& swapchainViews = m_swapchainObject.GetImageViews();
|
const auto& swapchainViews = m_swapchainObject.GetImageViews();
|
||||||
MOBILEGL_ASSERT(swapchainImageIndex < swapchainViews.size(),
|
MOBILEGL_ASSERT(swapchainImageIndex < swapchainViews.size(),
|
||||||
"GetOrCreateRenderPass: swapchain image index out of range");
|
"GetOrCreateRenderPass: swapchain image index out of range");
|
||||||
|
desc.initialLayout = hasClear ?
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED :
|
||||||
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
attachmentViews[i] = swapchainViews[swapchainImageIndex];
|
attachmentViews[i] = swapchainViews[swapchainImageIndex];
|
||||||
} else {
|
} else {
|
||||||
textureResources[i] = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
textureResources[i] = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
||||||
@@ -186,6 +190,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
MOBILEGL_ASSERT(hasClear || textureResources[i]->layout != VK_IMAGE_LAYOUT_UNDEFINED,
|
MOBILEGL_ASSERT(hasClear || textureResources[i]->layout != VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
"GetOrCreateRenderPass: color attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD (attachment=%d)",
|
"GetOrCreateRenderPass: color attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD (attachment=%d)",
|
||||||
texture->GetExternalIndex(), i);
|
texture->GetExternalIndex(), i);
|
||||||
|
desc.initialLayout = hasClear ?
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED :
|
||||||
|
textureResources[i]->layout;
|
||||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||||
.texture = texture,
|
.texture = texture,
|
||||||
.finalLayout = desc.finalLayout,
|
.finalLayout = desc.finalLayout,
|
||||||
@@ -219,6 +226,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload);
|
Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload);
|
||||||
Bool clearDepth = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Depth;
|
Bool clearDepth = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Depth;
|
||||||
Bool clearStencil = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Stencil;
|
Bool clearStencil = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Stencil;
|
||||||
|
VkImageLayout trackedDepthLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
|
if (!isDefaultFbo) {
|
||||||
|
depthTextureResource = m_textureManager.SyncTextureAndGetDescriptor(texture);
|
||||||
|
MOBILEGL_ASSERT(depthTextureResource,
|
||||||
|
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment");
|
||||||
|
trackedDepthLayout = depthTextureResource->layout;
|
||||||
|
}
|
||||||
depthAttachmentDescription.flags = 0;
|
depthAttachmentDescription.flags = 0;
|
||||||
depthAttachmentDescription.format =
|
depthAttachmentDescription.format =
|
||||||
MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
|
MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
|
||||||
@@ -231,15 +245,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VK_ATTACHMENT_LOAD_OP_CLEAR :
|
VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||||
VK_ATTACHMENT_LOAD_OP_LOAD;
|
VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||||
depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
// UNDEFINED is only valid when both depth and stencil are discarded/cleared.
|
|
||||||
depthAttachmentDescription.initialLayout = (clearDepth && clearStencil) ?
|
|
||||||
VK_IMAGE_LAYOUT_UNDEFINED :
|
|
||||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
|
||||||
depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
MOBILEGL_ASSERT(!(depthAttachmentDescription.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD &&
|
if (!isDefaultFbo && trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||||
depthAttachmentDescription.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED),
|
if (!clearDepth) {
|
||||||
"GetOrCreateRenderPass: invalid depth-stencil state (stencil LOAD + initialLayout UNDEFINED), textureId=%d",
|
depthAttachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
texture.GetExternalIndex());
|
}
|
||||||
|
if (!clearStencil) {
|
||||||
|
depthAttachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
depthAttachmentDescription.initialLayout =
|
||||||
|
(clearDepth && clearStencil) || (!isDefaultFbo && trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED) ?
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED :
|
||||||
|
trackedDepthLayout;
|
||||||
if (hasClear) {
|
if (hasClear) {
|
||||||
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
||||||
.attachmentIndex = depthAttachmentIndex,
|
.attachmentIndex = depthAttachmentIndex,
|
||||||
@@ -249,9 +267,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (isDefaultFbo) {
|
if (isDefaultFbo) {
|
||||||
attachmentViews.emplace_back(m_swapchainObject.GetDepthStencilImageView(swapchainImageIndex));
|
attachmentViews.emplace_back(m_swapchainObject.GetDepthStencilImageView(swapchainImageIndex));
|
||||||
} else {
|
} else {
|
||||||
depthTextureResource = m_textureManager.SyncTextureAndGetDescriptor(texture);
|
|
||||||
MOBILEGL_ASSERT(depthTextureResource,
|
|
||||||
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment");
|
|
||||||
MOBILEGL_ASSERT(clearDepth || clearStencil || depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED,
|
MOBILEGL_ASSERT(clearDepth || clearStencil || depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
"GetOrCreateRenderPass: depth attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD",
|
"GetOrCreateRenderPass: depth attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD",
|
||||||
texture.GetExternalIndex());
|
texture.GetExternalIndex());
|
||||||
@@ -314,6 +329,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferCreateInfo, nullptr, &framebuffer));
|
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferCreateInfo, nullptr, &framebuffer));
|
||||||
IntVec2 extent = {width, height};
|
IntVec2 extent = {width, height};
|
||||||
RenderPassEntry renderPassEntry {
|
RenderPassEntry renderPassEntry {
|
||||||
|
hash,
|
||||||
renderPass,
|
renderPass,
|
||||||
framebuffer,
|
framebuffer,
|
||||||
compatibilityHash,
|
compatibilityHash,
|
||||||
@@ -372,13 +388,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
|
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
|
||||||
s_clearManager->PopPendingClear(pending.texture);
|
s_clearManager->PopPendingClear(pending.texture);
|
||||||
}
|
}
|
||||||
s_activeRenderPass = &renderPassEntry;
|
s_activeRenderPass.hash = renderPassEntry.hash;
|
||||||
|
s_activeRenderPass.compatibilityHash = renderPassEntry.compatibilityHash;
|
||||||
|
s_activeRenderPass.trackedAttachmentLayouts = renderPassEntry.trackedAttachmentLayouts;
|
||||||
|
s_activeRenderPass.extent = renderPassEntry.extent;
|
||||||
|
s_hasActiveRenderPass = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) {
|
Bool VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) {
|
||||||
auto* activeRenderPass = s_activeRenderPass;
|
auto* activeRenderPass = GetActiveRenderPass();
|
||||||
vkCmdEndRenderPass(commandBuffer);
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
if (activeRenderPass != nullptr && !activeRenderPass->trackedAttachmentLayouts.empty()) {
|
if (activeRenderPass != nullptr && !activeRenderPass->trackedAttachmentLayouts.empty()) {
|
||||||
MOBILEGL_ASSERT(s_textureManager != nullptr, "EndRenderPass: texture manager is null");
|
MOBILEGL_ASSERT(s_textureManager != nullptr, "EndRenderPass: texture manager is null");
|
||||||
@@ -386,11 +406,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
s_textureManager->UpdateTrackedImageLayout(trackedAttachment.texture, trackedAttachment.finalLayout);
|
s_textureManager->UpdateTrackedImageLayout(trackedAttachment.texture, trackedAttachment.finalLayout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s_activeRenderPass = nullptr;
|
s_activeRenderPass = {};
|
||||||
|
s_hasActiveRenderPass = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderPassEntry* VkRenderPassManager::GetActiveRenderPass() {
|
ActiveRenderPassInfo* VkRenderPassManager::GetActiveRenderPass() {
|
||||||
return s_activeRenderPass;
|
return s_hasActiveRenderPass ? &s_activeRenderPass : nullptr;
|
||||||
}
|
}
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
struct RenderPassEntry {
|
struct RenderPassEntry {
|
||||||
static inline VkDevice s_device;
|
static inline VkDevice s_device;
|
||||||
static inline Vector<VkTextureManager::TextureResource*> s_textureResourcesScratch;
|
static inline Vector<VkTextureManager::TextureResource*> s_textureResourcesScratch;
|
||||||
|
Uint64 hash = 0;
|
||||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||||
Uint64 compatibilityHash = 0;
|
Uint64 compatibilityHash = 0;
|
||||||
@@ -44,6 +45,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
RenderPassEntry() = default;
|
RenderPassEntry() = default;
|
||||||
RenderPassEntry(const RenderPassEntry&) = delete;
|
RenderPassEntry(const RenderPassEntry&) = delete;
|
||||||
RenderPassEntry(RenderPassEntry&& that) noexcept {
|
RenderPassEntry(RenderPassEntry&& that) noexcept {
|
||||||
|
std::swap(hash, that.hash);
|
||||||
std::swap(renderPass, that.renderPass);
|
std::swap(renderPass, that.renderPass);
|
||||||
std::swap(framebuffer, that.framebuffer);
|
std::swap(framebuffer, that.framebuffer);
|
||||||
std::swap(compatibilityHash, that.compatibilityHash);
|
std::swap(compatibilityHash, that.compatibilityHash);
|
||||||
@@ -54,6 +56,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
std::swap(subpass, that.subpass);
|
std::swap(subpass, that.subpass);
|
||||||
}
|
}
|
||||||
RenderPassEntry(
|
RenderPassEntry(
|
||||||
|
Uint64 hash,
|
||||||
VkRenderPass renderpass,
|
VkRenderPass renderpass,
|
||||||
VkFramebuffer framebuffer,
|
VkFramebuffer framebuffer,
|
||||||
Uint64 compatibilityHash,
|
Uint64 compatibilityHash,
|
||||||
@@ -61,6 +64,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
const Vector<TrackedAttachmentLayoutInfo>& trackedAttachmentLayouts,
|
const Vector<TrackedAttachmentLayoutInfo>& trackedAttachmentLayouts,
|
||||||
Uint32 attachmentCount,
|
Uint32 attachmentCount,
|
||||||
IntVec2 extent, int subpass):
|
IntVec2 extent, int subpass):
|
||||||
|
hash(hash),
|
||||||
renderPass(renderpass),
|
renderPass(renderpass),
|
||||||
framebuffer(framebuffer),
|
framebuffer(framebuffer),
|
||||||
compatibilityHash(compatibilityHash),
|
compatibilityHash(compatibilityHash),
|
||||||
@@ -89,6 +93,21 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ActiveRenderPassInfo {
|
||||||
|
Uint64 hash = 0;
|
||||||
|
Uint64 compatibilityHash = 0;
|
||||||
|
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
|
||||||
|
IntVec2 extent = {0, 0};
|
||||||
|
|
||||||
|
Bool CompatibleWith(const RenderPassEntry& that) const {
|
||||||
|
return compatibilityHash == that.compatibilityHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool CompatibleWith(Uint64 thatCompatibilityHash) const {
|
||||||
|
return compatibilityHash == thatCompatibilityHash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class VkRenderPassManager {
|
class VkRenderPassManager {
|
||||||
public:
|
public:
|
||||||
using HashType = Uint64;
|
using HashType = Uint64;
|
||||||
@@ -107,7 +126,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
RenderPassEntry& GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex);
|
RenderPassEntry& GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex);
|
||||||
static Bool BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry);
|
static Bool BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry);
|
||||||
static Bool EndRenderPass(VkCommandBuffer commandBuffer);
|
static Bool EndRenderPass(VkCommandBuffer commandBuffer);
|
||||||
static RenderPassEntry* GetActiveRenderPass();
|
static ActiveRenderPassInfo* GetActiveRenderPass();
|
||||||
private:
|
private:
|
||||||
VkDevice m_device = VK_NULL_HANDLE;
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
const VulkanRendererConfig& m_config;
|
const VulkanRendererConfig& m_config;
|
||||||
@@ -116,7 +135,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
const SwapchainObject& m_swapchainObject;
|
const SwapchainObject& m_swapchainObject;
|
||||||
UnorderedMap<Uint64, RenderPassEntry> m_renderPasses;
|
UnorderedMap<Uint64, RenderPassEntry> m_renderPasses;
|
||||||
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||||
static inline RenderPassEntry* s_activeRenderPass = nullptr;
|
static inline ActiveRenderPassInfo s_activeRenderPass{};
|
||||||
|
static inline Bool s_hasActiveRenderPass = false;
|
||||||
static inline VkClearManager* s_clearManager = nullptr;
|
static inline VkClearManager* s_clearManager = nullptr;
|
||||||
static inline VkTextureManager* s_textureManager = nullptr;
|
static inline VkTextureManager* s_textureManager = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
resource.~TextureResource();
|
resource.Reset();
|
||||||
|
|
||||||
auto aspect = GetAspectMaskForFormat(format);
|
auto aspect = GetAspectMaskForFormat(format);
|
||||||
|
|
||||||
|
|||||||
@@ -425,7 +425,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
// Begin render pass, and handle clear
|
// Begin render pass, and handle clear
|
||||||
|
|
||||||
if (activeRenderPass && (activeRenderPass == &renderPassEntry || activeRenderPass->CompatibleWith(renderPassEntry))) {
|
if (activeRenderPass && activeRenderPass->CompatibleWith(renderPassEntry)) {
|
||||||
ClearAttachmentsOnActiveRenderPass(frame.commandBuffer, renderPassEntry);
|
ClearAttachmentsOnActiveRenderPass(frame.commandBuffer, renderPassEntry);
|
||||||
} else {
|
} else {
|
||||||
// No active render pass or active one not compatible.
|
// No active render pass or active one not compatible.
|
||||||
|
|||||||
Reference in New Issue
Block a user