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.
This commit is contained in:
committed by
Mathias Agopian
parent
904989f7f4
commit
5447baab00
@@ -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,
|
||||
}));
|
||||
|
||||
@@ -1461,6 +1461,7 @@ void VulkanDriver::readPixels(Handle<HwRenderTarget> 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<HwRenderTarget> 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<HwRenderTarget> 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<HwRenderTarget> 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<HwRenderTarget> 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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "VulkanMemory.h"
|
||||
#include "VulkanTexture.h"
|
||||
#include "VulkanUtility.h"
|
||||
|
||||
#include <private/backend/BackendUtils.h>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user