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; }