mirror of
https://github.com/love2d/love.git
synced 2026-08-20 12:40:20 +02:00
vulkan: add memory barriers for compute-writable textures.
This commit is contained in:
@@ -462,12 +462,9 @@ void Texture::clear(const VulkanImageData &data)
|
|||||||
|
|
||||||
VkImageLayout clearLayout = data.layout == VK_IMAGE_LAYOUT_GENERAL ? data.layout : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
VkImageLayout clearLayout = data.layout == VK_IMAGE_LAYOUT_GENERAL ? data.layout : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
|
|
||||||
if (clearLayout != data.layout)
|
Vulkan::cmdTransitionImageLayout(commandBuffer, data.image, format, renderTarget,
|
||||||
{
|
data.layout, clearLayout,
|
||||||
Vulkan::cmdTransitionImageLayout(commandBuffer, data.image, format, renderTarget,
|
0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
|
||||||
data.layout, clearLayout,
|
|
||||||
0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPixelFormatDepthStencil(format))
|
if (isPixelFormatDepthStencil(format))
|
||||||
{
|
{
|
||||||
@@ -482,12 +479,9 @@ void Texture::clear(const VulkanImageData &data)
|
|||||||
vkCmdClearColorImage(commandBuffer, data.image, clearLayout, &clearColor, 1, &range);
|
vkCmdClearColorImage(commandBuffer, data.image, clearLayout, &clearColor, 1, &range);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clearLayout != data.layout)
|
Vulkan::cmdTransitionImageLayout(commandBuffer, data.image, format, renderTarget,
|
||||||
{
|
clearLayout, data.layout,
|
||||||
Vulkan::cmdTransitionImageLayout(commandBuffer, data.image, format, renderTarget,
|
0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
|
||||||
clearLayout, data.layout,
|
|
||||||
0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkClearColorValue Texture::getClearColor(love::graphics::Texture *texture, const ColorD &color)
|
VkClearColorValue Texture::getClearColor(love::graphics::Texture *texture, const ColorD &color)
|
||||||
@@ -531,11 +525,13 @@ void Texture::generateMipmapsInternal()
|
|||||||
{
|
{
|
||||||
auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
|
auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
|
||||||
|
|
||||||
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
|
auto dstPipelineStages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT
|
||||||
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget,
|
| VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
imageData.layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
||||||
rootView.startMipmap, static_cast<uint32_t>(getMipmapCount()),
|
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget,
|
||||||
rootView.startLayer, static_cast<uint32_t>(layerCount));
|
imageData.layout, imageData.layout == VK_IMAGE_LAYOUT_GENERAL ? imageData.layout : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
rootView.startMipmap, static_cast<uint32_t>(getMipmapCount()),
|
||||||
|
rootView.startLayer, static_cast<uint32_t>(layerCount));
|
||||||
|
|
||||||
VkImageMemoryBarrier barrier{};
|
VkImageMemoryBarrier barrier{};
|
||||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
@@ -559,10 +555,23 @@ void Texture::generateMipmapsInternal()
|
|||||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
|
|
||||||
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
|
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
|
||||||
|
{
|
||||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
1, &barrier);
|
1, &barrier);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VkMemoryBarrier memoryBarrier{};
|
||||||
|
memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
||||||
|
memoryBarrier.srcAccessMask = barrier.srcAccessMask;
|
||||||
|
memoryBarrier.dstAccessMask = barrier.dstAccessMask;
|
||||||
|
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||||
|
1, &memoryBarrier,
|
||||||
|
0, nullptr,
|
||||||
|
0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
VkImageBlit blit{};
|
VkImageBlit blit{};
|
||||||
blit.srcOffsets[0] = { 0, 0, 0 };
|
blit.srcOffsets[0] = { 0, 0, 0 };
|
||||||
@@ -596,30 +605,27 @@ void Texture::generateMipmapsInternal()
|
|||||||
VK_FILTER_LINEAR);
|
VK_FILTER_LINEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
// This sucks, but we want the whole texture to be VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL because we
|
||||||
barrier.newLayout = imageData.layout;
|
// transition the whole thing back to the original layout after the loop.
|
||||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
if (i == mipLevels - 1 && imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
|
||||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
{
|
||||||
|
barrier.subresourceRange.baseMipLevel = rootView.startMipmap + i;
|
||||||
|
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
|
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||||
|
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
|
|
||||||
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
|
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
|
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
1, &barrier);
|
1, &barrier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
barrier.subresourceRange.baseMipLevel = rootView.startMipmap + mipLevels - 1;
|
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget,
|
||||||
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
imageData.layout == VK_IMAGE_LAYOUT_GENERAL ? imageData.layout : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageData.layout,
|
||||||
barrier.newLayout = imageData.layout;
|
rootView.startMipmap, static_cast<uint32_t>(getMipmapCount()),
|
||||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
rootView.startLayer, static_cast<uint32_t>(layerCount));
|
||||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
||||||
|
|
||||||
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
|
|
||||||
vkCmdPipelineBarrier(commandBuffer,
|
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
|
|
||||||
0, nullptr,
|
|
||||||
0, nullptr,
|
|
||||||
1, &barrier);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::uploadByteData(const void *data, size_t size, int level, int slice, const Rect &r)
|
void Texture::uploadByteData(const void *data, size_t size, int level, int slice, const Rect &r)
|
||||||
@@ -668,34 +674,24 @@ void Texture::uploadByteData(const void *data, size_t size, int level, int slice
|
|||||||
|
|
||||||
auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
|
auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
|
||||||
|
|
||||||
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
|
VkImageLayout copyDstLayout = imageData.layout == VK_IMAGE_LAYOUT_GENERAL ? imageData.layout : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
{
|
|
||||||
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget,
|
|
||||||
imageData.layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
||||||
level, 1, baseLayer, 1);
|
|
||||||
|
|
||||||
vkCmdCopyBufferToImage(
|
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget,
|
||||||
commandBuffer,
|
imageData.layout, copyDstLayout,
|
||||||
stagingBuffer,
|
level, 1, baseLayer, 1);
|
||||||
imageData.image,
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
||||||
1,
|
|
||||||
®ion
|
|
||||||
);
|
|
||||||
|
|
||||||
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget,
|
vkCmdCopyBufferToImage(
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageData.layout,
|
commandBuffer,
|
||||||
level, 1, baseLayer, 1);
|
stagingBuffer,
|
||||||
}
|
imageData.image,
|
||||||
else
|
copyDstLayout,
|
||||||
vkCmdCopyBufferToImage(
|
1,
|
||||||
commandBuffer,
|
®ion
|
||||||
stagingBuffer,
|
);
|
||||||
imageData.image,
|
|
||||||
imageData.layout,
|
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget,
|
||||||
1,
|
copyDstLayout, imageData.layout,
|
||||||
®ion
|
level, 1, baseLayer, 1);
|
||||||
);
|
|
||||||
|
|
||||||
vgfx->queueCleanUp([allocator = allocator, stagingBuffer, vmaAllocation]() {
|
vgfx->queueCleanUp([allocator = allocator, stagingBuffer, vmaAllocation]() {
|
||||||
vmaDestroyBuffer(allocator, stagingBuffer, vmaAllocation);
|
vmaDestroyBuffer(allocator, stagingBuffer, vmaAllocation);
|
||||||
@@ -722,16 +718,12 @@ void Texture::copyFromBuffer(graphics::Buffer *source, size_t sourceoffset, int
|
|||||||
region.imageExtent.width = static_cast<uint32_t>(rect.w);
|
region.imageExtent.width = static_cast<uint32_t>(rect.w);
|
||||||
region.imageExtent.height = static_cast<uint32_t>(rect.h);
|
region.imageExtent.height = static_cast<uint32_t>(rect.h);
|
||||||
|
|
||||||
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
|
VkImageLayout copyDstLayout = imageData.layout == VK_IMAGE_LAYOUT_GENERAL ? imageData.layout : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
{
|
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget, imageData.layout, copyDstLayout, layers.mipLevel, 1, layers.baseArrayLayer, 1);
|
||||||
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget, imageData.layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, layers.mipLevel, 1, layers.baseArrayLayer, 1);
|
|
||||||
|
|
||||||
vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), imageData.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), imageData.image, copyDstLayout, 1, ®ion);
|
||||||
|
|
||||||
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageData.layout, layers.mipLevel, 1, layers.baseArrayLayer, 1);
|
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget, copyDstLayout, imageData.layout, layers.mipLevel, 1, layers.baseArrayLayer, 1);
|
||||||
}
|
|
||||||
else
|
|
||||||
vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), imageData.image, VK_IMAGE_LAYOUT_GENERAL, 1, ®ion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size)
|
void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size)
|
||||||
@@ -755,16 +747,12 @@ void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const
|
|||||||
region.imageExtent.height = static_cast<uint32_t>(rect.h);
|
region.imageExtent.height = static_cast<uint32_t>(rect.h);
|
||||||
region.imageExtent.depth = 1;
|
region.imageExtent.depth = 1;
|
||||||
|
|
||||||
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
|
VkImageLayout copySrcLayout = imageData.layout == VK_IMAGE_LAYOUT_GENERAL ? imageData.layout : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||||
{
|
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget, imageData.layout, copySrcLayout, layers.mipLevel, 1, layers.baseArrayLayer, 1);
|
||||||
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget, imageData.layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, layers.mipLevel, 1, layers.baseArrayLayer, 1);
|
|
||||||
|
|
||||||
vkCmdCopyImageToBuffer(commandBuffer, imageData.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, (VkBuffer) dest->getHandle(), 1, ®ion);
|
vkCmdCopyImageToBuffer(commandBuffer, imageData.image, copySrcLayout, (VkBuffer) dest->getHandle(), 1, ®ion);
|
||||||
|
|
||||||
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageData.layout, layers.mipLevel, 1, layers.baseArrayLayer, 1);
|
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget, copySrcLayout, imageData.layout, layers.mipLevel, 1, layers.baseArrayLayer, 1);
|
||||||
}
|
|
||||||
else
|
|
||||||
vkCmdCopyImageToBuffer(commandBuffer, imageData.image, VK_IMAGE_LAYOUT_GENERAL, (VkBuffer)dest->getHandle(), 1, ®ion);
|
|
||||||
|
|
||||||
// TODO: This could be combined with the cmdTransitionImageLayout barrier.
|
// TODO: This could be combined with the cmdTransitionImageLayout barrier.
|
||||||
((Buffer *)dest)->postGPUWriteBarrier(commandBuffer);
|
((Buffer *)dest)->postGPUWriteBarrier(commandBuffer);
|
||||||
|
|||||||
@@ -883,41 +883,61 @@ void Vulkan::addImageLayoutTransitionOptions(bool previous, bool renderTarget, b
|
|||||||
|
|
||||||
void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, PixelFormat format, bool renderTarget, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount)
|
void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, PixelFormat format, bool renderTarget, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount)
|
||||||
{
|
{
|
||||||
VkImageMemoryBarrier barrier{};
|
VkImageMemoryBarrier imageBarrier{};
|
||||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
barrier.oldLayout = oldLayout;
|
imageBarrier.oldLayout = oldLayout;
|
||||||
barrier.newLayout = newLayout;
|
imageBarrier.newLayout = newLayout;
|
||||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
barrier.image = image;
|
imageBarrier.image = image;
|
||||||
barrier.subresourceRange.baseMipLevel = baseLevel;
|
imageBarrier.subresourceRange.baseMipLevel = baseLevel;
|
||||||
barrier.subresourceRange.levelCount = levelCount;
|
imageBarrier.subresourceRange.levelCount = levelCount;
|
||||||
barrier.subresourceRange.baseArrayLayer = baseLayer;
|
imageBarrier.subresourceRange.baseArrayLayer = baseLayer;
|
||||||
barrier.subresourceRange.layerCount = layerCount;
|
imageBarrier.subresourceRange.layerCount = layerCount;
|
||||||
|
|
||||||
const PixelFormatInfo &info = getPixelFormatInfo(format);
|
const PixelFormatInfo &info = getPixelFormatInfo(format);
|
||||||
|
|
||||||
VkPipelineStageFlags sourceStage = 0;
|
VkPipelineStageFlags sourceStage = 0;
|
||||||
VkPipelineStageFlags destinationStage = 0;
|
VkPipelineStageFlags destinationStage = 0;
|
||||||
|
|
||||||
addImageLayoutTransitionOptions(true, renderTarget, info.depth || info.stencil, oldLayout, barrier.srcAccessMask, sourceStage);
|
addImageLayoutTransitionOptions(true, renderTarget, info.depth || info.stencil, oldLayout, imageBarrier.srcAccessMask, sourceStage);
|
||||||
addImageLayoutTransitionOptions(false, renderTarget, info.depth || info.stencil, newLayout, barrier.dstAccessMask, destinationStage);
|
addImageLayoutTransitionOptions(false, renderTarget, info.depth || info.stencil, newLayout, imageBarrier.dstAccessMask, destinationStage);
|
||||||
|
|
||||||
if (info.color)
|
if (info.color)
|
||||||
barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT;
|
imageBarrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
if (info.depth)
|
if (info.depth)
|
||||||
barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
imageBarrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
if (info.stencil)
|
if (info.stencil)
|
||||||
barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
imageBarrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
|
||||||
vkCmdPipelineBarrier(
|
if (oldLayout != newLayout)
|
||||||
commandBuffer,
|
{
|
||||||
sourceStage, destinationStage,
|
vkCmdPipelineBarrier(
|
||||||
0,
|
commandBuffer,
|
||||||
0, nullptr,
|
sourceStage, destinationStage,
|
||||||
0, nullptr,
|
0,
|
||||||
1, &barrier
|
0, nullptr,
|
||||||
);
|
0, nullptr,
|
||||||
|
1, &imageBarrier
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No layout transition needed, but we do still need a memory barrier.
|
||||||
|
VkMemoryBarrier memoryBarrier{};
|
||||||
|
memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
||||||
|
memoryBarrier.srcAccessMask = imageBarrier.srcAccessMask;
|
||||||
|
memoryBarrier.dstAccessMask = imageBarrier.dstAccessMask;
|
||||||
|
|
||||||
|
vkCmdPipelineBarrier(
|
||||||
|
commandBuffer,
|
||||||
|
sourceStage, destinationStage,
|
||||||
|
0,
|
||||||
|
1, &memoryBarrier,
|
||||||
|
0, nullptr,
|
||||||
|
0, nullptr
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // vulkan
|
} // vulkan
|
||||||
|
|||||||
Reference in New Issue
Block a user