vulkan: Fix validation errors (#6717)
- Depth attachment layout has generated a lot of error due to it being read-only. But the store-ops for the attachment during the renderpass are all write ops. We set the depth attachment layout as VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL - Enable extra blitting step for SSAO because of the above layout conundrum. - Index buffers did not have a pipeline barriers after loading them. - Remove `assert_invariant(utils::popcount(sampleCount) == 1);` from `reduceSampleCount`. This assert fails when enabling the duplicate pass for SSAO.
This commit is contained in:
@@ -32,11 +32,101 @@ using namespace utils;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
namespace {
|
||||
|
||||
inline void blitFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspect, VkFilter filter,
|
||||
const VkExtent2D srcExtent, VulkanAttachment src, VulkanAttachment dst,
|
||||
const VkOffset3D srcRect[2], const VkOffset3D dstRect[2]) {
|
||||
const VkImageBlit blitRegions[1] = {{.srcSubresource = {aspect, src.level, src.layer, 1},
|
||||
.srcOffsets = {srcRect[0], srcRect[1]},
|
||||
.dstSubresource = {aspect, dst.level, dst.layer, 1},
|
||||
.dstOffsets = {dstRect[0], dstRect[1]}}};
|
||||
|
||||
const VkImageResolve resolveRegions[1] = {{.srcSubresource = {aspect, src.level, src.layer, 1},
|
||||
.srcOffset = srcRect[0],
|
||||
.dstSubresource = {aspect, dst.level, dst.layer, 1},
|
||||
.dstOffset = dstRect[0],
|
||||
.extent = {srcExtent.width, srcExtent.height, 1}}};
|
||||
|
||||
const VkImageSubresourceRange srcRange = {
|
||||
.aspectMask = aspect,
|
||||
.baseMipLevel = src.level,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = src.layer,
|
||||
.layerCount = 1,
|
||||
};
|
||||
|
||||
const VkImageSubresourceRange dstRange = {
|
||||
.aspectMask = aspect,
|
||||
.baseMipLevel = dst.level,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = dst.layer,
|
||||
.layerCount = 1,
|
||||
};
|
||||
const VkImageLayout srcLayout = getDefaultImageLayout(src.texture->usage);
|
||||
transitionImageLayout(cmdbuffer, {
|
||||
src.getImage(),
|
||||
srcLayout,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
srcRange,
|
||||
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||
0,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_READ_BIT,
|
||||
});
|
||||
|
||||
transitionImageLayout(cmdbuffer, {
|
||||
dst.getImage(),
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
dstRange,
|
||||
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||
0,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
});
|
||||
|
||||
if (src.texture->samples > 1 && dst.texture->samples == 1) {
|
||||
assert_invariant(
|
||||
aspect != VK_IMAGE_ASPECT_DEPTH_BIT && "Resolve with depth is not yet supported.");
|
||||
vkCmdResolveImage(cmdbuffer, src.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
dst.getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, resolveRegions);
|
||||
} else {
|
||||
vkCmdBlitImage(cmdbuffer, src.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
dst.getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, blitRegions, filter);
|
||||
}
|
||||
|
||||
VkImageLayout newSrcLayout = getDefaultImageLayout(src.texture->usage);
|
||||
VkImageLayout const newDestLayout = getDefaultImageLayout(dst.texture->usage);
|
||||
|
||||
// In the case of blitting the depth attachment, we transition the source into GENERAL (for
|
||||
// sampling) and set the copy as ATTACHMENT_OPTIMAL (to be set as the attachment).
|
||||
if (any(src.texture->usage & TextureUsage::DEPTH_ATTACHMENT)) {
|
||||
newSrcLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
}
|
||||
|
||||
transitionImageLayout(cmdbuffer, textureTransitionHelper({
|
||||
.image = src.getImage(),
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
.newLayout = newSrcLayout,
|
||||
.subresources = srcRange,
|
||||
}));
|
||||
|
||||
transitionImageLayout(cmdbuffer, textureTransitionHelper({
|
||||
.image = dst.getImage(),
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.newLayout = newDestLayout,
|
||||
.subresources = dstRange,
|
||||
}));
|
||||
}
|
||||
|
||||
struct BlitterUniforms {
|
||||
int sampleCount;
|
||||
float inverseSampleCount;
|
||||
};
|
||||
|
||||
}// anonymous namespace
|
||||
|
||||
void VulkanBlitter::blitColor(BlitArgs args) {
|
||||
const VulkanAttachment src = args.srcTarget->getColor(args.targetIndex);
|
||||
const VulkanAttachment dst = args.dstTarget->getColor(0);
|
||||
@@ -56,8 +146,8 @@ void VulkanBlitter::blitColor(BlitArgs args) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
blitFast(aspect, args.filter, args.srcTarget->getExtent(), src, dst,
|
||||
VkCommandBuffer const cmdbuffer = mContext.commands->get().cmdbuffer;
|
||||
blitFast(cmdbuffer, aspect, args.filter, args.srcTarget->getExtent(), src, dst,
|
||||
args.srcRectPair, args.dstRectPair);
|
||||
}
|
||||
|
||||
@@ -88,90 +178,11 @@ void VulkanBlitter::blitDepth(BlitArgs args) {
|
||||
args.dstRectPair);
|
||||
return;
|
||||
}
|
||||
|
||||
blitFast(aspect, args.filter, args.srcTarget->getExtent(), src, dst, args.srcRectPair,
|
||||
VkCommandBuffer const cmdbuffer = mContext.commands->get().cmdbuffer;
|
||||
blitFast(cmdbuffer, aspect, args.filter, args.srcTarget->getExtent(), src, dst, args.srcRectPair,
|
||||
args.dstRectPair);
|
||||
}
|
||||
|
||||
void VulkanBlitter::blitFast(VkImageAspectFlags aspect, VkFilter filter,
|
||||
const VkExtent2D srcExtent, VulkanAttachment src, VulkanAttachment dst,
|
||||
const VkOffset3D srcRect[2], const VkOffset3D dstRect[2]) {
|
||||
const VkImageBlit blitRegions[1] = {{
|
||||
.srcSubresource = { aspect, src.level, src.layer, 1 },
|
||||
.srcOffsets = { srcRect[0], srcRect[1] },
|
||||
.dstSubresource = { aspect, dst.level, dst.layer, 1 },
|
||||
.dstOffsets = { dstRect[0], dstRect[1] }
|
||||
}};
|
||||
|
||||
const VkImageResolve resolveRegions[1] = {{
|
||||
.srcSubresource = { aspect, src.level, src.layer, 1 },
|
||||
.srcOffset = srcRect[0],
|
||||
.dstSubresource = { aspect, dst.level, dst.layer, 1 },
|
||||
.dstOffset = dstRect[0],
|
||||
.extent = { srcExtent.width, srcExtent.height, 1 }
|
||||
}};
|
||||
|
||||
const VkImageSubresourceRange srcRange = {
|
||||
.aspectMask = aspect,
|
||||
.baseMipLevel = src.level,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = src.layer,
|
||||
.layerCount = 1,
|
||||
};
|
||||
|
||||
const VkImageSubresourceRange dstRange = {
|
||||
.aspectMask = aspect,
|
||||
.baseMipLevel = dst.level,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = dst.layer,
|
||||
.layerCount = 1,
|
||||
};
|
||||
|
||||
const VkCommandBuffer cmdbuffer = mContext.commands->get().cmdbuffer;
|
||||
|
||||
const VkImageLayout srcLayout = getDefaultImageLayout(src.texture->usage);
|
||||
|
||||
transitionImageLayout(cmdbuffer, {
|
||||
src.getImage(),
|
||||
srcLayout,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
srcRange,
|
||||
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT
|
||||
});
|
||||
|
||||
transitionImageLayout(cmdbuffer, {
|
||||
dst.getImage(),
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
dstRange,
|
||||
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
});
|
||||
|
||||
if (src.texture->samples > 1 && dst.texture->samples == 1) {
|
||||
assert_invariant(aspect != VK_IMAGE_ASPECT_DEPTH_BIT && "Resolve with depth is not yet supported.");
|
||||
vkCmdResolveImage(cmdbuffer, src.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst.getImage(),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, resolveRegions);
|
||||
} else {
|
||||
vkCmdBlitImage(cmdbuffer, src.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst.getImage(),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, blitRegions, filter);
|
||||
}
|
||||
|
||||
transitionImageLayout(cmdbuffer, blitterTransitionHelper({
|
||||
.image = src.getImage(),
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
.newLayout = srcLayout,
|
||||
.subresources = srcRange
|
||||
}));
|
||||
|
||||
transitionImageLayout(cmdbuffer, blitterTransitionHelper({
|
||||
.image = dst.getImage(),
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.newLayout = getDefaultImageLayout(dst.texture->usage),
|
||||
.subresources = dstRange,
|
||||
}));
|
||||
}
|
||||
|
||||
void VulkanBlitter::shutdown() noexcept {
|
||||
if (mContext.device) {
|
||||
|
||||
@@ -53,10 +53,6 @@ public:
|
||||
private:
|
||||
void lazyInit() noexcept;
|
||||
|
||||
void blitFast(VkImageAspectFlags aspect, VkFilter filter, const VkExtent2D srcExtent,
|
||||
VulkanAttachment src, VulkanAttachment dst, const VkOffset3D srcRect[2],
|
||||
const VkOffset3D dstRect[2]);
|
||||
|
||||
void blitSlowDepth(VkImageAspectFlags aspect, VkFilter filter,
|
||||
const VkExtent2D srcExtent, VulkanAttachment src, VulkanAttachment dst,
|
||||
const VkOffset3D srcRect[2], const VkOffset3D dstRect[2]);
|
||||
|
||||
@@ -652,7 +652,26 @@ bool VulkanDriver::isWorkaroundNeeded(Workaround workaround) {
|
||||
// early exit condition is flattened in EASU code
|
||||
return deviceProperties.vendorID == 0x5143; // Qualcomm
|
||||
case Workaround::ALLOW_READ_ONLY_ANCILLARY_FEEDBACK_LOOP:
|
||||
return true;
|
||||
// Supporting depth attachment as both sampler and attachment is only possible if we set
|
||||
// the depth attachment as read-only (e.g. during SSAO pass), however note that the
|
||||
// store-ops for attachments wrt VkRenderPass only has VK_ATTACHMENT_STORE_OP_DONT_CARE
|
||||
// and VK_ATTACHMENT_STORE_OP_STORE for versions below 1.3. Only at 1.3 and above do we
|
||||
// have a true read-only choice VK_ATTACHMENT_STORE_OP_NONE. That means for < 1.3, we
|
||||
// will trigger a validation sync error if we use the depth attachment also as a
|
||||
// sampler. See full error below:
|
||||
//
|
||||
// SYNC-HAZARD-WRITE-AFTER-READ(ERROR / SPEC): msgNum: 929810911 - Validation Error:
|
||||
// [ SYNC-HAZARD-WRITE-AFTER-READ ] Object 0: handle = 0x6160000c3680,
|
||||
// type = VK_OBJECT_TYPE_RENDER_PASS; | MessageID = 0x376bc9df | vkCmdEndRenderPass:
|
||||
// Hazard WRITE_AFTER_READ in subpass 0 for attachment 1 depth aspect during store with
|
||||
// storeOp VK_ATTACHMENT_STORE_OP_STORE. Access info (usage:
|
||||
// SYNC_LATE_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE, prior_usage:
|
||||
// SYNC_FRAGMENT_SHADER_SHADER_STORAGE_READ, read_barriers: VK_PIPELINE_STAGE_2_NONE,
|
||||
// command: vkCmdDrawIndexed, seq_no: 177, reset_no: 1)
|
||||
//
|
||||
// Therefore we apply the existing workaround of an extra blit until a better
|
||||
// resolution.
|
||||
return false;
|
||||
case Workaround::ADRENO_UNIFORM_ARRAY_CRASH:
|
||||
return false;
|
||||
}
|
||||
@@ -871,39 +890,27 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
VulkanAttachment depth = rt->getSamples() == 1 ? rt->getDepth() : rt->getMsaaDepth();
|
||||
|
||||
VulkanDepthLayout initialDepthLayout = fromVkImageLayout(depth.getLayout());
|
||||
VulkanDepthLayout renderPassDepthLayout =
|
||||
fromVkImageLayout(getDefaultImageLayout(TextureUsage::DEPTH_ATTACHMENT));
|
||||
VulkanDepthLayout finalDepthLayout = renderPassDepthLayout;
|
||||
|
||||
// Sometimes we need to permit the shader to sample the depth attachment by transitioning the
|
||||
// layout of all its subresources to a read-only layout. This is especially crucial for SSAO.
|
||||
//
|
||||
// We cannot perform this transition using the render pass because the shaders in this render
|
||||
// pass might sample from multiple miplevels.
|
||||
//
|
||||
// We do not use GENERAL here due to the following validation message:
|
||||
//
|
||||
// The Vulkan spec states: Image subresources used as attachments in the current render pass
|
||||
// must not be accessed in any way other than as an attachment by this command, except for
|
||||
// cases involving read-only access to depth/stencil attachments as described in the Render
|
||||
// Pass chapter.
|
||||
//
|
||||
// https://vulkan.lunarg.com/doc/view/1.2.182.0/mac/1.2-extensions/vkspec.html#VUID-vkCmdDrawIndexed-None-04584)
|
||||
//
|
||||
if (params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) {
|
||||
VkImageSubresourceRange range = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = depth.texture->levels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = depth.texture->depth,
|
||||
};
|
||||
depth.texture->transitionLayout(cmdbuffer, range, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL);
|
||||
initialDepthLayout = renderPassDepthLayout = finalDepthLayout = VulkanDepthLayout::READ_ONLY;
|
||||
}
|
||||
VulkanDepthLayout renderPassDepthLayout = VulkanDepthLayout::ATTACHMENT;
|
||||
VulkanDepthLayout finalDepthLayout = VulkanDepthLayout::ATTACHMENT;
|
||||
|
||||
TargetBufferFlags clearVal = params.flags.clear;
|
||||
TargetBufferFlags discardEndVal = params.flags.discardEnd;
|
||||
if (depth.texture) {
|
||||
depth.texture->trackLayout(depth.level, depth.layer, toVkImageLayout(renderPassDepthLayout));
|
||||
if (params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) {
|
||||
discardEndVal &= ~TargetBufferFlags::DEPTH;
|
||||
clearVal &= ~TargetBufferFlags::DEPTH;
|
||||
}
|
||||
if (initialDepthLayout != VulkanDepthLayout::ATTACHMENT) {
|
||||
VkImageSubresourceRange subresources{
|
||||
.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = depth.texture->levels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = depth.texture->depth,
|
||||
};
|
||||
depth.texture->transitionLayout(cmdbuffer, subresources,
|
||||
toVkImageLayout(renderPassDepthLayout));
|
||||
}
|
||||
}
|
||||
|
||||
// Create the VkRenderPass or fetch it from cache.
|
||||
@@ -913,9 +920,9 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
.renderPassDepthLayout = renderPassDepthLayout,
|
||||
.finalDepthLayout = finalDepthLayout,
|
||||
.depthFormat = depth.getFormat(),
|
||||
.clear = params.flags.clear,
|
||||
.clear = clearVal,
|
||||
.discardStart = discardStart,
|
||||
.discardEnd = params.flags.discardEnd,
|
||||
.discardEnd = discardEndVal,
|
||||
.samples = rt->getSamples(),
|
||||
.subpassMask = uint8_t(params.subpassMask),
|
||||
};
|
||||
@@ -1070,21 +1077,6 @@ void VulkanDriver::endRenderPass(int) {
|
||||
VulkanRenderTarget* rt = mContext.currentRenderPass.renderTarget;
|
||||
assert_invariant(rt);
|
||||
|
||||
// In some cases, depth needs to be transitioned from DEPTH_STENCIL_READ_ONLY_OPTIMAL back to
|
||||
// GENERAL. We did not do this using the render pass because we need to change multiple mips.
|
||||
if (mContext.currentRenderPass.params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) {
|
||||
const VulkanAttachment& depth = rt->getDepth();
|
||||
VkImageSubresourceRange range = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = depth.texture->levels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = depth.texture->depth,
|
||||
};
|
||||
depth.texture->transitionLayout(cmdbuffer, range,
|
||||
getDefaultImageLayout(TextureUsage::DEPTH_ATTACHMENT));
|
||||
}
|
||||
|
||||
// Since we might soon be sampling from the render target that we just wrote to, we need a
|
||||
// pipeline barrier between framebuffer writes and shader reads. This is a memory barrier rather
|
||||
// than an image barrier. If we were to use image barriers here, we would potentially need to
|
||||
|
||||
@@ -30,8 +30,7 @@ namespace filament::backend {
|
||||
// Avoid using VkImageLayout since it requires 4 bytes.
|
||||
enum class VulkanDepthLayout : uint8_t {
|
||||
UNDEFINED, // VK_IMAGE_LAYOUT_UNDEFINED
|
||||
GENERAL, // VK_IMAGE_LAYOUT_GENERAL
|
||||
READ_ONLY, // VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL.
|
||||
ATTACHMENT, // VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
|
||||
};
|
||||
|
||||
// Simple manager for VkFramebuffer and VkRenderPass objects.
|
||||
@@ -134,17 +133,19 @@ private:
|
||||
|
||||
inline VulkanDepthLayout fromVkImageLayout(VkImageLayout layout) {
|
||||
switch (layout) {
|
||||
case VK_IMAGE_LAYOUT_GENERAL: return VulkanDepthLayout::GENERAL;
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: return VulkanDepthLayout::READ_ONLY;
|
||||
default: return VulkanDepthLayout::UNDEFINED;
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
return VulkanDepthLayout::ATTACHMENT;
|
||||
default:
|
||||
return VulkanDepthLayout::UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
inline VkImageLayout toVkImageLayout(VulkanDepthLayout layout) {
|
||||
switch (layout) {
|
||||
case VulkanDepthLayout::GENERAL: return VK_IMAGE_LAYOUT_GENERAL;
|
||||
case VulkanDepthLayout::READ_ONLY: return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
|
||||
default: return VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
case VulkanDepthLayout::ATTACHMENT:
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
default:
|
||||
return VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi
|
||||
// VK_IMAGE_LAYOUT_PREINITIALIZED or VK_IMAGE_LAYOUT_GENERAL layout. Calling
|
||||
// vkGetImageSubresourceLayout for a linear image returns a subresource layout mapping that is
|
||||
// valid for either of those image layouts."
|
||||
transitionImageLayout(cmdbuffer, blitterTransitionHelper({
|
||||
transitionImageLayout(cmdbuffer, textureTransitionHelper({
|
||||
.image = image->image,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
|
||||
@@ -632,11 +632,8 @@ VkImageViewType getImageViewType(SamplerType target) {
|
||||
// exceptions for depth and for transient use of specialized layouts, which is why VulkanTexture
|
||||
// tracks actual layout at the subresource level.
|
||||
VkImageLayout getDefaultImageLayout(TextureUsage usage) {
|
||||
// Filament sometimes samples from depth while it is bound to the current render target, (e.g.
|
||||
// SSAO does this while depth writes are disabled) so let's keep it simple and use GENERAL for
|
||||
// all depth textures.
|
||||
if (any(usage & TextureUsage::DEPTH_ATTACHMENT)) {
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
// Filament sometimes samples from one miplevel while writing to another level in the same
|
||||
@@ -676,29 +673,8 @@ void transitionImageLayout(VkCommandBuffer cmdbuffer, VulkanLayoutTransition tra
|
||||
nullptr, 1, &barrier);
|
||||
}
|
||||
|
||||
VulkanLayoutTransition blitterTransitionHelper(VulkanLayoutTransition transition) {
|
||||
switch (transition.newLayout) {
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
case VK_IMAGE_LAYOUT_GENERAL:
|
||||
transition.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
transition.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
transition.srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
transition.dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
|
||||
default:
|
||||
transition.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
transition.dstAccessMask = 0;
|
||||
transition.srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
transition.dstStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
break;
|
||||
}
|
||||
return transition;
|
||||
}
|
||||
|
||||
VulkanLayoutTransition textureTransitionHelper(VulkanLayoutTransition transition) {
|
||||
const bool isTransferSrc = transition.oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
switch (transition.newLayout) {
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
transition.srcAccessMask = 0;
|
||||
@@ -714,13 +690,20 @@ VulkanLayoutTransition textureTransitionHelper(VulkanLayoutTransition transition
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
case VK_IMAGE_LAYOUT_GENERAL:
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
|
||||
transition.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
transition.srcAccessMask
|
||||
= isTransferSrc ? VK_ACCESS_TRANSFER_READ_BIT : VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
transition.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
transition.srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
transition.dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
transition.srcAccessMask
|
||||
= isTransferSrc ? VK_ACCESS_TRANSFER_READ_BIT : VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
transition.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
transition.srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
transition.dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||
break;
|
||||
// We support PRESENT as a target layout to allow blitting from the swap chain.
|
||||
// See also SwapChain::makePresentable().
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
@@ -765,7 +748,6 @@ bool isDepthFormat(VkFormat format) {
|
||||
static uint32_t mostSignificantBit(uint32_t x) { return 1ul << (31ul - utils::clz(x)); }
|
||||
|
||||
uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask) {
|
||||
assert_invariant(utils::popcount(sampleCount) == 1);
|
||||
if (sampleCount & mask) {
|
||||
return sampleCount;
|
||||
}
|
||||
|
||||
@@ -56,11 +56,6 @@ VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags);
|
||||
void transitionImageLayout(VkCommandBuffer cmdbuffer, VulkanLayoutTransition transition);
|
||||
|
||||
// Helper function for populating barrier fields based on the desired image layout.
|
||||
// This logic is specific to blitting.
|
||||
VulkanLayoutTransition blitterTransitionHelper(VulkanLayoutTransition transition);
|
||||
|
||||
// Helper function for populating barrier fields based on the desired image layout.
|
||||
// This logic is specific to texturing.
|
||||
VulkanLayoutTransition textureTransitionHelper(VulkanLayoutTransition transition);
|
||||
|
||||
bool equivalent(const VkRect2D& a, const VkRect2D& b);
|
||||
|
||||
Reference in New Issue
Block a user