Added fallback to plain image copy with manual swizzle if blit is not supported (Refs #288)

This commit is contained in:
saschawillems 2017-02-23 19:14:53 +01:00
parent 27f45cb367
commit bfbb636aab

View file

@ -27,12 +27,6 @@
class VulkanExample : public VulkanExampleBase class VulkanExample : public VulkanExampleBase
{ {
public: public:
struct {
VkPipelineVertexInputStateCreateInfo inputState;
std::vector<VkVertexInputBindingDescription> bindingDescriptions;
std::vector<VkVertexInputAttributeDescription> attributeDescriptions;
} vertices;
// Vertex layout for the models // Vertex layout for the models
vks::VertexLayout vertexLayout = vks::VertexLayout({ vks::VertexLayout vertexLayout = vks::VertexLayout({
vks::VERTEX_COMPONENT_POSITION, vks::VERTEX_COMPONENT_POSITION,
@ -134,55 +128,6 @@ public:
} }
} }
void prepareVertices()
{
// Binding description
vertices.bindingDescriptions.resize(1);
vertices.bindingDescriptions[0] =
vks::initializers::vertexInputBindingDescription(
VERTEX_BUFFER_BIND_ID,
vertexLayout.stride(),
VK_VERTEX_INPUT_RATE_VERTEX);
// Attribute descriptions
// Describes memory layout and shader positions
vertices.attributeDescriptions.resize(4);
// Location 0 : Position
vertices.attributeDescriptions[0] =
vks::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
0,
VK_FORMAT_R32G32B32_SFLOAT,
0);
// Location 1 : Normal
vertices.attributeDescriptions[1] =
vks::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
1,
VK_FORMAT_R32G32B32_SFLOAT,
sizeof(float) * 3);
// Location 2 : Texture coordinates
vertices.attributeDescriptions[2] =
vks::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
2,
VK_FORMAT_R32G32_SFLOAT,
sizeof(float) * 6);
// Location 3 : Color
vertices.attributeDescriptions[3] =
vks::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
3,
VK_FORMAT_R32G32B32_SFLOAT,
sizeof(float) * 8);
vertices.inputState = vks::initializers::pipelineVertexInputStateCreateInfo();
vertices.inputState.vertexBindingDescriptionCount = vertices.bindingDescriptions.size();
vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data();
vertices.inputState.vertexAttributeDescriptionCount = vertices.attributeDescriptions.size();
vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data();
}
void setupDescriptorPool() void setupDescriptorPool()
{ {
// Example uses one ubo and one image sampler // Example uses one ubo and one image sampler
@ -286,19 +231,14 @@ public:
dynamicStateEnables.size(), dynamicStateEnables.size(),
0); 0);
// Spherical environment rendering pipeline
// Load shaders
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
shaderStages[0] = loadShader(getAssetPath() + "shaders/screenshot/mesh.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getAssetPath() + "shaders/screenshot/mesh.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
VkGraphicsPipelineCreateInfo pipelineCreateInfo = VkGraphicsPipelineCreateInfo pipelineCreateInfo =
vks::initializers::pipelineCreateInfo( vks::initializers::pipelineCreateInfo(
pipelineLayout, pipelineLayout,
renderPass, renderPass,
0); 0);
pipelineCreateInfo.pVertexInputState = &vertices.inputState; std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
pipelineCreateInfo.pRasterizationState = &rasterizationState; pipelineCreateInfo.pRasterizationState = &rasterizationState;
pipelineCreateInfo.pColorBlendState = &colorBlendState; pipelineCreateInfo.pColorBlendState = &colorBlendState;
@ -309,6 +249,31 @@ public:
pipelineCreateInfo.stageCount = shaderStages.size(); pipelineCreateInfo.stageCount = shaderStages.size();
pipelineCreateInfo.pStages = shaderStages.data(); pipelineCreateInfo.pStages = shaderStages.data();
// Vertex bindings and attributes
// Binding description
std::vector<VkVertexInputBindingDescription> vertexInputBindings = {
vks::initializers::vertexInputBindingDescription(0, vertexLayout.stride(), VK_VERTEX_INPUT_RATE_VERTEX),
};
// Attribute descriptions
std::vector<VkVertexInputAttributeDescription> vertexInputAttributes = {
vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), // Position
vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3), // Normal
vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 6), // UV
vks::initializers::vertexInputAttributeDescription(0, 3, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 8), // Color
};
VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo();
vertexInputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexInputBindings.size());
vertexInputState.pVertexBindingDescriptions = vertexInputBindings.data();
vertexInputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexInputAttributes.size());
vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data();
pipelineCreateInfo.pVertexInputState = &vertexInputState;
// Mesh rendering pipeline
shaderStages[0] = loadShader(getAssetPath() + "shaders/screenshot/mesh.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getAssetPath() + "shaders/screenshot/mesh.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline));
} }
@ -343,27 +308,32 @@ public:
{ {
// Get format properties for the swapchain color format // Get format properties for the swapchain color format
VkFormatProperties formatProps; VkFormatProperties formatProps;
vkGetPhysicalDeviceFormatProperties(physicalDevice, swapChain.colorFormat, &formatProps);
// Check if the device supports blitting to linear images boolean supportsBlit = true;
if (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT)) {
std::cerr << "Error: Device does not support blitting to linear tiled images!" << std::endl; // Check blit support for source and destination
return;
}
// Check if the device supports blitting from optimal images (the swapchain images are in optimal format) // Check if the device supports blitting from optimal images (the swapchain images are in optimal format)
if (!(formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT)) { vkGetPhysicalDeviceFormatProperties(physicalDevice, swapChain.colorFormat, &formatProps);
std::cerr << "Error: Device does not support blitting from optimal tiled images!" << std::endl; if (!(formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT)) {
return; std::cerr << "Device does not support blitting from optimal tiled images, using copy instead of blit!" << std::endl;
supportsBlit = false;
} }
// Source for the blit is the last rendered swapchain image // Check if the device supports blitting to linear images
vkGetPhysicalDeviceFormatProperties(physicalDevice, VK_FORMAT_R8G8B8A8_UNORM, &formatProps);
if (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT)) {
std::cerr << "Device does not support blitting to linear tiled images, using copy instead of blit!" << std::endl;
supportsBlit = false;
}
// Source for the copy is the last rendered swapchain image
VkImage srcImage = swapChain.images[currentBuffer]; VkImage srcImage = swapChain.images[currentBuffer];
// Create the linear tiled destination image to copy to and to read the memory from // Create the linear tiled destination image to copy to and to read the memory from
VkImageCreateInfo imgCreateInfo(vks::initializers::imageCreateInfo()); VkImageCreateInfo imgCreateInfo(vks::initializers::imageCreateInfo());
imgCreateInfo.imageType = VK_IMAGE_TYPE_2D; imgCreateInfo.imageType = VK_IMAGE_TYPE_2D;
// Note that vkCmdBlitImage will also do format conversions if the swapchain color format would differ // Note that vkCmdBlitImage (if supported) will also do format conversions if the swapchain color format would differ
imgCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; imgCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
imgCreateInfo.extent.width = width; imgCreateInfo.extent.width = width;
imgCreateInfo.extent.height = height; imgCreateInfo.extent.height = height;
@ -411,6 +381,9 @@ public:
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT); VK_PIPELINE_STAGE_TRANSFER_BIT);
// If source and destination support blit we'll blit as this also does automatic format conversion (e.g. from BGR to RGB)
if (supportsBlit)
{
// Define the region to blit (we will blit the whole swapchain image) // Define the region to blit (we will blit the whole swapchain image)
VkOffset3D blitSize; VkOffset3D blitSize;
blitSize.x = width; blitSize.x = width;
@ -432,6 +405,27 @@ public:
1, 1,
&imageBlitRegion, &imageBlitRegion,
VK_FILTER_NEAREST); VK_FILTER_NEAREST);
}
else
{
// Otherwise use image copy (requires us to manually flip components)
VkImageCopy imageCopyRegion{};
imageCopyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageCopyRegion.srcSubresource.layerCount = 1;
imageCopyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageCopyRegion.dstSubresource.layerCount = 1;
imageCopyRegion.extent.width = width;
imageCopyRegion.extent.height = height;
imageCopyRegion.extent.depth = 1;
// Issue the copy command
vkCmdCopyImage(
copyCmd,
srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&imageCopyRegion);
}
// Transition destination image to general layout, which is the required layout for mapping the image memory later on // Transition destination image to general layout, which is the required layout for mapping the image memory later on
vks::tools::setImageLayout( vks::tools::setImageLayout(
@ -472,13 +466,32 @@ public:
// ppm header // ppm header
file << "P6\n" << width << "\n" << height << "\n" << 255 << "\n"; file << "P6\n" << width << "\n" << height << "\n" << 255 << "\n";
// If source is BGR (destination is always RGB) and we can't use blit (which does automatic conversion), we'll have to manually swizzle color components
boolean colorSwizzle = false;
// Check if source is BGR
// Note: Not complete, only contains most common and basic BGR surface formats for demonstation purposes
if (!supportsBlit)
{
std::vector<VkFormat> formatsBGR = { VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SNORM };
colorSwizzle = (std::find(formatsBGR.begin(), formatsBGR.end(), swapChain.colorFormat) != formatsBGR.end());
}
// ppm binary pixel data // ppm binary pixel data
for (uint32_t y = 0; y < height; y++) for (uint32_t y = 0; y < height; y++)
{ {
unsigned int *row = (unsigned int*)data; unsigned int *row = (unsigned int*)data;
for (uint32_t x = 0; x < width; x++) for (uint32_t x = 0; x < width; x++)
{
if (colorSwizzle)
{
file.write((char*)row+2, 1);
file.write((char*)row+1, 1);
file.write((char*)row, 1);
}
else
{ {
file.write((char*)row, 3); file.write((char*)row, 3);
}
row++; row++;
} }
data += subResourceLayout.rowPitch; data += subResourceLayout.rowPitch;
@ -508,7 +521,6 @@ public:
{ {
VulkanExampleBase::prepare(); VulkanExampleBase::prepare();
loadAssets(); loadAssets();
prepareVertices();
prepareUniformBuffers(); prepareUniformBuffers();
setupDescriptorSetLayout(); setupDescriptorSetLayout();
preparePipelines(); preparePipelines();