diff --git a/examples/screenshot/screenshot.cpp b/examples/screenshot/screenshot.cpp index 2bdaca0b..94e436fd 100644 --- a/examples/screenshot/screenshot.cpp +++ b/examples/screenshot/screenshot.cpp @@ -21,7 +21,6 @@ #include "vulkanexamplebase.h" #include "VulkanModel.hpp" -#define VERTEX_BUFFER_BIND_ID 0 #define ENABLE_VALIDATION false class VulkanExample : public VulkanExampleBase @@ -34,10 +33,7 @@ public: vks::VERTEX_COMPONENT_COLOR, }); - struct { - vks::Model object; - } models; - + vks::Model model; vks::Buffer uniformBuffer; struct { @@ -67,20 +63,16 @@ public: ~VulkanExample() { - // Clean up used Vulkan resources - // Note : Inherited destructor cleans up resources stored in base class vkDestroyPipeline(device, pipeline, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); - - models.object.destroy(); - + model.destroy(); uniformBuffer.destroy(); } void loadAssets() { - models.object.loadFromFile(getAssetPath() + "models/chinesedragon.dae", vertexLayout, 0.1f, vulkanDevice, queue); + model.loadFromFile(getAssetPath() + "models/chinesedragon.dae", vertexLayout, 0.1f, vulkanDevice, queue); } void buildCommandBuffers() @@ -119,10 +111,10 @@ public: vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); VkDeviceSize offsets[1] = { 0 }; - vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &models.object.vertices.buffer, offsets); - vkCmdBindIndexBuffer(drawCmdBuffers[i], models.object.indices.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &model.vertices.buffer, offsets); + vkCmdBindIndexBuffer(drawCmdBuffers[i], model.indices.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(drawCmdBuffers[i], models.object.indexCount, 1, 0, 0, 0); + vkCmdDrawIndexed(drawCmdBuffers[i], model.indexCount, 1, 0, 0, 0); vkCmdEndRenderPass(drawCmdBuffers[i]); @@ -132,115 +124,70 @@ public: void setupDescriptorPool() { - // Example uses one ubo and one image sampler std::vector poolSizes = { vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), }; - - VkDescriptorPoolCreateInfo descriptorPoolInfo = - vks::initializers::descriptorPoolCreateInfo( - poolSizes.size(), - poolSizes.data(), - 2); - + VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); } void setupDescriptorSetLayout() { std::vector setLayoutBindings = { - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), // Binding 0 : Vertex shader uniform buffer + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), // Binding 0: Vertex shader uniform buffer }; - - VkDescriptorSetLayoutCreateInfo descriptorLayout = - vks::initializers::descriptorSetLayoutCreateInfo( - setLayoutBindings.data(), - setLayoutBindings.size()); - + VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); - VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = - vks::initializers::pipelineLayoutCreateInfo( - &descriptorSetLayout, - 1); - + VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); } void setupDescriptorSet() { - VkDescriptorSetAllocateInfo allocInfo = - vks::initializers::descriptorSetAllocateInfo( - descriptorPool, - &descriptorSetLayout, - 1); - + VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); - std::vector writeDescriptorSets = { - vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor), // Binding 0 : Vertex shader uniform buffer + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor), // Binding 0: Vertex shader uniform buffer }; - - vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); + vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, nullptr); } void preparePipelines() { - VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = - vks::initializers::pipelineInputAssemblyStateCreateInfo( - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - 0, - VK_FALSE); + VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); + VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_CLOCKWISE, 0); + VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); + VkPipelineColorBlendStateCreateInfo colorBlendState = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); + VkPipelineDepthStencilStateCreateInfo depthStencilState = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL); + VkPipelineViewportStateCreateInfo viewportState = vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); + VkPipelineMultisampleStateCreateInfo multisampleState = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0); + std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables); - VkPipelineRasterizationStateCreateInfo rasterizationState = - vks::initializers::pipelineRasterizationStateCreateInfo( - VK_POLYGON_MODE_FILL, - VK_CULL_MODE_BACK_BIT, - VK_FRONT_FACE_CLOCKWISE, - 0); - - VkPipelineColorBlendAttachmentState blendAttachmentState = - vks::initializers::pipelineColorBlendAttachmentState( - 0xf, - VK_FALSE); - - VkPipelineColorBlendStateCreateInfo colorBlendState = - vks::initializers::pipelineColorBlendStateCreateInfo( - 1, - &blendAttachmentState); - - VkPipelineDepthStencilStateCreateInfo depthStencilState = - vks::initializers::pipelineDepthStencilStateCreateInfo( - VK_TRUE, - VK_TRUE, - VK_COMPARE_OP_LESS_OR_EQUAL); - - VkPipelineViewportStateCreateInfo viewportState = - vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); - - VkPipelineMultisampleStateCreateInfo multisampleState = - vks::initializers::pipelineMultisampleStateCreateInfo( - VK_SAMPLE_COUNT_1_BIT, - 0); - - std::vector dynamicStateEnables = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR + // Vertex bindings and attributes + // Binding description + std::vector vertexInputBindings = { + vks::initializers::vertexInputBindingDescription(0, vertexLayout.stride(), VK_VERTEX_INPUT_RATE_VERTEX), }; - VkPipelineDynamicStateCreateInfo dynamicState = - vks::initializers::pipelineDynamicStateCreateInfo( - dynamicStateEnables.data(), - dynamicStateEnables.size(), - 0); + // 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_R32G32B32_SFLOAT, sizeof(float) * 6), // 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(); - VkGraphicsPipelineCreateInfo pipelineCreateInfo = - vks::initializers::pipelineCreateInfo( - pipelineLayout, - renderPass, - 0); - - std::array shaderStages; + std::array shaderStages = { + loadShader(getAssetPath() + "shaders/screenshot/mesh.vert.spv", VK_SHADER_STAGE_VERTEX_BIT), + loadShader(getAssetPath() + "shaders/screenshot/mesh.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT), + }; + VkGraphicsPipelineCreateInfo pipelineCreateInfo = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0); pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; pipelineCreateInfo.pRasterizationState = &rasterizationState; pipelineCreateInfo.pColorBlendState = &colorBlendState; @@ -250,31 +197,7 @@ public: pipelineCreateInfo.pDynamicState = &dynamicState; 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_R32G32B32_SFLOAT, sizeof(float) * 6), // 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)); } @@ -286,7 +209,7 @@ public: VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniformBuffer, sizeof(uboVS)); - + VK_CHECK_RESULT(uniformBuffer.map()); updateUniformBuffers(); } @@ -295,26 +218,20 @@ public: uboVS.projection = camera.matrices.perspective; uboVS.view = camera.matrices.view; uboVS.model = glm::mat4(1.0f); - - VK_CHECK_RESULT(uniformBuffer.map()); uniformBuffer.copyTo(&uboVS, sizeof(uboVS)); - uniformBuffer.unmap(); } - // Take a screenshot for the curretn swapchain image + // Take a screenshot from the current swapchain image // This is done using a blit from the swapchain image to a linear image whose memory content is then saved as a ppm image // Getting the image date directly from a swapchain image wouldn't work as they're usually stored in an implementation dependant optimal tiling format // Note: This requires the swapchain images to be created with the VK_IMAGE_USAGE_TRANSFER_SRC_BIT flag (see VulkanSwapChain::create) void saveScreenshot(const char *filename) { screenshotSaved = false; - - // Get format properties for the swapchain color format - VkFormatProperties formatProps; - bool supportsBlit = true; // Check blit support for source and destination + VkFormatProperties formatProps; // Check if the device supports blitting from optimal images (the swapchain images are in optimal format) vkGetPhysicalDeviceFormatProperties(physicalDevice, swapChain.colorFormat, &formatProps); @@ -334,22 +251,22 @@ public: 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; + VkImageCreateInfo imageCreateCI(vks::initializers::imageCreateInfo()); + imageCreateCI.imageType = VK_IMAGE_TYPE_2D; // 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; - imgCreateInfo.extent.depth = 1; - imgCreateInfo.arrayLayers = 1; - imgCreateInfo.mipLevels = 1; - imgCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imgCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imgCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; - imgCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; + imageCreateCI.format = VK_FORMAT_R8G8B8A8_UNORM; + imageCreateCI.extent.width = width; + imageCreateCI.extent.height = height; + imageCreateCI.extent.depth = 1; + imageCreateCI.arrayLayers = 1; + imageCreateCI.mipLevels = 1; + imageCreateCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageCreateCI.samples = VK_SAMPLE_COUNT_1_BIT; + imageCreateCI.tiling = VK_IMAGE_TILING_LINEAR; + imageCreateCI.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; // Create the image VkImage dstImage; - VK_CHECK_RESULT(vkCreateImage(device, &imgCreateInfo, nullptr, &dstImage)); + VK_CHECK_RESULT(vkCreateImage(device, &imageCreateCI, nullptr, &dstImage)); // Create memory to back up the image VkMemoryRequirements memRequirements; VkMemoryAllocateInfo memAllocInfo(vks::initializers::memoryAllocateInfo()); @@ -463,10 +380,8 @@ public: vulkanDevice->flushCommandBuffer(copyCmd, queue); // Get layout of the image (including row pitch) - VkImageSubresource subResource{}; - subResource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + VkImageSubresource subResource { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 }; VkSubresourceLayout subResourceLayout; - vkGetImageSubresourceLayout(device, dstImage, &subResource, &subResourceLayout); // Map image memory so we can start copying from it