Created
September 6, 2026 18:34
-
-
Save CloudCodingSpace/e0c40d7e346f3548d4a737b59639205d to your computer and use it in GitHub Desktop.
Basic C++ snippet for any app using GLFW 3.x and Vulkan 1.2.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "Application.h" | |
| #include <cassert> | |
| #include <string> | |
| #include <cstring> | |
| #include <algorithm> | |
| #include <vector> | |
| u8* ReadFile(std::string path, u64* size) { | |
| FILE* file = fopen(path.c_str(), "rb"); | |
| assert(file && "Failed to open file!"); | |
| fseek(file, 0, SEEK_END); | |
| *size = ftell(file); | |
| rewind(file); | |
| u8* content = new u8[*size]; | |
| fread(content, sizeof(u8) * *size, 1, file); | |
| fclose(file); | |
| return content; | |
| } | |
| static uint32_t FindMemoryType(VkPhysicalDevice device, uint32_t typeFilter, VkMemoryPropertyFlags properties) { | |
| VkPhysicalDeviceMemoryProperties props = {}; | |
| vkGetPhysicalDeviceMemoryProperties(device, &props); | |
| for (uint32_t i = 0; i < props.memoryTypeCount; i++) | |
| { | |
| if ((typeFilter & (1 << i)) && (props.memoryTypes[i].propertyFlags & properties) == properties) | |
| { | |
| return i; | |
| } | |
| } | |
| assert(false && "Failed to find the suitable memory index!"); | |
| return 0xffffffff; | |
| } | |
| Application::Application(const char* name, int width, int height) : m_Width{ width }, m_Height{ height } | |
| { | |
| // Window | |
| { | |
| assert(glfwInit() && "Failed to initialize glfw!"); | |
| glfwWindowHint(GLFW_VISIBLE, false); | |
| glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); | |
| m_Window = glfwCreateWindow(m_Width, m_Height, name, nullptr, nullptr); | |
| assert(m_Window && "Failed to create the window!"); | |
| } | |
| // Instance | |
| { | |
| u32 extCount = 0; | |
| const char** exts = glfwGetRequiredInstanceExtensions(&extCount); | |
| VkApplicationInfo appInfo = { | |
| .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, | |
| .pApplicationName = name, | |
| .applicationVersion = VK_MAKE_VERSION(1, 0, 0), | |
| .pEngineName = name, | |
| .engineVersion = VK_MAKE_VERSION(1, 0, 0), | |
| .apiVersion = VK_API_VERSION_1_0 | |
| }; | |
| VkInstanceCreateInfo info = { | |
| .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, | |
| .pApplicationInfo = &appInfo, | |
| .enabledExtensionCount = extCount, | |
| .ppEnabledExtensionNames = exts | |
| }; | |
| VK_CHECK(vkCreateInstance(&info, nullptr, &m_Instance)); | |
| } | |
| // Surface | |
| VK_CHECK(glfwCreateWindowSurface(m_Instance, m_Window, nullptr, &m_Surface)); | |
| // Physical device | |
| { | |
| u32 count = 0; | |
| VK_CHECK(vkEnumeratePhysicalDevices(m_Instance, &count, nullptr)); | |
| std::vector<VkPhysicalDevice> devices(count); | |
| VK_CHECK(vkEnumeratePhysicalDevices(m_Instance, &count, devices.data())); | |
| for(auto& device : devices) | |
| { | |
| u32 queueCount = 0; | |
| vkGetPhysicalDeviceQueueFamilyProperties(device, &queueCount, nullptr); | |
| std::vector<VkQueueFamilyProperties> queueProps(queueCount); | |
| vkGetPhysicalDeviceQueueFamilyProperties(device, &queueCount, queueProps.data()); | |
| i32 gIdx = -1, pIdx = -1, cIdx = -1; | |
| for(u32 i = 0; i < queueCount; i++) | |
| { | |
| if(queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) | |
| gIdx = i; | |
| if(queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) | |
| cIdx = i; | |
| VkBool32 present = false; | |
| VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(device, i, m_Surface, &present)); | |
| if(present) | |
| pIdx = i; | |
| VkPhysicalDeviceScalarBlockLayoutFeatures scalarFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES }; | |
| VkPhysicalDeviceFeatures2 features = {}; | |
| features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; | |
| features.pNext = &scalarFeatures; | |
| vkGetPhysicalDeviceFeatures2(device, &features); | |
| if(present && (gIdx != -1) && (pIdx != -1) && (cIdx != -1) && scalarFeatures.scalarBlockLayout) { | |
| m_PhysicalDevice = device; | |
| m_GraphicsQueueIdx = gIdx; | |
| m_PresentQueueIdx = pIdx; | |
| m_ComputeQueueIdx = cIdx; | |
| break; | |
| } | |
| } | |
| } | |
| assert((m_PhysicalDevice != nullptr) && "Failed to find a suitable physical device!"); | |
| vkGetPhysicalDeviceFeatures(m_PhysicalDevice, &m_PhysicalDeviceFeatures); | |
| } | |
| // Device | |
| { | |
| bool extsSupported = false; | |
| std::vector<const char*> exts = { | |
| VK_KHR_SWAPCHAIN_EXTENSION_NAME | |
| }; | |
| // Checking if extensions supported | |
| { | |
| u32 count = 0; | |
| VK_CHECK(vkEnumerateDeviceExtensionProperties(m_PhysicalDevice, nullptr, &count, nullptr)); | |
| std::vector<VkExtensionProperties> props(count); | |
| VK_CHECK(vkEnumerateDeviceExtensionProperties(m_PhysicalDevice, nullptr, &count, props.data())); | |
| for(auto ext : exts) | |
| { | |
| for(auto& prop : props) | |
| { | |
| if(strcmp(prop.extensionName, ext) == 0) | |
| extsSupported = true; | |
| } | |
| } | |
| } | |
| assert(extsSupported && "The device extensions aren't supported!"); | |
| float priority = 1.0f; | |
| i32 indices[3] = { | |
| m_GraphicsQueueIdx, | |
| m_PresentQueueIdx, | |
| m_ComputeQueueIdx | |
| }; | |
| for(i32 i = 0; i < 3; i++) | |
| { | |
| bool exists = false; | |
| for(i32 idx : m_UniqueQueues) | |
| { | |
| if(idx == indices[i]) | |
| exists = true; | |
| } | |
| if(!exists) | |
| m_UniqueQueues.push_back(indices[i]); | |
| } | |
| std::vector<VkDeviceQueueCreateInfo> queueInfos; | |
| for(i32 idx : m_UniqueQueues) | |
| { | |
| VkDeviceQueueCreateInfo info = { | |
| .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, | |
| .queueFamilyIndex = (u32)idx, | |
| .queueCount = 1, | |
| .pQueuePriorities = &priority | |
| }; | |
| queueInfos.push_back(info); | |
| } | |
| VkPhysicalDeviceScalarBlockLayoutFeatures scalarFeatures = {}; | |
| scalarFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES; | |
| scalarFeatures.scalarBlockLayout = VK_TRUE; | |
| VkDeviceCreateInfo info = { | |
| .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, | |
| .pNext = &scalarFeatures, | |
| .queueCreateInfoCount = (u32)queueInfos.size(), | |
| .pQueueCreateInfos = queueInfos.data(), | |
| .enabledExtensionCount = (u32)exts.size(), | |
| .ppEnabledExtensionNames = exts.data(), | |
| .pEnabledFeatures = &m_PhysicalDeviceFeatures | |
| }; | |
| VK_CHECK(vkCreateDevice(m_PhysicalDevice, &info, nullptr, &m_Device)); | |
| vkGetDeviceQueue(m_Device, m_GraphicsQueueIdx, 0, &m_GraphicsQueue); | |
| vkGetDeviceQueue(m_Device, m_PresentQueueIdx, 0, &m_PresentQueue); | |
| vkGetDeviceQueue(m_Device, m_ComputeQueueIdx, 0, &m_ComputeQueue); | |
| } | |
| // Renderpass | |
| { | |
| m_ScCaps = GetScCaps(); | |
| VkAttachmentDescription colorAttachment{}; | |
| colorAttachment.format = m_ScCaps.format.format; | |
| colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | |
| colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; | |
| 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.samples = VK_SAMPLE_COUNT_1_BIT; | |
| VkAttachmentReference colorRef{}; | |
| colorRef.attachment = 0; | |
| colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | |
| VkSubpassDescription subpass{}; | |
| subpass.colorAttachmentCount = 1; | |
| subpass.pColorAttachments = &colorRef; | |
| subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; | |
| VkSubpassDependency dependency{}; | |
| dependency.srcSubpass = VK_SUBPASS_EXTERNAL; | |
| dependency.dstSubpass = 0; | |
| dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; | |
| dependency.srcAccessMask = 0; | |
| dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; | |
| dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; | |
| dependency.dependencyFlags = 0; | |
| VkRenderPassCreateInfo info{}; | |
| info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; | |
| info.attachmentCount = 1; | |
| info.pAttachments = &colorAttachment; | |
| info.subpassCount = 1; | |
| info.pSubpasses = &subpass; | |
| info.dependencyCount = 1; | |
| info.pDependencies = &dependency; | |
| VK_CHECK(vkCreateRenderPass(m_Device, &info, nullptr, &m_Pass)); | |
| } | |
| // Swapchain | |
| CreateSwapchain(); | |
| // Command pool and buffers | |
| { | |
| { | |
| VkCommandPoolCreateInfo info{}; | |
| info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; | |
| info.queueFamilyIndex = m_GraphicsQueueIdx; | |
| info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; | |
| VK_CHECK(vkCreateCommandPool(m_Device, &info, nullptr, &m_GraphicsCmdPool)); | |
| info.queueFamilyIndex = m_ComputeQueueIdx; | |
| VK_CHECK(vkCreateCommandPool(m_Device, &info, nullptr, &m_ComputeCmdPool)); | |
| } | |
| { | |
| for(u32 i = 0; i < FRAMES_IN_FLIGHT; i++) | |
| { | |
| m_GraphicsCmdBuffs[i] = AllocateCommandBuffer(m_GraphicsCmdPool); | |
| m_ComputeCmdBuffs[i] = AllocateCommandBuffer(m_ComputeCmdPool); | |
| } | |
| } | |
| } | |
| // Sync objs | |
| { | |
| VkFenceCreateInfo fenceInfo{}; | |
| fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; | |
| fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; | |
| VkSemaphoreCreateInfo semaInfo{}; | |
| semaInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; | |
| for(u32 i = 0; i < FRAMES_IN_FLIGHT; i++) | |
| { | |
| VK_CHECK(vkCreateFence(m_Device, &fenceInfo, nullptr, &m_InFlightFences[i])); | |
| VK_CHECK(vkCreateSemaphore(m_Device, &semaInfo, nullptr, &m_ImageAvailable[i])); | |
| VK_CHECK(vkCreateSemaphore(m_Device, &semaInfo, nullptr, &m_ComputeFinished[i])); | |
| } | |
| m_RenderFinished.resize(m_ScImages.size()); | |
| for(auto& sema : m_RenderFinished) | |
| { | |
| VK_CHECK(vkCreateSemaphore(m_Device, &semaInfo, nullptr, &sema)); | |
| } | |
| } | |
| // UI descriptor pool | |
| { | |
| VkDescriptorPoolSize pool_sizes[] = | |
| { | |
| { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 10000 }, | |
| }; | |
| VkDescriptorPoolCreateInfo pool_info = {}; | |
| pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; | |
| pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; | |
| pool_info.maxSets = 10000; | |
| pool_info.poolSizeCount = 1; | |
| pool_info.pPoolSizes = pool_sizes; | |
| VK_CHECK(vkCreateDescriptorPool(m_Device, &pool_info, nullptr, &m_UiDescPool)); | |
| } | |
| // ImGui | |
| { | |
| IMGUI_CHECKVERSION(); | |
| ImGui::CreateContext(); | |
| ImGui::StyleColorsDark(); | |
| ImGuiIO& io = ImGui::GetIO(); | |
| io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; | |
| io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; | |
| ImGuiStyle& style = ImGui::GetStyle(); | |
| style.WindowRounding = 12.0f; | |
| style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| style.WindowPadding = ImVec2(0.0f, 0.0f); | |
| style.FrameBorderSize = 3; | |
| style.FramePadding = ImVec2(5, 5); | |
| style.FrameRounding = 6; | |
| style.TabRounding = 6; | |
| style.GrabRounding = 6; | |
| style.PopupRounding = 6; | |
| style.ChildRounding = 6; | |
| style.WindowRounding = 6; | |
| style.ScrollbarRounding = 6; | |
| ImVec4* colors = style.Colors; | |
| colors[ImGuiCol_TextDisabled] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); | |
| colors[ImGuiCol_WindowBg] = ImVec4(0.13f, 0.13f, 0.13f, 1.00f); | |
| colors[ImGuiCol_ChildBg] = ImVec4(0.13f, 0.13f, 0.13f, 0.00f); | |
| colors[ImGuiCol_PopupBg] = ImVec4(0.13f, 0.13f, 0.13f, 0.94f); | |
| colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f); | |
| colors[ImGuiCol_BorderShadow] = ImVec4(0.14f, 0.14f, 0.14f, 0.74f); | |
| colors[ImGuiCol_FrameBg] = ImVec4(0.33f, 0.33f, 0.33f, 0.54f); | |
| colors[ImGuiCol_FrameBgHovered] = ImVec4(0.31f, 0.31f, 0.31f, 0.40f); | |
| colors[ImGuiCol_FrameBgActive] = ImVec4(0.23f, 0.23f, 0.23f, 0.75f); | |
| colors[ImGuiCol_TitleBg] = ImVec4(0.16f, 0.16f, 0.16f, 1.00f); | |
| colors[ImGuiCol_TitleBgActive] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); | |
| colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.12f, 0.12f, 0.12f, 0.51f); | |
| colors[ImGuiCol_MenuBarBg] = ImVec4(0.13f, 0.13f, 0.13f, 1.00f); | |
| colors[ImGuiCol_ScrollbarBg] = ImVec4(0.13f, 0.13f, 0.13f, 0.53f); | |
| colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f); | |
| colors[ImGuiCol_CheckMark] = ImVec4(0.40f, 0.40f, 0.41f, 1.00f); | |
| colors[ImGuiCol_SliderGrab] = ImVec4(0.39f, 0.39f, 0.40f, 1.00f); | |
| colors[ImGuiCol_SliderGrabActive] = ImVec4(0.43f, 0.43f, 0.43f, 1.00f); | |
| colors[ImGuiCol_Button] = ImVec4(0.25f, 0.24f, 0.24f, 0.40f); | |
| colors[ImGuiCol_ButtonHovered] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f); | |
| colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.46f, 0.46f, 1.00f); | |
| colors[ImGuiCol_Header] = ImVec4(0.29f, 0.29f, 0.29f, 0.31f); | |
| colors[ImGuiCol_HeaderHovered] = ImVec4(0.29f, 0.29f, 0.29f, 0.31f); | |
| colors[ImGuiCol_HeaderActive] = ImVec4(0.46f, 0.46f, 0.46f, 1.00f); | |
| colors[ImGuiCol_SeparatorHovered] = ImVec4(0.39f, 0.39f, 0.39f, 0.78f); | |
| colors[ImGuiCol_SeparatorActive] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); | |
| colors[ImGuiCol_ResizeGrip] = ImVec4(0.16f, 0.16f, 0.16f, 0.20f); | |
| colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.20f, 0.20f, 0.20f, 0.67f); | |
| colors[ImGuiCol_ResizeGripActive] = ImVec4(0.27f, 0.28f, 0.28f, 0.95f); | |
| colors[ImGuiCol_TabHovered] = ImVec4(0.27f, 0.27f, 0.27f, 0.80f); | |
| colors[ImGuiCol_Tab] = ImVec4(0.28f, 0.28f, 0.28f, 0.86f); | |
| colors[ImGuiCol_TabSelected] = ImVec4(0.47f, 0.47f, 0.47f, 1.00f); | |
| colors[ImGuiCol_TabSelectedOverline] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f); | |
| colors[ImGuiCol_TabDimmed] = ImVec4(0.18f, 0.19f, 0.21f, 0.97f); | |
| colors[ImGuiCol_TabDimmedSelected] = ImVec4(0.17f, 0.19f, 0.22f, 1.00f); | |
| colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.19f, 0.17f, 0.17f, 1.00f); | |
| colors[ImGuiCol_DockingPreview] = ImVec4(0.20f, 0.29f, 0.41f, 0.70f); | |
| colors[ImGuiCol_TitleBgActive] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f); | |
| io.Fonts->AddFontFromFileTTF("assets/fonts/consolas.ttf", 18.0f, nullptr, nullptr); | |
| ImGui_ImplGlfw_InitForVulkan(m_Window, true); | |
| ImGui_ImplVulkan_InitInfo info{}; | |
| info.Subpass = 0; | |
| info.Allocator = nullptr; | |
| info.ApiVersion = VK_API_VERSION_1_2; | |
| info.DescriptorPool = m_UiDescPool; | |
| info.Device = m_Device; | |
| info.ImageCount = FRAMES_IN_FLIGHT; | |
| info.MinImageCount = FRAMES_IN_FLIGHT; | |
| info.Instance = m_Instance; | |
| info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; | |
| info.PhysicalDevice = m_PhysicalDevice; | |
| info.Queue = m_GraphicsQueue; | |
| info.QueueFamily = m_GraphicsQueueIdx; | |
| info.RenderPass = m_Pass; | |
| ImGui_ImplVulkan_Init(&info); | |
| ImGui_ImplVulkan_CreateFontsTexture(); | |
| } | |
| } | |
| Application::~Application() | |
| { | |
| VK_CHECK(vkDeviceWaitIdle(m_Device)); | |
| ImGui_ImplVulkan_Shutdown(); | |
| ImGui_ImplGlfw_Shutdown(); | |
| ImGui::DestroyContext(); | |
| vkDestroyDescriptorPool(m_Device, m_UiDescPool, nullptr); | |
| for(auto& fence : m_InFlightFences) | |
| vkDestroyFence(m_Device, fence, nullptr); | |
| for(auto& sema : m_ImageAvailable) | |
| vkDestroySemaphore(m_Device, sema, nullptr); | |
| for(auto& sema : m_ComputeFinished) | |
| vkDestroySemaphore(m_Device, sema, nullptr); | |
| for(auto& sema : m_RenderFinished) | |
| vkDestroySemaphore(m_Device, sema, nullptr); | |
| vkDestroyCommandPool(m_Device, m_GraphicsCmdPool, nullptr); | |
| vkDestroyCommandPool(m_Device, m_ComputeCmdPool, nullptr); | |
| for(auto& fb : m_Framebuffers) | |
| vkDestroyFramebuffer(m_Device, fb, nullptr); | |
| for(auto& view : m_ScImageViews) | |
| vkDestroyImageView(m_Device, view, nullptr); | |
| vkDestroySwapchainKHR(m_Device, m_Swapchain, nullptr); | |
| vkDestroyRenderPass(m_Device, m_Pass, nullptr); | |
| vkDestroyDevice(m_Device, nullptr); | |
| vkDestroySurfaceKHR(m_Instance, m_Surface, nullptr); | |
| vkDestroyInstance(m_Instance, nullptr); | |
| glfwDestroyWindow(m_Window); | |
| glfwTerminate(); | |
| } | |
| void Application::Run() | |
| { | |
| glfwShowWindow(m_Window); | |
| while(!glfwWindowShouldClose(m_Window)) | |
| { | |
| glfwGetFramebufferSize(m_Window, &m_Width, &m_Height); | |
| if(!StartFrame()) | |
| continue; | |
| // ImGui | |
| ImGui::ShowDemoWindow(); | |
| EndFrame(); | |
| if(glfwGetKey(m_Window, GLFW_KEY_ESCAPE) == GLFW_PRESS) | |
| break; | |
| glfwPollEvents(); | |
| } | |
| } | |
| bool Application::StartFrame() | |
| { | |
| VK_CHECK(vkWaitForFences(m_Device, 1, &m_InFlightFences[m_FrameIdx], true, UINT64_MAX)); | |
| VkResult result = vkAcquireNextImageKHR(m_Device, m_Swapchain, UINT64_MAX, m_ImageAvailable[m_FrameIdx], nullptr, &m_ImageIdx); | |
| if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) | |
| { | |
| Resize(); | |
| m_FrameIdx = (m_FrameIdx + 1) % FRAMES_IN_FLIGHT; | |
| return false; | |
| } | |
| else | |
| { | |
| VK_CHECK(result); | |
| } | |
| VK_CHECK(vkResetFences(m_Device, 1, &m_InFlightFences[m_FrameIdx])); | |
| VK_CHECK(vkResetCommandBuffer(m_GraphicsCmdBuffs[m_FrameIdx], 0)); | |
| VK_CHECK(vkResetCommandBuffer(m_ComputeCmdBuffs[m_FrameIdx], 0)); | |
| BeginCommandBuffer(m_GraphicsCmdBuffs[m_FrameIdx], VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); | |
| BeginCommandBuffer(m_ComputeCmdBuffs[m_FrameIdx], VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); | |
| VkClearValue clearColor = {}; | |
| clearColor.color = {0.1f, 0.1f, 0.1f, 1.0f}; | |
| VkRenderPassBeginInfo rpInfo{}; | |
| rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; | |
| rpInfo.clearValueCount = 1; | |
| rpInfo.pClearValues = &clearColor; | |
| rpInfo.renderArea.offset = {0, 0}; | |
| rpInfo.renderArea.extent = m_ScCaps.extent; | |
| rpInfo.renderPass = m_Pass; | |
| rpInfo.framebuffer = m_Framebuffers[m_ImageIdx]; | |
| vkCmdBeginRenderPass(m_GraphicsCmdBuffs[m_FrameIdx], &rpInfo, VK_SUBPASS_CONTENTS_INLINE); | |
| ImGui_ImplVulkan_NewFrame(); | |
| ImGui_ImplGlfw_NewFrame(); | |
| ImGui::NewFrame(); | |
| ImGui::DockSpaceOverViewport(ImGui::GetID("Dockspace"), ImGui::GetMainViewport()); | |
| return true; | |
| } | |
| void Application::EndFrame() | |
| { | |
| ImGui::EndFrame(); | |
| ImGui::Render(); | |
| ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), m_GraphicsCmdBuffs[m_FrameIdx], nullptr); | |
| ImGui::UpdatePlatformWindows(); | |
| ImGui::RenderPlatformWindowsDefault(); | |
| vkCmdEndRenderPass(m_GraphicsCmdBuffs[m_FrameIdx]); | |
| VK_CHECK(vkEndCommandBuffer(m_GraphicsCmdBuffs[m_FrameIdx])); | |
| VK_CHECK(vkEndCommandBuffer(m_ComputeCmdBuffs[m_FrameIdx])); | |
| VkPipelineStageFlags waitStages[] = { | |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | |
| }; | |
| VkSubmitInfo submitInfo{}; | |
| submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; | |
| submitInfo.commandBufferCount = 1; | |
| submitInfo.pCommandBuffers = &m_ComputeCmdBuffs[m_FrameIdx]; | |
| submitInfo.pWaitDstStageMask = waitStages; | |
| submitInfo.waitSemaphoreCount = 1; | |
| submitInfo.signalSemaphoreCount = 1; | |
| submitInfo.pWaitSemaphores = &m_ImageAvailable[m_FrameIdx]; | |
| submitInfo.pSignalSemaphores = &m_ComputeFinished[m_FrameIdx]; | |
| VK_CHECK(vkQueueSubmit(m_ComputeQueue, 1, &submitInfo, nullptr)); | |
| submitInfo.pCommandBuffers = &m_GraphicsCmdBuffs[m_FrameIdx]; | |
| submitInfo.pWaitSemaphores = &m_ComputeFinished[m_FrameIdx]; | |
| submitInfo.pSignalSemaphores = &m_RenderFinished[m_ImageIdx]; | |
| VK_CHECK(vkQueueSubmit(m_GraphicsQueue, 1, &submitInfo, m_InFlightFences[m_FrameIdx])); | |
| VkPresentInfoKHR presentInfo{}; | |
| presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; | |
| presentInfo.swapchainCount = 1; | |
| presentInfo.pSwapchains = &m_Swapchain; | |
| presentInfo.pImageIndices = &m_ImageIdx; | |
| presentInfo.waitSemaphoreCount = 1; | |
| presentInfo.pWaitSemaphores = &m_RenderFinished[m_ImageIdx]; | |
| VkResult result = vkQueuePresentKHR(m_PresentQueue, &presentInfo); | |
| if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) | |
| { | |
| Resize(); | |
| } | |
| m_FrameIdx = (m_FrameIdx + 1) % FRAMES_IN_FLIGHT; | |
| } | |
| ScCaps Application::GetScCaps() | |
| { | |
| ScCaps caps; | |
| VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_PhysicalDevice, m_Surface, &caps.caps)); | |
| { | |
| caps.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; | |
| u32 count = 0; | |
| VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(m_PhysicalDevice, m_Surface, &count, nullptr)); | |
| std::vector<VkPresentModeKHR> modes(count); | |
| VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(m_PhysicalDevice, m_Surface, &count, modes.data())); | |
| for(auto& mode : modes) | |
| { | |
| if(mode == VK_PRESENT_MODE_MAILBOX_KHR) | |
| { | |
| caps.presentMode = mode; | |
| break; | |
| } | |
| } | |
| } | |
| { | |
| u32 count = 0; | |
| VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(m_PhysicalDevice, m_Surface, &count, nullptr)); | |
| std::vector<VkSurfaceFormatKHR> formats(count); | |
| VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(m_PhysicalDevice, m_Surface, &count, formats.data())); | |
| caps.format = formats[0]; | |
| for(auto& format : formats) | |
| { | |
| if((format.format == VK_FORMAT_R8G8B8A8_UNORM) && (format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)) | |
| { | |
| caps.format = format; | |
| break; | |
| } | |
| } | |
| } | |
| { | |
| if(caps.caps.currentExtent.width != UINT32_MAX) | |
| { | |
| caps.extent = caps.caps.currentExtent; | |
| } | |
| else | |
| { | |
| int width, height; | |
| glfwGetFramebufferSize(m_Window, &width, &height); | |
| caps.extent.width = width; | |
| caps.extent.height = height; | |
| caps.extent.width = CLAMP(caps.extent.width, caps.caps.minImageExtent.width, caps.caps.maxImageExtent.width); | |
| caps.extent.height = CLAMP(caps.extent.height, caps.caps.minImageExtent.height, caps.caps.maxImageExtent.height); | |
| } | |
| } | |
| return caps; | |
| } | |
| void Application::CreateSwapchain() | |
| { | |
| { | |
| u32 imgCount = m_ScCaps.caps.minImageCount + 1; | |
| if(m_ScCaps.caps.maxImageCount > 0 && imgCount > m_ScCaps.caps.maxImageCount) | |
| { | |
| imgCount = m_ScCaps.caps.maxImageCount; | |
| } | |
| VkSwapchainCreateInfoKHR info = { | |
| .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, | |
| .surface = m_Surface, | |
| .minImageCount = imgCount, | |
| .imageFormat = m_ScCaps.format.format, | |
| .imageColorSpace = m_ScCaps.format.colorSpace, | |
| .imageExtent = m_ScCaps.extent, | |
| .imageArrayLayers = 1, | |
| .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, | |
| .preTransform = m_ScCaps.caps.currentTransform, | |
| .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, | |
| .presentMode = m_ScCaps.presentMode, | |
| .clipped = VK_TRUE, | |
| .oldSwapchain = nullptr | |
| }; | |
| std::vector<u32> queues = { | |
| (u32)m_GraphicsQueueIdx, | |
| (u32)m_ComputeQueueIdx, | |
| (u32)m_PresentQueueIdx | |
| }; | |
| std::sort(queues.begin(), queues.end()); | |
| queues.erase(std::unique(queues.begin(), queues.end()), queues.end()); | |
| if(queues.size() == 1) | |
| { | |
| info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; | |
| } | |
| else | |
| { | |
| info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; | |
| info.queueFamilyIndexCount = queues.size(); | |
| info.pQueueFamilyIndices = queues.data(); | |
| } | |
| VK_CHECK(vkCreateSwapchainKHR(m_Device, &info, nullptr, &m_Swapchain)); | |
| } | |
| { | |
| u32 count = 0; | |
| VK_CHECK(vkGetSwapchainImagesKHR(m_Device, m_Swapchain, &count, nullptr)); | |
| m_ScImages.resize(count); | |
| VK_CHECK(vkGetSwapchainImagesKHR(m_Device, m_Swapchain, &count, m_ScImages.data())); | |
| } | |
| { | |
| m_ScImageViews.reserve(m_ScImages.size()); | |
| for(auto& image : m_ScImages) | |
| { | |
| VkImageViewCreateInfo info {}; | |
| info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; | |
| info.format = m_ScCaps.format.format; | |
| info.subresourceRange.levelCount = 1; | |
| info.subresourceRange.layerCount = 1; | |
| info.subresourceRange.baseMipLevel = 0; | |
| info.subresourceRange.baseArrayLayer = 0; | |
| info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | |
| info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; | |
| info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; | |
| info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; | |
| info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; | |
| info.image = image; | |
| info.viewType = VK_IMAGE_VIEW_TYPE_2D; | |
| VkImageView view; | |
| VK_CHECK(vkCreateImageView(m_Device, &info, nullptr, &view)); | |
| m_ScImageViews.push_back(view); | |
| } | |
| } | |
| { | |
| m_Framebuffers.reserve(m_ScImages.size()); | |
| for(auto& view : m_ScImageViews) | |
| { | |
| VkFramebufferCreateInfo info{}; | |
| info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; | |
| info.attachmentCount = 1; | |
| info.pAttachments = &view; | |
| info.renderPass = m_Pass; | |
| info.layers = 1; | |
| info.width = m_ScCaps.extent.width; | |
| info.height = m_ScCaps.extent.height; | |
| VkFramebuffer fb; | |
| VK_CHECK(vkCreateFramebuffer(m_Device, &info, nullptr, &fb)); | |
| m_Framebuffers.push_back(fb); | |
| } | |
| } | |
| } | |
| void Application::Resize() | |
| { | |
| int width = 0, height = 0; | |
| glfwGetFramebufferSize(m_Window, &width, &height); | |
| while(width == 0 || height == 0) | |
| { | |
| glfwGetFramebufferSize(m_Window, &width, &height); | |
| glfwWaitEvents(); | |
| } | |
| VK_CHECK(vkDeviceWaitIdle(m_Device)); | |
| for(auto& fb : m_Framebuffers) | |
| vkDestroyFramebuffer(m_Device, fb, nullptr); | |
| for(auto& view : m_ScImageViews) | |
| vkDestroyImageView(m_Device, view, nullptr); | |
| for(auto& sema : m_RenderFinished) | |
| vkDestroySemaphore(m_Device, sema, nullptr); | |
| for(auto& sema : m_ImageAvailable) | |
| vkDestroySemaphore(m_Device, sema, nullptr); | |
| vkDestroySwapchainKHR(m_Device, m_Swapchain, nullptr); | |
| m_ScImages.clear(); | |
| m_ScImageViews.clear(); | |
| m_Framebuffers.clear(); | |
| m_RenderFinished.clear(); | |
| VkSemaphoreCreateInfo semaInfo{}; | |
| semaInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; | |
| m_ScCaps = GetScCaps(); | |
| CreateSwapchain(); | |
| m_RenderFinished.resize(m_ScImages.size()); | |
| for(auto& sema : m_RenderFinished) | |
| VK_CHECK(vkCreateSemaphore(m_Device, &semaInfo, nullptr, &sema)); | |
| for(auto& sema : m_ImageAvailable) | |
| VK_CHECK(vkCreateSemaphore(m_Device, &semaInfo, nullptr, &sema)); | |
| } | |
| void Application::Camera::Create(Application* app) | |
| { | |
| m_Rt = app; | |
| m_Pos = glm::vec3(0, 0, 3); | |
| m_Front = glm::vec3(0, 0, -1); | |
| m_Up = glm::vec3(0, 1, 0); | |
| m_Right = glm::normalize(glm::cross(m_Up, m_Front)); | |
| m_LastX = (float)m_Rt->m_Width / 2; | |
| m_LastY = (float)m_Rt->m_Height / 2; | |
| if(m_Rt->m_Height == 0) | |
| return; | |
| m_Proj = glm::perspective(glm::radians(m_Fov), m_Rt->m_Width/(float)m_Rt->m_Height, 0.01f, 1000.0f); | |
| m_Proj[1][1] *= -1.0f; | |
| m_View = glm::lookAt(m_Pos, m_Pos + m_Front, m_Up); | |
| } | |
| void Application::Camera::Update(float dt) | |
| { | |
| GLFWwindow* window = m_Rt->m_Window; | |
| bool moved = false; | |
| { | |
| if(glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { | |
| m_Pos += m_Front * m_Speed * dt; | |
| moved = true; | |
| } | |
| if(glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { | |
| m_Pos -= m_Front * m_Speed * dt; | |
| moved = true; | |
| } | |
| if(glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { | |
| m_Pos -= m_Right * m_Speed * dt; | |
| moved = true; | |
| } | |
| if(glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) { | |
| m_Pos += m_Right * m_Speed * dt; | |
| moved = true; | |
| } | |
| if(glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) { | |
| m_Pos -= m_Up * m_Speed * dt; | |
| moved = true; | |
| } | |
| if(glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) { | |
| m_Pos += m_Up * m_Speed * dt; | |
| moved = true; | |
| } | |
| } | |
| { | |
| if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) | |
| { | |
| double xpos, ypos; | |
| glfwGetCursorPos(window, &xpos, &ypos); | |
| if(m_FirstMouse) | |
| { | |
| glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); | |
| m_LastX = xpos; | |
| m_LastY = ypos; | |
| m_FirstMouse = false; | |
| } | |
| float dtX = xpos - m_LastX; | |
| float dtY = m_LastY - ypos; | |
| m_LastX = xpos; | |
| m_LastY = ypos; | |
| if(dtX != 0 || dtY != 0) | |
| { | |
| dtX *= m_Sensitivity; | |
| dtY *= m_Sensitivity; | |
| m_Yaw += dtX; | |
| m_Pitch += dtY; | |
| if(m_Pitch > 89.9f) | |
| m_Pitch = 89.9f; | |
| else if(m_Pitch < -89.9f) | |
| m_Pitch = -89.9f; | |
| glm::vec3 front(0.0f); | |
| front.x = glm::cos(glm::radians(m_Yaw)) * glm::cos(glm::radians(m_Pitch)); | |
| front.y = glm::sin(glm::radians(m_Pitch)); | |
| front.z = glm::sin(glm::radians(m_Yaw)) * glm::cos(glm::radians(m_Pitch)); | |
| m_Front = front; | |
| moved = true; | |
| } | |
| } | |
| else if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_RELEASE) | |
| { | |
| glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); | |
| m_FirstMouse = true; | |
| } | |
| } | |
| m_Right = glm::normalize(glm::cross(m_Front, glm::vec3(0, 1, 0))); | |
| m_Up = glm::normalize(glm::cross(m_Right, m_Front)); | |
| if(!moved) | |
| return; | |
| if(m_Rt->m_Height == 0) | |
| return; | |
| m_Proj = glm::perspective(glm::radians(m_Fov), m_Rt->m_Width/(float)m_Rt->m_Height, 0.01f, 1000.0f); | |
| m_Proj[1][1] *= -1.0f; | |
| m_View = glm::lookAt(m_Pos, m_Pos + m_Front, m_Up); | |
| } | |
| void Application::CreateBuffer(Buffer& buffer, const BufferInfo& buffInfo) | |
| { | |
| buffer.info = buffInfo; | |
| { | |
| VkBufferCreateInfo info{}; | |
| info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; | |
| info.queueFamilyIndexCount = m_UniqueQueues.size(); | |
| info.pQueueFamilyIndices = m_UniqueQueues.data(); | |
| info.sharingMode = m_UniqueQueues.size() > 1 ? VK_SHARING_MODE_CONCURRENT : VK_SHARING_MODE_EXCLUSIVE; | |
| info.size = buffInfo.size; | |
| info.usage = buffInfo.usage; | |
| VK_CHECK(vkCreateBuffer(m_Device, &info, nullptr, &buffer.buffer)); | |
| } | |
| { | |
| VkMemoryRequirements req{}; | |
| vkGetBufferMemoryRequirements(m_Device, buffer.buffer, &req); | |
| VkMemoryAllocateInfo info{}; | |
| info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; | |
| info.memoryTypeIndex = FindMemoryType(m_PhysicalDevice, req.memoryTypeBits, buffInfo.memProps); | |
| info.allocationSize = req.size; | |
| VK_CHECK(vkAllocateMemory(m_Device, &info, nullptr, &buffer.memory)); | |
| VK_CHECK(vkBindBufferMemory(m_Device, buffer.buffer, buffer.memory, 0)); | |
| } | |
| if(buffInfo.data) | |
| UploadDataToBuffer(buffer, buffInfo.data); | |
| } | |
| void Application::DestroyBuffer(Buffer& buffer) | |
| { | |
| vkDestroyBuffer(m_Device, buffer.buffer, nullptr); | |
| vkFreeMemory(m_Device, buffer.memory, nullptr); | |
| memset(&buffer, 0, sizeof(buffer)); | |
| } | |
| void Application::UploadDataToBuffer(Buffer& buffer, void* data) | |
| { | |
| if((buffer.info.usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != VK_BUFFER_USAGE_TRANSFER_DST_BIT || !buffer.info.size) | |
| assert(false && "Can't upload to buffer!"); | |
| VkCommandBuffer cmdBuff = AllocateCommandBuffer(m_GraphicsCmdPool); | |
| VkFence fence = CreateFence(); | |
| BufferInfo buffInfo{}; | |
| buffInfo.size = buffer.info.size; | |
| buffInfo.memProps = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | |
| buffInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; | |
| Buffer stagingBuffer{}; | |
| CreateBuffer(stagingBuffer, buffInfo); | |
| void* mappedMem = nullptr; | |
| VK_CHECK(vkMapMemory(m_Device, stagingBuffer.memory, 0, buffInfo.size, 0, &mappedMem)); | |
| memcpy(mappedMem, data, buffInfo.size); | |
| vkUnmapMemory(m_Device, stagingBuffer.memory); | |
| BeginCommandBuffer(cmdBuff, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); | |
| VkBufferCopy region{}; | |
| region.size = buffInfo.size; | |
| region.srcOffset = 0; | |
| region.dstOffset = 0; | |
| vkCmdCopyBuffer(cmdBuff, stagingBuffer.buffer, buffer.buffer, 1, ®ion); | |
| vkEndCommandBuffer(cmdBuff); | |
| VkSubmitInfo info{}; | |
| info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; | |
| info.commandBufferCount = 1; | |
| info.pCommandBuffers = &cmdBuff; | |
| VK_CHECK(vkQueueSubmit(m_GraphicsQueue, 1, &info, fence)); | |
| VK_CHECK(vkWaitForFences(m_Device, 1, &fence, VK_TRUE, UINT64_MAX)); | |
| DestroyBuffer(stagingBuffer); | |
| vkDestroyFence(m_Device, fence, nullptr); | |
| FreeCommandBuffer(cmdBuff, m_GraphicsCmdPool); | |
| } | |
| void Application::CreateImage(Image& image, const ImageInfo& imgInfo) | |
| { | |
| image.info = imgInfo; | |
| { | |
| VkImageCreateInfo info{}; | |
| info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; | |
| info.arrayLayers = 1; | |
| info.extent.width = imgInfo.width; | |
| info.extent.height = imgInfo.height; | |
| info.extent.depth = 1; | |
| info.format = imgInfo.format; | |
| info.imageType = VK_IMAGE_TYPE_2D; | |
| info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | |
| info.mipLevels = 1; | |
| info.queueFamilyIndexCount = m_UniqueQueues.size(); | |
| info.pQueueFamilyIndices = m_UniqueQueues.data(); | |
| info.sharingMode = m_UniqueQueues.size() > 1 ? VK_SHARING_MODE_CONCURRENT : VK_SHARING_MODE_EXCLUSIVE; | |
| info.samples = VK_SAMPLE_COUNT_1_BIT; | |
| info.tiling = VK_IMAGE_TILING_OPTIMAL; | |
| info.usage = imgInfo.usage; | |
| VK_CHECK(vkCreateImage(m_Device, &info, nullptr, &image.image)); | |
| } | |
| { | |
| VkMemoryRequirements memReq{}; | |
| vkGetImageMemoryRequirements(m_Device, image.image, &memReq); | |
| VkMemoryAllocateInfo info{}; | |
| info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; | |
| info.allocationSize = memReq.size; | |
| info.memoryTypeIndex = FindMemoryType(m_PhysicalDevice, memReq.memoryTypeBits, imgInfo.memProps); | |
| VK_CHECK(vkAllocateMemory(m_Device, &info, nullptr, &image.mem)); | |
| VK_CHECK(vkBindImageMemory(m_Device, image.image, image.mem, 0)); | |
| } | |
| { | |
| VkImageViewCreateInfo info{}; | |
| info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; | |
| info.components = { VK_COMPONENT_SWIZZLE_IDENTITY }; | |
| info.format = imgInfo.format; | |
| info.image = image.image; | |
| info.subresourceRange = { | |
| .aspectMask = imgInfo.aspectFlags, | |
| .baseMipLevel = 0, | |
| .levelCount = 1, | |
| .baseArrayLayer = 0, | |
| .layerCount = 1 | |
| }; | |
| info.viewType = VK_IMAGE_VIEW_TYPE_2D; | |
| VK_CHECK(vkCreateImageView(m_Device, &info, nullptr, &image.view)); | |
| } | |
| if(!imgInfo.gpuResource) | |
| return; | |
| { | |
| VkSamplerCreateInfo info{}; | |
| info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; | |
| info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; | |
| info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; | |
| info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; | |
| info.anisotropyEnable = VK_FALSE; | |
| info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; | |
| info.compareEnable = VK_FALSE; | |
| info.compareOp = VK_COMPARE_OP_ALWAYS; | |
| info.minFilter = VK_FILTER_LINEAR; | |
| info.magFilter = VK_FILTER_LINEAR; | |
| info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; | |
| VK_CHECK(vkCreateSampler(m_Device, &info, nullptr, &image.sampler)); | |
| } | |
| } | |
| void Application::DestroyImage(Image& image) | |
| { | |
| vkDestroyImage(m_Device, image.image, nullptr); | |
| vkDestroyImageView(m_Device, image.view, nullptr); | |
| vkFreeMemory(m_Device, image.mem, nullptr); | |
| if(!image.info.gpuResource) | |
| return; | |
| vkDestroySampler(m_Device, image.sampler, nullptr); | |
| memset(&image, 0, sizeof(image)); | |
| } | |
| VkFence Application::CreateFence() { | |
| VkFence fence = nullptr; | |
| VkFenceCreateInfo info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; | |
| VK_CHECK(vkCreateFence(m_Device, &info, nullptr, &fence)); | |
| return fence; | |
| } | |
| VkCommandBuffer Application::AllocateCommandBuffer(VkCommandPool pool) { | |
| VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; | |
| info.commandBufferCount = 1; | |
| info.commandPool = pool; | |
| info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; | |
| VkCommandBuffer buff = nullptr; | |
| VK_CHECK(vkAllocateCommandBuffers(m_Device, &info, &buff)); | |
| return buff; | |
| } | |
| void Application::FreeCommandBuffer(VkCommandBuffer buffer, VkCommandPool pool) { | |
| vkFreeCommandBuffers(m_Device, pool, 1, &buffer); | |
| } | |
| void Application::BeginCommandBuffer(VkCommandBuffer buffer, VkCommandBufferUsageFlagBits usage) { | |
| VkCommandBufferBeginInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; | |
| info.flags = usage; | |
| VK_CHECK(vkBeginCommandBuffer(buffer, &info)); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| #include <vulkan/vulkan.h> | |
| #include <GLFW/glfw3.h> | |
| #include <cstdint> | |
| #include <vector> | |
| #include <glm/glm.hpp> | |
| #include <glm/gtc/matrix_transform.hpp> | |
| #include <imgui/imgui.h> | |
| #include <imgui/imgui_impl_glfw.h> | |
| #include <imgui/imgui_impl_vulkan.h> | |
| #include <vulkan/vk_enum_string_helper.h> | |
| typedef uint32_t u32; | |
| typedef uint64_t u64; | |
| typedef uint8_t u8; | |
| typedef int32_t i32; | |
| #define FRAMES_IN_FLIGHT 2 | |
| #define VK_CHECK(result) do { if(result != VK_SUCCESS) { printf("VkResult: %s (line: %d, file: %s\n", string_VkResult(result), __LINE__, __FILE__); assert(false); } } while(0); | |
| #define CLAMP(value, min, max) ((value < min) ? min : (value > max) ? max : value) | |
| u8* ReadFile(std::string path, u64* size); | |
| struct ScCaps | |
| { | |
| VkExtent2D extent; | |
| VkSurfaceFormatKHR format; | |
| VkPresentModeKHR presentMode; | |
| VkSurfaceCapabilitiesKHR caps; | |
| }; | |
| class Application | |
| { | |
| public: | |
| Application(const char* name, int width, int height); | |
| ~Application(); | |
| virtual void Run(); | |
| protected: | |
| bool StartFrame(); | |
| void EndFrame(); | |
| ScCaps GetScCaps(); | |
| void CreateSwapchain(); | |
| void Resize(); | |
| void ResizeImages(u32 width, u32 height); | |
| protected: | |
| struct ImageInfo { | |
| u32 width, height; | |
| VkFormat format; | |
| bool gpuResource; | |
| VkImageUsageFlags usage; | |
| VkMemoryPropertyFlagBits memProps; | |
| VkImageAspectFlags aspectFlags; | |
| }; | |
| struct Image { | |
| ImageInfo info; | |
| VkImage image; | |
| VkDeviceMemory mem; | |
| VkImageView view; | |
| VkSampler sampler; | |
| }; | |
| struct BufferInfo { | |
| u64 size; | |
| VkMemoryPropertyFlags memProps; | |
| VkBufferUsageFlags usage; | |
| void* data; | |
| }; | |
| struct Buffer { | |
| BufferInfo info; | |
| VkBuffer buffer; | |
| VkDeviceMemory memory; | |
| }; | |
| class Camera | |
| { | |
| public: | |
| void Create(Application* rt); | |
| void Update(float dt); | |
| inline glm::vec3 GetPos() { return m_Pos; } | |
| inline glm::vec3 GetFront() { return m_Front; } | |
| inline glm::vec3 GetUp() { return m_Up; } | |
| inline glm::vec3 GetRight() { return m_Right; } | |
| inline glm::mat4 GetVP() { return m_Proj * m_View; } | |
| private: | |
| glm::mat4 m_Proj = glm::mat4(1.0f); | |
| glm::mat4 m_View = glm::mat4(1.0f); | |
| glm::vec3 m_Front, m_Right, m_Up, m_Pos; | |
| Application* m_Rt = nullptr; | |
| bool m_FirstMouse = true; | |
| float m_LastX = 400, m_LastY = 300, m_Yaw = -90.0f, m_Pitch = 0.0f; | |
| const float m_Fov = 86.0f, m_Sensitivity = 0.05f, m_Speed = 0.5f; | |
| }; | |
| protected: | |
| void CreateBuffer(Buffer& buffer, const BufferInfo& info); | |
| void DestroyBuffer(Buffer& buffer); | |
| void UploadDataToBuffer(Buffer& buffer, void* data); | |
| void CreateImage(Image& image, const ImageInfo& info); | |
| void DestroyImage(Image& image); | |
| VkFence CreateFence(); | |
| VkCommandBuffer AllocateCommandBuffer(VkCommandPool pool); | |
| void FreeCommandBuffer(VkCommandBuffer buffer, VkCommandPool pool); | |
| void BeginCommandBuffer(VkCommandBuffer buffer, VkCommandBufferUsageFlagBits usage); | |
| protected: | |
| struct { | |
| float resolution[2]; | |
| } m_PushConstantData = {}; | |
| GLFWwindow* m_Window = nullptr; | |
| int m_Width, m_Height; | |
| VkInstance m_Instance = nullptr; | |
| VkSurfaceKHR m_Surface = nullptr; | |
| VkPhysicalDevice m_PhysicalDevice = nullptr; | |
| VkPhysicalDeviceFeatures m_PhysicalDeviceFeatures = {}; | |
| VkDevice m_Device = nullptr; | |
| i32 m_GraphicsQueueIdx = -1, m_PresentQueueIdx = -1, m_ComputeQueueIdx = -1; | |
| VkQueue m_GraphicsQueue = nullptr, m_PresentQueue = nullptr, m_ComputeQueue = nullptr; | |
| VkRenderPass m_Pass = nullptr; | |
| std::vector<u32> m_UniqueQueues; | |
| ScCaps m_ScCaps{}; | |
| VkSwapchainKHR m_Swapchain = nullptr; | |
| std::vector<VkImage> m_ScImages; | |
| std::vector<VkImageView> m_ScImageViews; | |
| std::vector<VkFramebuffer> m_Framebuffers; | |
| VkCommandPool m_GraphicsCmdPool = nullptr; | |
| VkCommandPool m_ComputeCmdPool = nullptr; | |
| VkCommandBuffer m_GraphicsCmdBuffs[FRAMES_IN_FLIGHT]; | |
| VkCommandBuffer m_ComputeCmdBuffs[FRAMES_IN_FLIGHT]; | |
| VkFence m_InFlightFences[FRAMES_IN_FLIGHT]; | |
| VkSemaphore m_ImageAvailable[FRAMES_IN_FLIGHT]; | |
| VkSemaphore m_ComputeFinished[FRAMES_IN_FLIGHT]; | |
| std::vector<VkSemaphore> m_RenderFinished; | |
| VkDescriptorPool m_UiDescPool = nullptr; | |
| u32 m_ImageIdx = 0; | |
| u32 m_FrameIdx = 0; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment