Load mip levels for cube maps and texture arrays (TextureLoader)

This commit is contained in:
saschawillems 2016-06-18 17:42:33 +02:00
parent b7dae92ed8
commit 4ba4d67935

View file

@ -449,8 +449,9 @@ namespace vkTools
#endif #endif
assert(!texCube.empty()); assert(!texCube.empty());
texture->width = (uint32_t)texCube[0].dimensions().x; texture->width = static_cast<uint32_t>(texCube.dimensions().x);
texture->height = (uint32_t)texCube[0].dimensions().y; texture->height = static_cast<uint32_t>(texCube.dimensions().y);
texture->mipLevels = static_cast<uint32_t>(texCube.levels());
VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo();
VkMemoryRequirements memReqs; VkMemoryRequirements memReqs;
@ -483,22 +484,36 @@ namespace vkTools
memcpy(data, texCube.data(), texCube.size()); memcpy(data, texCube.data(), texCube.size());
vkUnmapMemory(device, stagingMemory); vkUnmapMemory(device, stagingMemory);
// Setup buffer copy regions for the cube faces // Setup buffer copy regions for each face including all of it's miplevels
// As all faces of a cube map must have the same dimensions, we can do a single copy std::vector<VkBufferImageCopy> bufferCopyRegions;
VkBufferImageCopy bufferCopyRegion = {}; size_t offset = 0;
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
bufferCopyRegion.imageSubresource.mipLevel = 0; for (uint32_t face = 0; face < 6; face++)
bufferCopyRegion.imageSubresource.baseArrayLayer = 0; {
bufferCopyRegion.imageSubresource.layerCount = 6; for (uint32_t level = 0; level < texture->mipLevels; level++)
bufferCopyRegion.imageExtent.width = texture->width; {
bufferCopyRegion.imageExtent.height = texture->height; VkBufferImageCopy bufferCopyRegion = {};
bufferCopyRegion.imageExtent.depth = 1; bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
bufferCopyRegion.imageSubresource.mipLevel = level;
bufferCopyRegion.imageSubresource.baseArrayLayer = face;
bufferCopyRegion.imageSubresource.layerCount = 1;
bufferCopyRegion.imageExtent.width = static_cast<uint32_t>(texCube[face][level].dimensions().x);
bufferCopyRegion.imageExtent.height = static_cast<uint32_t>(texCube[face][level].dimensions().y);
bufferCopyRegion.imageExtent.depth = 1;
bufferCopyRegion.bufferOffset = offset;
bufferCopyRegions.push_back(bufferCopyRegion);
// Increase offset into staging buffer for next level / face
offset += texCube[face][level].size();
}
}
// Create optimal tiled target image // Create optimal tiled target image
VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo(); VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo();
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = format; imageCreateInfo.format = format;
imageCreateInfo.mipLevels = 1; imageCreateInfo.mipLevels = texture->mipLevels;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
@ -529,7 +544,7 @@ namespace vkTools
VkImageSubresourceRange subresourceRange = {}; VkImageSubresourceRange subresourceRange = {};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.baseMipLevel = 0; subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1; subresourceRange.levelCount = texture->mipLevels;
subresourceRange.layerCount = 6; subresourceRange.layerCount = 6;
vkTools::setImageLayout( vkTools::setImageLayout(
@ -546,9 +561,8 @@ namespace vkTools
stagingBuffer, stagingBuffer,
texture->image, texture->image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, static_cast<uint32_t>(bufferCopyRegions.size()),
&bufferCopyRegion bufferCopyRegions.data());
);
// Change texture image layout to shader read after all faces have been copied // Change texture image layout to shader read after all faces have been copied
texture->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; texture->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@ -589,7 +603,7 @@ namespace vkTools
sampler.maxAnisotropy = 8; sampler.maxAnisotropy = 8;
sampler.compareOp = VK_COMPARE_OP_NEVER; sampler.compareOp = VK_COMPARE_OP_NEVER;
sampler.minLod = 0.0f; sampler.minLod = 0.0f;
sampler.maxLod = 0.0f; sampler.maxLod = (float)texture->mipLevels;
sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
VK_CHECK_RESULT(vkCreateSampler(device, &sampler, nullptr, &texture->sampler)); VK_CHECK_RESULT(vkCreateSampler(device, &sampler, nullptr, &texture->sampler));
@ -601,6 +615,7 @@ namespace vkTools
view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
view.subresourceRange.layerCount = 6; view.subresourceRange.layerCount = 6;
view.subresourceRange.levelCount = texture->mipLevels;
view.image = texture->image; view.image = texture->image;
VK_CHECK_RESULT(vkCreateImageView(device, &view, nullptr, &texture->view)); VK_CHECK_RESULT(vkCreateImageView(device, &view, nullptr, &texture->view));
@ -643,6 +658,7 @@ namespace vkTools
texture->width = static_cast<uint32_t>(tex2DArray.dimensions().x); texture->width = static_cast<uint32_t>(tex2DArray.dimensions().x);
texture->height = static_cast<uint32_t>(tex2DArray.dimensions().y); texture->height = static_cast<uint32_t>(tex2DArray.dimensions().y);
texture->layerCount = static_cast<uint32_t>(tex2DArray.layers()); texture->layerCount = static_cast<uint32_t>(tex2DArray.layers());
texture->mipLevels = static_cast<uint32_t>(tex2DArray.levels());
VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo();
VkMemoryRequirements memReqs; VkMemoryRequirements memReqs;
@ -672,57 +688,31 @@ namespace vkTools
// Copy texture data into staging buffer // Copy texture data into staging buffer
uint8_t *data; uint8_t *data;
VK_CHECK_RESULT(vkMapMemory(device, stagingMemory, 0, memReqs.size, 0, (void **)&data)); VK_CHECK_RESULT(vkMapMemory(device, stagingMemory, 0, memReqs.size, 0, (void **)&data));
memcpy(data, tex2DArray.data(), tex2DArray.size()); memcpy(data, tex2DArray.data(), static_cast<size_t>(tex2DArray.size()));
vkUnmapMemory(device, stagingMemory); vkUnmapMemory(device, stagingMemory);
// Setup buffer copy regions for array layers // Setup buffer copy regions for each layer including all of it's miplevels
std::vector<VkBufferImageCopy> bufferCopyRegions; std::vector<VkBufferImageCopy> bufferCopyRegions;
uint32_t offset = 0; size_t offset = 0;
// Check if all array layers have the same dimesions
bool sameDims = true;
for (uint32_t layer = 0; layer < texture->layerCount; layer++) for (uint32_t layer = 0; layer < texture->layerCount; layer++)
{ {
if (tex2DArray[layer].dimensions().x != texture->width || tex2DArray[layer].dimensions().y != texture->height) for (uint32_t level = 0; level < texture->mipLevels; level++)
{
sameDims = false;
break;
}
}
// If all layers of the texture array have the same dimensions, we only need to do one copy
if (sameDims)
{
VkBufferImageCopy bufferCopyRegion = {};
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
bufferCopyRegion.imageSubresource.mipLevel = 0;
bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
bufferCopyRegion.imageSubresource.layerCount = texture->layerCount;
bufferCopyRegion.imageExtent.width = static_cast<uint32_t>(tex2DArray[0].dimensions().x);
bufferCopyRegion.imageExtent.height = static_cast<uint32_t>(tex2DArray[0].dimensions().y);
bufferCopyRegion.imageExtent.depth = 1;
bufferCopyRegion.bufferOffset = offset;
bufferCopyRegions.push_back(bufferCopyRegion);
}
else
{
// If dimensions differ, copy layer by layer and pass offsets
for (uint32_t layer = 0; layer < texture->layerCount; layer++)
{ {
VkBufferImageCopy bufferCopyRegion = {}; VkBufferImageCopy bufferCopyRegion = {};
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
bufferCopyRegion.imageSubresource.mipLevel = 0; bufferCopyRegion.imageSubresource.mipLevel = level;
bufferCopyRegion.imageSubresource.baseArrayLayer = layer; bufferCopyRegion.imageSubresource.baseArrayLayer = layer;
bufferCopyRegion.imageSubresource.layerCount = 1; bufferCopyRegion.imageSubresource.layerCount = 1;
bufferCopyRegion.imageExtent.width = static_cast<uint32_t>(tex2DArray[layer].dimensions().x); bufferCopyRegion.imageExtent.width = static_cast<uint32_t>(tex2DArray[layer][level].dimensions().x);
bufferCopyRegion.imageExtent.height = static_cast<uint32_t>(tex2DArray[layer].dimensions().y); bufferCopyRegion.imageExtent.height = static_cast<uint32_t>(tex2DArray[layer][level].dimensions().y);
bufferCopyRegion.imageExtent.depth = 1; bufferCopyRegion.imageExtent.depth = 1;
bufferCopyRegion.bufferOffset = offset; bufferCopyRegion.bufferOffset = offset;
bufferCopyRegions.push_back(bufferCopyRegion); bufferCopyRegions.push_back(bufferCopyRegion);
offset += static_cast<uint32_t>(tex2DArray[layer].size()); // Increase offset into staging buffer for next level / face
offset += tex2DArray[layer][level].size();
} }
} }
@ -730,7 +720,6 @@ namespace vkTools
VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo(); VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo();
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = format; imageCreateInfo.format = format;
imageCreateInfo.mipLevels = 1;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
@ -739,6 +728,7 @@ namespace vkTools
imageCreateInfo.extent = { texture->width, texture->height, 1 }; imageCreateInfo.extent = { texture->width, texture->height, 1 };
imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageCreateInfo.arrayLayers = texture->layerCount; imageCreateInfo.arrayLayers = texture->layerCount;
imageCreateInfo.mipLevels = texture->mipLevels;
VK_CHECK_RESULT(vkCreateImage(device, &imageCreateInfo, nullptr, &texture->image)); VK_CHECK_RESULT(vkCreateImage(device, &imageCreateInfo, nullptr, &texture->image));
@ -758,7 +748,7 @@ namespace vkTools
VkImageSubresourceRange subresourceRange = {}; VkImageSubresourceRange subresourceRange = {};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.baseMipLevel = 0; subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1; subresourceRange.levelCount = texture->mipLevels;
subresourceRange.layerCount = texture->layerCount; subresourceRange.layerCount = texture->layerCount;
vkTools::setImageLayout( vkTools::setImageLayout(
@ -769,15 +759,14 @@ namespace vkTools
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
subresourceRange); subresourceRange);
// Copy the cube map faces from the staging buffer to the optimal tiled image // Copy the layers and mip levels from the staging buffer to the optimal tiled image
vkCmdCopyBufferToImage( vkCmdCopyBufferToImage(
cmdBuffer, cmdBuffer,
stagingBuffer, stagingBuffer,
texture->image, texture->image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
static_cast<uint32_t>(bufferCopyRegions.size()), static_cast<uint32_t>(bufferCopyRegions.size()),
bufferCopyRegions.data() bufferCopyRegions.data());
);
// Change texture image layout to shader read after all faces have been copied // Change texture image layout to shader read after all faces have been copied
texture->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; texture->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@ -818,7 +807,7 @@ namespace vkTools
sampler.maxAnisotropy = 8; sampler.maxAnisotropy = 8;
sampler.compareOp = VK_COMPARE_OP_NEVER; sampler.compareOp = VK_COMPARE_OP_NEVER;
sampler.minLod = 0.0f; sampler.minLod = 0.0f;
sampler.maxLod = 0.0f; sampler.maxLod = (float)texture->mipLevels;
sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
VK_CHECK_RESULT(vkCreateSampler(device, &sampler, nullptr, &texture->sampler)); VK_CHECK_RESULT(vkCreateSampler(device, &sampler, nullptr, &texture->sampler));
@ -830,6 +819,7 @@ namespace vkTools
view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
view.subresourceRange.layerCount = texture->layerCount; view.subresourceRange.layerCount = texture->layerCount;
view.subresourceRange.levelCount = texture->mipLevels;
view.image = texture->image; view.image = texture->image;
VK_CHECK_RESULT(vkCreateImageView(device, &view, nullptr, &texture->view)); VK_CHECK_RESULT(vkCreateImageView(device, &view, nullptr, &texture->view));