From 5447baab00a735590b79d6732c8af3358a7b1f7d Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 27 Sep 2021 14:59:00 -0700 Subject: [PATCH] rework Vulkan image layout transitions The main issue that gets fixed here are: - VK_IMAGE_LAYOUT_UNDEFINED cannot be used if the image content is to be preserved after the transition. Unfortunately, there is more than a few places in the VK backend where we use VK_IMAGE_LAYOUT_UNDEFINED on images that are later used as sources. - accessing an image memory from the host is only supported if the the layout is PREINITIALIZED or GENERAL. However, images in the staging pool were transitioned to other layouts and put back into the pool, later they would be mapped/memcpy'ed into. Instead we now always use the GENERAL layout and never change it. - images that where in the pool where transitioned using the miplevel of the texture we were copying into, however this didn't make sense because images from the pool don't have mip levels. As part of these fixes, we also refactor imageLayoutTranstion(), because there was two copies of this function, one specific to texture and another one more generic. We now always use the more generic one, with a new helper for textures. Note: didn't fix "readPixels" which has at least problem (1), because it's a tricky implementation, and it requires more toughts. --- filament/backend/src/vulkan/VulkanBlitter.cpp | 57 ++----- filament/backend/src/vulkan/VulkanDriver.cpp | 5 + .../backend/src/vulkan/VulkanStagePool.cpp | 18 ++ filament/backend/src/vulkan/VulkanStagePool.h | 1 + filament/backend/src/vulkan/VulkanTexture.cpp | 156 ++++++++---------- filament/backend/src/vulkan/VulkanTexture.h | 6 +- filament/backend/src/vulkan/VulkanUtility.cpp | 61 +++++++ filament/backend/src/vulkan/VulkanUtility.h | 9 + libs/bluevk/src/BlueVKDarwin.cpp | 2 +- 9 files changed, 185 insertions(+), 130 deletions(-) diff --git a/filament/backend/src/vulkan/VulkanBlitter.cpp b/filament/backend/src/vulkan/VulkanBlitter.cpp index 0280d7b9b5..2ec2c29099 100644 --- a/filament/backend/src/vulkan/VulkanBlitter.cpp +++ b/filament/backend/src/vulkan/VulkanBlitter.cpp @@ -38,30 +38,6 @@ struct BlitterUniforms { float inverseSampleCount; }; -// Helper function for populating barrier fields based on the desired image layout. -// This logic is specific to blitting, please keep this private to VulkanBlitter. -static VulkanLayoutTransition transitionHelper(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; -} - void VulkanBlitter::blitColor(BlitArgs args) { const VulkanAttachment src = args.srcTarget->getColor(mContext.currentSurface, args.targetIndex); const VulkanAttachment dst = args.dstTarget->getColor(mContext.currentSurface, 0); @@ -153,9 +129,15 @@ void VulkanBlitter::blitFast(VkImageAspectFlags aspect, VkFilter filter, const VkCommandBuffer cmdbuffer = mContext.commands->get().cmdbuffer; + + VkImageLayout srcLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + if (src.texture) { + srcLayout = mContext.getTextureLayout(src.texture->usage); + } + transitionImageLayout(cmdbuffer, { src.image, - VK_IMAGE_LAYOUT_UNDEFINED, + srcLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, srcRange, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, @@ -180,21 +162,12 @@ void VulkanBlitter::blitFast(VkImageAspectFlags aspect, VkFilter filter, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, blitRegions, filter); } - if (src.texture) { - transitionImageLayout(cmdbuffer, transitionHelper({ - .image = src.image, - .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .newLayout = mContext.getTextureLayout(src.texture->usage), - .subresources = srcRange - })); - } else if (!mContext.currentSurface->headlessQueue) { - transitionImageLayout(cmdbuffer, transitionHelper({ - .image = src.image, - .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - .subresources = srcRange - })); - } + transitionImageLayout(cmdbuffer, blitterTransitionHelper({ + .image = src.image, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .newLayout = srcLayout, + .subresources = srcRange + })); // Determine the desired texture layout for the destination while ensuring that the default // render target is supported, which has no associated texture. @@ -202,9 +175,9 @@ void VulkanBlitter::blitFast(VkImageAspectFlags aspect, VkFilter filter, mContext.getTextureLayout(dst.texture->usage) : mContext.currentSurface->getColor().layout; - transitionImageLayout(cmdbuffer, transitionHelper({ + transitionImageLayout(cmdbuffer, blitterTransitionHelper({ .image = dst.image, - .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, .newLayout = desiredLayout, .subresources = dstRange, })); diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 929c2a6f11..8e4b0bf58a 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -1461,6 +1461,7 @@ void VulkanDriver::readPixels(Handle src, uint32_t x, uint32_t y const VkCommandBuffer cmdbuffer = mContext.commands->get().cmdbuffer; + // TODO: staging should just use the GENERAL layout transitionImageLayout(cmdbuffer, { .image = stagingImage, .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, @@ -1512,6 +1513,7 @@ void VulkanDriver::readPixels(Handle src, uint32_t x, uint32_t y .layerCount = 1, }; + // FIXME: the content of the source may be destroyed because of VK_IMAGE_LAYOUT_UNDEFINED VkImage srcImage = srcTarget->getColor(mContext.currentSurface, 0).image; transitionImageLayout(cmdbuffer, { .image = srcImage, @@ -1534,6 +1536,7 @@ void VulkanDriver::readPixels(Handle src, uint32_t x, uint32_t y if (srcTexture || mContext.currentSurface->presentQueue) { const VkImageLayout present = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + // FIXME: the content of image we just blitted into may be destroyed because of VK_IMAGE_LAYOUT_UNDEFINED transitionImageLayout(cmdbuffer, { .image = srcImage, .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, @@ -1545,6 +1548,7 @@ void VulkanDriver::readPixels(Handle src, uint32_t x, uint32_t y .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, }); } else { + // FIXME: the content of image we just blitted into may be destroyed because of VK_IMAGE_LAYOUT_UNDEFINED transitionImageLayout(cmdbuffer, { .image = srcImage, .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, @@ -1559,6 +1563,7 @@ void VulkanDriver::readPixels(Handle src, uint32_t x, uint32_t y // Transition the staging image layout to GENERAL. + // TODO: why is this not using transitionImageLayout() ? VkImageMemoryBarrier barrier = { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, diff --git a/filament/backend/src/vulkan/VulkanStagePool.cpp b/filament/backend/src/vulkan/VulkanStagePool.cpp index ac6cc5f676..55fb001dcb 100644 --- a/filament/backend/src/vulkan/VulkanStagePool.cpp +++ b/filament/backend/src/vulkan/VulkanStagePool.cpp @@ -100,6 +100,24 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi assert_invariant(result == VK_SUCCESS); + VkImageAspectFlags aspectFlags = isDepthFormat(vkformat) ? VK_IMAGE_ASPECT_DEPTH_BIT + : VK_IMAGE_ASPECT_COLOR_BIT; + + const VkCommandBuffer cmdbuffer = mContext.commands->get().cmdbuffer; + + // We use VK_IMAGE_LAYOUT_GENERAL here because the spec says: + // "Host access to image memory is only well-defined for linear images and for image + // subresources of those images which are currently in either the + // 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({ + .image = image->image, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .subresources = { aspectFlags, 0, 1, 0, 1 } + })); + return image; } diff --git a/filament/backend/src/vulkan/VulkanStagePool.h b/filament/backend/src/vulkan/VulkanStagePool.h index 3badfd78d2..8e3b88aff4 100644 --- a/filament/backend/src/vulkan/VulkanStagePool.h +++ b/filament/backend/src/vulkan/VulkanStagePool.h @@ -52,6 +52,7 @@ public: // The stage is automatically released back to the pool after TIME_BEFORE_EVICTION frames. VulkanStage const* acquireStage(uint32_t numBytes); + // Images have VK_IMAGE_LAYOUT_GENERAL and must not be transitioned to any other layout VulkanStageImage const* acquireImage(PixelDataFormat format, PixelDataType type, uint32_t width, uint32_t height); diff --git a/filament/backend/src/vulkan/VulkanTexture.cpp b/filament/backend/src/vulkan/VulkanTexture.cpp index 8bdfca9404..143a4cc06b 100644 --- a/filament/backend/src/vulkan/VulkanTexture.cpp +++ b/filament/backend/src/vulkan/VulkanTexture.cpp @@ -16,6 +16,7 @@ #include "VulkanMemory.h" #include "VulkanTexture.h" +#include "VulkanUtility.h" #include @@ -28,66 +29,6 @@ using namespace bluevk; namespace filament { namespace backend { -// Issues a barrier that transforms the layout of the image, e.g. from a CPU-writeable -// layout to a GPU-readable layout. -static void transitionImageLayout(VkCommandBuffer cmd, VkImage image, - VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t miplevel, - uint32_t layerCount, uint32_t levelCount, VkImageAspectFlags aspect) { - if (oldLayout == newLayout) { - return; - } - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = oldLayout; - barrier.newLayout = newLayout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; - barrier.subresourceRange.aspectMask = aspect; - barrier.subresourceRange.baseMipLevel = miplevel; - barrier.subresourceRange.levelCount = levelCount; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = layerCount; - VkPipelineStageFlags sourceStage; - VkPipelineStageFlags destinationStage; - switch (newLayout) { - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - case VK_IMAGE_LAYOUT_GENERAL: - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - - // We support PRESENT as a target layout to allow blitting from the swap chain. - // See also makeSwapChainPresentable(). - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: - barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barrier.dstAccessMask = 0; - sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - destinationStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - break; - - default: - PANIC_POSTCONDITION("Unsupported layout transition."); - } - vkCmdPipelineBarrier(cmd, sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, - &barrier); -} - VulkanTexture::VulkanTexture(VulkanContext& context, SamplerType target, uint8_t levels, TextureFormat tformat, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth, TextureUsage tusage, VulkanStagePool& stagePool, VkComponentMapping swizzle) : @@ -238,9 +179,18 @@ VulkanTexture::VulkanTexture(VulkanContext& context, SamplerType target, uint8_t // Transition the layout of each image slice. if (any(usage & (TextureUsage::COLOR_ATTACHMENT | TextureUsage::DEPTH_ATTACHMENT))) { const uint32_t layers = mPrimaryViewRange.layerCount; - transitionImageLayout(mContext.commands->get().cmdbuffer, mTextureImage, - VK_IMAGE_LAYOUT_UNDEFINED, - mContext.getTextureLayout(usage), 0, layers, levels, mAspect); + transitionImageLayout(mContext.commands->get().cmdbuffer, textureTransitionHelper({ + .image = mTextureImage, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = mContext.getTextureLayout(usage), + .subresources = { + mAspect, + 0, + levels, + 0, + layers + } + })); } } @@ -285,7 +235,7 @@ void VulkanTexture::update3DImage(const PixelBufferDescriptor& data, uint32_t wi } void VulkanTexture::updateWithCopyBuffer(const PixelBufferDescriptor& hostData, uint32_t width, - uint32_t height, uint32_t depth, int miplevel) { + uint32_t height, uint32_t depth, uint32_t miplevel) { void* mapped = nullptr; VulkanStage const* stage = mStagePool.acquireStage(hostData.size); vmaMapMemory(mContext.allocator, stage->memory, &mapped); @@ -294,21 +244,41 @@ void VulkanTexture::updateWithCopyBuffer(const PixelBufferDescriptor& hostData, vmaFlushAllocation(mContext.allocator, stage->memory, 0, hostData.size); const VkCommandBuffer cmdbuffer = mContext.commands->get().cmdbuffer; - transitionImageLayout(cmdbuffer, mTextureImage, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, miplevel, 1, 1, mAspect); + + // We can't blindly use LAYOUT_UNDEFINED because it may destroy the data, and because + // we're potentially updating only a sub-region it would be a problem. + VkImageLayout textureLayout = mContext.getTextureLayout(usage); + transitionImageLayout(cmdbuffer, textureTransitionHelper({ + .image = mTextureImage, + .oldLayout = textureLayout, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .subresources = { + mAspect, + miplevel, 1, + 0,1 + } + })); copyBufferToImage(cmdbuffer, stage->buffer, mTextureImage, width, height, depth, nullptr, miplevel); - transitionImageLayout(cmdbuffer, mTextureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - mContext.getTextureLayout(usage), miplevel, 1, 1, mAspect); + transitionImageLayout(cmdbuffer, textureTransitionHelper({ + .image = mTextureImage, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = textureLayout, + .subresources = { + mAspect, + miplevel, 1, + 0,1 + } + })); } void VulkanTexture::updateWithBlitImage(const PixelBufferDescriptor& hostData, uint32_t width, - uint32_t height, uint32_t depth, int miplevel) { + uint32_t height, uint32_t depth, uint32_t miplevel) { void* mapped = nullptr; - VulkanStageImage const* stage = mStagePool.acquireImage(hostData.format, hostData.type, - width, height); + VulkanStageImage const* stage = mStagePool.acquireImage( + hostData.format, hostData.type, width, height); vmaMapMemory(mContext.allocator, stage->memory, &mapped); memcpy(mapped, hostData.buffer, hostData.size); vmaUnmapMemory(mContext.allocator, stage->memory); @@ -328,21 +298,29 @@ void VulkanTexture::updateWithBlitImage(const PixelBufferDescriptor& hostData, u .dstOffsets = { rect[0], rect[1] } }}; - transitionImageLayout(cmdbuffer, stage->image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, miplevel, 1, 1, mAspect); - - transitionImageLayout(cmdbuffer, mTextureImage, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, miplevel, 1, 1, mAspect); + // We can't blindly use LAYOUT_UNDEFINED because it may destroy the data, and because + // we're potentially updating only a sub-region it would be a problem. + VkImageLayout textureLayout = mContext.getTextureLayout(usage); + transitionImageLayout(cmdbuffer, textureTransitionHelper({ + .image = mTextureImage, + .oldLayout = textureLayout, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .subresources = { mAspect, miplevel, 1, 0, 1 } + })); vkCmdBlitImage(cmdbuffer, stage->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mTextureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, blitRegions, VK_FILTER_NEAREST); - transitionImageLayout(cmdbuffer, mTextureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - mContext.getTextureLayout(usage), miplevel, 1, 1, mAspect); + transitionImageLayout(cmdbuffer, textureTransitionHelper({ + .image = mTextureImage, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = textureLayout, + .subresources = { mAspect, miplevel, 1, 0, 1 } + })); } void VulkanTexture::updateCubeImage(const PixelBufferDescriptor& data, - const FaceOffsets& faceOffsets, int miplevel) { + const FaceOffsets& faceOffsets, uint32_t miplevel) { assert_invariant(this->target == SamplerType::SAMPLER_CUBEMAP); const bool reshape = getBytesPerPixel(format) == 3; const void* cpuData = data.buffer; @@ -361,19 +339,29 @@ void VulkanTexture::updateCubeImage(const PixelBufferDescriptor& data, vmaUnmapMemory(mContext.allocator, stage->memory); vmaFlushAllocation(mContext.allocator, stage->memory, 0, numDstBytes); + const VkCommandBuffer cmdbuffer = mContext.commands->get().cmdbuffer; const uint32_t width = std::max(1u, this->width >> miplevel); const uint32_t height = std::max(1u, this->height >> miplevel); - transitionImageLayout(cmdbuffer, mTextureImage, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, miplevel, 6, 1, mAspect); + // We can use LAYOUT_UNDEFINED here because we're always replacing the whole data, so it + // doesn't matter if the previous data is lost. + transitionImageLayout(cmdbuffer, textureTransitionHelper({ + .image = mTextureImage, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .subresources = { mAspect, miplevel, 1, 0, 6 } + })); copyBufferToImage(cmdbuffer, stage->buffer, mTextureImage, width, height, 1, &faceOffsets, miplevel); - transitionImageLayout(cmdbuffer, mTextureImage, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mContext.getTextureLayout(usage), miplevel, 6, - 1, mAspect); + transitionImageLayout(cmdbuffer, textureTransitionHelper({ + .image = mTextureImage, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = mContext.getTextureLayout(usage), + .subresources = { mAspect, miplevel, 1, 0, 6 } + })); } void VulkanTexture::setPrimaryRange(uint32_t minMiplevel, uint32_t maxMiplevel) { diff --git a/filament/backend/src/vulkan/VulkanTexture.h b/filament/backend/src/vulkan/VulkanTexture.h index c7c4c3e1a4..2d3cd6a207 100644 --- a/filament/backend/src/vulkan/VulkanTexture.h +++ b/filament/backend/src/vulkan/VulkanTexture.h @@ -34,7 +34,7 @@ struct VulkanTexture : public HwTexture { void update3DImage(const PixelBufferDescriptor& data, uint32_t width, uint32_t height, uint32_t depth, int miplevel); void updateCubeImage(const PixelBufferDescriptor& data, const FaceOffsets& faceOffsets, - int miplevel); + uint32_t miplevel); // Returns the primary image view, which is used for shader sampling. VkImageView getPrimaryImageView() const { return mCachedImageViews.at(mPrimaryViewRange); } @@ -64,10 +64,10 @@ private: FaceOffsets const* faceOffsets, uint32_t miplevel); void updateWithCopyBuffer(const PixelBufferDescriptor& hostData, uint32_t width, - uint32_t height, uint32_t depth, int miplevel); + uint32_t height, uint32_t depth, uint32_t miplevel); void updateWithBlitImage(const PixelBufferDescriptor& hostData, uint32_t width, - uint32_t height, uint32_t depth, int miplevel); + uint32_t height, uint32_t depth, uint32_t miplevel); VulkanTexture* mSidecarMSAA = nullptr; const VkFormat mVkFormat; diff --git a/filament/backend/src/vulkan/VulkanUtility.cpp b/filament/backend/src/vulkan/VulkanUtility.cpp index eeab8d0aa7..f32261720d 100644 --- a/filament/backend/src/vulkan/VulkanUtility.cpp +++ b/filament/backend/src/vulkan/VulkanUtility.cpp @@ -519,6 +519,67 @@ 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) { + switch (transition.newLayout) { + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + transition.srcAccessMask = 0; + transition.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + transition.srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + transition.dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + transition.srcAccessMask = 0; + transition.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + transition.srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + transition.dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + 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; + + // We support PRESENT as a target layout to allow blitting from the swap chain. + // See also makeSwapChainPresentable(). + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + 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; + + default: + PANIC_POSTCONDITION("Unsupported layout transition."); + } + return transition; +} + + bool equivalent(const VkRect2D& a, const VkRect2D& b) { // These are all integers so there's no need for an epsilon. return a.extent.width == b.extent.width && a.extent.height == b.extent.height && diff --git a/filament/backend/src/vulkan/VulkanUtility.h b/filament/backend/src/vulkan/VulkanUtility.h index 71578a0f6d..c2ebc58f22 100644 --- a/filament/backend/src/vulkan/VulkanUtility.h +++ b/filament/backend/src/vulkan/VulkanUtility.h @@ -48,6 +48,15 @@ VkFrontFace getFrontFace(bool inverseFrontFaces); PixelDataType getComponentType(VkFormat format); VkComponentMapping getSwizzleMap(TextureSwizzle swizzle[4]); 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); bool equivalent(const VkExtent2D& a, const VkExtent2D& b); bool isDepthFormat(VkFormat format); diff --git a/libs/bluevk/src/BlueVKDarwin.cpp b/libs/bluevk/src/BlueVKDarwin.cpp index 7aa8893763..0fa36827f5 100644 --- a/libs/bluevk/src/BlueVKDarwin.cpp +++ b/libs/bluevk/src/BlueVKDarwin.cpp @@ -51,7 +51,7 @@ bool loadLibrary() { module = dlopen(dylibPath.c_str(), RTLD_NOW | RTLD_LOCAL); if (module == nullptr) { - printf("%s", dlerror()); + printf("%s\n", dlerror()); } return module != nullptr; }