Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/vsg/state/ImageView.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<ImageView> createImageView(Device* device, ref_ptr<Image> image, VkImageAspectFlags aspectFlags);

/// convenience function that uploads staging buffer data to device including mipmaps.
extern VSG_DECLSPEC void transferImageData(ref_ptr<ImageView> imageView, VkImageLayout targetImageLayout, Data::Properties properties, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipLevels, Data::MipmapOffsets mipmapOffsets, ref_ptr<Buffer> stagingBuffer, VkDeviceSize stagingBufferOffset, VkCommandBuffer vk_commandBuffer, vsg::Device* device);

} // namespace vsg
243 changes: 1 addition & 242 deletions src/vsg/app/TransferTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<VkBufferImageCopy> 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<size_t>(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<size_t>(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<uint32_t>(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<VkImageBlit> 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<uint32_t>(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()
Expand Down
Loading