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 12df2ca984..65f497e5f7 100644 --- a/src/vsg/app/TransferTask.cpp +++ b/src/vsg/app/TransferTask.cpp @@ -326,248 +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); - - 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; - } - - 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(), - 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 015b7f1d69..68588ad9a4 100644 --- a/src/vsg/commands/CopyAndReleaseImage.cpp +++ b/src/vsg/commands/CopyAndReleaseImage.cpp @@ -166,253 +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); - - 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; - } - - vkCmdBlitImage(commandBuffer, - vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - static_cast(blits.size()), blits.data(), - 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); + } +}