mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Feat] (MG_Backend/DirectVulkan): per-fbo pending clear state
This commit is contained in:
@@ -41,30 +41,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RecreateOffscreenColorTarget(target, colorAttachment, objectVersion);
|
return RecreateOffscreenColorTarget(target, glFbo, colorAttachment, objectVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VkFramebufferManager::ClearColor(VkCommandBuffer commandBuffer, Uint glFboExternalIndex,
|
Bool VkFramebufferManager::TransitionOffscreenColorToAttachment(VkCommandBuffer commandBuffer,
|
||||||
const VkClearColorValue& clearColor) {
|
Uint glFboExternalIndex) {
|
||||||
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||||
if (it == m_offscreenColorTargets.end()) {
|
if (it == m_offscreenColorTargets.end()) {
|
||||||
MGLOG_W("VkFramebufferManager::ClearColor skipped: no offscreen target for FBO %u", glFboExternalIndex);
|
MGLOG_W("VkFramebufferManager::TransitionOffscreenColorToAttachment skipped: FBO %u not found",
|
||||||
|
glFboExternalIndex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return TransitionColorTargetForAttachment(commandBuffer, it->second) &&
|
||||||
auto& target = it->second;
|
TransitionDepthStencilTargetForAttachment(commandBuffer, it->second);
|
||||||
if (!TransitionColorTargetForClear(commandBuffer, target)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageSubresourceRange subresourceRange{};
|
|
||||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
subresourceRange.baseMipLevel = 0;
|
|
||||||
subresourceRange.levelCount = 1;
|
|
||||||
subresourceRange.baseArrayLayer = 0;
|
|
||||||
subresourceRange.layerCount = 1;
|
|
||||||
vkCmdClearColorImage(commandBuffer, target.image, target.layout, &clearColor, 1, &subresourceRange);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VkFramebufferManager::TransitionOffscreenColorToTransferSrc(VkCommandBuffer commandBuffer,
|
Bool VkFramebufferManager::TransitionOffscreenColorToTransferSrc(VkCommandBuffer commandBuffer,
|
||||||
@@ -89,8 +78,24 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bool VkFramebufferManager::GetOffscreenRenderTarget(Uint glFboExternalIndex, VkRenderPass& outRenderPass,
|
||||||
|
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
|
||||||
|
VkFormat& outDepthStencilFormat) const {
|
||||||
|
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||||
|
if (it == m_offscreenColorTargets.end() || it->second.framebuffer == VK_NULL_HANDLE ||
|
||||||
|
it->second.renderPassLoad == VK_NULL_HANDLE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
outRenderPass = it->second.renderPassLoad;
|
||||||
|
outFramebuffer = it->second.framebuffer;
|
||||||
|
outExtent = it->second.extent;
|
||||||
|
outDepthStencilFormat = it->second.depthStencilFormat;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Bool VkFramebufferManager::RecreateOffscreenColorTarget(
|
Bool VkFramebufferManager::RecreateOffscreenColorTarget(
|
||||||
OffscreenColorTarget& target, const MG_State::GLState::FramebufferAttachmentObject& colorAttachment,
|
OffscreenColorTarget& target, const MG_State::GLState::FramebufferObject& glFbo,
|
||||||
|
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment,
|
||||||
Uint16 glObjectVersion) {
|
Uint16 glObjectVersion) {
|
||||||
DestroyOffscreenColorTarget(target);
|
DestroyOffscreenColorTarget(target);
|
||||||
|
|
||||||
@@ -144,43 +149,202 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
viewInfo.subresourceRange.layerCount = 1;
|
viewInfo.subresourceRange.layerCount = 1;
|
||||||
VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &target.imageView), "vkCreateImageView(offscreen color)");
|
VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &target.imageView), "vkCreateImageView(offscreen color)");
|
||||||
|
|
||||||
|
const auto& depthAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Depth);
|
||||||
|
const auto& stencilAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Stencil);
|
||||||
|
const Bool requestedDepthStencil =
|
||||||
|
(depthAttachment.IsValid() && !depthAttachment.IsEmpty()) ||
|
||||||
|
(stencilAttachment.IsValid() && !stencilAttachment.IsEmpty());
|
||||||
|
VkFormat depthStencilFormat = ResolveDepthStencilFormat(depthAttachment, stencilAttachment);
|
||||||
|
if (depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT) {
|
||||||
|
depthStencilFormat = FindSupportedDepthStencilFormat({VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT});
|
||||||
|
} else if (depthStencilFormat == VK_FORMAT_D32_SFLOAT) {
|
||||||
|
depthStencilFormat = FindSupportedDepthStencilFormat({VK_FORMAT_D32_SFLOAT, VK_FORMAT_D16_UNORM});
|
||||||
|
}
|
||||||
|
const Bool hasDepthStencil = (depthStencilFormat != VK_FORMAT_UNDEFINED);
|
||||||
|
if (requestedDepthStencil && !hasDepthStencil) {
|
||||||
|
MGLOG_W("VkFramebufferManager: FBO %u depth/stencil attachment exists but format is unsupported",
|
||||||
|
glFbo.GetExternalIndex());
|
||||||
|
}
|
||||||
|
if (hasDepthStencil) {
|
||||||
|
VkImageCreateInfo depthImageInfo{};
|
||||||
|
depthImageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
|
depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||||
|
depthImageInfo.extent.width = static_cast<Uint32>(size.x());
|
||||||
|
depthImageInfo.extent.height = static_cast<Uint32>(size.y());
|
||||||
|
depthImageInfo.extent.depth = 1;
|
||||||
|
depthImageInfo.mipLevels = 1;
|
||||||
|
depthImageInfo.arrayLayers = 1;
|
||||||
|
depthImageInfo.format = depthStencilFormat;
|
||||||
|
depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
|
depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||||
|
depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
VK_VERIFY(vkCreateImage(m_device, &depthImageInfo, nullptr, &target.depthStencilImage),
|
||||||
|
"vkCreateImage(offscreen depth/stencil)");
|
||||||
|
|
||||||
|
VkMemoryRequirements depthMemoryRequirements{};
|
||||||
|
vkGetImageMemoryRequirements(m_device, target.depthStencilImage, &depthMemoryRequirements);
|
||||||
|
VkMemoryAllocateInfo depthAllocInfo{};
|
||||||
|
depthAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
|
depthAllocInfo.allocationSize = depthMemoryRequirements.size;
|
||||||
|
depthAllocInfo.memoryTypeIndex =
|
||||||
|
FindMemoryType(depthMemoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
VK_VERIFY(vkAllocateMemory(m_device, &depthAllocInfo, nullptr, &target.depthStencilMemory),
|
||||||
|
"vkAllocateMemory(offscreen depth/stencil)");
|
||||||
|
VK_VERIFY(vkBindImageMemory(m_device, target.depthStencilImage, target.depthStencilMemory, 0),
|
||||||
|
"vkBindImageMemory(offscreen depth/stencil)");
|
||||||
|
|
||||||
|
VkImageAspectFlags depthAspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
|
if (depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT || depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||||
|
depthAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
}
|
||||||
|
VkImageViewCreateInfo depthViewInfo{};
|
||||||
|
depthViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
depthViewInfo.image = target.depthStencilImage;
|
||||||
|
depthViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
depthViewInfo.format = depthStencilFormat;
|
||||||
|
depthViewInfo.subresourceRange.aspectMask = depthAspectMask;
|
||||||
|
depthViewInfo.subresourceRange.baseMipLevel = 0;
|
||||||
|
depthViewInfo.subresourceRange.levelCount = 1;
|
||||||
|
depthViewInfo.subresourceRange.baseArrayLayer = 0;
|
||||||
|
depthViewInfo.subresourceRange.layerCount = 1;
|
||||||
|
VK_VERIFY(vkCreateImageView(m_device, &depthViewInfo, nullptr, &target.depthStencilImageView),
|
||||||
|
"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.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
target.extent = {static_cast<Uint32>(size.x()), static_cast<Uint32>(size.y())};
|
target.extent = {static_cast<Uint32>(size.x()), static_cast<Uint32>(size.y())};
|
||||||
target.format = format;
|
target.format = format;
|
||||||
|
target.depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
target.depthStencilFormat = depthStencilFormat;
|
||||||
target.glObjectVersion = glObjectVersion;
|
target.glObjectVersion = glObjectVersion;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkFramebufferManager::DestroyOffscreenColorTarget(OffscreenColorTarget& target) {
|
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) {
|
if (target.imageView != VK_NULL_HANDLE) {
|
||||||
vkDestroyImageView(m_device, target.imageView, nullptr);
|
vkDestroyImageView(m_device, target.imageView, nullptr);
|
||||||
target.imageView = VK_NULL_HANDLE;
|
target.imageView = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
if (target.depthStencilImageView != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyImageView(m_device, target.depthStencilImageView, nullptr);
|
||||||
|
target.depthStencilImageView = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
if (target.image != VK_NULL_HANDLE) {
|
if (target.image != VK_NULL_HANDLE) {
|
||||||
vkDestroyImage(m_device, target.image, nullptr);
|
vkDestroyImage(m_device, target.image, nullptr);
|
||||||
target.image = VK_NULL_HANDLE;
|
target.image = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
if (target.depthStencilImage != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyImage(m_device, target.depthStencilImage, nullptr);
|
||||||
|
target.depthStencilImage = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
if (target.memory != VK_NULL_HANDLE) {
|
if (target.memory != VK_NULL_HANDLE) {
|
||||||
vkFreeMemory(m_device, target.memory, nullptr);
|
vkFreeMemory(m_device, target.memory, nullptr);
|
||||||
target.memory = VK_NULL_HANDLE;
|
target.memory = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
if (target.depthStencilMemory != VK_NULL_HANDLE) {
|
||||||
|
vkFreeMemory(m_device, target.depthStencilMemory, nullptr);
|
||||||
|
target.depthStencilMemory = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
target.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
target.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
target.depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
target.extent = {0, 0};
|
target.extent = {0, 0};
|
||||||
target.format = VK_FORMAT_UNDEFINED;
|
target.format = VK_FORMAT_UNDEFINED;
|
||||||
|
target.depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||||
target.glObjectVersion = 0;
|
target.glObjectVersion = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VkFramebufferManager::TransitionColorTargetForClear(VkCommandBuffer commandBuffer, OffscreenColorTarget& target) {
|
Bool VkFramebufferManager::TransitionColorTargetForAttachment(VkCommandBuffer commandBuffer,
|
||||||
if (target.layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
OffscreenColorTarget& target) {
|
||||||
|
if (target.layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageMemoryBarrier barrier{};
|
VkImageMemoryBarrier barrier{};
|
||||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
barrier.srcAccessMask = 0;
|
barrier.srcAccessMask = 0;
|
||||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
barrier.oldLayout = target.layout;
|
barrier.oldLayout = target.layout;
|
||||||
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
barrier.image = target.image;
|
barrier.image = target.image;
|
||||||
@@ -189,10 +353,46 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
barrier.subresourceRange.levelCount = 1;
|
barrier.subresourceRange.levelCount = 1;
|
||||||
barrier.subresourceRange.baseArrayLayer = 0;
|
barrier.subresourceRange.baseArrayLayer = 0;
|
||||||
barrier.subresourceRange.layerCount = 1;
|
barrier.subresourceRange.layerCount = 1;
|
||||||
|
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
0, 0, nullptr, 0, nullptr, 1, &barrier);
|
0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||||
target.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
target.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkFramebufferManager::TransitionDepthStencilTargetForAttachment(VkCommandBuffer commandBuffer,
|
||||||
|
OffscreenColorTarget& target) {
|
||||||
|
if (target.depthStencilImage == VK_NULL_HANDLE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (target.depthStencilLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
|
if (target.depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||||
|
target.depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||||
|
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageMemoryBarrier barrier{};
|
||||||
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
barrier.srcAccessMask = 0;
|
||||||
|
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||||
|
barrier.oldLayout = target.depthStencilLayout;
|
||||||
|
barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
barrier.image = target.depthStencilImage;
|
||||||
|
barrier.subresourceRange.aspectMask = aspectMask;
|
||||||
|
barrier.subresourceRange.baseMipLevel = 0;
|
||||||
|
barrier.subresourceRange.levelCount = 1;
|
||||||
|
barrier.subresourceRange.baseArrayLayer = 0;
|
||||||
|
barrier.subresourceRange.layerCount = 1;
|
||||||
|
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||||
|
0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||||
|
target.depthStencilLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,4 +455,59 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return VK_FORMAT_UNDEFINED;
|
return VK_FORMAT_UNDEFINED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkFormat VkFramebufferManager::ResolveDepthStencilFormat(
|
||||||
|
const MG_State::GLState::FramebufferAttachmentObject& depthAttachment,
|
||||||
|
const MG_State::GLState::FramebufferAttachmentObject& stencilAttachment) {
|
||||||
|
const auto resolveAttachmentFormat = [](const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
||||||
|
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
|
||||||
|
if (attachment.IsTexture()) {
|
||||||
|
const auto texture = attachment.GetTexture();
|
||||||
|
internalFormat = texture ? texture->GetFormat() : TextureInternalFormat::Unknown;
|
||||||
|
} else if (attachment.IsRenderbuffer()) {
|
||||||
|
const auto renderbuffer = attachment.GetRenderbuffer();
|
||||||
|
internalFormat = renderbuffer ? renderbuffer->GetInternalFormat() : TextureInternalFormat::Unknown;
|
||||||
|
}
|
||||||
|
return internalFormat;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto depthFormat = resolveAttachmentFormat(depthAttachment);
|
||||||
|
const auto stencilFormat = resolveAttachmentFormat(stencilAttachment);
|
||||||
|
|
||||||
|
switch (depthFormat) {
|
||||||
|
case TextureInternalFormat::Depth24Stencil8:
|
||||||
|
case TextureInternalFormat::Depth32FStencil8:
|
||||||
|
case TextureInternalFormat::DepthStencil:
|
||||||
|
return VK_FORMAT_D24_UNORM_S8_UINT;
|
||||||
|
case TextureInternalFormat::DepthComponent16:
|
||||||
|
return VK_FORMAT_D16_UNORM;
|
||||||
|
case TextureInternalFormat::DepthComponent24:
|
||||||
|
case TextureInternalFormat::DepthComponent32:
|
||||||
|
case TextureInternalFormat::DepthComponent32F:
|
||||||
|
case TextureInternalFormat::DepthComponent:
|
||||||
|
return VK_FORMAT_D32_SFLOAT;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (stencilFormat) {
|
||||||
|
case TextureInternalFormat::Depth24Stencil8:
|
||||||
|
case TextureInternalFormat::Depth32FStencil8:
|
||||||
|
case TextureInternalFormat::DepthStencil:
|
||||||
|
return VK_FORMAT_D24_UNORM_S8_UINT;
|
||||||
|
default:
|
||||||
|
return VK_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkFormat VkFramebufferManager::FindSupportedDepthStencilFormat(const Vector<VkFormat>& candidates) const {
|
||||||
|
for (auto format : candidates) {
|
||||||
|
VkFormatProperties properties{};
|
||||||
|
vkGetPhysicalDeviceFormatProperties(m_physicalDevice, format, &properties);
|
||||||
|
if ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return VK_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
|
|||||||
@@ -27,9 +27,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
Bool EnsureOffscreenColorTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo);
|
Bool EnsureOffscreenColorTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo);
|
||||||
Bool ClearColor(VkCommandBuffer commandBuffer, Uint glFboExternalIndex, const VkClearColorValue& clearColor);
|
Bool TransitionOffscreenColorToAttachment(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||||
Bool TransitionOffscreenColorToTransferSrc(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
Bool TransitionOffscreenColorToTransferSrc(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||||
Bool GetOffscreenColorImage(Uint glFboExternalIndex, VkImage& outImage, VkExtent2D& outExtent) const;
|
Bool GetOffscreenColorImage(Uint glFboExternalIndex, VkImage& outImage, VkExtent2D& outExtent) const;
|
||||||
|
Bool GetOffscreenRenderTarget(Uint glFboExternalIndex, VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer,
|
||||||
|
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct OffscreenColorTarget {
|
struct OffscreenColorTarget {
|
||||||
@@ -39,17 +41,29 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
VkExtent2D extent = {0, 0};
|
VkExtent2D extent = {0, 0};
|
||||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||||
|
VkImage depthStencilImage = VK_NULL_HANDLE;
|
||||||
|
VkDeviceMemory depthStencilMemory = VK_NULL_HANDLE;
|
||||||
|
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;
|
Uint16 glObjectVersion = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Bool RecreateOffscreenColorTarget(OffscreenColorTarget& target,
|
Bool RecreateOffscreenColorTarget(OffscreenColorTarget& target,
|
||||||
|
const MG_State::GLState::FramebufferObject& glFbo,
|
||||||
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment,
|
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment,
|
||||||
Uint16 glObjectVersion);
|
Uint16 glObjectVersion);
|
||||||
void DestroyOffscreenColorTarget(OffscreenColorTarget& target);
|
void DestroyOffscreenColorTarget(OffscreenColorTarget& target);
|
||||||
Bool TransitionColorTargetForClear(VkCommandBuffer commandBuffer, OffscreenColorTarget& target);
|
Bool TransitionColorTargetForAttachment(VkCommandBuffer commandBuffer, OffscreenColorTarget& target);
|
||||||
|
Bool TransitionDepthStencilTargetForAttachment(VkCommandBuffer commandBuffer, OffscreenColorTarget& target);
|
||||||
Bool TransitionColorTargetForBlitSrc(VkCommandBuffer commandBuffer, OffscreenColorTarget& target);
|
Bool TransitionColorTargetForBlitSrc(VkCommandBuffer commandBuffer, OffscreenColorTarget& target);
|
||||||
Uint32 FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const;
|
Uint32 FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const;
|
||||||
static VkFormat ResolveColorFormat(const MG_State::GLState::FramebufferAttachmentObject& colorAttachment);
|
static VkFormat ResolveColorFormat(const MG_State::GLState::FramebufferAttachmentObject& colorAttachment);
|
||||||
|
static VkFormat ResolveDepthStencilFormat(const MG_State::GLState::FramebufferAttachmentObject& depthAttachment,
|
||||||
|
const MG_State::GLState::FramebufferAttachmentObject& stencilAttachment);
|
||||||
|
VkFormat FindSupportedDepthStencilFormat(const Vector<VkFormat>& candidates) const;
|
||||||
|
|
||||||
VkDevice m_device = VK_NULL_HANDLE;
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "MG_State/GLState/Core.h"
|
#include "MG_State/GLState/Core.h"
|
||||||
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
||||||
|
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
VkBool32 VulkanRenderer::DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
VkBool32 VulkanRenderer::DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
@@ -76,7 +77,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
payload.programHash = programHash;
|
payload.programHash = programHash;
|
||||||
payload.vertexInputHash = vertexInputHash;
|
payload.vertexInputHash = vertexInputHash;
|
||||||
payload.pipelineLayout = m_pipelineLayout;
|
payload.pipelineLayout = m_pipelineLayout;
|
||||||
payload.renderPass = m_renderPassLoad;
|
payload.renderPass = (m_activeRenderPass != VK_NULL_HANDLE) ? m_activeRenderPass : m_renderPassLoad;
|
||||||
payload.subpass = 0;
|
payload.subpass = 0;
|
||||||
payload.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
payload.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
payload.stages = &stages;
|
payload.stages = &stages;
|
||||||
@@ -215,39 +216,39 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_pendingClearMask != 0 &&
|
const Uint64 pendingKey = BuildPendingClearKey(drawFboExternalIndex, isDefaultFramebufferTarget);
|
||||||
(m_pendingClearDrawFboExternalIndex != drawFboExternalIndex ||
|
auto& pending = m_pendingClears[pendingKey];
|
||||||
m_pendingClearTargetsDefaultFramebuffer != isDefaultFramebufferTarget)) {
|
|
||||||
MGLOG_W("Pending clear target changed from FBO %u to FBO %u before execution; dropping previous pending clear",
|
|
||||||
m_pendingClearDrawFboExternalIndex, drawFboExternalIndex);
|
|
||||||
m_pendingClearMask = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((requestMask & GL_COLOR_BUFFER_BIT) != 0) {
|
if ((requestMask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||||
m_pendingClearColor.float32[0] = color.x();
|
pending.color.float32[0] = color.x();
|
||||||
m_pendingClearColor.float32[1] = color.y();
|
pending.color.float32[1] = color.y();
|
||||||
m_pendingClearColor.float32[2] = color.z();
|
pending.color.float32[2] = color.z();
|
||||||
m_pendingClearColor.float32[3] = color.w();
|
pending.color.float32[3] = color.w();
|
||||||
}
|
}
|
||||||
if ((requestMask & GL_DEPTH_BUFFER_BIT) != 0) {
|
if ((requestMask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||||
m_pendingClearDepth = depth;
|
pending.depth = depth;
|
||||||
}
|
}
|
||||||
if ((requestMask & GL_STENCIL_BUFFER_BIT) != 0) {
|
if ((requestMask & GL_STENCIL_BUFFER_BIT) != 0) {
|
||||||
m_pendingClearStencil = stencil;
|
pending.stencil = stencil;
|
||||||
}
|
}
|
||||||
m_pendingClearDrawFboExternalIndex = drawFboExternalIndex;
|
pending.drawFboExternalIndex = drawFboExternalIndex;
|
||||||
m_pendingClearTargetsDefaultFramebuffer = isDefaultFramebufferTarget;
|
pending.targetsDefaultFramebuffer = isDefaultFramebufferTarget;
|
||||||
m_pendingClearMask |= requestMask;
|
pending.mask |= requestMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VulkanRenderer::ConsumePendingColorClear(VkClearColorValue& outClearColor) {
|
Bool VulkanRenderer::ConsumePendingColorClear(VkClearColorValue& outClearColor) {
|
||||||
if ((m_pendingClearMask & GL_COLOR_BUFFER_BIT) == 0) {
|
for (auto it = m_pendingClears.begin(); it != m_pendingClears.end(); ++it) {
|
||||||
return false;
|
if (!it->second.targetsDefaultFramebuffer || (it->second.mask & GL_COLOR_BUFFER_BIT) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
outClearColor = it->second.color;
|
||||||
|
it->second.mask &= ~GL_COLOR_BUFFER_BIT;
|
||||||
|
if (it->second.mask == 0) {
|
||||||
|
m_pendingClears.erase(it);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
outClearColor = m_pendingClearColor;
|
|
||||||
m_pendingClearMask &= ~GL_COLOR_BUFFER_BIT;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::TransitionSwapchainImageToColorAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex) {
|
void VulkanRenderer::TransitionSwapchainImageToColorAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex) {
|
||||||
@@ -284,7 +285,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
VkClearRect clearRect{};
|
VkClearRect clearRect{};
|
||||||
clearRect.rect.offset = {0, 0};
|
clearRect.rect.offset = {0, 0};
|
||||||
clearRect.rect.extent = m_swapchainObject.GetExtent();
|
clearRect.rect.extent = m_activeRenderExtent;
|
||||||
clearRect.baseArrayLayer = 0;
|
clearRect.baseArrayLayer = 0;
|
||||||
clearRect.layerCount = 1;
|
clearRect.layerCount = 1;
|
||||||
|
|
||||||
@@ -292,11 +293,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::RecordDepthStencilClear(VkCommandBuffer commandBuffer, GLbitfield mask, Float depth, Uint32 stencil) {
|
void VulkanRenderer::RecordDepthStencilClear(VkCommandBuffer commandBuffer, GLbitfield mask, Float depth, Uint32 stencil) {
|
||||||
|
if (m_activeDepthStencilFormat == VK_FORMAT_UNDEFINED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
VkImageAspectFlags aspectMask = 0;
|
VkImageAspectFlags aspectMask = 0;
|
||||||
if ((mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
if ((mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||||
aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
}
|
}
|
||||||
if ((mask & GL_STENCIL_BUFFER_BIT) != 0 && HasStencilComponent(m_depthStencilFormat)) {
|
if ((mask & GL_STENCIL_BUFFER_BIT) != 0 && HasStencilComponent(m_activeDepthStencilFormat)) {
|
||||||
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
}
|
}
|
||||||
if (aspectMask == 0) {
|
if (aspectMask == 0) {
|
||||||
@@ -310,7 +315,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
VkClearRect clearRect{};
|
VkClearRect clearRect{};
|
||||||
clearRect.rect.offset = {0, 0};
|
clearRect.rect.offset = {0, 0};
|
||||||
clearRect.rect.extent = m_swapchainObject.GetExtent();
|
clearRect.rect.extent = m_activeRenderExtent;
|
||||||
clearRect.baseArrayLayer = 0;
|
clearRect.baseArrayLayer = 0;
|
||||||
clearRect.layerCount = 1;
|
clearRect.layerCount = 1;
|
||||||
|
|
||||||
@@ -351,50 +356,59 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
m_depthStencilImageLayouts[imageIndex] = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
m_depthStencilImageLayouts[imageIndex] = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VulkanRenderer::RecordOffscreenColorClear(VkCommandBuffer commandBuffer) {
|
|
||||||
if (!m_framebufferManager || !MG_State::pGLContext) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto fbo = MG_State::pGLContext->GetFramebufferObject(m_pendingClearDrawFboExternalIndex);
|
|
||||||
if (!fbo) {
|
|
||||||
MGLOG_W("RecordOffscreenColorClear skipped: draw FBO %u not found", m_pendingClearDrawFboExternalIndex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!m_framebufferManager->EnsureOffscreenColorTarget(m_pendingClearDrawFboExternalIndex, *fbo)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return m_framebufferManager->ClearColor(commandBuffer, m_pendingClearDrawFboExternalIndex, m_pendingClearColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::EnsureFrameRecordingStarted() {
|
void VulkanRenderer::EnsureFrameRecordingStarted() {
|
||||||
auto& frame = m_frameContext.GetCurrent();
|
auto& frame = m_frameContext.GetCurrent();
|
||||||
if (frame.isCommandRecording) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frame.hasCommandBufferRecorded) {
|
if (frame.hasCommandBufferRecorded) {
|
||||||
MGLOG_W("EnsureFrameRecordingStarted skipped: current frame command buffer is already finalized");
|
MGLOG_W("EnsureFrameRecordingStarted skipped: current frame command buffer is already finalized");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkCommandBuffer& commandBuffer = m_frameContext.BeginCommandRecording();
|
const auto drawFbo = MG_State::pGLContext
|
||||||
if (m_uniformDescriptorBinder) {
|
? MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject()
|
||||||
m_uniformDescriptorBinder->BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
: nullptr;
|
||||||
|
const auto defaultFboInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
||||||
|
const auto defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO : nullptr;
|
||||||
|
const Bool drawTargetsDefault = (drawFbo == defaultFbo) || (drawFbo == nullptr && defaultFbo != nullptr);
|
||||||
|
const Uint drawFboExternalIndex = drawFbo ? drawFbo->GetExternalIndex() : (defaultFbo ? defaultFbo->GetExternalIndex() : 0U);
|
||||||
|
const Uint64 drawTargetKey = BuildPendingClearKey(drawFboExternalIndex, drawTargetsDefault);
|
||||||
|
|
||||||
|
if (frame.isCommandRecording && m_isMainRenderPassActive) {
|
||||||
|
const Bool activeTargetMismatch =
|
||||||
|
(drawTargetsDefault != m_activeRenderTargetIsDefault) ||
|
||||||
|
(!drawTargetsDefault && m_activeDrawFboExternalIndex != drawFboExternalIndex);
|
||||||
|
if (activeTargetMismatch) {
|
||||||
|
vkCmdEndRenderPass(frame.commandBuffer);
|
||||||
|
m_isMainRenderPassActive = false;
|
||||||
|
m_activeRenderPass = VK_NULL_HANDLE;
|
||||||
|
m_activeRenderExtent = {0, 0};
|
||||||
|
m_activeDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||||
|
m_activeRenderTargetIsDefault = true;
|
||||||
|
m_activeDrawFboExternalIndex = 0;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_pendingClearMask != 0 && !m_pendingClearTargetsDefaultFramebuffer) {
|
VkCommandBuffer* commandBufferPtr = nullptr;
|
||||||
if ((m_pendingClearMask & GL_COLOR_BUFFER_BIT) != 0) {
|
if (frame.isCommandRecording) {
|
||||||
if (!RecordOffscreenColorClear(commandBuffer)) {
|
commandBufferPtr = &frame.commandBuffer;
|
||||||
MGLOG_W("Failed to clear non-default FBO %u color attachment",
|
} else {
|
||||||
m_pendingClearDrawFboExternalIndex);
|
commandBufferPtr = &m_frameContext.BeginCommandRecording();
|
||||||
}
|
if (m_uniformDescriptorBinder) {
|
||||||
m_pendingClearMask &= ~GL_COLOR_BUFFER_BIT;
|
m_uniformDescriptorBinder->BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||||
}
|
}
|
||||||
if ((m_pendingClearMask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
|
}
|
||||||
MGLOG_W("Depth/stencil clear on non-default FBO is not implemented yet (FBO %u)",
|
VkCommandBuffer& commandBuffer = *commandBufferPtr;
|
||||||
m_pendingClearDrawFboExternalIndex);
|
|
||||||
m_pendingClearMask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
if (!drawTargetsDefault) {
|
||||||
|
if (!m_framebufferManager || !drawFbo) {
|
||||||
|
MGLOG_W("EnsureFrameRecordingStarted skipped: offscreen draw target is unavailable");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!m_framebufferManager->EnsureOffscreenColorTarget(drawFboExternalIndex, *drawFbo)) {
|
||||||
|
MGLOG_W("EnsureFrameRecordingStarted skipped: failed to materialize offscreen target for FBO %u",
|
||||||
|
drawFboExternalIndex);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This frame touched only offscreen resources. Present still requires
|
// This frame touched only offscreen resources. Present still requires
|
||||||
@@ -420,33 +434,90 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
0, 0, nullptr, 0, nullptr, 1, &presentBarrier);
|
0, 0, nullptr, 0, nullptr, 1, &presentBarrier);
|
||||||
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_framebufferManager->TransitionOffscreenColorToAttachment(commandBuffer, drawFboExternalIndex)) {
|
||||||
|
MGLOG_W("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)) {
|
||||||
|
MGLOG_W("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);
|
||||||
|
m_isMainRenderPassActive = true;
|
||||||
|
m_activeRenderPass = offscreenRenderPass;
|
||||||
|
m_activeRenderExtent = offscreenExtent;
|
||||||
|
m_activeDepthStencilFormat = offscreenDepthStencilFormat;
|
||||||
|
m_activeRenderTargetIsDefault = false;
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
pendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
if (pendingIt->second.mask == 0) {
|
||||||
|
m_pendingClears.erase(pendingIt);
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired);
|
TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired);
|
||||||
TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired);
|
TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired);
|
||||||
|
|
||||||
const Bool useRenderPassClearValue = (m_pendingClearMask & GL_COLOR_BUFFER_BIT) != 0;
|
|
||||||
VkClearValue clearValues[1]{};
|
|
||||||
if (useRenderPassClearValue) {
|
|
||||||
clearValues[0].color = m_pendingClearColor;
|
|
||||||
m_pendingClearMask &= ~GL_COLOR_BUFFER_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkRenderPassBeginInfo renderPassInfo{};
|
VkRenderPassBeginInfo renderPassInfo{};
|
||||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
renderPassInfo.renderPass = useRenderPassClearValue ? m_renderPassClear : m_renderPassLoad;
|
renderPassInfo.renderPass = m_renderPassLoad;
|
||||||
renderPassInfo.framebuffer = m_framebuffers[m_imageIndexAcquired];
|
renderPassInfo.framebuffer = m_framebuffers[m_imageIndexAcquired];
|
||||||
renderPassInfo.renderArea.offset = {0, 0};
|
renderPassInfo.renderArea.offset = {0, 0};
|
||||||
renderPassInfo.renderArea.extent = m_swapchainObject.GetExtent();
|
renderPassInfo.renderArea.extent = m_swapchainObject.GetExtent();
|
||||||
renderPassInfo.clearValueCount = useRenderPassClearValue ? 1 : 0;
|
renderPassInfo.clearValueCount = 0;
|
||||||
renderPassInfo.pClearValues = useRenderPassClearValue ? clearValues : nullptr;
|
renderPassInfo.pClearValues = nullptr;
|
||||||
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
m_isMainRenderPassActive = true;
|
m_isMainRenderPassActive = true;
|
||||||
|
m_activeRenderPass = renderPassInfo.renderPass;
|
||||||
if ((m_pendingClearMask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
|
m_activeRenderExtent = renderPassInfo.renderArea.extent;
|
||||||
RecordDepthStencilClear(commandBuffer, m_pendingClearMask, m_pendingClearDepth, m_pendingClearStencil);
|
m_activeDepthStencilFormat = m_depthStencilFormat;
|
||||||
m_pendingClearMask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
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);
|
||||||
|
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);
|
||||||
|
pendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
if (pendingIt->second.mask == 0) {
|
||||||
|
m_pendingClears.erase(pendingIt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,6 +530,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (m_isMainRenderPassActive) {
|
if (m_isMainRenderPassActive) {
|
||||||
vkCmdEndRenderPass(frame.commandBuffer);
|
vkCmdEndRenderPass(frame.commandBuffer);
|
||||||
m_isMainRenderPassActive = false;
|
m_isMainRenderPassActive = false;
|
||||||
|
m_activeRenderPass = VK_NULL_HANDLE;
|
||||||
|
m_activeRenderExtent = {0, 0};
|
||||||
|
m_activeDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||||
|
m_activeRenderTargetIsDefault = true;
|
||||||
|
m_activeDrawFboExternalIndex = 0;
|
||||||
}
|
}
|
||||||
m_frameContext.EndCommandRecording();
|
m_frameContext.EndCommandRecording();
|
||||||
}
|
}
|
||||||
@@ -559,7 +635,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VkCommandBuffer& commandBuffer = frame.commandBuffer;
|
VkCommandBuffer& commandBuffer = frame.commandBuffer;
|
||||||
const auto swapchainExtent = m_swapchainObject.GetExtent();
|
const auto activeExtent = m_activeRenderExtent;
|
||||||
|
|
||||||
if (payload.program == nullptr) {
|
if (payload.program == nullptr) {
|
||||||
MGLOG_W("DrawArrays skipped: no current program is bound");
|
MGLOG_W("DrawArrays skipped: no current program is bound");
|
||||||
@@ -601,15 +677,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VkViewport viewport{};
|
VkViewport viewport{};
|
||||||
viewport.x = 0.0f;
|
viewport.x = 0.0f;
|
||||||
viewport.y = 0.0f;
|
viewport.y = 0.0f;
|
||||||
viewport.width = static_cast<float>(swapchainExtent.width);
|
viewport.width = static_cast<float>(activeExtent.width);
|
||||||
viewport.height = static_cast<float>(swapchainExtent.height);
|
viewport.height = static_cast<float>(activeExtent.height);
|
||||||
viewport.minDepth = 0.0f;
|
viewport.minDepth = 0.0f;
|
||||||
viewport.maxDepth = 1.0f;
|
viewport.maxDepth = 1.0f;
|
||||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||||
|
|
||||||
VkRect2D scissor{};
|
VkRect2D scissor{};
|
||||||
scissor.offset = {0, 0};
|
scissor.offset = {0, 0};
|
||||||
scissor.extent = swapchainExtent;
|
scissor.extent = activeExtent;
|
||||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||||
|
|
||||||
vkCmdDraw(commandBuffer, static_cast<Uint32>(payload.count), 1, static_cast<Uint32>(payload.first), 0);
|
vkCmdDraw(commandBuffer, static_cast<Uint32>(payload.count), 1, static_cast<Uint32>(payload.first), 0);
|
||||||
@@ -687,7 +763,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VkCommandBuffer& commandBuffer = frame.commandBuffer;
|
VkCommandBuffer& commandBuffer = frame.commandBuffer;
|
||||||
const auto swapchainExtent = m_swapchainObject.GetExtent();
|
const auto activeExtent = m_activeRenderExtent;
|
||||||
|
|
||||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineToBind);
|
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineToBind);
|
||||||
if (m_uniformDescriptorBinder &&
|
if (m_uniformDescriptorBinder &&
|
||||||
@@ -711,15 +787,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VkViewport viewport{};
|
VkViewport viewport{};
|
||||||
viewport.x = 0.0f;
|
viewport.x = 0.0f;
|
||||||
viewport.y = 0.0f;
|
viewport.y = 0.0f;
|
||||||
viewport.width = static_cast<float>(swapchainExtent.width);
|
viewport.width = static_cast<float>(activeExtent.width);
|
||||||
viewport.height = static_cast<float>(swapchainExtent.height);
|
viewport.height = static_cast<float>(activeExtent.height);
|
||||||
viewport.minDepth = 0.0f;
|
viewport.minDepth = 0.0f;
|
||||||
viewport.maxDepth = 1.0f;
|
viewport.maxDepth = 1.0f;
|
||||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||||
|
|
||||||
VkRect2D scissor{};
|
VkRect2D scissor{};
|
||||||
scissor.offset = {0, 0};
|
scissor.offset = {0, 0};
|
||||||
scissor.extent = swapchainExtent;
|
scissor.extent = activeExtent;
|
||||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||||
|
|
||||||
vkCmdBindIndexBuffer(commandBuffer, m_indexBuffer.GetHandle(), 0, vkIndexType);
|
vkCmdBindIndexBuffer(commandBuffer, m_indexBuffer.GetHandle(), 0, vkIndexType);
|
||||||
@@ -756,6 +832,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (m_isMainRenderPassActive) {
|
if (m_isMainRenderPassActive) {
|
||||||
vkCmdEndRenderPass(commandBuffer);
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
m_isMainRenderPassActive = false;
|
m_isMainRenderPassActive = false;
|
||||||
|
m_activeRenderPass = VK_NULL_HANDLE;
|
||||||
|
m_activeRenderExtent = {0, 0};
|
||||||
|
m_activeDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||||
|
m_activeRenderTargetIsDefault = true;
|
||||||
|
m_activeDrawFboExternalIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_framebufferManager || !MG_State::pGLContext) {
|
if (!m_framebufferManager || !MG_State::pGLContext) {
|
||||||
@@ -865,37 +946,166 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
MOBILEGL_ASSERT(m_imageIndexAcquired < m_swapchainObject.GetImageCount(),
|
MOBILEGL_ASSERT(m_imageIndexAcquired < m_swapchainObject.GetImageCount(),
|
||||||
"Present, acquired image index out of range");
|
"Present, acquired image index out of range");
|
||||||
auto& frame = m_frameContext.GetCurrent();
|
auto& frame = m_frameContext.GetCurrent();
|
||||||
if (m_pendingClearMask != 0 && frame.hasCommandBufferRecorded) {
|
if (!m_pendingClears.empty() && frame.hasCommandBufferRecorded) {
|
||||||
MGLOG_W("Dropping pending clear for current frame because command buffer is already finalized");
|
MGLOG_W("Dropping pending clears for current frame because command buffer is already finalized");
|
||||||
m_pendingClearMask = 0;
|
m_pendingClears.clear();
|
||||||
} else if (m_pendingClearMask != 0 && frame.isCommandRecording) {
|
} else if (!m_pendingClears.empty()) {
|
||||||
if (m_pendingClearTargetsDefaultFramebuffer && m_isMainRenderPassActive) {
|
auto activateTarget = [&](Bool targetIsDefault, Uint targetFboExternalIndex) -> Bool {
|
||||||
if ((m_pendingClearMask & GL_COLOR_BUFFER_BIT) != 0) {
|
const Bool alreadyMatched =
|
||||||
RecordColorClear(frame.commandBuffer, m_pendingClearColor);
|
frame.isCommandRecording &&
|
||||||
|
m_isMainRenderPassActive &&
|
||||||
|
(targetIsDefault == m_activeRenderTargetIsDefault) &&
|
||||||
|
(targetIsDefault || targetFboExternalIndex == m_activeDrawFboExternalIndex);
|
||||||
|
if (alreadyMatched) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if ((m_pendingClearMask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
|
if (frame.hasCommandBufferRecorded) {
|
||||||
RecordDepthStencilClear(frame.commandBuffer, m_pendingClearMask, m_pendingClearDepth, m_pendingClearStencil);
|
return false;
|
||||||
}
|
}
|
||||||
m_pendingClearMask = 0;
|
if (!frame.isCommandRecording) {
|
||||||
} else if (!m_pendingClearTargetsDefaultFramebuffer) {
|
m_frameContext.BeginCommandRecording();
|
||||||
if ((m_pendingClearMask & GL_COLOR_BUFFER_BIT) != 0) {
|
if (m_uniformDescriptorBinder) {
|
||||||
if (!RecordOffscreenColorClear(frame.commandBuffer)) {
|
m_uniformDescriptorBinder->BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||||
MGLOG_W("Present: failed to clear non-default FBO %u color attachment",
|
|
||||||
m_pendingClearDrawFboExternalIndex);
|
|
||||||
}
|
}
|
||||||
m_pendingClearMask &= ~GL_COLOR_BUFFER_BIT;
|
|
||||||
}
|
}
|
||||||
if ((m_pendingClearMask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
|
VkCommandBuffer commandBuffer = frame.commandBuffer;
|
||||||
MGLOG_W("Present: depth/stencil clear on non-default FBO is not implemented yet (FBO %u)",
|
|
||||||
m_pendingClearDrawFboExternalIndex);
|
if (m_isMainRenderPassActive) {
|
||||||
m_pendingClearMask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
|
m_isMainRenderPassActive = false;
|
||||||
|
m_activeRenderPass = VK_NULL_HANDLE;
|
||||||
|
m_activeRenderExtent = {0, 0};
|
||||||
|
m_activeDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||||
|
m_activeRenderTargetIsDefault = true;
|
||||||
|
m_activeDrawFboExternalIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetIsDefault) {
|
||||||
|
TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired);
|
||||||
|
TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired);
|
||||||
|
|
||||||
|
VkRenderPassBeginInfo renderPassInfo{};
|
||||||
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
|
renderPassInfo.renderPass = m_renderPassLoad;
|
||||||
|
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);
|
||||||
|
m_isMainRenderPassActive = true;
|
||||||
|
m_activeRenderPass = renderPassInfo.renderPass;
|
||||||
|
m_activeRenderExtent = renderPassInfo.renderArea.extent;
|
||||||
|
m_activeDepthStencilFormat = m_depthStencilFormat;
|
||||||
|
m_activeRenderTargetIsDefault = true;
|
||||||
|
m_activeDrawFboExternalIndex = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_framebufferManager || !MG_State::pGLContext) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto pendingFbo = MG_State::pGLContext->GetFramebufferObject(targetFboExternalIndex);
|
||||||
|
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)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto swapchainOldLayout = m_swapchainObject.GetImageLayout(m_imageIndexAcquired);
|
||||||
|
if (swapchainOldLayout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR &&
|
||||||
|
swapchainOldLayout != VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR) {
|
||||||
|
VkImageMemoryBarrier presentBarrier{};
|
||||||
|
presentBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
presentBarrier.srcAccessMask = 0;
|
||||||
|
presentBarrier.dstAccessMask = 0;
|
||||||
|
presentBarrier.oldLayout = swapchainOldLayout;
|
||||||
|
presentBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
|
presentBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
presentBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
presentBarrier.image = m_swapchainObject.GetImage(m_imageIndexAcquired);
|
||||||
|
presentBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
presentBarrier.subresourceRange.baseMipLevel = 0;
|
||||||
|
presentBarrier.subresourceRange.levelCount = 1;
|
||||||
|
presentBarrier.subresourceRange.baseArrayLayer = 0;
|
||||||
|
presentBarrier.subresourceRange.layerCount = 1;
|
||||||
|
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||||
|
0, 0, nullptr, 0, nullptr, 1, &presentBarrier);
|
||||||
|
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_isMainRenderPassActive = true;
|
||||||
|
m_activeRenderPass = offscreenRenderPass;
|
||||||
|
m_activeRenderExtent = offscreenExtent;
|
||||||
|
m_activeDepthStencilFormat = offscreenDepthStencilFormat;
|
||||||
|
m_activeRenderTargetIsDefault = false;
|
||||||
|
m_activeDrawFboExternalIndex = targetFboExternalIndex;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
while (!m_pendingClears.empty()) {
|
||||||
|
auto pendingIt = m_pendingClears.end();
|
||||||
|
if (m_isMainRenderPassActive) {
|
||||||
|
const Uint64 activeKey =
|
||||||
|
BuildPendingClearKey(m_activeDrawFboExternalIndex, m_activeRenderTargetIsDefault);
|
||||||
|
pendingIt = m_pendingClears.find(activeKey);
|
||||||
|
}
|
||||||
|
if (pendingIt == m_pendingClears.end()) {
|
||||||
|
pendingIt = m_pendingClears.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto pendingTarget = pendingIt->second;
|
||||||
|
if (!activateTarget(pendingTarget.targetsDefaultFramebuffer, pendingTarget.drawFboExternalIndex)) {
|
||||||
|
MGLOG_W("Present: dropping pending clear because target activation failed (FBO %u, default=%d)",
|
||||||
|
pendingTarget.drawFboExternalIndex, pendingTarget.targetsDefaultFramebuffer);
|
||||||
|
m_pendingClears.erase(pendingIt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Uint64 activeKey =
|
||||||
|
BuildPendingClearKey(m_activeDrawFboExternalIndex, m_activeRenderTargetIsDefault);
|
||||||
|
auto activePendingIt = m_pendingClears.find(activeKey);
|
||||||
|
if (activePendingIt == m_pendingClears.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((activePendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||||
|
RecordColorClear(frame.commandBuffer, 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);
|
||||||
|
activePendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
if (activePendingIt->second.mask == 0) {
|
||||||
|
m_pendingClears.erase(activePendingIt);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
MGLOG_W("Present: pending default-FBO clear cannot execute because no render pass is active");
|
|
||||||
m_pendingClearMask = 0;
|
|
||||||
}
|
}
|
||||||
} else if (m_pendingClearMask != 0) {
|
|
||||||
EnsureFrameRecordingStarted();
|
|
||||||
}
|
}
|
||||||
EndFrameRecordingIfNeeded();
|
EndFrameRecordingIfNeeded();
|
||||||
|
|
||||||
@@ -1312,6 +1522,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Uint64 VulkanRenderer::BuildPendingClearKey(Uint drawFboExternalIndex, Bool targetsDefaultFramebuffer) {
|
||||||
|
return (static_cast<Uint64>(targetsDefaultFramebuffer ? 1 : 0) << 63) |
|
||||||
|
static_cast<Uint64>(drawFboExternalIndex);
|
||||||
|
}
|
||||||
|
|
||||||
Bool VulkanRenderer::HasStencilComponent(VkFormat format) {
|
Bool VulkanRenderer::HasStencilComponent(VkFormat format) {
|
||||||
return format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT;
|
return format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||||
}
|
}
|
||||||
@@ -1630,6 +1845,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
m_frameContext.GetCurrent().hasCommandBufferRecorded = false;
|
m_frameContext.GetCurrent().hasCommandBufferRecorded = false;
|
||||||
}
|
}
|
||||||
m_isMainRenderPassActive = false;
|
m_isMainRenderPassActive = false;
|
||||||
|
m_activeRenderPass = VK_NULL_HANDLE;
|
||||||
|
m_activeRenderExtent = {0, 0};
|
||||||
|
m_activeDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||||
|
m_activeRenderTargetIsDefault = true;
|
||||||
|
m_activeDrawFboExternalIndex = 0;
|
||||||
|
m_pendingClears.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
|
|||||||
@@ -74,6 +74,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
void RecreateSwapchain();
|
void RecreateSwapchain();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct PendingClearState {
|
||||||
|
GLbitfield mask = 0;
|
||||||
|
VkClearColorValue color = {{0.0f, 0.0f, 0.0f, 1.0f}};
|
||||||
|
Float depth = 1.0f;
|
||||||
|
Uint32 stencil = 0;
|
||||||
|
Uint drawFboExternalIndex = 0;
|
||||||
|
Bool targetsDefaultFramebuffer = true;
|
||||||
|
};
|
||||||
|
|
||||||
struct QueueFamilyIndices {
|
struct QueueFamilyIndices {
|
||||||
Int32 graphicsFamily = -1;
|
Int32 graphicsFamily = -1;
|
||||||
Int32 presentFamily = -1;
|
Int32 presentFamily = -1;
|
||||||
@@ -129,13 +138,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
Uint m_imageIndexAcquired = 0;
|
Uint m_imageIndexAcquired = 0;
|
||||||
FrameContext m_frameContext;
|
FrameContext m_frameContext;
|
||||||
GLbitfield m_pendingClearMask = 0;
|
UnorderedMap<Uint64, PendingClearState> m_pendingClears;
|
||||||
VkClearColorValue m_pendingClearColor = {{0.0f, 0.0f, 0.0f, 1.0f}};
|
|
||||||
Float m_pendingClearDepth = 1.0f;
|
|
||||||
Uint32 m_pendingClearStencil = 0;
|
|
||||||
Uint m_pendingClearDrawFboExternalIndex = 0;
|
|
||||||
Bool m_pendingClearTargetsDefaultFramebuffer = true;
|
|
||||||
Bool m_isMainRenderPassActive = false;
|
Bool m_isMainRenderPassActive = false;
|
||||||
|
VkRenderPass m_activeRenderPass = VK_NULL_HANDLE;
|
||||||
|
VkExtent2D m_activeRenderExtent = {0, 0};
|
||||||
|
VkFormat m_activeDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||||
|
Bool m_activeRenderTargetIsDefault = true;
|
||||||
|
Uint m_activeDrawFboExternalIndex = 0;
|
||||||
|
|
||||||
UniquePtr<PipelineFactory> m_pipelineFactory;
|
UniquePtr<PipelineFactory> m_pipelineFactory;
|
||||||
UniquePtr<ProgramFactory> m_programFactory;
|
UniquePtr<ProgramFactory> m_programFactory;
|
||||||
@@ -167,7 +176,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
void TransitionDepthStencilImageToAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex);
|
void TransitionDepthStencilImageToAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex);
|
||||||
void RecordColorClear(VkCommandBuffer commandBuffer, const VkClearColorValue& clearColor);
|
void RecordColorClear(VkCommandBuffer commandBuffer, const VkClearColorValue& clearColor);
|
||||||
void RecordDepthStencilClear(VkCommandBuffer commandBuffer, GLbitfield mask, Float depth, Uint32 stencil);
|
void RecordDepthStencilClear(VkCommandBuffer commandBuffer, GLbitfield mask, Float depth, Uint32 stencil);
|
||||||
Bool RecordOffscreenColorClear(VkCommandBuffer commandBuffer);
|
|
||||||
void EndFrameRecordingIfNeeded();
|
void EndFrameRecordingIfNeeded();
|
||||||
Bool UploadAndBindVertexStreams(
|
Bool UploadAndBindVertexStreams(
|
||||||
const VertexInputStateFactory::BackendVertexInputState& vertexInputState,
|
const VertexInputStateFactory::BackendVertexInputState& vertexInputState,
|
||||||
@@ -185,6 +193,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
static Bool IsNecessaryDeviceExtensionSupported(VkPhysicalDevice device);
|
static Bool IsNecessaryDeviceExtensionSupported(VkPhysicalDevice device);
|
||||||
static Bool GetMoreCapablePhysicalDevice(VkPhysicalDevice newVkDevice, VkSurfaceKHR surface, const PhysicalDevice& compareWithDevice, PhysicalDevice& outBetterDevice);
|
static Bool GetMoreCapablePhysicalDevice(VkPhysicalDevice newVkDevice, VkSurfaceKHR surface, const PhysicalDevice& compareWithDevice, PhysicalDevice& outBetterDevice);
|
||||||
Uint32 FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const;
|
Uint32 FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const;
|
||||||
|
static Uint64 BuildPendingClearKey(Uint drawFboExternalIndex, Bool targetsDefaultFramebuffer);
|
||||||
static Bool HasStencilComponent(VkFormat format);
|
static Bool HasStencilComponent(VkFormat format);
|
||||||
static VkFormat FindSupportedDepthStencilFormat(VkPhysicalDevice physicalDevice);
|
static VkFormat FindSupportedDepthStencilFormat(VkPhysicalDevice physicalDevice);
|
||||||
static constexpr VkDynamicState s_dynamicStates[] = {
|
static constexpr VkDynamicState s_dynamicStates[] = {
|
||||||
|
|||||||
Reference in New Issue
Block a user