#include "dofpass.h" #include #include #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #include "renderer.h" DoFPass::DoFPass(Renderer& renderer) : renderer_(renderer) { createRenderPass(); createDescriptorSetLayout(); createPipeline(); createBokehImage(); } DoFPass::~DoFPass() { vkDestroySampler(renderer_.getDevice(), bokehSampler_, nullptr); vkDestroyImageView(renderer_.getDevice(), bokehImageView_, nullptr); vkFreeMemory(renderer_.getDevice(), bokehMemory_, nullptr); vkDestroyImage(renderer_.getDevice(), bokehImage_, nullptr); vkDestroyPipeline(renderer_.getDevice(), pipeline_, nullptr); vkDestroyPipelineLayout(renderer_.getDevice(), pipelineLayout_, nullptr); vkDestroyDescriptorSetLayout(renderer_.getDevice(), setLayout_, nullptr); vkDestroyRenderPass(renderer_.getDevice(), renderPass_, nullptr); } void DoFPass::render(VkCommandBuffer commandBuffer, RenderTarget* target) { VkViewport viewport = {}; viewport.width = target->extent.width / 2; viewport.height = target->extent.height / 2; viewport.maxDepth = 1.0f; vkCmdSetViewport(commandBuffer, 0, 1, &viewport); VkRect2D scissor = {}; scissor.extent.width = target->extent.width / 2; scissor.extent.height = target->extent.height / 2; vkCmdSetScissor(commandBuffer, 0, 1, &scissor); VkClearValue clearColor = {}; VkRenderPassBeginInfo renderPassBeginInfo = {}; renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassBeginInfo.framebuffer = target->farFieldFramebuffers[target->currentImage]; renderPassBeginInfo.renderPass = renderPass_; renderPassBeginInfo.renderArea.extent.width = target->extent.width / 2; renderPassBeginInfo.renderArea.extent.height = target->extent.height / 2; renderPassBeginInfo.clearValueCount = 1; renderPassBeginInfo.pClearValues = &clearColor; // far field vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); glm::vec4 dpack; dpack[0] = 0; dpack[1] = 0.9581; dpack[2] = target->extent.width / 2; dpack[3] = target->extent.height / 2; vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &target->dofSets[target->currentImage], 0, nullptr); vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(glm::vec4), &dpack); vkCmdDraw(commandBuffer, 3, (target->extent.width / 2) * (target->extent.height / 2), 0, 0); vkCmdEndRenderPass(commandBuffer); //near field renderPassBeginInfo.framebuffer = target->nearFieldFramebuffers[target->currentImage]; vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &target->dofSets[target->currentImage], 0, nullptr); dpack[0] = 1; dpack[1] = 0.9581; vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(glm::vec4), &dpack); //FIXME: near field is bugged //vkCmdDraw(commandBuffer, 3, (target->extent.width / 2) * (target->extent.height / 2), 0, 0); vkCmdEndRenderPass(commandBuffer); } void DoFPass::createDescriptorSet(RenderTarget* target) { VkDescriptorSetAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocInfo.descriptorPool = renderer_.getDescriptorPool(); allocInfo.descriptorSetCount = target->numImages; // FIXME: lol what auto layouts = new VkDescriptorSetLayout[target->numImages]; for(uint32_t i = 0; i < target->numImages; i++) layouts[i] = setLayout_; allocInfo.pSetLayouts = layouts; target->dofSets = new VkDescriptorSet[target->numImages]; vkAllocateDescriptorSets(renderer_.getDevice(), &allocInfo, target->dofSets); delete[] layouts; for(uint32_t i = 0; i < target->numImages; i++) { VkDescriptorImageInfo bokehImageInfo = {}; bokehImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; bokehImageInfo.imageView = bokehImageView_; bokehImageInfo.sampler = bokehSampler_; VkDescriptorImageInfo sceneImageInfo = {}; sceneImageInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; sceneImageInfo.imageView = target->offscreenColorImageViews[i]; sceneImageInfo.sampler = bokehSampler_; VkDescriptorImageInfo depthImageInfo = {}; depthImageInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;; depthImageInfo.imageView = target->offscreenDepthImageViews[i]; depthImageInfo.sampler = bokehSampler_; VkWriteDescriptorSet bokehDescriptorWrite = {}; bokehDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; bokehDescriptorWrite.descriptorCount = 1; bokehDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; bokehDescriptorWrite.dstSet = target->dofSets[i]; bokehDescriptorWrite.pImageInfo = &bokehImageInfo; VkWriteDescriptorSet sceneDescriptorWrite = {}; sceneDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; sceneDescriptorWrite.descriptorCount = 1; sceneDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; sceneDescriptorWrite.dstBinding = 1; sceneDescriptorWrite.dstSet = target->dofSets[i]; sceneDescriptorWrite.pImageInfo = &sceneImageInfo; VkWriteDescriptorSet depthDescriptorWrite = {}; depthDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; depthDescriptorWrite.descriptorCount = 1; depthDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; depthDescriptorWrite.dstBinding = 2; depthDescriptorWrite.dstSet = target->dofSets[i]; depthDescriptorWrite.pImageInfo = &depthImageInfo; const std::array descriptorWrites = { bokehDescriptorWrite, sceneDescriptorWrite, depthDescriptorWrite }; vkUpdateDescriptorSets(renderer_.getDevice(), descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); } } void DoFPass::createRenderPass() { VkAttachmentDescription colorAttachment = {}; colorAttachment.format = VK_FORMAT_R32G32B32A32_SFLOAT; colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkAttachmentReference colorAttachmentRef = {}; colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkSubpassDescription subpass = {}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &colorAttachmentRef; VkRenderPassCreateInfo renderPassInfo = {}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; renderPassInfo.attachmentCount = 1; renderPassInfo.pAttachments = &colorAttachment; renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; vkCreateRenderPass(renderer_.getDevice(), &renderPassInfo, nullptr, &renderPass_); } void DoFPass::createDescriptorSetLayout() { VkDescriptorSetLayoutBinding bokehSamplerBinding = {}; bokehSamplerBinding.descriptorCount = 1; bokehSamplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; bokehSamplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; VkDescriptorSetLayoutBinding sceneSamplerBinding = {}; sceneSamplerBinding.binding = 1; sceneSamplerBinding.descriptorCount = 1; sceneSamplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; sceneSamplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; VkDescriptorSetLayoutBinding depthSamplerBinding = {}; depthSamplerBinding.binding = 2; depthSamplerBinding.descriptorCount = 1; depthSamplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; depthSamplerBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; const std::array bindings = { bokehSamplerBinding, sceneSamplerBinding, depthSamplerBinding }; VkDescriptorSetLayoutCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; createInfo.bindingCount = bindings.size(); createInfo.pBindings = bindings.data(); vkCreateDescriptorSetLayout(renderer_.getDevice(), &createInfo, nullptr, &setLayout_); } void DoFPass::createPipeline() { VkShaderModule vertShaderModule = renderer_.createShader("shaders/gfield.vert.spv"); VkShaderModule fragShaderModule = renderer_.createShader("shaders/gfield.frag.spv"); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; vertShaderStageInfo.module = vertShaderModule; vertShaderStageInfo.pName = "main"; VkPipelineShaderStageCreateInfo fragShaderStageInfo = {}; fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; fragShaderStageInfo.module = fragShaderModule; fragShaderStageInfo.pName = "main"; const std::array shaderStages = {vertShaderStageInfo, fragShaderStageInfo}; VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; VkPipelineViewportStateCreateInfo viewportState = {}; viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; viewportState.viewportCount = 1; viewportState.scissorCount = 1; VkPipelineRasterizationStateCreateInfo rasterizer = {}; rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rasterizer.polygonMode = VK_POLYGON_MODE_FILL; rasterizer.lineWidth = 1.0f; rasterizer.cullMode = VK_CULL_MODE_FRONT_BIT; rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; VkPipelineMultisampleStateCreateInfo multisampling = {}; multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; colorBlendAttachment.blendEnable = VK_TRUE; colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE; colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; VkPipelineColorBlendStateCreateInfo colorBlending = {}; colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; colorBlending.attachmentCount = 1; colorBlending.pAttachments = &colorBlendAttachment; const std::array dynamicStates = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; VkPipelineDynamicStateCreateInfo dynamicState = {}; dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dynamicState.dynamicStateCount = dynamicStates.size(); dynamicState.pDynamicStates = dynamicStates.data(); VkPushConstantRange pushConstant = {}; pushConstant.size = sizeof(glm::vec4); pushConstant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; pipelineLayoutInfo.pSetLayouts = &setLayout_; pipelineLayoutInfo.pushConstantRangeCount = 1; pipelineLayoutInfo.pPushConstantRanges = &pushConstant; vkCreatePipelineLayout(renderer_.getDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout_); VkGraphicsPipelineCreateInfo pipelineInfo = {}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipelineInfo.stageCount = shaderStages.size(); pipelineInfo.pStages = shaderStages.data(); pipelineInfo.pVertexInputState = &vertexInputInfo; pipelineInfo.pInputAssemblyState = &inputAssembly; pipelineInfo.pViewportState = &viewportState; pipelineInfo.pRasterizationState = &rasterizer; pipelineInfo.pMultisampleState = &multisampling; pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.pDynamicState = &dynamicState; pipelineInfo.layout = pipelineLayout_; pipelineInfo.renderPass = renderPass_; vkCreateGraphicsPipelines(renderer_.getDevice(), nullptr, 1, &pipelineInfo, nullptr, &pipeline_); vkDestroyShaderModule(renderer_.getDevice(), fragShaderModule, nullptr); vkDestroyShaderModule(renderer_.getDevice(), vertShaderModule, nullptr); } void DoFPass::createBokehImage() { int width, height, channels; stbi_uc* pixels = stbi_load("data/bokeh.png", &width, &height, &channels, STBI_rgb_alpha); VkImageCreateInfo imageCreateInfo = {}; imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.extent.width = width; imageCreateInfo.extent.height = height; imageCreateInfo.extent.depth = 1; imageCreateInfo.mipLevels = 1; imageCreateInfo.arrayLayers = 1; imageCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; vkCreateImage(renderer_.getDevice(), &imageCreateInfo, nullptr, &bokehImage_); VkMemoryRequirements memRequirements; vkGetImageMemoryRequirements(renderer_.getDevice(), bokehImage_, &memRequirements); VkMemoryAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = renderer_.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vkAllocateMemory(renderer_.getDevice(), &allocInfo, nullptr, &bokehMemory_); vkBindImageMemory(renderer_.getDevice(), bokehImage_, bokehMemory_, 0); VkBuffer stagingBuffer; VkDeviceMemory stagingMemory; VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = width * height * 4; bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; vkCreateBuffer(renderer_.getDevice(), &bufferInfo, nullptr, &stagingBuffer); vkGetBufferMemoryRequirements(renderer_.getDevice(), stagingBuffer, &memRequirements); allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = renderer_.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); vkAllocateMemory(renderer_.getDevice(), &allocInfo, nullptr, &stagingMemory); vkBindBufferMemory(renderer_.getDevice(), stagingBuffer, stagingMemory, 0); void* data; vkMapMemory(renderer_.getDevice(), stagingMemory, 0, width * height * 4, 0, &data); memcpy(data, pixels, width * height * 4); vkUnmapMemory(renderer_.getDevice(), stagingMemory); stbi_image_free(pixels); VkCommandBufferAllocateInfo bufferAllocateInfo = {}; bufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; bufferAllocateInfo.commandPool = renderer_.getCommandPool(); bufferAllocateInfo.commandBufferCount = 1; VkCommandBuffer commandBuffer = nullptr; vkAllocateCommandBuffers(renderer_.getDevice(), &bufferAllocateInfo, &commandBuffer); VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; vkBeginCommandBuffer(commandBuffer, &beginInfo); // change layout to transfer dst { VkImageMemoryBarrier imageMemoryBarrier = {}; imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; imageMemoryBarrier.image = bokehImage_; imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageMemoryBarrier.subresourceRange.layerCount = 1; imageMemoryBarrier.subresourceRange.levelCount = 1; vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); } VkBufferImageCopy region = {}; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.layerCount = 1; region.imageExtent.width = width; region.imageExtent.height = height; region.imageExtent.depth = 1; vkCmdCopyBufferToImage( commandBuffer, stagingBuffer, bokehImage_, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion ); // change layout to shader read only { VkImageMemoryBarrier imageMemoryBarrier = {}; imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageMemoryBarrier.image = bokehImage_; imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageMemoryBarrier.subresourceRange.layerCount = 1; imageMemoryBarrier.subresourceRange.levelCount = 1; vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); } vkEndCommandBuffer(commandBuffer); VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &commandBuffer; VkFenceCreateInfo fenceCreateInfo = {}; fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; VkFence fence = nullptr; vkCreateFence(renderer_.getDevice(), &fenceCreateInfo, nullptr, &fence); vkQueueSubmit(renderer_.getGraphicsQueue(), 1, &submitInfo, fence); vkWaitForFences(renderer_.getDevice(), 1, &fence, VK_TRUE, -1); vkDestroyFence(renderer_.getDevice(), fence, nullptr); vkFreeCommandBuffers(renderer_.getDevice(), renderer_.getCommandPool(), 1, &commandBuffer); vkFreeMemory(renderer_.getDevice(), stagingMemory, nullptr); vkDestroyBuffer(renderer_.getDevice(), stagingBuffer, nullptr); VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = bokehImage_; createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; createInfo.format = VK_FORMAT_R8G8B8A8_UNORM; createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; createInfo.subresourceRange.levelCount = 1; createInfo.subresourceRange.layerCount = 1; vkCreateImageView(renderer_.getDevice(), &createInfo, nullptr, &bokehImageView_); VkSamplerCreateInfo samplerInfo = {}; samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; samplerInfo.magFilter = VK_FILTER_LINEAR; samplerInfo.minFilter = VK_FILTER_LINEAR; samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; vkCreateSampler(renderer_.getDevice(), &samplerInfo, nullptr, &bokehSampler_); }