From 7340ff84c1be7d274df8ab79add1b6039a047d57 Mon Sep 17 00:00:00 2001 From: siystar Date: Tue, 18 Jul 2023 11:16:33 +0200 Subject: [PATCH 1/3] [FIXED] array texture mipmaps --- src/vsg/commands/CopyAndReleaseImage.cpp | 33 ++++++++++-------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/vsg/commands/CopyAndReleaseImage.cpp b/src/vsg/commands/CopyAndReleaseImage.cpp index 015b7f1d69..5de42cac49 100644 --- a/src/vsg/commands/CopyAndReleaseImage.cpp +++ b/src/vsg/commands/CopyAndReleaseImage.cpp @@ -337,29 +337,24 @@ void CopyAndReleaseImage::CopyData::record(CommandBuffer& commandBuffer) const 0, nullptr, 1, &barrier); - std::vector blits(arrayLayers); - - for (auto face = 0u; face < arrayLayers; ++face) - { - auto& blit = blits[face]; - blit.srcOffsets[0] = {0, 0, 0}; - blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth}; - blit.srcSubresource.aspectMask = aspectMask; - blit.srcSubresource.mipLevel = i - 1; - blit.srcSubresource.baseArrayLayer = face; - blit.srcSubresource.layerCount = arrayLayers; - blit.dstOffsets[0] = {0, 0, 0}; - blit.dstOffsets[1] = {mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, mipDepth > 1 ? mipDepth / 2 : 1}; - blit.dstSubresource.aspectMask = aspectMask; - blit.dstSubresource.mipLevel = i; - blit.dstSubresource.baseArrayLayer = face; - blit.dstSubresource.layerCount = arrayLayers; - } + VkImageBlit blit; + blit.srcOffsets[0] = {0, 0, 0}; + blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth}; + blit.srcSubresource.aspectMask = aspectMask; + blit.srcSubresource.mipLevel = i - 1; + blit.srcSubresource.baseArrayLayer = 0; + blit.srcSubresource.layerCount = arrayLayers; + blit.dstOffsets[0] = {0, 0, 0}; + blit.dstOffsets[1] = {mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, mipDepth > 1 ? mipDepth / 2 : 1}; + blit.dstSubresource.aspectMask = aspectMask; + blit.dstSubresource.mipLevel = i; + blit.dstSubresource.baseArrayLayer = 0; + blit.dstSubresource.layerCount = arrayLayers; vkCmdBlitImage(commandBuffer, vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - static_cast(blits.size()), blits.data(), + 1, &blit, VK_FILTER_LINEAR); barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; From 75272d2cef0c6b54910260ee864c0fbd06cfaf62 Mon Sep 17 00:00:00 2001 From: siystar Date: Tue, 18 Jul 2023 20:42:53 +0200 Subject: [PATCH 2/3] [FIXED] another instance of array texture mipmaps in TransferTask.cpp Invalid layerCount was passed to vkCmdBlitImage when generating mipmaps for an array texture. In the code that loops over arrayLayers and blits each layer, layerCount should have been set to 1, not arrayLayers. Fixed by removing the loop. Let Vulkan loop over the image layers using a single blit of baseArrayLayer=0, layerCount=arrayLayers. Test case: auto imageData = vsg::ubvec4Array3D::create(256, 256, 32, vsg::ubvec4(), vsg::Data::Properties(VK_FORMAT_R8G8B8A8_UNORM)); imageData->properties.imageViewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; sampler->maxLod = 4; // Generate mipmaps --- src/vsg/app/TransferTask.cpp | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/vsg/app/TransferTask.cpp b/src/vsg/app/TransferTask.cpp index 12df2ca984..9f6e91f105 100644 --- a/src/vsg/app/TransferTask.cpp +++ b/src/vsg/app/TransferTask.cpp @@ -492,29 +492,24 @@ void TransferTask::_transferImageInfo(VkCommandBuffer vk_commandBuffer, Frame& f 0, nullptr, 1, &barrier); - std::vector blits(arrayLayers); - - for (auto face = 0u; face < arrayLayers; ++face) - { - auto& blit = blits[face]; - blit.srcOffsets[0] = {0, 0, 0}; - blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth}; - blit.srcSubresource.aspectMask = aspectMask; - blit.srcSubresource.mipLevel = i - 1; - blit.srcSubresource.baseArrayLayer = face; - blit.srcSubresource.layerCount = arrayLayers; - blit.dstOffsets[0] = {0, 0, 0}; - blit.dstOffsets[1] = {mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, mipDepth > 1 ? mipDepth / 2 : 1}; - blit.dstSubresource.aspectMask = aspectMask; - blit.dstSubresource.mipLevel = i; - blit.dstSubresource.baseArrayLayer = face; - blit.dstSubresource.layerCount = arrayLayers; - } + VkImageBlit blit; + blit.srcOffsets[0] = {0, 0, 0}; + blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth}; + blit.srcSubresource.aspectMask = aspectMask; + blit.srcSubresource.mipLevel = i - 1; + blit.srcSubresource.baseArrayLayer = 0; + blit.srcSubresource.layerCount = arrayLayers; + blit.dstOffsets[0] = {0, 0, 0}; + blit.dstOffsets[1] = {mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, mipDepth > 1 ? mipDepth / 2 : 1}; + blit.dstSubresource.aspectMask = aspectMask; + blit.dstSubresource.mipLevel = i; + blit.dstSubresource.baseArrayLayer = 0; + blit.dstSubresource.layerCount = arrayLayers; vkCmdBlitImage(vk_commandBuffer, vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - static_cast(blits.size()), blits.data(), + 1, &blit, VK_FILTER_LINEAR); barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; From 449c2b98928f0f3c20ae934f5283f4de37f08274 Mon Sep 17 00:00:00 2001 From: siystar Date: Thu, 20 Jul 2023 11:35:21 +0200 Subject: [PATCH 3/3] [ADDED] vsg::transferImageData shared by CopyAndReleaseImage and TransferTask Tested dynamic image updates Tested array texture mipmaps --- include/vsg/state/ImageView.h | 3 + src/vsg/app/TransferTask.cpp | 238 +--------------------- src/vsg/commands/CopyAndReleaseImage.cpp | 243 +--------------------- src/vsg/state/ImageView.cpp | 244 +++++++++++++++++++++++ 4 files changed, 249 insertions(+), 479 deletions(-) diff --git a/include/vsg/state/ImageView.h b/include/vsg/state/ImageView.h index 93d99acd7f..226fbc8bba 100644 --- a/include/vsg/state/ImageView.h +++ b/include/vsg/state/ImageView.h @@ -67,4 +67,7 @@ namespace vsg /// convenience function that create an ImageView and allocates device memory and an Image for it. extern VSG_DECLSPEC ref_ptr createImageView(Device* device, ref_ptr image, VkImageAspectFlags aspectFlags); + /// convenience function that uploads staging buffer data to device including mipmaps. + extern VSG_DECLSPEC void transferImageData(ref_ptr imageView, VkImageLayout targetImageLayout, Data::Properties properties, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipLevels, Data::MipmapOffsets mipmapOffsets, ref_ptr stagingBuffer, VkDeviceSize stagingBufferOffset, VkCommandBuffer vk_commandBuffer, vsg::Device* device); + } // namespace vsg diff --git a/src/vsg/app/TransferTask.cpp b/src/vsg/app/TransferTask.cpp index 9f6e91f105..65f497e5f7 100644 --- a/src/vsg/app/TransferTask.cpp +++ b/src/vsg/app/TransferTask.cpp @@ -326,243 +326,7 @@ void TransferTask::_transferImageInfo(VkCommandBuffer vk_commandBuffer, Frame& f } // transfer data. - - uint32_t faceWidth = width; - uint32_t faceHeight = height; - uint32_t faceDepth = depth; - uint32_t arrayLayers = 1; - - switch (imageInfo.imageView->viewType) - { - case (VK_IMAGE_VIEW_TYPE_CUBE): - arrayLayers = faceDepth; - faceDepth = 1; - break; - case (VK_IMAGE_VIEW_TYPE_1D_ARRAY): - arrayLayers = faceHeight * faceDepth; - faceHeight = 1; - faceDepth = 1; - break; - case (VK_IMAGE_VIEW_TYPE_2D_ARRAY): - arrayLayers = faceDepth; - faceDepth = 1; - break; - case (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY): - arrayLayers = faceDepth; - faceDepth = 1; - break; - default: - break; - } - - uint32_t destWidth = faceWidth * properties.blockWidth; - uint32_t destHeight = faceHeight * properties.blockHeight; - uint32_t destDepth = faceDepth * properties.blockDepth; - - const auto valueSize = properties.stride; // data->valueSize(); - - bool useDataMipmaps = (mipLevels > 1) && (mipmapOffsets.size() > 1); - bool generatMipmaps = (mipLevels > 1) && (mipmapOffsets.size() <= 1); - - auto vk_textureImage = textureImage->vk(deviceID); - - if (generatMipmaps) - { - VkFormatProperties props; - vkGetPhysicalDeviceFormatProperties(*(device->getPhysicalDevice()), properties.format, &props); - const bool isBlitPossible = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT) > 0; - - if (!isBlitPossible) - { - generatMipmaps = false; - } - } - - // transfer the data. - VkImageMemoryBarrier preCopyBarrier = {}; - preCopyBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - preCopyBarrier.srcAccessMask = 0; - preCopyBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - preCopyBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - preCopyBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - preCopyBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - preCopyBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - preCopyBarrier.image = vk_textureImage; - preCopyBarrier.subresourceRange.aspectMask = aspectMask; - preCopyBarrier.subresourceRange.baseArrayLayer = 0; - preCopyBarrier.subresourceRange.layerCount = arrayLayers; - preCopyBarrier.subresourceRange.levelCount = mipLevels; - preCopyBarrier.subresourceRange.baseMipLevel = 0; - - vkCmdPipelineBarrier(vk_commandBuffer, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &preCopyBarrier); - - std::vector regions; - - if (useDataMipmaps) - { - size_t local_offset = 0u; - regions.resize(mipLevels * arrayLayers); - - uint32_t mipWidth = destWidth; - uint32_t mipHeight = destHeight; - uint32_t mipDepth = destDepth; - - for (uint32_t mipLevel = 0; mipLevel < mipLevels; ++mipLevel) - { - const size_t faceSize = static_cast(faceWidth * faceHeight * faceDepth * valueSize); - - for (uint32_t face = 0; face < arrayLayers; ++face) - { - auto& region = regions[mipLevel * arrayLayers + face]; - region.bufferOffset = source_offset + local_offset; - region.bufferRowLength = 0; - region.bufferImageHeight = 0; - region.imageSubresource.aspectMask = aspectMask; - region.imageSubresource.mipLevel = mipLevel; - region.imageSubresource.baseArrayLayer = face; - region.imageSubresource.layerCount = 1; - region.imageOffset = {0, 0, 0}; - region.imageExtent = {mipWidth, mipHeight, mipDepth}; - - local_offset += faceSize; - } - - if (mipWidth > 1) mipWidth /= 2; - if (mipHeight > 1) mipHeight /= 2; - if (mipDepth > 1) mipDepth /= 2; - if (faceWidth > 1) faceWidth /= 2; - if (faceHeight > 1) faceHeight /= 2; - if (faceDepth > 1) faceDepth /= 2; - } - } - else - { - regions.resize(arrayLayers); - - const size_t faceSize = static_cast(faceWidth * faceHeight * faceDepth * valueSize); - for (auto face = 0u; face < arrayLayers; face++) - { - auto& region = regions[face]; - region.bufferOffset = source_offset + face * faceSize; - region.bufferRowLength = 0; - region.bufferImageHeight = 0; - region.imageSubresource.aspectMask = aspectMask; - region.imageSubresource.mipLevel = 0; - region.imageSubresource.baseArrayLayer = face; - region.imageSubresource.layerCount = 1; - region.imageOffset = {0, 0, 0}; - region.imageExtent = {destWidth, destHeight, destDepth}; - } - } - - vkCmdCopyBufferToImage(vk_commandBuffer, imageStagingBuffer->vk(deviceID), vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - static_cast(regions.size()), regions.data()); - - if (generatMipmaps) - { - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.image = vk_textureImage; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.subresourceRange.aspectMask = aspectMask; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = arrayLayers; - barrier.subresourceRange.levelCount = 1; - - int32_t mipWidth = destWidth; - int32_t mipHeight = destHeight; - int32_t mipDepth = destDepth; - - for (uint32_t i = 1; i < mipLevels; ++i) - { - barrier.subresourceRange.baseMipLevel = i - 1; - 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; - - vkCmdPipelineBarrier(vk_commandBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &barrier); - - VkImageBlit blit; - blit.srcOffsets[0] = {0, 0, 0}; - blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth}; - blit.srcSubresource.aspectMask = aspectMask; - blit.srcSubresource.mipLevel = i - 1; - blit.srcSubresource.baseArrayLayer = 0; - blit.srcSubresource.layerCount = arrayLayers; - blit.dstOffsets[0] = {0, 0, 0}; - blit.dstOffsets[1] = {mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, mipDepth > 1 ? mipDepth / 2 : 1}; - blit.dstSubresource.aspectMask = aspectMask; - blit.dstSubresource.mipLevel = i; - blit.dstSubresource.baseArrayLayer = 0; - blit.dstSubresource.layerCount = arrayLayers; - - vkCmdBlitImage(vk_commandBuffer, - vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &blit, - VK_FILTER_LINEAR); - - barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barrier.newLayout = targetImageLayout; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - vkCmdPipelineBarrier(vk_commandBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &barrier); - - if (mipWidth > 1) mipWidth /= 2; - if (mipHeight > 1) mipHeight /= 2; - if (mipDepth > 1) mipDepth /= 2; - } - - barrier.subresourceRange.baseMipLevel = mipLevels - 1; - barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier.newLayout = targetImageLayout; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - vkCmdPipelineBarrier(vk_commandBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &barrier); - } - else - { - VkImageMemoryBarrier postCopyBarrier = {}; - postCopyBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - postCopyBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - postCopyBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - postCopyBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - postCopyBarrier.newLayout = targetImageLayout; - postCopyBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - postCopyBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - postCopyBarrier.image = vk_textureImage; - postCopyBarrier.subresourceRange.aspectMask = aspectMask; - postCopyBarrier.subresourceRange.baseArrayLayer = 0; - postCopyBarrier.subresourceRange.layerCount = arrayLayers; - postCopyBarrier.subresourceRange.levelCount = mipLevels; - postCopyBarrier.subresourceRange.baseMipLevel = 0; - - vkCmdPipelineBarrier(vk_commandBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &postCopyBarrier); - } + transferImageData(imageInfo.imageView, imageInfo.imageLayout, properties, width, height, depth, mipLevels, mipmapOffsets, imageStagingBuffer, source_offset, vk_commandBuffer, device); } VkResult TransferTask::transferDynamicData() diff --git a/src/vsg/commands/CopyAndReleaseImage.cpp b/src/vsg/commands/CopyAndReleaseImage.cpp index 5de42cac49..68588ad9a4 100644 --- a/src/vsg/commands/CopyAndReleaseImage.cpp +++ b/src/vsg/commands/CopyAndReleaseImage.cpp @@ -166,248 +166,7 @@ void CopyAndReleaseImage::_copyDirectly(ref_ptr data, ref_ptr d void CopyAndReleaseImage::CopyData::record(CommandBuffer& commandBuffer) const { - ref_ptr imageStagingBuffer(source->buffer); - ref_ptr textureImage(destination->imageView->image); - auto aspectMask = destination->imageView->subresourceRange.aspectMask; - VkImageLayout targetImageLayout = destination->imageLayout; - - uint32_t faceWidth = width; - uint32_t faceHeight = height; - uint32_t faceDepth = depth; - uint32_t arrayLayers = 1; - - //switch(layout.imageViewType) - switch (destination->imageView->viewType) - { - case (VK_IMAGE_VIEW_TYPE_CUBE): - arrayLayers = faceDepth; - faceDepth = 1; - break; - case (VK_IMAGE_VIEW_TYPE_1D_ARRAY): - arrayLayers = faceHeight * faceDepth; - faceHeight = 1; - faceDepth = 1; - break; - case (VK_IMAGE_VIEW_TYPE_2D_ARRAY): - arrayLayers = faceDepth; - faceDepth = 1; - break; - case (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY): - arrayLayers = faceDepth; - faceDepth = 1; - break; - default: - break; - } - - uint32_t destWidth = faceWidth * layout.blockWidth; - uint32_t destHeight = faceHeight * layout.blockHeight; - uint32_t destDepth = faceDepth * layout.blockDepth; - - const auto valueSize = layout.stride; // data->valueSize(); - - bool useDataMipmaps = (mipLevels > 1) && (mipmapOffsets.size() > 1); - bool generatMipmaps = (mipLevels > 1) && (mipmapOffsets.size() <= 1); - - auto vk_textureImage = textureImage->vk(commandBuffer.deviceID); - - if (generatMipmaps) - { - VkFormatProperties props; - vkGetPhysicalDeviceFormatProperties(*(commandBuffer.getDevice()->getPhysicalDevice()), layout.format, &props); - const bool isBlitPossible = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT) > 0; - - if (!isBlitPossible) - { - generatMipmaps = false; - } - } - - // transfer the data. - VkImageMemoryBarrier preCopyBarrier = {}; - preCopyBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - preCopyBarrier.srcAccessMask = 0; - preCopyBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - preCopyBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - preCopyBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - preCopyBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - preCopyBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - preCopyBarrier.image = vk_textureImage; - preCopyBarrier.subresourceRange.aspectMask = aspectMask; - preCopyBarrier.subresourceRange.baseArrayLayer = 0; - preCopyBarrier.subresourceRange.layerCount = arrayLayers; - preCopyBarrier.subresourceRange.levelCount = mipLevels; - preCopyBarrier.subresourceRange.baseMipLevel = 0; - - vkCmdPipelineBarrier(commandBuffer, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &preCopyBarrier); - - std::vector regions; - - if (useDataMipmaps) - { - size_t offset = 0u; - regions.resize(mipLevels * arrayLayers); - - uint32_t mipWidth = destWidth; - uint32_t mipHeight = destHeight; - uint32_t mipDepth = destDepth; - - for (uint32_t mipLevel = 0; mipLevel < mipLevels; ++mipLevel) - { - const size_t faceSize = static_cast(faceWidth * faceHeight * faceDepth * valueSize); - - for (uint32_t face = 0; face < arrayLayers; ++face) - { - auto& region = regions[mipLevel * arrayLayers + face]; - region.bufferOffset = source->offset + offset; - region.bufferRowLength = 0; - region.bufferImageHeight = 0; - region.imageSubresource.aspectMask = aspectMask; - region.imageSubresource.mipLevel = mipLevel; - region.imageSubresource.baseArrayLayer = face; - region.imageSubresource.layerCount = 1; - region.imageOffset = {0, 0, 0}; - region.imageExtent = {mipWidth, mipHeight, mipDepth}; - - offset += faceSize; - } - - if (mipWidth > 1) mipWidth /= 2; - if (mipHeight > 1) mipHeight /= 2; - if (mipDepth > 1) mipDepth /= 2; - if (faceWidth > 1) faceWidth /= 2; - if (faceHeight > 1) faceHeight /= 2; - if (faceDepth > 1) faceDepth /= 2; - } - } - else - { - regions.resize(arrayLayers); - - const size_t faceSize = static_cast(faceWidth * faceHeight * faceDepth * valueSize); - for (auto face = 0u; face < arrayLayers; face++) - { - auto& region = regions[face]; - region.bufferOffset = source->offset + face * faceSize; - region.bufferRowLength = 0; - region.bufferImageHeight = 0; - region.imageSubresource.aspectMask = aspectMask; - region.imageSubresource.mipLevel = 0; - region.imageSubresource.baseArrayLayer = face; - region.imageSubresource.layerCount = 1; - region.imageOffset = {0, 0, 0}; - region.imageExtent = {destWidth, destHeight, destDepth}; - } - } - - vkCmdCopyBufferToImage(commandBuffer, imageStagingBuffer->vk(commandBuffer.deviceID), vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - static_cast(regions.size()), regions.data()); - - if (generatMipmaps) - { - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.image = vk_textureImage; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.subresourceRange.aspectMask = aspectMask; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = arrayLayers; - barrier.subresourceRange.levelCount = 1; - - int32_t mipWidth = destWidth; - int32_t mipHeight = destHeight; - int32_t mipDepth = destDepth; - - for (uint32_t i = 1; i < mipLevels; ++i) - { - barrier.subresourceRange.baseMipLevel = i - 1; - 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; - - vkCmdPipelineBarrier(commandBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &barrier); - - VkImageBlit blit; - blit.srcOffsets[0] = {0, 0, 0}; - blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth}; - blit.srcSubresource.aspectMask = aspectMask; - blit.srcSubresource.mipLevel = i - 1; - blit.srcSubresource.baseArrayLayer = 0; - blit.srcSubresource.layerCount = arrayLayers; - blit.dstOffsets[0] = {0, 0, 0}; - blit.dstOffsets[1] = {mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, mipDepth > 1 ? mipDepth / 2 : 1}; - blit.dstSubresource.aspectMask = aspectMask; - blit.dstSubresource.mipLevel = i; - blit.dstSubresource.baseArrayLayer = 0; - blit.dstSubresource.layerCount = arrayLayers; - - vkCmdBlitImage(commandBuffer, - vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &blit, - VK_FILTER_LINEAR); - - barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barrier.newLayout = targetImageLayout; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - vkCmdPipelineBarrier(commandBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &barrier); - - if (mipWidth > 1) mipWidth /= 2; - if (mipHeight > 1) mipHeight /= 2; - if (mipDepth > 1) mipDepth /= 2; - } - - barrier.subresourceRange.baseMipLevel = mipLevels - 1; - barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier.newLayout = targetImageLayout; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - vkCmdPipelineBarrier(commandBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &barrier); - } - else - { - VkImageMemoryBarrier postCopyBarrier = {}; - postCopyBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - postCopyBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - postCopyBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - postCopyBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - postCopyBarrier.newLayout = targetImageLayout; - postCopyBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - postCopyBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - postCopyBarrier.image = vk_textureImage; - postCopyBarrier.subresourceRange.aspectMask = aspectMask; - postCopyBarrier.subresourceRange.baseArrayLayer = 0; - postCopyBarrier.subresourceRange.layerCount = arrayLayers; - postCopyBarrier.subresourceRange.levelCount = mipLevels; - postCopyBarrier.subresourceRange.baseMipLevel = 0; - - vkCmdPipelineBarrier(commandBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &postCopyBarrier); - } + transferImageData(destination->imageView, destination->imageLayout, layout, width, height, depth, mipLevels, mipmapOffsets, source->buffer, source->offset, commandBuffer.vk(), commandBuffer.getDevice()); } void CopyAndReleaseImage::record(CommandBuffer& commandBuffer) const diff --git a/src/vsg/state/ImageView.cpp b/src/vsg/state/ImageView.cpp index a99fa61e31..bf3ca6df69 100644 --- a/src/vsg/state/ImageView.cpp +++ b/src/vsg/state/ImageView.cpp @@ -199,3 +199,247 @@ ref_ptr vsg::createImageView(Device* device, ref_ptr image, Vk return imageView; } + +void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetImageLayout, Data::Properties properties, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipLevels, Data::MipmapOffsets mipmapOffsets, ref_ptr stagingBuffer, VkDeviceSize stagingBufferOffset, VkCommandBuffer commandBuffer, vsg::Device* device) +{ + ref_ptr textureImage(imageView->image); + auto aspectMask = imageView->subresourceRange.aspectMask; + + uint32_t faceWidth = width; + uint32_t faceHeight = height; + uint32_t faceDepth = depth; + uint32_t arrayLayers = 1; + + //switch(properties.imageViewType) + switch (imageView->viewType) + { + case (VK_IMAGE_VIEW_TYPE_CUBE): + arrayLayers = faceDepth; + faceDepth = 1; + break; + case (VK_IMAGE_VIEW_TYPE_1D_ARRAY): + arrayLayers = faceHeight * faceDepth; + faceHeight = 1; + faceDepth = 1; + break; + case (VK_IMAGE_VIEW_TYPE_2D_ARRAY): + arrayLayers = faceDepth; + faceDepth = 1; + break; + case (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY): + arrayLayers = faceDepth; + faceDepth = 1; + break; + default: + break; + } + + uint32_t destWidth = faceWidth * properties.blockWidth; + uint32_t destHeight = faceHeight * properties.blockHeight; + uint32_t destDepth = faceDepth * properties.blockDepth; + + const auto valueSize = properties.stride; // data->valueSize(); + + bool useDataMipmaps = (mipLevels > 1) && (mipmapOffsets.size() > 1); + bool generatMipmaps = (mipLevels > 1) && (mipmapOffsets.size() <= 1); + + auto vk_textureImage = textureImage->vk(device->deviceID); + + if (generatMipmaps) + { + VkFormatProperties props; + vkGetPhysicalDeviceFormatProperties(*(device->getPhysicalDevice()), properties.format, &props); + const bool isBlitPossible = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT) > 0; + + if (!isBlitPossible) + { + generatMipmaps = false; + } + } + + // transfer the data. + VkImageMemoryBarrier preCopyBarrier = {}; + preCopyBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + preCopyBarrier.srcAccessMask = 0; + preCopyBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + preCopyBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + preCopyBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + preCopyBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + preCopyBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + preCopyBarrier.image = vk_textureImage; + preCopyBarrier.subresourceRange.aspectMask = aspectMask; + preCopyBarrier.subresourceRange.baseArrayLayer = 0; + preCopyBarrier.subresourceRange.layerCount = arrayLayers; + preCopyBarrier.subresourceRange.levelCount = mipLevels; + preCopyBarrier.subresourceRange.baseMipLevel = 0; + + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, + 0, nullptr, + 0, nullptr, + 1, &preCopyBarrier); + + std::vector regions; + + if (useDataMipmaps) + { + size_t offset = 0u; + regions.resize(mipLevels * arrayLayers); + + uint32_t mipWidth = destWidth; + uint32_t mipHeight = destHeight; + uint32_t mipDepth = destDepth; + + for (uint32_t mipLevel = 0; mipLevel < mipLevels; ++mipLevel) + { + const size_t faceSize = static_cast(faceWidth * faceHeight * faceDepth * valueSize); + + for (uint32_t face = 0; face < arrayLayers; ++face) + { + auto& region = regions[mipLevel * arrayLayers + face]; + region.bufferOffset = stagingBufferOffset + offset; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource.aspectMask = aspectMask; + region.imageSubresource.mipLevel = mipLevel; + region.imageSubresource.baseArrayLayer = face; + region.imageSubresource.layerCount = 1; + region.imageOffset = {0, 0, 0}; + region.imageExtent = {mipWidth, mipHeight, mipDepth}; + + offset += faceSize; + } + + if (mipWidth > 1) mipWidth /= 2; + if (mipHeight > 1) mipHeight /= 2; + if (mipDepth > 1) mipDepth /= 2; + if (faceWidth > 1) faceWidth /= 2; + if (faceHeight > 1) faceHeight /= 2; + if (faceDepth > 1) faceDepth /= 2; + } + } + else + { + regions.resize(arrayLayers); + + const size_t faceSize = static_cast(faceWidth * faceHeight * faceDepth * valueSize); + for (auto face = 0u; face < arrayLayers; face++) + { + auto& region = regions[face]; + region.bufferOffset = stagingBufferOffset + face * faceSize; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource.aspectMask = aspectMask; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = face; + region.imageSubresource.layerCount = 1; + region.imageOffset = {0, 0, 0}; + region.imageExtent = {destWidth, destHeight, destDepth}; + } + } + + vkCmdCopyBufferToImage(commandBuffer, stagingBuffer->vk(device->deviceID), vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + static_cast(regions.size()), regions.data()); + + if (generatMipmaps) + { + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.image = vk_textureImage; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.subresourceRange.aspectMask = aspectMask; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = arrayLayers; + barrier.subresourceRange.levelCount = 1; + + int32_t mipWidth = destWidth; + int32_t mipHeight = destHeight; + int32_t mipDepth = destDepth; + + for (uint32_t i = 1; i < mipLevels; ++i) + { + barrier.subresourceRange.baseMipLevel = i - 1; + 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; + + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, + 0, nullptr, + 0, nullptr, + 1, &barrier); + + VkImageBlit blit; + blit.srcOffsets[0] = {0, 0, 0}; + blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth}; + blit.srcSubresource.aspectMask = aspectMask; + blit.srcSubresource.mipLevel = i - 1; + blit.srcSubresource.baseArrayLayer = 0; + blit.srcSubresource.layerCount = arrayLayers; + blit.dstOffsets[0] = {0, 0, 0}; + blit.dstOffsets[1] = {mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, mipDepth > 1 ? mipDepth / 2 : 1}; + blit.dstSubresource.aspectMask = aspectMask; + blit.dstSubresource.mipLevel = i; + blit.dstSubresource.baseArrayLayer = 0; + blit.dstSubresource.layerCount = arrayLayers; + + vkCmdBlitImage(commandBuffer, + vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &blit, + VK_FILTER_LINEAR); + + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.newLayout = targetImageLayout; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, + 0, nullptr, + 0, nullptr, + 1, &barrier); + + if (mipWidth > 1) mipWidth /= 2; + if (mipHeight > 1) mipHeight /= 2; + if (mipDepth > 1) mipDepth /= 2; + } + + barrier.subresourceRange.baseMipLevel = mipLevels - 1; + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.newLayout = targetImageLayout; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, + 0, nullptr, + 0, nullptr, + 1, &barrier); + } + else + { + VkImageMemoryBarrier postCopyBarrier = {}; + postCopyBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + postCopyBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + postCopyBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + postCopyBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + postCopyBarrier.newLayout = targetImageLayout; + postCopyBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + postCopyBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + postCopyBarrier.image = vk_textureImage; + postCopyBarrier.subresourceRange.aspectMask = aspectMask; + postCopyBarrier.subresourceRange.baseArrayLayer = 0; + postCopyBarrier.subresourceRange.layerCount = arrayLayers; + postCopyBarrier.subresourceRange.levelCount = mipLevels; + postCopyBarrier.subresourceRange.baseMipLevel = 0; + + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, + 0, nullptr, + 0, nullptr, + 1, &postCopyBarrier); + } +}