From 509df3e2790f9fb6162d9cb2a4f2f3dd6465fdb8 Mon Sep 17 00:00:00 2001 From: Marcell Kiss Date: Sat, 11 Feb 2017 12:08:59 +0100 Subject: [PATCH 01/26] Fix new Vulkan validation warnings --- examples/vulkan_example/imgui_impl_glfw_vulkan.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index ef9da895..6ac4e4c0 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -236,10 +236,10 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) VkMappedMemoryRange range[2] = {}; range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; range[0].memory = g_VertexBufferMemory[g_FrameIndex]; - range[0].size = vertex_size; + range[0].size = VK_WHOLE_SIZE; range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; range[1].memory = g_IndexBufferMemory[g_FrameIndex]; - range[1].size = index_size; + range[1].size = VK_WHOLE_SIZE; err = vkFlushMappedMemoryRanges(g_Device, 2, range); ImGui_ImplGlfwVulkan_VkResult(err); vkUnmapMemory(g_Device, g_VertexBufferMemory[g_FrameIndex]); @@ -483,6 +483,7 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) region.imageSubresource.layerCount = 1; region.imageExtent.width = width; region.imageExtent.height = height; + region.imageExtent.depth = 1; vkCmdCopyBufferToImage(command_buffer, g_UploadBuffer, g_FontImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); VkImageMemoryBarrier use_barrier[1] = {}; From e0244c8f62f5d74d321bc45f8d51e002f926a988 Mon Sep 17 00:00:00 2001 From: Marcell Kiss Date: Sat, 11 Feb 2017 12:09:31 +0100 Subject: [PATCH 02/26] Fix scissor offset being negative --- examples/vulkan_example/imgui_impl_glfw_vulkan.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 6ac4e4c0..29aed598 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -301,8 +301,8 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) else { VkRect2D scissor; - scissor.offset.x = (int32_t)(pcmd->ClipRect.x); - scissor.offset.y = (int32_t)(pcmd->ClipRect.y); + scissor.offset.x = (int32_t)(pcmd->ClipRect.x) > 0 ? (int32_t)(pcmd->ClipRect.x) : 0; // clamp these to 0, scissor offset.xy must be > 0 + scissor.offset.y = (int32_t)(pcmd->ClipRect.y) > 0 ? (int32_t)(pcmd->ClipRect.y) : 0; scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x); scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // TODO: + 1?????? vkCmdSetScissor(g_CommandBuffer, 0, 1, &scissor); From fd90da38e16d04828f99998237d99681e52d1212 Mon Sep 17 00:00:00 2001 From: Peter Particle Date: Sun, 26 Feb 2017 13:25:54 +0100 Subject: [PATCH 03/26] Vulkan backend: g_FrameIndex not used fix -> huge perf gain Added a macro to switch between unlimited frame rate (VK_PRESENT_MODE_IMMEDIATE_KHR) and limited to 60 fps (VK_PRESENT_MODE_FIFO_KHR). Only the latter mode is guaranteed to be available, but the former one most likely is. --- examples/vulkan_example/main.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index 8116e08c..265ec803 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -12,6 +12,7 @@ #include "imgui_impl_glfw_vulkan.h" #define IMGUI_MAX_POSSIBLE_BACK_BUFFERS 16 +#define IMGUI_UNLIMITED_FRAME_RATE static VkAllocationCallbacks* g_Allocator = NULL; static VkInstance g_Instance = VK_NULL_HANDLE; @@ -83,7 +84,12 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + +#ifdef IMGUI_UNLIMITED_FRAME_RATE + info.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; +#elif info.presentMode = VK_PRESENT_MODE_FIFO_KHR; +#endif info.clipped = VK_TRUE; info.oldSwapchain = old_swapchain; VkSurfaceCapabilitiesKHR cap; @@ -93,6 +99,7 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) info.minImageCount = (cap.minImageCount + 2 < cap.maxImageCount) ? (cap.minImageCount + 2) : cap.maxImageCount; else info.minImageCount = cap.minImageCount + 2; + if (cap.currentExtent.width == 0xffffffff) { fb_width = w; @@ -462,7 +469,7 @@ static void frame_end() check_vk_result(err); check_vk_result(res); } - g_FrameIndex = (g_FrameIndex) % IMGUI_VK_QUEUED_FRAMES; + g_FrameIndex = (g_FrameIndex+1) % IMGUI_VK_QUEUED_FRAMES; } static void error_callback(int error, const char* description) From 337019a68f4ee1d1cc1fc9e023d07b0cbe04d505 Mon Sep 17 00:00:00 2001 From: Peter Particle Date: Sun, 26 Feb 2017 17:16:37 +0100 Subject: [PATCH 04/26] typo, #elif instead of #else, fixed --- examples/vulkan_example/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index 265ec803..9e7455c3 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -87,7 +87,7 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) #ifdef IMGUI_UNLIMITED_FRAME_RATE info.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; -#elif +#else info.presentMode = VK_PRESENT_MODE_FIFO_KHR; #endif info.clipped = VK_TRUE; From 12deb53b11eeb3f74ed1ff86ae91ca15345781d9 Mon Sep 17 00:00:00 2001 From: saschawillems Date: Sun, 26 Mar 2017 19:38:05 +0200 Subject: [PATCH 05/26] Set required depth member for buffer image copy --- examples/vulkan_example/imgui_impl_glfw_vulkan.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index ef9da895..72fa5bc8 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -483,6 +483,7 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) region.imageSubresource.layerCount = 1; region.imageExtent.width = width; region.imageExtent.height = height; + region.imageExtent.depth = 1; vkCmdCopyBufferToImage(command_buffer, g_UploadBuffer, g_FontImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); VkImageMemoryBarrier use_barrier[1] = {}; From 4da26d85cdf4d84eb0e491fbfcf1efce3311d093 Mon Sep 17 00:00:00 2001 From: saschawillems Date: Sun, 26 Mar 2017 19:54:59 +0200 Subject: [PATCH 06/26] Clip negative scissor offsets to zero --- examples/vulkan_example/imgui_impl_glfw_vulkan.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 72fa5bc8..e7dfe32b 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -301,8 +301,8 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) else { VkRect2D scissor; - scissor.offset.x = (int32_t)(pcmd->ClipRect.x); - scissor.offset.y = (int32_t)(pcmd->ClipRect.y); + scissor.offset.x = (int32_t)(pcmd->ClipRect.x) > 0 ? (int32_t)(pcmd->ClipRect.x) : 0; + scissor.offset.y = (int32_t)(pcmd->ClipRect.y) > 0 ? (int32_t)(pcmd->ClipRect.y) : 0; scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x); scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // TODO: + 1?????? vkCmdSetScissor(g_CommandBuffer, 0, 1, &scissor); From dbfd5d6e9afb4d6d140febee0e176b002c203d04 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 1 May 2017 12:55:47 +0200 Subject: [PATCH 07/26] Ignoring unreasonnable Clang -wformat-pedantic warning (#1090) See e.g. http://clang-developers.42468.n3.nabble.com/The-p-conversion-and-cast-to-void-td4044226.html --- imgui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index dd30abdf..b5b8a747 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -639,11 +639,12 @@ // Clang warnings with -Weverything #ifdef __clang__ #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. -#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. #pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // +#pragma clang diagnostic ignored "-Wformat-pedantic" // warning : format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic. #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' // #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used From b3d237a5ceaabbdac52759abfb423be1d553b053 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 1 May 2017 13:47:59 +0200 Subject: [PATCH 08/26] Examples: SDL2: Added build .bat files for win32. --- examples/sdl_opengl2_example/build_win32.bat | 1 + examples/sdl_opengl3_example/build_win32.bat | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 examples/sdl_opengl2_example/build_win32.bat create mode 100644 examples/sdl_opengl3_example/build_win32.bat diff --git a/examples/sdl_opengl2_example/build_win32.bat b/examples/sdl_opengl2_example/build_win32.bat new file mode 100644 index 00000000..6509f3ae --- /dev/null +++ b/examples/sdl_opengl2_example/build_win32.bat @@ -0,0 +1 @@ +cl /Zi /MD /I ..\.. /I ..\libs\gl3w /I %SDL2DIR%\include main.cpp imgui_impl_sdl.cpp ..\..\imgui*.cpp ..\libs\gl3w\GL\gl3w.c /link /libpath:%SDL2DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib /subsystem:console diff --git a/examples/sdl_opengl3_example/build_win32.bat b/examples/sdl_opengl3_example/build_win32.bat new file mode 100644 index 00000000..b6e73271 --- /dev/null +++ b/examples/sdl_opengl3_example/build_win32.bat @@ -0,0 +1,2 @@ +set SDL2DIR=D:\T-Work\Libs\SDL\SDL2-2.0.3 +cl /Zi /MD /I ..\.. /I ..\libs\gl3w /I %SDL2DIR%\include main.cpp imgui_impl_sdl_gl3.cpp ..\..\imgui*.cpp ..\libs\gl3w\GL\gl3w.c /link /libpath:%SDL2DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib /subsystem:console From c3d9e0a6ebfdb8c3917b4a67a561b16fece7c861 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 1 May 2017 15:00:42 +0200 Subject: [PATCH 09/26] Examples: SDL2: Tweaked batch files for Win32. --- examples/.gitignore | 8 ++++++++ examples/sdl_opengl2_example/build_win32.bat | 4 +++- examples/sdl_opengl3_example/build_win32.bat | 5 +++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/examples/.gitignore b/examples/.gitignore index 54d15398..4a3d57c0 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -25,6 +25,14 @@ opengl3_example/Release/* opengl3_example/ipch/* opengl3_example/x64/* opengl3_example/opengl3_example +sdl_opengl2_example/Debug/* +sdl_opengl2_example/Release/* +sdl_opengl2_example/ipch/* +sdl_opengl2_example/x64/* +sdl_opengl3_example/Debug/* +sdl_opengl3_example/Release/* +sdl_opengl3_example/ipch/* +sdl_opengl3_example/x64/* *.opensdf *.sdf *.suo diff --git a/examples/sdl_opengl2_example/build_win32.bat b/examples/sdl_opengl2_example/build_win32.bat index 6509f3ae..3cf81e60 100644 --- a/examples/sdl_opengl2_example/build_win32.bat +++ b/examples/sdl_opengl2_example/build_win32.bat @@ -1 +1,3 @@ -cl /Zi /MD /I ..\.. /I ..\libs\gl3w /I %SDL2DIR%\include main.cpp imgui_impl_sdl.cpp ..\..\imgui*.cpp ..\libs\gl3w\GL\gl3w.c /link /libpath:%SDL2DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib /subsystem:console +@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. +mkdir Debug +cl /nologo /Zi /MD /I ..\.. /I ..\libs\gl3w /I %SDL_DIR%\include main.cpp imgui_impl_sdl.cpp ..\..\imgui*.cpp ..\libs\gl3w\GL\gl3w.c /FeDebug/sdl_opengl2_example.exe /FoDebug/ /link /libpath:%SDL_DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib /subsystem:console diff --git a/examples/sdl_opengl3_example/build_win32.bat b/examples/sdl_opengl3_example/build_win32.bat index b6e73271..43567542 100644 --- a/examples/sdl_opengl3_example/build_win32.bat +++ b/examples/sdl_opengl3_example/build_win32.bat @@ -1,2 +1,3 @@ -set SDL2DIR=D:\T-Work\Libs\SDL\SDL2-2.0.3 -cl /Zi /MD /I ..\.. /I ..\libs\gl3w /I %SDL2DIR%\include main.cpp imgui_impl_sdl_gl3.cpp ..\..\imgui*.cpp ..\libs\gl3w\GL\gl3w.c /link /libpath:%SDL2DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib /subsystem:console +@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. +mkdir Debug +cl /nologo /Zi /MD /I ..\.. /I ..\libs\gl3w /I %SDL_DIR%\include main.cpp imgui_impl_sdl_gl3.cpp ..\..\imgui*.cpp ..\libs\gl3w\GL\gl3w.c /FeDebug/sdl_opengl3_example.exe /FoDebug/ /link /libpath:%SDL_DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib /subsystem:console From 497381dc3d4031bfb30de6027ea85bfded77e4f2 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 1 May 2017 15:53:50 +0200 Subject: [PATCH 10/26] Comments --- imgui_demo.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 58f7a795..b8f4478e 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,9 +1,11 @@ // dear imgui, v1.50 WIP // (demo code) -// Don't remove this file from your project! It is useful reference code that you can execute. -// You can call ImGui::ShowTestWindow() in your code to learn about various features of ImGui. +// Message to the person tempted to delete this file when integrating ImGui into their code base: +// Do NOT remove this file from your project! It is useful reference code that you and other users will want to refer to. // Everything in this file will be stripped out by the linker if you don't call ImGui::ShowTestWindow(). +// During development, you can call ImGui::ShowTestWindow() in your code to learn about various features of ImGui. +// Removing this file from your project is hindering your access to documentation, likely leading you to poorer usage of the library. #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS From 5418bb19ffb9b39580633ad9468bcc0fdf9b5002 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 1 May 2017 16:14:13 +0200 Subject: [PATCH 11/26] Examples: Vulkan: windows batch file for 64-bits. --- examples/vulkan_example/build_win64.bat | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 examples/vulkan_example/build_win64.bat diff --git a/examples/vulkan_example/build_win64.bat b/examples/vulkan_example/build_win64.bat new file mode 100644 index 00000000..a8c05a55 --- /dev/null +++ b/examples/vulkan_example/build_win64.bat @@ -0,0 +1,4 @@ +@REM Build for Visual Studio compiler. Run your copy of amd64/vcvars32.bat to setup 64-bit command-line compiler. +mkdir Debug +cl /nologo /Zi /MD /I ..\.. /I ..\libs\glfw\include /I %VULKAN_SDK%\include *.cpp ..\..\*.cpp /FeDebug/vulkan_example.exe /FoDebug/ /link /LIBPATH:..\libs\glfw\lib-vc2010-64 /libpath:%VULKAN_SDK%\bin glfw3.lib opengl32.lib gdi32.lib shell32.lib vulkan-1.lib + From 56dff3a0803de0450ea242dd0757d2f51d9eb75a Mon Sep 17 00:00:00 2001 From: Peter Particle Date: Sun, 26 Feb 2017 13:36:40 +0100 Subject: [PATCH 12/26] Vulkan backend: optionally enabling vulkan validation layers and debug report callback Additional layer, extension and the callback itself are used/created when IMGUI_VULKAN_DEBUG_REPORT is defined. The callback reports seven (potential!) errors which will be fixed with another pull request. --- examples/vulkan_example/main.cpp | 71 +++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index 9e7455c3..2ca245d8 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -12,7 +12,8 @@ #include "imgui_impl_glfw_vulkan.h" #define IMGUI_MAX_POSSIBLE_BACK_BUFFERS 16 -#define IMGUI_UNLIMITED_FRAME_RATE +#define IMGUI_UNLIMITED_FRAME_RATE +#define IMGUI_VULKAN_DEBUG_REPORT static VkAllocationCallbacks* g_Allocator = NULL; static VkInstance g_Instance = VK_NULL_HANDLE; @@ -23,6 +24,7 @@ static VkSwapchainKHR g_Swapchain = VK_NULL_HANDLE; static VkRenderPass g_RenderPass = VK_NULL_HANDLE; static uint32_t g_QueueFamily = 0; static VkQueue g_Queue = VK_NULL_HANDLE; +static VkDebugReportCallbackEXT g_Debug_Report = VK_NULL_HANDLE; static VkFormat g_ImageFormat = VK_FORMAT_B8G8R8A8_UNORM; static VkFormat g_ViewFormat = VK_FORMAT_B8G8R8A8_UNORM; @@ -89,7 +91,7 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) info.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; #else info.presentMode = VK_PRESENT_MODE_FIFO_KHR; -#endif +#endif // IMGUI_UNLIMITED_FRAME_RATE info.clipped = VK_TRUE; info.oldSwapchain = old_swapchain; VkSurfaceCapabilitiesKHR cap; @@ -191,20 +193,71 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) } } +#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) +{ + printf( "ObjectType : %i\nMessage : %s\n\n", objectType, pMessage ); + return VK_FALSE; +} +#endif // IMGUI_VULKAN_DEBUG_REPORT + static void setup_vulkan(GLFWwindow* window) { VkResult err; // Create Vulkan Instance { - uint32_t glfw_extensions_count; - const char** glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extensions_count); + uint32_t extensions_count; + const char** glfw_extensions = glfwGetRequiredInstanceExtensions(&extensions_count); + VkInstanceCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - create_info.enabledExtensionCount = glfw_extensions_count; +#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; + + // need additional storage for char pointer to debug report extension + const char** extensions = (const char**)malloc(sizeof(const char*) * (extensions_count + 1)); + for(size_t i = 0; i < extensions_count; i++) + extensions[i] = glfw_extensions[i]; + extensions[ extensions_count ] = "VK_EXT_debug_report"; + create_info.enabledExtensionCount = extensions_count+1; + create_info.ppEnabledExtensionNames = extensions; +#elif + create_info.enabledExtensionCount = extensions_count; create_info.ppEnabledExtensionNames = glfw_extensions; +#endif // IMGUI_VULKAN_DEBUG_REPORT + err = vkCreateInstance(&create_info, g_Allocator, &g_Instance); check_vk_result(err); + +#ifdef IMGUI_VULKAN_DEBUG_REPORT + free(extensions); + + // create 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; + + // get the proc address of the function pointer, required for used extensions + PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT = + (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkCreateDebugReportCallbackEXT"); + + err = vkCreateDebugReportCallbackEXT( g_Instance, &debug_report_ci, g_Allocator, &g_Debug_Report ); + check_vk_result( err ); +#endif // IMGUI_VULKAN_DEBUG_REPORT } // Create Window Surface @@ -381,6 +434,14 @@ static void cleanup_vulkan() vkDestroyRenderPass(g_Device, g_RenderPass, g_Allocator); vkDestroySwapchainKHR(g_Device, g_Swapchain, g_Allocator); vkDestroySurfaceKHR(g_Instance, g_Surface, g_Allocator); + +#ifdef IMGUI_VULKAN_DEBUG_REPORT + // get the proc address of the function pointer, required for used extensions + auto vkDestroyDebugReportCallbackEXT = + (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT"); + vkDestroyDebugReportCallbackEXT(g_Instance, g_Debug_Report, g_Allocator); +#endif // IMGUI_VULKAN_DEBUG_REPORT + vkDestroyDevice(g_Device, g_Allocator); vkDestroyInstance(g_Instance, g_Allocator); } From 89d03d5cca8b9c52e359702eb58a7f4e87d5c153 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 1 May 2017 16:46:57 +0200 Subject: [PATCH 13/26] Examples: Vulkan: Disable IMGUI_VULKAN_DEBUG_REPORT by default. Update .bat files for newer VulkanSDK. --- examples/vulkan_example/build_win32.bat | 2 +- examples/vulkan_example/build_win64.bat | 2 +- examples/vulkan_example/main.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/vulkan_example/build_win32.bat b/examples/vulkan_example/build_win32.bat index e8b5a6c7..b76741ae 100644 --- a/examples/vulkan_example/build_win32.bat +++ b/examples/vulkan_example/build_win32.bat @@ -1,4 +1,4 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. mkdir Debug -cl /nologo /Zi /MD /I ..\.. /I ..\libs\glfw\include /I %VULKAN_SDK%\include *.cpp ..\..\*.cpp /FeDebug/vulkan_example.exe /FoDebug/ /link /LIBPATH:..\libs\glfw\lib-vc2010-32 /libpath:%VULKAN_SDK%\bin32 glfw3.lib opengl32.lib gdi32.lib shell32.lib vulkan-1.lib +cl /nologo /Zi /MD /I ..\.. /I ..\libs\glfw\include /I %VULKAN_SDK%\include *.cpp ..\..\*.cpp /FeDebug/vulkan_example.exe /FoDebug/ /link /LIBPATH:..\libs\glfw\lib-vc2010-32 /libpath:%VULKAN_SDK%\lib32 glfw3.lib opengl32.lib gdi32.lib shell32.lib vulkan-1.lib diff --git a/examples/vulkan_example/build_win64.bat b/examples/vulkan_example/build_win64.bat index a8c05a55..83ecf5a1 100644 --- a/examples/vulkan_example/build_win64.bat +++ b/examples/vulkan_example/build_win64.bat @@ -1,4 +1,4 @@ @REM Build for Visual Studio compiler. Run your copy of amd64/vcvars32.bat to setup 64-bit command-line compiler. mkdir Debug -cl /nologo /Zi /MD /I ..\.. /I ..\libs\glfw\include /I %VULKAN_SDK%\include *.cpp ..\..\*.cpp /FeDebug/vulkan_example.exe /FoDebug/ /link /LIBPATH:..\libs\glfw\lib-vc2010-64 /libpath:%VULKAN_SDK%\bin glfw3.lib opengl32.lib gdi32.lib shell32.lib vulkan-1.lib +cl /nologo /Zi /MD /I ..\.. /I ..\libs\glfw\include /I %VULKAN_SDK%\include *.cpp ..\..\*.cpp /FeDebug/vulkan_example.exe /FoDebug/ /link /LIBPATH:..\libs\glfw\lib-vc2010-64 /libpath:%VULKAN_SDK%\lib glfw3.lib opengl32.lib gdi32.lib shell32.lib vulkan-1.lib diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index 2ca245d8..7b2d8571 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -13,7 +13,7 @@ #define IMGUI_MAX_POSSIBLE_BACK_BUFFERS 16 #define IMGUI_UNLIMITED_FRAME_RATE -#define IMGUI_VULKAN_DEBUG_REPORT +//#define IMGUI_VULKAN_DEBUG_REPORT static VkAllocationCallbacks* g_Allocator = NULL; static VkInstance g_Instance = VK_NULL_HANDLE; @@ -233,7 +233,7 @@ static void setup_vulkan(GLFWwindow* window) extensions[ extensions_count ] = "VK_EXT_debug_report"; create_info.enabledExtensionCount = extensions_count+1; create_info.ppEnabledExtensionNames = extensions; -#elif +#else create_info.enabledExtensionCount = extensions_count; create_info.ppEnabledExtensionNames = glfw_extensions; #endif // IMGUI_VULKAN_DEBUG_REPORT From 33874073dc3275a7d99e20c9986d39998328b62f Mon Sep 17 00:00:00 2001 From: Peter Particle Date: Sun, 26 Feb 2017 17:31:02 +0100 Subject: [PATCH 14/26] Fixed all issues found by vulkan debug report. Reasons for the major design changes are commented. --- examples/vulkan_example/main.cpp | 118 ++++++++++++++++++++++++------- 1 file changed, 93 insertions(+), 25 deletions(-) diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index 7b2d8571..10755706 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -26,10 +26,9 @@ static uint32_t g_QueueFamily = 0; static VkQueue g_Queue = VK_NULL_HANDLE; static VkDebugReportCallbackEXT g_Debug_Report = VK_NULL_HANDLE; -static VkFormat g_ImageFormat = VK_FORMAT_B8G8R8A8_UNORM; -static VkFormat g_ViewFormat = VK_FORMAT_B8G8R8A8_UNORM; -static VkColorSpaceKHR g_ColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; +static VkSurfaceFormatKHR g_SurfaceFormat; static VkImageSubresourceRange g_ImageRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; +static VkPresentModeKHR g_PresentMode; static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; @@ -79,19 +78,14 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) VkSwapchainCreateInfoKHR info = {}; info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; info.surface = g_Surface; - info.imageFormat = g_ImageFormat; - info.imageColorSpace = g_ColorSpace; + info.imageFormat = g_SurfaceFormat.format; + info.imageColorSpace = g_SurfaceFormat.colorSpace; info.imageArrayLayers = 1; info.imageUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - -#ifdef IMGUI_UNLIMITED_FRAME_RATE - info.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; -#else - info.presentMode = VK_PRESENT_MODE_FIFO_KHR; -#endif // IMGUI_UNLIMITED_FRAME_RATE + info.presentMode = g_PresentMode; info.clipped = VK_TRUE; info.oldSwapchain = old_swapchain; VkSurfaceCapabilitiesKHR cap; @@ -129,7 +123,7 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) // Create the Render Pass: { VkAttachmentDescription attachment = {}; - attachment.format = g_ViewFormat; + attachment.format = g_SurfaceFormat.format; attachment.samples = VK_SAMPLE_COUNT_1_BIT; attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -159,7 +153,7 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) VkImageViewCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; info.viewType = VK_IMAGE_VIEW_TYPE_2D; - info.format = g_ViewFormat; + info.format = g_SurfaceFormat.format; info.components.r = VK_COMPONENT_SWIZZLE_R; info.components.g = VK_COMPONENT_SWIZZLE_G; info.components.b = VK_COMPONENT_SWIZZLE_B; @@ -228,7 +222,7 @@ static void setup_vulkan(GLFWwindow* window) // need additional storage for char pointer to debug report extension const char** extensions = (const char**)malloc(sizeof(const char*) * (extensions_count + 1)); - for(size_t i = 0; i < extensions_count; i++) + for (size_t i = 0; i < extensions_count; i++) extensions[i] = glfw_extensions[i]; extensions[ extensions_count ] = "VK_EXT_debug_report"; create_info.enabledExtensionCount = extensions_count+1; @@ -266,11 +260,26 @@ static void setup_vulkan(GLFWwindow* window) check_vk_result(err); } - // Get GPU (WARNING here we assume the first gpu is one we can use) + // Get GPU { - uint32_t count = 1; - err = vkEnumeratePhysicalDevices(g_Instance, &count, &g_Gpu); + uint32_t gpu_count; + err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, NULL); check_vk_result(err); + + if( gpu_count == 1 ) { // only one gpu, assume it has a graphics queue family and use it + err = vkEnumeratePhysicalDevices( g_Instance, &gpu_count, &g_Gpu ); + check_vk_result( err ); + } else { + VkPhysicalDevice* gpus = (VkPhysicalDevice*)malloc(sizeof(VkPhysicalDevice) * gpu_count); + err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus); + check_vk_result(err); + + // here 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_Gpu = gpus[0]; + free(gpus); + } } // Get queue @@ -303,26 +312,85 @@ static void setup_vulkan(GLFWwindow* window) // Get Surface Format { - VkFormat image_view_format[][2] = {{VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM}, {VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM}}; + // Per Spec Format and View Format are expected to be the same unless VK_IMAGE_CREATE_MUTABLE_BIT was set at image creation + // Assuming that the default behaviour is without setting this bit, there is no need for seperate Spapchain image and image view format + // additionally severeal new color spaces were introduced with Vulkan Spec v1.0.40 + // hence we must make sure that a format with the mostly available color space, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, is found and used uint32_t count; vkGetPhysicalDeviceSurfaceFormatsKHR(g_Gpu, g_Surface, &count, NULL); VkSurfaceFormatKHR *formats = (VkSurfaceFormatKHR*)malloc(sizeof(VkSurfaceFormatKHR) * count); vkGetPhysicalDeviceSurfaceFormatsKHR(g_Gpu, g_Surface, &count, formats); - for (size_t i = 0; i < sizeof(image_view_format) / sizeof(image_view_format[0]); i++) + + // first check if only one format, VK_FORMAT_UNDEFINED, is available, which would imply that any format is available + if (count == 1) { - for (uint32_t j = 0; j < count; j++) + if( formats[0].format == VK_FORMAT_UNDEFINED ) { - if (formats[j].format == image_view_format[i][0]) - { - g_ImageFormat = image_view_format[i][0]; - g_ViewFormat = image_view_format[i][1]; - g_ColorSpace = formats[j].colorSpace; + g_SurfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM; + g_SurfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + } + else + { // no point in searching another format + g_SurfaceFormat = formats[0]; + } + } + else + { + // request several formats, the first found will be used + VkFormat requestSurfaceImageFormat[] = {VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM}; + VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + bool requestedFound = false; + for (size_t i = 0; i < sizeof(requestSurfaceImageFormat) / sizeof(requestSurfaceImageFormat[0]); i++) + { + if( requestedFound ) { + break; } + for (uint32_t j = 0; j < count; j++) + { + if (formats[j].format == requestSurfaceImageFormat[i] && formats[j].colorSpace == requestSurfaceColorSpace) + { + g_SurfaceFormat = formats[j]; + requestedFound = true; + } + } + } + + // if none of the requested image formats could be found, use the first available + if (!requestedFound) + { + g_SurfaceFormat = formats[0]; } } free(formats); } + + // Get Present Mode + { + // Requst a certain mode and confirm that it is available. If not use VK_PRESENT_MODE_FIFO_KHR which is mandatory +#ifdef IMGUI_UNLIMITED_FRAME_RATE + g_PresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; +#else + g_PresentMode = VK_PRESENT_MODE_FIFO_KHR; +#endif + uint32_t count = 0; + vkGetPhysicalDeviceSurfacePresentModesKHR( g_Gpu, g_Surface, &count, nullptr ); + VkPresentModeKHR* presentModes = ( VkPresentModeKHR* )malloc( sizeof( VkQueueFamilyProperties ) * count ); + vkGetPhysicalDeviceSurfacePresentModesKHR( g_Gpu, g_Surface, &count, presentModes ); + bool presentModeAvailable = false; + for (size_t i = 0; i < count; i++) + { + if (presentModes[i] == g_PresentMode) + { + presentModeAvailable = true; + break; + } + } + if( !presentModeAvailable ) + g_PresentMode = VK_PRESENT_MODE_FIFO_KHR; // allways available + } + + // Create Logical Device { int device_extension_count = 1; From eaae754211dbc92e583e24666253b62c2f5d0e1d Mon Sep 17 00:00:00 2001 From: Peter Particle Date: Sun, 26 Feb 2017 17:58:02 +0100 Subject: [PATCH 15/26] Removed redundant barrier. The transition of the swapchain image(s) can happen implicitly in the renderpass. This approach has been stated to be more efficient than using an explicit barrier. See "Vulkan Programming Guide", Chapter 7: "Graphics Pipelines", section "Renderpasses". --- examples/vulkan_example/main.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index 10755706..4240ffce 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -130,7 +130,7 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachment.finalLayout = VK_IMAGE_LAYOUT_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; @@ -554,19 +554,6 @@ static void frame_end() { VkResult err; vkCmdEndRenderPass(g_CommandBuffer[g_FrameIndex]); - { - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = g_BackBuffer[g_BackBufferIndex]; - barrier.subresourceRange = g_ImageRange; - vkCmdPipelineBarrier(g_CommandBuffer[g_FrameIndex], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); - } { VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo info = {}; From a9add1ce63089f6e16e5f3c91cda101337153987 Mon Sep 17 00:00:00 2001 From: Peter Particle Date: Mon, 27 Feb 2017 14:50:10 +0100 Subject: [PATCH 16/26] Removed redundant VkResult plugged into VkPresentInfoKHR pResults attribute. This is only meaningful when we present directly to multiple swapchains. In that case we can an VkResult per swapchain. --- examples/vulkan_example/main.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index 4240ffce..957afc43 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -572,7 +572,6 @@ static void frame_end() check_vk_result(err); } { - VkResult res; VkSwapchainKHR swapchains[1] = {g_Swapchain}; uint32_t indices[1] = {g_BackBufferIndex}; VkPresentInfoKHR info = {}; @@ -580,10 +579,8 @@ static void frame_end() info.swapchainCount = 1; info.pSwapchains = swapchains; info.pImageIndices = indices; - info.pResults = &res; err = vkQueuePresentKHR(g_Queue, &info); check_vk_result(err); - check_vk_result(res); } g_FrameIndex = (g_FrameIndex+1) % IMGUI_VK_QUEUED_FRAMES; } From 201d589714c6ef7ff40c87140818a2208b8686b7 Mon Sep 17 00:00:00 2001 From: Peter Particle Date: Mon, 27 Feb 2017 15:05:08 +0100 Subject: [PATCH 17/26] Image presentation now depends on the completeness of command buffer submission through semaphores. To maintain maximum frame rate we render to the last acquired swapchain image but present the last but one drawn image. This behavior is optional through conditional compilation macros. --- examples/vulkan_example/main.cpp | 73 +++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index 957afc43..f3a86e0e 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -13,7 +13,9 @@ #define IMGUI_MAX_POSSIBLE_BACK_BUFFERS 16 #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; @@ -34,7 +36,7 @@ static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; static int fb_width, fb_height; -static uint32_t g_BackBufferIndex = 0; +static uint32_t g_BackbufferIndices[IMGUI_VK_QUEUED_FRAMES]; // keep track of recently rendered swapchain frame indices static uint32_t g_BackBufferCount = 0; static VkImage g_BackBuffer[IMGUI_MAX_POSSIBLE_BACK_BUFFERS] = {}; static VkImageView g_BackBufferView[IMGUI_MAX_POSSIBLE_BACK_BUFFERS] = {}; @@ -44,7 +46,8 @@ static uint32_t g_FrameIndex = 0; static VkCommandPool g_CommandPool[IMGUI_VK_QUEUED_FRAMES]; static VkCommandBuffer g_CommandBuffer[IMGUI_VK_QUEUED_FRAMES]; static VkFence g_Fence[IMGUI_VK_QUEUED_FRAMES]; -static VkSemaphore g_Semaphore[IMGUI_VK_QUEUED_FRAMES]; +static VkSemaphore g_PresentCompleteSemaphore[IMGUI_VK_QUEUED_FRAMES]; +static VkSemaphore g_RenderCompleteSemaphore[IMGUI_VK_QUEUED_FRAMES]; static VkClearValue g_ClearValue = {}; @@ -452,7 +455,9 @@ static void setup_vulkan(GLFWwindow* window) { VkSemaphoreCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - err = vkCreateSemaphore(g_Device, &info, g_Allocator, &g_Semaphore[i]); + err = vkCreateSemaphore(g_Device, &info, g_Allocator, &g_PresentCompleteSemaphore[i]); + check_vk_result(err); + err = vkCreateSemaphore(g_Device, &info, g_Allocator, &g_RenderCompleteSemaphore[i]); check_vk_result(err); } } @@ -492,7 +497,8 @@ static void cleanup_vulkan() vkDestroyFence(g_Device, g_Fence[i], g_Allocator); vkFreeCommandBuffers(g_Device, g_CommandPool[i], 1, &g_CommandBuffer[i]); vkDestroyCommandPool(g_Device, g_CommandPool[i], g_Allocator); - vkDestroySemaphore(g_Device, g_Semaphore[i], g_Allocator); + vkDestroySemaphore(g_Device, g_PresentCompleteSemaphore[i], g_Allocator); + vkDestroySemaphore(g_Device, g_RenderCompleteSemaphore[i], g_Allocator); } for (uint32_t i = 0; i < g_BackBufferCount; i++) { @@ -525,7 +531,7 @@ static void frame_begin() check_vk_result(err); } { - err = vkAcquireNextImageKHR(g_Device, g_Swapchain, UINT64_MAX, g_Semaphore[g_FrameIndex], VK_NULL_HANDLE, &g_BackBufferIndex); + err = vkAcquireNextImageKHR(g_Device, g_Swapchain, UINT64_MAX, g_PresentCompleteSemaphore[g_FrameIndex], VK_NULL_HANDLE, &g_BackbufferIndices[g_FrameIndex]); check_vk_result(err); } { @@ -541,7 +547,7 @@ static void frame_begin() VkRenderPassBeginInfo info = {}; info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; info.renderPass = g_RenderPass; - info.framebuffer = g_Framebuffer[g_BackBufferIndex]; + info.framebuffer = g_Framebuffer[g_BackbufferIndices[g_FrameIndex]]; info.renderArea.extent.width = fb_width; info.renderArea.extent.height = fb_height; info.clearValueCount = 1; @@ -559,10 +565,12 @@ static void frame_end() VkSubmitInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; info.waitSemaphoreCount = 1; - info.pWaitSemaphores = &g_Semaphore[g_FrameIndex]; + info.pWaitSemaphores = &g_PresentCompleteSemaphore[g_FrameIndex]; info.pWaitDstStageMask = &wait_stage; info.commandBufferCount = 1; info.pCommandBuffers = &g_CommandBuffer[g_FrameIndex]; + info.signalSemaphoreCount = 1; + info.pSignalSemaphores = &g_RenderCompleteSemaphore[g_FrameIndex]; err = vkEndCommandBuffer(g_CommandBuffer[g_FrameIndex]); check_vk_result(err); @@ -571,18 +579,32 @@ static void frame_end() err = vkQueueSubmit(g_Queue, 1, &info, g_Fence[g_FrameIndex]); check_vk_result(err); } - { - VkSwapchainKHR swapchains[1] = {g_Swapchain}; - uint32_t indices[1] = {g_BackBufferIndex}; - VkPresentInfoKHR info = {}; - info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - info.swapchainCount = 1; - info.pSwapchains = swapchains; - info.pImageIndices = indices; - err = vkQueuePresentKHR(g_Queue, &info); - check_vk_result(err); - } - g_FrameIndex = (g_FrameIndex+1) % IMGUI_VK_QUEUED_FRAMES; +} + +static void frame_present() +{ + VkResult err; +// If IMGUI_UNLIMITED_FRAME_RATE is defined we present the latest but one frame +// Othrewise we present the latest rendered frame +#ifdef IMGUI_UNLIMITED_FRAME_RATE + uint32_t PresentIndex = (g_FrameIndex + IMGUI_VK_QUEUED_FRAMES - 1) % IMGUI_VK_QUEUED_FRAMES; +#else + uint32_t PresentIndex = g_FrameIndex; +#endif // IMGUI_UNLIMITED_FRAME_RATE + + VkSwapchainKHR swapchains[1] = {g_Swapchain}; + uint32_t indices[1] = {g_BackbufferIndices[PresentIndex]}; + VkPresentInfoKHR info = {}; + info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + info.waitSemaphoreCount = 1; + info.pWaitSemaphores = &g_RenderCompleteSemaphore[PresentIndex]; + info.swapchainCount = 1; + info.pSwapchains = swapchains; + info.pImageIndices = indices; + err = vkQueuePresentKHR(g_Queue, &info); + check_vk_result(err); + + g_FrameIndex = (g_FrameIndex + 1) % IMGUI_VK_QUEUED_FRAMES; } static void error_callback(int error, const char* description) @@ -660,6 +682,18 @@ int main(int, char**) bool show_another_window = false; ImVec4 clear_color = ImColor(114, 144, 154); + // When IMGUI_UNLIMITED_FRAME_RATE is defined we render into latest image acquired from the swapchain + // but we display the image which was rendered before + // hence we must render once and increase the g_FrameIndex without presenting, which we do befor entering the render loop + // this is also the reason why frame_end() is split into frame_end() and frame_present(), the latter one not being called here +#ifdef IMGUI_UNLIMITED_FRAME_RATE + ImGui_ImplGlfwVulkan_NewFrame(); + frame_begin(); + ImGui_ImplGlfwVulkan_Render(g_CommandBuffer[g_FrameIndex]); + frame_end(); + g_FrameIndex = (g_FrameIndex + 1) % IMGUI_VK_QUEUED_FRAMES; +#endif // IMGUI_UNLIMITED_FRAME_RATE + // Main loop while (!glfwWindowShouldClose(window)) { @@ -702,6 +736,7 @@ int main(int, char**) frame_begin(); ImGui_ImplGlfwVulkan_Render(g_CommandBuffer[g_FrameIndex]); frame_end(); + frame_present(); } // Cleanup From f87b1525220254f6b1ad60ff6f5a6fa3ae5a8bd0 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 1 May 2017 17:07:05 +0200 Subject: [PATCH 18/26] Examples: Vulkan: Various very minor stylistic fixes, fixing typos in comments, etc. (#1042 #1043) --- examples/vulkan_example/main.cpp | 67 ++++++++++++-------------------- 1 file changed, 25 insertions(+), 42 deletions(-) diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index f3a86e0e..26539269 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -192,16 +192,9 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) #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) + VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) { - printf( "ObjectType : %i\nMessage : %s\n\n", objectType, pMessage ); + printf("[vulkan] ObjectType: %i\nMessage: %s\n\n", objectType, pMessage ); return VK_FALSE; } #endif // IMGUI_VULKAN_DEBUG_REPORT @@ -217,6 +210,9 @@ static void setup_vulkan(GLFWwindow* window) VkInstanceCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + create_info.enabledExtensionCount = extensions_count; + create_info.ppEnabledExtensionNames = glfw_extensions; + #ifdef IMGUI_VULKAN_DEBUG_REPORT // enabling multiple validation layers grouped as lunarg standard validation const char* layers[] = {"VK_LAYER_LUNARG_standard_validation"}; @@ -230,9 +226,6 @@ static void setup_vulkan(GLFWwindow* window) extensions[ extensions_count ] = "VK_EXT_debug_report"; create_info.enabledExtensionCount = extensions_count+1; create_info.ppEnabledExtensionNames = extensions; -#else - create_info.enabledExtensionCount = extensions_count; - create_info.ppEnabledExtensionNames = glfw_extensions; #endif // IMGUI_VULKAN_DEBUG_REPORT err = vkCreateInstance(&create_info, g_Allocator, &g_Instance); @@ -253,7 +246,7 @@ static void setup_vulkan(GLFWwindow* window) (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkCreateDebugReportCallbackEXT"); err = vkCreateDebugReportCallbackEXT( g_Instance, &debug_report_ci, g_Allocator, &g_Debug_Report ); - check_vk_result( err ); + check_vk_result(err); #endif // IMGUI_VULKAN_DEBUG_REPORT } @@ -269,20 +262,15 @@ static void setup_vulkan(GLFWwindow* window) err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, NULL); check_vk_result(err); - if( gpu_count == 1 ) { // only one gpu, assume it has a graphics queue family and use it - err = vkEnumeratePhysicalDevices( g_Instance, &gpu_count, &g_Gpu ); - check_vk_result( err ); - } else { - VkPhysicalDevice* gpus = (VkPhysicalDevice*)malloc(sizeof(VkPhysicalDevice) * gpu_count); - err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus); - check_vk_result(err); + VkPhysicalDevice* gpus = (VkPhysicalDevice*)malloc(sizeof(VkPhysicalDevice) * gpu_count); + err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus); + check_vk_result(err); - // here 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_Gpu = gpus[0]; - free(gpus); - } + // 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_Gpu = gpus[0]; + free(gpus); } // Get queue @@ -316,8 +304,8 @@ static void setup_vulkan(GLFWwindow* window) // Get Surface Format { // Per Spec Format and View Format are expected to be the same unless VK_IMAGE_CREATE_MUTABLE_BIT was set at image creation - // Assuming that the default behaviour is without setting this bit, there is no need for seperate Spapchain image and image view format - // additionally severeal new color spaces were introduced with Vulkan Spec v1.0.40 + // Assuming that the default behavior is without setting this bit, there is no need for separate Spawchain image and image view format + // additionally several new color spaces were introduced with Vulkan Spec v1.0.40 // hence we must make sure that a format with the mostly available color space, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, is found and used uint32_t count; vkGetPhysicalDeviceSurfaceFormatsKHR(g_Gpu, g_Surface, &count, NULL); @@ -360,9 +348,7 @@ static void setup_vulkan(GLFWwindow* window) // if none of the requested image formats could be found, use the first available if (!requestedFound) - { g_SurfaceFormat = formats[0]; - } } free(formats); } @@ -377,9 +363,9 @@ static void setup_vulkan(GLFWwindow* window) g_PresentMode = VK_PRESENT_MODE_FIFO_KHR; #endif uint32_t count = 0; - vkGetPhysicalDeviceSurfacePresentModesKHR( g_Gpu, g_Surface, &count, nullptr ); - VkPresentModeKHR* presentModes = ( VkPresentModeKHR* )malloc( sizeof( VkQueueFamilyProperties ) * count ); - vkGetPhysicalDeviceSurfacePresentModesKHR( g_Gpu, g_Surface, &count, presentModes ); + vkGetPhysicalDeviceSurfacePresentModesKHR(g_Gpu, g_Surface, &count, nullptr); + VkPresentModeKHR* presentModes = (VkPresentModeKHR*)malloc(sizeof(VkQueueFamilyProperties) * count); + vkGetPhysicalDeviceSurfacePresentModesKHR(g_Gpu, g_Surface, &count, presentModes); bool presentModeAvailable = false; for (size_t i = 0; i < count; i++) { @@ -390,7 +376,7 @@ static void setup_vulkan(GLFWwindow* window) } } if( !presentModeAvailable ) - g_PresentMode = VK_PRESENT_MODE_FIFO_KHR; // allways available + g_PresentMode = VK_PRESENT_MODE_FIFO_KHR; // always available } @@ -511,8 +497,7 @@ static void cleanup_vulkan() #ifdef IMGUI_VULKAN_DEBUG_REPORT // get the proc address of the function pointer, required for used extensions - auto vkDestroyDebugReportCallbackEXT = - (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT"); + auto vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT"); vkDestroyDebugReportCallbackEXT(g_Instance, g_Debug_Report, g_Allocator); #endif // IMGUI_VULKAN_DEBUG_REPORT @@ -584,8 +569,7 @@ static void frame_end() static void frame_present() { VkResult err; -// If IMGUI_UNLIMITED_FRAME_RATE is defined we present the latest but one frame -// Othrewise we present the latest rendered frame + // If IMGUI_UNLIMITED_FRAME_RATE is defined we present the latest but one frame. Otherwise we present the latest rendered frame #ifdef IMGUI_UNLIMITED_FRAME_RATE uint32_t PresentIndex = (g_FrameIndex + IMGUI_VK_QUEUED_FRAMES - 1) % IMGUI_VK_QUEUED_FRAMES; #else @@ -682,10 +666,9 @@ int main(int, char**) bool show_another_window = false; ImVec4 clear_color = ImColor(114, 144, 154); - // When IMGUI_UNLIMITED_FRAME_RATE is defined we render into latest image acquired from the swapchain - // but we display the image which was rendered before - // hence we must render once and increase the g_FrameIndex without presenting, which we do befor entering the render loop - // this is also the reason why frame_end() is split into frame_end() and frame_present(), the latter one not being called here + // When IMGUI_UNLIMITED_FRAME_RATE is defined we render into latest image acquired from the swapchain but we display the image which was rendered before. + // Hence we must render once and increase the g_FrameIndex without presenting, which we do before entering the render loop. + // This is also the reason why frame_end() is split into frame_end() and frame_present(), the later one not being called here. #ifdef IMGUI_UNLIMITED_FRAME_RATE ImGui_ImplGlfwVulkan_NewFrame(); frame_begin(); From b0db625cab7ef9fb2791504710a3b912ffc2ee33 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 1 May 2017 17:07:53 +0200 Subject: [PATCH 19/26] Examples: Vulkan: Fixed an extra validation (tested on Windows with VulkanSDK 1.0.46.0) (#1042) --- examples/vulkan_example/imgui_impl_glfw_vulkan.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index e5bc426a..d43929f6 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -541,6 +541,7 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; info.minLod = -1000; info.maxLod = 1000; + info.maxAnisotropy = 1.0f; err = vkCreateSampler(g_Device, &info, g_Allocator, &g_FontSampler); ImGui_ImplGlfwVulkan_VkResult(err); } From 9614552ebaca1729e82524b70ea14304f1dc5a35 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 1 May 2017 17:16:40 +0200 Subject: [PATCH 20/26] README.md added link to Nicolas Guillemot flashtalk (#1099) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b10c3f92..4fdad38d 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,7 @@ The Immediate Mode GUI paradigm may at first appear unusual to some users. This - [A presentation by Rickard Gustafsson and Johannes Algelind](http://www.cse.chalmers.se/edu/year/2011/course/TDA361/Advanced%20Computer%20Graphics/IMGUI.pdf). - [Jari Komppa's tutorial on building an ImGui library](http://iki.fi/sol/imgui/). - [Casey Muratori's original video that popularized the concept](https://mollyrocket.com/861). +- [Nicolas Guillemot's CppCon'16 flashtalk about Dear ImGui](https://www.youtube.com/watch?v=LSRJ1jZq90k). See the [Links page](https://github.com/ocornut/imgui/wiki/Links) for third-party bindings to different languages and frameworks. From df52f46b13891acf6298a6a783d7f024ccd9ab21 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 2 May 2017 10:43:00 +0200 Subject: [PATCH 21/26] Comments, documentation (#1121) --- extra_fonts/README.txt | 4 +++- extra_fonts/binary_to_compressed_c.cpp | 13 +++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/extra_fonts/README.txt b/extra_fonts/README.txt index 60d33e2e..8df8340a 100644 --- a/extra_fonts/README.txt +++ b/extra_fonts/README.txt @@ -96,7 +96,9 @@ EMBEDDING FONT IN SOURCE CODE --------------------------------- - Compile and use 'binary_to_compressed_c.cpp' to create a compressed C style array. Then load the font with: + Compile and use 'binary_to_compressed_c.cpp' to create a compressed C style array. + See the documentation in binary_to_compressed_c.cpp for instruction on how to use the tool. + Then load the font with: ImFont* font = io.Fonts->AddFontFromMemoryCompressedTTF(compressed_data, compressed_data_size, size_pixels, ...); diff --git a/extra_fonts/binary_to_compressed_c.cpp b/extra_fonts/binary_to_compressed_c.cpp index 79beaad6..ee160a42 100644 --- a/extra_fonts/binary_to_compressed_c.cpp +++ b/extra_fonts/binary_to_compressed_c.cpp @@ -7,12 +7,17 @@ // Note that even with compression, the output array is likely to be bigger than the binary file.. // Load compressed TTF fonts with ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF() -// Single file application, build with: -// # cl.exe binary_to_compressed_c.cpp -// # gcc binary_to_compressed_c.cpp -// etc. +// Build with, e.g: +// # cl.exe binary_to_compressed_c.cpp +// # gcc binary_to_compressed_c.cpp // You can also find a precompiled Windows binary in the binary/demo package available from https://github.com/ocornut/imgui +// Usage: +// binary_to_compressed_c.exe [-base85] [-nocompress] +// Usage example: +// # binary_to_compressed_c.exe myfont.ttf MyFont > myfont.cpp +// # binary_to_compressed_c.exe -base85 myfont.ttf MyFont > myfont.cpp + #define _CRT_SECURE_NO_WARNINGS #include #include From bd9868f447b18e811fa76415aa2d55677955daa6 Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 13 May 2017 20:25:09 +0200 Subject: [PATCH 22/26] Scrollbar: Avoid rendering when sizes are negative to reduce glitches (not sure how this ever slipped through - perhaps because of WindowMinSize settings). --- imgui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index b5b8a747..5b1d4f22 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4474,6 +4474,8 @@ static void Scrollbar(ImGuiWindow* window, bool horizontal) : ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + border_size, window_rect.Max.x - border_size, window_rect.Max.y - other_scrollbar_size_w - border_size); if (!horizontal) bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f); + if (bb.GetWidth() <= 0.0f || bb.GetHeight() <= 0.0f) + return; float window_rounding = (window->Flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding; int window_rounding_corners; From 0828a1fd6c0ee7d53d4a7013a56002aaffc86896 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 14 May 2017 16:27:10 +0200 Subject: [PATCH 23/26] Fixed computation of ImFont::MetricsTotalSurface not taking oversampling into account --- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b8f4478e..b503146c 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1752,7 +1752,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SameLine(); ShowHelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)"); ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar); - ImGui::Text("Texture surface: %d pixels (approx)", font->MetricsTotalSurface); + ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)sqrtf((int)font->MetricsTotalSurface), (int)sqrtf((int)font->MetricsTotalSurface)); for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) { ImFontConfig* cfg = &font->ConfigData[config_i]; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 87b60c7d..fa7cac52 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1456,7 +1456,7 @@ bool ImFontAtlas::Build() glyph.XAdvance = (pc.xadvance + cfg.GlyphExtraSpacing.x); // Bake spacing into XAdvance if (cfg.PixelSnapH) glyph.XAdvance = (float)(int)(glyph.XAdvance + 0.5f); - dst_font->MetricsTotalSurface += (int)(glyph.X1 - glyph.X0 + 1.99f) * (int)(glyph.Y1 - glyph.Y0 + 1.99f); // +1 to account for average padding, +0.99 to round + dst_font->MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * TexWidth + 1.99f) * (int)((glyph.V1 - glyph.V0) * TexHeight + 1.99f); // +1 to account for average padding, +0.99 to round } } cfg.DstFont->BuildLookupTable(); From c5c77a347636134ea33257b030a775e9a0563ce0 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 26 May 2017 13:36:52 +0200 Subject: [PATCH 24/26] ImFontConfig: Added GlyphOffset to explicitely offset glyphs at font build time, useful for merged fonts. May remove MergeGlyphCenterV soon. --- imgui.h | 3 ++- imgui_draw.cpp | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/imgui.h b/imgui.h index d77c56c0..92e07c58 100644 --- a/imgui.h +++ b/imgui.h @@ -1270,9 +1270,10 @@ struct ImFontConfig int OversampleH, OversampleV; // 3, 1 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs + ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input const ImWchar* GlyphRanges; // // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). - bool MergeGlyphCenterV; // false // When merging (multiple ImFontInput for one ImFont), vertically center new glyphs instead of aligning their baseline + bool MergeGlyphCenterV; // false // When merging (multiple ImFontInput for one ImFont), vertically center new glyphs instead of aligning their baseline. Prefer using an explicit GlyphOffset.y setting instead, may obsolete MergeGlyphCenterV. // [Internal] char Name[32]; // Name (strictly for debugging) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index fa7cac52..c7bc928c 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1043,6 +1043,7 @@ ImFontConfig::ImFontConfig() OversampleV = 1; PixelSnapH = false; GlyphExtraSpacing = ImVec2(0.0f, 0.0f); + GlyphOffset = ImVec2(0.0f, 0.0f); GlyphRanges = NULL; MergeMode = false; MergeGlyphCenterV = false; @@ -1426,7 +1427,8 @@ bool ImFontAtlas::Build() dst_font->MetricsTotalSurface = 0; } dst_font->ConfigDataCount++; - float off_y = (cfg.MergeMode && cfg.MergeGlyphCenterV) ? (ascent - dst_font->Ascent) * 0.5f : 0.0f; + float off_x = cfg.GlyphOffset.x, off_y = cfg.GlyphOffset.y; + float merge_off_y = (cfg.MergeMode && cfg.MergeGlyphCenterV) ? (ascent - dst_font->Ascent) * 0.5f : 0.0f; dst_font->FallbackGlyph = NULL; // Always clear fallback so FindGlyph can return NULL. It will be set again in BuildLookupTable() for (int i = 0; i < tmp.RangesCount; i++) @@ -1449,10 +1451,10 @@ bool ImFontAtlas::Build() dst_font->Glyphs.resize(dst_font->Glyphs.Size + 1); ImFont::Glyph& glyph = dst_font->Glyphs.back(); glyph.Codepoint = (ImWchar)codepoint; - glyph.X0 = q.x0; glyph.Y0 = q.y0; glyph.X1 = q.x1; glyph.Y1 = q.y1; + glyph.X0 = q.x0 + off_x; glyph.Y0 = q.y0 + off_y; glyph.X1 = q.x1 + off_x; glyph.Y1 = q.y1 + off_y; glyph.U0 = q.s0; glyph.V0 = q.t0; glyph.U1 = q.s1; glyph.V1 = q.t1; - glyph.Y0 += (float)(int)(dst_font->Ascent + off_y + 0.5f); - glyph.Y1 += (float)(int)(dst_font->Ascent + off_y + 0.5f); + glyph.Y0 += (float)(int)(dst_font->Ascent + merge_off_y + 0.5f); + glyph.Y1 += (float)(int)(dst_font->Ascent + merge_off_y + 0.5f); glyph.XAdvance = (pc.xadvance + cfg.GlyphExtraSpacing.x); // Bake spacing into XAdvance if (cfg.PixelSnapH) glyph.XAdvance = (float)(int)(glyph.XAdvance + 0.5f); From 026d021df166fe93f5560ecf2b58188556c75110 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 26 May 2017 13:40:53 +0200 Subject: [PATCH 25/26] Demo: Fixed warnings introduced in 0828a1fd6c0ee7d53d4a7013a56002aaffc86896 --- imgui_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b503146c..5f0d45b2 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1752,7 +1752,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SameLine(); ShowHelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)"); ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar); - ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)sqrtf((int)font->MetricsTotalSurface), (int)sqrtf((int)font->MetricsTotalSurface)); + ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)sqrtf((float)font->MetricsTotalSurface), (int)sqrtf((float)font->MetricsTotalSurface)); for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) { ImFontConfig* cfg = &font->ConfigData[config_i]; From 9da53bcecdc2273fef86f032ad55c36393c38ebd Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 26 May 2017 13:42:36 +0200 Subject: [PATCH 26/26] ImFontConfig: Removed MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. (Breaking change) --- imgui.cpp | 3 ++- imgui.h | 3 +-- imgui_draw.cpp | 9 ++++----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5b1d4f22..4fc6a9da 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -152,7 +152,8 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. - - 2017/05/01 (1.50) - Renamed ImDrawList::PathFill() to ImDrawList::PathFillConvex() for clarity. + - 2017/05/26 (1.50) - Removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. + - 2017/05/01 (1.50) - Renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity. - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild(). - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. diff --git a/imgui.h b/imgui.h index 92e07c58..63efc637 100644 --- a/imgui.h +++ b/imgui.h @@ -1272,8 +1272,7 @@ struct ImFontConfig ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input const ImWchar* GlyphRanges; // // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. - bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). - bool MergeGlyphCenterV; // false // When merging (multiple ImFontInput for one ImFont), vertically center new glyphs instead of aligning their baseline. Prefer using an explicit GlyphOffset.y setting instead, may obsolete MergeGlyphCenterV. + bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. // [Internal] char Name[32]; // Name (strictly for debugging) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c7bc928c..ca500d4e 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1046,7 +1046,6 @@ ImFontConfig::ImFontConfig() GlyphOffset = ImVec2(0.0f, 0.0f); GlyphRanges = NULL; MergeMode = false; - MergeGlyphCenterV = false; DstFont = NULL; memset(Name, 0, sizeof(Name)); } @@ -1427,8 +1426,8 @@ bool ImFontAtlas::Build() dst_font->MetricsTotalSurface = 0; } dst_font->ConfigDataCount++; - float off_x = cfg.GlyphOffset.x, off_y = cfg.GlyphOffset.y; - float merge_off_y = (cfg.MergeMode && cfg.MergeGlyphCenterV) ? (ascent - dst_font->Ascent) * 0.5f : 0.0f; + float off_x = cfg.GlyphOffset.x; + float off_y = cfg.GlyphOffset.y; dst_font->FallbackGlyph = NULL; // Always clear fallback so FindGlyph can return NULL. It will be set again in BuildLookupTable() for (int i = 0; i < tmp.RangesCount; i++) @@ -1453,8 +1452,8 @@ bool ImFontAtlas::Build() glyph.Codepoint = (ImWchar)codepoint; glyph.X0 = q.x0 + off_x; glyph.Y0 = q.y0 + off_y; glyph.X1 = q.x1 + off_x; glyph.Y1 = q.y1 + off_y; glyph.U0 = q.s0; glyph.V0 = q.t0; glyph.U1 = q.s1; glyph.V1 = q.t1; - glyph.Y0 += (float)(int)(dst_font->Ascent + merge_off_y + 0.5f); - glyph.Y1 += (float)(int)(dst_font->Ascent + merge_off_y + 0.5f); + glyph.Y0 += (float)(int)(dst_font->Ascent + 0.5f); + glyph.Y1 += (float)(int)(dst_font->Ascent + 0.5f); glyph.XAdvance = (pc.xadvance + cfg.GlyphExtraSpacing.x); // Bake spacing into XAdvance if (cfg.PixelSnapH) glyph.XAdvance = (float)(int)(glyph.XAdvance + 0.5f);