diff --git a/screenshot/screenshot.cpp b/screenshot/screenshot.cpp index 1d5f0eeb..a3b39ced 100644 --- a/screenshot/screenshot.cpp +++ b/screenshot/screenshot.cpp @@ -27,12 +27,6 @@ class VulkanExample : public VulkanExampleBase { public: - struct { - VkPipelineVertexInputStateCreateInfo inputState; - std::vector bindingDescriptions; - std::vector 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 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 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 vertexInputBindings = { + vks::initializers::vertexInputBindingDescription(0, vertexLayout.stride(), VK_VERTEX_INPUT_RATE_VERTEX), + }; + + // Attribute descriptions + std::vector 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(vertexInputBindings.size()); + vertexInputState.pVertexBindingDescriptions = vertexInputBindings.data(); + vertexInputState.vertexAttributeDescriptionCount = static_cast(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 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();