void FramebufferManager::DestroyEFBFramebuffer() { if (m_efb_framebuffer != VK_NULL_HANDLE) { vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_efb_framebuffer, nullptr); m_efb_framebuffer = VK_NULL_HANDLE; } if (m_efb_convert_framebuffer != VK_NULL_HANDLE) { vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_efb_convert_framebuffer, nullptr); m_efb_convert_framebuffer = VK_NULL_HANDLE; } if (m_depth_resolve_framebuffer != VK_NULL_HANDLE) { vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_depth_resolve_framebuffer, nullptr); m_depth_resolve_framebuffer = VK_NULL_HANDLE; } m_efb_color_texture.reset(); m_efb_convert_color_texture.reset(); m_efb_depth_texture.reset(); m_efb_resolve_color_texture.reset(); m_efb_resolve_depth_texture.reset(); }
VulkanFramebuffer::~VulkanFramebuffer() { VkDevice device = mOwner->getDevice().getLogical(); vkDestroyFramebuffer(device, mDefault.framebuffer, gVulkanAllocator); vkDestroyRenderPass(device, mDefault.renderPass, gVulkanAllocator); for(auto& entry : mVariants) { vkDestroyFramebuffer(device, entry.second.framebuffer, gVulkanAllocator); vkDestroyRenderPass(device, entry.second.renderPass, gVulkanAllocator); } }
static void cleanup_vulkan() { vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator); for (int i = 0; i < IMGUI_VK_QUEUED_FRAMES; i++) { vkDestroyFence(g_Device, g_Fence[i], g_Allocator); vkFreeCommandBuffers(g_Device, g_CommandPool[i], 1, &g_CommandBuffer[i]); vkDestroyCommandPool(g_Device, g_CommandPool[i], g_Allocator); vkDestroySemaphore(g_Device, g_PresentCompleteSemaphore[i], g_Allocator); vkDestroySemaphore(g_Device, g_RenderCompleteSemaphore[i], g_Allocator); } for (uint32_t i = 0; i < g_BackBufferCount; i++) { vkDestroyImageView(g_Device, g_BackBufferView[i], g_Allocator); vkDestroyFramebuffer(g_Device, g_Framebuffer[i], g_Allocator); } vkDestroyRenderPass(g_Device, g_RenderPass, g_Allocator); vkDestroySwapchainKHR(g_Device, g_Swapchain, g_Allocator); vkDestroySurfaceKHR(g_Instance, g_Surface, g_Allocator); #ifdef IMGUI_VULKAN_DEBUG_REPORT // get the proc address of the function pointer, required for used extensions auto vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT"); vkDestroyDebugReportCallbackEXT(g_Instance, g_Debug_Report, g_Allocator); #endif // IMGUI_VULKAN_DEBUG_REPORT vkDestroyDevice(g_Device, g_Allocator); vkDestroyInstance(g_Instance, g_Allocator); }
void Tutorial03::ChildClear() { if( GetDevice() != VK_NULL_HANDLE ) { vkDeviceWaitIdle( GetDevice() ); if( (Vulkan.GraphicsCommandBuffers.size() > 0) && (Vulkan.GraphicsCommandBuffers[0] != VK_NULL_HANDLE) ) { vkFreeCommandBuffers( GetDevice(), Vulkan.GraphicsCommandPool, static_cast<uint32_t>(Vulkan.GraphicsCommandBuffers.size()), &Vulkan.GraphicsCommandBuffers[0] ); Vulkan.GraphicsCommandBuffers.clear(); } if( Vulkan.GraphicsCommandPool != VK_NULL_HANDLE ) { vkDestroyCommandPool( GetDevice(), Vulkan.GraphicsCommandPool, nullptr ); Vulkan.GraphicsCommandPool = VK_NULL_HANDLE; } if( Vulkan.GraphicsPipeline != VK_NULL_HANDLE ) { vkDestroyPipeline( GetDevice(), Vulkan.GraphicsPipeline, nullptr ); Vulkan.GraphicsPipeline = VK_NULL_HANDLE; } if( Vulkan.RenderPass != VK_NULL_HANDLE ) { vkDestroyRenderPass( GetDevice(), Vulkan.RenderPass, nullptr ); Vulkan.RenderPass = VK_NULL_HANDLE; } for( size_t i = 0; i < Vulkan.Framebuffers.size(); ++i ) { if( Vulkan.Framebuffers[i] != VK_NULL_HANDLE ) { vkDestroyFramebuffer( GetDevice(), Vulkan.Framebuffers[i], nullptr ); Vulkan.Framebuffers[i] = VK_NULL_HANDLE; } } Vulkan.Framebuffers.clear(); } }
VKRenderPass::~VKRenderPass() { VKRenderer* renderer = VKRenderer::RendererInstance; //Free input descriptor sets vkFreeDescriptorSets(m_device, m_descriptorPool, static_cast<uint32_t>(m_inputTargetDescriptorSets.size()), m_inputTargetDescriptorSets.data()); //Destroy framebuffer images for (size_t i = 0; i < m_colorImages.size(); i++) { Image_vk image = m_colorImages[i]; vkDestroyImageView(m_device, image.view, nullptr); vkDestroyImage(m_device, image.image, nullptr); vkFreeMemory(m_device, image.memory, nullptr); } //Destroy depth image vkDestroyImageView(m_device, m_depthImage.view, nullptr); vkDestroyImage(m_device, m_depthImage.image, nullptr); vkFreeMemory(m_device, m_depthImage.memory, nullptr); //Free instance texel buffers if(m_instanceBlock.buffer != VK_NULL_HANDLE) DeleteUniformBuffer(m_device, m_instanceBlock); //Destroy framebuffer vkDestroyFramebuffer(m_device, m_framebuffer, nullptr); //Destroy the render pass vkDestroyRenderPass(m_device, m_renderPass, nullptr); }
VulkanExampleBase::~VulkanExampleBase() { // Clean up Vulkan resources swapChain.cleanup(); if (descriptorPool != VK_NULL_HANDLE) { vkDestroyDescriptorPool(device, descriptorPool, nullptr); } if (setupCmdBuffer != VK_NULL_HANDLE) { vkFreeCommandBuffers(device, cmdPool, 1, &setupCmdBuffer); } destroyCommandBuffers(); vkDestroyRenderPass(device, renderPass, nullptr); for (uint32_t i = 0; i < frameBuffers.size(); i++) { vkDestroyFramebuffer(device, frameBuffers[i], nullptr); } for (auto& shaderModule : shaderModules) { vkDestroyShaderModule(device, shaderModule, nullptr); } vkDestroyImageView(device, depthStencil.view, nullptr); vkDestroyImage(device, depthStencil.image, nullptr); vkFreeMemory(device, depthStencil.mem, nullptr); vkDestroyPipelineCache(device, pipelineCache, nullptr); if (textureLoader) { delete textureLoader; } vkDestroyCommandPool(device, cmdPool, nullptr); vkDestroySemaphore(device, semaphores.presentComplete, nullptr); vkDestroySemaphore(device, semaphores.renderComplete, nullptr); vkDestroyDevice(device, nullptr); if (enableValidation) { vkDebug::freeDebugCallback(instance); } vkDestroyInstance(instance, nullptr); #if defined(__linux) #if defined(__ANDROID__) // todo : android cleanup (if required) #else xcb_destroy_window(connection, window); xcb_disconnect(connection); #endif #endif }
void vkeGameRendererDynamic::releaseFramebuffer(){ VulkanDC *dc = VulkanDC::Get(); VulkanDC::Device *device = dc->getDefaultDevice(); device->waitIdle(); vkDestroyImageView(device->getVKDevice(), m_depth_attachment.view, NULL); vkDestroyImageView(device->getVKDevice(), m_color_attachment.view, NULL); vkDestroyImageView(device->getVKDevice(), m_resolve_attachment[0].view, NULL); vkDestroyImageView(device->getVKDevice(), m_resolve_attachment[1].view, NULL); m_depth_attachment.view = NULL; m_color_attachment.view = NULL; m_resolve_attachment[0].view = NULL; m_resolve_attachment[1].view = NULL; vkDestroyImage(device->getVKDevice(), m_depth_attachment.image, NULL); vkDestroyImage(device->getVKDevice(), m_color_attachment.image, NULL); vkDestroyImage(device->getVKDevice(), m_resolve_attachment[0].image, NULL); vkDestroyImage(device->getVKDevice(), m_resolve_attachment[1].image, NULL); m_depth_attachment.image = NULL; m_color_attachment.image = NULL; m_resolve_attachment[0].image = NULL; m_resolve_attachment[1].image = NULL; vkFreeMemory(device->getVKDevice(), m_depth_attachment.memory, NULL); vkFreeMemory(device->getVKDevice(), m_color_attachment.memory, NULL); vkFreeMemory(device->getVKDevice(), m_resolve_attachment[0].memory, NULL); vkFreeMemory(device->getVKDevice(), m_resolve_attachment[1].memory, NULL); m_depth_attachment.memory = NULL; m_color_attachment.memory = NULL; m_resolve_attachment[0].memory = NULL; m_resolve_attachment[1].memory = NULL; vkDestroyFramebuffer(device->getVKDevice(), m_framebuffers[0], NULL); vkDestroyFramebuffer(device->getVKDevice(), m_framebuffers[1], NULL); m_framebuffers[0] = NULL; m_framebuffers[1] = NULL; }
void SwapChain::DestroySwapChainImages() { for (const auto& it : m_swap_chain_images) { // Images themselves are cleaned up by the swap chain object vkDestroyFramebuffer(g_vulkan_context->GetDevice(), it.framebuffer, nullptr); } m_swap_chain_images.clear(); }
void _agpu_framebuffer::lostReferences() { vkDestroyFramebuffer(device->device, framebuffer, nullptr); vkDestroyRenderPass(device->device, renderPass, nullptr); for (auto view : attachmentViews) vkDestroyImageView(device->device, view, nullptr); for (auto texture : attachmentTextures) texture->release(); }
void destroy_swapchain_framebuffers(const VulkanBackend& backend, PresentationInfo& presentInfo) { for (size_t i = 0; i < presentInfo.framebuffers.size(); i++) { vkDestroyImageView(backend.device, presentInfo.imageViews[i], nullptr); vkDestroyFramebuffer(backend.device, presentInfo.framebuffers[i], nullptr); } presentInfo.imageViews.clear(); presentInfo.framebuffers.clear(); }
FrameBuffer::~FrameBuffer() { if (VK_NULL_HANDLE == m_FrameBuffer) { return; } vkDestroyFramebuffer(GetRawDevice(), m_FrameBuffer, nullptr); m_FrameBuffer = VK_NULL_HANDLE; VKRHI_METHOD_TRACE }
void VulkanWindow::FinalizeFrameBuffers() { for ( auto& i : mVkFramebuffers ) { if ( i != VK_NULL_HANDLE ) { vkDestroyFramebuffer ( mVulkanRenderer.GetDevice(), i, nullptr ); i = VK_NULL_HANDLE; } } }
~VulkanExample() { vkDestroyPipeline(device, pipelines.skybox, nullptr); vkDestroyPipeline(device, pipelines.reflect, nullptr); vkDestroyPipeline(device, pipelines.composition, nullptr); vkDestroyPipeline(device, pipelines.bloom[0], nullptr); vkDestroyPipeline(device, pipelines.bloom[1], nullptr); vkDestroyPipelineLayout(device, pipelineLayouts.models, nullptr); vkDestroyPipelineLayout(device, pipelineLayouts.composition, nullptr); vkDestroyPipelineLayout(device, pipelineLayouts.bloomFilter, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.models, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.composition, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.bloomFilter, nullptr); vkDestroySemaphore(device, offscreen.semaphore, nullptr); vkDestroyRenderPass(device, offscreen.renderPass, nullptr); vkDestroyRenderPass(device, filterPass.renderPass, nullptr); vkDestroyFramebuffer(device, offscreen.frameBuffer, nullptr); vkDestroyFramebuffer(device, filterPass.frameBuffer, nullptr); vkDestroySampler(device, offscreen.sampler, nullptr); vkDestroySampler(device, filterPass.sampler, nullptr); offscreen.depth.destroy(device); offscreen.color[0].destroy(device); offscreen.color[1].destroy(device); filterPass.color[0].destroy(device); for (auto& model : models.objects) { model.destroy(); } models.skybox.destroy(); uniformBuffers.matrices.destroy(); uniformBuffers.params.destroy(); textures.envmap.destroy(); }
void VKFramebuffer::cleanup() { VulkanCore * instance = VulkanCore::getInstance(); VkDevice device = instance->getDevice(); if(mFramebuffer != 0) { vkDestroyFramebuffer(device, mFramebuffer, nullptr); mFramebuffer = 0; } if(mCascadeFramebuffer.size() != 0) { for(int i = 0; i < mCascadeFramebuffer.size(); i++) vkDestroyFramebuffer(device, mCascadeFramebuffer[i], nullptr); mCascadeFramebuffer.clear(); } if(mRenderpass != 0) { vkDestroyRenderPass(device, mRenderpass, nullptr); mRenderpass = 0; } }
void VulkanExampleBase::windowResize() { if (!prepared) { return; } prepared = false; // Recreate swap chain width = destWidth; height = destHeight; createSetupCommandBuffer(); setupSwapChain(); // Recreate the frame buffers vkDestroyImageView(device, depthStencil.view, nullptr); vkDestroyImage(device, depthStencil.image, nullptr); vkFreeMemory(device, depthStencil.mem, nullptr); setupDepthStencil(); for (uint32_t i = 0; i < frameBuffers.size(); i++) { vkDestroyFramebuffer(device, frameBuffers[i], nullptr); } setupFrameBuffer(); flushSetupCommandBuffer(); // Command buffers need to be recreated as they may store // references to the recreated frame buffer destroyCommandBuffers(); createCommandBuffers(); buildCommandBuffers(); vkQueueWaitIdle(queue); vkDeviceWaitIdle(device); // Notify derived class windowResized(); viewChanged(); prepared = true; }
~VulkanExample() { // Clean up used Vulkan resources // Note : Inherited destructor cleans up resources stored in base class // Texture target textureLoader->destroyTexture(offScreenFrameBuf.textureTarget); // Frame buffer // Color attachment vkDestroyImageView(device, offScreenFrameBuf.color.view, nullptr); vkDestroyImage(device, offScreenFrameBuf.color.image, nullptr); vkFreeMemory(device, offScreenFrameBuf.color.mem, nullptr); // Depth attachment vkDestroyImageView(device, offScreenFrameBuf.depth.view, nullptr); vkDestroyImage(device, offScreenFrameBuf.depth.image, nullptr); vkFreeMemory(device, offScreenFrameBuf.depth.mem, nullptr); vkDestroyFramebuffer(device, offScreenFrameBuf.frameBuffer, nullptr); vkDestroyPipeline(device, pipelines.quad, nullptr); vkDestroyPipeline(device, pipelines.offscreen, nullptr); vkDestroyPipelineLayout(device, pipelineLayouts.quad, nullptr); vkDestroyPipelineLayout(device, pipelineLayouts.offscreen, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); // Meshes vkMeshLoader::freeMeshBufferResources(device, &meshes.scene); vkMeshLoader::freeMeshBufferResources(device, &meshes.quad); // Uniform buffers vkTools::destroyUniformData(device, &uniformDataVS); vkTools::destroyUniformData(device, &uniformDataOffscreenVS); vkFreeCommandBuffers(device, cmdPool, 1, &offScreenCmdBuffer); }
~VulkanExample() { // Clean up used Vulkan resources // Note : Inherited destructor cleans up resources stored in base class // Frame buffer // Color attachment vkDestroyImageView(device, offscreenPass.color.view, nullptr); vkDestroyImage(device, offscreenPass.color.image, nullptr); vkFreeMemory(device, offscreenPass.color.mem, nullptr); // Depth attachment vkDestroyImageView(device, offscreenPass.depth.view, nullptr); vkDestroyImage(device, offscreenPass.depth.image, nullptr); vkFreeMemory(device, offscreenPass.depth.mem, nullptr); vkDestroyRenderPass(device, offscreenPass.renderPass, nullptr); vkDestroySampler(device, offscreenPass.sampler, nullptr); vkDestroyFramebuffer(device, offscreenPass.frameBuffer, nullptr); vkDestroyPipeline(device, pipelines.radialBlur, nullptr); vkDestroyPipeline(device, pipelines.phongPass, nullptr); vkDestroyPipeline(device, pipelines.colorPass, nullptr); vkDestroyPipeline(device, pipelines.offscreenDisplay, nullptr); vkDestroyPipelineLayout(device, pipelineLayouts.radialBlur, nullptr); vkDestroyPipelineLayout(device, pipelineLayouts.scene, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.scene, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.radialBlur, nullptr); models.example.destroy(); uniformBuffers.scene.destroy(); uniformBuffers.blurParams.destroy(); textures.gradient.destroy(); }
TextureConverter::~TextureConverter() { for (const auto& it : m_palette_conversion_shaders) { if (it != VK_NULL_HANDLE) vkDestroyShaderModule(g_vulkan_context->GetDevice(), it, nullptr); } if (m_texel_buffer_view_r8_uint != VK_NULL_HANDLE) vkDestroyBufferView(g_vulkan_context->GetDevice(), m_texel_buffer_view_r8_uint, nullptr); if (m_texel_buffer_view_r16_uint != VK_NULL_HANDLE) vkDestroyBufferView(g_vulkan_context->GetDevice(), m_texel_buffer_view_r16_uint, nullptr); if (m_texel_buffer_view_r32g32_uint != VK_NULL_HANDLE) vkDestroyBufferView(g_vulkan_context->GetDevice(), m_texel_buffer_view_r32g32_uint, nullptr); if (m_texel_buffer_view_rgba8_unorm != VK_NULL_HANDLE) vkDestroyBufferView(g_vulkan_context->GetDevice(), m_texel_buffer_view_rgba8_unorm, nullptr); if (m_encoding_render_pass != VK_NULL_HANDLE) vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_encoding_render_pass, nullptr); if (m_encoding_render_framebuffer != VK_NULL_HANDLE) vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_encoding_render_framebuffer, nullptr); for (auto& it : m_encoding_shaders) vkDestroyShaderModule(g_vulkan_context->GetDevice(), it.second, nullptr); for (const auto& it : m_decoding_pipelines) { if (it.second.compute_shader != VK_NULL_HANDLE) vkDestroyShaderModule(g_vulkan_context->GetDevice(), it.second.compute_shader, nullptr); } if (m_rgb_to_yuyv_shader != VK_NULL_HANDLE) vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_rgb_to_yuyv_shader, nullptr); if (m_yuyv_to_rgb_shader != VK_NULL_HANDLE) vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_yuyv_to_rgb_shader, nullptr); }
VulkanBase::~VulkanBase() { swapChain.cleanup(); vkDestroyDescriptorPool(device, descriptorPool, nullptr); if (setupCmdBuffer != VK_NULL_HANDLE) vkFreeCommandBuffers(device, cmdPool, 1, &setupCmdBuffer); destroyCommandBuffers(); vkDestroyRenderPass(device, renderPass, nullptr); for (uint32_t i = 0; i < frameBuffers.size(); i++) vkDestroyFramebuffer(device, frameBuffers[i], nullptr); for (auto& shaderModule : shaderModules) vkDestroyShaderModule(device, shaderModule, nullptr); vkDestroyImageView(device, depthStencil.view, nullptr); vkDestroyImage(device, depthStencil.image, nullptr); vkFreeMemory(device, depthStencil.mem, nullptr); vkDestroyPipelineCache(device, pipelineCache, nullptr); if (textureLoader) delete textureLoader; vkDestroyCommandPool(device, cmdPool, nullptr); vkDestroySemaphore(device, semaphores.presentComplete, nullptr); vkDestroySemaphore(device, semaphores.renderComplete, nullptr); vkDestroyDevice(device, nullptr); if (enableValidation) vkDebug::freeDebugCallback(instance); vkDestroyInstance(instance, nullptr); }
void CommandBufferManager::DeferFramebufferDestruction(VkFramebuffer object) { FrameResources& resources = m_frame_resources[m_current_frame]; resources.cleanup_resources.push_back( [object]() { vkDestroyFramebuffer(g_vulkan_context->GetDevice(), object, nullptr); }); }
int main(void) { VkInstance instance; { const char debug_ext[] = "VK_EXT_debug_report"; const char* extensions[] = {debug_ext,}; const char validation_layer[] = "VK_LAYER_LUNARG_standard_validation"; const char* layers[] = {validation_layer,}; VkInstanceCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pNext = NULL, .flags = 0, .pApplicationInfo = NULL, .enabledLayerCount = NELEMS(layers), .ppEnabledLayerNames = layers, .enabledExtensionCount = NELEMS(extensions), .ppEnabledExtensionNames = extensions, }; assert(vkCreateInstance(&create_info, NULL, &instance) == VK_SUCCESS); } VkDebugReportCallbackEXT debug_callback; { VkDebugReportCallbackCreateInfoEXT create_info = { .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT, .pNext = NULL, .flags = (VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT), .pfnCallback = &debugReportCallback, .pUserData = NULL, }; PFN_vkCreateDebugReportCallbackEXT createDebugReportCallback = (PFN_vkCreateDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); assert(createDebugReportCallback); assert(createDebugReportCallback(instance, &create_info, NULL, &debug_callback) == VK_SUCCESS); } VkPhysicalDevice phy_device; { uint32_t num_devices; assert(vkEnumeratePhysicalDevices(instance, &num_devices, NULL) == VK_SUCCESS); assert(num_devices >= 1); VkPhysicalDevice * phy_devices = malloc(sizeof(*phy_devices) * num_devices); assert(vkEnumeratePhysicalDevices(instance, &num_devices, phy_devices) == VK_SUCCESS); phy_device = phy_devices[0]; free(phy_devices); } VkPhysicalDeviceMemoryProperties memory_properties; vkGetPhysicalDeviceMemoryProperties(phy_device, &memory_properties); VkDevice device; { float queue_priorities[] = {1.0}; const char validation_layer[] = "VK_LAYER_LUNARG_standard_validation"; const char* layers[] = {validation_layer,}; uint32_t nqueues; matchingQueues(phy_device, VK_QUEUE_GRAPHICS_BIT, &nqueues, NULL); assert(nqueues > 0); uint32_t * queue_family_idxs = malloc(sizeof(*queue_family_idxs) * nqueues); matchingQueues(phy_device, VK_QUEUE_GRAPHICS_BIT, &nqueues, queue_family_idxs); VkDeviceQueueCreateInfo queue_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .pNext = NULL, .flags = 0, .queueFamilyIndex = queue_family_idxs[0], .queueCount = 1, .pQueuePriorities = queue_priorities, }; free(queue_family_idxs); VkPhysicalDeviceFeatures features = { .geometryShader = VK_TRUE, .fillModeNonSolid = VK_TRUE, }; VkDeviceCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .pNext = NULL, .flags = 0, .queueCreateInfoCount = 1, .pQueueCreateInfos = &queue_info, .enabledLayerCount = NELEMS(layers), .ppEnabledLayerNames = layers, .enabledExtensionCount = 0, .ppEnabledExtensionNames = NULL, .pEnabledFeatures = &features, }; assert(vkCreateDevice(phy_device, &create_info, NULL, &device) == VK_SUCCESS); } VkQueue queue; vkGetDeviceQueue(device, 0, 0, &queue); VkCommandPool cmd_pool; { VkCommandPoolCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .pNext = NULL, .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, .queueFamilyIndex = 0, }; assert(vkCreateCommandPool(device, &create_info, NULL, &cmd_pool) == VK_SUCCESS); } VkRenderPass render_pass; { VkAttachmentDescription attachments[] = {{ .flags = 0, .format = VK_FORMAT_R8G8B8A8_UNORM, .samples = VK_SAMPLE_COUNT_8_BIT, .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, }, { .flags = 0, .format = VK_FORMAT_D16_UNORM, .samples = VK_SAMPLE_COUNT_8_BIT, .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, }, { .flags = 0, .format = VK_FORMAT_R8G8B8A8_UNORM, .samples = VK_SAMPLE_COUNT_1_BIT, .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .storeOp = VK_ATTACHMENT_STORE_OP_STORE, .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, }}; VkAttachmentReference attachment_refs[NELEMS(attachments)] = {{ .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, }, { .attachment = 1, .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, }, { .attachment = 2, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, }}; VkSubpassDescription subpasses[1] = {{ .flags = 0, .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, .inputAttachmentCount = 0, .pInputAttachments = NULL, .colorAttachmentCount = 1, .pColorAttachments = &attachment_refs[0], .pResolveAttachments = &attachment_refs[2], .pDepthStencilAttachment = &attachment_refs[1], .preserveAttachmentCount = 0, .pPreserveAttachments = NULL, }}; VkSubpassDependency dependencies[] = {{ .srcSubpass = 0, .dstSubpass = VK_SUBPASS_EXTERNAL, .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, .dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, .dependencyFlags = 0, }}; VkRenderPassCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, .pNext = NULL, .flags = 0, .attachmentCount = NELEMS(attachments), .pAttachments = attachments, .subpassCount = NELEMS(subpasses), .pSubpasses = subpasses, .dependencyCount = NELEMS(dependencies), .pDependencies = dependencies, }; assert(vkCreateRenderPass(device, &create_info, NULL, &render_pass) == VK_SUCCESS); } VkImage images[3]; VkDeviceMemory image_memories[NELEMS(images)]; VkImageView views[NELEMS(images)]; createFrameImage(memory_properties, device, render_size, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_8_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_ASPECT_COLOR_BIT, &images[0], &image_memories[0], &views[0]); createFrameImage(memory_properties, device, render_size, VK_FORMAT_D16_UNORM, VK_SAMPLE_COUNT_8_BIT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_ASPECT_DEPTH_BIT, &images[1], &image_memories[1], &views[1]); createFrameImage(memory_properties, device, render_size, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_IMAGE_ASPECT_COLOR_BIT, &images[2], &image_memories[2], &views[2]); VkBuffer verts_buffer; VkDeviceMemory verts_memory; createBuffer(memory_properties, device, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, sizeof(verts), verts, &verts_buffer, &verts_memory); VkBuffer index_buffer; VkDeviceMemory index_memory; createBuffer(memory_properties, device, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, sizeof(indices), indices, &index_buffer, &index_memory); VkBuffer image_buffer; VkDeviceMemory image_buffer_memory; createBuffer(memory_properties, device, VK_BUFFER_USAGE_TRANSFER_DST_BIT, render_size.height * render_size.width * 4, NULL, &image_buffer, &image_buffer_memory); VkFramebuffer framebuffer; createFramebuffer(device, render_size, 3, views, render_pass, &framebuffer); VkShaderModule shaders[5]; { char* filenames[NELEMS(shaders)] = {"cube.vert.spv", "cube.geom.spv", "cube.frag.spv", "wireframe.geom.spv", "color.frag.spv"}; for (size_t i = 0; i < NELEMS(shaders); i++){ size_t code_size; uint32_t * code; assert((code_size = loadModule(filenames[i], &code)) != 0); VkShaderModuleCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, .pNext = NULL, .flags = 0, .codeSize = code_size, .pCode = code, }; assert(vkCreateShaderModule(device, &create_info, NULL, &shaders[i]) == VK_SUCCESS); free(code); } } VkPipelineLayout pipeline_layout; { VkPushConstantRange push_range = { .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, .offset = 0, .size = 4, }; VkPipelineLayoutCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = NULL, .flags = 0, .setLayoutCount = 0, .pSetLayouts = NULL, .pushConstantRangeCount = 1, .pPushConstantRanges = &push_range, }; assert(vkCreatePipelineLayout(device, &create_info, NULL, &pipeline_layout) == VK_SUCCESS); } VkPipeline pipelines[2]; { VkPipelineShaderStageCreateInfo stages[3] = {{ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .pNext = NULL, .flags = 0, .stage = VK_SHADER_STAGE_VERTEX_BIT, .module = shaders[0], .pName = "main", .pSpecializationInfo = NULL, },{ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .pNext = NULL, .flags = 0, .stage = VK_SHADER_STAGE_GEOMETRY_BIT, .module = shaders[1], .pName = "main", .pSpecializationInfo = NULL, },{ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .pNext = NULL, .flags = 0, .stage = VK_SHADER_STAGE_FRAGMENT_BIT, .module = shaders[2], .pName = "main", .pSpecializationInfo = NULL, }}; VkVertexInputBindingDescription vtx_binding = { .binding = 0, .stride = sizeof(struct Vertex), .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, }; VkVertexInputAttributeDescription vtx_attr = { .location = 0, .binding = 0, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(struct Vertex, pos), }; VkPipelineVertexInputStateCreateInfo vtx_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .vertexBindingDescriptionCount = 1, .pVertexBindingDescriptions = &vtx_binding, .vertexAttributeDescriptionCount = 1, .pVertexAttributeDescriptions = &vtx_attr, }; VkPipelineInputAssemblyStateCreateInfo ia_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, .primitiveRestartEnable = VK_TRUE, }; VkViewport viewport = { .x = 0, .y = 0, .width = render_size.width, .height = render_size.height, .minDepth = 0.0, .maxDepth = 1.0, }; VkRect2D scissor= { .offset = {.x = 0, .y = 0,}, .extent = render_size, }; VkPipelineViewportStateCreateInfo viewport_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .viewportCount = 1, .pViewports = &viewport, .scissorCount = 1, .pScissors = &scissor, }; VkPipelineRasterizationStateCreateInfo rasterization_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .depthClampEnable = VK_FALSE, .rasterizerDiscardEnable = VK_FALSE, .polygonMode = VK_POLYGON_MODE_FILL, .cullMode = VK_CULL_MODE_NONE, .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, .depthBiasEnable = VK_FALSE, .lineWidth = 1.0, }; VkPipelineMultisampleStateCreateInfo multisample_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .rasterizationSamples = VK_SAMPLE_COUNT_8_BIT, .sampleShadingEnable = VK_FALSE, .minSampleShading = 0.0, .pSampleMask = NULL, .alphaToCoverageEnable = VK_FALSE, .alphaToOneEnable = VK_FALSE, }; VkPipelineDepthStencilStateCreateInfo depth_stencil_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .depthTestEnable = VK_TRUE, .depthWriteEnable = VK_TRUE, .depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL, .depthBoundsTestEnable = VK_FALSE, .stencilTestEnable = VK_FALSE, .front = {}, .back = {}, .minDepthBounds = 0.0, .maxDepthBounds = 1.0, }; VkPipelineColorBlendAttachmentState color_blend_attachment = { .blendEnable = VK_FALSE, .colorWriteMask = ( VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT), }; VkPipelineColorBlendStateCreateInfo color_blend_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, .pNext = NULL, .flags = 0, .logicOpEnable = VK_FALSE, //.logicOp = 0, .attachmentCount = 1, .pAttachments = &color_blend_attachment, .blendConstants = {}, }; VkGraphicsPipelineCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = NULL, .flags = 0, .stageCount = NELEMS(stages), .pStages = stages, .pVertexInputState = &vtx_state, .pInputAssemblyState = &ia_state, .pTessellationState = NULL, .pViewportState = &viewport_state, .pRasterizationState = &rasterization_state, .pMultisampleState = &multisample_state, .pDepthStencilState = &depth_stencil_state, .pColorBlendState = &color_blend_state, .pDynamicState = NULL, .layout = pipeline_layout, .renderPass = render_pass, .subpass = 0, .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = 0, }; assert(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &create_info, NULL, &pipelines[0]) == VK_SUCCESS); stages[1].module = shaders[3]; stages[2].module = shaders[4]; rasterization_state.polygonMode = VK_POLYGON_MODE_LINE; assert(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &create_info, NULL, &pipelines[1]) == VK_SUCCESS); } VkCommandBuffer draw_buffers[2]; { VkCommandBufferAllocateInfo allocate_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .pNext = NULL, .commandPool = cmd_pool, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, .commandBufferCount = NELEMS(draw_buffers), }; assert(vkAllocateCommandBuffers(device, &allocate_info, draw_buffers) == VK_SUCCESS); } { VkCommandBufferBeginInfo begin_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .pNext = NULL, .flags = 0, .pInheritanceInfo = NULL, }; VkClearValue clear_values[] = {{ .color.float32 = {0.0, 0.0, 0.0, 1.0}, }, { .depthStencil = {.depth = 1.0}, }}; VkRenderPassBeginInfo renderpass_begin_info = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .pNext = NULL, .renderPass = render_pass, .framebuffer = framebuffer, .renderArea = { .offset = {.x = 0, .y = 0}, .extent = render_size, }, .clearValueCount = NELEMS(clear_values), .pClearValues = clear_values, }; for (size_t i = 0; i < NELEMS(draw_buffers); i++){ assert(vkBeginCommandBuffer(draw_buffers[i], &begin_info) == VK_SUCCESS); uint32_t persp = i == 0; vkCmdPushConstants(draw_buffers[i], pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(persp), &persp); vkCmdBeginRenderPass(draw_buffers[i], &renderpass_begin_info, VK_SUBPASS_CONTENTS_INLINE); VkDeviceSize offset = 0; vkCmdBindVertexBuffers(draw_buffers[i], 0, 1, &verts_buffer, &offset); vkCmdBindIndexBuffer(draw_buffers[i], index_buffer, 0, VK_INDEX_TYPE_UINT32); for (size_t j = 0; j < NELEMS(pipelines); j++) { vkCmdBindPipeline(draw_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[j]); vkCmdDrawIndexed(draw_buffers[i], 20, 27, 0, 0, 0); } vkCmdEndRenderPass(draw_buffers[i]); } VkBufferImageCopy copy = { .bufferOffset = 0, .bufferRowLength = 0, // Tightly packed .bufferImageHeight = 0, // Tightly packed .imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, .imageOffset = {0, 0, 0}, .imageExtent = {.width = render_size.width, .height = render_size.height, .depth = 1}, }; VkBufferMemoryBarrier transfer_barrier = { .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, .pNext = 0, .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, .dstAccessMask = VK_ACCESS_HOST_READ_BIT, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .buffer = image_buffer, .offset = 0, .size = VK_WHOLE_SIZE, }; for (size_t i = 0; i < NELEMS(draw_buffers); i++){ vkCmdCopyImageToBuffer(draw_buffers[i], images[2], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image_buffer, 1, ©); vkCmdPipelineBarrier(draw_buffers[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 0, NULL, 1, &transfer_barrier, 0, NULL); assert(vkEndCommandBuffer(draw_buffers[i]) == VK_SUCCESS); } } VkFence fence; { VkFenceCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = 0, .flags = 0, }; assert(vkCreateFence(device, &create_info, NULL, &fence) == VK_SUCCESS); } { char * filenames[] = {"cube_persp.tif", "cube_ortho.tif"}; char * image_data; assert(vkMapMemory(device, image_buffer_memory, 0, VK_WHOLE_SIZE, 0, (void **) &image_data) == VK_SUCCESS); VkMappedMemoryRange image_flush = { .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, .pNext = NULL, .memory = image_buffer_memory, .offset = 0, .size = VK_WHOLE_SIZE, }; VkSubmitInfo submit_info = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .pNext = NULL, .waitSemaphoreCount = 0, .pWaitSemaphores = NULL, .pWaitDstStageMask = NULL, .commandBufferCount = 1, .pCommandBuffers = NULL, .signalSemaphoreCount = 0, .pSignalSemaphores = NULL, }; for (size_t i = 0; i < NELEMS(filenames); i++){ submit_info.pCommandBuffers = &draw_buffers[i]; assert(vkResetFences(device, 1, &fence) == VK_SUCCESS); assert(vkQueueSubmit(queue, 1, &submit_info, fence) == VK_SUCCESS); assert(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX) == VK_SUCCESS); assert(vkInvalidateMappedMemoryRanges(device, 1, &image_flush) == VK_SUCCESS); assert(writeTiff(filenames[i], image_data, render_size, nchannels) == 0); } vkUnmapMemory(device, image_buffer_memory); } assert(vkQueueWaitIdle(queue) == VK_SUCCESS); vkDestroyFence(device, fence, NULL); vkDestroyFramebuffer(device, framebuffer, NULL); for (size_t i = 0; i < NELEMS(images); i++){ vkDestroyImage(device, images[i], NULL); vkDestroyImageView(device, views[i], NULL); vkFreeMemory(device, image_memories[i], NULL); } vkDestroyBuffer(device, image_buffer, NULL); vkFreeMemory(device, image_buffer_memory, NULL); vkDestroyBuffer(device, verts_buffer, NULL); vkFreeMemory(device, verts_memory, NULL); vkDestroyBuffer(device, index_buffer, NULL); vkFreeMemory(device, index_memory, NULL); for (size_t i = 0; i < NELEMS(pipelines); i++){ vkDestroyPipeline(device, pipelines[i], NULL); } vkDestroyPipelineLayout(device, pipeline_layout, NULL); for(size_t i = 0; i < NELEMS(shaders); i++) vkDestroyShaderModule(device, shaders[i], NULL); vkDestroyRenderPass(device, render_pass, NULL); vkFreeCommandBuffers(device, cmd_pool, NELEMS(draw_buffers), draw_buffers); vkDestroyCommandPool(device, cmd_pool, NULL); vkDestroyDevice(device, NULL); { PFN_vkDestroyDebugReportCallbackEXT destroyDebugReportCallback = (PFN_vkDestroyDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); assert(destroyDebugReportCallback); destroyDebugReportCallback(instance, debug_callback, NULL); } vkDestroyInstance(instance, NULL); return 0; }
void VulkanDeleteList::PerformDeletes(VkDevice device) { for (auto &cmdPool : cmdPools_) { vkDestroyCommandPool(device, cmdPool, nullptr); } cmdPools_.clear(); for (auto &descPool : descPools_) { vkDestroyDescriptorPool(device, descPool, nullptr); } descPools_.clear(); for (auto &module : modules_) { vkDestroyShaderModule(device, module, nullptr); } modules_.clear(); for (auto &buf : buffers_) { vkDestroyBuffer(device, buf, nullptr); } buffers_.clear(); for (auto &bufView : bufferViews_) { vkDestroyBufferView(device, bufView, nullptr); } bufferViews_.clear(); for (auto &image : images_) { vkDestroyImage(device, image, nullptr); } images_.clear(); for (auto &imageView : imageViews_) { vkDestroyImageView(device, imageView, nullptr); } imageViews_.clear(); for (auto &mem : deviceMemory_) { vkFreeMemory(device, mem, nullptr); } deviceMemory_.clear(); for (auto &sampler : samplers_) { vkDestroySampler(device, sampler, nullptr); } samplers_.clear(); for (auto &pipeline : pipelines_) { vkDestroyPipeline(device, pipeline, nullptr); } pipelines_.clear(); for (auto &pcache : pipelineCaches_) { vkDestroyPipelineCache(device, pcache, nullptr); } pipelineCaches_.clear(); for (auto &renderPass : renderPasses_) { vkDestroyRenderPass(device, renderPass, nullptr); } renderPasses_.clear(); for (auto &framebuffer : framebuffers_) { vkDestroyFramebuffer(device, framebuffer, nullptr); } framebuffers_.clear(); for (auto &pipeLayout : pipelineLayouts_) { vkDestroyPipelineLayout(device, pipeLayout, nullptr); } pipelineLayouts_.clear(); for (auto &descSetLayout : descSetLayouts_) { vkDestroyDescriptorSetLayout(device, descSetLayout, nullptr); } descSetLayouts_.clear(); for (auto &callback : callbacks_) { callback.func(callback.userdata); } callbacks_.clear(); }
//============================================================================== // Vulkan破棄 //============================================================================== void destroyVulkan() { for(auto& frameBuffer : g_frameBuffers) { vkDestroyFramebuffer(g_VulkanDevice, frameBuffer, nullptr); } if(g_depthBufferTexture.view) { vkDestroyImageView(g_VulkanDevice, g_depthBufferTexture.view, nullptr); } if(g_depthBufferTexture.image) { vkDestroyImage(g_VulkanDevice, g_depthBufferTexture.image, nullptr); } if(g_depthBufferTexture.memory) { vkFreeMemory(g_VulkanDevice, g_depthBufferTexture.memory, nullptr); } if(g_commandBuffers.empty() == false) { vkFreeCommandBuffers(g_VulkanDevice, g_VulkanCommandPool, SWAP_CHAIN_COUNT, g_commandBuffers.data()); } if(g_VulkanCommandPool) { vkDestroyCommandPool(g_VulkanDevice, g_VulkanCommandPool, nullptr); } if(g_VulkanSemahoreRenderComplete) { vkDestroySemaphore(g_VulkanDevice, g_VulkanSemahoreRenderComplete, nullptr); } if(g_VulkanFence) { vkDestroyFence(g_VulkanDevice, g_VulkanFence, nullptr); } if(g_VulkanSwapChain) { vkDestroySwapchainKHR(g_VulkanDevice, g_VulkanSwapChain, nullptr); } if(g_VulkanSurface) { vkDestroySurfaceKHR(g_VulkanInstance, g_VulkanSurface, nullptr); } if(g_VulkanDevice) { vkDestroyDevice(g_VulkanDevice, nullptr); } if(g_VulkanInstance) { vkDestroyInstance(g_VulkanInstance, nullptr); } g_frameBuffers.clear(); g_commandBuffers.clear(); g_VulkanSurface = nullptr; g_VulkanSwapChain = nullptr; g_VulkanCommandPool = nullptr; g_VulkanSemahoreRenderComplete = nullptr; g_VulkanFence = nullptr; g_VulkanQueue = nullptr; g_VulkanDevice = nullptr; g_VulkanInstance = nullptr; }
void Renderer::_DeInitFramebuffers() { for (size_t i = 0; i < _window->getSwapchainImageViews().size(); i++) { vkDestroyFramebuffer(_device, _swapchain_framebuffers[i], nullptr); _swapchain_framebuffers[i] = nullptr; } }
/** * Sample using multiple render passes per framebuffer (different x,y extents) * and multiple subpasses per renderpass. */ int sample_main(int argc, char *argv[]) { VkResult U_ASSERT_ONLY res; struct sample_info info = {}; char sample_title[] = "Multi-pass render passes"; const bool depthPresent = true; process_command_line_args(info, argc, argv); init_global_layer_properties(info); init_instance_extension_names(info); init_device_extension_names(info); init_instance(info, sample_title); init_enumerate_device(info); init_window_size(info, 500, 500); init_connection(info); init_window(info); init_swapchain_extension(info); init_device(info); init_command_pool(info); init_command_buffer(info); execute_begin_command_buffer(info); init_device_queue(info); init_swap_chain(info); info.depth.format = VK_FORMAT_D32_SFLOAT_S8_UINT; init_depth_buffer(info); init_uniform_buffer(info); init_descriptor_and_pipeline_layouts(info, false); init_vertex_buffer(info, g_vb_solid_face_colors_Data, sizeof(g_vb_solid_face_colors_Data), sizeof(g_vb_solid_face_colors_Data[0]), false); init_descriptor_pool(info, false); init_descriptor_set(info, false); init_pipeline_cache(info); /* VULKAN_KEY_START */ /** * First renderpass in this sample. * Stenciled rendering: subpass 1 draw to stencil buffer, subpass 2 draw to * color buffer with stencil test */ VkAttachmentDescription attachments[2]; attachments[0].format = info.format; attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; attachments[0].flags = 0; attachments[1].format = info.depth.format; attachments[1].samples = VK_SAMPLE_COUNT_1_BIT; attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; attachments[1].flags = 0; VkAttachmentReference color_reference = {}; color_reference.attachment = 0; color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkAttachmentReference depth_reference = {}; depth_reference.attachment = 1; depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; VkSubpassDescription subpass = {}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.flags = 0; subpass.inputAttachmentCount = 0; subpass.pInputAttachments = NULL; subpass.colorAttachmentCount = 0; subpass.pColorAttachments = NULL; subpass.pResolveAttachments = NULL; subpass.pDepthStencilAttachment = &depth_reference; subpass.preserveAttachmentCount = 0; subpass.pPreserveAttachments = NULL; std::vector<VkSubpassDescription> subpasses; /* first a depthstencil-only subpass */ subpasses.push_back(subpass); subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &color_reference; /* then depthstencil and color */ subpasses.push_back(subpass); /* Set up a dependency between the source and destination subpasses */ VkSubpassDependency dependency = {}; dependency.srcSubpass = 0; dependency.dstSubpass = 1; dependency.dependencyFlags = 0; dependency.srcStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; dependency.dstStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; dependency.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; dependency.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; VkRenderPassCreateInfo rp_info = {}; rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; rp_info.pNext = NULL; rp_info.attachmentCount = 2; rp_info.pAttachments = attachments; rp_info.subpassCount = subpasses.size(); rp_info.pSubpasses = subpasses.data(); rp_info.dependencyCount = 1; rp_info.pDependencies = &dependency; VkRenderPass stencil_render_pass; res = vkCreateRenderPass(info.device, &rp_info, NULL, &stencil_render_pass); assert(!res); /* now that we have the render pass, create framebuffer and pipelines */ info.render_pass = stencil_render_pass; init_framebuffers(info, depthPresent); VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE]; VkPipelineDynamicStateCreateInfo dynamicState = {}; memset(dynamicStateEnables, 0, sizeof dynamicStateEnables); dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dynamicState.pNext = NULL; dynamicState.pDynamicStates = dynamicStateEnables; dynamicState.dynamicStateCount = 0; VkPipelineVertexInputStateCreateInfo vi; vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vi.pNext = NULL; vi.vertexBindingDescriptionCount = 1; vi.pVertexBindingDescriptions = &info.vi_binding; vi.vertexAttributeDescriptionCount = 2; vi.pVertexAttributeDescriptions = info.vi_attribs; VkPipelineInputAssemblyStateCreateInfo ia; ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; ia.pNext = NULL; ia.primitiveRestartEnable = VK_FALSE; ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; VkPipelineRasterizationStateCreateInfo rs; rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rs.pNext = NULL; rs.polygonMode = VK_POLYGON_MODE_FILL; rs.cullMode = VK_CULL_MODE_BACK_BIT; rs.frontFace = VK_FRONT_FACE_CLOCKWISE; rs.depthClampEnable = VK_FALSE; rs.rasterizerDiscardEnable = VK_FALSE; rs.depthBiasEnable = VK_FALSE; rs.depthBiasConstantFactor = 0; rs.depthBiasClamp = 0; rs.depthBiasSlopeFactor = 0; rs.lineWidth = 0; VkPipelineColorBlendStateCreateInfo cb; cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; cb.pNext = NULL; VkPipelineColorBlendAttachmentState att_state[1]; att_state[0].colorWriteMask = 0xf; att_state[0].blendEnable = VK_FALSE; att_state[0].alphaBlendOp = VK_BLEND_OP_ADD; att_state[0].colorBlendOp = VK_BLEND_OP_ADD; att_state[0].srcColorBlendFactor = VK_BLEND_FACTOR_ZERO; att_state[0].dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; att_state[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; att_state[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; cb.attachmentCount = 1; cb.pAttachments = att_state; cb.logicOpEnable = VK_FALSE; cb.logicOp = VK_LOGIC_OP_NO_OP; cb.blendConstants[0] = 1.0f; cb.blendConstants[1] = 1.0f; cb.blendConstants[2] = 1.0f; cb.blendConstants[3] = 1.0f; VkPipelineViewportStateCreateInfo vp = {}; vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; vp.pNext = NULL; vp.viewportCount = NUM_VIEWPORTS; dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT; vp.scissorCount = NUM_SCISSORS; dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR; VkPipelineDepthStencilStateCreateInfo ds; ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; ds.pNext = NULL; ds.depthTestEnable = VK_TRUE; ds.depthWriteEnable = VK_TRUE; ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; ds.depthBoundsTestEnable = VK_FALSE; ds.minDepthBounds = 0; ds.maxDepthBounds = 0; ds.stencilTestEnable = VK_TRUE; ds.back.failOp = VK_STENCIL_OP_REPLACE; ds.back.depthFailOp = VK_STENCIL_OP_REPLACE; ds.back.passOp = VK_STENCIL_OP_REPLACE; ds.back.compareOp = VK_COMPARE_OP_ALWAYS; ds.back.compareMask = 0xff; ds.back.writeMask = 0xff; ds.back.reference = 0x44; ds.front = ds.back; VkPipelineMultisampleStateCreateInfo ms; ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; ms.pNext = NULL; ms.pSampleMask = NULL; ms.rasterizationSamples = NUM_SAMPLES; ms.sampleShadingEnable = VK_FALSE; ms.minSampleShading = 0.0; ms.alphaToCoverageEnable = VK_FALSE; ms.alphaToOneEnable = VK_FALSE; VkGraphicsPipelineCreateInfo pipeline; pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipeline.pNext = NULL; pipeline.layout = info.pipeline_layout; pipeline.basePipelineHandle = VK_NULL_HANDLE; pipeline.basePipelineIndex = 0; pipeline.flags = 0; pipeline.pVertexInputState = &vi; pipeline.pInputAssemblyState = &ia; pipeline.pRasterizationState = &rs; pipeline.pColorBlendState = NULL; pipeline.pTessellationState = NULL; pipeline.pMultisampleState = &ms; pipeline.pDynamicState = &dynamicState; pipeline.pViewportState = &vp; pipeline.pDepthStencilState = &ds; pipeline.pStages = info.shaderStages; pipeline.stageCount = 2; pipeline.renderPass = stencil_render_pass; pipeline.subpass = 0; init_shaders(info, normalVertShaderText, fragShaderText); /* The first pipeline will render in subpass 0 to fill the stencil */ pipeline.subpass = 0; VkPipeline stencil_cube_pipe = VK_NULL_HANDLE; res = vkCreateGraphicsPipelines(info.device, info.pipelineCache, 1, &pipeline, NULL, &stencil_cube_pipe); assert(res == VK_SUCCESS); /* destroy the shaders used for the above pipelin eand replace them with those for the fullscreen fill pass */ destroy_shaders(info); init_shaders(info, fullscreenVertShaderText, fragShaderText); /* the second pipeline will stencil test but not write, using the same * reference */ ds.back.failOp = VK_STENCIL_OP_KEEP; ds.back.depthFailOp = VK_STENCIL_OP_KEEP; ds.back.passOp = VK_STENCIL_OP_KEEP; ds.back.compareOp = VK_COMPARE_OP_EQUAL; ds.front = ds.back; /* don't test depth, only use stencil test */ ds.depthTestEnable = VK_FALSE; /* the second pipeline will be a fullscreen triangle strip, with vertices generated purely from the vertex shader - no inputs needed */ ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; vi.vertexAttributeDescriptionCount = 0; vi.vertexBindingDescriptionCount = 0; /* this pipeline will run in the second subpass */ pipeline.subpass = 1; pipeline.pColorBlendState = &cb; VkPipeline stencil_fullscreen_pipe = VK_NULL_HANDLE; res = vkCreateGraphicsPipelines(info.device, info.pipelineCache, 1, &pipeline, NULL, &stencil_fullscreen_pipe); assert(res == VK_SUCCESS); destroy_shaders(info); info.pipeline = VK_NULL_HANDLE; VkClearValue clear_values[2]; clear_values[0].color.float32[0] = 0.2f; clear_values[0].color.float32[1] = 0.2f; clear_values[0].color.float32[2] = 0.2f; clear_values[0].color.float32[3] = 0.2f; clear_values[1].depthStencil.depth = 1.0f; clear_values[1].depthStencil.stencil = 0; VkSemaphore presentCompleteSemaphore; VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo; presentCompleteSemaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; presentCompleteSemaphoreCreateInfo.pNext = NULL; presentCompleteSemaphoreCreateInfo.flags = 0; res = vkCreateSemaphore(info.device, &presentCompleteSemaphoreCreateInfo, NULL, &presentCompleteSemaphore); assert(res == VK_SUCCESS); // Get the index of the next available swapchain image: res = vkAcquireNextImageKHR(info.device, info.swap_chain, UINT64_MAX, presentCompleteSemaphore, NULL, &info.current_buffer); // TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR // return codes assert(res == VK_SUCCESS); VkRenderPassBeginInfo rp_begin; rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; rp_begin.pNext = NULL; rp_begin.renderPass = stencil_render_pass; rp_begin.framebuffer = info.framebuffers[info.current_buffer]; rp_begin.renderArea.offset.x = 0; rp_begin.renderArea.offset.y = 0; rp_begin.renderArea.extent.width = info.width / 2; rp_begin.renderArea.extent.height = info.height; rp_begin.clearValueCount = 2; rp_begin.pClearValues = clear_values; /* Begin the first render pass. This will render in the left half of the screen. Subpass 0 will render a cube, stencil writing but outputting no color. Subpass 1 will render a fullscreen pass, stencil testing and outputting color only where the cube filled in stencil */ vkCmdBeginRenderPass(info.cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, stencil_cube_pipe); vkCmdBindDescriptorSets(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline_layout, 0, NUM_DESCRIPTOR_SETS, info.desc_set.data(), 0, NULL); const VkDeviceSize offsets[1] = {0}; vkCmdBindVertexBuffers(info.cmd, 0, 1, &info.vertex_buffer.buf, offsets); VkViewport viewport; viewport.height = (float)info.height; viewport.width = (float)info.width / 2; viewport.minDepth = (float)0.0f; viewport.maxDepth = (float)1.0f; viewport.x = 0; viewport.y = 0; vkCmdSetViewport(info.cmd, 0, NUM_VIEWPORTS, &viewport); VkRect2D scissor; scissor.extent.width = info.width / 2; scissor.extent.height = info.height; scissor.offset.x = 0; scissor.offset.y = 0; vkCmdSetScissor(info.cmd, 0, NUM_SCISSORS, &scissor); /* Draw the cube into stencil */ vkCmdDraw(info.cmd, 12 * 3, 1, 0, 0); /* Advance to the next subpass */ vkCmdNextSubpass(info.cmd, VK_SUBPASS_CONTENTS_INLINE); /* Bind the fullscreen pass pipeline */ vkCmdBindPipeline(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, stencil_fullscreen_pipe); vkCmdSetViewport(info.cmd, 0, NUM_VIEWPORTS, &viewport); vkCmdSetScissor(info.cmd, 0, NUM_SCISSORS, &scissor); /* Draw the fullscreen pass */ vkCmdDraw(info.cmd, 4, 1, 0, 0); vkCmdEndRenderPass(info.cmd); /** * Second renderpass in this sample. * Blended rendering, each subpass blends continuously onto the color */ /* note that we reuse a lot of the initialisation strutures from the first render pass, so this represents a 'delta' from that configuration */ /* This time, the first subpass will use color */ subpasses[0].colorAttachmentCount = 1; subpasses[0].pColorAttachments = &color_reference; /* The dependency between the subpasses now includes the color attachment */ dependency.srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; dependency.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; /* Otherwise, the render pass is identical */ VkRenderPass blend_render_pass; res = vkCreateRenderPass(info.device, &rp_info, NULL, &blend_render_pass); assert(!res); pipeline.renderPass = blend_render_pass; /* We must recreate the framebuffers with this renderpass as the two render passes are not compatible. Store the current framebuffers for later deletion */ VkFramebuffer *stencil_framebuffers = info.framebuffers; info.framebuffers = NULL; info.render_pass = blend_render_pass; init_framebuffers(info, depthPresent); /* Now create the pipelines for the second render pass */ /* We are rendering the cube again, configure the vertex inputs */ ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; vi.vertexAttributeDescriptionCount = 2; vi.vertexBindingDescriptionCount = 1; /* The first pipeline will depth write and depth test */ ds.depthWriteEnable = VK_TRUE; ds.depthTestEnable = VK_TRUE; /* We don't want to stencil test */ ds.stencilTestEnable = VK_FALSE; /* This time, both pipelines will blend. the first pipeline uses the blend constant to determine the blend amount */ att_state[0].colorWriteMask = 0xf; att_state[0].blendEnable = VK_TRUE; att_state[0].alphaBlendOp = VK_BLEND_OP_ADD; att_state[0].colorBlendOp = VK_BLEND_OP_ADD; att_state[0].srcColorBlendFactor = VK_BLEND_FACTOR_CONSTANT_ALPHA; att_state[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE; att_state[0].srcColorBlendFactor = VK_BLEND_FACTOR_CONSTANT_ALPHA; att_state[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; cb.blendConstants[0] = 1.0f; cb.blendConstants[1] = 1.0f; cb.blendConstants[2] = 1.0f; cb.blendConstants[3] = 0.3f; init_shaders(info, normalVertShaderText, fragShaderText); /* This is the first subpass's pipeline, to blend a cube onto the color * image */ pipeline.subpass = 0; VkPipeline blend_cube_pipe = VK_NULL_HANDLE; res = vkCreateGraphicsPipelines(info.device, info.pipelineCache, 1, &pipeline, NULL, &blend_cube_pipe); assert(res == VK_SUCCESS); /* Now we will set up the fullscreen pass to render on top. */ destroy_shaders(info); init_shaders(info, fullscreenVertShaderText, fragShaderText); /* the second pipeline will be a fullscreen triangle strip with no inputs */ ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; vi.vertexAttributeDescriptionCount = 0; vi.vertexBindingDescriptionCount = 0; /* We'll use the alpha output from the shader */ att_state[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; att_state[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE; att_state[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; att_state[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; /* This renders in the second subpass */ pipeline.subpass = 1; VkPipeline blend_fullscreen_pipe = VK_NULL_HANDLE; res = vkCreateGraphicsPipelines(info.device, info.pipelineCache, 1, &pipeline, NULL, &blend_fullscreen_pipe); assert(res == VK_SUCCESS); destroy_shaders(info); info.pipeline = VK_NULL_HANDLE; /* Now we are going to render in the right half of the screen */ viewport.x = (float)info.width / 2; scissor.offset.x = info.width / 2; rp_begin.renderArea.offset.x = info.width / 2; /* Use our framebuffer and render pass */ rp_begin.framebuffer = info.framebuffers[info.current_buffer]; rp_begin.renderPass = blend_render_pass; vkCmdBeginRenderPass(info.cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, blend_cube_pipe); vkCmdBindDescriptorSets(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline_layout, 0, NUM_DESCRIPTOR_SETS, info.desc_set.data(), 0, NULL); vkCmdBindVertexBuffers(info.cmd, 0, 1, &info.vertex_buffer.buf, offsets); vkCmdSetViewport(info.cmd, 0, NUM_VIEWPORTS, &viewport); vkCmdSetScissor(info.cmd, 0, NUM_SCISSORS, &scissor); /* Draw the cube blending */ vkCmdDraw(info.cmd, 12 * 3, 1, 0, 0); /* Advance to the next subpass */ vkCmdNextSubpass(info.cmd, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, blend_fullscreen_pipe); vkCmdBindDescriptorSets(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline_layout, 0, NUM_DESCRIPTOR_SETS, info.desc_set.data(), 0, NULL); /* Adjust the viewport to be a square in the centre, just overlapping the * cube */ viewport.x += 25.0f; viewport.y += 150.0f; viewport.width -= 50.0f; viewport.height -= 300.0f; vkCmdSetViewport(info.cmd, 0, NUM_VIEWPORTS, &viewport); vkCmdSetScissor(info.cmd, 0, NUM_SCISSORS, &scissor); vkCmdDraw(info.cmd, 4, 1, 0, 0); /* The second renderpass is complete */ vkCmdEndRenderPass(info.cmd); /* VULKAN_KEY_END */ VkImageMemoryBarrier prePresentBarrier = {}; prePresentBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; prePresentBarrier.pNext = NULL; prePresentBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; prePresentBarrier.dstAccessMask = 0; prePresentBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; prePresentBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; prePresentBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; prePresentBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; prePresentBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; prePresentBarrier.subresourceRange.baseMipLevel = 0; prePresentBarrier.subresourceRange.levelCount = 1; prePresentBarrier.subresourceRange.baseArrayLayer = 0; prePresentBarrier.subresourceRange.layerCount = 1; prePresentBarrier.image = info.buffers[info.current_buffer].image; vkCmdPipelineBarrier(info.cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &prePresentBarrier); res = vkEndCommandBuffer(info.cmd); const VkCommandBuffer cmd_bufs[] = {info.cmd}; VkFenceCreateInfo fenceInfo; VkFence drawFence; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.pNext = NULL; fenceInfo.flags = 0; vkCreateFence(info.device, &fenceInfo, NULL, &drawFence); VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; VkSubmitInfo submit_info[1] = {}; submit_info[0].pNext = NULL; submit_info[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info[0].waitSemaphoreCount = 1; submit_info[0].pWaitSemaphores = &presentCompleteSemaphore; submit_info[0].commandBufferCount = 1; submit_info[0].pCommandBuffers = cmd_bufs; submit_info[0].pWaitDstStageMask = &pipe_stage_flags; submit_info[0].signalSemaphoreCount = 0; submit_info[0].pSignalSemaphores = NULL; /* Queue the command buffer for execution */ res = vkQueueSubmit(info.queue, 1, submit_info, drawFence); assert(res == VK_SUCCESS); /* Now present the image in the window */ VkPresentInfoKHR present; present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; present.pNext = NULL; present.swapchainCount = 1; present.pSwapchains = &info.swap_chain; present.pImageIndices = &info.current_buffer; present.pWaitSemaphores = NULL; present.waitSemaphoreCount = 0; present.pResults = NULL; /* Make sure command buffer is finished before presenting */ do { res = vkWaitForFences(info.device, 1, &drawFence, VK_TRUE, FENCE_TIMEOUT); } while (res == VK_TIMEOUT); assert(res == VK_SUCCESS); res = vkQueuePresentKHR(info.queue, &present); assert(res == VK_SUCCESS); wait_seconds(1); /* VULKAN_KEY_END */ if (info.save_images) write_ppm(info, "drawsubpasses"); for (uint32_t i = 0; i < info.swapchainImageCount; i++) vkDestroyFramebuffer(info.device, stencil_framebuffers[i], NULL); free(stencil_framebuffers); vkDestroyRenderPass(info.device, stencil_render_pass, NULL); vkDestroyRenderPass(info.device, blend_render_pass, NULL); vkDestroyPipeline(info.device, blend_cube_pipe, NULL); vkDestroyPipeline(info.device, blend_fullscreen_pipe, NULL); vkDestroyPipeline(info.device, stencil_cube_pipe, NULL); vkDestroyPipeline(info.device, stencil_fullscreen_pipe, NULL); vkDestroySemaphore(info.device, presentCompleteSemaphore, NULL); vkDestroyFence(info.device, drawFence, NULL); destroy_pipeline_cache(info); destroy_descriptor_pool(info); destroy_vertex_buffer(info); destroy_framebuffers(info); destroy_descriptor_and_pipeline_layouts(info); destroy_uniform_buffer(info); destroy_depth_buffer(info); destroy_swap_chain(info); destroy_command_buffer(info); destroy_command_pool(info); destroy_device(info); destroy_window(info); destroy_instance(info); return 0; }
static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) { VkResult err; VkSwapchainKHR old_swapchain = g_Swapchain; err = vkDeviceWaitIdle(g_Device); check_vk_result(err); // Destroy old Framebuffer: for (uint32_t i = 0; i < g_BackBufferCount; i++) if (g_BackBufferView[i]) vkDestroyImageView(g_Device, g_BackBufferView[i], g_Allocator); for (uint32_t i = 0; i < g_BackBufferCount; i++) if (g_Framebuffer[i]) vkDestroyFramebuffer(g_Device, g_Framebuffer[i], g_Allocator); if (g_RenderPass) vkDestroyRenderPass(g_Device, g_RenderPass, g_Allocator); // Create Swapchain: { VkSwapchainCreateInfoKHR info = {}; info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; info.surface = g_Surface; info.imageFormat = g_SurfaceFormat.format; info.imageColorSpace = g_SurfaceFormat.colorSpace; info.imageArrayLayers = 1; info.imageUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; info.presentMode = g_PresentMode; info.clipped = VK_TRUE; info.oldSwapchain = old_swapchain; VkSurfaceCapabilitiesKHR cap; err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_Gpu, g_Surface, &cap); check_vk_result(err); if (cap.maxImageCount > 0) info.minImageCount = (cap.minImageCount + 2 < cap.maxImageCount) ? (cap.minImageCount + 2) : cap.maxImageCount; else info.minImageCount = cap.minImageCount + 2; if (cap.currentExtent.width == 0xffffffff) { fb_width = w; fb_height = h; info.imageExtent.width = fb_width; info.imageExtent.height = fb_height; } else { fb_width = cap.currentExtent.width; fb_height = cap.currentExtent.height; info.imageExtent.width = fb_width; info.imageExtent.height = fb_height; } err = vkCreateSwapchainKHR(g_Device, &info, g_Allocator, &g_Swapchain); check_vk_result(err); err = vkGetSwapchainImagesKHR(g_Device, g_Swapchain, &g_BackBufferCount, NULL); check_vk_result(err); err = vkGetSwapchainImagesKHR(g_Device, g_Swapchain, &g_BackBufferCount, g_BackBuffer); check_vk_result(err); } if (old_swapchain) vkDestroySwapchainKHR(g_Device, old_swapchain, g_Allocator); // Create the Render Pass: { VkAttachmentDescription attachment = {}; attachment.format = g_SurfaceFormat.format; attachment.samples = VK_SAMPLE_COUNT_1_BIT; attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; VkAttachmentReference color_attachment = {}; color_attachment.attachment = 0; color_attachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkSubpassDescription subpass = {}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &color_attachment; VkRenderPassCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; info.attachmentCount = 1; info.pAttachments = &attachment; info.subpassCount = 1; info.pSubpasses = &subpass; err = vkCreateRenderPass(g_Device, &info, g_Allocator, &g_RenderPass); check_vk_result(err); } // Create The Image Views { VkImageViewCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; info.viewType = VK_IMAGE_VIEW_TYPE_2D; info.format = g_SurfaceFormat.format; info.components.r = VK_COMPONENT_SWIZZLE_R; info.components.g = VK_COMPONENT_SWIZZLE_G; info.components.b = VK_COMPONENT_SWIZZLE_B; info.components.a = VK_COMPONENT_SWIZZLE_A; info.subresourceRange = g_ImageRange; for (uint32_t i = 0; i < g_BackBufferCount; i++) { info.image = g_BackBuffer[i]; err = vkCreateImageView(g_Device, &info, g_Allocator, &g_BackBufferView[i]); check_vk_result(err); } } // Create Framebuffer: { VkImageView attachment[1]; VkFramebufferCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; info.renderPass = g_RenderPass; info.attachmentCount = 1; info.pAttachments = attachment; info.width = fb_width; info.height = fb_height; info.layers = 1; for (uint32_t i = 0; i < g_BackBufferCount; i++) { attachment[0] = g_BackBufferView[i]; err = vkCreateFramebuffer(g_Device, &info, g_Allocator, &g_Framebuffer[i]); check_vk_result(err); } } }
/** * Good ol' main function. */ int main(int argc, char* argv[]) { static int windowWidth = 800; static int windowHeight = 600; static const char * applicationName = "SdlVulkanDemo_03_double_buffering"; static const char * engineName = applicationName; bool boolResult; VkResult result; /* * SDL2 Initialization */ SDL_Window *mySdlWindow; SDL_SysWMinfo mySdlSysWmInfo; boolResult = vkdemos::utils::sdl2Initialization(applicationName, windowWidth, windowHeight, mySdlWindow, mySdlSysWmInfo); assert(boolResult); /* * Vulkan initialization. */ std::vector<const char *> layersNamesToEnable; layersNamesToEnable.push_back("VK_LAYER_LUNARG_standard_validation"); std::vector<const char *> extensionsNamesToEnable; extensionsNamesToEnable.push_back(VK_KHR_SURFACE_EXTENSION_NAME); extensionsNamesToEnable.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); extensionsNamesToEnable.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); // TODO: add support for other windowing systems VkInstance myInstance; boolResult = vkdemos::createVkInstance(layersNamesToEnable, extensionsNamesToEnable, applicationName, engineName, myInstance); assert(boolResult); VkDebugReportCallbackEXT myDebugReportCallback; vkdemos::createDebugReportCallback(myInstance, VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT, vkdemos::debugCallback, myDebugReportCallback ); VkPhysicalDevice myPhysicalDevice; boolResult = vkdemos::chooseVkPhysicalDevice(myInstance, 0, myPhysicalDevice); assert(boolResult); VkSurfaceKHR mySurface; boolResult = vkdemos::createVkSurface(myInstance, mySdlSysWmInfo, mySurface); assert(boolResult); VkDevice myDevice; VkQueue myQueue; uint32_t myQueueFamilyIndex; boolResult = vkdemos::createVkDeviceAndVkQueue(myPhysicalDevice, mySurface, layersNamesToEnable, myDevice, myQueue, myQueueFamilyIndex); assert(boolResult); VkSwapchainKHR mySwapchain; VkFormat mySurfaceFormat; boolResult = vkdemos::createVkSwapchain(myPhysicalDevice, myDevice, mySurface, windowWidth, windowHeight, FRAME_LAG, VK_NULL_HANDLE, mySwapchain, mySurfaceFormat); assert(boolResult); std::vector<VkImage> mySwapchainImagesVector; std::vector<VkImageView> mySwapchainImageViewsVector; boolResult = vkdemos::getSwapchainImagesAndViews(myDevice, mySwapchain, mySurfaceFormat, mySwapchainImagesVector, mySwapchainImageViewsVector); assert(boolResult); VkCommandPool myCommandPool; boolResult = vkdemos::createCommandPool(myDevice, myQueueFamilyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, myCommandPool); assert(boolResult); VkCommandBuffer myCmdBufferInitialization; boolResult = vkdemos::allocateCommandBuffer(myDevice, myCommandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, myCmdBufferInitialization); assert(boolResult); /* * Initializations from Demo 02 (Triangle). */ VkPhysicalDeviceMemoryProperties myMemoryProperties; vkGetPhysicalDeviceMemoryProperties(myPhysicalDevice, &myMemoryProperties); // Create the Depth Buffer's Image and View. const VkFormat myDepthBufferFormat = VK_FORMAT_D16_UNORM; VkImage myDepthImage; VkImageView myDepthImageView; VkDeviceMemory myDepthMemory; boolResult = vkdemos::createAndAllocateImage(myDevice, myMemoryProperties, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0, myDepthBufferFormat, windowWidth, windowHeight, myDepthImage, myDepthMemory, &myDepthImageView, VK_IMAGE_ASPECT_DEPTH_BIT ); assert(boolResult); // Create the renderpass. VkRenderPass myRenderPass; boolResult = demo02CreateRenderPass(myDevice, mySurfaceFormat, myDepthBufferFormat, myRenderPass); assert(boolResult); // Create the Framebuffers, based on the number of swapchain images. std::vector<VkFramebuffer> myFramebuffersVector; myFramebuffersVector.reserve(mySwapchainImageViewsVector.size()); for(const auto view : mySwapchainImageViewsVector) { VkFramebuffer fb; boolResult = vkdemos::utils::createFramebuffer(myDevice, myRenderPass, {view, myDepthImageView}, windowWidth, windowHeight, fb); assert(boolResult); myFramebuffersVector.push_back(fb); } // Create a buffer to use as the vertex buffer. const size_t vertexBufferSize = sizeof(TriangleDemoVertex)*NUM_DEMO_VERTICES; VkBuffer myVertexBuffer; VkDeviceMemory myVertexBufferMemory; boolResult = vkdemos::createAndAllocateBuffer(myDevice, myMemoryProperties, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, vertexBufferSize, myVertexBuffer, myVertexBufferMemory ); assert(boolResult); // Map vertex buffer and insert data { void *mappedBuffer; result = vkMapMemory(myDevice, myVertexBufferMemory, 0, VK_WHOLE_SIZE, 0, &mappedBuffer); assert(result == VK_SUCCESS); memcpy(mappedBuffer, vertices, vertexBufferSize); vkUnmapMemory(myDevice, myVertexBufferMemory); } // Create the pipeline. const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = nullptr, .flags = 0, .setLayoutCount = 0, .pSetLayouts = nullptr, .pushConstantRangeCount = 0, .pPushConstantRanges = nullptr, }; VkPipelineLayout myPipelineLayout; result = vkCreatePipelineLayout(myDevice, &pipelineLayoutCreateInfo, nullptr, &myPipelineLayout); assert(result == VK_SUCCESS); // Create Pipeline. VkPipeline myGraphicsPipeline; boolResult = demo02CreatePipeline(myDevice, myRenderPass, myPipelineLayout, VERTEX_SHADER_FILENAME, FRAGMENT_SHADER_FILENAME, VERTEX_INPUT_BINDING, myGraphicsPipeline); assert(boolResult); /* * In the PerFrameData struct we group all the objects that are used in a single frame, and that * must remain valid for the duration of that frame. * */ PerFrameData perFrameDataVector[FRAME_LAG]; for(int i = 0; i < FRAME_LAG; i++) { boolResult = vkdemos::allocateCommandBuffer(myDevice, myCommandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, perFrameDataVector[i].presentCmdBuffer); assert(boolResult); result = vkdemos::utils::createFence(myDevice, perFrameDataVector[i].presentFence); assert(result == VK_SUCCESS); result = vkdemos::utils::createSemaphore(myDevice, perFrameDataVector[i].imageAcquiredSemaphore); assert(result == VK_SUCCESS); result = vkdemos::utils::createSemaphore(myDevice, perFrameDataVector[i].renderingCompletedSemaphore); assert(result == VK_SUCCESS); perFrameDataVector[i].fenceInitialized = false; } /* * Generation and submission of the initialization commands' command buffer. */ // We fill the initialization command buffer with... the initialization commands. boolResult = demo02FillInitializationCommandBuffer(myCmdBufferInitialization, myDepthImage); assert(boolResult); // We now submit the command buffer to the queue we created before, and we wait // for its completition. VkSubmitInfo submitInfo = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .pNext = nullptr, .waitSemaphoreCount = 0, .pWaitSemaphores = nullptr, .pWaitDstStageMask = nullptr, .commandBufferCount = 1, .pCommandBuffers = &myCmdBufferInitialization, .signalSemaphoreCount = 0, .pSignalSemaphores = nullptr }; result = vkQueueSubmit(myQueue, 1, &submitInfo, VK_NULL_HANDLE); assert(result == VK_SUCCESS); // Wait for the queue to complete its work. result = vkQueueWaitIdle(myQueue); assert(result == VK_SUCCESS); /* * Event loop */ SDL_Event sdlEvent; bool quit = false; // Just some variables for frame statistics long frameNumber = 0; long frameMaxTime = LONG_MIN; long frameMinTime = LONG_MAX; long frameAvgTimeSum = 0; long frameAvgTimeSumSquare = 0; constexpr long FRAMES_PER_STAT = 120; // How many frames to wait before printing frame time statistics. // The main event/render loop. while(!quit) { // Process events for this frame while(SDL_PollEvent(&sdlEvent)) { if (sdlEvent.type == SDL_QUIT) { quit = true; } if (sdlEvent.type == SDL_KEYDOWN && sdlEvent.key.keysym.sym == SDLK_ESCAPE) { quit = true; } } // Rendering code if(!quit) { // Render a single frame auto renderStartTime = std::chrono::high_resolution_clock::now(); quit = !demo03RenderSingleFrame(myDevice, myQueue, mySwapchain, myFramebuffersVector, myRenderPass, myGraphicsPipeline, myVertexBuffer, VERTEX_INPUT_BINDING, perFrameDataVector[frameNumber % FRAME_LAG], windowWidth, windowHeight); auto renderStopTime = std::chrono::high_resolution_clock::now(); // Compute frame time statistics auto elapsedTimeUs = std::chrono::duration_cast<std::chrono::microseconds>(renderStopTime - renderStartTime).count(); frameMaxTime = std::max(frameMaxTime, elapsedTimeUs); frameMinTime = std::min(frameMinTime, elapsedTimeUs); frameAvgTimeSum += elapsedTimeUs; frameAvgTimeSumSquare += elapsedTimeUs*elapsedTimeUs; // Print statistics if necessary if(frameNumber % FRAMES_PER_STAT == 0) { auto average = frameAvgTimeSum/FRAMES_PER_STAT; auto stddev = std::sqrt(frameAvgTimeSumSquare/FRAMES_PER_STAT - average*average); std::cout << "Frame time: average " << std::setw(6) << average << " us, maximum " << std::setw(6) << frameMaxTime << " us, minimum " << std::setw(6) << frameMinTime << " us, stddev " << (long)stddev << " (" << std::fixed << std::setprecision(2) << (stddev/average * 100.0f) << "%)" << std::endl; frameMaxTime = LONG_MIN; frameMinTime = LONG_MAX; frameAvgTimeSum = 0; frameAvgTimeSumSquare = 0; } frameNumber++; } } /* * Deinitialization */ // We wait for pending operations to complete before starting to destroy stuff. result = vkQueueWaitIdle(myQueue); assert(result == VK_SUCCESS); // Destroy the objects in the perFrameDataVector array. for(int i = 0; i < FRAME_LAG; i++) { vkDestroyFence(myDevice, perFrameDataVector[i].presentFence, nullptr); vkDestroySemaphore(myDevice, perFrameDataVector[i].imageAcquiredSemaphore, nullptr); vkDestroySemaphore(myDevice, perFrameDataVector[i].renderingCompletedSemaphore, nullptr); } /* * For more informations on the following commands, refer to Demo 02. */ vkDestroyPipeline(myDevice, myGraphicsPipeline, nullptr); vkDestroyPipelineLayout(myDevice, myPipelineLayout, nullptr); vkDestroyBuffer(myDevice, myVertexBuffer, nullptr); vkFreeMemory(myDevice, myVertexBufferMemory, nullptr); for(auto framebuffer : myFramebuffersVector) vkDestroyFramebuffer(myDevice, framebuffer, nullptr); vkDestroyRenderPass(myDevice, myRenderPass, nullptr); vkDestroyImageView(myDevice, myDepthImageView, nullptr); vkDestroyImage(myDevice, myDepthImage, nullptr); vkFreeMemory(myDevice, myDepthMemory, nullptr); /* * For more informations on the following commands, refer to Demo 01. */ vkDestroyCommandPool(myDevice, myCommandPool, nullptr); for(auto imgView : mySwapchainImageViewsVector) vkDestroyImageView(myDevice, imgView, nullptr); vkDestroySwapchainKHR(myDevice, mySwapchain, nullptr); vkDestroyDevice(myDevice, nullptr); vkDestroySurfaceKHR(myInstance, mySurface, nullptr); vkdemos::destroyDebugReportCallback(myInstance, myDebugReportCallback); vkDestroyInstance(myInstance, nullptr); SDL_DestroyWindow(mySdlWindow); SDL_Quit(); return 0; }