Added fallback to plain image copy with manual swizzle if blit is not supported (Refs #288)
This commit is contained in:
parent
27f45cb367
commit
bfbb636aab
1 changed files with 107 additions and 95 deletions
|
|
@ -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,27 +381,51 @@ public:
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||||
|
|
||||||
// Define the region to blit (we will blit the whole swapchain image)
|
// If source and destination support blit we'll blit as this also does automatic format conversion (e.g. from BGR to RGB)
|
||||||
VkOffset3D blitSize;
|
if (supportsBlit)
|
||||||
blitSize.x = width;
|
{
|
||||||
blitSize.y = height;
|
// Define the region to blit (we will blit the whole swapchain image)
|
||||||
blitSize.z = 1;
|
VkOffset3D blitSize;
|
||||||
VkImageBlit imageBlitRegion{};
|
blitSize.x = width;
|
||||||
imageBlitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
blitSize.y = height;
|
||||||
imageBlitRegion.srcSubresource.layerCount = 1;
|
blitSize.z = 1;
|
||||||
imageBlitRegion.srcOffsets[1] = blitSize;
|
VkImageBlit imageBlitRegion{};
|
||||||
imageBlitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
imageBlitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
imageBlitRegion.dstSubresource.layerCount = 1;
|
imageBlitRegion.srcSubresource.layerCount = 1;
|
||||||
imageBlitRegion.dstOffsets[1] = blitSize;
|
imageBlitRegion.srcOffsets[1] = blitSize;
|
||||||
|
imageBlitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
imageBlitRegion.dstSubresource.layerCount = 1;
|
||||||
|
imageBlitRegion.dstOffsets[1] = blitSize;
|
||||||
|
|
||||||
// Issue the blit command
|
// Issue the blit command
|
||||||
vkCmdBlitImage(
|
vkCmdBlitImage(
|
||||||
copyCmd,
|
copyCmd,
|
||||||
srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
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++)
|
||||||
{
|
{
|
||||||
file.write((char*)row, 3);
|
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);
|
||||||
|
}
|
||||||
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();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue