diff --git a/TODO.md b/TODO.md index 0f4374f..d48a367 100644 --- a/TODO.md +++ b/TODO.md @@ -2,11 +2,9 @@ ## Hello screen again - - [~] Extract OpenGL - - Rename Passes/Programs as Pipelines - - [~] Minimal Vulkan - - [ ] ImGui - - [ ] Config (yaml) + - [x] Extract OpenGL + - [x] Minimal Vulkan + - [x] ImGui ## Hello other @@ -16,6 +14,11 @@ - [ ] Encryption - [x] Embedded - [x] Standalone + - [ ] VK + - [ ] Pipeline recreate + - [ ] Pipeline cache + - [ ] Reuse descriptors + - [ ] Secondary buffers ## Hello world @@ -26,6 +29,7 @@ - [~] Occlusion Culling - [ ] Iterator ray - [ ] Cast from chunk center + - [ ] Transparency ## Hello darkness @@ -44,14 +48,18 @@ - https://imgur.com/a/bh2iy - https://speciesdevblog.files.wordpress.com/2012/11/biomemap.png - [ ] Galaxy - - [ ] Dynamic SIMD libs - - [ ] FastNoiseSIMD / HastyNoise double precision - [ ] Octree + - SIMD + - [ ] Dynamic SIMD libs + - [ ] FastNoiseSIMD / HastyNoise double precision + - [ ] https://github.com/Auburn/FastNoise2/releases - [ ] Cross plateforme encoding + - [ ] Config (yaml) - [ ] HDR - https://www.youtube.com/watch?v=iikdcAA7cww - Toon shading - Eye adaptation + - [ ] Correct sRGB conversions - [ ] Post processing - https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing - Bloom @@ -59,5 +67,3 @@ - [ ] Deferred - [ ] Cascaded shadow maps - [ ] Ray Tracing - - [ ] Transparency - - [ ] https://github.com/Auburn/FastNoise2/releases diff --git a/include/imgui/impl_vk/imgui_impl_vulkan.opp b/include/imgui/imgui_impl_vulkan.cpp similarity index 94% rename from include/imgui/impl_vk/imgui_impl_vulkan.opp rename to include/imgui/imgui_impl_vulkan.cpp index 465060d..b3685f4 100644 --- a/include/imgui/impl_vk/imgui_impl_vulkan.opp +++ b/include/imgui/imgui_impl_vulkan.cpp @@ -78,7 +78,6 @@ static VkDeviceSize g_BufferMemoryAlignment = 256; static VkPipelineCreateFlags g_PipelineCreateFlags = 0x00; static VkDescriptorSetLayout g_DescriptorSetLayout = VK_NULL_HANDLE; static VkPipelineLayout g_PipelineLayout = VK_NULL_HANDLE; -static VkDescriptorSet g_DescriptorSet = VK_NULL_HANDLE; static VkPipeline g_Pipeline = VK_NULL_HANDLE; // Font data @@ -179,36 +178,38 @@ layout(set=0, binding=0) uniform sampler2D sTexture; layout(location = 0) in struct { vec4 Color; vec2 UV; } In; void main() { - fColor = In.Color * texture(sTexture, In.UV.st); + fColor = pow(In.Color * texture(sTexture, In.UV.st), vec4(vec3(2.2), 1)); } */ static uint32_t __glsl_shader_frag_spv[] = { - 0x07230203,0x00010000,0x00080001,0x0000001e,0x00000000,0x00020011,0x00000001,0x0006000b, - 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, - 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000d,0x00030010, - 0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d, - 0x00000000,0x00040005,0x00000009,0x6c6f4366,0x0000726f,0x00030005,0x0000000b,0x00000000, - 0x00050006,0x0000000b,0x00000000,0x6f6c6f43,0x00000072,0x00040006,0x0000000b,0x00000001, - 0x00005655,0x00030005,0x0000000d,0x00006e49,0x00050005,0x00000016,0x78655473,0x65727574, - 0x00000000,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000d,0x0000001e, - 0x00000000,0x00040047,0x00000016,0x00000022,0x00000000,0x00040047,0x00000016,0x00000021, - 0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006, - 0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,0x00000003, - 0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040017,0x0000000a,0x00000006, - 0x00000002,0x0004001e,0x0000000b,0x00000007,0x0000000a,0x00040020,0x0000000c,0x00000001, - 0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040015,0x0000000e,0x00000020, - 0x00000001,0x0004002b,0x0000000e,0x0000000f,0x00000000,0x00040020,0x00000010,0x00000001, - 0x00000007,0x00090019,0x00000013,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000, - 0x00000001,0x00000000,0x0003001b,0x00000014,0x00000013,0x00040020,0x00000015,0x00000000, - 0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x0004002b,0x0000000e,0x00000018, - 0x00000001,0x00040020,0x00000019,0x00000001,0x0000000a,0x00050036,0x00000002,0x00000004, - 0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041,0x00000010,0x00000011,0x0000000d, - 0x0000000f,0x0004003d,0x00000007,0x00000012,0x00000011,0x0004003d,0x00000014,0x00000017, - 0x00000016,0x00050041,0x00000019,0x0000001a,0x0000000d,0x00000018,0x0004003d,0x0000000a, - 0x0000001b,0x0000001a,0x00050057,0x00000007,0x0000001c,0x00000017,0x0000001b,0x00050085, - 0x00000007,0x0000001d,0x00000012,0x0000001c,0x0003003e,0x00000009,0x0000001d,0x000100fd, - 0x00010038 + 0x07230203,0x00010000,0x00080008,0x00000022,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000d,0x00030010, + 0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d, + 0x00000000,0x00040005,0x00000009,0x6c6f4366,0x0000726f,0x00030005,0x0000000b,0x00000000, + 0x00050006,0x0000000b,0x00000000,0x6f6c6f43,0x00000072,0x00040006,0x0000000b,0x00000001, + 0x00005655,0x00030005,0x0000000d,0x00006e49,0x00050005,0x00000016,0x78655473,0x65727574, + 0x00000000,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000d,0x0000001e, + 0x00000000,0x00040047,0x00000016,0x00000022,0x00000000,0x00040047,0x00000016,0x00000021, + 0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006, + 0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,0x00000003, + 0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040017,0x0000000a,0x00000006, + 0x00000002,0x0004001e,0x0000000b,0x00000007,0x0000000a,0x00040020,0x0000000c,0x00000001, + 0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040015,0x0000000e,0x00000020, + 0x00000001,0x0004002b,0x0000000e,0x0000000f,0x00000000,0x00040020,0x00000010,0x00000001, + 0x00000007,0x00090019,0x00000013,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000, + 0x00000001,0x00000000,0x0003001b,0x00000014,0x00000013,0x00040020,0x00000015,0x00000000, + 0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x0004002b,0x0000000e,0x00000018, + 0x00000001,0x00040020,0x00000019,0x00000001,0x0000000a,0x0004002b,0x00000006,0x0000001e, + 0x400ccccd,0x0004002b,0x00000006,0x0000001f,0x3f800000,0x0007002c,0x00000007,0x00000020, + 0x0000001e,0x0000001e,0x0000001e,0x0000001f,0x00050036,0x00000002,0x00000004,0x00000000, + 0x00000003,0x000200f8,0x00000005,0x00050041,0x00000010,0x00000011,0x0000000d,0x0000000f, + 0x0004003d,0x00000007,0x00000012,0x00000011,0x0004003d,0x00000014,0x00000017,0x00000016, + 0x00050041,0x00000019,0x0000001a,0x0000000d,0x00000018,0x0004003d,0x0000000a,0x0000001b, + 0x0000001a,0x00050057,0x00000007,0x0000001c,0x00000017,0x0000001b,0x00050085,0x00000007, + 0x0000001d,0x00000012,0x0000001c,0x0007000c,0x00000007,0x00000021,0x00000001,0x0000001a, + 0x0000001d,0x00000020,0x0003003e,0x00000009,0x00000021,0x000100fd,0x00010038 }; //----------------------------------------------------------------------------- @@ -268,11 +269,9 @@ static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkCommandBuffer command_buffer, ImGui_ImplVulkanH_FrameRenderBuffers* rb, int fb_width, int fb_height) { - // Bind pipeline and descriptor sets: + // Bind pipeline: { vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_Pipeline); - VkDescriptorSet desc_set[1] = { g_DescriptorSet }; - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_PipelineLayout, 0, 1, desc_set, 0, NULL); } // Bind Vertex And Index Buffer: @@ -384,6 +383,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm // (Because we merged all buffers into a single one, we maintain our own offset into them) int global_vtx_offset = 0; int global_idx_offset = 0; + // Avoid rebinding textures + ImTextureID currentTexture = nullptr; for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; @@ -424,6 +425,13 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm scissor.extent.height = (uint32_t)(clip_rect.w - clip_rect.y); vkCmdSetScissor(command_buffer, 0, 1, &scissor); + // Bind descriptorset with font or user texture + if (pcmd->TextureId != currentTexture) { + VkDescriptorSet desc_set[1] = { (VkDescriptorSet)pcmd->TextureId }; + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_PipelineLayout, 0, 1, desc_set, 0, NULL); + currentTexture = pcmd->TextureId; + } + // Draw vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); } @@ -490,20 +498,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) check_vk_result(err); } - // Update the Descriptor Set: - { - VkDescriptorImageInfo desc_image[1] = {}; - desc_image[0].sampler = g_FontSampler; - desc_image[0].imageView = g_FontView; - desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - VkWriteDescriptorSet write_desc[1] = {}; - write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_desc[0].dstSet = g_DescriptorSet; - write_desc[0].descriptorCount = 1; - write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - write_desc[0].pImageInfo = desc_image; - vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL); - } + VkDescriptorSet font_descriptor_set = (VkDescriptorSet)ImGui_ImplVulkan_AddTexture({g_FontSampler, g_FontView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}); // Create the Upload Buffer: { @@ -581,7 +576,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) } // Store our identifier - io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontImage; + io.Fonts->TexID = (ImTextureID)font_descriptor_set; return true; } @@ -628,12 +623,10 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() if (!g_DescriptorSetLayout) { - VkSampler sampler[1] = {g_FontSampler}; VkDescriptorSetLayoutBinding binding[1] = {}; binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; binding[0].descriptorCount = 1; binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - binding[0].pImmutableSamplers = sampler; VkDescriptorSetLayoutCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; info.bindingCount = 1; @@ -642,17 +635,6 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() check_vk_result(err); } - // Create Descriptor Set: - { - VkDescriptorSetAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = v->DescriptorPool; - alloc_info.descriptorSetCount = 1; - alloc_info.pSetLayouts = &g_DescriptorSetLayout; - err = vkAllocateDescriptorSets(v->Device, &alloc_info, &g_DescriptorSet); - check_vk_result(err); - } - if (!g_PipelineLayout) { // Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix @@ -1224,3 +1206,35 @@ void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVul buffers->Index = 0; buffers->Count = 0; } + +ImTextureID ImGui_ImplVulkan_AddTexture(VkDescriptorImageInfo imageInfo){ + VkResult err; + + //TODO: hash imageInfo and cache + + ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo; + VkDescriptorSet descriptor_set; + // Create Descriptor Set: + { + VkDescriptorSetAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = v->DescriptorPool; + alloc_info.descriptorSetCount = 1; + alloc_info.pSetLayouts = &g_DescriptorSetLayout; + err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set); + check_vk_result(err); + } + + // Update the Descriptor Set: + { + VkWriteDescriptorSet write_desc[1] = {}; + write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_desc[0].dstSet = descriptor_set; + write_desc[0].descriptorCount = 1; + write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write_desc[0].pImageInfo = &imageInfo; + vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL); + } + + return (ImTextureID)descriptor_set; +} diff --git a/include/imgui/impl_vk/imgui_impl_vulkan.h b/include/imgui/imgui_impl_vulkan.h similarity index 98% rename from include/imgui/impl_vk/imgui_impl_vulkan.h rename to include/imgui/imgui_impl_vulkan.h index 0eb772e..41938bc 100644 --- a/include/imgui/impl_vk/imgui_impl_vulkan.h +++ b/include/imgui/imgui_impl_vulkan.h @@ -22,7 +22,7 @@ #pragma once #include "imgui.h" // IMGUI_IMPL_API -#include +#include // Initialization data, for ImGui_ImplVulkan_Init() // [Please zero-clear before use!] @@ -50,7 +50,7 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, V IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer); IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects(); IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated) - +IMGUI_IMPL_API ImTextureID ImGui_ImplVulkan_AddTexture(VkDescriptorImageInfo imageInfo); //------------------------------------------------------------------------- // Internal / Miscellaneous Vulkan Helpers diff --git a/include/imgui/impl_vk/gen_spv.sh b/include/imgui/impl_vk/gen_spv.sh deleted file mode 100644 index e0d7f3b..0000000 --- a/include/imgui/impl_vk/gen_spv.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag -glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert diff --git a/include/imgui/impl_vk/glsl_shader.frag b/include/imgui/impl_vk/glsl_shader.frag deleted file mode 100644 index ce7e6f7..0000000 --- a/include/imgui/impl_vk/glsl_shader.frag +++ /dev/null @@ -1,14 +0,0 @@ -#version 450 core -layout(location = 0) out vec4 fColor; - -layout(set=0, binding=0) uniform sampler2D sTexture; - -layout(location = 0) in struct { - vec4 Color; - vec2 UV; -} In; - -void main() -{ - fColor = In.Color * texture(sTexture, In.UV.st); -} diff --git a/include/imgui/impl_vk/glsl_shader.vert b/include/imgui/impl_vk/glsl_shader.vert deleted file mode 100644 index 9425365..0000000 --- a/include/imgui/impl_vk/glsl_shader.vert +++ /dev/null @@ -1,25 +0,0 @@ -#version 450 core -layout(location = 0) in vec2 aPos; -layout(location = 1) in vec2 aUV; -layout(location = 2) in vec4 aColor; - -layout(push_constant) uniform uPushConstant { - vec2 uScale; - vec2 uTranslate; -} pc; - -out gl_PerVertex { - vec4 gl_Position; -}; - -layout(location = 0) out struct { - vec4 Color; - vec2 UV; -} Out; - -void main() -{ - Out.Color = aColor; - Out.UV = aUV; - gl_Position = vec4(aPos * pc.uScale + pc.uTranslate, 0, 1); -} diff --git a/include/imgui/impl_vk/impl_glfw_gl.opp b/include/imgui/impl_vk/impl_glfw_gl.opp deleted file mode 100644 index 3094330..0000000 --- a/include/imgui/impl_vk/impl_glfw_gl.opp +++ /dev/null @@ -1,214 +0,0 @@ -// dear imgui: standalone example application for GLFW + OpenGL 3, using programmable pipeline -// If you are new to dear imgui, see examples/README.txt and documentation at the top of imgui.cpp. -// (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.) - -#include "imgui.h" -#include "imgui_impl_glfw.h" -#include "imgui_impl_opengl3.h" -#include - -// About Desktop OpenGL function loaders: -// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. -// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). -// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. -#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) -#include // Initialize with gl3wInit() -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) -#include // Initialize with glewInit() -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) -#include // Initialize with gladLoadGL() -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) -#include // Initialize with gladLoadGL(...) or gladLoaderLoadGL() -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) -#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. -#include // Initialize with glbinding::Binding::initialize() -#include -using namespace gl; -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) -#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors. -#include // Initialize with glbinding::initialize() -#include -using namespace gl; -#else -#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM -#endif - -// Include glfw3.h after our OpenGL definitions -#include - -// [Win32] Our example includes a copy of glfw3.lib pre-compiled with VS2010 to maximize ease of testing and compatibility with old VS compilers. -// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma. -// Your own project should not be affected, as you are likely to link with a newer binary of GLFW that is adequate for your version of Visual Studio. -#if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) -#pragma comment(lib, "legacy_stdio_definitions") -#endif - -static void glfw_error_callback(int error, const char* description) -{ - fprintf(stderr, "Glfw Error %d: %s\n", error, description); -} - -int main(int, char**) -{ - // Setup window - glfwSetErrorCallback(glfw_error_callback); - if (!glfwInit()) - return 1; - - // Decide GL+GLSL versions -#if __APPLE__ - // GL 3.2 + GLSL 150 - const char* glsl_version = "#version 150"; - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac -#else - // GL 3.0 + GLSL 130 - const char* glsl_version = "#version 130"; - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only - //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only -#endif - - // Create window with graphics context - GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+OpenGL3 example", NULL, NULL); - if (window == NULL) - return 1; - glfwMakeContextCurrent(window); - glfwSwapInterval(1); // Enable vsync - - // Initialize OpenGL loader -#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) - bool err = gl3wInit() != 0; -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) - bool err = glewInit() != GLEW_OK; -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) - bool err = gladLoadGL() == 0; -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) - bool err = gladLoadGL(glfwGetProcAddress) == 0; // glad2 recommend using the windowing library loader instead of the (optionally) bundled one. -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) - bool err = false; - glbinding::Binding::initialize(); -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) - bool err = false; - glbinding::initialize([](const char* name) { return (glbinding::ProcAddress)glfwGetProcAddress(name); }); -#else - bool err = false; // If you use IMGUI_IMPL_OPENGL_LOADER_CUSTOM, your loader is likely to requires some form of initialization. -#endif - if (err) - { - fprintf(stderr, "Failed to initialize OpenGL loader!\n"); - return 1; - } - - // Setup Dear ImGui context - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); (void)io; - //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls - - // Setup Dear ImGui style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - - // Setup Platform/Renderer bindings - ImGui_ImplGlfw_InitForOpenGL(window, true); - ImGui_ImplOpenGL3_Init(glsl_version); - - // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. - // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.md' for more instructions and details. - // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); - //IM_ASSERT(font != NULL); - - // Our state - bool show_demo_window = true; - bool show_another_window = false; - ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); - - // Main loop - while (!glfwWindowShouldClose(window)) - { - // Poll and handle events (inputs, window resize, etc.) - // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. - // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. - // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. - // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. - glfwPollEvents(); - - // Start the Dear ImGui frame - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). - if (show_demo_window) - ImGui::ShowDemoWindow(&show_demo_window); - - // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window. - { - static float f = 0.0f; - static int counter = 0; - - ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. - - ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) - ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state - ImGui::Checkbox("Another Window", &show_another_window); - - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f - ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color - - if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) - counter++; - ImGui::SameLine(); - ImGui::Text("counter = %d", counter); - - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGui::End(); - } - - // 3. Show another simple window. - if (show_another_window) - { - ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) - ImGui::Text("Hello from another window!"); - if (ImGui::Button("Close Me")) - show_another_window = false; - ImGui::End(); - } - - // Rendering - ImGui::Render(); - int display_w, display_h; - glfwGetFramebufferSize(window, &display_w, &display_h); - glViewport(0, 0, display_w, display_h); - glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); - glClear(GL_COLOR_BUFFER_BIT); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - - glfwSwapBuffers(window); - } - - // Cleanup - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - ImGui::DestroyContext(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/include/imgui/impl_vk/main.opp b/include/imgui/impl_vk/main.opp deleted file mode 100644 index 58d0ab7..0000000 --- a/include/imgui/impl_vk/main.opp +++ /dev/null @@ -1,536 +0,0 @@ -// dear imgui: standalone example application for Glfw + Vulkan -// If you are new to dear imgui, see examples/README.txt and documentation at the top of imgui.cpp. - -// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app. -// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h. -// You will use those if you want to use this rendering back-end in your engine/app. -// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by -// the back-end itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code. -// Read comments in imgui_impl_vulkan.h. - -#include "imgui.h" -#include "imgui_impl_glfw.h" -#include "imgui_impl_vulkan.h" -#include // printf, fprintf -#include // abort -#define GLFW_INCLUDE_NONE -#define GLFW_INCLUDE_VULKAN -#include -#include - -// [Win32] Our example includes a copy of glfw3.lib pre-compiled with VS2010 to maximize ease of testing and compatibility with old VS compilers. -// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma. -// Your own project should not be affected, as you are likely to link with a newer binary of GLFW that is adequate for your version of Visual Studio. -#if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) -#pragma comment(lib, "legacy_stdio_definitions") -#endif - -//#define IMGUI_UNLIMITED_FRAME_RATE -#ifdef _DEBUG -#define IMGUI_VULKAN_DEBUG_REPORT -#endif - -static VkAllocationCallbacks* g_Allocator = NULL; -static VkInstance g_Instance = VK_NULL_HANDLE; -static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE; -static VkDevice g_Device = VK_NULL_HANDLE; -static uint32_t g_QueueFamily = (uint32_t)-1; -static VkQueue g_Queue = VK_NULL_HANDLE; -static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE; -static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; -static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; - -static ImGui_ImplVulkanH_Window g_MainWindowData; -static int g_MinImageCount = 2; -static bool g_SwapChainRebuild = false; -static int g_SwapChainResizeWidth = 0; -static int g_SwapChainResizeHeight = 0; - -static void check_vk_result(VkResult err) -{ - if (err == 0) - return; - fprintf(stderr, "[vulkan] Error: VkResult = %d\n", err); - if (err < 0) - abort(); -} - -#ifdef IMGUI_VULKAN_DEBUG_REPORT -static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) -{ - (void)flags; (void)object; (void)location; (void)messageCode; (void)pUserData; (void)pLayerPrefix; // Unused arguments - fprintf(stderr, "[vulkan] Debug report from ObjectType: %i\nMessage: %s\n\n", objectType, pMessage); - return VK_FALSE; -} -#endif // IMGUI_VULKAN_DEBUG_REPORT - -static void SetupVulkan(const char** extensions, uint32_t extensions_count) -{ - VkResult err; - - // Create Vulkan Instance - { - VkInstanceCreateInfo create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - create_info.enabledExtensionCount = extensions_count; - create_info.ppEnabledExtensionNames = extensions; - -#ifdef IMGUI_VULKAN_DEBUG_REPORT - // Enabling multiple validation layers grouped as LunarG standard validation - const char* layers[] = { "VK_LAYER_LUNARG_standard_validation" }; - create_info.enabledLayerCount = 1; - create_info.ppEnabledLayerNames = layers; - - // Enable debug report extension (we need additional storage, so we duplicate the user array to add our new extension to it) - const char** extensions_ext = (const char**)malloc(sizeof(const char*) * (extensions_count + 1)); - memcpy(extensions_ext, extensions, extensions_count * sizeof(const char*)); - extensions_ext[extensions_count] = "VK_EXT_debug_report"; - create_info.enabledExtensionCount = extensions_count + 1; - create_info.ppEnabledExtensionNames = extensions_ext; - - // Create Vulkan Instance - err = vkCreateInstance(&create_info, g_Allocator, &g_Instance); - check_vk_result(err); - free(extensions_ext); - - // Get the function pointer (required for any extensions) - auto vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkCreateDebugReportCallbackEXT"); - IM_ASSERT(vkCreateDebugReportCallbackEXT != NULL); - - // Setup the debug report callback - VkDebugReportCallbackCreateInfoEXT debug_report_ci = {}; - debug_report_ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; - debug_report_ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; - debug_report_ci.pfnCallback = debug_report; - debug_report_ci.pUserData = NULL; - err = vkCreateDebugReportCallbackEXT(g_Instance, &debug_report_ci, g_Allocator, &g_DebugReport); - check_vk_result(err); -#else - // Create Vulkan Instance without any debug feature - err = vkCreateInstance(&create_info, g_Allocator, &g_Instance); - check_vk_result(err); - IM_UNUSED(g_DebugReport); -#endif - } - - // Select GPU - { - uint32_t gpu_count; - err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, NULL); - check_vk_result(err); - IM_ASSERT(gpu_count > 0); - - VkPhysicalDevice* gpus = (VkPhysicalDevice*)malloc(sizeof(VkPhysicalDevice) * gpu_count); - err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus); - check_vk_result(err); - - // If a number >1 of GPUs got reported, you should find the best fit GPU for your purpose - // e.g. VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU if available, or with the greatest memory available, etc. - // for sake of simplicity we'll just take the first one, assuming it has a graphics queue family. - g_PhysicalDevice = gpus[0]; - free(gpus); - } - - // Select graphics queue family - { - uint32_t count; - vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, NULL); - VkQueueFamilyProperties* queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties) * count); - vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, queues); - for (uint32_t i = 0; i < count; i++) - if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) - { - g_QueueFamily = i; - break; - } - free(queues); - IM_ASSERT(g_QueueFamily != (uint32_t)-1); - } - - // Create Logical Device (with 1 queue) - { - int device_extension_count = 1; - const char* device_extensions[] = { "VK_KHR_swapchain" }; - const float queue_priority[] = { 1.0f }; - VkDeviceQueueCreateInfo queue_info[1] = {}; - queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue_info[0].queueFamilyIndex = g_QueueFamily; - queue_info[0].queueCount = 1; - queue_info[0].pQueuePriorities = queue_priority; - VkDeviceCreateInfo create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - create_info.queueCreateInfoCount = sizeof(queue_info) / sizeof(queue_info[0]); - create_info.pQueueCreateInfos = queue_info; - create_info.enabledExtensionCount = device_extension_count; - create_info.ppEnabledExtensionNames = device_extensions; - err = vkCreateDevice(g_PhysicalDevice, &create_info, g_Allocator, &g_Device); - check_vk_result(err); - vkGetDeviceQueue(g_Device, g_QueueFamily, 0, &g_Queue); - } - - // Create Descriptor Pool - { - VkDescriptorPoolSize pool_sizes[] = - { - { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 }, - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 }, - { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 }, - { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 } - }; - 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 = 1000 * IM_ARRAYSIZE(pool_sizes); - pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); - pool_info.pPoolSizes = pool_sizes; - err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool); - check_vk_result(err); - } -} - -// All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo. -// Your real engine/app may not use them. -static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height) -{ - wd->Surface = surface; - - // Check for WSI support - VkBool32 res; - vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, wd->Surface, &res); - if (res != VK_TRUE) - { - fprintf(stderr, "Error no WSI support on physical device 0\n"); - exit(-1); - } - - // Select Surface Format - const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM }; - const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; - wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_ARRAYSIZE(requestSurfaceImageFormat), requestSurfaceColorSpace); - - // Select Present Mode -#ifdef IMGUI_UNLIMITED_FRAME_RATE - VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR }; -#else - VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_FIFO_KHR }; -#endif - wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(g_PhysicalDevice, wd->Surface, &present_modes[0], IM_ARRAYSIZE(present_modes)); - //printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode); - - // Create SwapChain, RenderPass, Framebuffer, etc. - IM_ASSERT(g_MinImageCount >= 2); - ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount); -} - -static void CleanupVulkan() -{ - vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator); - -#ifdef IMGUI_VULKAN_DEBUG_REPORT - // Remove the debug report callback - auto vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT"); - vkDestroyDebugReportCallbackEXT(g_Instance, g_DebugReport, g_Allocator); -#endif // IMGUI_VULKAN_DEBUG_REPORT - - vkDestroyDevice(g_Device, g_Allocator); - vkDestroyInstance(g_Instance, g_Allocator); -} - -static void CleanupVulkanWindow() -{ - ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator); -} - -static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) -{ - VkResult err; - - VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore; - VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; - err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); - check_vk_result(err); - - ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; - { - err = vkWaitForFences(g_Device, 1, &fd->Fence, VK_TRUE, UINT64_MAX); // wait indefinitely instead of periodically checking - check_vk_result(err); - - err = vkResetFences(g_Device, 1, &fd->Fence); - check_vk_result(err); - } - { - err = vkResetCommandPool(g_Device, fd->CommandPool, 0); - check_vk_result(err); - VkCommandBufferBeginInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - err = vkBeginCommandBuffer(fd->CommandBuffer, &info); - check_vk_result(err); - } - { - VkRenderPassBeginInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - info.renderPass = wd->RenderPass; - info.framebuffer = fd->Framebuffer; - info.renderArea.extent.width = wd->Width; - info.renderArea.extent.height = wd->Height; - info.clearValueCount = 1; - info.pClearValues = &wd->ClearValue; - vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE); - } - - // Record dear imgui primitives into command buffer - ImGui_ImplVulkan_RenderDrawData(draw_data, fd->CommandBuffer); - - // Submit command buffer - vkCmdEndRenderPass(fd->CommandBuffer); - { - VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - VkSubmitInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - info.waitSemaphoreCount = 1; - info.pWaitSemaphores = &image_acquired_semaphore; - info.pWaitDstStageMask = &wait_stage; - info.commandBufferCount = 1; - info.pCommandBuffers = &fd->CommandBuffer; - info.signalSemaphoreCount = 1; - info.pSignalSemaphores = &render_complete_semaphore; - - err = vkEndCommandBuffer(fd->CommandBuffer); - check_vk_result(err); - err = vkQueueSubmit(g_Queue, 1, &info, fd->Fence); - check_vk_result(err); - } -} - -static void FramePresent(ImGui_ImplVulkanH_Window* wd) -{ - VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; - VkPresentInfoKHR info = {}; - info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - info.waitSemaphoreCount = 1; - info.pWaitSemaphores = &render_complete_semaphore; - info.swapchainCount = 1; - info.pSwapchains = &wd->Swapchain; - info.pImageIndices = &wd->FrameIndex; - VkResult err = vkQueuePresentKHR(g_Queue, &info); - check_vk_result(err); - wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->ImageCount; // Now we can use the next set of semaphores -} - -static void glfw_error_callback(int error, const char* description) -{ - fprintf(stderr, "Glfw Error %d: %s\n", error, description); -} - -static void glfw_resize_callback(GLFWwindow*, int w, int h) -{ - g_SwapChainRebuild = true; - g_SwapChainResizeWidth = w; - g_SwapChainResizeHeight = h; -} - -int main(int, char**) -{ - // Setup GLFW window - glfwSetErrorCallback(glfw_error_callback); - if (!glfwInit()) - return 1; - - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+Vulkan example", NULL, NULL); - - // Setup Vulkan - if (!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - uint32_t extensions_count = 0; - const char** extensions = glfwGetRequiredInstanceExtensions(&extensions_count); - SetupVulkan(extensions, extensions_count); - - // Create Window Surface - VkSurfaceKHR surface; - VkResult err = glfwCreateWindowSurface(g_Instance, window, g_Allocator, &surface); - check_vk_result(err); - - // Create Framebuffers - int w, h; - glfwGetFramebufferSize(window, &w, &h); - glfwSetFramebufferSizeCallback(window, glfw_resize_callback); - ImGui_ImplVulkanH_Window* wd = &g_MainWindowData; - SetupVulkanWindow(wd, surface, w, h); - - // Setup Dear ImGui context - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); (void)io; - //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls - - // Setup Dear ImGui style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - - // Setup Platform/Renderer bindings - ImGui_ImplGlfw_InitForVulkan(window, true); - ImGui_ImplVulkan_InitInfo init_info = {}; - init_info.Instance = g_Instance; - init_info.PhysicalDevice = g_PhysicalDevice; - init_info.Device = g_Device; - init_info.QueueFamily = g_QueueFamily; - init_info.Queue = g_Queue; - init_info.PipelineCache = g_PipelineCache; - init_info.DescriptorPool = g_DescriptorPool; - init_info.Allocator = g_Allocator; - init_info.MinImageCount = g_MinImageCount; - init_info.ImageCount = wd->ImageCount; - init_info.CheckVkResultFn = check_vk_result; - ImGui_ImplVulkan_Init(&init_info, wd->RenderPass); - - // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. - // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.md' for more instructions and details. - // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); - //IM_ASSERT(font != NULL); - - // Upload Fonts - { - // Use any command queue - VkCommandPool command_pool = wd->Frames[wd->FrameIndex].CommandPool; - VkCommandBuffer command_buffer = wd->Frames[wd->FrameIndex].CommandBuffer; - - err = vkResetCommandPool(g_Device, command_pool, 0); - check_vk_result(err); - VkCommandBufferBeginInfo begin_info = {}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - err = vkBeginCommandBuffer(command_buffer, &begin_info); - check_vk_result(err); - - ImGui_ImplVulkan_CreateFontsTexture(command_buffer); - - VkSubmitInfo end_info = {}; - end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - end_info.commandBufferCount = 1; - end_info.pCommandBuffers = &command_buffer; - err = vkEndCommandBuffer(command_buffer); - check_vk_result(err); - err = vkQueueSubmit(g_Queue, 1, &end_info, VK_NULL_HANDLE); - check_vk_result(err); - - err = vkDeviceWaitIdle(g_Device); - check_vk_result(err); - ImGui_ImplVulkan_DestroyFontUploadObjects(); - } - - // Our state - bool show_demo_window = true; - bool show_another_window = false; - ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); - - // Main loop - while (!glfwWindowShouldClose(window)) - { - // Poll and handle events (inputs, window resize, etc.) - // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. - // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. - // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. - // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. - glfwPollEvents(); - - // Resize swap chain? - if (g_SwapChainRebuild && g_SwapChainResizeWidth > 0 && g_SwapChainResizeHeight > 0) - { - g_SwapChainRebuild = false; - ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount); - ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData, g_QueueFamily, g_Allocator, g_SwapChainResizeWidth, g_SwapChainResizeHeight, g_MinImageCount); - g_MainWindowData.FrameIndex = 0; - } - - // Start the Dear ImGui frame - ImGui_ImplVulkan_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). - if (show_demo_window) - ImGui::ShowDemoWindow(&show_demo_window); - - // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window. - { - static float f = 0.0f; - static int counter = 0; - - ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. - - ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) - ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state - ImGui::Checkbox("Another Window", &show_another_window); - - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f - ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color - - if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) - counter++; - ImGui::SameLine(); - ImGui::Text("counter = %d", counter); - - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGui::End(); - } - - // 3. Show another simple window. - if (show_another_window) - { - ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) - ImGui::Text("Hello from another window!"); - if (ImGui::Button("Close Me")) - show_another_window = false; - ImGui::End(); - } - - // Rendering - ImGui::Render(); - ImDrawData* draw_data = ImGui::GetDrawData(); - const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f); - if (!is_minimized) - { - memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float)); - FrameRender(wd, draw_data); - FramePresent(wd); - } - } - - // Cleanup - err = vkDeviceWaitIdle(g_Device); - check_vk_result(err); - ImGui_ImplVulkan_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - ImGui::DestroyContext(); - - CleanupVulkanWindow(); - CleanupVulkan(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/src/client/Client.cpp b/src/client/Client.cpp index 8286f86..03509db 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -13,15 +13,16 @@ Client::Client(config::client::options& options): options(options) { } Client::~Client() { } void Client::run(server_handle* const localHandle) { - if (!render::Load(window, options.preferVulkan, options.renderer, options.window.samples)) + if (!render::Load(window, options.preferVulkan, options.renderer, options.window.getSamples())) return; window.setTargetFPS(options.window.targetFPS); - + window.setFullscreen(options.window.fullscreen); InputMap inputs(window.getPtr()); Controllable player(window.getPtr(), inputs, options.control); Camera camera(&player, options.camera); + state.position = player.position; auto pipeline = render::Renderer::Get(); pipeline->LightInvDir = glm::normalize(glm::vec3(-.5f, 2, -2)); @@ -55,7 +56,7 @@ void Client::run(server_handle* const localHandle) { } camera.update(); pipeline->lookFrom(camera); - pipeline->LightInvDir = glm::vec3(glm::rotate(glm::mat4(1), deltaTime * .5f, glm::vec3(1, .5, .1)) * glm::vec4(pipeline->LightInvDir, 0)); + pipeline->LightInvDir = glm::vec3(glm::rotate(glm::mat4(1), deltaTime * .1f, glm::vec3(1, .5, .1)) * glm::vec4(pipeline->LightInvDir, 0)); { const auto ray_result = world->raycast(camera.getRay() * options.voxel_density); @@ -113,7 +114,7 @@ void Client::run(server_handle* const localHandle) { player.setOptions(options.control); } if(actions && render::UI::Actions::FillMode) { - //TODO: pipeline->setFillMode(options.renderer.wireframe); + pipeline->setFillMode(options.renderer.wireframe); } } { // Rendering @@ -184,7 +185,6 @@ void Client::run(server_handle* const localHandle) { options.contouring = state.contouring->getOptions(); world.reset(); - render::UI::Unload(); render::Renderer::Unload(); window.destroy(); } \ No newline at end of file diff --git a/src/client/Window.cpp b/src/client/Window.cpp index 9fcfca5..0f561a1 100644 --- a/src/client/Window.cpp +++ b/src/client/Window.cpp @@ -43,7 +43,6 @@ bool Window::create(const CreateInfo &opt) { break; case CreateInfo::Client::Type::VK: - LOG_W("WIP client type"); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); break; diff --git a/src/client/config.hpp b/src/client/config.hpp index 3575eca..6fd784c 100644 --- a/src/client/config.hpp +++ b/src/client/config.hpp @@ -29,7 +29,7 @@ public: assert(config["enabled"]); window.targetFPS = config["window"]["target_fps"].value_or(window.targetFPS); - window.samples = config["window"]["samples"].value_or(window.samples); + window.sampling = config["window"]["sampling"].value_or(window.sampling); window.fullscreen = config["window"]["fullscreen"].value_or(window.fullscreen); renderer.inFlightFrames = config["window"]["parallel_frames"].value_or(renderer.inFlightFrames); @@ -96,7 +96,7 @@ public: config.insert_or_assign("enabled", true); config.insert_or_assign("window", toml::table({ {"target_fps", window.targetFPS}, - {"samples", window.samples}, + {"sampling", window.sampling}, {"fullscreen", window.fullscreen}, {"parallel_frames", renderer.inFlightFrames} })); @@ -181,8 +181,10 @@ public: struct { int targetFPS = 60; - int samples = -1; + int sampling = -1; bool fullscreen = false; + + constexpr int getSamples() const { return sampling > 0 ? (1 << (sampling - 1)) : sampling; } } window; bool preferVulkan = true; diff --git a/src/client/render/Renderer.hpp b/src/client/render/Renderer.hpp index 7681e53..ffc98b1 100644 --- a/src/client/render/Renderer.hpp +++ b/src/client/render/Renderer.hpp @@ -86,6 +86,7 @@ public: virtual void setClearColor(glm::vec4) = 0; virtual void reloadShaders(const passOptions &) = 0; virtual void reloadTextures(const std::string &, float mipMapLOD, float anisotropy) = 0; + virtual void setFillMode(bool wireframe) = 0; virtual void loadUI(Window&) = 0; diff --git a/src/client/render/UI.cpp b/src/client/render/UI.cpp index 1be726e..b89e277 100644 --- a/src/client/render/UI.cpp +++ b/src/client/render/UI.cpp @@ -52,14 +52,24 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons if (options.debugMenu.render) { ImGui::Begin("Debug: Render", &options.debugMenu.render, ImGuiWindowFlags_AlwaysAutoResize); - ImGui::Text("Tris: %ld (%ld models)", reports.tris_count, reports.models_count); - ImGui::Separator(); ImGui::Checkbox("Overlay", &options.overlay.visible); + { + ImGui::Combo("Driver", (int*)&options.preferVulkan, "OpenGL\0Vulkan\0"); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Prefer Vulkan over OpenGL if available (requires restart)"); + auto samples = std::to_string(options.window.getSamples()) + "x"; + ImGui::SliderInt("MSAA", &options.window.sampling, -1, 7, options.window.sampling > 0 ? samples.c_str() : + (options.window.sampling < 0 ? "System default" : "Minimun")); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Anti-aliasing (requires restart).\nActual value may be smaller than requested"); + + ImGui::Separator(); + } + if (ImGui::SliderInt("FPS", &options.window.targetFPS, Window::MIN_FPS-1, Window::MAX_FPS+1, options.window.targetFPS > Window::MIN_FPS ? (options.window.targetFPS < Window::MAX_FPS ? "%d" : "UNLIMITED") : "VSYNC")){ actions |= Actions::FPS; } - ImGui::Text("Sampling %d (requires restart)", options.window.samples); if (ImGui::Checkbox("Fullscreen", &options.window.fullscreen)){ actions |= Actions::FullScreen; } @@ -106,8 +116,9 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons actions |= Actions::FillMode; } ImGui::Text("Textures '%s'", options.renderer.textures.c_str()); // MAYBE: select + std::string anisotropy = std::to_string(options.renderer.getAnisotropy()) + "x"; if (ImGui::SliderInt("Quality", &options.renderer.textureQuality, 0, 200, "%d%%") | - ImGui::SliderInt("Sharpness", &options.renderer.textureSharpness, 0, 8)) { + ImGui::SliderInt("Sharpness", &options.renderer.textureSharpness, 0, 8, anisotropy.c_str())) { actions |= Actions::RendererTextures; } if(ImGui::IsItemHovered()) diff --git a/src/client/render/gl/Renderer.cpp b/src/client/render/gl/Renderer.cpp index f65e259..7a81d29 100644 --- a/src/client/render/gl/Renderer.cpp +++ b/src/client/render/gl/Renderer.cpp @@ -29,9 +29,11 @@ Renderer::Renderer(const renderOptions& options): FogColor = glm::vec3(options.clear_color.x, options.clear_color.y, options.clear_color.z); loadTextures(options.textures, options.getMipmapLodBias(), options.getAnisotropy()); + setFillMode(options.wireframe); } Renderer::~Renderer() { + render::UI::Unload(); unloadTextures(); glDeleteVertexArrays(1, &VertexArrayID); } @@ -172,3 +174,7 @@ void Renderer::setClearColor(glm::vec4 c) { FogColor = c; glClearColor(c.r, c.g, c.b, c.a); } + +void Renderer::setFillMode(bool wireframe) { + glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL); +} diff --git a/src/client/render/gl/Renderer.hpp b/src/client/render/gl/Renderer.hpp index d95c4c0..b360554 100644 --- a/src/client/render/gl/Renderer.hpp +++ b/src/client/render/gl/Renderer.hpp @@ -55,6 +55,7 @@ public: void lookFrom(const Camera&) override; void reloadShaders(const pass::VoxelProgram::options &) override; void reloadTextures(const std::string &, float mipMapLOD, float anisotropy) override; + void setFillMode(bool wireframe) override; void loadUI(Window &) override; diff --git a/src/client/render/vk/Allocator.cpp b/src/client/render/vk/Allocator.cpp index 4c1dee4..88ac58f 100644 --- a/src/client/render/vk/Allocator.cpp +++ b/src/client/render/vk/Allocator.cpp @@ -175,6 +175,11 @@ void submitCmd(VkCommandBuffer buffer, VkQueue queue) { vkQueueWaitIdle(queue); //MAYBE: use fences vkResetCommandBuffer(buffer, 0); } +void Allocator::transfer(std::function call) { + beginCmd(transferBuffer); + call(transferBuffer); + submitCmd(transferBuffer, transferQueue); +} void Allocator::copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size) { beginCmd(transferBuffer); diff --git a/src/client/render/vk/Allocator.hpp b/src/client/render/vk/Allocator.hpp index 1bd1141..c4b8980 100644 --- a/src/client/render/vk/Allocator.hpp +++ b/src/client/render/vk/Allocator.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace render::vk { @@ -32,6 +33,7 @@ public: memory::ptr allocate(VkMemoryRequirements, VkMemoryPropertyFlags, bool optimalTiling = false); bool deallocate(const memory::area&); + void transfer(std::function); void copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size); void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels, uint32_t arrayLayers); void copyBufferToImage(VkBuffer src, VkImage dst, uint32_t width, uint32_t height, uint32_t mipLevels = 1, uint32_t arrayLayer = 0); diff --git a/src/client/render/vk/CommandCenter.cpp b/src/client/render/vk/CommandCenter.cpp index 93818e0..b826d18 100644 --- a/src/client/render/vk/CommandCenter.cpp +++ b/src/client/render/vk/CommandCenter.cpp @@ -113,6 +113,23 @@ void CommandCenter::allocate(const std::vector& views, const Pipeli } } + uiFramebuffers.resize(views.size()); + + for (size_t i = 0; i < views.size(); i++) { + VkFramebufferCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + info.renderPass = pipe.getUIRenderPass(); + info.attachmentCount = 1; + info.pAttachments = &views[i]; + info.width = extent.width; + info.height = extent.height; + info.layers = 1; + + if (vkCreateFramebuffer(device, &info, ALLOC, &uiFramebuffers[i]) != VK_SUCCESS) { + FATAL("Failed to create ui framebuffer!"); + } + } + { // Uniform buffers std::vector requirements; requirements.resize(framebuffers.size(), Buffer::requirement(sizeof(VoxelUBO), Buffer::Usage::UNIFORM)); @@ -253,6 +270,9 @@ void CommandCenter::free() { for (size_t i = 0; i < framebuffers.size(); i++) { vkDestroyFramebuffer(device, framebuffers[i], ALLOC); } + for (size_t i = 0; i < uiFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, uiFramebuffers[i], ALLOC); + } freed = true; } @@ -277,7 +297,7 @@ void CommandCenter::startRecording(uint32_t idx, VkRenderPass renderPass, VkExte if (!idx) { TracyVkCollect(tracyCtx, graphicsBuffers[idx]); } - TracyVkZone(tracyCtx, graphicsBuffers[idx], "Render"); + TracyVkZone(tracyCtx, graphicsBuffers[idx], "Begin"); VkRenderPassBeginInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassInfo.renderPass = renderPass; @@ -336,9 +356,24 @@ void CommandCenter::recordPostprocess(uint32_t idx, const Subpass& skyPass, bool vkCmdDraw(graphicsBuffers[idx], skyCubeBuffer->size, 1, 0, 0); } vkCmdEndRenderPass(graphicsBuffers[idx]); - TracyVkZone(tracyCtx, graphicsBuffers[idx], "Swap"); } +void CommandCenter::recordUI(uint32_t idx, VkRenderPass uiPass, VkExtent2D extent, const std::function& call) { + TracyVkZone(tracyCtx, graphicsBuffers[idx], "UI"); + VkRenderPassBeginInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + info.renderPass = uiPass; + info.framebuffer = uiFramebuffers[idx]; + info.renderArea.extent = extent; + info.clearValueCount = 1; + VkClearValue clearValue{}; + clearValue.color = {0.f, 0.f, 0.f, 1.f}; + info.pClearValues = &clearValue; + vkCmdBeginRenderPass(graphicsBuffers[idx], &info, VK_SUBPASS_CONTENTS_INLINE); + + call(graphicsBuffers[idx]); + vkCmdEndRenderPass(graphicsBuffers[idx]); +} void CommandCenter::submitGraphics(uint32_t idx, VkSemaphore waitSemaphore, VkSemaphore signalSemaphore, VkFence submittedFence) { assert(!freed); diff --git a/src/client/render/vk/CommandCenter.hpp b/src/client/render/vk/CommandCenter.hpp index 970cda0..43aca23 100644 --- a/src/client/render/vk/CommandCenter.hpp +++ b/src/client/render/vk/CommandCenter.hpp @@ -2,6 +2,7 @@ #include "forward.hpp" #include +#include #include #include "api/Buffers.hpp" #include "api/Images.hpp" @@ -29,17 +30,19 @@ public: void startIndicPass(uint32_t idx, const Subpass&); size_t recordIndicator(uint32_t idx, const Subpass&, glm::mat4 model); void recordPostprocess(uint32_t idx, const Subpass&, bool skybox); + void recordUI(uint32_t idx, VkRenderPass uiPass, VkExtent2D, const std::function &); void submitGraphics(uint32_t, VkSemaphore, VkSemaphore, VkFence); + void loadAtlases(const std::string &texturePath, int anisotropy, float lodBias); void allocate(const std::vector&, const Pipeline&, VkPhysicalDevice, VkExtent2D); void free(); private: - void loadAtlases(const std::string &texturePath, int anisotropy, float lodBias); VkDevice device; std::vector framebuffers; + std::vector uiFramebuffers; VkFormat colorFormat; VkSampleCountFlagBits colorSamples; diff --git a/src/client/render/vk/Pipeline.cpp b/src/client/render/vk/Pipeline.cpp index 33e4496..7918096 100644 --- a/src/client/render/vk/Pipeline.cpp +++ b/src/client/render/vk/Pipeline.cpp @@ -23,8 +23,8 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - colorAttachment.finalLayout = hasSamples ? - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + // NOTE: UI RenderPass do VK_IMAGE_LAYOUT_PRESENT_SRC_KHR VkAttachmentReference colorAttachmentRef{}; colorAttachmentRef.attachment = 0; //TODO: layouts bind @@ -52,7 +52,8 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + // NOTE: UI RenderPass do VK_IMAGE_LAYOUT_PRESENT_SRC_KHR VkAttachmentReference colorAttachmentResolveRef{}; colorAttachmentResolveRef.attachment = 2; @@ -126,6 +127,46 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render FATAL("Failed to create render pass!"); } } + { // UI Render pass + VkAttachmentDescription attachment = {}; + attachment.format = info.getSurfaceFormat().format; + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + 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_COLOR_ATTACHMENT_OPTIMAL; + 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; + + VkSubpassDependency dependency = {}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.srcAccessMask = 0; // or VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + VkRenderPassCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + info.attachmentCount = 1; + info.pAttachments = &attachment; + info.subpassCount = 1; + info.pSubpasses = &subpass; + info.dependencyCount = 1; + info.pDependencies = &dependency; + if (vkCreateRenderPass(device, &info, nullptr, &uiRenderPass) != VK_SUCCESS) { + FATAL("Failed to create UI render pass!"); + } + } //MAYBE: use sets (ubo, (samplers, passInfos)) //MAYBE: reuse sub UBO { // Voxel descriptor @@ -310,7 +351,7 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rasterizer.depthClampEnable = VK_FALSE; rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = options.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL; + rasterizer.polygonMode = options.wireframe && info.features.fillModeNonSolid ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL; rasterizer.lineWidth = 1.0f; rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; @@ -519,6 +560,8 @@ Pipeline::~Pipeline() { vkDestroyPipelineLayout(device, pass.layout, ALLOC); }; + vkDestroyRenderPass(device, uiRenderPass, ALLOC); + destroy(worldPass); destroy(indicPass); destroy(skyPass); diff --git a/src/client/render/vk/Pipeline.hpp b/src/client/render/vk/Pipeline.hpp index 07e40d6..30a8c94 100644 --- a/src/client/render/vk/Pipeline.hpp +++ b/src/client/render/vk/Pipeline.hpp @@ -28,6 +28,8 @@ public: constexpr VkDescriptorSetLayout getSkyDescriptorSet() const { return skyDescriptorSet; } constexpr const Subpass& getSkyPass() const { return skyPass; } + constexpr VkRenderPass getUIRenderPass() const { return uiRenderPass; } + private: VkDevice device; @@ -40,5 +42,7 @@ private: Subpass worldPass; Subpass indicPass; Subpass skyPass; + + VkRenderPass uiRenderPass; }; } \ No newline at end of file diff --git a/src/client/render/vk/Renderer.cpp b/src/client/render/vk/Renderer.cpp index 8b0e9d5..60e1ed5 100644 --- a/src/client/render/vk/Renderer.cpp +++ b/src/client/render/vk/Renderer.cpp @@ -12,6 +12,7 @@ #include #include #include +#include using namespace render::vk; @@ -81,6 +82,7 @@ Renderer::~Renderer() { vkDeviceWaitIdle(device); const auto imageCount = swapChain->getImageViews().size(); destroySwapChain(); + render::UI::Unload(); for(size_t i = 0; i < renderFinishedSemaphores.size(); i++) { vkDestroyFence(device, inFlightFences[i], ALLOC); @@ -111,6 +113,8 @@ void Renderer::recreateSwapChain() { swapChain = std::make_unique(device, getInfos()); pipeline = std::make_unique(device, getInfos(), options); commandCenter->allocate(swapChain->getImageViews(), *pipeline.get(), getInfos().device, getInfos().swapDetails.capabilities.currentExtent); + + dynamic_cast(UI::Get())->setImageCount(swapChain->getImageViews().size()); } void Renderer::destroySwapChain() { commandCenter->free(); @@ -333,6 +337,12 @@ bool Renderer::Load(Window& window, const renderOptions& opt, int samples) { if (infos.features.samplerAnisotropy) score += 1000; + if (infos.features.sampleRateShading) + score += 1500; + + if (infos.features.fillModeNonSolid) + score += 100; + //TODO: check others limits if (!infos.queueIndices.isComplete()) @@ -377,6 +387,7 @@ bool Renderer::Load(Window& window, const renderOptions& opt, int samples) { deviceFeatures.geometryShader = physicalInfo.features.geometryShader; deviceFeatures.samplerAnisotropy = physicalInfo.features.samplerAnisotropy; deviceFeatures.sampleRateShading = physicalInfo.features.sampleRateShading; + deviceFeatures.fillModeNonSolid = physicalInfo.features.fillModeNonSolid; std::vector extensions(requiredExtensions); extensions.insert(extensions.end(), physicalInfo.optionalExtensions.begin(), physicalInfo.optionalExtensions.end()); @@ -404,6 +415,12 @@ bool Renderer::Load(Window& window, const renderOptions& opt, int samples) { LodModel::MakeDefault(); return true; } +Renderer::UICtx Renderer::getUICtx() const { + auto queueFamily = physicalInfo->queueIndices.graphicsFamily.value(); + VkQueue queue; + vkGetDeviceQueue(device, queueFamily, 0, &queue); + return {instance, physicalInfo->device, device, queueFamily, queue, (uint32_t)swapChain->getImageViews().size(), pipeline->getUIRenderPass()}; +} void Renderer::loadUI(Window& w) { UI::Load(w); @@ -411,6 +428,7 @@ void Renderer::loadUI(Window& w) { void Renderer::beginFrame() { assert(currentImage == UINT32_MAX); + ZoneScopedN("VkWaitForFrame"); if (auto newImage = swapChain->acquireNextImage(imageAvailableSemaphores[currentFrame], inFlightFences[currentFrame])) { currentImage = newImage.value(); @@ -467,7 +485,10 @@ std::function Renderer::beginIndicatorPass() { void Renderer::postProcess() { commandCenter->recordPostprocess(currentImage, pipeline->getSkyPass(), options.skybox); } - +void Renderer::recordUI(std::function call) { + return commandCenter->recordUI(currentImage, pipeline->getUIRenderPass(), + getInfos().swapDetails.capabilities.currentExtent, call); +} void Renderer::endFrame() { commandCenter->submitGraphics(currentImage, imageAvailableSemaphores[currentFrame], renderFinishedSemaphores[currentFrame], inFlightFences[currentFrame]); @@ -485,13 +506,20 @@ void Renderer::swapBuffer(Window&) { vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX); } -void Renderer::reloadShaders(const passOptions&) { - /*WorldPass = std::make_unique(options); - EntityPass = std::make_unique(options);*/ +void Renderer::reloadShaders(const passOptions& opt) { + options.voxel = opt; + recreateSwapChain(); } -void Renderer::reloadTextures(const std::string&, float, float) { - /*unloadTextures(); - loadTextures(texturePath, mipMapLOD, anisotropy);*/ +void Renderer::reloadTextures(const std::string& textures, float mipmap, float anisotropy) { + vkDeviceWaitIdle(device); + commandCenter->free(); + commandCenter->loadAtlases(textures, anisotropy, mipmap); + commandCenter->allocate(swapChain->getImageViews(), *pipeline.get(), getInfos().device, + getInfos().swapDetails.capabilities.currentExtent); +} +void Renderer::setFillMode(bool wireframe) { + options.wireframe = wireframe; + recreateSwapChain(); } void Renderer::lookFrom(const Camera& camera) { diff --git a/src/client/render/vk/Renderer.hpp b/src/client/render/vk/Renderer.hpp index 1d787ac..3af8d7f 100644 --- a/src/client/render/vk/Renderer.hpp +++ b/src/client/render/vk/Renderer.hpp @@ -24,6 +24,7 @@ public: std::function &)> beginEntityPass() override; std::function beginIndicatorPass() override; void postProcess() override; + void recordUI(std::function); void endFrame() override; void swapBuffer(Window &) override; @@ -33,8 +34,19 @@ public: void lookFrom(const Camera &) override; void reloadShaders(const passOptions &) override; void reloadTextures(const std::string &, float mipMapLOD, float anisotropy) override; + void setFillMode(bool wireframe) override; Allocator* getAllocator() const { return allocator.get(); } + struct UICtx { + VkInstance instance; + VkPhysicalDevice physicalDevice; + VkDevice device; + uint32_t queueFamily; + VkQueue queue; + uint32_t imageCount; + VkRenderPass renderPass; + }; + UICtx getUICtx() const; void setResized() { framebufferResized = true; } diff --git a/src/client/render/vk/UI.cpp b/src/client/render/vk/UI.cpp index a41ffe7..d863e3e 100644 --- a/src/client/render/vk/UI.cpp +++ b/src/client/render/vk/UI.cpp @@ -1,28 +1,103 @@ #include "UI.hpp" #include "../../Window.hpp" -#include +#include "Renderer.hpp" +#include "Allocator.hpp" +#include +#include +#include "../../../core/utils/logger.hpp" using namespace render::vk; +static void imgui_check_vk_result(VkResult err) { + if (err == 0) + return; + if (err < 0) { + FATAL("VK ImGui error " << err); + } else { + LOG_W("VK ImGui error " << err); + } +} + UI::UI(GLFWwindow *window): render::UI() { + auto ctx = Renderer::Get()->getUICtx(); + device = ctx.device; + { // Descriptor pool + std::array poolSizes{}; + poolSizes[0].type = VK_DESCRIPTOR_TYPE_SAMPLER; + poolSizes[0].descriptorCount = 1000; + poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + poolSizes[1].descriptorCount = 1000; + poolSizes[2].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + poolSizes[2].descriptorCount = 1000; + poolSizes[3].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + poolSizes[3].descriptorCount = 1000; + poolSizes[4].type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + poolSizes[4].descriptorCount = 1000; + poolSizes[5].type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + poolSizes[5].descriptorCount = 1000; + poolSizes[6].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + poolSizes[6].descriptorCount = 1000; + poolSizes[7].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + poolSizes[7].descriptorCount = 1000; + poolSizes[8].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + poolSizes[8].descriptorCount = 1000; + poolSizes[9].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; + poolSizes[9].descriptorCount = 1000; + poolSizes[10].type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + poolSizes[10].descriptorCount = 1000; + + VkDescriptorPoolCreateInfo poolInfo{}; + poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolInfo.poolSizeCount = poolSizes.size(); + poolInfo.pPoolSizes = poolSizes.data(); + poolInfo.maxSets = 1000 * poolSizes.size(); + poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + + if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) { + FATAL("Failed to create UI descriptor pool!"); + } + } + // Setup Platform/Renderer bindings - /*ImGui_ImplGlfw_InitForOpenGL(window, true); - ImGui_ImplOpenGL3_Init("#version 130"); - aim = Texture::CreatePtr("ui/Aim", false);*/ + ImGui_ImplGlfw_InitForVulkan(window, true); + ImGui_ImplVulkan_InitInfo init_info = {}; + init_info.Instance = ctx.instance; + init_info.PhysicalDevice = ctx.physicalDevice; + init_info.Device = ctx.device; + init_info.QueueFamily = ctx.queueFamily; + init_info.Queue = ctx.queue; + init_info.PipelineCache = VK_NULL_HANDLE; + init_info.DescriptorPool = descriptorPool; + init_info.Allocator = nullptr; + init_info.MinImageCount = ctx.imageCount; + init_info.ImageCount = ctx.imageCount; + init_info.CheckVkResultFn = imgui_check_vk_result; + ImGui_ImplVulkan_Init(&init_info, ctx.renderPass); + Allocator::GetDefault()->transfer(ImGui_ImplVulkan_CreateFontsTexture); + aimTexture = Texture::LoadFromFile("content/textures/ui/Aim.dds", {false, false, Texture::Wrap::MIRRORED_REPEAT, 0, false}); + aimHandle = (intptr_t)ImGui_ImplVulkan_AddTexture(aimTexture->getDescriptor()); } UI::~UI() { - /*ImGui_ImplGlfw_Shutdown(); - ImGui_ImplOpenGL3_Shutdown();*/ + ImGui_ImplVulkan_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + + vkDestroyDescriptorPool(device, descriptorPool, nullptr); +} + +void UI::setImageCount(uint32_t count) { + ImGui_ImplVulkan_SetMinImageCount(count); } UI::Actions UI::draw(config::client::options &o, state::state &s, const state::reports &r) { - /*ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame();*/ - return UI::Actions::None; //render::UI::draw(o, s, r, aim); + ImGui_ImplVulkan_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + return render::UI::draw(o, s, r, aimHandle); } void UI::render() { - //ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + Renderer::Get()->recordUI([](VkCommandBuffer buffer){ + ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), buffer); + }); } void UI::Load(Window& w) { diff --git a/src/client/render/vk/UI.hpp b/src/client/render/vk/UI.hpp index bb0ceea..89f970e 100644 --- a/src/client/render/vk/UI.hpp +++ b/src/client/render/vk/UI.hpp @@ -1,6 +1,8 @@ #pragma once #include "../UI.hpp" +#include "forward.hpp" +#include "api/Images.hpp" struct GLFWwindow; class Window; @@ -18,7 +20,13 @@ public: Actions draw(config::client::options &, state::state &, const state::reports &) override; void render() override; + void setImageCount(uint32_t); + private: - intptr_t aim; + VkDevice device; + + std::unique_ptr aimTexture; + intptr_t aimHandle; + VkDescriptorPool descriptorPool; }; } \ No newline at end of file diff --git a/src/client/world/DistantUniverse.cpp b/src/client/world/DistantUniverse.cpp index d68f723..2a38be9 100644 --- a/src/client/world/DistantUniverse.cpp +++ b/src/client/world/DistantUniverse.cpp @@ -82,6 +82,7 @@ void DistantUniverse::pullNetwork(voxel_pos pos) { switch (type) { case server_packet_type::CAPABILITIES: { PacketReader(packet).read(serverDistance); + emit(world::action::Move(pos)); break; } diff --git a/src/client/world/LocalUniverse.cpp b/src/client/world/LocalUniverse.cpp index 000dd3e..ed037fa 100644 --- a/src/client/world/LocalUniverse.cpp +++ b/src/client/world/LocalUniverse.cpp @@ -25,6 +25,8 @@ LocalUniverse::~LocalUniverse() { void LocalUniverse::update(voxel_pos pos, float) { const auto cur_chunk = glm::divide(pos); const auto chunkChange = cur_chunk != last_chunk; + if (last_chunk.x == INT_MAX) + emit(world::action::Move(pos)); last_chunk = cur_chunk; if(chunkChange) {