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
|
||||
{
|
||||
public:
|
||||
struct {
|
||||
VkPipelineVertexInputStateCreateInfo inputState;
|
||||
std::vector<VkVertexInputBindingDescription> bindingDescriptions;
|
||||
std::vector<VkVertexInputAttributeDescription> attributeDescriptions;
|
||||
} vertices;
|
||||
|
||||
// Vertex layout for the models
|
||||
vks::VertexLayout vertexLayout = vks::VertexLayout({
|
||||
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()
|
||||
{
|
||||
// Example uses one ubo and one image sampler
|
||||
|
|
@ -286,19 +231,14 @@ public:
|
|||
dynamicStateEnables.size(),
|
||||
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 =
|
||||
vks::initializers::pipelineCreateInfo(
|
||||
pipelineLayout,
|
||||
renderPass,
|
||||
0);
|
||||
|
||||
pipelineCreateInfo.pVertexInputState = &vertices.inputState;
|
||||
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
|
||||
|
||||
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
|
||||
pipelineCreateInfo.pRasterizationState = &rasterizationState;
|
||||
pipelineCreateInfo.pColorBlendState = &colorBlendState;
|
||||
|
|
@ -309,6 +249,31 @@ public:
|
|||
pipelineCreateInfo.stageCount = shaderStages.size();
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
@ -343,27 +308,32 @@ public:
|
|||
{
|
||||
// Get format properties for the swapchain color format
|
||||
VkFormatProperties formatProps;
|
||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, swapChain.colorFormat, &formatProps);
|
||||
|
||||
// Check if the device supports blitting to linear images
|
||||
if (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT)) {
|
||||
std::cerr << "Error: Device does not support blitting to linear tiled images!" << std::endl;
|
||||
return;
|
||||
}
|
||||
boolean supportsBlit = true;
|
||||
|
||||
// Check blit support for source and destination
|
||||
|
||||
// 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)) {
|
||||
std::cerr << "Error: Device does not support blitting from optimal tiled images!" << std::endl;
|
||||
return;
|
||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, swapChain.colorFormat, &formatProps);
|
||||
if (!(formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT)) {
|
||||
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];
|
||||
|
||||
// Create the linear tiled destination image to copy to and to read the memory from
|
||||
VkImageCreateInfo imgCreateInfo(vks::initializers::imageCreateInfo());
|
||||
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.extent.width = width;
|
||||
imgCreateInfo.extent.height = height;
|
||||
|
|
@ -411,27 +381,51 @@ public:
|
|||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
|
||||
// Define the region to blit (we will blit the whole swapchain image)
|
||||
VkOffset3D blitSize;
|
||||
blitSize.x = width;
|
||||
blitSize.y = height;
|
||||
blitSize.z = 1;
|
||||
VkImageBlit imageBlitRegion{};
|
||||
imageBlitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
imageBlitRegion.srcSubresource.layerCount = 1;
|
||||
imageBlitRegion.srcOffsets[1] = blitSize;
|
||||
imageBlitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
imageBlitRegion.dstSubresource.layerCount = 1;
|
||||
imageBlitRegion.dstOffsets[1] = blitSize;
|
||||
// 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)
|
||||
VkOffset3D blitSize;
|
||||
blitSize.x = width;
|
||||
blitSize.y = height;
|
||||
blitSize.z = 1;
|
||||
VkImageBlit imageBlitRegion{};
|
||||
imageBlitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
imageBlitRegion.srcSubresource.layerCount = 1;
|
||||
imageBlitRegion.srcOffsets[1] = blitSize;
|
||||
imageBlitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
imageBlitRegion.dstSubresource.layerCount = 1;
|
||||
imageBlitRegion.dstOffsets[1] = blitSize;
|
||||
|
||||
// Issue the blit command
|
||||
vkCmdBlitImage(
|
||||
copyCmd,
|
||||
srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1,
|
||||
&imageBlitRegion,
|
||||
VK_FILTER_NEAREST);
|
||||
// Issue the blit command
|
||||
vkCmdBlitImage(
|
||||
copyCmd,
|
||||
srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1,
|
||||
&imageBlitRegion,
|
||||
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
|
||||
vks::tools::setImageLayout(
|
||||
|
|
@ -472,13 +466,32 @@ public:
|
|||
// ppm header
|
||||
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
|
||||
for (uint32_t y = 0; y < height; y++)
|
||||
{
|
||||
unsigned int *row = (unsigned int*)data;
|
||||
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++;
|
||||
}
|
||||
data += subResourceLayout.rowPitch;
|
||||
|
|
@ -508,7 +521,6 @@ public:
|
|||
{
|
||||
VulkanExampleBase::prepare();
|
||||
loadAssets();
|
||||
prepareVertices();
|
||||
prepareUniformBuffers();
|
||||
setupDescriptorSetLayout();
|
||||
preparePipelines();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue