[Refactor] (MG_Backend/DirectVulkan): Move renderpass/framebuffer vk management out of VulkanRenderer.

This commit is contained in:
BZLZHH
2026-02-21 20:53:33 +08:00
parent d5940f40be
commit 3c66016489
6 changed files with 483 additions and 306 deletions
@@ -240,16 +240,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return false;
}
Bool VkFramebufferManager::GetOffscreenRenderTarget(Uint glFboExternalIndex, VkRenderPass& outRenderPass,
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
VkFormat& outDepthStencilFormat) const {
Bool VkFramebufferManager::GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView,
VkFormat& outColorFormat, VkImageView& outDepthStencilView,
VkFormat& outDepthStencilFormat, VkExtent2D& outExtent) const {
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
if (it == m_offscreenColorTargets.end() || it->second.framebuffer == VK_NULL_HANDLE ||
it->second.renderPassLoad == VK_NULL_HANDLE) {
if (it == m_offscreenColorTargets.end() || it->second.imageView == VK_NULL_HANDLE) {
return false;
}
outRenderPass = it->second.renderPassLoad;
outFramebuffer = it->second.framebuffer;
outColorView = it->second.imageView;
outColorFormat = it->second.format;
outDepthStencilView = it->second.depthStencilImageView;
outExtent = it->second.extent;
outDepthStencilFormat = it->second.depthStencilFormat;
return true;
@@ -378,76 +378,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
"vkCreateImageView(offscreen depth/stencil)");
}
VkAttachmentDescription colorAttachmentDesc{};
colorAttachmentDesc.format = format;
colorAttachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
colorAttachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorAttachmentDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference colorAttachmentRef{};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
VkAttachmentDescription depthAttachmentDesc{};
VkAttachmentReference depthAttachmentRef{};
Array<VkAttachmentDescription, 2> attachments{};
attachments[0] = colorAttachmentDesc;
Uint32 attachmentCount = 1;
if (hasDepthStencil) {
depthAttachmentDesc.format = depthStencilFormat;
depthAttachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
depthAttachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
depthAttachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
depthAttachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachmentDesc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthAttachmentDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthAttachmentRef.attachment = 1;
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
subpass.pDepthStencilAttachment = &depthAttachmentRef;
attachments[1] = depthAttachmentDesc;
attachmentCount = 2;
}
VkRenderPassCreateInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = attachmentCount;
renderPassInfo.pAttachments = attachments.data();
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
VK_VERIFY(vkCreateRenderPass(m_device, &renderPassInfo, nullptr, &target.renderPassLoad),
"vkCreateRenderPass(offscreen)");
Array<VkImageView, 2> framebufferAttachments{};
framebufferAttachments[0] = target.imageView;
Uint32 framebufferAttachmentCount = 1;
if (hasDepthStencil) {
framebufferAttachments[1] = target.depthStencilImageView;
framebufferAttachmentCount = 2;
}
VkFramebufferCreateInfo framebufferInfo{};
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferInfo.renderPass = target.renderPassLoad;
framebufferInfo.attachmentCount = framebufferAttachmentCount;
framebufferInfo.pAttachments = framebufferAttachments.data();
framebufferInfo.width = static_cast<Uint32>(size.x());
framebufferInfo.height = static_cast<Uint32>(size.y());
framebufferInfo.layers = 1;
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &target.framebuffer),
"vkCreateFramebuffer(offscreen)");
target.layout = VK_IMAGE_LAYOUT_UNDEFINED;
target.extent = {static_cast<Uint32>(size.x()), static_cast<Uint32>(size.y())};
target.format = format;
@@ -461,14 +391,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
void VkFramebufferManager::DestroyOffscreenColorTarget(OffscreenColorTarget& target) {
if (target.framebuffer != VK_NULL_HANDLE) {
vkDestroyFramebuffer(m_device, target.framebuffer, nullptr);
target.framebuffer = VK_NULL_HANDLE;
}
if (target.renderPassLoad != VK_NULL_HANDLE) {
vkDestroyRenderPass(m_device, target.renderPassLoad, nullptr);
target.renderPassLoad = VK_NULL_HANDLE;
}
if (target.imageView != VK_NULL_HANDLE) {
vkDestroyImageView(m_device, target.imageView, nullptr);
target.imageView = VK_NULL_HANDLE;
@@ -39,9 +39,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Bool GetOffscreenDepthStencilImage(Uint glFboExternalIndex, VkImage& outImage, VkExtent2D& outExtent,
VkFormat& outFormat) const;
Bool GetOffscreenColorViewByTexture(Uint textureExternalIndex, VkImageView& outImageView) const;
Bool GetOffscreenRenderTarget(Uint glFboExternalIndex, VkRenderPass& outRenderPass,
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
VkFormat& outDepthStencilFormat) const;
Bool GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView, VkFormat& outColorFormat,
VkImageView& outDepthStencilView, VkFormat& outDepthStencilFormat,
VkExtent2D& outExtent) const;
private:
struct OffscreenColorTarget {
@@ -56,8 +56,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkImageView depthStencilImageView = VK_NULL_HANDLE;
VkImageLayout depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
VkRenderPass renderPassLoad = VK_NULL_HANDLE;
VkFramebuffer framebuffer = VK_NULL_HANDLE;
Uint16 glObjectVersion = 0;
Uint colorTextureExternalIndex = 0;
};
@@ -27,6 +27,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
void VkRenderPassManager::Shutdown() {
DestroyDefaultFramebuffers();
for (auto& [_, target] : m_offscreenRenderTargets) {
DestroyOffscreenRenderTarget(target);
}
m_offscreenRenderTargets.clear();
if (m_device != VK_NULL_HANDLE) {
if (m_renderPassClear != VK_NULL_HANDLE) {
vkDestroyRenderPass(m_device, m_renderPassClear, nullptr);
@@ -40,9 +46,202 @@ namespace MobileGL::MG_Backend::DirectVulkan {
m_renderPassLoad = VK_NULL_HANDLE;
m_colorFormat = VK_FORMAT_UNDEFINED;
m_depthStencilFormat = VK_FORMAT_UNDEFINED;
m_defaultExtent = {0, 0};
m_device = VK_NULL_HANDLE;
}
Bool VkRenderPassManager::RecreateDefaultFramebuffers(const Vector<VkImageView>& colorViews,
const Vector<VkImageView>& depthStencilViews,
VkExtent2D extent) {
DestroyDefaultFramebuffers();
if (m_device == VK_NULL_HANDLE || m_renderPassLoad == VK_NULL_HANDLE || extent.width == 0 ||
extent.height == 0 || colorViews.empty() || colorViews.size() != depthStencilViews.size()) {
return false;
}
m_defaultFramebuffers.reserve(colorViews.size());
for (SizeT i = 0; i < colorViews.size(); ++i) {
if (colorViews[i] == VK_NULL_HANDLE || depthStencilViews[i] == VK_NULL_HANDLE) {
DestroyDefaultFramebuffers();
return false;
}
VkImageView attachments[] = {colorViews[i], depthStencilViews[i]};
VkFramebufferCreateInfo createInfo{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
createInfo.renderPass = m_renderPassLoad;
createInfo.attachmentCount = static_cast<Uint32>(std::size(attachments));
createInfo.pAttachments = attachments;
createInfo.width = extent.width;
createInfo.height = extent.height;
createInfo.layers = 1;
VkFramebuffer framebuffer = VK_NULL_HANDLE;
if (vkCreateFramebuffer(m_device, &createInfo, nullptr, &framebuffer) != VK_SUCCESS) {
DestroyDefaultFramebuffers();
return false;
}
m_defaultFramebuffers.push_back(framebuffer);
}
m_defaultExtent = extent;
return true;
}
Bool VkRenderPassManager::GetDefaultRenderTarget(Uint32 imageIndex, VkRenderPass& outRenderPass,
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
VkFormat& outDepthStencilFormat) const {
if (imageIndex >= m_defaultFramebuffers.size() || m_renderPassLoad == VK_NULL_HANDLE) {
return false;
}
outRenderPass = m_renderPassLoad;
outFramebuffer = m_defaultFramebuffers[imageIndex];
outExtent = m_defaultExtent;
outDepthStencilFormat = m_depthStencilFormat;
return outFramebuffer != VK_NULL_HANDLE;
}
Bool VkRenderPassManager::EnsureOffscreenRenderTarget(const OffscreenRenderTargetInfo& targetInfo) {
if (m_device == VK_NULL_HANDLE || targetInfo.colorView == VK_NULL_HANDLE ||
targetInfo.colorFormat == VK_FORMAT_UNDEFINED || targetInfo.extent.width == 0 ||
targetInfo.extent.height == 0) {
return false;
}
const Bool hasDepthStencil =
targetInfo.depthStencilView != VK_NULL_HANDLE && targetInfo.depthStencilFormat != VK_FORMAT_UNDEFINED;
auto& target = m_offscreenRenderTargets[targetInfo.targetExternalIndex];
if (target.framebuffer != VK_NULL_HANDLE && target.renderPassLoad != VK_NULL_HANDLE &&
target.targetVersion == targetInfo.targetVersion && target.colorView == targetInfo.colorView &&
target.colorFormat == targetInfo.colorFormat && target.depthStencilView == targetInfo.depthStencilView &&
target.depthStencilFormat == targetInfo.depthStencilFormat &&
target.extent.width == targetInfo.extent.width && target.extent.height == targetInfo.extent.height) {
return true;
}
DestroyOffscreenRenderTarget(target);
const VkFormat depthStencilFormat = hasDepthStencil ? targetInfo.depthStencilFormat : VK_FORMAT_UNDEFINED;
target.renderPassLoad = CreateRenderPass(targetInfo.colorFormat, depthStencilFormat, VK_ATTACHMENT_LOAD_OP_LOAD,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
if (target.renderPassLoad == VK_NULL_HANDLE) {
return false;
}
Array<VkImageView, 2> attachments{};
attachments[0] = targetInfo.colorView;
Uint32 attachmentCount = 1;
if (hasDepthStencil) {
attachments[1] = targetInfo.depthStencilView;
attachmentCount = 2;
}
VkFramebufferCreateInfo framebufferInfo{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
framebufferInfo.renderPass = target.renderPassLoad;
framebufferInfo.attachmentCount = attachmentCount;
framebufferInfo.pAttachments = attachments.data();
framebufferInfo.width = targetInfo.extent.width;
framebufferInfo.height = targetInfo.extent.height;
framebufferInfo.layers = 1;
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &target.framebuffer),
"vkCreateFramebuffer(offscreen)");
target.targetVersion = targetInfo.targetVersion;
target.colorView = targetInfo.colorView;
target.colorFormat = targetInfo.colorFormat;
target.depthStencilView = targetInfo.depthStencilView;
target.depthStencilFormat = targetInfo.depthStencilFormat;
target.extent = targetInfo.extent;
return true;
}
Bool VkRenderPassManager::GetOffscreenRenderTarget(Uint targetExternalIndex, VkRenderPass& outRenderPass,
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
VkFormat& outDepthStencilFormat) const {
auto it = m_offscreenRenderTargets.find(targetExternalIndex);
if (it == m_offscreenRenderTargets.end() || it->second.renderPassLoad == VK_NULL_HANDLE ||
it->second.framebuffer == VK_NULL_HANDLE) {
return false;
}
outRenderPass = it->second.renderPassLoad;
outFramebuffer = it->second.framebuffer;
outExtent = it->second.extent;
outDepthStencilFormat = it->second.depthStencilFormat;
return true;
}
void VkRenderPassManager::RemoveOffscreenRenderTarget(Uint targetExternalIndex) {
auto it = m_offscreenRenderTargets.find(targetExternalIndex);
if (it == m_offscreenRenderTargets.end()) {
return;
}
DestroyOffscreenRenderTarget(it->second);
m_offscreenRenderTargets.erase(it);
}
void VkRenderPassManager::BeginRenderPass(VkCommandBuffer commandBuffer, VkRenderPass renderPass,
VkFramebuffer framebuffer, VkExtent2D extent) const {
VkRenderPassBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
beginInfo.renderPass = renderPass;
beginInfo.framebuffer = framebuffer;
beginInfo.renderArea.offset = {0, 0};
beginInfo.renderArea.extent = extent;
beginInfo.clearValueCount = 0;
beginInfo.pClearValues = nullptr;
vkCmdBeginRenderPass(commandBuffer, &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
}
void VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) const {
vkCmdEndRenderPass(commandBuffer);
}
void VkRenderPassManager::RecordColorClear(VkCommandBuffer commandBuffer, VkExtent2D extent,
const VkClearColorValue& clearColor) const {
VkClearAttachment clearAttachment{};
clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
clearAttachment.colorAttachment = 0;
clearAttachment.clearValue.color = clearColor;
VkClearRect clearRect{};
clearRect.rect.offset = {0, 0};
clearRect.rect.extent = extent;
clearRect.baseArrayLayer = 0;
clearRect.layerCount = 1;
vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect);
}
void VkRenderPassManager::RecordDepthStencilClear(VkCommandBuffer commandBuffer, VkExtent2D extent, GLbitfield mask,
Float depth, Uint32 stencil, VkFormat depthStencilFormat) const {
if (depthStencilFormat == VK_FORMAT_UNDEFINED) {
return;
}
VkImageAspectFlags aspectMask = 0;
if ((mask & GL_DEPTH_BUFFER_BIT) != 0) {
aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
}
if ((mask & GL_STENCIL_BUFFER_BIT) != 0 && HasStencilComponent(depthStencilFormat)) {
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
if (aspectMask == 0) {
return;
}
VkClearAttachment clearAttachment{};
clearAttachment.aspectMask = aspectMask;
clearAttachment.clearValue.depthStencil.depth = depth;
clearAttachment.clearValue.depthStencil.stencil = stencil;
VkClearRect clearRect{};
clearRect.rect.offset = {0, 0};
clearRect.rect.extent = extent;
clearRect.baseArrayLayer = 0;
clearRect.layerCount = 1;
vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect);
}
VkRenderPass VkRenderPassManager::GetLoadRenderPass() const {
return m_renderPassLoad;
}
@@ -56,24 +255,34 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MOBILEGL_ASSERT(m_colorFormat != VK_FORMAT_UNDEFINED, "VkRenderPassManager: color format is undefined");
MOBILEGL_ASSERT(m_depthStencilFormat != VK_FORMAT_UNDEFINED,
"VkRenderPassManager: depth/stencil format is undefined");
return CreateRenderPass(m_colorFormat, m_depthStencilFormat, colorLoadOp, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
}
VkRenderPass VkRenderPassManager::CreateRenderPass(VkFormat colorFormat, VkFormat depthStencilFormat,
VkAttachmentLoadOp colorLoadOp,
VkImageLayout colorFinalLayout) const {
VkAttachmentDescription color{};
color.format = m_colorFormat;
color.format = colorFormat;
color.samples = VK_SAMPLE_COUNT_1_BIT;
color.loadOp = colorLoadOp;
color.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
color.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
color.finalLayout = colorFinalLayout;
color.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
color.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
const Bool hasDepthStencil = depthStencilFormat != VK_FORMAT_UNDEFINED;
VkAttachmentDescription depthStencil{};
depthStencil.format = m_depthStencilFormat;
depthStencil.samples = VK_SAMPLE_COUNT_1_BIT;
depthStencil.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
depthStencil.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthStencil.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
depthStencil.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthStencil.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthStencil.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
if (hasDepthStencil) {
depthStencil.format = depthStencilFormat;
depthStencil.samples = VK_SAMPLE_COUNT_1_BIT;
depthStencil.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
depthStencil.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthStencil.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
depthStencil.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthStencil.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthStencil.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
VkAttachmentReference colorRef{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
VkAttachmentReference depthStencilRef{1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
@@ -82,18 +291,57 @@ namespace MobileGL::MG_Backend::DirectVulkan {
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorRef;
subpass.pDepthStencilAttachment = &depthStencilRef;
if (hasDepthStencil) {
subpass.pDepthStencilAttachment = &depthStencilRef;
}
VkAttachmentDescription attachments[2] = {color, depthStencil};
Array<VkAttachmentDescription, 2> attachments{};
attachments[0] = color;
Uint32 attachmentCount = 1;
if (hasDepthStencil) {
attachments[1] = depthStencil;
attachmentCount = 2;
}
VkRenderPassCreateInfo createInfo{VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO};
createInfo.attachmentCount = 2;
createInfo.pAttachments = attachments;
createInfo.attachmentCount = attachmentCount;
createInfo.pAttachments = attachments.data();
createInfo.subpassCount = 1;
createInfo.pSubpasses = &subpass;
VkRenderPass renderPass = VK_NULL_HANDLE;
VK_VERIFY(vkCreateRenderPass(m_device, &createInfo, nullptr, &renderPass), "vkCreateRenderPass(default)");
VK_VERIFY(vkCreateRenderPass(m_device, &createInfo, nullptr, &renderPass), "vkCreateRenderPass");
return renderPass;
}
void VkRenderPassManager::DestroyDefaultFramebuffers() {
for (auto framebuffer : m_defaultFramebuffers) {
if (framebuffer != VK_NULL_HANDLE) {
vkDestroyFramebuffer(m_device, framebuffer, nullptr);
}
}
m_defaultFramebuffers.clear();
m_defaultExtent = {0, 0};
}
void VkRenderPassManager::DestroyOffscreenRenderTarget(OffscreenRenderTarget& target) {
if (target.framebuffer != VK_NULL_HANDLE) {
vkDestroyFramebuffer(m_device, target.framebuffer, nullptr);
target.framebuffer = VK_NULL_HANDLE;
}
if (target.renderPassLoad != VK_NULL_HANDLE) {
vkDestroyRenderPass(m_device, target.renderPassLoad, nullptr);
target.renderPassLoad = VK_NULL_HANDLE;
}
target.targetVersion = 0;
target.colorView = VK_NULL_HANDLE;
target.colorFormat = VK_FORMAT_UNDEFINED;
target.depthStencilView = VK_NULL_HANDLE;
target.depthStencilFormat = VK_FORMAT_UNDEFINED;
target.extent = {0, 0};
}
Bool VkRenderPassManager::HasStencilComponent(VkFormat format) {
return format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT;
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -20,19 +20,67 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
};
struct OffscreenRenderTargetInfo {
Uint targetExternalIndex = 0;
Uint16 targetVersion = 0;
VkImageView colorView = VK_NULL_HANDLE;
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
VkImageView depthStencilView = VK_NULL_HANDLE;
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
VkExtent2D extent = {0, 0};
};
Bool Initialize(const InitInfo& initInfo);
void Shutdown();
Bool RecreateDefaultFramebuffers(const Vector<VkImageView>& colorViews,
const Vector<VkImageView>& depthStencilViews, VkExtent2D extent);
Bool GetDefaultRenderTarget(Uint32 imageIndex, VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer,
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) const;
Bool EnsureOffscreenRenderTarget(const OffscreenRenderTargetInfo& targetInfo);
Bool GetOffscreenRenderTarget(Uint targetExternalIndex, VkRenderPass& outRenderPass,
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
VkFormat& outDepthStencilFormat) const;
void RemoveOffscreenRenderTarget(Uint targetExternalIndex);
void BeginRenderPass(VkCommandBuffer commandBuffer, VkRenderPass renderPass, VkFramebuffer framebuffer,
VkExtent2D extent) const;
void EndRenderPass(VkCommandBuffer commandBuffer) const;
void RecordColorClear(VkCommandBuffer commandBuffer, VkExtent2D extent,
const VkClearColorValue& clearColor) const;
void RecordDepthStencilClear(VkCommandBuffer commandBuffer, VkExtent2D extent, GLbitfield mask, Float depth,
Uint32 stencil, VkFormat depthStencilFormat) const;
VkRenderPass GetLoadRenderPass() const;
VkRenderPass GetClearRenderPass() const;
private:
struct OffscreenRenderTarget {
Uint16 targetVersion = 0;
VkImageView colorView = VK_NULL_HANDLE;
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
VkImageView depthStencilView = VK_NULL_HANDLE;
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
VkExtent2D extent = {0, 0};
VkRenderPass renderPassLoad = VK_NULL_HANDLE;
VkFramebuffer framebuffer = VK_NULL_HANDLE;
};
VkRenderPass CreateDefaultRenderPass(VkAttachmentLoadOp colorLoadOp) const;
VkRenderPass CreateRenderPass(VkFormat colorFormat, VkFormat depthStencilFormat, VkAttachmentLoadOp colorLoadOp,
VkImageLayout colorFinalLayout) const;
void DestroyDefaultFramebuffers();
void DestroyOffscreenRenderTarget(OffscreenRenderTarget& target);
static Bool HasStencilComponent(VkFormat format);
VkDevice m_device = VK_NULL_HANDLE;
VkFormat m_colorFormat = VK_FORMAT_UNDEFINED;
VkFormat m_depthStencilFormat = VK_FORMAT_UNDEFINED;
VkRenderPass m_renderPassLoad = VK_NULL_HANDLE;
VkRenderPass m_renderPassClear = VK_NULL_HANDLE;
Vector<VkFramebuffer> m_defaultFramebuffers;
VkExtent2D m_defaultExtent = {0, 0};
UnorderedMap<Uint, OffscreenRenderTarget> m_offscreenRenderTargets;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -254,10 +254,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
m_textureSamplerManager.reset();
}
m_vertexInputStateFactory.reset();
if (m_framebufferManager) {
m_framebufferManager->Shutdown();
m_framebufferManager.reset();
}
for (auto& buffer : m_frameVertexUploadBuffers) {
buffer.Destroy();
}
@@ -283,6 +279,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
ShutdownSwapchain();
m_renderPassManager.reset();
if (m_framebufferManager) {
m_framebufferManager->Shutdown();
m_framebufferManager.reset();
}
if (m_commandPool != VK_NULL_HANDLE) {
vkDestroyCommandPool(m_device, m_commandPool, nullptr);
@@ -383,52 +383,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
m_swapchainObject.SetImageLayout(imageIndex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
void VulkanRenderer::RecordColorClear(VkCommandBuffer commandBuffer, const VkClearColorValue& clearColor) {
VkClearAttachment clearAttachment{};
clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
clearAttachment.colorAttachment = 0;
clearAttachment.clearValue.color = clearColor;
VkClearRect clearRect{};
clearRect.rect.offset = {0, 0};
clearRect.rect.extent = m_activeRenderExtent;
clearRect.baseArrayLayer = 0;
clearRect.layerCount = 1;
vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect);
}
void VulkanRenderer::RecordDepthStencilClear(VkCommandBuffer commandBuffer, GLbitfield mask, Float depth,
Uint32 stencil) {
if (m_activeDepthStencilFormat == VK_FORMAT_UNDEFINED) {
return;
}
VkImageAspectFlags aspectMask = 0;
if ((mask & GL_DEPTH_BUFFER_BIT) != 0) {
aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
}
if ((mask & GL_STENCIL_BUFFER_BIT) != 0 && HasStencilComponent(m_activeDepthStencilFormat)) {
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
if (aspectMask == 0) {
return;
}
VkClearAttachment clearAttachment{};
clearAttachment.aspectMask = aspectMask;
clearAttachment.clearValue.depthStencil.depth = depth;
clearAttachment.clearValue.depthStencil.stencil = stencil;
VkClearRect clearRect{};
clearRect.rect.offset = {0, 0};
clearRect.rect.extent = m_activeRenderExtent;
clearRect.baseArrayLayer = 0;
clearRect.layerCount = 1;
vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect);
}
void VulkanRenderer::TransitionDepthStencilImageToAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex) {
if (m_depthStencilImageLayouts.empty()) {
return;
@@ -487,7 +441,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
(drawTargetsDefault != m_activeRenderTargetIsDefault) ||
(!drawTargetsDefault && m_activeDrawFboExternalIndex != drawFboExternalIndex);
if (activeTargetMismatch) {
vkCmdEndRenderPass(frame.commandBuffer);
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "EnsureFrameRecordingStarted: manager is null");
m_renderPassManager->EndRenderPass(frame.commandBuffer);
if (m_activeRenderTargetIsDefault) {
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
}
@@ -514,15 +469,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkCommandBuffer& commandBuffer = *commandBufferPtr;
if (!drawTargetsDefault) {
if (!m_framebufferManager || !drawFbo) {
if (!m_framebufferManager || !m_renderPassManager || !drawFbo) {
MGLOG_D("EnsureFrameRecordingStarted skipped: offscreen draw target is unavailable");
return;
}
if (!m_framebufferManager->EnsureOffscreenColorTarget(drawFboExternalIndex, *drawFbo)) {
MGLOG_D("EnsureFrameRecordingStarted skipped: failed to materialize offscreen target for FBO %u",
drawFboExternalIndex);
return;
}
// This frame touched only offscreen resources. Present still requires
// the acquired swapchain image to be in PRESENT layout.
@@ -549,33 +499,24 @@ namespace MobileGL::MG_Backend::DirectVulkan {
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
}
if (!m_framebufferManager->TransitionOffscreenColorToAttachment(commandBuffer, drawFboExternalIndex)) {
MGLOG_D("EnsureFrameRecordingStarted skipped: failed to transition offscreen FBO %u for attachment",
drawFboExternalIndex);
return;
}
VkRenderPass offscreenRenderPass = VK_NULL_HANDLE;
VkFramebuffer offscreenFramebuffer = VK_NULL_HANDLE;
VkExtent2D offscreenExtent{};
VkFormat offscreenDepthStencilFormat = VK_FORMAT_UNDEFINED;
if (!m_framebufferManager->GetOffscreenRenderTarget(drawFboExternalIndex, offscreenRenderPass,
offscreenFramebuffer, offscreenExtent,
offscreenDepthStencilFormat)) {
if (!EnsureOffscreenRenderTarget(drawFboExternalIndex, *drawFbo, offscreenRenderPass, offscreenFramebuffer,
offscreenExtent, offscreenDepthStencilFormat)) {
MGLOG_D("EnsureFrameRecordingStarted skipped: offscreen render target for FBO %u is unavailable",
drawFboExternalIndex);
return;
}
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = offscreenRenderPass;
renderPassInfo.framebuffer = offscreenFramebuffer;
renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = offscreenExtent;
renderPassInfo.clearValueCount = 0;
renderPassInfo.pClearValues = nullptr;
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
if (!m_framebufferManager->TransitionOffscreenColorToAttachment(commandBuffer, drawFboExternalIndex)) {
MGLOG_D("EnsureFrameRecordingStarted skipped: failed to transition offscreen FBO %u for attachment",
drawFboExternalIndex);
return;
}
m_renderPassManager->BeginRenderPass(commandBuffer, offscreenRenderPass, offscreenFramebuffer,
offscreenExtent);
m_isMainRenderPassActive = true;
m_activeRenderPass = offscreenRenderPass;
m_activeRenderExtent = offscreenExtent;
@@ -585,12 +526,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
auto pendingIt = m_pendingClears.find(drawTargetKey);
if (pendingIt != m_pendingClears.end()) {
if ((pendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) {
RecordColorClear(commandBuffer, pendingIt->second.color);
m_renderPassManager->RecordColorClear(commandBuffer, m_activeRenderExtent, pendingIt->second.color);
pendingIt->second.mask &= ~GL_COLOR_BUFFER_BIT;
}
if ((pendingIt->second.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
RecordDepthStencilClear(commandBuffer, pendingIt->second.mask, pendingIt->second.depth,
pendingIt->second.stencil);
m_renderPassManager->RecordDepthStencilClear(commandBuffer, m_activeRenderExtent,
pendingIt->second.mask, pendingIt->second.depth,
pendingIt->second.stencil, m_activeDepthStencilFormat);
pendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
if (pendingIt->second.mask == 0) {
@@ -603,30 +545,33 @@ namespace MobileGL::MG_Backend::DirectVulkan {
TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired);
TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired);
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = GetDefaultLoadRenderPass();
renderPassInfo.framebuffer = m_framebuffers[m_imageIndexAcquired];
renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = m_swapchainObject.GetExtent();
renderPassInfo.clearValueCount = 0;
renderPassInfo.pClearValues = nullptr;
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
VkRenderPass defaultRenderPass = VK_NULL_HANDLE;
VkFramebuffer defaultFramebuffer = VK_NULL_HANDLE;
VkExtent2D defaultExtent{};
VkFormat defaultDepthStencilFormat = VK_FORMAT_UNDEFINED;
if (!GetDefaultRenderTargetForCurrentImage(defaultRenderPass, defaultFramebuffer, defaultExtent,
defaultDepthStencilFormat)) {
MGLOG_D("EnsureFrameRecordingStarted skipped: default render target unavailable");
return;
}
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "EnsureFrameRecordingStarted: manager is null");
m_renderPassManager->BeginRenderPass(commandBuffer, defaultRenderPass, defaultFramebuffer, defaultExtent);
m_isMainRenderPassActive = true;
m_activeRenderPass = renderPassInfo.renderPass;
m_activeRenderExtent = renderPassInfo.renderArea.extent;
m_activeDepthStencilFormat = m_depthStencilFormat;
m_activeRenderPass = defaultRenderPass;
m_activeRenderExtent = defaultExtent;
m_activeDepthStencilFormat = defaultDepthStencilFormat;
m_activeRenderTargetIsDefault = true;
m_activeDrawFboExternalIndex = drawFboExternalIndex;
auto pendingIt = m_pendingClears.find(drawTargetKey);
if (pendingIt != m_pendingClears.end()) {
if ((pendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) {
RecordColorClear(commandBuffer, pendingIt->second.color);
m_renderPassManager->RecordColorClear(commandBuffer, m_activeRenderExtent, pendingIt->second.color);
pendingIt->second.mask &= ~GL_COLOR_BUFFER_BIT;
}
if ((pendingIt->second.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
RecordDepthStencilClear(commandBuffer, pendingIt->second.mask, pendingIt->second.depth,
pendingIt->second.stencil);
m_renderPassManager->RecordDepthStencilClear(commandBuffer, m_activeRenderExtent,
pendingIt->second.mask, pendingIt->second.depth,
pendingIt->second.stencil, m_activeDepthStencilFormat);
pendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
if (pendingIt->second.mask == 0) {
@@ -642,7 +587,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
if (m_isMainRenderPassActive) {
vkCmdEndRenderPass(frame.commandBuffer);
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "EndFrameRecordingIfNeeded: manager is null");
m_renderPassManager->EndRenderPass(frame.commandBuffer);
if (m_activeRenderTargetIsDefault) {
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
}
@@ -1270,7 +1216,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkCommandBuffer commandBuffer = frame.commandBuffer;
if (m_isMainRenderPassActive) {
vkCmdEndRenderPass(commandBuffer);
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "BlitFramebuffer: render pass manager is null");
m_renderPassManager->EndRenderPass(commandBuffer);
if (m_activeRenderTargetIsDefault) {
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
}
@@ -1286,6 +1233,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MGLOG_W("BlitFramebuffer skipped: offscreen framebuffer manager not available");
return false;
}
if (!m_renderPassManager) {
MGLOG_W("BlitFramebuffer skipped: render pass manager not available");
return false;
}
auto consumePendingClearForTarget = [&](Bool targetIsDefault, Uint targetFboExternalIndex) {
const Uint64 pendingKey = BuildPendingClearKey(targetFboExternalIndex, targetIsDefault);
@@ -1304,60 +1255,55 @@ namespace MobileGL::MG_Backend::DirectVulkan {
TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired);
TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired);
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = GetDefaultLoadRenderPass();
renderPassInfo.framebuffer = m_framebuffers[m_imageIndexAcquired];
renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = m_swapchainObject.GetExtent();
renderPassInfo.clearValueCount = 0;
renderPassInfo.pClearValues = nullptr;
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
VkRenderPass renderPass = VK_NULL_HANDLE;
VkFramebuffer framebuffer = VK_NULL_HANDLE;
VkExtent2D extent{};
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
if (!GetDefaultRenderTargetForCurrentImage(renderPass, framebuffer, extent, depthStencilFormat)) {
return;
}
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "BlitFramebuffer: manager is null");
m_renderPassManager->BeginRenderPass(commandBuffer, renderPass, framebuffer, extent);
m_activeRenderExtent = renderPassInfo.renderArea.extent;
m_activeDepthStencilFormat = m_depthStencilFormat;
m_activeRenderExtent = extent;
m_activeDepthStencilFormat = depthStencilFormat;
if ((pending.mask & GL_COLOR_BUFFER_BIT) != 0) {
RecordColorClear(commandBuffer, pending.color);
m_renderPassManager->RecordColorClear(commandBuffer, m_activeRenderExtent, pending.color);
}
if ((pending.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
RecordDepthStencilClear(commandBuffer, pending.mask, pending.depth, pending.stencil);
m_renderPassManager->RecordDepthStencilClear(commandBuffer, m_activeRenderExtent, pending.mask,
pending.depth, pending.stencil,
m_activeDepthStencilFormat);
}
vkCmdEndRenderPass(commandBuffer);
m_renderPassManager->EndRenderPass(commandBuffer);
} else if (m_framebufferManager && MG_State::pGLContext) {
const auto targetFbo = MG_State::pGLContext->GetFramebufferObject(targetFboExternalIndex);
if (targetFbo && m_framebufferManager->EnsureOffscreenColorTarget(targetFboExternalIndex, *targetFbo) &&
VkRenderPass offscreenRenderPass = VK_NULL_HANDLE;
VkFramebuffer offscreenFramebuffer = VK_NULL_HANDLE;
VkExtent2D offscreenExtent{};
VkFormat offscreenDepthStencilFormat = VK_FORMAT_UNDEFINED;
if (targetFbo &&
EnsureOffscreenRenderTarget(targetFboExternalIndex, *targetFbo, offscreenRenderPass,
offscreenFramebuffer, offscreenExtent, offscreenDepthStencilFormat) &&
m_framebufferManager->TransitionOffscreenColorToAttachment(commandBuffer, targetFboExternalIndex)) {
VkRenderPass offscreenRenderPass = VK_NULL_HANDLE;
VkFramebuffer offscreenFramebuffer = VK_NULL_HANDLE;
VkExtent2D offscreenExtent{};
VkFormat offscreenDepthStencilFormat = VK_FORMAT_UNDEFINED;
if (m_framebufferManager->GetOffscreenRenderTarget(targetFboExternalIndex, offscreenRenderPass,
offscreenFramebuffer, offscreenExtent,
offscreenDepthStencilFormat)) {
VkRenderPassBeginInfo offscreenPassInfo{};
offscreenPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
offscreenPassInfo.renderPass = offscreenRenderPass;
offscreenPassInfo.framebuffer = offscreenFramebuffer;
offscreenPassInfo.renderArea.offset = {0, 0};
offscreenPassInfo.renderArea.extent = offscreenExtent;
offscreenPassInfo.clearValueCount = 0;
offscreenPassInfo.pClearValues = nullptr;
vkCmdBeginRenderPass(commandBuffer, &offscreenPassInfo, VK_SUBPASS_CONTENTS_INLINE);
m_renderPassManager->BeginRenderPass(commandBuffer, offscreenRenderPass, offscreenFramebuffer,
offscreenExtent);
m_activeRenderExtent = offscreenPassInfo.renderArea.extent;
m_activeDepthStencilFormat = offscreenDepthStencilFormat;
m_activeRenderExtent = offscreenExtent;
m_activeDepthStencilFormat = offscreenDepthStencilFormat;
if ((pending.mask & GL_COLOR_BUFFER_BIT) != 0) {
RecordColorClear(commandBuffer, pending.color);
}
if ((pending.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
RecordDepthStencilClear(commandBuffer, pending.mask, pending.depth, pending.stencil);
}
vkCmdEndRenderPass(commandBuffer);
if ((pending.mask & GL_COLOR_BUFFER_BIT) != 0) {
m_renderPassManager->RecordColorClear(commandBuffer, m_activeRenderExtent, pending.color);
}
if ((pending.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
m_renderPassManager->RecordDepthStencilClear(commandBuffer, m_activeRenderExtent, pending.mask,
pending.depth, pending.stencil,
m_activeDepthStencilFormat);
}
m_renderPassManager->EndRenderPass(commandBuffer);
}
}
@@ -1858,6 +1804,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (frame.hasCommandBufferRecorded) {
return false;
}
if (!m_renderPassManager) {
return false;
}
if (!frame.isCommandRecording) {
m_frameContext.BeginCommandRecording();
if (m_uniformDescriptorBinder) {
@@ -1867,7 +1816,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkCommandBuffer commandBuffer = frame.commandBuffer;
if (m_isMainRenderPassActive) {
vkCmdEndRenderPass(commandBuffer);
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "Present: render pass manager is null");
m_renderPassManager->EndRenderPass(commandBuffer);
if (m_activeRenderTargetIsDefault) {
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
}
@@ -1883,19 +1833,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired);
TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired);
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = GetDefaultLoadRenderPass();
renderPassInfo.framebuffer = m_framebuffers[m_imageIndexAcquired];
renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = m_swapchainObject.GetExtent();
renderPassInfo.clearValueCount = 0;
renderPassInfo.pClearValues = nullptr;
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
VkRenderPass renderPass = VK_NULL_HANDLE;
VkFramebuffer framebuffer = VK_NULL_HANDLE;
VkExtent2D extent{};
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
if (!GetDefaultRenderTargetForCurrentImage(renderPass, framebuffer, extent, depthStencilFormat)) {
return false;
}
m_renderPassManager->BeginRenderPass(commandBuffer, renderPass, framebuffer, extent);
m_isMainRenderPassActive = true;
m_activeRenderPass = renderPassInfo.renderPass;
m_activeRenderExtent = renderPassInfo.renderArea.extent;
m_activeDepthStencilFormat = m_depthStencilFormat;
m_activeRenderPass = renderPass;
m_activeRenderExtent = extent;
m_activeDepthStencilFormat = depthStencilFormat;
m_activeRenderTargetIsDefault = true;
m_activeDrawFboExternalIndex = 0;
return true;
@@ -1908,21 +1857,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (!pendingFbo) {
return false;
}
if (!m_framebufferManager->EnsureOffscreenColorTarget(targetFboExternalIndex, *pendingFbo)) {
return false;
}
if (!m_framebufferManager->TransitionOffscreenColorToAttachment(commandBuffer,
targetFboExternalIndex)) {
return false;
}
VkRenderPass offscreenRenderPass = VK_NULL_HANDLE;
VkFramebuffer offscreenFramebuffer = VK_NULL_HANDLE;
VkExtent2D offscreenExtent{};
VkFormat offscreenDepthStencilFormat = VK_FORMAT_UNDEFINED;
if (!m_framebufferManager->GetOffscreenRenderTarget(targetFboExternalIndex, offscreenRenderPass,
offscreenFramebuffer, offscreenExtent,
offscreenDepthStencilFormat)) {
if (!EnsureOffscreenRenderTarget(targetFboExternalIndex, *pendingFbo, offscreenRenderPass,
offscreenFramebuffer, offscreenExtent, offscreenDepthStencilFormat)) {
return false;
}
if (!m_framebufferManager->TransitionOffscreenColorToAttachment(commandBuffer,
targetFboExternalIndex)) {
return false;
}
@@ -1949,15 +1893,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
}
VkRenderPassBeginInfo offscreenPassInfo{};
offscreenPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
offscreenPassInfo.renderPass = offscreenRenderPass;
offscreenPassInfo.framebuffer = offscreenFramebuffer;
offscreenPassInfo.renderArea.offset = {0, 0};
offscreenPassInfo.renderArea.extent = offscreenExtent;
offscreenPassInfo.clearValueCount = 0;
offscreenPassInfo.pClearValues = nullptr;
vkCmdBeginRenderPass(commandBuffer, &offscreenPassInfo, VK_SUBPASS_CONTENTS_INLINE);
m_renderPassManager->BeginRenderPass(commandBuffer, offscreenRenderPass, offscreenFramebuffer,
offscreenExtent);
m_isMainRenderPassActive = true;
m_activeRenderPass = offscreenRenderPass;
m_activeRenderExtent = offscreenExtent;
@@ -1994,12 +1931,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
if ((activePendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) {
RecordColorClear(frame.commandBuffer, activePendingIt->second.color);
m_renderPassManager->RecordColorClear(frame.commandBuffer, m_activeRenderExtent,
activePendingIt->second.color);
activePendingIt->second.mask &= ~GL_COLOR_BUFFER_BIT;
}
if ((activePendingIt->second.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
RecordDepthStencilClear(frame.commandBuffer, activePendingIt->second.mask,
activePendingIt->second.depth, activePendingIt->second.stencil);
m_renderPassManager->RecordDepthStencilClear(
frame.commandBuffer, m_activeRenderExtent, activePendingIt->second.mask,
activePendingIt->second.depth, activePendingIt->second.stencil, m_activeDepthStencilFormat);
activePendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
if (activePendingIt->second.mask == 0) {
@@ -2541,26 +2480,49 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return renderPass;
}
void VulkanRenderer::CreateDefaultFramebuffers() {
// Create framebuffers now (use swapchain imageviews)
const auto& imageViews = m_swapchainObject.GetImageViews();
const auto swapchainExtent = m_swapchainObject.GetExtent();
Vector<VkFramebuffer>& fbs = m_framebuffers;
fbs.reserve(imageViews.size());
for (SizeT i = 0; i < imageViews.size(); ++i) {
VkImageView attachments[] = {imageViews[i], m_depthStencilImageViews[i]};
VkFramebufferCreateInfo fbci{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
fbci.renderPass = GetDefaultLoadRenderPass();
fbci.attachmentCount = static_cast<Uint32>(std::size(attachments));
fbci.pAttachments = attachments;
fbci.width = swapchainExtent.width;
fbci.height = swapchainExtent.height;
fbci.layers = 1;
VkFramebuffer fb;
VK_VERIFY(vkCreateFramebuffer(m_device, &fbci, nullptr, &fb), "vkCreateFramebuffer");
fbs.push_back(fb);
Bool VulkanRenderer::GetDefaultRenderTargetForCurrentImage(VkRenderPass& outRenderPass,
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
VkFormat& outDepthStencilFormat) const {
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "GetDefaultRenderTargetForCurrentImage: manager is null");
return m_renderPassManager->GetDefaultRenderTarget(m_imageIndexAcquired, outRenderPass, outFramebuffer,
outExtent, outDepthStencilFormat);
}
Bool VulkanRenderer::EnsureOffscreenRenderTarget(Uint glFboExternalIndex,
const MG_State::GLState::FramebufferObject& glFbo,
VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer,
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) {
MOBILEGL_ASSERT(m_framebufferManager != nullptr, "EnsureOffscreenRenderTarget: framebuffer manager is null");
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "EnsureOffscreenRenderTarget: render pass manager is null");
if (!m_framebufferManager->EnsureOffscreenColorTarget(glFboExternalIndex, glFbo)) {
return false;
}
MGLOG_D("Default framebuffer created.");
VkImageView colorView = VK_NULL_HANDLE;
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
VkImageView depthStencilView = VK_NULL_HANDLE;
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
VkExtent2D extent{};
if (!m_framebufferManager->GetOffscreenRenderSurface(glFboExternalIndex, colorView, colorFormat,
depthStencilView, depthStencilFormat, extent)) {
return false;
}
VkRenderPassManager::OffscreenRenderTargetInfo targetInfo{};
targetInfo.targetExternalIndex = glFboExternalIndex;
targetInfo.targetVersion = glFbo.GetObjectVersion();
targetInfo.colorView = colorView;
targetInfo.colorFormat = colorFormat;
targetInfo.depthStencilView = depthStencilView;
targetInfo.depthStencilFormat = depthStencilFormat;
targetInfo.extent = extent;
if (!m_renderPassManager->EnsureOffscreenRenderTarget(targetInfo)) {
return false;
}
return m_renderPassManager->GetOffscreenRenderTarget(glFboExternalIndex, outRenderPass, outFramebuffer,
outExtent, outDepthStencilFormat);
}
void VulkanRenderer::CreateSurface() {
@@ -2707,11 +2669,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
void VulkanRenderer::ShutdownSwapchain() {
for (auto fb : m_framebuffers) {
vkDestroyFramebuffer(m_device, fb, nullptr);
}
m_framebuffers.clear();
DestroyDepthStencilResources();
if (m_renderPassManager) {
@@ -2746,7 +2703,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
renderPassInitInfo.depthStencilFormat = m_depthStencilFormat;
MOBILEGL_ASSERT(m_renderPassManager->Initialize(renderPassInitInfo),
"RecreateSwapchain: render pass manager initialization failed");
CreateDefaultFramebuffers();
MOBILEGL_ASSERT(m_renderPassManager->RecreateDefaultFramebuffers(
m_swapchainObject.GetImageViews(), m_depthStencilImageViews, m_swapchainObject.GetExtent()),
"RecreateSwapchain: default framebuffers initialization failed");
if (m_pipelineFactory) {
m_pipelineFactory->DestroyAll();
}
@@ -25,6 +25,7 @@
#include "../VkIncludes.h"
namespace MobileGL::MG_State::GLState {
class FramebufferObject;
class ProgramObject;
class VertexArrayObject;
} // namespace MobileGL::MG_State::GLState
@@ -125,7 +126,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkCommandPool m_commandPool = VK_NULL_HANDLE;
Vector<VkFramebuffer> m_framebuffers;
VkFormat m_depthStencilFormat = VK_FORMAT_UNDEFINED;
Vector<VkImage> m_depthStencilImages;
Vector<VkDeviceMemory> m_depthStencilImageMemories;
@@ -172,15 +172,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void CreateDepthStencilResources();
void DestroyDepthStencilResources();
VkRenderPass GetDefaultLoadRenderPass() const;
void CreateDefaultFramebuffers();
Bool GetDefaultRenderTargetForCurrentImage(VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer,
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) const;
Bool EnsureOffscreenRenderTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo,
VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer,
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat);
void PrepareDemoPipeline();
VkPipeline GetOrCreatePipeline(const MG_State::GLState::ProgramObject& program, VkPipelineLayout pipelineLayout,
Uint64 vertexInputHash,
const VkPipelineVertexInputStateCreateInfo& vertexInputState);
void TransitionSwapchainImageToColorAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex);
void TransitionDepthStencilImageToAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex);
void RecordColorClear(VkCommandBuffer commandBuffer, const VkClearColorValue& clearColor);
void RecordDepthStencilClear(VkCommandBuffer commandBuffer, GLbitfield mask, Float depth, Uint32 stencil);
void EndFrameRecordingIfNeeded();
void DeferDestroyBuffer(VkBufferObject& buffer);
void CollectDeferredBufferReleases(Uint32 frameIndex);