Merge pull request #13535 from hrydgard/vk-separate-layout-transition

Vk: Separate layout transitions from renderpasses again.
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2020-10-11 12:22:11 +02:00
commit 4ff059d3d8
7 files changed
+205 -249

No files matched your search

-18
View File
@@ -1126,24 +1126,6 @@ void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int
VkImageLayout oldImageLayout, VkImageLayout newImageLayout,
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) {
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR
if (aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) {
// Hack to disable transaction elimination on ARM Mali.
if (oldImageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || oldImageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
oldImageLayout = VK_IMAGE_LAYOUT_GENERAL;
if (newImageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || newImageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
newImageLayout = VK_IMAGE_LAYOUT_GENERAL;
}
#endif
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_DEPTH_STENCIL
if (aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) {
// Hack to disable transaction elimination on ARM Mali.
if (oldImageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || oldImageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
oldImageLayout = VK_IMAGE_LAYOUT_GENERAL;
if (newImageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || newImageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
newImageLayout = VK_IMAGE_LAYOUT_GENERAL;
}
#endif
VkImageMemoryBarrier image_memory_barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
image_memory_barrier.srcAccessMask = srcAccessMask;
image_memory_barrier.dstAccessMask = dstAccessMask;
-6
View File
@@ -107,12 +107,6 @@ private:
std::vector<Callback> callbacks_;
};
// Useful for debugging on ARM Mali. This eliminates transaction elimination
// which can cause artifacts if you get barriers wrong (or if there are driver bugs).
// Cost is reduced performance on some GPU architectures.
// #define VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR
// #define VULKAN_USE_GENERAL_LAYOUT_FOR_DEPTH_STENCIL
// VulkanContext manages the device and swapchain, and deferred deletion of objects.
class VulkanContext {
public:
+201 -194
View File
@@ -12,8 +12,7 @@ void VulkanQueueRunner::CreateDeviceObjects() {
INFO_LOG(G3D, "VulkanQueueRunner::CreateDeviceObjects");
InitBackbufferRenderPass();
framebufferRenderPass_ = GetRenderPass(VKRRenderPassAction::CLEAR, VKRRenderPassAction::CLEAR, VKRRenderPassAction::CLEAR,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
framebufferRenderPass_ = GetRenderPass(VKRRenderPassAction::CLEAR, VKRRenderPassAction::CLEAR, VKRRenderPassAction::CLEAR);
#if 0
// Just to check whether it makes sense to split some of these. drawidx is way bigger than the others...
@@ -126,22 +125,13 @@ void VulkanQueueRunner::InitBackbufferRenderPass() {
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // Don't care about storing backbuffer Z - we clear it anyway.
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_DEPTH_STENCIL
attachments[1].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_GENERAL;
#else
attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
#endif
attachments[1].flags = 0;
VkAttachmentReference color_reference{};
color_reference.attachment = 0;
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR
color_reference.layout = VK_IMAGE_LAYOUT_GENERAL;
#else
color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
#endif
VkAttachmentReference depth_reference{};
depth_reference.attachment = 1;
@@ -204,13 +194,8 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) {
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR
attachments[0].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_GENERAL;
#else
attachments[0].initialLayout = key.prevColorLayout;
attachments[0].finalLayout = key.finalColorLayout;
#endif
attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments[0].flags = 0;
attachments[1].format = vulkan_->GetDeviceInfo().preferredDepthStencilFormat;
@@ -239,13 +224,8 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) {
}
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_DEPTH_STENCIL
attachments[1].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_GENERAL;
#else
attachments[1].initialLayout = key.prevDepthStencilLayout;
attachments[1].finalLayout = key.finalDepthStencilLayout;
#endif
attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments[1].flags = 0;
VkAttachmentReference color_reference{};
@@ -268,136 +248,12 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) {
subpass.preserveAttachmentCount = 0;
subpass.pPreserveAttachments = nullptr;
VkSubpassDependency deps[2]{};
int numDeps = 0;
switch (key.prevColorLayout) {
case VK_IMAGE_LAYOUT_UNDEFINED:
// No need to specify stage or access.
break;
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
// Already the right color layout. Unclear that we need to do a lot here..
break;
case VK_IMAGE_LAYOUT_GENERAL:
// We came from the Mali workaround, and are transitioning back to COLOR_ATTACHMENT_OPTIMAL.
deps[numDeps].srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
deps[numDeps].srcStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
deps[numDeps].srcAccessMask |= VK_ACCESS_SHADER_READ_BIT;
deps[numDeps].srcStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
deps[numDeps].srcAccessMask |= VK_ACCESS_TRANSFER_WRITE_BIT;
deps[numDeps].srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
deps[numDeps].srcAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
deps[numDeps].srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
default:
_dbg_assert_msg_(false, "GetRenderPass: Unexpected color layout %d", (int)key.prevColorLayout);
break;
}
switch (key.prevDepthStencilLayout) {
case VK_IMAGE_LAYOUT_UNDEFINED:
// No need to specify stage or access.
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
// Already the right depth layout. Unclear that we need to do a lot here..
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
deps[numDeps].srcAccessMask |= VK_ACCESS_SHADER_READ_BIT;
deps[numDeps].srcStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
deps[numDeps].srcAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
deps[numDeps].srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
deps[numDeps].srcAccessMask |= VK_ACCESS_TRANSFER_WRITE_BIT;
deps[numDeps].srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
default:
_dbg_assert_msg_(false, "GetRenderPass: Unexpected depth layout %d", (int)key.prevDepthStencilLayout);
break;
}
if (deps[numDeps].srcAccessMask) {
deps[numDeps].srcSubpass = VK_SUBPASS_EXTERNAL;
deps[numDeps].dstSubpass = 0;
deps[numDeps].dependencyFlags = 0;
deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
deps[numDeps].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
numDeps++;
}
// And the final transition.
// Don't need to transition it if VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL.
switch (key.finalColorLayout) {
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
deps[numDeps].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
deps[numDeps].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
deps[numDeps].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_UNDEFINED:
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
// Nothing to do.
break;
default:
_dbg_assert_msg_(false, "GetRenderPass: Unexpected final color layout %d", (int)key.finalColorLayout);
break;
}
switch (key.finalDepthStencilLayout) {
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
deps[numDeps].dstAccessMask |= VK_ACCESS_SHADER_READ_BIT;
deps[numDeps].dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
deps[numDeps].dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
deps[numDeps].dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
deps[numDeps].dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
deps[numDeps].dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_UNDEFINED:
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
// Nothing to do.
break;
default:
_dbg_assert_msg_(false, "GetRenderPass: Unexpected final depth layout %d", (int)key.finalDepthStencilLayout);
break;
}
if (deps[numDeps].dstAccessMask) {
deps[numDeps].srcSubpass = 0;
deps[numDeps].dstSubpass = VK_SUBPASS_EXTERNAL;
deps[numDeps].dependencyFlags = 0;
deps[numDeps].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
deps[numDeps].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
numDeps++;
}
VkRenderPassCreateInfo rp{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
rp.attachmentCount = 2;
rp.pAttachments = attachments;
rp.subpassCount = 1;
rp.pSubpasses = &subpass;
if (numDeps) {
rp.dependencyCount = numDeps;
rp.pDependencies = deps;
}
VkResult res = vkCreateRenderPass(vulkan_->GetDevice(), &rp, nullptr, &pass);
_assert_(res == VK_SUCCESS);
_assert_(pass != VK_NULL_HANDLE);
@@ -1016,6 +872,194 @@ void VulkanQueueRunner::LogReadbackImage(const VKRStep &step) {
INFO_LOG(G3D, "%s", StepToString(step).c_str());
}
void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout colorLayout, VkImage depthStencilImage, VkImageLayout depthStencilLayout) {
VkPipelineStageFlags srcStageMask = 0;
VkPipelineStageFlags dstStageMask = 0;
int barrierCount = 0;
VkImageMemoryBarrier barrier[2]{};
if (colorLayout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier[0].pNext = nullptr;
switch (colorLayout) {
case VK_IMAGE_LAYOUT_UNDEFINED:
// No need to specify stage or access.
break;
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
// Already the right color layout. Unclear that we need to do a lot here..
break;
case VK_IMAGE_LAYOUT_GENERAL:
// We came from the Mali workaround, and are transitioning back to COLOR_ATTACHMENT_OPTIMAL.
barrier[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
srcStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
barrier[0].srcAccessMask |= VK_ACCESS_SHADER_READ_BIT;
srcStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
barrier[0].srcAccessMask |= VK_ACCESS_TRANSFER_WRITE_BIT;
srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
barrier[0].srcAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
default:
_dbg_assert_msg_(false, "GetRenderPass: Unexpected color layout %d", (int)colorLayout);
break;
}
dstStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
barrier[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier[0].oldLayout = colorLayout;
barrier[0].newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier[0].image = colorImage;
barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier[0].subresourceRange.baseMipLevel = 0;
barrier[0].subresourceRange.levelCount = 1;
barrier[0].subresourceRange.layerCount = 1;
barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrierCount++;
}
if (depthStencilImage != VK_NULL_HANDLE && depthStencilLayout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
barrier[barrierCount].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier[barrierCount].pNext = nullptr;
switch (depthStencilLayout) {
case VK_IMAGE_LAYOUT_UNDEFINED:
// No need to specify stage or access.
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
// Already the right depth layout. Unclear that we need to do a lot here..
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
barrier[barrierCount].srcAccessMask |= VK_ACCESS_SHADER_READ_BIT;
srcStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
barrier[barrierCount].srcAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
barrier[barrierCount].srcAccessMask |= VK_ACCESS_TRANSFER_WRITE_BIT;
srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
default:
_dbg_assert_msg_(false, "GetRenderPass: Unexpected depth layout %d", (int)depthStencilLayout);
break;
}
dstStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
barrier[barrierCount].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
barrier[barrierCount].oldLayout = depthStencilLayout;
barrier[barrierCount].newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
barrier[barrierCount].image = depthStencilImage;
barrier[barrierCount].subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
barrier[barrierCount].subresourceRange.baseMipLevel = 0;
barrier[barrierCount].subresourceRange.levelCount = 1;
barrier[barrierCount].subresourceRange.layerCount = 1;
barrier[barrierCount].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier[barrierCount].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrierCount++;
}
if (barrierCount) {
vkCmdPipelineBarrier(cmd, srcStageMask, dstStageMask, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, barrierCount, barrier);
}
}
void TransitionFromOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout colorLayout, VkImage depthStencilImage, VkImageLayout depthStencilLayout) {
VkPipelineStageFlags srcStageMask = 0;
VkPipelineStageFlags dstStageMask = 0;
// If layouts aren't optimal, transition them.
VkImageMemoryBarrier barrier[2]{};
int barrierCount = 0;
if (colorLayout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier[0].pNext = nullptr;
srcStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
barrier[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
// And the final transition.
// Don't need to transition it if VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL.
switch (colorLayout) {
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_UNDEFINED:
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
// Nothing to do.
break;
default:
_dbg_assert_msg_(false, "GetRenderPass: Unexpected final color layout %d", (int)colorLayout);
break;
}
barrier[0].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier[0].newLayout = colorLayout;
barrier[0].image = colorImage;
barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier[0].subresourceRange.baseMipLevel = 0;
barrier[0].subresourceRange.levelCount = 1;
barrier[0].subresourceRange.layerCount = 1;
barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrierCount++;
}
if (depthStencilImage && depthStencilLayout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
barrier[barrierCount].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier[barrierCount].pNext = nullptr;
srcStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
barrier[barrierCount].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
switch (depthStencilLayout) {
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
barrier[barrierCount].dstAccessMask |= VK_ACCESS_SHADER_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
barrier[barrierCount].dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
barrier[barrierCount].dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_UNDEFINED:
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
// Nothing to do.
break;
default:
_dbg_assert_msg_(false, "GetRenderPass: Unexpected final depth layout %d", (int)depthStencilLayout);
break;
}
barrier[barrierCount].oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
barrier[barrierCount].newLayout = depthStencilLayout;
barrier[barrierCount].image = depthStencilImage;
barrier[barrierCount].subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
barrier[barrierCount].subresourceRange.baseMipLevel = 0;
barrier[barrierCount].subresourceRange.levelCount = 1;
barrier[barrierCount].subresourceRange.layerCount = 1;
barrier[barrierCount].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier[barrierCount].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrierCount++;
}
if (barrierCount) {
vkCmdPipelineBarrier(cmd, srcStageMask, dstStageMask, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, barrierCount, barrier);
}
}
void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer cmd) {
// TODO: If there are multiple, we can transition them together.
@@ -1311,8 +1355,10 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
}
vkCmdEndRenderPass(cmd);
// The renderpass handles the layout transition.
if (fb) {
// If the desired final layout aren't the optimal layout for rendering, transition.
TransitionFromOptimal(cmd, fb->color.image, step.render.finalColorLayout, fb->depth.image, step.render.finalDepthStencilLayout);
fb->color.layout = step.render.finalColorLayout;
fb->depth.layout = step.render.finalDepthStencilLayout;
}
@@ -1350,15 +1396,12 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step
fb->color.layout = VK_IMAGE_LAYOUT_GENERAL;
}
renderPass = GetRenderPass(
step.render.color, step.render.depth, step.render.stencil,
fb->color.layout, fb->depth.layout,
step.render.finalColorLayout,
step.render.finalDepthStencilLayout);
TransitionToOptimal(cmd, fb->color.image, fb->color.layout, fb->depth.image, fb->depth.layout);
// We now do any layout pretransitions as part of the render pass.
fb->color.layout = step.render.finalColorLayout;
fb->depth.layout = step.render.finalDepthStencilLayout;
renderPass = GetRenderPass(step.render.color, step.render.depth, step.render.stencil);
// The transition from the optimal format happens after EndRenderPass, now that we don't
// do it as part of the renderpass itself anymore.
if (step.render.color == VKRRenderPassAction::CLEAR) {
Uint8x4ToFloat4(clearVal[0].color.float32, step.render.clearColor);
@@ -1580,24 +1623,6 @@ void VulkanQueueRunner::SetupTransitionToTransferSrc(VKRImage &img, VkImageMemor
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
img.layout = barrier.newLayout;
// NOTE: Must do this AFTER updating img.layout to avoid behaviour differences.
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR
if (aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
if (barrier.oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || barrier.oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
if (barrier.newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || barrier.newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
}
#endif
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_DEPTH_STENCIL
if (aspect != VK_IMAGE_ASPECT_COLOR_BIT) {
if (barrier.oldLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || barrier.oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
if (barrier.newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || barrier.newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
}
#endif
}
void VulkanQueueRunner::SetupTransitionToTransferDst(VKRImage &img, VkImageMemoryBarrier &barrier, VkPipelineStageFlags &stage, VkImageAspectFlags aspect) {
@@ -1639,24 +1664,6 @@ void VulkanQueueRunner::SetupTransitionToTransferDst(VKRImage &img, VkImageMemor
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
img.layout = barrier.newLayout;
// NOTE: Must do this AFTER updating img.layout to avoid behaviour differences.
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR
if (aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
if (barrier.oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || barrier.oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
if (barrier.newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || barrier.newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
}
#endif
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_DEPTH_STENCIL
if (aspect != VK_IMAGE_ASPECT_COLOR_BIT) {
if (barrier.oldLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || barrier.oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
if (barrier.newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || barrier.newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
}
#endif
}
void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd) {
+4 -7
View File
@@ -209,17 +209,12 @@ public:
VKRRenderPassAction colorLoadAction;
VKRRenderPassAction depthLoadAction;
VKRRenderPassAction stencilLoadAction;
VkImageLayout prevColorLayout;
VkImageLayout prevDepthStencilLayout;
VkImageLayout finalColorLayout;
VkImageLayout finalDepthStencilLayout;
};
// Only call this from the render thread! Also ok during initialization (LoadCache).
VkRenderPass GetRenderPass(
VKRRenderPassAction colorLoadAction, VKRRenderPassAction depthLoadAction, VKRRenderPassAction stencilLoadAction,
VkImageLayout prevColorLayout, VkImageLayout prevDepthStencilLayout, VkImageLayout finalColorLayout, VkImageLayout finalDepthStencilLayout) {
RPKey key{ colorLoadAction, depthLoadAction, stencilLoadAction, prevColorLayout, prevDepthStencilLayout, finalColorLayout, finalDepthStencilLayout };
VKRRenderPassAction colorLoadAction, VKRRenderPassAction depthLoadAction, VKRRenderPassAction stencilLoadAction) {
RPKey key{ colorLoadAction, depthLoadAction, stencilLoadAction };
return GetRenderPass(key);
}
@@ -271,6 +266,8 @@ private:
VkImage backbufferImage_ = VK_NULL_HANDLE;
VkRenderPass backbufferRenderPass_ = VK_NULL_HANDLE;
// The "Compatible" render pass. Used when creating pipelines that render to "normal" framebuffers.
VkRenderPass framebufferRenderPass_ = VK_NULL_HANDLE;
// Renderpasses, all combinations of preserving or clearing or dont-care-ing fb contents.
-4
View File
@@ -993,11 +993,7 @@ VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) {
if (key.imageViews_[i] && key.samplers_[i] && key.samplers_[i]->GetSampler()) {
imageDesc[i].imageView = key.imageViews_[i];
imageDesc[i].sampler = key.samplers_[i]->GetSampler();
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR
imageDesc[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
#else
imageDesc[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
#endif
writes[numWrites].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writes[numWrites].dstSet = descSet;
writes[numWrites].dstArrayElement = 0;
-12
View File
@@ -446,11 +446,7 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
if (imageView) {
_dbg_assert_(sampler != VK_NULL_HANDLE);
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR
tex[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
#else
tex[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
#endif
tex[0].imageView = imageView;
tex[0].sampler = sampler;
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
@@ -464,11 +460,7 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
}
if (boundSecondary_) {
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR
tex[1].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
#else
tex[1].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
#endif
tex[1].imageView = boundSecondary_;
tex[1].sampler = samplerSecondary_;
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
@@ -482,11 +474,7 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
}
if (boundDepal_) {
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR
tex[2].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
#else
tex[2].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
#endif
tex[2].imageView = boundDepal_;
tex[2].sampler = samplerSecondary_; // doesn't matter, we use load
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
-8
View File
@@ -196,11 +196,7 @@ VkDescriptorSet Vulkan2D::GetDescriptorSet(VkImageView tex1, VkSampler sampler1,
VkDescriptorImageInfo image1{};
VkDescriptorImageInfo image2{};
if (tex1 && sampler1) {
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR
image1.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
#else
image1.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
#endif
image1.imageView = tex1;
image1.sampler = sampler1;
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
@@ -213,11 +209,7 @@ VkDescriptorSet Vulkan2D::GetDescriptorSet(VkImageView tex1, VkSampler sampler1,
}
if (tex2 && sampler2) {
// TODO: Also support LAYOUT_GENERAL to be able to texture from framebuffers without transitioning them?
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR
image2.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
#else
image2.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
#endif
image2.imageView = tex2;
image2.sampler = sampler2;
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;