diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index ad43c68..9bedf3f 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -98,6 +98,11 @@
-----------------------------------------------------------------------
Breaking Changes:
+- Examples: Vulkan: Added MinImageCount/ImageCount fields in ImGui_ImplVulkan_InitInfo, required
+ during initialization to specify the number of in-flight image requested by swap chains.
+ (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam]
+- Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely
+ on them but it is possible you have!).
Other Changes:
- InputText: Fixed selection background starts rendering one frame after the cursor movement
@@ -108,11 +113,15 @@
- GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419)
- GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero.
- Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood]
+- Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert
+ to using the ImGui::MemAlloc()/MemFree() calls directly.
- Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized
GL function loaders early, and help users understand what they are missing. (#2421)
- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop.
+- Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int).
- Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
+- Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam]
- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454)
- Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott]
- Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott]
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index ad43c68..9bedf3f 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -98,6 +98,11 @@
-----------------------------------------------------------------------
Breaking Changes:
+- Examples: Vulkan: Added MinImageCount/ImageCount fields in ImGui_ImplVulkan_InitInfo, required
+ during initialization to specify the number of in-flight image requested by swap chains.
+ (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam]
+- Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely
+ on them but it is possible you have!).
Other Changes:
- InputText: Fixed selection background starts rendering one frame after the cursor movement
@@ -108,11 +113,15 @@
- GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419)
- GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero.
- Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood]
+- Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert
+ to using the ImGui::MemAlloc()/MemFree() calls directly.
- Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized
GL function loaders early, and help users understand what they are missing. (#2421)
- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop.
+- Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int).
- Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
+- Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam]
- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454)
- Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott]
- Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott]
diff --git a/docs/README.md b/docs/README.md
index febacf0..ba48517 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -219,29 +219,32 @@
**Where is the documentation?**
-- The documentation is at the top of imgui.cpp + effectively imgui.h.
-- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output.
-- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder.
-- We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
-- Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ applications and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ - We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
**Which version should I get?**
I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
-You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Several projects are using this branch and it is kept in sync with master regularly.
+You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Many projects are using this branch and it is kept in sync with master regularly.
**Who uses Dear ImGui?**
-See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) pages for an (incomplete) list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
**Why the odd dual naming, "Dear ImGui" vs "ImGui"?**
-The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would taker off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library in ambiguous situations. Please try to refer to it as "Dear ImGui".
+The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would take off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). To reduce this ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library. Please try to refer to this library as "Dear ImGui".
**How can I tell whether to dispatch mouse/keyboard to imgui or to my application?**
**How can I display an image? What is ImTextureID, how does it works?**
-
**How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.**
+
**Why are multiple widgets reacting when I interact with a single one? How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...**
**How can I use my own math types instead of ImVec2/ImVec4?**
**How can I load a different font than the default?**
**How can I easily use icons in my application?**
@@ -254,7 +257,7 @@
**I integrated Dear ImGui in my engine and some elements are disappearing when I move windows around..**
**How can I help?**
-See the FAQ in imgui.cpp for answers.
+See the FAQ in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) for answers.
**Can you create elaborate/serious tools with Dear ImGui?**
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index ad43c68..9bedf3f 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -98,6 +98,11 @@
-----------------------------------------------------------------------
Breaking Changes:
+- Examples: Vulkan: Added MinImageCount/ImageCount fields in ImGui_ImplVulkan_InitInfo, required
+ during initialization to specify the number of in-flight image requested by swap chains.
+ (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam]
+- Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely
+ on them but it is possible you have!).
Other Changes:
- InputText: Fixed selection background starts rendering one frame after the cursor movement
@@ -108,11 +113,15 @@
- GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419)
- GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero.
- Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood]
+- Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert
+ to using the ImGui::MemAlloc()/MemFree() calls directly.
- Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized
GL function loaders early, and help users understand what they are missing. (#2421)
- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop.
+- Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int).
- Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
+- Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam]
- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454)
- Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott]
- Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott]
diff --git a/docs/README.md b/docs/README.md
index febacf0..ba48517 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -219,29 +219,32 @@
**Where is the documentation?**
-- The documentation is at the top of imgui.cpp + effectively imgui.h.
-- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output.
-- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder.
-- We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
-- Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ applications and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ - We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
**Which version should I get?**
I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
-You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Several projects are using this branch and it is kept in sync with master regularly.
+You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Many projects are using this branch and it is kept in sync with master regularly.
**Who uses Dear ImGui?**
-See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) pages for an (incomplete) list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
**Why the odd dual naming, "Dear ImGui" vs "ImGui"?**
-The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would taker off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library in ambiguous situations. Please try to refer to it as "Dear ImGui".
+The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would take off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). To reduce this ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library. Please try to refer to this library as "Dear ImGui".
**How can I tell whether to dispatch mouse/keyboard to imgui or to my application?**
**How can I display an image? What is ImTextureID, how does it works?**
-
**How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.**
+
**Why are multiple widgets reacting when I interact with a single one? How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...**
**How can I use my own math types instead of ImVec2/ImVec4?**
**How can I load a different font than the default?**
**How can I easily use icons in my application?**
@@ -254,7 +257,7 @@
**I integrated Dear ImGui in my engine and some elements are disappearing when I move windows around..**
**How can I help?**
-See the FAQ in imgui.cpp for answers.
+See the FAQ in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) for answers.
**Can you create elaborate/serious tools with Dear ImGui?**
diff --git a/docs/issue_template.md b/docs/issue_template.md
index 6d88b27..21f0c1a 100644
--- a/docs/issue_template.md
+++ b/docs/issue_template.md
@@ -4,11 +4,11 @@
https://github.com/ocornut/imgui/issues/2261
2. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/LOADING FONTS, please post on the "Getting Started" Discourse forum:
-https://discourse.dearimgui.org/c/getting-started
+https://discourse.dearimgui.org
-3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
+3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
-4. Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users, unless they browse the site.
+4. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.
5. Delete points 1-5 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue.
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index ad43c68..9bedf3f 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -98,6 +98,11 @@
-----------------------------------------------------------------------
Breaking Changes:
+- Examples: Vulkan: Added MinImageCount/ImageCount fields in ImGui_ImplVulkan_InitInfo, required
+ during initialization to specify the number of in-flight image requested by swap chains.
+ (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam]
+- Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely
+ on them but it is possible you have!).
Other Changes:
- InputText: Fixed selection background starts rendering one frame after the cursor movement
@@ -108,11 +113,15 @@
- GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419)
- GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero.
- Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood]
+- Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert
+ to using the ImGui::MemAlloc()/MemFree() calls directly.
- Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized
GL function loaders early, and help users understand what they are missing. (#2421)
- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop.
+- Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int).
- Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
+- Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam]
- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454)
- Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott]
- Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott]
diff --git a/docs/README.md b/docs/README.md
index febacf0..ba48517 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -219,29 +219,32 @@
**Where is the documentation?**
-- The documentation is at the top of imgui.cpp + effectively imgui.h.
-- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output.
-- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder.
-- We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
-- Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ applications and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ - We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
**Which version should I get?**
I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
-You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Several projects are using this branch and it is kept in sync with master regularly.
+You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Many projects are using this branch and it is kept in sync with master regularly.
**Who uses Dear ImGui?**
-See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) pages for an (incomplete) list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
**Why the odd dual naming, "Dear ImGui" vs "ImGui"?**
-The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would taker off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library in ambiguous situations. Please try to refer to it as "Dear ImGui".
+The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would take off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). To reduce this ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library. Please try to refer to this library as "Dear ImGui".
**How can I tell whether to dispatch mouse/keyboard to imgui or to my application?**
**How can I display an image? What is ImTextureID, how does it works?**
-
**How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.**
+
**Why are multiple widgets reacting when I interact with a single one? How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...**
**How can I use my own math types instead of ImVec2/ImVec4?**
**How can I load a different font than the default?**
**How can I easily use icons in my application?**
@@ -254,7 +257,7 @@
**I integrated Dear ImGui in my engine and some elements are disappearing when I move windows around..**
**How can I help?**
-See the FAQ in imgui.cpp for answers.
+See the FAQ in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) for answers.
**Can you create elaborate/serious tools with Dear ImGui?**
diff --git a/docs/issue_template.md b/docs/issue_template.md
index 6d88b27..21f0c1a 100644
--- a/docs/issue_template.md
+++ b/docs/issue_template.md
@@ -4,11 +4,11 @@
https://github.com/ocornut/imgui/issues/2261
2. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/LOADING FONTS, please post on the "Getting Started" Discourse forum:
-https://discourse.dearimgui.org/c/getting-started
+https://discourse.dearimgui.org
-3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
+3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
-4. Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users, unless they browse the site.
+4. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.
5. Delete points 1-5 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue.
diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp
index 6f2c4cd..c1548ff 100644
--- a/examples/example_glfw_vulkan/main.cpp
+++ b/examples/example_glfw_vulkan/main.cpp
@@ -1,6 +1,13 @@
// 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"
@@ -23,19 +30,21 @@
#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 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_WindowData g_WindowData;
-static bool g_ResizeWanted = false;
-static int g_ResizeWidth = 0, g_ResizeHeight = 0;
+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)
{
@@ -107,6 +116,7 @@
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);
@@ -183,7 +193,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -211,14 +223,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -231,15 +241,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -260,7 +276,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -283,7 +299,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -292,18 +308,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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)
@@ -313,14 +330,14 @@
static void glfw_resize_callback(GLFWwindow*, int w, int h)
{
- g_ResizeWanted = true;
- g_ResizeWidth = w;
- g_ResizeHeight = h;
+ g_SwapChainRebuild = true;
+ g_SwapChainResizeWidth = w;
+ g_SwapChainResizeHeight = h;
}
int main(int, char**)
{
- // Setup window
+ // Setup GLFW window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
return 1;
@@ -347,8 +364,8 @@
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glfwSetFramebufferSizeCallback(window, glfw_resize_callback);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
@@ -384,6 +401,8 @@
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);
@@ -429,7 +448,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -445,10 +464,13 @@
// - 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();
- if (g_ResizeWanted)
+
+ if (g_SwapChainRebuild)
{
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, g_ResizeWidth, g_ResizeHeight);
- g_ResizeWanted = false;
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -514,6 +536,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
glfwDestroyWindow(window);
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index ad43c68..9bedf3f 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -98,6 +98,11 @@
-----------------------------------------------------------------------
Breaking Changes:
+- Examples: Vulkan: Added MinImageCount/ImageCount fields in ImGui_ImplVulkan_InitInfo, required
+ during initialization to specify the number of in-flight image requested by swap chains.
+ (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam]
+- Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely
+ on them but it is possible you have!).
Other Changes:
- InputText: Fixed selection background starts rendering one frame after the cursor movement
@@ -108,11 +113,15 @@
- GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419)
- GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero.
- Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood]
+- Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert
+ to using the ImGui::MemAlloc()/MemFree() calls directly.
- Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized
GL function loaders early, and help users understand what they are missing. (#2421)
- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop.
+- Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int).
- Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
+- Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam]
- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454)
- Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott]
- Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott]
diff --git a/docs/README.md b/docs/README.md
index febacf0..ba48517 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -219,29 +219,32 @@
**Where is the documentation?**
-- The documentation is at the top of imgui.cpp + effectively imgui.h.
-- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output.
-- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder.
-- We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
-- Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ applications and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ - We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
**Which version should I get?**
I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
-You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Several projects are using this branch and it is kept in sync with master regularly.
+You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Many projects are using this branch and it is kept in sync with master regularly.
**Who uses Dear ImGui?**
-See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) pages for an (incomplete) list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
**Why the odd dual naming, "Dear ImGui" vs "ImGui"?**
-The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would taker off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library in ambiguous situations. Please try to refer to it as "Dear ImGui".
+The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would take off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). To reduce this ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library. Please try to refer to this library as "Dear ImGui".
**How can I tell whether to dispatch mouse/keyboard to imgui or to my application?**
**How can I display an image? What is ImTextureID, how does it works?**
-
**How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.**
+
**Why are multiple widgets reacting when I interact with a single one? How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...**
**How can I use my own math types instead of ImVec2/ImVec4?**
**How can I load a different font than the default?**
**How can I easily use icons in my application?**
@@ -254,7 +257,7 @@
**I integrated Dear ImGui in my engine and some elements are disappearing when I move windows around..**
**How can I help?**
-See the FAQ in imgui.cpp for answers.
+See the FAQ in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) for answers.
**Can you create elaborate/serious tools with Dear ImGui?**
diff --git a/docs/issue_template.md b/docs/issue_template.md
index 6d88b27..21f0c1a 100644
--- a/docs/issue_template.md
+++ b/docs/issue_template.md
@@ -4,11 +4,11 @@
https://github.com/ocornut/imgui/issues/2261
2. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/LOADING FONTS, please post on the "Getting Started" Discourse forum:
-https://discourse.dearimgui.org/c/getting-started
+https://discourse.dearimgui.org
-3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
+3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
-4. Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users, unless they browse the site.
+4. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.
5. Delete points 1-5 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue.
diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp
index 6f2c4cd..c1548ff 100644
--- a/examples/example_glfw_vulkan/main.cpp
+++ b/examples/example_glfw_vulkan/main.cpp
@@ -1,6 +1,13 @@
// 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"
@@ -23,19 +30,21 @@
#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 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_WindowData g_WindowData;
-static bool g_ResizeWanted = false;
-static int g_ResizeWidth = 0, g_ResizeHeight = 0;
+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)
{
@@ -107,6 +116,7 @@
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);
@@ -183,7 +193,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -211,14 +223,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -231,15 +241,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -260,7 +276,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -283,7 +299,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -292,18 +308,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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)
@@ -313,14 +330,14 @@
static void glfw_resize_callback(GLFWwindow*, int w, int h)
{
- g_ResizeWanted = true;
- g_ResizeWidth = w;
- g_ResizeHeight = h;
+ g_SwapChainRebuild = true;
+ g_SwapChainResizeWidth = w;
+ g_SwapChainResizeHeight = h;
}
int main(int, char**)
{
- // Setup window
+ // Setup GLFW window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
return 1;
@@ -347,8 +364,8 @@
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glfwSetFramebufferSizeCallback(window, glfw_resize_callback);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
@@ -384,6 +401,8 @@
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);
@@ -429,7 +448,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -445,10 +464,13 @@
// - 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();
- if (g_ResizeWanted)
+
+ if (g_SwapChainRebuild)
{
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, g_ResizeWidth, g_ResizeHeight);
- g_ResizeWanted = false;
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -514,6 +536,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
glfwDestroyWindow(window);
diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp
index 42ab4a6..077a825 100644
--- a/examples/example_sdl_vulkan/main.cpp
+++ b/examples/example_sdl_vulkan/main.cpp
@@ -1,6 +1,13 @@
// dear imgui: standalone example application for SDL2 + 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_sdl.h"
#include "imgui_impl_vulkan.h"
@@ -15,17 +22,21 @@
#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 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_WindowData g_WindowData;
+static ImGui_ImplVulkanH_Window g_MainWindowData;
+static uint32_t 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)
{
@@ -97,6 +108,7 @@
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);
@@ -173,7 +185,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -201,14 +215,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -221,15 +233,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -250,7 +268,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -273,7 +291,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -282,18 +300,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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
}
int main(int, char**)
@@ -331,8 +350,8 @@
// Create Framebuffers
int w, h;
SDL_GetWindowSize(window, &w, &h);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
ImGui::CreateContext();
@@ -366,6 +385,8 @@
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);
@@ -411,7 +432,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -434,7 +455,19 @@
if (event.type == SDL_QUIT)
done = true;
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED && event.window.windowID == SDL_GetWindowID(window))
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, (int)event.window.data1, (int)event.window.data2);
+ {
+ g_SwapChainResizeWidth = (int)event.window.data1;
+ g_SwapChainResizeHeight = (int)event.window.data2;
+ g_SwapChainRebuild = true;
+ }
+ }
+
+ if (g_SwapChainRebuild)
+ {
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -500,6 +533,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
SDL_DestroyWindow(window);
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index ad43c68..9bedf3f 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -98,6 +98,11 @@
-----------------------------------------------------------------------
Breaking Changes:
+- Examples: Vulkan: Added MinImageCount/ImageCount fields in ImGui_ImplVulkan_InitInfo, required
+ during initialization to specify the number of in-flight image requested by swap chains.
+ (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam]
+- Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely
+ on them but it is possible you have!).
Other Changes:
- InputText: Fixed selection background starts rendering one frame after the cursor movement
@@ -108,11 +113,15 @@
- GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419)
- GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero.
- Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood]
+- Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert
+ to using the ImGui::MemAlloc()/MemFree() calls directly.
- Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized
GL function loaders early, and help users understand what they are missing. (#2421)
- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop.
+- Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int).
- Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
+- Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam]
- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454)
- Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott]
- Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott]
diff --git a/docs/README.md b/docs/README.md
index febacf0..ba48517 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -219,29 +219,32 @@
**Where is the documentation?**
-- The documentation is at the top of imgui.cpp + effectively imgui.h.
-- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output.
-- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder.
-- We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
-- Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ applications and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ - We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
**Which version should I get?**
I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
-You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Several projects are using this branch and it is kept in sync with master regularly.
+You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Many projects are using this branch and it is kept in sync with master regularly.
**Who uses Dear ImGui?**
-See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) pages for an (incomplete) list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
**Why the odd dual naming, "Dear ImGui" vs "ImGui"?**
-The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would taker off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library in ambiguous situations. Please try to refer to it as "Dear ImGui".
+The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would take off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). To reduce this ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library. Please try to refer to this library as "Dear ImGui".
**How can I tell whether to dispatch mouse/keyboard to imgui or to my application?**
**How can I display an image? What is ImTextureID, how does it works?**
-
**How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.**
+
**Why are multiple widgets reacting when I interact with a single one? How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...**
**How can I use my own math types instead of ImVec2/ImVec4?**
**How can I load a different font than the default?**
**How can I easily use icons in my application?**
@@ -254,7 +257,7 @@
**I integrated Dear ImGui in my engine and some elements are disappearing when I move windows around..**
**How can I help?**
-See the FAQ in imgui.cpp for answers.
+See the FAQ in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) for answers.
**Can you create elaborate/serious tools with Dear ImGui?**
diff --git a/docs/issue_template.md b/docs/issue_template.md
index 6d88b27..21f0c1a 100644
--- a/docs/issue_template.md
+++ b/docs/issue_template.md
@@ -4,11 +4,11 @@
https://github.com/ocornut/imgui/issues/2261
2. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/LOADING FONTS, please post on the "Getting Started" Discourse forum:
-https://discourse.dearimgui.org/c/getting-started
+https://discourse.dearimgui.org
-3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
+3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
-4. Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users, unless they browse the site.
+4. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.
5. Delete points 1-5 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue.
diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp
index 6f2c4cd..c1548ff 100644
--- a/examples/example_glfw_vulkan/main.cpp
+++ b/examples/example_glfw_vulkan/main.cpp
@@ -1,6 +1,13 @@
// 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"
@@ -23,19 +30,21 @@
#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 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_WindowData g_WindowData;
-static bool g_ResizeWanted = false;
-static int g_ResizeWidth = 0, g_ResizeHeight = 0;
+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)
{
@@ -107,6 +116,7 @@
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);
@@ -183,7 +193,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -211,14 +223,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -231,15 +241,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -260,7 +276,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -283,7 +299,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -292,18 +308,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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)
@@ -313,14 +330,14 @@
static void glfw_resize_callback(GLFWwindow*, int w, int h)
{
- g_ResizeWanted = true;
- g_ResizeWidth = w;
- g_ResizeHeight = h;
+ g_SwapChainRebuild = true;
+ g_SwapChainResizeWidth = w;
+ g_SwapChainResizeHeight = h;
}
int main(int, char**)
{
- // Setup window
+ // Setup GLFW window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
return 1;
@@ -347,8 +364,8 @@
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glfwSetFramebufferSizeCallback(window, glfw_resize_callback);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
@@ -384,6 +401,8 @@
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);
@@ -429,7 +448,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -445,10 +464,13 @@
// - 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();
- if (g_ResizeWanted)
+
+ if (g_SwapChainRebuild)
{
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, g_ResizeWidth, g_ResizeHeight);
- g_ResizeWanted = false;
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -514,6 +536,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
glfwDestroyWindow(window);
diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp
index 42ab4a6..077a825 100644
--- a/examples/example_sdl_vulkan/main.cpp
+++ b/examples/example_sdl_vulkan/main.cpp
@@ -1,6 +1,13 @@
// dear imgui: standalone example application for SDL2 + 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_sdl.h"
#include "imgui_impl_vulkan.h"
@@ -15,17 +22,21 @@
#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 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_WindowData g_WindowData;
+static ImGui_ImplVulkanH_Window g_MainWindowData;
+static uint32_t 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)
{
@@ -97,6 +108,7 @@
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);
@@ -173,7 +185,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -201,14 +215,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -221,15 +233,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -250,7 +268,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -273,7 +291,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -282,18 +300,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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
}
int main(int, char**)
@@ -331,8 +350,8 @@
// Create Framebuffers
int w, h;
SDL_GetWindowSize(window, &w, &h);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
ImGui::CreateContext();
@@ -366,6 +385,8 @@
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);
@@ -411,7 +432,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -434,7 +455,19 @@
if (event.type == SDL_QUIT)
done = true;
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED && event.window.windowID == SDL_GetWindowID(window))
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, (int)event.window.data1, (int)event.window.data2);
+ {
+ g_SwapChainResizeWidth = (int)event.window.data1;
+ g_SwapChainResizeHeight = (int)event.window.data2;
+ g_SwapChainRebuild = true;
+ }
+ }
+
+ if (g_SwapChainRebuild)
+ {
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -500,6 +533,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
SDL_DestroyWindow(window);
diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp
index 5911878..39ec861 100644
--- a/examples/imgui_impl_vulkan.cpp
+++ b/examples/imgui_impl_vulkan.cpp
@@ -12,8 +12,17 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2019-XX-XX: *BREAKING CHANGE*: Vulkan: Added ImageCount/MinImageCount fields in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetMinImageCount().
+// 2019-XX-XX: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper.
// 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
// 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int).
// 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display.
@@ -35,46 +44,61 @@
#include "imgui_impl_vulkan.h"
#include
-// Vulkan data
-static const VkAllocationCallbacks* g_Allocator = NULL;
-static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE;
-static VkInstance g_Instance = 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 VkPipelineCache g_PipelineCache = VK_NULL_HANDLE;
-static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
-static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
-static void (*g_CheckVkResultFn)(VkResult err) = NULL;
-
-static VkDeviceSize g_BufferMemoryAlignment = 256;
-static VkPipelineCreateFlags g_PipelineCreateFlags = 0;
-
-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;
-
-// Frame data
-struct FrameDataForRender
+// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_FrameRenderBuffers
{
- VkDeviceMemory VertexBufferMemory;
- VkDeviceMemory IndexBufferMemory;
- VkDeviceSize VertexBufferSize;
- VkDeviceSize IndexBufferSize;
- VkBuffer VertexBuffer;
- VkBuffer IndexBuffer;
+ VkDeviceMemory VertexBufferMemory;
+ VkDeviceMemory IndexBufferMemory;
+ VkDeviceSize VertexBufferSize;
+ VkDeviceSize IndexBufferSize;
+ VkBuffer VertexBuffer;
+ VkBuffer IndexBuffer;
};
-static int g_FrameIndex = 0;
-static FrameDataForRender g_FramesDataBuffers[IMGUI_VK_QUEUED_FRAMES] = {};
+
+// Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_WindowRenderBuffers
+{
+ uint32_t Index;
+ uint32_t Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* FrameRenderBuffers;
+};
+
+// Vulkan data
+static ImGui_ImplVulkan_InitInfo g_VulkanInitInfo = {};
+static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
+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
-static VkSampler g_FontSampler = VK_NULL_HANDLE;
-static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
-static VkImage g_FontImage = VK_NULL_HANDLE;
-static VkImageView g_FontView = VK_NULL_HANDLE;
-static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
-static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+static VkSampler g_FontSampler = VK_NULL_HANDLE;
+static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
+static VkImage g_FontImage = VK_NULL_HANDLE;
+static VkImageView g_FontView = VK_NULL_HANDLE;
+static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
+static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+
+// Render buffers
+static ImGui_ImplVulkanH_WindowRenderBuffers g_MainWindowRenderBuffers;
+
+// Forward Declarations
+bool ImGui_ImplVulkan_CreateDeviceObjects();
+void ImGui_ImplVulkan_DestroyDeviceObjects();
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
+
+//-----------------------------------------------------------------------------
+// SHADERS
+//-----------------------------------------------------------------------------
// Forward Declarations
static void ImGui_ImplVulkan_InitPlatformInterface();
@@ -185,10 +209,15 @@
0x00010038
};
+//-----------------------------------------------------------------------------
+// FUNCTIONS
+//-----------------------------------------------------------------------------
+
static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkPhysicalDeviceMemoryProperties prop;
- vkGetPhysicalDeviceMemoryProperties(g_PhysicalDevice, &prop);
+ vkGetPhysicalDeviceMemoryProperties(v->PhysicalDevice, &prop);
for (uint32_t i = 0; i < prop.memoryTypeCount; i++)
if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<CheckVkResultFn)
+ v->CheckVkResultFn(err);
}
static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
if (buffer != VK_NULL_HANDLE)
- vkDestroyBuffer(g_Device, buffer, g_Allocator);
- if (buffer_memory)
- vkFreeMemory(g_Device, buffer_memory, g_Allocator);
+ vkDestroyBuffer(v->Device, buffer, v->Allocator);
+ if (buffer_memory != VK_NULL_HANDLE)
+ vkFreeMemory(v->Device, buffer_memory, v->Allocator);
VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / g_BufferMemoryAlignment + 1) * g_BufferMemoryAlignment;
VkBufferCreateInfo buffer_info = {};
@@ -215,20 +246,20 @@
buffer_info.size = vertex_buffer_size_aligned;
buffer_info.usage = usage;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &buffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &buffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, buffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, buffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &buffer_memory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &buffer_memory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, buffer, buffer_memory, 0);
+ err = vkBindBufferMemory(v->Device, buffer, buffer_memory, 0);
check_vk_result(err);
p_buffer_size = new_size;
}
@@ -243,25 +274,38 @@
if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount == 0)
return;
- VkResult err;
- FrameDataForRender* fd = &g_FramesDataBuffers[g_FrameIndex];
- g_FrameIndex = (g_FrameIndex + 1) % IM_ARRAYSIZE(g_FramesDataBuffers);
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
- // Create the Vertex and Index buffers:
+ // Allocate array to store enough vertex/index buffers
+ ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &g_MainWindowRenderBuffers;
+ if (wrb->FrameRenderBuffers == NULL)
+ {
+ wrb->Index = 0;
+ wrb->Count = v->ImageCount;
+ wrb->FrameRenderBuffers = (ImGui_ImplVulkanH_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ }
+ IM_ASSERT(wrb->Count == v->ImageCount);
+ wrb->Index = (wrb->Index + 1) % wrb->Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index];
+
+ VkResult err;
+
+ // Create or resize the vertex/index buffers
size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);
size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx);
- if (fd->VertexBuffer == VK_NULL_HANDLE || fd->VertexBufferSize < vertex_size)
- CreateOrResizeBuffer(fd->VertexBuffer, fd->VertexBufferMemory, fd->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
- if (fd->IndexBuffer == VK_NULL_HANDLE || fd->IndexBufferSize < index_size)
- CreateOrResizeBuffer(fd->IndexBuffer, fd->IndexBufferMemory, fd->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
+ if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size)
+ CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+ if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size)
+ CreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
// Upload vertex/index data into a single contiguous GPU buffer
{
ImDrawVert* vtx_dst = NULL;
ImDrawIdx* idx_dst = NULL;
- err = vkMapMemory(g_Device, fd->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
+ err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
check_vk_result(err);
- err = vkMapMemory(g_Device, fd->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
+ err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
check_vk_result(err);
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
@@ -273,15 +317,15 @@
}
VkMappedMemoryRange range[2] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[0].memory = fd->VertexBufferMemory;
+ range[0].memory = rb->VertexBufferMemory;
range[0].size = VK_WHOLE_SIZE;
range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[1].memory = fd->IndexBufferMemory;
+ range[1].memory = rb->IndexBufferMemory;
range[1].size = VK_WHOLE_SIZE;
- err = vkFlushMappedMemoryRanges(g_Device, 2, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 2, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, fd->VertexBufferMemory);
- vkUnmapMemory(g_Device, fd->IndexBufferMemory);
+ vkUnmapMemory(v->Device, rb->VertexBufferMemory);
+ vkUnmapMemory(v->Device, rb->IndexBufferMemory);
}
// Bind pipeline and descriptor sets:
@@ -293,10 +337,10 @@
// Bind Vertex And Index Buffer:
{
- VkBuffer vertex_buffers[1] = { fd->VertexBuffer };
+ VkBuffer vertex_buffers[1] = { rb->VertexBuffer };
VkDeviceSize vertex_offset[1] = { 0 };
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset);
- vkCmdBindIndexBuffer(command_buffer, fd->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
+ vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
}
// Setup viewport:
@@ -379,6 +423,7 @@
bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
@@ -404,17 +449,17 @@
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- err = vkCreateImage(g_Device, &info, g_Allocator, &g_FontImage);
+ err = vkCreateImage(v->Device, &info, v->Allocator, &g_FontImage);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetImageMemoryRequirements(g_Device, g_FontImage, &req);
+ vkGetImageMemoryRequirements(v->Device, g_FontImage, &req);
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_FontMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_FontMemory);
check_vk_result(err);
- err = vkBindImageMemory(g_Device, g_FontImage, g_FontMemory, 0);
+ err = vkBindImageMemory(v->Device, g_FontImage, g_FontMemory, 0);
check_vk_result(err);
}
@@ -428,7 +473,7 @@
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.levelCount = 1;
info.subresourceRange.layerCount = 1;
- err = vkCreateImageView(g_Device, &info, g_Allocator, &g_FontView);
+ err = vkCreateImageView(v->Device, &info, v->Allocator, &g_FontView);
check_vk_result(err);
}
@@ -444,7 +489,7 @@
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
- vkUpdateDescriptorSets(g_Device, 1, write_desc, 0, NULL);
+ vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
// Create the Upload Buffer:
@@ -454,34 +499,34 @@
buffer_info.size = upload_size;
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_UploadBuffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &g_UploadBuffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, g_UploadBuffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, g_UploadBuffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_UploadBufferMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_UploadBufferMemory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, g_UploadBuffer, g_UploadBufferMemory, 0);
+ err = vkBindBufferMemory(v->Device, g_UploadBuffer, g_UploadBufferMemory, 0);
check_vk_result(err);
}
// Upload to Buffer:
{
char* map = NULL;
- err = vkMapMemory(g_Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
+ err = vkMapMemory(v->Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
check_vk_result(err);
memcpy(map, pixels, upload_size);
VkMappedMemoryRange range[1] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[0].memory = g_UploadBufferMemory;
range[0].size = upload_size;
- err = vkFlushMappedMemoryRanges(g_Device, 1, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 1, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, g_UploadBufferMemory);
+ vkUnmapMemory(v->Device, g_UploadBufferMemory);
}
// Copy to Image:
@@ -530,6 +575,7 @@
bool ImGui_ImplVulkan_CreateDeviceObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
VkShaderModule vert_module;
VkShaderModule frag_module;
@@ -540,13 +586,13 @@
vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
vert_info.codeSize = sizeof(__glsl_shader_vert_spv);
vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv;
- err = vkCreateShaderModule(g_Device, &vert_info, g_Allocator, &vert_module);
+ err = vkCreateShaderModule(v->Device, &vert_info, v->Allocator, &vert_module);
check_vk_result(err);
VkShaderModuleCreateInfo frag_info = {};
frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
frag_info.codeSize = sizeof(__glsl_shader_frag_spv);
frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv;
- err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module);
+ err = vkCreateShaderModule(v->Device, &frag_info, v->Allocator, &frag_module);
check_vk_result(err);
}
@@ -563,7 +609,7 @@
info.minLod = -1000;
info.maxLod = 1000;
info.maxAnisotropy = 1.0f;
- err = vkCreateSampler(g_Device, &info, g_Allocator, &g_FontSampler);
+ err = vkCreateSampler(v->Device, &info, v->Allocator, &g_FontSampler);
check_vk_result(err);
}
@@ -579,7 +625,7 @@
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
info.bindingCount = 1;
info.pBindings = binding;
- err = vkCreateDescriptorSetLayout(g_Device, &info, g_Allocator, &g_DescriptorSetLayout);
+ err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &g_DescriptorSetLayout);
check_vk_result(err);
}
@@ -587,10 +633,10 @@
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- alloc_info.descriptorPool = g_DescriptorPool;
+ alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &g_DescriptorSetLayout;
- err = vkAllocateDescriptorSets(g_Device, &alloc_info, &g_DescriptorSet);
+ err = vkAllocateDescriptorSets(v->Device, &alloc_info, &g_DescriptorSet);
check_vk_result(err);
}
@@ -608,7 +654,7 @@
layout_info.pSetLayouts = set_layout;
layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = push_constants;
- err = vkCreatePipelineLayout(g_Device, &layout_info, g_Allocator, &g_PipelineLayout);
+ err = vkCreatePipelineLayout(v->Device, &layout_info, v->Allocator, &g_PipelineLayout);
check_vk_result(err);
}
@@ -706,49 +752,43 @@
info.pDynamicState = &dynamic_state;
info.layout = g_PipelineLayout;
info.renderPass = g_RenderPass;
- err = vkCreateGraphicsPipelines(g_Device, g_PipelineCache, 1, &info, g_Allocator, &g_Pipeline);
+ err = vkCreateGraphicsPipelines(v->Device, v->PipelineCache, 1, &info, v->Allocator, &g_Pipeline);
check_vk_result(err);
- vkDestroyShaderModule(g_Device, vert_module, g_Allocator);
- vkDestroyShaderModule(g_Device, frag_module, g_Allocator);
+ vkDestroyShaderModule(v->Device, vert_module, v->Allocator);
+ vkDestroyShaderModule(v->Device, frag_module, v->Allocator);
return true;
}
-void ImGui_ImplVulkan_InvalidateFontUploadObjects()
+void ImGui_ImplVulkan_DestroyFontUploadObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
if (g_UploadBuffer)
{
- vkDestroyBuffer(g_Device, g_UploadBuffer, g_Allocator);
+ vkDestroyBuffer(v->Device, g_UploadBuffer, v->Allocator);
g_UploadBuffer = VK_NULL_HANDLE;
}
if (g_UploadBufferMemory)
{
- vkFreeMemory(g_Device, g_UploadBufferMemory, g_Allocator);
+ vkFreeMemory(v->Device, g_UploadBufferMemory, v->Allocator);
g_UploadBufferMemory = VK_NULL_HANDLE;
}
}
-void ImGui_ImplVulkan_InvalidateDeviceObjects()
+void ImGui_ImplVulkan_DestroyDeviceObjects()
{
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
- for (int i = 0; i < IM_ARRAYSIZE(g_FramesDataBuffers); i++)
- {
- FrameDataForRender* fd = &g_FramesDataBuffers[i];
- if (fd->VertexBuffer) { vkDestroyBuffer (g_Device, fd->VertexBuffer, g_Allocator); fd->VertexBuffer = VK_NULL_HANDLE; }
- if (fd->VertexBufferMemory) { vkFreeMemory (g_Device, fd->VertexBufferMemory, g_Allocator); fd->VertexBufferMemory = VK_NULL_HANDLE; }
- if (fd->IndexBuffer) { vkDestroyBuffer (g_Device, fd->IndexBuffer, g_Allocator); fd->IndexBuffer = VK_NULL_HANDLE; }
- if (fd->IndexBufferMemory) { vkFreeMemory (g_Device, fd->IndexBufferMemory, g_Allocator); fd->IndexBufferMemory = VK_NULL_HANDLE; }
- }
-
- if (g_FontView) { vkDestroyImageView(g_Device, g_FontView, g_Allocator); g_FontView = VK_NULL_HANDLE; }
- if (g_FontImage) { vkDestroyImage(g_Device, g_FontImage, g_Allocator); g_FontImage = VK_NULL_HANDLE; }
- if (g_FontMemory) { vkFreeMemory(g_Device, g_FontMemory, g_Allocator); g_FontMemory = VK_NULL_HANDLE; }
- if (g_FontSampler) { vkDestroySampler(g_Device, g_FontSampler, g_Allocator); g_FontSampler = VK_NULL_HANDLE; }
- if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(g_Device, g_DescriptorSetLayout, g_Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
- if (g_PipelineLayout) { vkDestroyPipelineLayout(g_Device, g_PipelineLayout, g_Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
- if (g_Pipeline) { vkDestroyPipeline(g_Device, g_Pipeline, g_Allocator); g_Pipeline = VK_NULL_HANDLE; }
+ if (g_FontView) { vkDestroyImageView(v->Device, g_FontView, v->Allocator); g_FontView = VK_NULL_HANDLE; }
+ if (g_FontImage) { vkDestroyImage(v->Device, g_FontImage, v->Allocator); g_FontImage = VK_NULL_HANDLE; }
+ if (g_FontMemory) { vkFreeMemory(v->Device, g_FontMemory, v->Allocator); g_FontMemory = VK_NULL_HANDLE; }
+ if (g_FontSampler) { vkDestroySampler(v->Device, g_FontSampler, v->Allocator); g_FontSampler = VK_NULL_HANDLE; }
+ if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, g_DescriptorSetLayout, v->Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
+ if (g_PipelineLayout) { vkDestroyPipelineLayout(v->Device, g_PipelineLayout, v->Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
+ if (g_Pipeline) { vkDestroyPipeline(v->Device, g_Pipeline, v->Allocator); g_Pipeline = VK_NULL_HANDLE; }
}
bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass)
@@ -763,19 +803,12 @@
IM_ASSERT(info->Device != VK_NULL_HANDLE);
IM_ASSERT(info->Queue != VK_NULL_HANDLE);
IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE);
+ IM_ASSERT(info->MinImageCount >= 2);
+ IM_ASSERT(info->ImageCount >= info->MinImageCount);
IM_ASSERT(render_pass != VK_NULL_HANDLE);
- g_Instance = info->Instance;
- g_PhysicalDevice = info->PhysicalDevice;
- g_Device = info->Device;
- g_QueueFamily = info->QueueFamily;
- g_Queue = info->Queue;
+ g_VulkanInitInfo = *info;
g_RenderPass = render_pass;
- g_PipelineCache = info->PipelineCache;
- g_DescriptorPool = info->DescriptorPool;
- g_Allocator = info->Allocator;
- g_CheckVkResultFn = info->CheckVkResultFn;
-
ImGui_ImplVulkan_CreateDeviceObjects();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
@@ -787,16 +820,30 @@
void ImGui_ImplVulkan_Shutdown()
{
ImGui_ImplVulkan_ShutdownPlatformInterface();
- ImGui_ImplVulkan_InvalidateDeviceObjects();
+ ImGui_ImplVulkan_DestroyDeviceObjects();
}
void ImGui_ImplVulkan_NewFrame()
{
}
+void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
+{
+ IM_ASSERT(min_image_count >= 2);
+ if (g_VulkanInitInfo.MinImageCount == min_image_count)
+ return;
+
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ VkResult err = vkDeviceWaitIdle(v->Device);
+ check_vk_result(err);
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ g_VulkanInitInfo.MinImageCount = min_image_count;
+}
+
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -804,40 +851,12 @@
// 2) the upcoming multi-viewport feature will need them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-#include // malloc
-
-ImGui_ImplVulkanH_FrameData::ImGui_ImplVulkanH_FrameData()
-{
- BackbufferIndex = 0;
- CommandPool = VK_NULL_HANDLE;
- CommandBuffer = VK_NULL_HANDLE;
- Fence = VK_NULL_HANDLE;
- ImageAcquiredSemaphore = VK_NULL_HANDLE;
- RenderCompleteSemaphore = VK_NULL_HANDLE;
-}
-
-ImGui_ImplVulkanH_WindowData::ImGui_ImplVulkanH_WindowData()
-{
- Width = Height = 0;
- Swapchain = VK_NULL_HANDLE;
- Surface = VK_NULL_HANDLE;
- memset(&SurfaceFormat, 0, sizeof(SurfaceFormat));
- PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
- RenderPass = VK_NULL_HANDLE;
- ClearEnable = true;
- memset(&ClearValue, 0, sizeof(ClearValue));
- BackBufferCount = 0;
- memset(&BackBuffer, 0, sizeof(BackBuffer));
- memset(&BackBufferView, 0, sizeof(BackBufferView));
- memset(&Framebuffer, 0, sizeof(Framebuffer));
- FrameIndex = 0;
-}
-
VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space)
{
IM_ASSERT(request_formats != NULL);
@@ -904,7 +923,7 @@
return VK_PRESENT_MODE_FIFO_KHR; // Always available
}
-void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator)
{
IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE);
(void)physical_device;
@@ -912,9 +931,10 @@
// Create Command Buffers
VkResult err;
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i];
{
VkCommandPoolCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
@@ -942,9 +962,9 @@
{
VkSemaphoreCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- err = vkCreateSemaphore(device, &info, allocator, &fd->ImageAcquiredSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->ImageAcquiredSemaphore);
check_vk_result(err);
- err = vkCreateSemaphore(device, &info, allocator, &fd->RenderCompleteSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->RenderCompleteSemaphore);
check_vk_result(err);
}
}
@@ -962,24 +982,26 @@
return 1;
}
-void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h)
+// Also destroy old swap chain and in-flight frames data, if any.
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count)
{
- uint32_t min_image_count = 2; // FIXME: this should become a function parameter
-
VkResult err;
VkSwapchainKHR old_swapchain = wd->Swapchain;
err = vkDeviceWaitIdle(device);
check_vk_result(err);
+ // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one.
// Destroy old Framebuffer
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- if (wd->BackBufferView[i])
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- if (wd->Framebuffer[i])
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- wd->BackBufferCount = 0;
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
+ wd->ImageCount = 0;
if (wd->RenderPass)
vkDestroyRenderPass(device, wd->RenderPass, allocator);
@@ -1023,10 +1045,21 @@
}
err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, NULL);
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, NULL);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, wd->BackBuffer);
+ VkImage backbuffers[16] = {};
+ IM_ASSERT(wd->ImageCount >= min_image_count);
+ IM_ASSERT(wd->ImageCount < IM_ARRAYSIZE(backbuffers));
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers);
check_vk_result(err);
+
+ IM_ASSERT(wd->Frames == NULL);
+ wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount);
+ wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->ImageCount);
+ memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount);
+ memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->ImageCount);
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
+ wd->Frames[i].Backbuffer = backbuffers[i];
}
if (old_swapchain)
vkDestroySwapchainKHR(device, old_swapchain, allocator);
@@ -1080,10 +1113,11 @@
info.components.a = VK_COMPONENT_SWIZZLE_A;
VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
info.subresourceRange = image_range;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- info.image = wd->BackBuffer[i];
- err = vkCreateImageView(device, &info, allocator, &wd->BackBufferView[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ info.image = fd->Backbuffer;
+ err = vkCreateImageView(device, &info, allocator, &fd->BackbufferView);
check_vk_result(err);
}
}
@@ -1099,38 +1133,82 @@
info.width = wd->Width;
info.height = wd->Height;
info.layers = 1;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- attachment[0] = wd->BackBufferView[i];
- err = vkCreateFramebuffer(device, &info, allocator, &wd->Framebuffer[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ attachment[0] = fd->BackbufferView;
+ err = vkCreateFramebuffer(device, &info, allocator, &fd->Framebuffer);
check_vk_result(err);
}
}
}
-void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count)
+{
+ (void)instance;
+ ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count);
+ ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator)
{
vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals)
//vkQueueWaitIdle(g_Queue);
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
- vkDestroyFence(device, fd->Fence, allocator);
- vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
- vkDestroyCommandPool(device, fd->CommandPool, allocator);
- vkDestroySemaphore(device, fd->ImageAcquiredSemaphore, allocator);
- vkDestroySemaphore(device, fd->RenderCompleteSemaphore, allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
- {
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
- }
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
vkDestroyRenderPass(device, wd->RenderPass, allocator);
vkDestroySwapchainKHR(device, wd->Swapchain, allocator);
vkDestroySurfaceKHR(instance, wd->Surface, allocator);
- *wd = ImGui_ImplVulkanH_WindowData();
+
+ *wd = ImGui_ImplVulkanH_Window();
+}
+
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroyFence(device, fd->Fence, allocator);
+ vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
+ vkDestroyCommandPool(device, fd->CommandPool, allocator);
+ fd->Fence = VK_NULL_HANDLE;
+ fd->CommandBuffer = VK_NULL_HANDLE;
+ fd->CommandPool = VK_NULL_HANDLE;
+
+ vkDestroyImageView(device, fd->BackbufferView, allocator);
+ vkDestroyFramebuffer(device, fd->Framebuffer, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator);
+ vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator);
+ fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;
+}
+
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; }
+ if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; }
+ if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; }
+ if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; }
+ buffers->VertexBufferSize = 0;
+ buffers->IndexBufferSize = 0;
+}
+
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ for (uint32_t n = 0; n < buffers->Count; n++)
+ ImGui_ImplVulkanH_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator);
+ IM_FREE(buffers->FrameRenderBuffers);
+ buffers->FrameRenderBuffers = NULL;
+ buffers->Index = 0;
+ buffers->Count = 0;
}
//--------------------------------------------------------------------------------------------------------
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index ad43c68..9bedf3f 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -98,6 +98,11 @@
-----------------------------------------------------------------------
Breaking Changes:
+- Examples: Vulkan: Added MinImageCount/ImageCount fields in ImGui_ImplVulkan_InitInfo, required
+ during initialization to specify the number of in-flight image requested by swap chains.
+ (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam]
+- Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely
+ on them but it is possible you have!).
Other Changes:
- InputText: Fixed selection background starts rendering one frame after the cursor movement
@@ -108,11 +113,15 @@
- GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419)
- GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero.
- Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood]
+- Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert
+ to using the ImGui::MemAlloc()/MemFree() calls directly.
- Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized
GL function loaders early, and help users understand what they are missing. (#2421)
- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop.
+- Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int).
- Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
+- Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam]
- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454)
- Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott]
- Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott]
diff --git a/docs/README.md b/docs/README.md
index febacf0..ba48517 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -219,29 +219,32 @@
**Where is the documentation?**
-- The documentation is at the top of imgui.cpp + effectively imgui.h.
-- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output.
-- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder.
-- We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
-- Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ applications and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ - We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
**Which version should I get?**
I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
-You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Several projects are using this branch and it is kept in sync with master regularly.
+You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Many projects are using this branch and it is kept in sync with master regularly.
**Who uses Dear ImGui?**
-See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) pages for an (incomplete) list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
**Why the odd dual naming, "Dear ImGui" vs "ImGui"?**
-The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would taker off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library in ambiguous situations. Please try to refer to it as "Dear ImGui".
+The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would take off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). To reduce this ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library. Please try to refer to this library as "Dear ImGui".
**How can I tell whether to dispatch mouse/keyboard to imgui or to my application?**
**How can I display an image? What is ImTextureID, how does it works?**
-
**How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.**
+
**Why are multiple widgets reacting when I interact with a single one? How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...**
**How can I use my own math types instead of ImVec2/ImVec4?**
**How can I load a different font than the default?**
**How can I easily use icons in my application?**
@@ -254,7 +257,7 @@
**I integrated Dear ImGui in my engine and some elements are disappearing when I move windows around..**
**How can I help?**
-See the FAQ in imgui.cpp for answers.
+See the FAQ in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) for answers.
**Can you create elaborate/serious tools with Dear ImGui?**
diff --git a/docs/issue_template.md b/docs/issue_template.md
index 6d88b27..21f0c1a 100644
--- a/docs/issue_template.md
+++ b/docs/issue_template.md
@@ -4,11 +4,11 @@
https://github.com/ocornut/imgui/issues/2261
2. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/LOADING FONTS, please post on the "Getting Started" Discourse forum:
-https://discourse.dearimgui.org/c/getting-started
+https://discourse.dearimgui.org
-3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
+3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
-4. Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users, unless they browse the site.
+4. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.
5. Delete points 1-5 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue.
diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp
index 6f2c4cd..c1548ff 100644
--- a/examples/example_glfw_vulkan/main.cpp
+++ b/examples/example_glfw_vulkan/main.cpp
@@ -1,6 +1,13 @@
// 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"
@@ -23,19 +30,21 @@
#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 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_WindowData g_WindowData;
-static bool g_ResizeWanted = false;
-static int g_ResizeWidth = 0, g_ResizeHeight = 0;
+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)
{
@@ -107,6 +116,7 @@
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);
@@ -183,7 +193,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -211,14 +223,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -231,15 +241,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -260,7 +276,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -283,7 +299,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -292,18 +308,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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)
@@ -313,14 +330,14 @@
static void glfw_resize_callback(GLFWwindow*, int w, int h)
{
- g_ResizeWanted = true;
- g_ResizeWidth = w;
- g_ResizeHeight = h;
+ g_SwapChainRebuild = true;
+ g_SwapChainResizeWidth = w;
+ g_SwapChainResizeHeight = h;
}
int main(int, char**)
{
- // Setup window
+ // Setup GLFW window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
return 1;
@@ -347,8 +364,8 @@
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glfwSetFramebufferSizeCallback(window, glfw_resize_callback);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
@@ -384,6 +401,8 @@
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);
@@ -429,7 +448,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -445,10 +464,13 @@
// - 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();
- if (g_ResizeWanted)
+
+ if (g_SwapChainRebuild)
{
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, g_ResizeWidth, g_ResizeHeight);
- g_ResizeWanted = false;
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -514,6 +536,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
glfwDestroyWindow(window);
diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp
index 42ab4a6..077a825 100644
--- a/examples/example_sdl_vulkan/main.cpp
+++ b/examples/example_sdl_vulkan/main.cpp
@@ -1,6 +1,13 @@
// dear imgui: standalone example application for SDL2 + 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_sdl.h"
#include "imgui_impl_vulkan.h"
@@ -15,17 +22,21 @@
#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 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_WindowData g_WindowData;
+static ImGui_ImplVulkanH_Window g_MainWindowData;
+static uint32_t 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)
{
@@ -97,6 +108,7 @@
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);
@@ -173,7 +185,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -201,14 +215,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -221,15 +233,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -250,7 +268,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -273,7 +291,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -282,18 +300,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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
}
int main(int, char**)
@@ -331,8 +350,8 @@
// Create Framebuffers
int w, h;
SDL_GetWindowSize(window, &w, &h);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
ImGui::CreateContext();
@@ -366,6 +385,8 @@
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);
@@ -411,7 +432,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -434,7 +455,19 @@
if (event.type == SDL_QUIT)
done = true;
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED && event.window.windowID == SDL_GetWindowID(window))
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, (int)event.window.data1, (int)event.window.data2);
+ {
+ g_SwapChainResizeWidth = (int)event.window.data1;
+ g_SwapChainResizeHeight = (int)event.window.data2;
+ g_SwapChainRebuild = true;
+ }
+ }
+
+ if (g_SwapChainRebuild)
+ {
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -500,6 +533,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
SDL_DestroyWindow(window);
diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp
index 5911878..39ec861 100644
--- a/examples/imgui_impl_vulkan.cpp
+++ b/examples/imgui_impl_vulkan.cpp
@@ -12,8 +12,17 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2019-XX-XX: *BREAKING CHANGE*: Vulkan: Added ImageCount/MinImageCount fields in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetMinImageCount().
+// 2019-XX-XX: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper.
// 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
// 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int).
// 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display.
@@ -35,46 +44,61 @@
#include "imgui_impl_vulkan.h"
#include
-// Vulkan data
-static const VkAllocationCallbacks* g_Allocator = NULL;
-static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE;
-static VkInstance g_Instance = 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 VkPipelineCache g_PipelineCache = VK_NULL_HANDLE;
-static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
-static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
-static void (*g_CheckVkResultFn)(VkResult err) = NULL;
-
-static VkDeviceSize g_BufferMemoryAlignment = 256;
-static VkPipelineCreateFlags g_PipelineCreateFlags = 0;
-
-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;
-
-// Frame data
-struct FrameDataForRender
+// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_FrameRenderBuffers
{
- VkDeviceMemory VertexBufferMemory;
- VkDeviceMemory IndexBufferMemory;
- VkDeviceSize VertexBufferSize;
- VkDeviceSize IndexBufferSize;
- VkBuffer VertexBuffer;
- VkBuffer IndexBuffer;
+ VkDeviceMemory VertexBufferMemory;
+ VkDeviceMemory IndexBufferMemory;
+ VkDeviceSize VertexBufferSize;
+ VkDeviceSize IndexBufferSize;
+ VkBuffer VertexBuffer;
+ VkBuffer IndexBuffer;
};
-static int g_FrameIndex = 0;
-static FrameDataForRender g_FramesDataBuffers[IMGUI_VK_QUEUED_FRAMES] = {};
+
+// Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_WindowRenderBuffers
+{
+ uint32_t Index;
+ uint32_t Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* FrameRenderBuffers;
+};
+
+// Vulkan data
+static ImGui_ImplVulkan_InitInfo g_VulkanInitInfo = {};
+static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
+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
-static VkSampler g_FontSampler = VK_NULL_HANDLE;
-static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
-static VkImage g_FontImage = VK_NULL_HANDLE;
-static VkImageView g_FontView = VK_NULL_HANDLE;
-static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
-static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+static VkSampler g_FontSampler = VK_NULL_HANDLE;
+static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
+static VkImage g_FontImage = VK_NULL_HANDLE;
+static VkImageView g_FontView = VK_NULL_HANDLE;
+static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
+static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+
+// Render buffers
+static ImGui_ImplVulkanH_WindowRenderBuffers g_MainWindowRenderBuffers;
+
+// Forward Declarations
+bool ImGui_ImplVulkan_CreateDeviceObjects();
+void ImGui_ImplVulkan_DestroyDeviceObjects();
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
+
+//-----------------------------------------------------------------------------
+// SHADERS
+//-----------------------------------------------------------------------------
// Forward Declarations
static void ImGui_ImplVulkan_InitPlatformInterface();
@@ -185,10 +209,15 @@
0x00010038
};
+//-----------------------------------------------------------------------------
+// FUNCTIONS
+//-----------------------------------------------------------------------------
+
static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkPhysicalDeviceMemoryProperties prop;
- vkGetPhysicalDeviceMemoryProperties(g_PhysicalDevice, &prop);
+ vkGetPhysicalDeviceMemoryProperties(v->PhysicalDevice, &prop);
for (uint32_t i = 0; i < prop.memoryTypeCount; i++)
if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<CheckVkResultFn)
+ v->CheckVkResultFn(err);
}
static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
if (buffer != VK_NULL_HANDLE)
- vkDestroyBuffer(g_Device, buffer, g_Allocator);
- if (buffer_memory)
- vkFreeMemory(g_Device, buffer_memory, g_Allocator);
+ vkDestroyBuffer(v->Device, buffer, v->Allocator);
+ if (buffer_memory != VK_NULL_HANDLE)
+ vkFreeMemory(v->Device, buffer_memory, v->Allocator);
VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / g_BufferMemoryAlignment + 1) * g_BufferMemoryAlignment;
VkBufferCreateInfo buffer_info = {};
@@ -215,20 +246,20 @@
buffer_info.size = vertex_buffer_size_aligned;
buffer_info.usage = usage;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &buffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &buffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, buffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, buffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &buffer_memory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &buffer_memory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, buffer, buffer_memory, 0);
+ err = vkBindBufferMemory(v->Device, buffer, buffer_memory, 0);
check_vk_result(err);
p_buffer_size = new_size;
}
@@ -243,25 +274,38 @@
if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount == 0)
return;
- VkResult err;
- FrameDataForRender* fd = &g_FramesDataBuffers[g_FrameIndex];
- g_FrameIndex = (g_FrameIndex + 1) % IM_ARRAYSIZE(g_FramesDataBuffers);
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
- // Create the Vertex and Index buffers:
+ // Allocate array to store enough vertex/index buffers
+ ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &g_MainWindowRenderBuffers;
+ if (wrb->FrameRenderBuffers == NULL)
+ {
+ wrb->Index = 0;
+ wrb->Count = v->ImageCount;
+ wrb->FrameRenderBuffers = (ImGui_ImplVulkanH_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ }
+ IM_ASSERT(wrb->Count == v->ImageCount);
+ wrb->Index = (wrb->Index + 1) % wrb->Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index];
+
+ VkResult err;
+
+ // Create or resize the vertex/index buffers
size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);
size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx);
- if (fd->VertexBuffer == VK_NULL_HANDLE || fd->VertexBufferSize < vertex_size)
- CreateOrResizeBuffer(fd->VertexBuffer, fd->VertexBufferMemory, fd->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
- if (fd->IndexBuffer == VK_NULL_HANDLE || fd->IndexBufferSize < index_size)
- CreateOrResizeBuffer(fd->IndexBuffer, fd->IndexBufferMemory, fd->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
+ if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size)
+ CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+ if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size)
+ CreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
// Upload vertex/index data into a single contiguous GPU buffer
{
ImDrawVert* vtx_dst = NULL;
ImDrawIdx* idx_dst = NULL;
- err = vkMapMemory(g_Device, fd->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
+ err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
check_vk_result(err);
- err = vkMapMemory(g_Device, fd->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
+ err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
check_vk_result(err);
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
@@ -273,15 +317,15 @@
}
VkMappedMemoryRange range[2] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[0].memory = fd->VertexBufferMemory;
+ range[0].memory = rb->VertexBufferMemory;
range[0].size = VK_WHOLE_SIZE;
range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[1].memory = fd->IndexBufferMemory;
+ range[1].memory = rb->IndexBufferMemory;
range[1].size = VK_WHOLE_SIZE;
- err = vkFlushMappedMemoryRanges(g_Device, 2, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 2, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, fd->VertexBufferMemory);
- vkUnmapMemory(g_Device, fd->IndexBufferMemory);
+ vkUnmapMemory(v->Device, rb->VertexBufferMemory);
+ vkUnmapMemory(v->Device, rb->IndexBufferMemory);
}
// Bind pipeline and descriptor sets:
@@ -293,10 +337,10 @@
// Bind Vertex And Index Buffer:
{
- VkBuffer vertex_buffers[1] = { fd->VertexBuffer };
+ VkBuffer vertex_buffers[1] = { rb->VertexBuffer };
VkDeviceSize vertex_offset[1] = { 0 };
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset);
- vkCmdBindIndexBuffer(command_buffer, fd->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
+ vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
}
// Setup viewport:
@@ -379,6 +423,7 @@
bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
@@ -404,17 +449,17 @@
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- err = vkCreateImage(g_Device, &info, g_Allocator, &g_FontImage);
+ err = vkCreateImage(v->Device, &info, v->Allocator, &g_FontImage);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetImageMemoryRequirements(g_Device, g_FontImage, &req);
+ vkGetImageMemoryRequirements(v->Device, g_FontImage, &req);
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_FontMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_FontMemory);
check_vk_result(err);
- err = vkBindImageMemory(g_Device, g_FontImage, g_FontMemory, 0);
+ err = vkBindImageMemory(v->Device, g_FontImage, g_FontMemory, 0);
check_vk_result(err);
}
@@ -428,7 +473,7 @@
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.levelCount = 1;
info.subresourceRange.layerCount = 1;
- err = vkCreateImageView(g_Device, &info, g_Allocator, &g_FontView);
+ err = vkCreateImageView(v->Device, &info, v->Allocator, &g_FontView);
check_vk_result(err);
}
@@ -444,7 +489,7 @@
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
- vkUpdateDescriptorSets(g_Device, 1, write_desc, 0, NULL);
+ vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
// Create the Upload Buffer:
@@ -454,34 +499,34 @@
buffer_info.size = upload_size;
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_UploadBuffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &g_UploadBuffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, g_UploadBuffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, g_UploadBuffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_UploadBufferMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_UploadBufferMemory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, g_UploadBuffer, g_UploadBufferMemory, 0);
+ err = vkBindBufferMemory(v->Device, g_UploadBuffer, g_UploadBufferMemory, 0);
check_vk_result(err);
}
// Upload to Buffer:
{
char* map = NULL;
- err = vkMapMemory(g_Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
+ err = vkMapMemory(v->Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
check_vk_result(err);
memcpy(map, pixels, upload_size);
VkMappedMemoryRange range[1] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[0].memory = g_UploadBufferMemory;
range[0].size = upload_size;
- err = vkFlushMappedMemoryRanges(g_Device, 1, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 1, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, g_UploadBufferMemory);
+ vkUnmapMemory(v->Device, g_UploadBufferMemory);
}
// Copy to Image:
@@ -530,6 +575,7 @@
bool ImGui_ImplVulkan_CreateDeviceObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
VkShaderModule vert_module;
VkShaderModule frag_module;
@@ -540,13 +586,13 @@
vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
vert_info.codeSize = sizeof(__glsl_shader_vert_spv);
vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv;
- err = vkCreateShaderModule(g_Device, &vert_info, g_Allocator, &vert_module);
+ err = vkCreateShaderModule(v->Device, &vert_info, v->Allocator, &vert_module);
check_vk_result(err);
VkShaderModuleCreateInfo frag_info = {};
frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
frag_info.codeSize = sizeof(__glsl_shader_frag_spv);
frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv;
- err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module);
+ err = vkCreateShaderModule(v->Device, &frag_info, v->Allocator, &frag_module);
check_vk_result(err);
}
@@ -563,7 +609,7 @@
info.minLod = -1000;
info.maxLod = 1000;
info.maxAnisotropy = 1.0f;
- err = vkCreateSampler(g_Device, &info, g_Allocator, &g_FontSampler);
+ err = vkCreateSampler(v->Device, &info, v->Allocator, &g_FontSampler);
check_vk_result(err);
}
@@ -579,7 +625,7 @@
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
info.bindingCount = 1;
info.pBindings = binding;
- err = vkCreateDescriptorSetLayout(g_Device, &info, g_Allocator, &g_DescriptorSetLayout);
+ err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &g_DescriptorSetLayout);
check_vk_result(err);
}
@@ -587,10 +633,10 @@
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- alloc_info.descriptorPool = g_DescriptorPool;
+ alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &g_DescriptorSetLayout;
- err = vkAllocateDescriptorSets(g_Device, &alloc_info, &g_DescriptorSet);
+ err = vkAllocateDescriptorSets(v->Device, &alloc_info, &g_DescriptorSet);
check_vk_result(err);
}
@@ -608,7 +654,7 @@
layout_info.pSetLayouts = set_layout;
layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = push_constants;
- err = vkCreatePipelineLayout(g_Device, &layout_info, g_Allocator, &g_PipelineLayout);
+ err = vkCreatePipelineLayout(v->Device, &layout_info, v->Allocator, &g_PipelineLayout);
check_vk_result(err);
}
@@ -706,49 +752,43 @@
info.pDynamicState = &dynamic_state;
info.layout = g_PipelineLayout;
info.renderPass = g_RenderPass;
- err = vkCreateGraphicsPipelines(g_Device, g_PipelineCache, 1, &info, g_Allocator, &g_Pipeline);
+ err = vkCreateGraphicsPipelines(v->Device, v->PipelineCache, 1, &info, v->Allocator, &g_Pipeline);
check_vk_result(err);
- vkDestroyShaderModule(g_Device, vert_module, g_Allocator);
- vkDestroyShaderModule(g_Device, frag_module, g_Allocator);
+ vkDestroyShaderModule(v->Device, vert_module, v->Allocator);
+ vkDestroyShaderModule(v->Device, frag_module, v->Allocator);
return true;
}
-void ImGui_ImplVulkan_InvalidateFontUploadObjects()
+void ImGui_ImplVulkan_DestroyFontUploadObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
if (g_UploadBuffer)
{
- vkDestroyBuffer(g_Device, g_UploadBuffer, g_Allocator);
+ vkDestroyBuffer(v->Device, g_UploadBuffer, v->Allocator);
g_UploadBuffer = VK_NULL_HANDLE;
}
if (g_UploadBufferMemory)
{
- vkFreeMemory(g_Device, g_UploadBufferMemory, g_Allocator);
+ vkFreeMemory(v->Device, g_UploadBufferMemory, v->Allocator);
g_UploadBufferMemory = VK_NULL_HANDLE;
}
}
-void ImGui_ImplVulkan_InvalidateDeviceObjects()
+void ImGui_ImplVulkan_DestroyDeviceObjects()
{
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
- for (int i = 0; i < IM_ARRAYSIZE(g_FramesDataBuffers); i++)
- {
- FrameDataForRender* fd = &g_FramesDataBuffers[i];
- if (fd->VertexBuffer) { vkDestroyBuffer (g_Device, fd->VertexBuffer, g_Allocator); fd->VertexBuffer = VK_NULL_HANDLE; }
- if (fd->VertexBufferMemory) { vkFreeMemory (g_Device, fd->VertexBufferMemory, g_Allocator); fd->VertexBufferMemory = VK_NULL_HANDLE; }
- if (fd->IndexBuffer) { vkDestroyBuffer (g_Device, fd->IndexBuffer, g_Allocator); fd->IndexBuffer = VK_NULL_HANDLE; }
- if (fd->IndexBufferMemory) { vkFreeMemory (g_Device, fd->IndexBufferMemory, g_Allocator); fd->IndexBufferMemory = VK_NULL_HANDLE; }
- }
-
- if (g_FontView) { vkDestroyImageView(g_Device, g_FontView, g_Allocator); g_FontView = VK_NULL_HANDLE; }
- if (g_FontImage) { vkDestroyImage(g_Device, g_FontImage, g_Allocator); g_FontImage = VK_NULL_HANDLE; }
- if (g_FontMemory) { vkFreeMemory(g_Device, g_FontMemory, g_Allocator); g_FontMemory = VK_NULL_HANDLE; }
- if (g_FontSampler) { vkDestroySampler(g_Device, g_FontSampler, g_Allocator); g_FontSampler = VK_NULL_HANDLE; }
- if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(g_Device, g_DescriptorSetLayout, g_Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
- if (g_PipelineLayout) { vkDestroyPipelineLayout(g_Device, g_PipelineLayout, g_Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
- if (g_Pipeline) { vkDestroyPipeline(g_Device, g_Pipeline, g_Allocator); g_Pipeline = VK_NULL_HANDLE; }
+ if (g_FontView) { vkDestroyImageView(v->Device, g_FontView, v->Allocator); g_FontView = VK_NULL_HANDLE; }
+ if (g_FontImage) { vkDestroyImage(v->Device, g_FontImage, v->Allocator); g_FontImage = VK_NULL_HANDLE; }
+ if (g_FontMemory) { vkFreeMemory(v->Device, g_FontMemory, v->Allocator); g_FontMemory = VK_NULL_HANDLE; }
+ if (g_FontSampler) { vkDestroySampler(v->Device, g_FontSampler, v->Allocator); g_FontSampler = VK_NULL_HANDLE; }
+ if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, g_DescriptorSetLayout, v->Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
+ if (g_PipelineLayout) { vkDestroyPipelineLayout(v->Device, g_PipelineLayout, v->Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
+ if (g_Pipeline) { vkDestroyPipeline(v->Device, g_Pipeline, v->Allocator); g_Pipeline = VK_NULL_HANDLE; }
}
bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass)
@@ -763,19 +803,12 @@
IM_ASSERT(info->Device != VK_NULL_HANDLE);
IM_ASSERT(info->Queue != VK_NULL_HANDLE);
IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE);
+ IM_ASSERT(info->MinImageCount >= 2);
+ IM_ASSERT(info->ImageCount >= info->MinImageCount);
IM_ASSERT(render_pass != VK_NULL_HANDLE);
- g_Instance = info->Instance;
- g_PhysicalDevice = info->PhysicalDevice;
- g_Device = info->Device;
- g_QueueFamily = info->QueueFamily;
- g_Queue = info->Queue;
+ g_VulkanInitInfo = *info;
g_RenderPass = render_pass;
- g_PipelineCache = info->PipelineCache;
- g_DescriptorPool = info->DescriptorPool;
- g_Allocator = info->Allocator;
- g_CheckVkResultFn = info->CheckVkResultFn;
-
ImGui_ImplVulkan_CreateDeviceObjects();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
@@ -787,16 +820,30 @@
void ImGui_ImplVulkan_Shutdown()
{
ImGui_ImplVulkan_ShutdownPlatformInterface();
- ImGui_ImplVulkan_InvalidateDeviceObjects();
+ ImGui_ImplVulkan_DestroyDeviceObjects();
}
void ImGui_ImplVulkan_NewFrame()
{
}
+void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
+{
+ IM_ASSERT(min_image_count >= 2);
+ if (g_VulkanInitInfo.MinImageCount == min_image_count)
+ return;
+
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ VkResult err = vkDeviceWaitIdle(v->Device);
+ check_vk_result(err);
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ g_VulkanInitInfo.MinImageCount = min_image_count;
+}
+
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -804,40 +851,12 @@
// 2) the upcoming multi-viewport feature will need them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-#include // malloc
-
-ImGui_ImplVulkanH_FrameData::ImGui_ImplVulkanH_FrameData()
-{
- BackbufferIndex = 0;
- CommandPool = VK_NULL_HANDLE;
- CommandBuffer = VK_NULL_HANDLE;
- Fence = VK_NULL_HANDLE;
- ImageAcquiredSemaphore = VK_NULL_HANDLE;
- RenderCompleteSemaphore = VK_NULL_HANDLE;
-}
-
-ImGui_ImplVulkanH_WindowData::ImGui_ImplVulkanH_WindowData()
-{
- Width = Height = 0;
- Swapchain = VK_NULL_HANDLE;
- Surface = VK_NULL_HANDLE;
- memset(&SurfaceFormat, 0, sizeof(SurfaceFormat));
- PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
- RenderPass = VK_NULL_HANDLE;
- ClearEnable = true;
- memset(&ClearValue, 0, sizeof(ClearValue));
- BackBufferCount = 0;
- memset(&BackBuffer, 0, sizeof(BackBuffer));
- memset(&BackBufferView, 0, sizeof(BackBufferView));
- memset(&Framebuffer, 0, sizeof(Framebuffer));
- FrameIndex = 0;
-}
-
VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space)
{
IM_ASSERT(request_formats != NULL);
@@ -904,7 +923,7 @@
return VK_PRESENT_MODE_FIFO_KHR; // Always available
}
-void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator)
{
IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE);
(void)physical_device;
@@ -912,9 +931,10 @@
// Create Command Buffers
VkResult err;
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i];
{
VkCommandPoolCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
@@ -942,9 +962,9 @@
{
VkSemaphoreCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- err = vkCreateSemaphore(device, &info, allocator, &fd->ImageAcquiredSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->ImageAcquiredSemaphore);
check_vk_result(err);
- err = vkCreateSemaphore(device, &info, allocator, &fd->RenderCompleteSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->RenderCompleteSemaphore);
check_vk_result(err);
}
}
@@ -962,24 +982,26 @@
return 1;
}
-void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h)
+// Also destroy old swap chain and in-flight frames data, if any.
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count)
{
- uint32_t min_image_count = 2; // FIXME: this should become a function parameter
-
VkResult err;
VkSwapchainKHR old_swapchain = wd->Swapchain;
err = vkDeviceWaitIdle(device);
check_vk_result(err);
+ // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one.
// Destroy old Framebuffer
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- if (wd->BackBufferView[i])
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- if (wd->Framebuffer[i])
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- wd->BackBufferCount = 0;
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
+ wd->ImageCount = 0;
if (wd->RenderPass)
vkDestroyRenderPass(device, wd->RenderPass, allocator);
@@ -1023,10 +1045,21 @@
}
err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, NULL);
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, NULL);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, wd->BackBuffer);
+ VkImage backbuffers[16] = {};
+ IM_ASSERT(wd->ImageCount >= min_image_count);
+ IM_ASSERT(wd->ImageCount < IM_ARRAYSIZE(backbuffers));
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers);
check_vk_result(err);
+
+ IM_ASSERT(wd->Frames == NULL);
+ wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount);
+ wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->ImageCount);
+ memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount);
+ memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->ImageCount);
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
+ wd->Frames[i].Backbuffer = backbuffers[i];
}
if (old_swapchain)
vkDestroySwapchainKHR(device, old_swapchain, allocator);
@@ -1080,10 +1113,11 @@
info.components.a = VK_COMPONENT_SWIZZLE_A;
VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
info.subresourceRange = image_range;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- info.image = wd->BackBuffer[i];
- err = vkCreateImageView(device, &info, allocator, &wd->BackBufferView[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ info.image = fd->Backbuffer;
+ err = vkCreateImageView(device, &info, allocator, &fd->BackbufferView);
check_vk_result(err);
}
}
@@ -1099,38 +1133,82 @@
info.width = wd->Width;
info.height = wd->Height;
info.layers = 1;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- attachment[0] = wd->BackBufferView[i];
- err = vkCreateFramebuffer(device, &info, allocator, &wd->Framebuffer[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ attachment[0] = fd->BackbufferView;
+ err = vkCreateFramebuffer(device, &info, allocator, &fd->Framebuffer);
check_vk_result(err);
}
}
}
-void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count)
+{
+ (void)instance;
+ ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count);
+ ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator)
{
vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals)
//vkQueueWaitIdle(g_Queue);
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
- vkDestroyFence(device, fd->Fence, allocator);
- vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
- vkDestroyCommandPool(device, fd->CommandPool, allocator);
- vkDestroySemaphore(device, fd->ImageAcquiredSemaphore, allocator);
- vkDestroySemaphore(device, fd->RenderCompleteSemaphore, allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
- {
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
- }
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
vkDestroyRenderPass(device, wd->RenderPass, allocator);
vkDestroySwapchainKHR(device, wd->Swapchain, allocator);
vkDestroySurfaceKHR(instance, wd->Surface, allocator);
- *wd = ImGui_ImplVulkanH_WindowData();
+
+ *wd = ImGui_ImplVulkanH_Window();
+}
+
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroyFence(device, fd->Fence, allocator);
+ vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
+ vkDestroyCommandPool(device, fd->CommandPool, allocator);
+ fd->Fence = VK_NULL_HANDLE;
+ fd->CommandBuffer = VK_NULL_HANDLE;
+ fd->CommandPool = VK_NULL_HANDLE;
+
+ vkDestroyImageView(device, fd->BackbufferView, allocator);
+ vkDestroyFramebuffer(device, fd->Framebuffer, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator);
+ vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator);
+ fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;
+}
+
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; }
+ if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; }
+ if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; }
+ if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; }
+ buffers->VertexBufferSize = 0;
+ buffers->IndexBufferSize = 0;
+}
+
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ for (uint32_t n = 0; n < buffers->Count; n++)
+ ImGui_ImplVulkanH_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator);
+ IM_FREE(buffers->FrameRenderBuffers);
+ buffers->FrameRenderBuffers = NULL;
+ buffers->Index = 0;
+ buffers->Count = 0;
}
//--------------------------------------------------------------------------------------------------------
diff --git a/examples/imgui_impl_vulkan.h b/examples/imgui_impl_vulkan.h
index ec45dbe..0389af5 100644
--- a/examples/imgui_impl_vulkan.h
+++ b/examples/imgui_impl_vulkan.h
@@ -12,24 +12,32 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
#pragma once
#include
-#define IMGUI_VK_QUEUED_FRAMES 2
-
-// Please zero-clear before use.
+// Initialization data, for ImGui_ImplVulkan_Init()
+// [Please zero-clear before use!]
struct ImGui_ImplVulkan_InitInfo
{
- VkInstance Instance;
- VkPhysicalDevice PhysicalDevice;
- VkDevice Device;
- uint32_t QueueFamily;
- VkQueue Queue;
- VkPipelineCache PipelineCache;
- VkDescriptorPool DescriptorPool;
- const VkAllocationCallbacks* Allocator;
- void (*CheckVkResultFn)(VkResult err);
+ VkInstance Instance;
+ VkPhysicalDevice PhysicalDevice;
+ VkDevice Device;
+ uint32_t QueueFamily;
+ VkQueue Queue;
+ VkPipelineCache PipelineCache;
+ VkDescriptorPool DescriptorPool;
+ uint32_t MinImageCount; // >= 2
+ uint32_t ImageCount; // >= MinImageCount
+ const VkAllocationCallbacks* Allocator;
+ void (*CheckVkResultFn)(VkResult err);
};
// Called by user code
@@ -38,16 +46,13 @@
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
-IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateFontUploadObjects();
-
-// Called by ImGui_ImplVulkan_Init() might be useful elsewhere.
-IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateDeviceObjects();
-IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateDeviceObjects();
+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)
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -55,38 +60,44 @@
// 2) the multi-viewport / platform window implementation needs them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-struct ImGui_ImplVulkanH_FrameData;
-struct ImGui_ImplVulkanH_WindowData;
+struct ImGui_ImplVulkanH_Frame;
+struct ImGui_ImplVulkanH_Window;
-IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
-IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h);
-IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
+// Helpers
+IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wnd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator);
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
// Helper structure to hold the data needed by one rendering frame
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
-struct ImGui_ImplVulkanH_FrameData
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_Frame
{
- uint32_t BackbufferIndex; // Keep track of recently rendered swapchain frame indices
VkCommandPool CommandPool;
VkCommandBuffer CommandBuffer;
VkFence Fence;
+ VkImage Backbuffer;
+ VkImageView BackbufferView;
+ VkFramebuffer Framebuffer;
+};
+
+struct ImGui_ImplVulkanH_FrameSemaphores
+{
VkSemaphore ImageAcquiredSemaphore;
VkSemaphore RenderCompleteSemaphore;
-
- IMGUI_IMPL_API ImGui_ImplVulkanH_FrameData();
};
// Helper structure to hold the data needed by one rendering context into one OS window
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
-struct ImGui_ImplVulkanH_WindowData
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+struct ImGui_ImplVulkanH_Window
{
int Width;
int Height;
@@ -97,13 +108,17 @@
VkRenderPass RenderPass;
bool ClearEnable;
VkClearValue ClearValue;
- uint32_t BackBufferCount;
- VkImage BackBuffer[16];
- VkImageView BackBufferView[16];
- VkFramebuffer Framebuffer[16];
- uint32_t FrameIndex;
- ImGui_ImplVulkanH_FrameData Frames[IMGUI_VK_QUEUED_FRAMES];
+ uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
+ uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
+ uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
+ ImGui_ImplVulkanH_Frame* Frames;
+ ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
- IMGUI_IMPL_API ImGui_ImplVulkanH_WindowData();
+ ImGui_ImplVulkanH_Window()
+ {
+ memset(this, 0, sizeof(*this));
+ PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
+ ClearEnable = true;
+ }
};
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index ad43c68..9bedf3f 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -98,6 +98,11 @@
-----------------------------------------------------------------------
Breaking Changes:
+- Examples: Vulkan: Added MinImageCount/ImageCount fields in ImGui_ImplVulkan_InitInfo, required
+ during initialization to specify the number of in-flight image requested by swap chains.
+ (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam]
+- Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely
+ on them but it is possible you have!).
Other Changes:
- InputText: Fixed selection background starts rendering one frame after the cursor movement
@@ -108,11 +113,15 @@
- GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419)
- GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero.
- Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood]
+- Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert
+ to using the ImGui::MemAlloc()/MemFree() calls directly.
- Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized
GL function loaders early, and help users understand what they are missing. (#2421)
- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop.
+- Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int).
- Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
+- Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam]
- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454)
- Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott]
- Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott]
diff --git a/docs/README.md b/docs/README.md
index febacf0..ba48517 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -219,29 +219,32 @@
**Where is the documentation?**
-- The documentation is at the top of imgui.cpp + effectively imgui.h.
-- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output.
-- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder.
-- We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
-- Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ applications and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ - We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
**Which version should I get?**
I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
-You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Several projects are using this branch and it is kept in sync with master regularly.
+You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Many projects are using this branch and it is kept in sync with master regularly.
**Who uses Dear ImGui?**
-See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) pages for an (incomplete) list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
**Why the odd dual naming, "Dear ImGui" vs "ImGui"?**
-The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would taker off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library in ambiguous situations. Please try to refer to it as "Dear ImGui".
+The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would take off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). To reduce this ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library. Please try to refer to this library as "Dear ImGui".
**How can I tell whether to dispatch mouse/keyboard to imgui or to my application?**
**How can I display an image? What is ImTextureID, how does it works?**
-
**How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.**
+
**Why are multiple widgets reacting when I interact with a single one? How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...**
**How can I use my own math types instead of ImVec2/ImVec4?**
**How can I load a different font than the default?**
**How can I easily use icons in my application?**
@@ -254,7 +257,7 @@
**I integrated Dear ImGui in my engine and some elements are disappearing when I move windows around..**
**How can I help?**
-See the FAQ in imgui.cpp for answers.
+See the FAQ in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) for answers.
**Can you create elaborate/serious tools with Dear ImGui?**
diff --git a/docs/issue_template.md b/docs/issue_template.md
index 6d88b27..21f0c1a 100644
--- a/docs/issue_template.md
+++ b/docs/issue_template.md
@@ -4,11 +4,11 @@
https://github.com/ocornut/imgui/issues/2261
2. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/LOADING FONTS, please post on the "Getting Started" Discourse forum:
-https://discourse.dearimgui.org/c/getting-started
+https://discourse.dearimgui.org
-3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
+3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
-4. Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users, unless they browse the site.
+4. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.
5. Delete points 1-5 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue.
diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp
index 6f2c4cd..c1548ff 100644
--- a/examples/example_glfw_vulkan/main.cpp
+++ b/examples/example_glfw_vulkan/main.cpp
@@ -1,6 +1,13 @@
// 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"
@@ -23,19 +30,21 @@
#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 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_WindowData g_WindowData;
-static bool g_ResizeWanted = false;
-static int g_ResizeWidth = 0, g_ResizeHeight = 0;
+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)
{
@@ -107,6 +116,7 @@
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);
@@ -183,7 +193,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -211,14 +223,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -231,15 +241,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -260,7 +276,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -283,7 +299,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -292,18 +308,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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)
@@ -313,14 +330,14 @@
static void glfw_resize_callback(GLFWwindow*, int w, int h)
{
- g_ResizeWanted = true;
- g_ResizeWidth = w;
- g_ResizeHeight = h;
+ g_SwapChainRebuild = true;
+ g_SwapChainResizeWidth = w;
+ g_SwapChainResizeHeight = h;
}
int main(int, char**)
{
- // Setup window
+ // Setup GLFW window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
return 1;
@@ -347,8 +364,8 @@
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glfwSetFramebufferSizeCallback(window, glfw_resize_callback);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
@@ -384,6 +401,8 @@
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);
@@ -429,7 +448,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -445,10 +464,13 @@
// - 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();
- if (g_ResizeWanted)
+
+ if (g_SwapChainRebuild)
{
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, g_ResizeWidth, g_ResizeHeight);
- g_ResizeWanted = false;
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -514,6 +536,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
glfwDestroyWindow(window);
diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp
index 42ab4a6..077a825 100644
--- a/examples/example_sdl_vulkan/main.cpp
+++ b/examples/example_sdl_vulkan/main.cpp
@@ -1,6 +1,13 @@
// dear imgui: standalone example application for SDL2 + 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_sdl.h"
#include "imgui_impl_vulkan.h"
@@ -15,17 +22,21 @@
#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 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_WindowData g_WindowData;
+static ImGui_ImplVulkanH_Window g_MainWindowData;
+static uint32_t 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)
{
@@ -97,6 +108,7 @@
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);
@@ -173,7 +185,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -201,14 +215,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -221,15 +233,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -250,7 +268,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -273,7 +291,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -282,18 +300,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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
}
int main(int, char**)
@@ -331,8 +350,8 @@
// Create Framebuffers
int w, h;
SDL_GetWindowSize(window, &w, &h);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
ImGui::CreateContext();
@@ -366,6 +385,8 @@
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);
@@ -411,7 +432,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -434,7 +455,19 @@
if (event.type == SDL_QUIT)
done = true;
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED && event.window.windowID == SDL_GetWindowID(window))
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, (int)event.window.data1, (int)event.window.data2);
+ {
+ g_SwapChainResizeWidth = (int)event.window.data1;
+ g_SwapChainResizeHeight = (int)event.window.data2;
+ g_SwapChainRebuild = true;
+ }
+ }
+
+ if (g_SwapChainRebuild)
+ {
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -500,6 +533,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
SDL_DestroyWindow(window);
diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp
index 5911878..39ec861 100644
--- a/examples/imgui_impl_vulkan.cpp
+++ b/examples/imgui_impl_vulkan.cpp
@@ -12,8 +12,17 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2019-XX-XX: *BREAKING CHANGE*: Vulkan: Added ImageCount/MinImageCount fields in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetMinImageCount().
+// 2019-XX-XX: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper.
// 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
// 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int).
// 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display.
@@ -35,46 +44,61 @@
#include "imgui_impl_vulkan.h"
#include
-// Vulkan data
-static const VkAllocationCallbacks* g_Allocator = NULL;
-static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE;
-static VkInstance g_Instance = 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 VkPipelineCache g_PipelineCache = VK_NULL_HANDLE;
-static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
-static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
-static void (*g_CheckVkResultFn)(VkResult err) = NULL;
-
-static VkDeviceSize g_BufferMemoryAlignment = 256;
-static VkPipelineCreateFlags g_PipelineCreateFlags = 0;
-
-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;
-
-// Frame data
-struct FrameDataForRender
+// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_FrameRenderBuffers
{
- VkDeviceMemory VertexBufferMemory;
- VkDeviceMemory IndexBufferMemory;
- VkDeviceSize VertexBufferSize;
- VkDeviceSize IndexBufferSize;
- VkBuffer VertexBuffer;
- VkBuffer IndexBuffer;
+ VkDeviceMemory VertexBufferMemory;
+ VkDeviceMemory IndexBufferMemory;
+ VkDeviceSize VertexBufferSize;
+ VkDeviceSize IndexBufferSize;
+ VkBuffer VertexBuffer;
+ VkBuffer IndexBuffer;
};
-static int g_FrameIndex = 0;
-static FrameDataForRender g_FramesDataBuffers[IMGUI_VK_QUEUED_FRAMES] = {};
+
+// Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_WindowRenderBuffers
+{
+ uint32_t Index;
+ uint32_t Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* FrameRenderBuffers;
+};
+
+// Vulkan data
+static ImGui_ImplVulkan_InitInfo g_VulkanInitInfo = {};
+static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
+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
-static VkSampler g_FontSampler = VK_NULL_HANDLE;
-static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
-static VkImage g_FontImage = VK_NULL_HANDLE;
-static VkImageView g_FontView = VK_NULL_HANDLE;
-static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
-static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+static VkSampler g_FontSampler = VK_NULL_HANDLE;
+static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
+static VkImage g_FontImage = VK_NULL_HANDLE;
+static VkImageView g_FontView = VK_NULL_HANDLE;
+static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
+static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+
+// Render buffers
+static ImGui_ImplVulkanH_WindowRenderBuffers g_MainWindowRenderBuffers;
+
+// Forward Declarations
+bool ImGui_ImplVulkan_CreateDeviceObjects();
+void ImGui_ImplVulkan_DestroyDeviceObjects();
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
+
+//-----------------------------------------------------------------------------
+// SHADERS
+//-----------------------------------------------------------------------------
// Forward Declarations
static void ImGui_ImplVulkan_InitPlatformInterface();
@@ -185,10 +209,15 @@
0x00010038
};
+//-----------------------------------------------------------------------------
+// FUNCTIONS
+//-----------------------------------------------------------------------------
+
static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkPhysicalDeviceMemoryProperties prop;
- vkGetPhysicalDeviceMemoryProperties(g_PhysicalDevice, &prop);
+ vkGetPhysicalDeviceMemoryProperties(v->PhysicalDevice, &prop);
for (uint32_t i = 0; i < prop.memoryTypeCount; i++)
if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<CheckVkResultFn)
+ v->CheckVkResultFn(err);
}
static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
if (buffer != VK_NULL_HANDLE)
- vkDestroyBuffer(g_Device, buffer, g_Allocator);
- if (buffer_memory)
- vkFreeMemory(g_Device, buffer_memory, g_Allocator);
+ vkDestroyBuffer(v->Device, buffer, v->Allocator);
+ if (buffer_memory != VK_NULL_HANDLE)
+ vkFreeMemory(v->Device, buffer_memory, v->Allocator);
VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / g_BufferMemoryAlignment + 1) * g_BufferMemoryAlignment;
VkBufferCreateInfo buffer_info = {};
@@ -215,20 +246,20 @@
buffer_info.size = vertex_buffer_size_aligned;
buffer_info.usage = usage;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &buffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &buffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, buffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, buffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &buffer_memory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &buffer_memory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, buffer, buffer_memory, 0);
+ err = vkBindBufferMemory(v->Device, buffer, buffer_memory, 0);
check_vk_result(err);
p_buffer_size = new_size;
}
@@ -243,25 +274,38 @@
if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount == 0)
return;
- VkResult err;
- FrameDataForRender* fd = &g_FramesDataBuffers[g_FrameIndex];
- g_FrameIndex = (g_FrameIndex + 1) % IM_ARRAYSIZE(g_FramesDataBuffers);
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
- // Create the Vertex and Index buffers:
+ // Allocate array to store enough vertex/index buffers
+ ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &g_MainWindowRenderBuffers;
+ if (wrb->FrameRenderBuffers == NULL)
+ {
+ wrb->Index = 0;
+ wrb->Count = v->ImageCount;
+ wrb->FrameRenderBuffers = (ImGui_ImplVulkanH_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ }
+ IM_ASSERT(wrb->Count == v->ImageCount);
+ wrb->Index = (wrb->Index + 1) % wrb->Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index];
+
+ VkResult err;
+
+ // Create or resize the vertex/index buffers
size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);
size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx);
- if (fd->VertexBuffer == VK_NULL_HANDLE || fd->VertexBufferSize < vertex_size)
- CreateOrResizeBuffer(fd->VertexBuffer, fd->VertexBufferMemory, fd->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
- if (fd->IndexBuffer == VK_NULL_HANDLE || fd->IndexBufferSize < index_size)
- CreateOrResizeBuffer(fd->IndexBuffer, fd->IndexBufferMemory, fd->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
+ if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size)
+ CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+ if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size)
+ CreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
// Upload vertex/index data into a single contiguous GPU buffer
{
ImDrawVert* vtx_dst = NULL;
ImDrawIdx* idx_dst = NULL;
- err = vkMapMemory(g_Device, fd->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
+ err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
check_vk_result(err);
- err = vkMapMemory(g_Device, fd->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
+ err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
check_vk_result(err);
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
@@ -273,15 +317,15 @@
}
VkMappedMemoryRange range[2] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[0].memory = fd->VertexBufferMemory;
+ range[0].memory = rb->VertexBufferMemory;
range[0].size = VK_WHOLE_SIZE;
range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[1].memory = fd->IndexBufferMemory;
+ range[1].memory = rb->IndexBufferMemory;
range[1].size = VK_WHOLE_SIZE;
- err = vkFlushMappedMemoryRanges(g_Device, 2, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 2, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, fd->VertexBufferMemory);
- vkUnmapMemory(g_Device, fd->IndexBufferMemory);
+ vkUnmapMemory(v->Device, rb->VertexBufferMemory);
+ vkUnmapMemory(v->Device, rb->IndexBufferMemory);
}
// Bind pipeline and descriptor sets:
@@ -293,10 +337,10 @@
// Bind Vertex And Index Buffer:
{
- VkBuffer vertex_buffers[1] = { fd->VertexBuffer };
+ VkBuffer vertex_buffers[1] = { rb->VertexBuffer };
VkDeviceSize vertex_offset[1] = { 0 };
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset);
- vkCmdBindIndexBuffer(command_buffer, fd->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
+ vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
}
// Setup viewport:
@@ -379,6 +423,7 @@
bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
@@ -404,17 +449,17 @@
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- err = vkCreateImage(g_Device, &info, g_Allocator, &g_FontImage);
+ err = vkCreateImage(v->Device, &info, v->Allocator, &g_FontImage);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetImageMemoryRequirements(g_Device, g_FontImage, &req);
+ vkGetImageMemoryRequirements(v->Device, g_FontImage, &req);
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_FontMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_FontMemory);
check_vk_result(err);
- err = vkBindImageMemory(g_Device, g_FontImage, g_FontMemory, 0);
+ err = vkBindImageMemory(v->Device, g_FontImage, g_FontMemory, 0);
check_vk_result(err);
}
@@ -428,7 +473,7 @@
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.levelCount = 1;
info.subresourceRange.layerCount = 1;
- err = vkCreateImageView(g_Device, &info, g_Allocator, &g_FontView);
+ err = vkCreateImageView(v->Device, &info, v->Allocator, &g_FontView);
check_vk_result(err);
}
@@ -444,7 +489,7 @@
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
- vkUpdateDescriptorSets(g_Device, 1, write_desc, 0, NULL);
+ vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
// Create the Upload Buffer:
@@ -454,34 +499,34 @@
buffer_info.size = upload_size;
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_UploadBuffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &g_UploadBuffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, g_UploadBuffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, g_UploadBuffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_UploadBufferMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_UploadBufferMemory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, g_UploadBuffer, g_UploadBufferMemory, 0);
+ err = vkBindBufferMemory(v->Device, g_UploadBuffer, g_UploadBufferMemory, 0);
check_vk_result(err);
}
// Upload to Buffer:
{
char* map = NULL;
- err = vkMapMemory(g_Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
+ err = vkMapMemory(v->Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
check_vk_result(err);
memcpy(map, pixels, upload_size);
VkMappedMemoryRange range[1] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[0].memory = g_UploadBufferMemory;
range[0].size = upload_size;
- err = vkFlushMappedMemoryRanges(g_Device, 1, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 1, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, g_UploadBufferMemory);
+ vkUnmapMemory(v->Device, g_UploadBufferMemory);
}
// Copy to Image:
@@ -530,6 +575,7 @@
bool ImGui_ImplVulkan_CreateDeviceObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
VkShaderModule vert_module;
VkShaderModule frag_module;
@@ -540,13 +586,13 @@
vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
vert_info.codeSize = sizeof(__glsl_shader_vert_spv);
vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv;
- err = vkCreateShaderModule(g_Device, &vert_info, g_Allocator, &vert_module);
+ err = vkCreateShaderModule(v->Device, &vert_info, v->Allocator, &vert_module);
check_vk_result(err);
VkShaderModuleCreateInfo frag_info = {};
frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
frag_info.codeSize = sizeof(__glsl_shader_frag_spv);
frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv;
- err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module);
+ err = vkCreateShaderModule(v->Device, &frag_info, v->Allocator, &frag_module);
check_vk_result(err);
}
@@ -563,7 +609,7 @@
info.minLod = -1000;
info.maxLod = 1000;
info.maxAnisotropy = 1.0f;
- err = vkCreateSampler(g_Device, &info, g_Allocator, &g_FontSampler);
+ err = vkCreateSampler(v->Device, &info, v->Allocator, &g_FontSampler);
check_vk_result(err);
}
@@ -579,7 +625,7 @@
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
info.bindingCount = 1;
info.pBindings = binding;
- err = vkCreateDescriptorSetLayout(g_Device, &info, g_Allocator, &g_DescriptorSetLayout);
+ err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &g_DescriptorSetLayout);
check_vk_result(err);
}
@@ -587,10 +633,10 @@
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- alloc_info.descriptorPool = g_DescriptorPool;
+ alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &g_DescriptorSetLayout;
- err = vkAllocateDescriptorSets(g_Device, &alloc_info, &g_DescriptorSet);
+ err = vkAllocateDescriptorSets(v->Device, &alloc_info, &g_DescriptorSet);
check_vk_result(err);
}
@@ -608,7 +654,7 @@
layout_info.pSetLayouts = set_layout;
layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = push_constants;
- err = vkCreatePipelineLayout(g_Device, &layout_info, g_Allocator, &g_PipelineLayout);
+ err = vkCreatePipelineLayout(v->Device, &layout_info, v->Allocator, &g_PipelineLayout);
check_vk_result(err);
}
@@ -706,49 +752,43 @@
info.pDynamicState = &dynamic_state;
info.layout = g_PipelineLayout;
info.renderPass = g_RenderPass;
- err = vkCreateGraphicsPipelines(g_Device, g_PipelineCache, 1, &info, g_Allocator, &g_Pipeline);
+ err = vkCreateGraphicsPipelines(v->Device, v->PipelineCache, 1, &info, v->Allocator, &g_Pipeline);
check_vk_result(err);
- vkDestroyShaderModule(g_Device, vert_module, g_Allocator);
- vkDestroyShaderModule(g_Device, frag_module, g_Allocator);
+ vkDestroyShaderModule(v->Device, vert_module, v->Allocator);
+ vkDestroyShaderModule(v->Device, frag_module, v->Allocator);
return true;
}
-void ImGui_ImplVulkan_InvalidateFontUploadObjects()
+void ImGui_ImplVulkan_DestroyFontUploadObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
if (g_UploadBuffer)
{
- vkDestroyBuffer(g_Device, g_UploadBuffer, g_Allocator);
+ vkDestroyBuffer(v->Device, g_UploadBuffer, v->Allocator);
g_UploadBuffer = VK_NULL_HANDLE;
}
if (g_UploadBufferMemory)
{
- vkFreeMemory(g_Device, g_UploadBufferMemory, g_Allocator);
+ vkFreeMemory(v->Device, g_UploadBufferMemory, v->Allocator);
g_UploadBufferMemory = VK_NULL_HANDLE;
}
}
-void ImGui_ImplVulkan_InvalidateDeviceObjects()
+void ImGui_ImplVulkan_DestroyDeviceObjects()
{
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
- for (int i = 0; i < IM_ARRAYSIZE(g_FramesDataBuffers); i++)
- {
- FrameDataForRender* fd = &g_FramesDataBuffers[i];
- if (fd->VertexBuffer) { vkDestroyBuffer (g_Device, fd->VertexBuffer, g_Allocator); fd->VertexBuffer = VK_NULL_HANDLE; }
- if (fd->VertexBufferMemory) { vkFreeMemory (g_Device, fd->VertexBufferMemory, g_Allocator); fd->VertexBufferMemory = VK_NULL_HANDLE; }
- if (fd->IndexBuffer) { vkDestroyBuffer (g_Device, fd->IndexBuffer, g_Allocator); fd->IndexBuffer = VK_NULL_HANDLE; }
- if (fd->IndexBufferMemory) { vkFreeMemory (g_Device, fd->IndexBufferMemory, g_Allocator); fd->IndexBufferMemory = VK_NULL_HANDLE; }
- }
-
- if (g_FontView) { vkDestroyImageView(g_Device, g_FontView, g_Allocator); g_FontView = VK_NULL_HANDLE; }
- if (g_FontImage) { vkDestroyImage(g_Device, g_FontImage, g_Allocator); g_FontImage = VK_NULL_HANDLE; }
- if (g_FontMemory) { vkFreeMemory(g_Device, g_FontMemory, g_Allocator); g_FontMemory = VK_NULL_HANDLE; }
- if (g_FontSampler) { vkDestroySampler(g_Device, g_FontSampler, g_Allocator); g_FontSampler = VK_NULL_HANDLE; }
- if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(g_Device, g_DescriptorSetLayout, g_Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
- if (g_PipelineLayout) { vkDestroyPipelineLayout(g_Device, g_PipelineLayout, g_Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
- if (g_Pipeline) { vkDestroyPipeline(g_Device, g_Pipeline, g_Allocator); g_Pipeline = VK_NULL_HANDLE; }
+ if (g_FontView) { vkDestroyImageView(v->Device, g_FontView, v->Allocator); g_FontView = VK_NULL_HANDLE; }
+ if (g_FontImage) { vkDestroyImage(v->Device, g_FontImage, v->Allocator); g_FontImage = VK_NULL_HANDLE; }
+ if (g_FontMemory) { vkFreeMemory(v->Device, g_FontMemory, v->Allocator); g_FontMemory = VK_NULL_HANDLE; }
+ if (g_FontSampler) { vkDestroySampler(v->Device, g_FontSampler, v->Allocator); g_FontSampler = VK_NULL_HANDLE; }
+ if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, g_DescriptorSetLayout, v->Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
+ if (g_PipelineLayout) { vkDestroyPipelineLayout(v->Device, g_PipelineLayout, v->Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
+ if (g_Pipeline) { vkDestroyPipeline(v->Device, g_Pipeline, v->Allocator); g_Pipeline = VK_NULL_HANDLE; }
}
bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass)
@@ -763,19 +803,12 @@
IM_ASSERT(info->Device != VK_NULL_HANDLE);
IM_ASSERT(info->Queue != VK_NULL_HANDLE);
IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE);
+ IM_ASSERT(info->MinImageCount >= 2);
+ IM_ASSERT(info->ImageCount >= info->MinImageCount);
IM_ASSERT(render_pass != VK_NULL_HANDLE);
- g_Instance = info->Instance;
- g_PhysicalDevice = info->PhysicalDevice;
- g_Device = info->Device;
- g_QueueFamily = info->QueueFamily;
- g_Queue = info->Queue;
+ g_VulkanInitInfo = *info;
g_RenderPass = render_pass;
- g_PipelineCache = info->PipelineCache;
- g_DescriptorPool = info->DescriptorPool;
- g_Allocator = info->Allocator;
- g_CheckVkResultFn = info->CheckVkResultFn;
-
ImGui_ImplVulkan_CreateDeviceObjects();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
@@ -787,16 +820,30 @@
void ImGui_ImplVulkan_Shutdown()
{
ImGui_ImplVulkan_ShutdownPlatformInterface();
- ImGui_ImplVulkan_InvalidateDeviceObjects();
+ ImGui_ImplVulkan_DestroyDeviceObjects();
}
void ImGui_ImplVulkan_NewFrame()
{
}
+void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
+{
+ IM_ASSERT(min_image_count >= 2);
+ if (g_VulkanInitInfo.MinImageCount == min_image_count)
+ return;
+
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ VkResult err = vkDeviceWaitIdle(v->Device);
+ check_vk_result(err);
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ g_VulkanInitInfo.MinImageCount = min_image_count;
+}
+
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -804,40 +851,12 @@
// 2) the upcoming multi-viewport feature will need them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-#include // malloc
-
-ImGui_ImplVulkanH_FrameData::ImGui_ImplVulkanH_FrameData()
-{
- BackbufferIndex = 0;
- CommandPool = VK_NULL_HANDLE;
- CommandBuffer = VK_NULL_HANDLE;
- Fence = VK_NULL_HANDLE;
- ImageAcquiredSemaphore = VK_NULL_HANDLE;
- RenderCompleteSemaphore = VK_NULL_HANDLE;
-}
-
-ImGui_ImplVulkanH_WindowData::ImGui_ImplVulkanH_WindowData()
-{
- Width = Height = 0;
- Swapchain = VK_NULL_HANDLE;
- Surface = VK_NULL_HANDLE;
- memset(&SurfaceFormat, 0, sizeof(SurfaceFormat));
- PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
- RenderPass = VK_NULL_HANDLE;
- ClearEnable = true;
- memset(&ClearValue, 0, sizeof(ClearValue));
- BackBufferCount = 0;
- memset(&BackBuffer, 0, sizeof(BackBuffer));
- memset(&BackBufferView, 0, sizeof(BackBufferView));
- memset(&Framebuffer, 0, sizeof(Framebuffer));
- FrameIndex = 0;
-}
-
VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space)
{
IM_ASSERT(request_formats != NULL);
@@ -904,7 +923,7 @@
return VK_PRESENT_MODE_FIFO_KHR; // Always available
}
-void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator)
{
IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE);
(void)physical_device;
@@ -912,9 +931,10 @@
// Create Command Buffers
VkResult err;
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i];
{
VkCommandPoolCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
@@ -942,9 +962,9 @@
{
VkSemaphoreCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- err = vkCreateSemaphore(device, &info, allocator, &fd->ImageAcquiredSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->ImageAcquiredSemaphore);
check_vk_result(err);
- err = vkCreateSemaphore(device, &info, allocator, &fd->RenderCompleteSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->RenderCompleteSemaphore);
check_vk_result(err);
}
}
@@ -962,24 +982,26 @@
return 1;
}
-void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h)
+// Also destroy old swap chain and in-flight frames data, if any.
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count)
{
- uint32_t min_image_count = 2; // FIXME: this should become a function parameter
-
VkResult err;
VkSwapchainKHR old_swapchain = wd->Swapchain;
err = vkDeviceWaitIdle(device);
check_vk_result(err);
+ // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one.
// Destroy old Framebuffer
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- if (wd->BackBufferView[i])
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- if (wd->Framebuffer[i])
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- wd->BackBufferCount = 0;
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
+ wd->ImageCount = 0;
if (wd->RenderPass)
vkDestroyRenderPass(device, wd->RenderPass, allocator);
@@ -1023,10 +1045,21 @@
}
err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, NULL);
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, NULL);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, wd->BackBuffer);
+ VkImage backbuffers[16] = {};
+ IM_ASSERT(wd->ImageCount >= min_image_count);
+ IM_ASSERT(wd->ImageCount < IM_ARRAYSIZE(backbuffers));
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers);
check_vk_result(err);
+
+ IM_ASSERT(wd->Frames == NULL);
+ wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount);
+ wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->ImageCount);
+ memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount);
+ memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->ImageCount);
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
+ wd->Frames[i].Backbuffer = backbuffers[i];
}
if (old_swapchain)
vkDestroySwapchainKHR(device, old_swapchain, allocator);
@@ -1080,10 +1113,11 @@
info.components.a = VK_COMPONENT_SWIZZLE_A;
VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
info.subresourceRange = image_range;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- info.image = wd->BackBuffer[i];
- err = vkCreateImageView(device, &info, allocator, &wd->BackBufferView[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ info.image = fd->Backbuffer;
+ err = vkCreateImageView(device, &info, allocator, &fd->BackbufferView);
check_vk_result(err);
}
}
@@ -1099,38 +1133,82 @@
info.width = wd->Width;
info.height = wd->Height;
info.layers = 1;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- attachment[0] = wd->BackBufferView[i];
- err = vkCreateFramebuffer(device, &info, allocator, &wd->Framebuffer[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ attachment[0] = fd->BackbufferView;
+ err = vkCreateFramebuffer(device, &info, allocator, &fd->Framebuffer);
check_vk_result(err);
}
}
}
-void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count)
+{
+ (void)instance;
+ ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count);
+ ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator)
{
vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals)
//vkQueueWaitIdle(g_Queue);
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
- vkDestroyFence(device, fd->Fence, allocator);
- vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
- vkDestroyCommandPool(device, fd->CommandPool, allocator);
- vkDestroySemaphore(device, fd->ImageAcquiredSemaphore, allocator);
- vkDestroySemaphore(device, fd->RenderCompleteSemaphore, allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
- {
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
- }
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
vkDestroyRenderPass(device, wd->RenderPass, allocator);
vkDestroySwapchainKHR(device, wd->Swapchain, allocator);
vkDestroySurfaceKHR(instance, wd->Surface, allocator);
- *wd = ImGui_ImplVulkanH_WindowData();
+
+ *wd = ImGui_ImplVulkanH_Window();
+}
+
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroyFence(device, fd->Fence, allocator);
+ vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
+ vkDestroyCommandPool(device, fd->CommandPool, allocator);
+ fd->Fence = VK_NULL_HANDLE;
+ fd->CommandBuffer = VK_NULL_HANDLE;
+ fd->CommandPool = VK_NULL_HANDLE;
+
+ vkDestroyImageView(device, fd->BackbufferView, allocator);
+ vkDestroyFramebuffer(device, fd->Framebuffer, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator);
+ vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator);
+ fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;
+}
+
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; }
+ if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; }
+ if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; }
+ if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; }
+ buffers->VertexBufferSize = 0;
+ buffers->IndexBufferSize = 0;
+}
+
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ for (uint32_t n = 0; n < buffers->Count; n++)
+ ImGui_ImplVulkanH_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator);
+ IM_FREE(buffers->FrameRenderBuffers);
+ buffers->FrameRenderBuffers = NULL;
+ buffers->Index = 0;
+ buffers->Count = 0;
}
//--------------------------------------------------------------------------------------------------------
diff --git a/examples/imgui_impl_vulkan.h b/examples/imgui_impl_vulkan.h
index ec45dbe..0389af5 100644
--- a/examples/imgui_impl_vulkan.h
+++ b/examples/imgui_impl_vulkan.h
@@ -12,24 +12,32 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
#pragma once
#include
-#define IMGUI_VK_QUEUED_FRAMES 2
-
-// Please zero-clear before use.
+// Initialization data, for ImGui_ImplVulkan_Init()
+// [Please zero-clear before use!]
struct ImGui_ImplVulkan_InitInfo
{
- VkInstance Instance;
- VkPhysicalDevice PhysicalDevice;
- VkDevice Device;
- uint32_t QueueFamily;
- VkQueue Queue;
- VkPipelineCache PipelineCache;
- VkDescriptorPool DescriptorPool;
- const VkAllocationCallbacks* Allocator;
- void (*CheckVkResultFn)(VkResult err);
+ VkInstance Instance;
+ VkPhysicalDevice PhysicalDevice;
+ VkDevice Device;
+ uint32_t QueueFamily;
+ VkQueue Queue;
+ VkPipelineCache PipelineCache;
+ VkDescriptorPool DescriptorPool;
+ uint32_t MinImageCount; // >= 2
+ uint32_t ImageCount; // >= MinImageCount
+ const VkAllocationCallbacks* Allocator;
+ void (*CheckVkResultFn)(VkResult err);
};
// Called by user code
@@ -38,16 +46,13 @@
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
-IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateFontUploadObjects();
-
-// Called by ImGui_ImplVulkan_Init() might be useful elsewhere.
-IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateDeviceObjects();
-IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateDeviceObjects();
+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)
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -55,38 +60,44 @@
// 2) the multi-viewport / platform window implementation needs them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-struct ImGui_ImplVulkanH_FrameData;
-struct ImGui_ImplVulkanH_WindowData;
+struct ImGui_ImplVulkanH_Frame;
+struct ImGui_ImplVulkanH_Window;
-IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
-IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h);
-IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
+// Helpers
+IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wnd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator);
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
// Helper structure to hold the data needed by one rendering frame
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
-struct ImGui_ImplVulkanH_FrameData
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_Frame
{
- uint32_t BackbufferIndex; // Keep track of recently rendered swapchain frame indices
VkCommandPool CommandPool;
VkCommandBuffer CommandBuffer;
VkFence Fence;
+ VkImage Backbuffer;
+ VkImageView BackbufferView;
+ VkFramebuffer Framebuffer;
+};
+
+struct ImGui_ImplVulkanH_FrameSemaphores
+{
VkSemaphore ImageAcquiredSemaphore;
VkSemaphore RenderCompleteSemaphore;
-
- IMGUI_IMPL_API ImGui_ImplVulkanH_FrameData();
};
// Helper structure to hold the data needed by one rendering context into one OS window
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
-struct ImGui_ImplVulkanH_WindowData
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+struct ImGui_ImplVulkanH_Window
{
int Width;
int Height;
@@ -97,13 +108,17 @@
VkRenderPass RenderPass;
bool ClearEnable;
VkClearValue ClearValue;
- uint32_t BackBufferCount;
- VkImage BackBuffer[16];
- VkImageView BackBufferView[16];
- VkFramebuffer Framebuffer[16];
- uint32_t FrameIndex;
- ImGui_ImplVulkanH_FrameData Frames[IMGUI_VK_QUEUED_FRAMES];
+ uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
+ uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
+ uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
+ ImGui_ImplVulkanH_Frame* Frames;
+ ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
- IMGUI_IMPL_API ImGui_ImplVulkanH_WindowData();
+ ImGui_ImplVulkanH_Window()
+ {
+ memset(this, 0, sizeof(*this));
+ PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
+ ClearEnable = true;
+ }
};
diff --git a/imgui.cpp b/imgui.cpp
index c96b2d8..65ea119 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -37,9 +37,14 @@
- Using gamepad/keyboard navigation controls.
- API BREAKING CHANGES (read me when you update!)
- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
+ - Where is the documentation?
+ - Which version should I get?
+ - Who uses Dear ImGui?
+ - Why the odd dual naming, "Dear ImGui" vs "ImGui"?
- How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
- How can I display an image? What is ImTextureID, how does it works?
- - How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.
+ - Why are multiple widgets reacting when I interact with a single one? How can I have
+ multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...
- How can I use my own math types instead of ImVec2/ImVec4?
- How can I load a different font than the default?
- How can I easily use icons in my application?
@@ -563,6 +568,39 @@
FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
======================================
+ Q: Where is the documentation?
+ A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/
+ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments
+ associated to it.
+
+ Q: Which version should I get?
+ A: I occasionally tag Releases (https://github.com/ocornut/imgui/releases) but it is generally safe
+ and recommended to sync to master/latest. The library is fairly stable and regressions tend to be
+ fixed fast when reported. You may also peak at the 'docking' branch which includes:
+ - Docking/Merging features (https://github.com/ocornut/imgui/issues/2109)
+ - Multi-viewport features (https://github.com/ocornut/imgui/issues/1542)
+ Many projects are using this branch and it is kept in sync with master regularly.
+
+ Q: Who uses Dear ImGui?
+ A: See "Quotes" (https://github.com/ocornut/imgui/wiki/Quotes) and
+ "Software using Dear ImGui" (https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages
+ for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+
+ Q: Why the odd dual naming, "Dear ImGui" vs "ImGui"?
+ A: The library started its life as "ImGui" due to the fact that I didn't give it a proper name when
+ when I released 1.0, and had no particular expectation that it would take off. However, the term IMGUI
+ (immediate-mode graphical user interface) was coined before and is being used in variety of other
+ situations (e.g. Unity uses it own implementation of the IMGUI paradigm).
+ To reduce the ambiguity without affecting existing code bases, I have decided on an alternate,
+ longer name "Dear ImGui" that people can use to refer to this specific library.
+ Please try to refer to this library as "Dear ImGui".
+
Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure (e.g. if (ImGui::GetIO().WantCaptureMouse) { ... } )
- When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application.
@@ -664,8 +702,8 @@
Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated.
+ Q: Why are multiple widgets reacting when I interact with a single one?
Q: How can I have multiple widgets with the same label or with an empty label?
- Q: I have multiple widgets with the same label, and only the first one works. Why is that?
A: A primer on labels and the ID Stack...
Dear ImGui internally need to uniquely identify UI elements.
@@ -1344,7 +1382,7 @@
char* ImStrdup(const char* str)
{
size_t len = strlen(str);
- void* buf = ImGui::MemAlloc(len + 1);
+ void* buf = IM_ALLOC(len + 1);
return (char*)memcpy(buf, (const void*)str, len + 1);
}
@@ -1354,8 +1392,8 @@
size_t src_size = strlen(src) + 1;
if (dst_buf_size < src_size)
{
- ImGui::MemFree(dst);
- dst = (char*)ImGui::MemAlloc(src_size);
+ IM_FREE(dst);
+ dst = (char*)IM_ALLOC(src_size);
if (p_dst_size)
*p_dst_size = src_size;
}
@@ -1571,7 +1609,7 @@
}
// Load file content into memory
-// Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
+// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()
void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes)
{
IM_ASSERT(filename && file_open_mode);
@@ -1590,7 +1628,7 @@
}
size_t file_size = (size_t)file_size_signed;
- void* file_data = ImGui::MemAlloc(file_size + padding_bytes);
+ void* file_data = IM_ALLOC(file_size + padding_bytes);
if (file_data == NULL)
{
fclose(f);
@@ -1599,7 +1637,7 @@
if (fread(file_data, 1, file_size, f) != file_size)
{
fclose(f);
- ImGui::MemFree(file_data);
+ IM_FREE(file_data);
return NULL;
}
if (padding_bytes > 0)
@@ -3024,6 +3062,7 @@
return ImMax(wrap_pos_x - pos.x, 1.0f);
}
+// IM_ALLOC() == ImGui::MemAlloc()
void* ImGui::MemAlloc(size_t size)
{
if (ImGuiContext* ctx = GImGui)
@@ -3031,6 +3070,7 @@
return GImAllocatorAllocFunc(size, GImAllocatorUserData);
}
+// IM_FREE() == ImGui::MemFree()
void ImGui::MemFree(void* ptr)
{
if (ptr)
@@ -9790,7 +9830,7 @@
if (!file_data)
return;
LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
- ImGui::MemFree(file_data);
+ IM_FREE(file_data);
}
ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
@@ -9814,7 +9854,7 @@
// For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy..
if (ini_size == 0)
ini_size = strlen(ini_data);
- char* buf = (char*)ImGui::MemAlloc(ini_size + 1);
+ char* buf = (char*)IM_ALLOC(ini_size + 1);
char* buf_end = buf + ini_size;
memcpy(buf, ini_data, ini_size);
buf[ini_size] = 0;
@@ -9861,7 +9901,7 @@
entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
}
}
- ImGui::MemFree(buf);
+ IM_FREE(buf);
g.SettingsLoaded = true;
DockContextOnLoadSettings(&g);
}
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index ad43c68..9bedf3f 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -98,6 +98,11 @@
-----------------------------------------------------------------------
Breaking Changes:
+- Examples: Vulkan: Added MinImageCount/ImageCount fields in ImGui_ImplVulkan_InitInfo, required
+ during initialization to specify the number of in-flight image requested by swap chains.
+ (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam]
+- Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely
+ on them but it is possible you have!).
Other Changes:
- InputText: Fixed selection background starts rendering one frame after the cursor movement
@@ -108,11 +113,15 @@
- GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419)
- GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero.
- Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood]
+- Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert
+ to using the ImGui::MemAlloc()/MemFree() calls directly.
- Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized
GL function loaders early, and help users understand what they are missing. (#2421)
- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop.
+- Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int).
- Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
+- Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam]
- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454)
- Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott]
- Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott]
diff --git a/docs/README.md b/docs/README.md
index febacf0..ba48517 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -219,29 +219,32 @@
**Where is the documentation?**
-- The documentation is at the top of imgui.cpp + effectively imgui.h.
-- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output.
-- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder.
-- We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
-- Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ applications and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ - We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
**Which version should I get?**
I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
-You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Several projects are using this branch and it is kept in sync with master regularly.
+You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Many projects are using this branch and it is kept in sync with master regularly.
**Who uses Dear ImGui?**
-See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) pages for an (incomplete) list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
**Why the odd dual naming, "Dear ImGui" vs "ImGui"?**
-The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would taker off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library in ambiguous situations. Please try to refer to it as "Dear ImGui".
+The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would take off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). To reduce this ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library. Please try to refer to this library as "Dear ImGui".
**How can I tell whether to dispatch mouse/keyboard to imgui or to my application?**
**How can I display an image? What is ImTextureID, how does it works?**
-
**How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.**
+
**Why are multiple widgets reacting when I interact with a single one? How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...**
**How can I use my own math types instead of ImVec2/ImVec4?**
**How can I load a different font than the default?**
**How can I easily use icons in my application?**
@@ -254,7 +257,7 @@
**I integrated Dear ImGui in my engine and some elements are disappearing when I move windows around..**
**How can I help?**
-See the FAQ in imgui.cpp for answers.
+See the FAQ in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) for answers.
**Can you create elaborate/serious tools with Dear ImGui?**
diff --git a/docs/issue_template.md b/docs/issue_template.md
index 6d88b27..21f0c1a 100644
--- a/docs/issue_template.md
+++ b/docs/issue_template.md
@@ -4,11 +4,11 @@
https://github.com/ocornut/imgui/issues/2261
2. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/LOADING FONTS, please post on the "Getting Started" Discourse forum:
-https://discourse.dearimgui.org/c/getting-started
+https://discourse.dearimgui.org
-3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
+3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
-4. Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users, unless they browse the site.
+4. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.
5. Delete points 1-5 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue.
diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp
index 6f2c4cd..c1548ff 100644
--- a/examples/example_glfw_vulkan/main.cpp
+++ b/examples/example_glfw_vulkan/main.cpp
@@ -1,6 +1,13 @@
// 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"
@@ -23,19 +30,21 @@
#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 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_WindowData g_WindowData;
-static bool g_ResizeWanted = false;
-static int g_ResizeWidth = 0, g_ResizeHeight = 0;
+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)
{
@@ -107,6 +116,7 @@
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);
@@ -183,7 +193,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -211,14 +223,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -231,15 +241,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -260,7 +276,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -283,7 +299,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -292,18 +308,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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)
@@ -313,14 +330,14 @@
static void glfw_resize_callback(GLFWwindow*, int w, int h)
{
- g_ResizeWanted = true;
- g_ResizeWidth = w;
- g_ResizeHeight = h;
+ g_SwapChainRebuild = true;
+ g_SwapChainResizeWidth = w;
+ g_SwapChainResizeHeight = h;
}
int main(int, char**)
{
- // Setup window
+ // Setup GLFW window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
return 1;
@@ -347,8 +364,8 @@
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glfwSetFramebufferSizeCallback(window, glfw_resize_callback);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
@@ -384,6 +401,8 @@
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);
@@ -429,7 +448,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -445,10 +464,13 @@
// - 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();
- if (g_ResizeWanted)
+
+ if (g_SwapChainRebuild)
{
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, g_ResizeWidth, g_ResizeHeight);
- g_ResizeWanted = false;
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -514,6 +536,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
glfwDestroyWindow(window);
diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp
index 42ab4a6..077a825 100644
--- a/examples/example_sdl_vulkan/main.cpp
+++ b/examples/example_sdl_vulkan/main.cpp
@@ -1,6 +1,13 @@
// dear imgui: standalone example application for SDL2 + 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_sdl.h"
#include "imgui_impl_vulkan.h"
@@ -15,17 +22,21 @@
#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 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_WindowData g_WindowData;
+static ImGui_ImplVulkanH_Window g_MainWindowData;
+static uint32_t 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)
{
@@ -97,6 +108,7 @@
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);
@@ -173,7 +185,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -201,14 +215,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -221,15 +233,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -250,7 +268,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -273,7 +291,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -282,18 +300,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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
}
int main(int, char**)
@@ -331,8 +350,8 @@
// Create Framebuffers
int w, h;
SDL_GetWindowSize(window, &w, &h);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
ImGui::CreateContext();
@@ -366,6 +385,8 @@
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);
@@ -411,7 +432,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -434,7 +455,19 @@
if (event.type == SDL_QUIT)
done = true;
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED && event.window.windowID == SDL_GetWindowID(window))
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, (int)event.window.data1, (int)event.window.data2);
+ {
+ g_SwapChainResizeWidth = (int)event.window.data1;
+ g_SwapChainResizeHeight = (int)event.window.data2;
+ g_SwapChainRebuild = true;
+ }
+ }
+
+ if (g_SwapChainRebuild)
+ {
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -500,6 +533,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
SDL_DestroyWindow(window);
diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp
index 5911878..39ec861 100644
--- a/examples/imgui_impl_vulkan.cpp
+++ b/examples/imgui_impl_vulkan.cpp
@@ -12,8 +12,17 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2019-XX-XX: *BREAKING CHANGE*: Vulkan: Added ImageCount/MinImageCount fields in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetMinImageCount().
+// 2019-XX-XX: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper.
// 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
// 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int).
// 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display.
@@ -35,46 +44,61 @@
#include "imgui_impl_vulkan.h"
#include
-// Vulkan data
-static const VkAllocationCallbacks* g_Allocator = NULL;
-static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE;
-static VkInstance g_Instance = 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 VkPipelineCache g_PipelineCache = VK_NULL_HANDLE;
-static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
-static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
-static void (*g_CheckVkResultFn)(VkResult err) = NULL;
-
-static VkDeviceSize g_BufferMemoryAlignment = 256;
-static VkPipelineCreateFlags g_PipelineCreateFlags = 0;
-
-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;
-
-// Frame data
-struct FrameDataForRender
+// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_FrameRenderBuffers
{
- VkDeviceMemory VertexBufferMemory;
- VkDeviceMemory IndexBufferMemory;
- VkDeviceSize VertexBufferSize;
- VkDeviceSize IndexBufferSize;
- VkBuffer VertexBuffer;
- VkBuffer IndexBuffer;
+ VkDeviceMemory VertexBufferMemory;
+ VkDeviceMemory IndexBufferMemory;
+ VkDeviceSize VertexBufferSize;
+ VkDeviceSize IndexBufferSize;
+ VkBuffer VertexBuffer;
+ VkBuffer IndexBuffer;
};
-static int g_FrameIndex = 0;
-static FrameDataForRender g_FramesDataBuffers[IMGUI_VK_QUEUED_FRAMES] = {};
+
+// Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_WindowRenderBuffers
+{
+ uint32_t Index;
+ uint32_t Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* FrameRenderBuffers;
+};
+
+// Vulkan data
+static ImGui_ImplVulkan_InitInfo g_VulkanInitInfo = {};
+static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
+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
-static VkSampler g_FontSampler = VK_NULL_HANDLE;
-static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
-static VkImage g_FontImage = VK_NULL_HANDLE;
-static VkImageView g_FontView = VK_NULL_HANDLE;
-static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
-static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+static VkSampler g_FontSampler = VK_NULL_HANDLE;
+static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
+static VkImage g_FontImage = VK_NULL_HANDLE;
+static VkImageView g_FontView = VK_NULL_HANDLE;
+static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
+static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+
+// Render buffers
+static ImGui_ImplVulkanH_WindowRenderBuffers g_MainWindowRenderBuffers;
+
+// Forward Declarations
+bool ImGui_ImplVulkan_CreateDeviceObjects();
+void ImGui_ImplVulkan_DestroyDeviceObjects();
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
+
+//-----------------------------------------------------------------------------
+// SHADERS
+//-----------------------------------------------------------------------------
// Forward Declarations
static void ImGui_ImplVulkan_InitPlatformInterface();
@@ -185,10 +209,15 @@
0x00010038
};
+//-----------------------------------------------------------------------------
+// FUNCTIONS
+//-----------------------------------------------------------------------------
+
static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkPhysicalDeviceMemoryProperties prop;
- vkGetPhysicalDeviceMemoryProperties(g_PhysicalDevice, &prop);
+ vkGetPhysicalDeviceMemoryProperties(v->PhysicalDevice, &prop);
for (uint32_t i = 0; i < prop.memoryTypeCount; i++)
if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<CheckVkResultFn)
+ v->CheckVkResultFn(err);
}
static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
if (buffer != VK_NULL_HANDLE)
- vkDestroyBuffer(g_Device, buffer, g_Allocator);
- if (buffer_memory)
- vkFreeMemory(g_Device, buffer_memory, g_Allocator);
+ vkDestroyBuffer(v->Device, buffer, v->Allocator);
+ if (buffer_memory != VK_NULL_HANDLE)
+ vkFreeMemory(v->Device, buffer_memory, v->Allocator);
VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / g_BufferMemoryAlignment + 1) * g_BufferMemoryAlignment;
VkBufferCreateInfo buffer_info = {};
@@ -215,20 +246,20 @@
buffer_info.size = vertex_buffer_size_aligned;
buffer_info.usage = usage;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &buffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &buffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, buffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, buffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &buffer_memory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &buffer_memory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, buffer, buffer_memory, 0);
+ err = vkBindBufferMemory(v->Device, buffer, buffer_memory, 0);
check_vk_result(err);
p_buffer_size = new_size;
}
@@ -243,25 +274,38 @@
if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount == 0)
return;
- VkResult err;
- FrameDataForRender* fd = &g_FramesDataBuffers[g_FrameIndex];
- g_FrameIndex = (g_FrameIndex + 1) % IM_ARRAYSIZE(g_FramesDataBuffers);
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
- // Create the Vertex and Index buffers:
+ // Allocate array to store enough vertex/index buffers
+ ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &g_MainWindowRenderBuffers;
+ if (wrb->FrameRenderBuffers == NULL)
+ {
+ wrb->Index = 0;
+ wrb->Count = v->ImageCount;
+ wrb->FrameRenderBuffers = (ImGui_ImplVulkanH_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ }
+ IM_ASSERT(wrb->Count == v->ImageCount);
+ wrb->Index = (wrb->Index + 1) % wrb->Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index];
+
+ VkResult err;
+
+ // Create or resize the vertex/index buffers
size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);
size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx);
- if (fd->VertexBuffer == VK_NULL_HANDLE || fd->VertexBufferSize < vertex_size)
- CreateOrResizeBuffer(fd->VertexBuffer, fd->VertexBufferMemory, fd->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
- if (fd->IndexBuffer == VK_NULL_HANDLE || fd->IndexBufferSize < index_size)
- CreateOrResizeBuffer(fd->IndexBuffer, fd->IndexBufferMemory, fd->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
+ if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size)
+ CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+ if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size)
+ CreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
// Upload vertex/index data into a single contiguous GPU buffer
{
ImDrawVert* vtx_dst = NULL;
ImDrawIdx* idx_dst = NULL;
- err = vkMapMemory(g_Device, fd->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
+ err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
check_vk_result(err);
- err = vkMapMemory(g_Device, fd->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
+ err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
check_vk_result(err);
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
@@ -273,15 +317,15 @@
}
VkMappedMemoryRange range[2] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[0].memory = fd->VertexBufferMemory;
+ range[0].memory = rb->VertexBufferMemory;
range[0].size = VK_WHOLE_SIZE;
range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[1].memory = fd->IndexBufferMemory;
+ range[1].memory = rb->IndexBufferMemory;
range[1].size = VK_WHOLE_SIZE;
- err = vkFlushMappedMemoryRanges(g_Device, 2, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 2, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, fd->VertexBufferMemory);
- vkUnmapMemory(g_Device, fd->IndexBufferMemory);
+ vkUnmapMemory(v->Device, rb->VertexBufferMemory);
+ vkUnmapMemory(v->Device, rb->IndexBufferMemory);
}
// Bind pipeline and descriptor sets:
@@ -293,10 +337,10 @@
// Bind Vertex And Index Buffer:
{
- VkBuffer vertex_buffers[1] = { fd->VertexBuffer };
+ VkBuffer vertex_buffers[1] = { rb->VertexBuffer };
VkDeviceSize vertex_offset[1] = { 0 };
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset);
- vkCmdBindIndexBuffer(command_buffer, fd->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
+ vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
}
// Setup viewport:
@@ -379,6 +423,7 @@
bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
@@ -404,17 +449,17 @@
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- err = vkCreateImage(g_Device, &info, g_Allocator, &g_FontImage);
+ err = vkCreateImage(v->Device, &info, v->Allocator, &g_FontImage);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetImageMemoryRequirements(g_Device, g_FontImage, &req);
+ vkGetImageMemoryRequirements(v->Device, g_FontImage, &req);
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_FontMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_FontMemory);
check_vk_result(err);
- err = vkBindImageMemory(g_Device, g_FontImage, g_FontMemory, 0);
+ err = vkBindImageMemory(v->Device, g_FontImage, g_FontMemory, 0);
check_vk_result(err);
}
@@ -428,7 +473,7 @@
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.levelCount = 1;
info.subresourceRange.layerCount = 1;
- err = vkCreateImageView(g_Device, &info, g_Allocator, &g_FontView);
+ err = vkCreateImageView(v->Device, &info, v->Allocator, &g_FontView);
check_vk_result(err);
}
@@ -444,7 +489,7 @@
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
- vkUpdateDescriptorSets(g_Device, 1, write_desc, 0, NULL);
+ vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
// Create the Upload Buffer:
@@ -454,34 +499,34 @@
buffer_info.size = upload_size;
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_UploadBuffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &g_UploadBuffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, g_UploadBuffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, g_UploadBuffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_UploadBufferMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_UploadBufferMemory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, g_UploadBuffer, g_UploadBufferMemory, 0);
+ err = vkBindBufferMemory(v->Device, g_UploadBuffer, g_UploadBufferMemory, 0);
check_vk_result(err);
}
// Upload to Buffer:
{
char* map = NULL;
- err = vkMapMemory(g_Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
+ err = vkMapMemory(v->Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
check_vk_result(err);
memcpy(map, pixels, upload_size);
VkMappedMemoryRange range[1] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[0].memory = g_UploadBufferMemory;
range[0].size = upload_size;
- err = vkFlushMappedMemoryRanges(g_Device, 1, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 1, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, g_UploadBufferMemory);
+ vkUnmapMemory(v->Device, g_UploadBufferMemory);
}
// Copy to Image:
@@ -530,6 +575,7 @@
bool ImGui_ImplVulkan_CreateDeviceObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
VkShaderModule vert_module;
VkShaderModule frag_module;
@@ -540,13 +586,13 @@
vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
vert_info.codeSize = sizeof(__glsl_shader_vert_spv);
vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv;
- err = vkCreateShaderModule(g_Device, &vert_info, g_Allocator, &vert_module);
+ err = vkCreateShaderModule(v->Device, &vert_info, v->Allocator, &vert_module);
check_vk_result(err);
VkShaderModuleCreateInfo frag_info = {};
frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
frag_info.codeSize = sizeof(__glsl_shader_frag_spv);
frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv;
- err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module);
+ err = vkCreateShaderModule(v->Device, &frag_info, v->Allocator, &frag_module);
check_vk_result(err);
}
@@ -563,7 +609,7 @@
info.minLod = -1000;
info.maxLod = 1000;
info.maxAnisotropy = 1.0f;
- err = vkCreateSampler(g_Device, &info, g_Allocator, &g_FontSampler);
+ err = vkCreateSampler(v->Device, &info, v->Allocator, &g_FontSampler);
check_vk_result(err);
}
@@ -579,7 +625,7 @@
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
info.bindingCount = 1;
info.pBindings = binding;
- err = vkCreateDescriptorSetLayout(g_Device, &info, g_Allocator, &g_DescriptorSetLayout);
+ err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &g_DescriptorSetLayout);
check_vk_result(err);
}
@@ -587,10 +633,10 @@
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- alloc_info.descriptorPool = g_DescriptorPool;
+ alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &g_DescriptorSetLayout;
- err = vkAllocateDescriptorSets(g_Device, &alloc_info, &g_DescriptorSet);
+ err = vkAllocateDescriptorSets(v->Device, &alloc_info, &g_DescriptorSet);
check_vk_result(err);
}
@@ -608,7 +654,7 @@
layout_info.pSetLayouts = set_layout;
layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = push_constants;
- err = vkCreatePipelineLayout(g_Device, &layout_info, g_Allocator, &g_PipelineLayout);
+ err = vkCreatePipelineLayout(v->Device, &layout_info, v->Allocator, &g_PipelineLayout);
check_vk_result(err);
}
@@ -706,49 +752,43 @@
info.pDynamicState = &dynamic_state;
info.layout = g_PipelineLayout;
info.renderPass = g_RenderPass;
- err = vkCreateGraphicsPipelines(g_Device, g_PipelineCache, 1, &info, g_Allocator, &g_Pipeline);
+ err = vkCreateGraphicsPipelines(v->Device, v->PipelineCache, 1, &info, v->Allocator, &g_Pipeline);
check_vk_result(err);
- vkDestroyShaderModule(g_Device, vert_module, g_Allocator);
- vkDestroyShaderModule(g_Device, frag_module, g_Allocator);
+ vkDestroyShaderModule(v->Device, vert_module, v->Allocator);
+ vkDestroyShaderModule(v->Device, frag_module, v->Allocator);
return true;
}
-void ImGui_ImplVulkan_InvalidateFontUploadObjects()
+void ImGui_ImplVulkan_DestroyFontUploadObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
if (g_UploadBuffer)
{
- vkDestroyBuffer(g_Device, g_UploadBuffer, g_Allocator);
+ vkDestroyBuffer(v->Device, g_UploadBuffer, v->Allocator);
g_UploadBuffer = VK_NULL_HANDLE;
}
if (g_UploadBufferMemory)
{
- vkFreeMemory(g_Device, g_UploadBufferMemory, g_Allocator);
+ vkFreeMemory(v->Device, g_UploadBufferMemory, v->Allocator);
g_UploadBufferMemory = VK_NULL_HANDLE;
}
}
-void ImGui_ImplVulkan_InvalidateDeviceObjects()
+void ImGui_ImplVulkan_DestroyDeviceObjects()
{
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
- for (int i = 0; i < IM_ARRAYSIZE(g_FramesDataBuffers); i++)
- {
- FrameDataForRender* fd = &g_FramesDataBuffers[i];
- if (fd->VertexBuffer) { vkDestroyBuffer (g_Device, fd->VertexBuffer, g_Allocator); fd->VertexBuffer = VK_NULL_HANDLE; }
- if (fd->VertexBufferMemory) { vkFreeMemory (g_Device, fd->VertexBufferMemory, g_Allocator); fd->VertexBufferMemory = VK_NULL_HANDLE; }
- if (fd->IndexBuffer) { vkDestroyBuffer (g_Device, fd->IndexBuffer, g_Allocator); fd->IndexBuffer = VK_NULL_HANDLE; }
- if (fd->IndexBufferMemory) { vkFreeMemory (g_Device, fd->IndexBufferMemory, g_Allocator); fd->IndexBufferMemory = VK_NULL_HANDLE; }
- }
-
- if (g_FontView) { vkDestroyImageView(g_Device, g_FontView, g_Allocator); g_FontView = VK_NULL_HANDLE; }
- if (g_FontImage) { vkDestroyImage(g_Device, g_FontImage, g_Allocator); g_FontImage = VK_NULL_HANDLE; }
- if (g_FontMemory) { vkFreeMemory(g_Device, g_FontMemory, g_Allocator); g_FontMemory = VK_NULL_HANDLE; }
- if (g_FontSampler) { vkDestroySampler(g_Device, g_FontSampler, g_Allocator); g_FontSampler = VK_NULL_HANDLE; }
- if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(g_Device, g_DescriptorSetLayout, g_Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
- if (g_PipelineLayout) { vkDestroyPipelineLayout(g_Device, g_PipelineLayout, g_Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
- if (g_Pipeline) { vkDestroyPipeline(g_Device, g_Pipeline, g_Allocator); g_Pipeline = VK_NULL_HANDLE; }
+ if (g_FontView) { vkDestroyImageView(v->Device, g_FontView, v->Allocator); g_FontView = VK_NULL_HANDLE; }
+ if (g_FontImage) { vkDestroyImage(v->Device, g_FontImage, v->Allocator); g_FontImage = VK_NULL_HANDLE; }
+ if (g_FontMemory) { vkFreeMemory(v->Device, g_FontMemory, v->Allocator); g_FontMemory = VK_NULL_HANDLE; }
+ if (g_FontSampler) { vkDestroySampler(v->Device, g_FontSampler, v->Allocator); g_FontSampler = VK_NULL_HANDLE; }
+ if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, g_DescriptorSetLayout, v->Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
+ if (g_PipelineLayout) { vkDestroyPipelineLayout(v->Device, g_PipelineLayout, v->Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
+ if (g_Pipeline) { vkDestroyPipeline(v->Device, g_Pipeline, v->Allocator); g_Pipeline = VK_NULL_HANDLE; }
}
bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass)
@@ -763,19 +803,12 @@
IM_ASSERT(info->Device != VK_NULL_HANDLE);
IM_ASSERT(info->Queue != VK_NULL_HANDLE);
IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE);
+ IM_ASSERT(info->MinImageCount >= 2);
+ IM_ASSERT(info->ImageCount >= info->MinImageCount);
IM_ASSERT(render_pass != VK_NULL_HANDLE);
- g_Instance = info->Instance;
- g_PhysicalDevice = info->PhysicalDevice;
- g_Device = info->Device;
- g_QueueFamily = info->QueueFamily;
- g_Queue = info->Queue;
+ g_VulkanInitInfo = *info;
g_RenderPass = render_pass;
- g_PipelineCache = info->PipelineCache;
- g_DescriptorPool = info->DescriptorPool;
- g_Allocator = info->Allocator;
- g_CheckVkResultFn = info->CheckVkResultFn;
-
ImGui_ImplVulkan_CreateDeviceObjects();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
@@ -787,16 +820,30 @@
void ImGui_ImplVulkan_Shutdown()
{
ImGui_ImplVulkan_ShutdownPlatformInterface();
- ImGui_ImplVulkan_InvalidateDeviceObjects();
+ ImGui_ImplVulkan_DestroyDeviceObjects();
}
void ImGui_ImplVulkan_NewFrame()
{
}
+void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
+{
+ IM_ASSERT(min_image_count >= 2);
+ if (g_VulkanInitInfo.MinImageCount == min_image_count)
+ return;
+
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ VkResult err = vkDeviceWaitIdle(v->Device);
+ check_vk_result(err);
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ g_VulkanInitInfo.MinImageCount = min_image_count;
+}
+
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -804,40 +851,12 @@
// 2) the upcoming multi-viewport feature will need them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-#include // malloc
-
-ImGui_ImplVulkanH_FrameData::ImGui_ImplVulkanH_FrameData()
-{
- BackbufferIndex = 0;
- CommandPool = VK_NULL_HANDLE;
- CommandBuffer = VK_NULL_HANDLE;
- Fence = VK_NULL_HANDLE;
- ImageAcquiredSemaphore = VK_NULL_HANDLE;
- RenderCompleteSemaphore = VK_NULL_HANDLE;
-}
-
-ImGui_ImplVulkanH_WindowData::ImGui_ImplVulkanH_WindowData()
-{
- Width = Height = 0;
- Swapchain = VK_NULL_HANDLE;
- Surface = VK_NULL_HANDLE;
- memset(&SurfaceFormat, 0, sizeof(SurfaceFormat));
- PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
- RenderPass = VK_NULL_HANDLE;
- ClearEnable = true;
- memset(&ClearValue, 0, sizeof(ClearValue));
- BackBufferCount = 0;
- memset(&BackBuffer, 0, sizeof(BackBuffer));
- memset(&BackBufferView, 0, sizeof(BackBufferView));
- memset(&Framebuffer, 0, sizeof(Framebuffer));
- FrameIndex = 0;
-}
-
VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space)
{
IM_ASSERT(request_formats != NULL);
@@ -904,7 +923,7 @@
return VK_PRESENT_MODE_FIFO_KHR; // Always available
}
-void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator)
{
IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE);
(void)physical_device;
@@ -912,9 +931,10 @@
// Create Command Buffers
VkResult err;
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i];
{
VkCommandPoolCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
@@ -942,9 +962,9 @@
{
VkSemaphoreCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- err = vkCreateSemaphore(device, &info, allocator, &fd->ImageAcquiredSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->ImageAcquiredSemaphore);
check_vk_result(err);
- err = vkCreateSemaphore(device, &info, allocator, &fd->RenderCompleteSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->RenderCompleteSemaphore);
check_vk_result(err);
}
}
@@ -962,24 +982,26 @@
return 1;
}
-void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h)
+// Also destroy old swap chain and in-flight frames data, if any.
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count)
{
- uint32_t min_image_count = 2; // FIXME: this should become a function parameter
-
VkResult err;
VkSwapchainKHR old_swapchain = wd->Swapchain;
err = vkDeviceWaitIdle(device);
check_vk_result(err);
+ // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one.
// Destroy old Framebuffer
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- if (wd->BackBufferView[i])
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- if (wd->Framebuffer[i])
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- wd->BackBufferCount = 0;
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
+ wd->ImageCount = 0;
if (wd->RenderPass)
vkDestroyRenderPass(device, wd->RenderPass, allocator);
@@ -1023,10 +1045,21 @@
}
err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, NULL);
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, NULL);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, wd->BackBuffer);
+ VkImage backbuffers[16] = {};
+ IM_ASSERT(wd->ImageCount >= min_image_count);
+ IM_ASSERT(wd->ImageCount < IM_ARRAYSIZE(backbuffers));
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers);
check_vk_result(err);
+
+ IM_ASSERT(wd->Frames == NULL);
+ wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount);
+ wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->ImageCount);
+ memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount);
+ memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->ImageCount);
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
+ wd->Frames[i].Backbuffer = backbuffers[i];
}
if (old_swapchain)
vkDestroySwapchainKHR(device, old_swapchain, allocator);
@@ -1080,10 +1113,11 @@
info.components.a = VK_COMPONENT_SWIZZLE_A;
VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
info.subresourceRange = image_range;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- info.image = wd->BackBuffer[i];
- err = vkCreateImageView(device, &info, allocator, &wd->BackBufferView[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ info.image = fd->Backbuffer;
+ err = vkCreateImageView(device, &info, allocator, &fd->BackbufferView);
check_vk_result(err);
}
}
@@ -1099,38 +1133,82 @@
info.width = wd->Width;
info.height = wd->Height;
info.layers = 1;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- attachment[0] = wd->BackBufferView[i];
- err = vkCreateFramebuffer(device, &info, allocator, &wd->Framebuffer[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ attachment[0] = fd->BackbufferView;
+ err = vkCreateFramebuffer(device, &info, allocator, &fd->Framebuffer);
check_vk_result(err);
}
}
}
-void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count)
+{
+ (void)instance;
+ ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count);
+ ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator)
{
vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals)
//vkQueueWaitIdle(g_Queue);
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
- vkDestroyFence(device, fd->Fence, allocator);
- vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
- vkDestroyCommandPool(device, fd->CommandPool, allocator);
- vkDestroySemaphore(device, fd->ImageAcquiredSemaphore, allocator);
- vkDestroySemaphore(device, fd->RenderCompleteSemaphore, allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
- {
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
- }
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
vkDestroyRenderPass(device, wd->RenderPass, allocator);
vkDestroySwapchainKHR(device, wd->Swapchain, allocator);
vkDestroySurfaceKHR(instance, wd->Surface, allocator);
- *wd = ImGui_ImplVulkanH_WindowData();
+
+ *wd = ImGui_ImplVulkanH_Window();
+}
+
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroyFence(device, fd->Fence, allocator);
+ vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
+ vkDestroyCommandPool(device, fd->CommandPool, allocator);
+ fd->Fence = VK_NULL_HANDLE;
+ fd->CommandBuffer = VK_NULL_HANDLE;
+ fd->CommandPool = VK_NULL_HANDLE;
+
+ vkDestroyImageView(device, fd->BackbufferView, allocator);
+ vkDestroyFramebuffer(device, fd->Framebuffer, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator);
+ vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator);
+ fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;
+}
+
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; }
+ if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; }
+ if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; }
+ if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; }
+ buffers->VertexBufferSize = 0;
+ buffers->IndexBufferSize = 0;
+}
+
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ for (uint32_t n = 0; n < buffers->Count; n++)
+ ImGui_ImplVulkanH_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator);
+ IM_FREE(buffers->FrameRenderBuffers);
+ buffers->FrameRenderBuffers = NULL;
+ buffers->Index = 0;
+ buffers->Count = 0;
}
//--------------------------------------------------------------------------------------------------------
diff --git a/examples/imgui_impl_vulkan.h b/examples/imgui_impl_vulkan.h
index ec45dbe..0389af5 100644
--- a/examples/imgui_impl_vulkan.h
+++ b/examples/imgui_impl_vulkan.h
@@ -12,24 +12,32 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
#pragma once
#include
-#define IMGUI_VK_QUEUED_FRAMES 2
-
-// Please zero-clear before use.
+// Initialization data, for ImGui_ImplVulkan_Init()
+// [Please zero-clear before use!]
struct ImGui_ImplVulkan_InitInfo
{
- VkInstance Instance;
- VkPhysicalDevice PhysicalDevice;
- VkDevice Device;
- uint32_t QueueFamily;
- VkQueue Queue;
- VkPipelineCache PipelineCache;
- VkDescriptorPool DescriptorPool;
- const VkAllocationCallbacks* Allocator;
- void (*CheckVkResultFn)(VkResult err);
+ VkInstance Instance;
+ VkPhysicalDevice PhysicalDevice;
+ VkDevice Device;
+ uint32_t QueueFamily;
+ VkQueue Queue;
+ VkPipelineCache PipelineCache;
+ VkDescriptorPool DescriptorPool;
+ uint32_t MinImageCount; // >= 2
+ uint32_t ImageCount; // >= MinImageCount
+ const VkAllocationCallbacks* Allocator;
+ void (*CheckVkResultFn)(VkResult err);
};
// Called by user code
@@ -38,16 +46,13 @@
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
-IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateFontUploadObjects();
-
-// Called by ImGui_ImplVulkan_Init() might be useful elsewhere.
-IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateDeviceObjects();
-IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateDeviceObjects();
+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)
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -55,38 +60,44 @@
// 2) the multi-viewport / platform window implementation needs them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-struct ImGui_ImplVulkanH_FrameData;
-struct ImGui_ImplVulkanH_WindowData;
+struct ImGui_ImplVulkanH_Frame;
+struct ImGui_ImplVulkanH_Window;
-IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
-IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h);
-IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
+// Helpers
+IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wnd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator);
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
// Helper structure to hold the data needed by one rendering frame
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
-struct ImGui_ImplVulkanH_FrameData
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_Frame
{
- uint32_t BackbufferIndex; // Keep track of recently rendered swapchain frame indices
VkCommandPool CommandPool;
VkCommandBuffer CommandBuffer;
VkFence Fence;
+ VkImage Backbuffer;
+ VkImageView BackbufferView;
+ VkFramebuffer Framebuffer;
+};
+
+struct ImGui_ImplVulkanH_FrameSemaphores
+{
VkSemaphore ImageAcquiredSemaphore;
VkSemaphore RenderCompleteSemaphore;
-
- IMGUI_IMPL_API ImGui_ImplVulkanH_FrameData();
};
// Helper structure to hold the data needed by one rendering context into one OS window
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
-struct ImGui_ImplVulkanH_WindowData
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+struct ImGui_ImplVulkanH_Window
{
int Width;
int Height;
@@ -97,13 +108,17 @@
VkRenderPass RenderPass;
bool ClearEnable;
VkClearValue ClearValue;
- uint32_t BackBufferCount;
- VkImage BackBuffer[16];
- VkImageView BackBufferView[16];
- VkFramebuffer Framebuffer[16];
- uint32_t FrameIndex;
- ImGui_ImplVulkanH_FrameData Frames[IMGUI_VK_QUEUED_FRAMES];
+ uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
+ uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
+ uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
+ ImGui_ImplVulkanH_Frame* Frames;
+ ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
- IMGUI_IMPL_API ImGui_ImplVulkanH_WindowData();
+ ImGui_ImplVulkanH_Window()
+ {
+ memset(this, 0, sizeof(*this));
+ PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
+ ClearEnable = true;
+ }
};
diff --git a/imgui.cpp b/imgui.cpp
index c96b2d8..65ea119 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -37,9 +37,14 @@
- Using gamepad/keyboard navigation controls.
- API BREAKING CHANGES (read me when you update!)
- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
+ - Where is the documentation?
+ - Which version should I get?
+ - Who uses Dear ImGui?
+ - Why the odd dual naming, "Dear ImGui" vs "ImGui"?
- How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
- How can I display an image? What is ImTextureID, how does it works?
- - How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.
+ - Why are multiple widgets reacting when I interact with a single one? How can I have
+ multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...
- How can I use my own math types instead of ImVec2/ImVec4?
- How can I load a different font than the default?
- How can I easily use icons in my application?
@@ -563,6 +568,39 @@
FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
======================================
+ Q: Where is the documentation?
+ A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/
+ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments
+ associated to it.
+
+ Q: Which version should I get?
+ A: I occasionally tag Releases (https://github.com/ocornut/imgui/releases) but it is generally safe
+ and recommended to sync to master/latest. The library is fairly stable and regressions tend to be
+ fixed fast when reported. You may also peak at the 'docking' branch which includes:
+ - Docking/Merging features (https://github.com/ocornut/imgui/issues/2109)
+ - Multi-viewport features (https://github.com/ocornut/imgui/issues/1542)
+ Many projects are using this branch and it is kept in sync with master regularly.
+
+ Q: Who uses Dear ImGui?
+ A: See "Quotes" (https://github.com/ocornut/imgui/wiki/Quotes) and
+ "Software using Dear ImGui" (https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages
+ for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+
+ Q: Why the odd dual naming, "Dear ImGui" vs "ImGui"?
+ A: The library started its life as "ImGui" due to the fact that I didn't give it a proper name when
+ when I released 1.0, and had no particular expectation that it would take off. However, the term IMGUI
+ (immediate-mode graphical user interface) was coined before and is being used in variety of other
+ situations (e.g. Unity uses it own implementation of the IMGUI paradigm).
+ To reduce the ambiguity without affecting existing code bases, I have decided on an alternate,
+ longer name "Dear ImGui" that people can use to refer to this specific library.
+ Please try to refer to this library as "Dear ImGui".
+
Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure (e.g. if (ImGui::GetIO().WantCaptureMouse) { ... } )
- When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application.
@@ -664,8 +702,8 @@
Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated.
+ Q: Why are multiple widgets reacting when I interact with a single one?
Q: How can I have multiple widgets with the same label or with an empty label?
- Q: I have multiple widgets with the same label, and only the first one works. Why is that?
A: A primer on labels and the ID Stack...
Dear ImGui internally need to uniquely identify UI elements.
@@ -1344,7 +1382,7 @@
char* ImStrdup(const char* str)
{
size_t len = strlen(str);
- void* buf = ImGui::MemAlloc(len + 1);
+ void* buf = IM_ALLOC(len + 1);
return (char*)memcpy(buf, (const void*)str, len + 1);
}
@@ -1354,8 +1392,8 @@
size_t src_size = strlen(src) + 1;
if (dst_buf_size < src_size)
{
- ImGui::MemFree(dst);
- dst = (char*)ImGui::MemAlloc(src_size);
+ IM_FREE(dst);
+ dst = (char*)IM_ALLOC(src_size);
if (p_dst_size)
*p_dst_size = src_size;
}
@@ -1571,7 +1609,7 @@
}
// Load file content into memory
-// Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
+// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()
void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes)
{
IM_ASSERT(filename && file_open_mode);
@@ -1590,7 +1628,7 @@
}
size_t file_size = (size_t)file_size_signed;
- void* file_data = ImGui::MemAlloc(file_size + padding_bytes);
+ void* file_data = IM_ALLOC(file_size + padding_bytes);
if (file_data == NULL)
{
fclose(f);
@@ -1599,7 +1637,7 @@
if (fread(file_data, 1, file_size, f) != file_size)
{
fclose(f);
- ImGui::MemFree(file_data);
+ IM_FREE(file_data);
return NULL;
}
if (padding_bytes > 0)
@@ -3024,6 +3062,7 @@
return ImMax(wrap_pos_x - pos.x, 1.0f);
}
+// IM_ALLOC() == ImGui::MemAlloc()
void* ImGui::MemAlloc(size_t size)
{
if (ImGuiContext* ctx = GImGui)
@@ -3031,6 +3070,7 @@
return GImAllocatorAllocFunc(size, GImAllocatorUserData);
}
+// IM_FREE() == ImGui::MemFree()
void ImGui::MemFree(void* ptr)
{
if (ptr)
@@ -9790,7 +9830,7 @@
if (!file_data)
return;
LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
- ImGui::MemFree(file_data);
+ IM_FREE(file_data);
}
ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
@@ -9814,7 +9854,7 @@
// For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy..
if (ini_size == 0)
ini_size = strlen(ini_data);
- char* buf = (char*)ImGui::MemAlloc(ini_size + 1);
+ char* buf = (char*)IM_ALLOC(ini_size + 1);
char* buf_end = buf + ini_size;
memcpy(buf, ini_data, ini_size);
buf[ini_size] = 0;
@@ -9861,7 +9901,7 @@
entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
}
}
- ImGui::MemFree(buf);
+ IM_FREE(buf);
g.SettingsLoaded = true;
DockContextOnLoadSettings(&g);
}
diff --git a/imgui.h b/imgui.h
index f990e06..4613625 100644
--- a/imgui.h
+++ b/imgui.h
@@ -13,6 +13,7 @@
// Forward declarations and basic types
// ImGui API (Dear ImGui end-user API)
// Flags & Enumerations
+// Memory allocations macros
// ImVector<>
// ImGuiStyle
// ImGuiIO
@@ -1256,6 +1257,22 @@
};
//-----------------------------------------------------------------------------
+// Helpers: Memory allocations macros
+// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE()
+// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
+// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions.
+//-----------------------------------------------------------------------------
+
+struct ImNewDummy {};
+inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; }
+inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new()
+#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE)
+#define IM_FREE(_PTR) ImGui::MemFree(_PTR)
+#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR)
+#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
+template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }
+
+//-----------------------------------------------------------------------------
// Helper: ImVector<>
// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug).
// You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it.
@@ -1280,7 +1297,7 @@
inline ImVector() { Size = Capacity = 0; Data = NULL; }
inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); }
inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; }
- inline ~ImVector() { if (Data) ImGui::MemFree(Data); }
+ inline ~ImVector() { if (Data) IM_FREE(Data); }
inline bool empty() const { return Size == 0; }
inline int size() const { return Size; }
@@ -1289,7 +1306,7 @@
inline T& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; }
inline const T& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; }
- inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } }
+ inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } }
inline T* begin() { return Data; }
inline const T* begin() const { return Data; }
inline T* end() { return Data + Size; }
@@ -1303,7 +1320,7 @@
inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; }
inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; }
- inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); ImGui::MemFree(Data); } Data = new_data; Capacity = new_capacity; }
+ inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; }
// NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden.
inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; }
@@ -1639,16 +1656,6 @@
// Helpers
//-----------------------------------------------------------------------------
-// Helper: IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() macros to call MemAlloc + Placement New, Placement Delete + MemFree
-// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
-// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions.
-struct ImNewDummy {};
-inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; }
-inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new()
-#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR)
-#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
-template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }
-
// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame.
// Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text("This will be called only once per frame");
struct ImGuiOnceUponAFrame
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index ad43c68..9bedf3f 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -98,6 +98,11 @@
-----------------------------------------------------------------------
Breaking Changes:
+- Examples: Vulkan: Added MinImageCount/ImageCount fields in ImGui_ImplVulkan_InitInfo, required
+ during initialization to specify the number of in-flight image requested by swap chains.
+ (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam]
+- Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely
+ on them but it is possible you have!).
Other Changes:
- InputText: Fixed selection background starts rendering one frame after the cursor movement
@@ -108,11 +113,15 @@
- GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419)
- GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero.
- Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood]
+- Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert
+ to using the ImGui::MemAlloc()/MemFree() calls directly.
- Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized
GL function loaders early, and help users understand what they are missing. (#2421)
- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop.
+- Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int).
- Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
+- Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam]
- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454)
- Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott]
- Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott]
diff --git a/docs/README.md b/docs/README.md
index febacf0..ba48517 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -219,29 +219,32 @@
**Where is the documentation?**
-- The documentation is at the top of imgui.cpp + effectively imgui.h.
-- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output.
-- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder.
-- We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
-- Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ applications and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ - We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
**Which version should I get?**
I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
-You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Several projects are using this branch and it is kept in sync with master regularly.
+You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Many projects are using this branch and it is kept in sync with master regularly.
**Who uses Dear ImGui?**
-See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) pages for an (incomplete) list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
**Why the odd dual naming, "Dear ImGui" vs "ImGui"?**
-The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would taker off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library in ambiguous situations. Please try to refer to it as "Dear ImGui".
+The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would take off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). To reduce this ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library. Please try to refer to this library as "Dear ImGui".
**How can I tell whether to dispatch mouse/keyboard to imgui or to my application?**
**How can I display an image? What is ImTextureID, how does it works?**
-
**How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.**
+
**Why are multiple widgets reacting when I interact with a single one? How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...**
**How can I use my own math types instead of ImVec2/ImVec4?**
**How can I load a different font than the default?**
**How can I easily use icons in my application?**
@@ -254,7 +257,7 @@
**I integrated Dear ImGui in my engine and some elements are disappearing when I move windows around..**
**How can I help?**
-See the FAQ in imgui.cpp for answers.
+See the FAQ in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) for answers.
**Can you create elaborate/serious tools with Dear ImGui?**
diff --git a/docs/issue_template.md b/docs/issue_template.md
index 6d88b27..21f0c1a 100644
--- a/docs/issue_template.md
+++ b/docs/issue_template.md
@@ -4,11 +4,11 @@
https://github.com/ocornut/imgui/issues/2261
2. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/LOADING FONTS, please post on the "Getting Started" Discourse forum:
-https://discourse.dearimgui.org/c/getting-started
+https://discourse.dearimgui.org
-3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
+3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
-4. Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users, unless they browse the site.
+4. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.
5. Delete points 1-5 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue.
diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp
index 6f2c4cd..c1548ff 100644
--- a/examples/example_glfw_vulkan/main.cpp
+++ b/examples/example_glfw_vulkan/main.cpp
@@ -1,6 +1,13 @@
// 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"
@@ -23,19 +30,21 @@
#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 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_WindowData g_WindowData;
-static bool g_ResizeWanted = false;
-static int g_ResizeWidth = 0, g_ResizeHeight = 0;
+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)
{
@@ -107,6 +116,7 @@
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);
@@ -183,7 +193,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -211,14 +223,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -231,15 +241,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -260,7 +276,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -283,7 +299,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -292,18 +308,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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)
@@ -313,14 +330,14 @@
static void glfw_resize_callback(GLFWwindow*, int w, int h)
{
- g_ResizeWanted = true;
- g_ResizeWidth = w;
- g_ResizeHeight = h;
+ g_SwapChainRebuild = true;
+ g_SwapChainResizeWidth = w;
+ g_SwapChainResizeHeight = h;
}
int main(int, char**)
{
- // Setup window
+ // Setup GLFW window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
return 1;
@@ -347,8 +364,8 @@
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glfwSetFramebufferSizeCallback(window, glfw_resize_callback);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
@@ -384,6 +401,8 @@
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);
@@ -429,7 +448,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -445,10 +464,13 @@
// - 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();
- if (g_ResizeWanted)
+
+ if (g_SwapChainRebuild)
{
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, g_ResizeWidth, g_ResizeHeight);
- g_ResizeWanted = false;
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -514,6 +536,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
glfwDestroyWindow(window);
diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp
index 42ab4a6..077a825 100644
--- a/examples/example_sdl_vulkan/main.cpp
+++ b/examples/example_sdl_vulkan/main.cpp
@@ -1,6 +1,13 @@
// dear imgui: standalone example application for SDL2 + 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_sdl.h"
#include "imgui_impl_vulkan.h"
@@ -15,17 +22,21 @@
#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 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_WindowData g_WindowData;
+static ImGui_ImplVulkanH_Window g_MainWindowData;
+static uint32_t 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)
{
@@ -97,6 +108,7 @@
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);
@@ -173,7 +185,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -201,14 +215,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -221,15 +233,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -250,7 +268,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -273,7 +291,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -282,18 +300,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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
}
int main(int, char**)
@@ -331,8 +350,8 @@
// Create Framebuffers
int w, h;
SDL_GetWindowSize(window, &w, &h);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
ImGui::CreateContext();
@@ -366,6 +385,8 @@
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);
@@ -411,7 +432,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -434,7 +455,19 @@
if (event.type == SDL_QUIT)
done = true;
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED && event.window.windowID == SDL_GetWindowID(window))
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, (int)event.window.data1, (int)event.window.data2);
+ {
+ g_SwapChainResizeWidth = (int)event.window.data1;
+ g_SwapChainResizeHeight = (int)event.window.data2;
+ g_SwapChainRebuild = true;
+ }
+ }
+
+ if (g_SwapChainRebuild)
+ {
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -500,6 +533,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
SDL_DestroyWindow(window);
diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp
index 5911878..39ec861 100644
--- a/examples/imgui_impl_vulkan.cpp
+++ b/examples/imgui_impl_vulkan.cpp
@@ -12,8 +12,17 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2019-XX-XX: *BREAKING CHANGE*: Vulkan: Added ImageCount/MinImageCount fields in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetMinImageCount().
+// 2019-XX-XX: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper.
// 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
// 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int).
// 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display.
@@ -35,46 +44,61 @@
#include "imgui_impl_vulkan.h"
#include
-// Vulkan data
-static const VkAllocationCallbacks* g_Allocator = NULL;
-static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE;
-static VkInstance g_Instance = 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 VkPipelineCache g_PipelineCache = VK_NULL_HANDLE;
-static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
-static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
-static void (*g_CheckVkResultFn)(VkResult err) = NULL;
-
-static VkDeviceSize g_BufferMemoryAlignment = 256;
-static VkPipelineCreateFlags g_PipelineCreateFlags = 0;
-
-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;
-
-// Frame data
-struct FrameDataForRender
+// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_FrameRenderBuffers
{
- VkDeviceMemory VertexBufferMemory;
- VkDeviceMemory IndexBufferMemory;
- VkDeviceSize VertexBufferSize;
- VkDeviceSize IndexBufferSize;
- VkBuffer VertexBuffer;
- VkBuffer IndexBuffer;
+ VkDeviceMemory VertexBufferMemory;
+ VkDeviceMemory IndexBufferMemory;
+ VkDeviceSize VertexBufferSize;
+ VkDeviceSize IndexBufferSize;
+ VkBuffer VertexBuffer;
+ VkBuffer IndexBuffer;
};
-static int g_FrameIndex = 0;
-static FrameDataForRender g_FramesDataBuffers[IMGUI_VK_QUEUED_FRAMES] = {};
+
+// Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_WindowRenderBuffers
+{
+ uint32_t Index;
+ uint32_t Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* FrameRenderBuffers;
+};
+
+// Vulkan data
+static ImGui_ImplVulkan_InitInfo g_VulkanInitInfo = {};
+static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
+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
-static VkSampler g_FontSampler = VK_NULL_HANDLE;
-static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
-static VkImage g_FontImage = VK_NULL_HANDLE;
-static VkImageView g_FontView = VK_NULL_HANDLE;
-static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
-static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+static VkSampler g_FontSampler = VK_NULL_HANDLE;
+static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
+static VkImage g_FontImage = VK_NULL_HANDLE;
+static VkImageView g_FontView = VK_NULL_HANDLE;
+static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
+static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+
+// Render buffers
+static ImGui_ImplVulkanH_WindowRenderBuffers g_MainWindowRenderBuffers;
+
+// Forward Declarations
+bool ImGui_ImplVulkan_CreateDeviceObjects();
+void ImGui_ImplVulkan_DestroyDeviceObjects();
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
+
+//-----------------------------------------------------------------------------
+// SHADERS
+//-----------------------------------------------------------------------------
// Forward Declarations
static void ImGui_ImplVulkan_InitPlatformInterface();
@@ -185,10 +209,15 @@
0x00010038
};
+//-----------------------------------------------------------------------------
+// FUNCTIONS
+//-----------------------------------------------------------------------------
+
static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkPhysicalDeviceMemoryProperties prop;
- vkGetPhysicalDeviceMemoryProperties(g_PhysicalDevice, &prop);
+ vkGetPhysicalDeviceMemoryProperties(v->PhysicalDevice, &prop);
for (uint32_t i = 0; i < prop.memoryTypeCount; i++)
if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<CheckVkResultFn)
+ v->CheckVkResultFn(err);
}
static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
if (buffer != VK_NULL_HANDLE)
- vkDestroyBuffer(g_Device, buffer, g_Allocator);
- if (buffer_memory)
- vkFreeMemory(g_Device, buffer_memory, g_Allocator);
+ vkDestroyBuffer(v->Device, buffer, v->Allocator);
+ if (buffer_memory != VK_NULL_HANDLE)
+ vkFreeMemory(v->Device, buffer_memory, v->Allocator);
VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / g_BufferMemoryAlignment + 1) * g_BufferMemoryAlignment;
VkBufferCreateInfo buffer_info = {};
@@ -215,20 +246,20 @@
buffer_info.size = vertex_buffer_size_aligned;
buffer_info.usage = usage;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &buffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &buffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, buffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, buffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &buffer_memory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &buffer_memory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, buffer, buffer_memory, 0);
+ err = vkBindBufferMemory(v->Device, buffer, buffer_memory, 0);
check_vk_result(err);
p_buffer_size = new_size;
}
@@ -243,25 +274,38 @@
if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount == 0)
return;
- VkResult err;
- FrameDataForRender* fd = &g_FramesDataBuffers[g_FrameIndex];
- g_FrameIndex = (g_FrameIndex + 1) % IM_ARRAYSIZE(g_FramesDataBuffers);
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
- // Create the Vertex and Index buffers:
+ // Allocate array to store enough vertex/index buffers
+ ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &g_MainWindowRenderBuffers;
+ if (wrb->FrameRenderBuffers == NULL)
+ {
+ wrb->Index = 0;
+ wrb->Count = v->ImageCount;
+ wrb->FrameRenderBuffers = (ImGui_ImplVulkanH_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ }
+ IM_ASSERT(wrb->Count == v->ImageCount);
+ wrb->Index = (wrb->Index + 1) % wrb->Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index];
+
+ VkResult err;
+
+ // Create or resize the vertex/index buffers
size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);
size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx);
- if (fd->VertexBuffer == VK_NULL_HANDLE || fd->VertexBufferSize < vertex_size)
- CreateOrResizeBuffer(fd->VertexBuffer, fd->VertexBufferMemory, fd->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
- if (fd->IndexBuffer == VK_NULL_HANDLE || fd->IndexBufferSize < index_size)
- CreateOrResizeBuffer(fd->IndexBuffer, fd->IndexBufferMemory, fd->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
+ if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size)
+ CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+ if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size)
+ CreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
// Upload vertex/index data into a single contiguous GPU buffer
{
ImDrawVert* vtx_dst = NULL;
ImDrawIdx* idx_dst = NULL;
- err = vkMapMemory(g_Device, fd->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
+ err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
check_vk_result(err);
- err = vkMapMemory(g_Device, fd->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
+ err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
check_vk_result(err);
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
@@ -273,15 +317,15 @@
}
VkMappedMemoryRange range[2] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[0].memory = fd->VertexBufferMemory;
+ range[0].memory = rb->VertexBufferMemory;
range[0].size = VK_WHOLE_SIZE;
range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[1].memory = fd->IndexBufferMemory;
+ range[1].memory = rb->IndexBufferMemory;
range[1].size = VK_WHOLE_SIZE;
- err = vkFlushMappedMemoryRanges(g_Device, 2, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 2, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, fd->VertexBufferMemory);
- vkUnmapMemory(g_Device, fd->IndexBufferMemory);
+ vkUnmapMemory(v->Device, rb->VertexBufferMemory);
+ vkUnmapMemory(v->Device, rb->IndexBufferMemory);
}
// Bind pipeline and descriptor sets:
@@ -293,10 +337,10 @@
// Bind Vertex And Index Buffer:
{
- VkBuffer vertex_buffers[1] = { fd->VertexBuffer };
+ VkBuffer vertex_buffers[1] = { rb->VertexBuffer };
VkDeviceSize vertex_offset[1] = { 0 };
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset);
- vkCmdBindIndexBuffer(command_buffer, fd->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
+ vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
}
// Setup viewport:
@@ -379,6 +423,7 @@
bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
@@ -404,17 +449,17 @@
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- err = vkCreateImage(g_Device, &info, g_Allocator, &g_FontImage);
+ err = vkCreateImage(v->Device, &info, v->Allocator, &g_FontImage);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetImageMemoryRequirements(g_Device, g_FontImage, &req);
+ vkGetImageMemoryRequirements(v->Device, g_FontImage, &req);
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_FontMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_FontMemory);
check_vk_result(err);
- err = vkBindImageMemory(g_Device, g_FontImage, g_FontMemory, 0);
+ err = vkBindImageMemory(v->Device, g_FontImage, g_FontMemory, 0);
check_vk_result(err);
}
@@ -428,7 +473,7 @@
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.levelCount = 1;
info.subresourceRange.layerCount = 1;
- err = vkCreateImageView(g_Device, &info, g_Allocator, &g_FontView);
+ err = vkCreateImageView(v->Device, &info, v->Allocator, &g_FontView);
check_vk_result(err);
}
@@ -444,7 +489,7 @@
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
- vkUpdateDescriptorSets(g_Device, 1, write_desc, 0, NULL);
+ vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
// Create the Upload Buffer:
@@ -454,34 +499,34 @@
buffer_info.size = upload_size;
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_UploadBuffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &g_UploadBuffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, g_UploadBuffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, g_UploadBuffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_UploadBufferMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_UploadBufferMemory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, g_UploadBuffer, g_UploadBufferMemory, 0);
+ err = vkBindBufferMemory(v->Device, g_UploadBuffer, g_UploadBufferMemory, 0);
check_vk_result(err);
}
// Upload to Buffer:
{
char* map = NULL;
- err = vkMapMemory(g_Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
+ err = vkMapMemory(v->Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
check_vk_result(err);
memcpy(map, pixels, upload_size);
VkMappedMemoryRange range[1] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[0].memory = g_UploadBufferMemory;
range[0].size = upload_size;
- err = vkFlushMappedMemoryRanges(g_Device, 1, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 1, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, g_UploadBufferMemory);
+ vkUnmapMemory(v->Device, g_UploadBufferMemory);
}
// Copy to Image:
@@ -530,6 +575,7 @@
bool ImGui_ImplVulkan_CreateDeviceObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
VkShaderModule vert_module;
VkShaderModule frag_module;
@@ -540,13 +586,13 @@
vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
vert_info.codeSize = sizeof(__glsl_shader_vert_spv);
vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv;
- err = vkCreateShaderModule(g_Device, &vert_info, g_Allocator, &vert_module);
+ err = vkCreateShaderModule(v->Device, &vert_info, v->Allocator, &vert_module);
check_vk_result(err);
VkShaderModuleCreateInfo frag_info = {};
frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
frag_info.codeSize = sizeof(__glsl_shader_frag_spv);
frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv;
- err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module);
+ err = vkCreateShaderModule(v->Device, &frag_info, v->Allocator, &frag_module);
check_vk_result(err);
}
@@ -563,7 +609,7 @@
info.minLod = -1000;
info.maxLod = 1000;
info.maxAnisotropy = 1.0f;
- err = vkCreateSampler(g_Device, &info, g_Allocator, &g_FontSampler);
+ err = vkCreateSampler(v->Device, &info, v->Allocator, &g_FontSampler);
check_vk_result(err);
}
@@ -579,7 +625,7 @@
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
info.bindingCount = 1;
info.pBindings = binding;
- err = vkCreateDescriptorSetLayout(g_Device, &info, g_Allocator, &g_DescriptorSetLayout);
+ err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &g_DescriptorSetLayout);
check_vk_result(err);
}
@@ -587,10 +633,10 @@
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- alloc_info.descriptorPool = g_DescriptorPool;
+ alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &g_DescriptorSetLayout;
- err = vkAllocateDescriptorSets(g_Device, &alloc_info, &g_DescriptorSet);
+ err = vkAllocateDescriptorSets(v->Device, &alloc_info, &g_DescriptorSet);
check_vk_result(err);
}
@@ -608,7 +654,7 @@
layout_info.pSetLayouts = set_layout;
layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = push_constants;
- err = vkCreatePipelineLayout(g_Device, &layout_info, g_Allocator, &g_PipelineLayout);
+ err = vkCreatePipelineLayout(v->Device, &layout_info, v->Allocator, &g_PipelineLayout);
check_vk_result(err);
}
@@ -706,49 +752,43 @@
info.pDynamicState = &dynamic_state;
info.layout = g_PipelineLayout;
info.renderPass = g_RenderPass;
- err = vkCreateGraphicsPipelines(g_Device, g_PipelineCache, 1, &info, g_Allocator, &g_Pipeline);
+ err = vkCreateGraphicsPipelines(v->Device, v->PipelineCache, 1, &info, v->Allocator, &g_Pipeline);
check_vk_result(err);
- vkDestroyShaderModule(g_Device, vert_module, g_Allocator);
- vkDestroyShaderModule(g_Device, frag_module, g_Allocator);
+ vkDestroyShaderModule(v->Device, vert_module, v->Allocator);
+ vkDestroyShaderModule(v->Device, frag_module, v->Allocator);
return true;
}
-void ImGui_ImplVulkan_InvalidateFontUploadObjects()
+void ImGui_ImplVulkan_DestroyFontUploadObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
if (g_UploadBuffer)
{
- vkDestroyBuffer(g_Device, g_UploadBuffer, g_Allocator);
+ vkDestroyBuffer(v->Device, g_UploadBuffer, v->Allocator);
g_UploadBuffer = VK_NULL_HANDLE;
}
if (g_UploadBufferMemory)
{
- vkFreeMemory(g_Device, g_UploadBufferMemory, g_Allocator);
+ vkFreeMemory(v->Device, g_UploadBufferMemory, v->Allocator);
g_UploadBufferMemory = VK_NULL_HANDLE;
}
}
-void ImGui_ImplVulkan_InvalidateDeviceObjects()
+void ImGui_ImplVulkan_DestroyDeviceObjects()
{
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
- for (int i = 0; i < IM_ARRAYSIZE(g_FramesDataBuffers); i++)
- {
- FrameDataForRender* fd = &g_FramesDataBuffers[i];
- if (fd->VertexBuffer) { vkDestroyBuffer (g_Device, fd->VertexBuffer, g_Allocator); fd->VertexBuffer = VK_NULL_HANDLE; }
- if (fd->VertexBufferMemory) { vkFreeMemory (g_Device, fd->VertexBufferMemory, g_Allocator); fd->VertexBufferMemory = VK_NULL_HANDLE; }
- if (fd->IndexBuffer) { vkDestroyBuffer (g_Device, fd->IndexBuffer, g_Allocator); fd->IndexBuffer = VK_NULL_HANDLE; }
- if (fd->IndexBufferMemory) { vkFreeMemory (g_Device, fd->IndexBufferMemory, g_Allocator); fd->IndexBufferMemory = VK_NULL_HANDLE; }
- }
-
- if (g_FontView) { vkDestroyImageView(g_Device, g_FontView, g_Allocator); g_FontView = VK_NULL_HANDLE; }
- if (g_FontImage) { vkDestroyImage(g_Device, g_FontImage, g_Allocator); g_FontImage = VK_NULL_HANDLE; }
- if (g_FontMemory) { vkFreeMemory(g_Device, g_FontMemory, g_Allocator); g_FontMemory = VK_NULL_HANDLE; }
- if (g_FontSampler) { vkDestroySampler(g_Device, g_FontSampler, g_Allocator); g_FontSampler = VK_NULL_HANDLE; }
- if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(g_Device, g_DescriptorSetLayout, g_Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
- if (g_PipelineLayout) { vkDestroyPipelineLayout(g_Device, g_PipelineLayout, g_Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
- if (g_Pipeline) { vkDestroyPipeline(g_Device, g_Pipeline, g_Allocator); g_Pipeline = VK_NULL_HANDLE; }
+ if (g_FontView) { vkDestroyImageView(v->Device, g_FontView, v->Allocator); g_FontView = VK_NULL_HANDLE; }
+ if (g_FontImage) { vkDestroyImage(v->Device, g_FontImage, v->Allocator); g_FontImage = VK_NULL_HANDLE; }
+ if (g_FontMemory) { vkFreeMemory(v->Device, g_FontMemory, v->Allocator); g_FontMemory = VK_NULL_HANDLE; }
+ if (g_FontSampler) { vkDestroySampler(v->Device, g_FontSampler, v->Allocator); g_FontSampler = VK_NULL_HANDLE; }
+ if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, g_DescriptorSetLayout, v->Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
+ if (g_PipelineLayout) { vkDestroyPipelineLayout(v->Device, g_PipelineLayout, v->Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
+ if (g_Pipeline) { vkDestroyPipeline(v->Device, g_Pipeline, v->Allocator); g_Pipeline = VK_NULL_HANDLE; }
}
bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass)
@@ -763,19 +803,12 @@
IM_ASSERT(info->Device != VK_NULL_HANDLE);
IM_ASSERT(info->Queue != VK_NULL_HANDLE);
IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE);
+ IM_ASSERT(info->MinImageCount >= 2);
+ IM_ASSERT(info->ImageCount >= info->MinImageCount);
IM_ASSERT(render_pass != VK_NULL_HANDLE);
- g_Instance = info->Instance;
- g_PhysicalDevice = info->PhysicalDevice;
- g_Device = info->Device;
- g_QueueFamily = info->QueueFamily;
- g_Queue = info->Queue;
+ g_VulkanInitInfo = *info;
g_RenderPass = render_pass;
- g_PipelineCache = info->PipelineCache;
- g_DescriptorPool = info->DescriptorPool;
- g_Allocator = info->Allocator;
- g_CheckVkResultFn = info->CheckVkResultFn;
-
ImGui_ImplVulkan_CreateDeviceObjects();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
@@ -787,16 +820,30 @@
void ImGui_ImplVulkan_Shutdown()
{
ImGui_ImplVulkan_ShutdownPlatformInterface();
- ImGui_ImplVulkan_InvalidateDeviceObjects();
+ ImGui_ImplVulkan_DestroyDeviceObjects();
}
void ImGui_ImplVulkan_NewFrame()
{
}
+void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
+{
+ IM_ASSERT(min_image_count >= 2);
+ if (g_VulkanInitInfo.MinImageCount == min_image_count)
+ return;
+
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ VkResult err = vkDeviceWaitIdle(v->Device);
+ check_vk_result(err);
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ g_VulkanInitInfo.MinImageCount = min_image_count;
+}
+
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -804,40 +851,12 @@
// 2) the upcoming multi-viewport feature will need them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-#include // malloc
-
-ImGui_ImplVulkanH_FrameData::ImGui_ImplVulkanH_FrameData()
-{
- BackbufferIndex = 0;
- CommandPool = VK_NULL_HANDLE;
- CommandBuffer = VK_NULL_HANDLE;
- Fence = VK_NULL_HANDLE;
- ImageAcquiredSemaphore = VK_NULL_HANDLE;
- RenderCompleteSemaphore = VK_NULL_HANDLE;
-}
-
-ImGui_ImplVulkanH_WindowData::ImGui_ImplVulkanH_WindowData()
-{
- Width = Height = 0;
- Swapchain = VK_NULL_HANDLE;
- Surface = VK_NULL_HANDLE;
- memset(&SurfaceFormat, 0, sizeof(SurfaceFormat));
- PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
- RenderPass = VK_NULL_HANDLE;
- ClearEnable = true;
- memset(&ClearValue, 0, sizeof(ClearValue));
- BackBufferCount = 0;
- memset(&BackBuffer, 0, sizeof(BackBuffer));
- memset(&BackBufferView, 0, sizeof(BackBufferView));
- memset(&Framebuffer, 0, sizeof(Framebuffer));
- FrameIndex = 0;
-}
-
VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space)
{
IM_ASSERT(request_formats != NULL);
@@ -904,7 +923,7 @@
return VK_PRESENT_MODE_FIFO_KHR; // Always available
}
-void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator)
{
IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE);
(void)physical_device;
@@ -912,9 +931,10 @@
// Create Command Buffers
VkResult err;
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i];
{
VkCommandPoolCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
@@ -942,9 +962,9 @@
{
VkSemaphoreCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- err = vkCreateSemaphore(device, &info, allocator, &fd->ImageAcquiredSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->ImageAcquiredSemaphore);
check_vk_result(err);
- err = vkCreateSemaphore(device, &info, allocator, &fd->RenderCompleteSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->RenderCompleteSemaphore);
check_vk_result(err);
}
}
@@ -962,24 +982,26 @@
return 1;
}
-void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h)
+// Also destroy old swap chain and in-flight frames data, if any.
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count)
{
- uint32_t min_image_count = 2; // FIXME: this should become a function parameter
-
VkResult err;
VkSwapchainKHR old_swapchain = wd->Swapchain;
err = vkDeviceWaitIdle(device);
check_vk_result(err);
+ // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one.
// Destroy old Framebuffer
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- if (wd->BackBufferView[i])
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- if (wd->Framebuffer[i])
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- wd->BackBufferCount = 0;
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
+ wd->ImageCount = 0;
if (wd->RenderPass)
vkDestroyRenderPass(device, wd->RenderPass, allocator);
@@ -1023,10 +1045,21 @@
}
err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, NULL);
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, NULL);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, wd->BackBuffer);
+ VkImage backbuffers[16] = {};
+ IM_ASSERT(wd->ImageCount >= min_image_count);
+ IM_ASSERT(wd->ImageCount < IM_ARRAYSIZE(backbuffers));
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers);
check_vk_result(err);
+
+ IM_ASSERT(wd->Frames == NULL);
+ wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount);
+ wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->ImageCount);
+ memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount);
+ memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->ImageCount);
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
+ wd->Frames[i].Backbuffer = backbuffers[i];
}
if (old_swapchain)
vkDestroySwapchainKHR(device, old_swapchain, allocator);
@@ -1080,10 +1113,11 @@
info.components.a = VK_COMPONENT_SWIZZLE_A;
VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
info.subresourceRange = image_range;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- info.image = wd->BackBuffer[i];
- err = vkCreateImageView(device, &info, allocator, &wd->BackBufferView[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ info.image = fd->Backbuffer;
+ err = vkCreateImageView(device, &info, allocator, &fd->BackbufferView);
check_vk_result(err);
}
}
@@ -1099,38 +1133,82 @@
info.width = wd->Width;
info.height = wd->Height;
info.layers = 1;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- attachment[0] = wd->BackBufferView[i];
- err = vkCreateFramebuffer(device, &info, allocator, &wd->Framebuffer[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ attachment[0] = fd->BackbufferView;
+ err = vkCreateFramebuffer(device, &info, allocator, &fd->Framebuffer);
check_vk_result(err);
}
}
}
-void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count)
+{
+ (void)instance;
+ ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count);
+ ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator)
{
vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals)
//vkQueueWaitIdle(g_Queue);
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
- vkDestroyFence(device, fd->Fence, allocator);
- vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
- vkDestroyCommandPool(device, fd->CommandPool, allocator);
- vkDestroySemaphore(device, fd->ImageAcquiredSemaphore, allocator);
- vkDestroySemaphore(device, fd->RenderCompleteSemaphore, allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
- {
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
- }
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
vkDestroyRenderPass(device, wd->RenderPass, allocator);
vkDestroySwapchainKHR(device, wd->Swapchain, allocator);
vkDestroySurfaceKHR(instance, wd->Surface, allocator);
- *wd = ImGui_ImplVulkanH_WindowData();
+
+ *wd = ImGui_ImplVulkanH_Window();
+}
+
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroyFence(device, fd->Fence, allocator);
+ vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
+ vkDestroyCommandPool(device, fd->CommandPool, allocator);
+ fd->Fence = VK_NULL_HANDLE;
+ fd->CommandBuffer = VK_NULL_HANDLE;
+ fd->CommandPool = VK_NULL_HANDLE;
+
+ vkDestroyImageView(device, fd->BackbufferView, allocator);
+ vkDestroyFramebuffer(device, fd->Framebuffer, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator);
+ vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator);
+ fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;
+}
+
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; }
+ if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; }
+ if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; }
+ if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; }
+ buffers->VertexBufferSize = 0;
+ buffers->IndexBufferSize = 0;
+}
+
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ for (uint32_t n = 0; n < buffers->Count; n++)
+ ImGui_ImplVulkanH_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator);
+ IM_FREE(buffers->FrameRenderBuffers);
+ buffers->FrameRenderBuffers = NULL;
+ buffers->Index = 0;
+ buffers->Count = 0;
}
//--------------------------------------------------------------------------------------------------------
diff --git a/examples/imgui_impl_vulkan.h b/examples/imgui_impl_vulkan.h
index ec45dbe..0389af5 100644
--- a/examples/imgui_impl_vulkan.h
+++ b/examples/imgui_impl_vulkan.h
@@ -12,24 +12,32 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
#pragma once
#include
-#define IMGUI_VK_QUEUED_FRAMES 2
-
-// Please zero-clear before use.
+// Initialization data, for ImGui_ImplVulkan_Init()
+// [Please zero-clear before use!]
struct ImGui_ImplVulkan_InitInfo
{
- VkInstance Instance;
- VkPhysicalDevice PhysicalDevice;
- VkDevice Device;
- uint32_t QueueFamily;
- VkQueue Queue;
- VkPipelineCache PipelineCache;
- VkDescriptorPool DescriptorPool;
- const VkAllocationCallbacks* Allocator;
- void (*CheckVkResultFn)(VkResult err);
+ VkInstance Instance;
+ VkPhysicalDevice PhysicalDevice;
+ VkDevice Device;
+ uint32_t QueueFamily;
+ VkQueue Queue;
+ VkPipelineCache PipelineCache;
+ VkDescriptorPool DescriptorPool;
+ uint32_t MinImageCount; // >= 2
+ uint32_t ImageCount; // >= MinImageCount
+ const VkAllocationCallbacks* Allocator;
+ void (*CheckVkResultFn)(VkResult err);
};
// Called by user code
@@ -38,16 +46,13 @@
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
-IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateFontUploadObjects();
-
-// Called by ImGui_ImplVulkan_Init() might be useful elsewhere.
-IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateDeviceObjects();
-IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateDeviceObjects();
+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)
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -55,38 +60,44 @@
// 2) the multi-viewport / platform window implementation needs them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-struct ImGui_ImplVulkanH_FrameData;
-struct ImGui_ImplVulkanH_WindowData;
+struct ImGui_ImplVulkanH_Frame;
+struct ImGui_ImplVulkanH_Window;
-IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
-IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h);
-IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
+// Helpers
+IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wnd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator);
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
// Helper structure to hold the data needed by one rendering frame
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
-struct ImGui_ImplVulkanH_FrameData
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_Frame
{
- uint32_t BackbufferIndex; // Keep track of recently rendered swapchain frame indices
VkCommandPool CommandPool;
VkCommandBuffer CommandBuffer;
VkFence Fence;
+ VkImage Backbuffer;
+ VkImageView BackbufferView;
+ VkFramebuffer Framebuffer;
+};
+
+struct ImGui_ImplVulkanH_FrameSemaphores
+{
VkSemaphore ImageAcquiredSemaphore;
VkSemaphore RenderCompleteSemaphore;
-
- IMGUI_IMPL_API ImGui_ImplVulkanH_FrameData();
};
// Helper structure to hold the data needed by one rendering context into one OS window
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
-struct ImGui_ImplVulkanH_WindowData
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+struct ImGui_ImplVulkanH_Window
{
int Width;
int Height;
@@ -97,13 +108,17 @@
VkRenderPass RenderPass;
bool ClearEnable;
VkClearValue ClearValue;
- uint32_t BackBufferCount;
- VkImage BackBuffer[16];
- VkImageView BackBufferView[16];
- VkFramebuffer Framebuffer[16];
- uint32_t FrameIndex;
- ImGui_ImplVulkanH_FrameData Frames[IMGUI_VK_QUEUED_FRAMES];
+ uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
+ uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
+ uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
+ ImGui_ImplVulkanH_Frame* Frames;
+ ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
- IMGUI_IMPL_API ImGui_ImplVulkanH_WindowData();
+ ImGui_ImplVulkanH_Window()
+ {
+ memset(this, 0, sizeof(*this));
+ PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
+ ClearEnable = true;
+ }
};
diff --git a/imgui.cpp b/imgui.cpp
index c96b2d8..65ea119 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -37,9 +37,14 @@
- Using gamepad/keyboard navigation controls.
- API BREAKING CHANGES (read me when you update!)
- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
+ - Where is the documentation?
+ - Which version should I get?
+ - Who uses Dear ImGui?
+ - Why the odd dual naming, "Dear ImGui" vs "ImGui"?
- How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
- How can I display an image? What is ImTextureID, how does it works?
- - How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.
+ - Why are multiple widgets reacting when I interact with a single one? How can I have
+ multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...
- How can I use my own math types instead of ImVec2/ImVec4?
- How can I load a different font than the default?
- How can I easily use icons in my application?
@@ -563,6 +568,39 @@
FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
======================================
+ Q: Where is the documentation?
+ A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/
+ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments
+ associated to it.
+
+ Q: Which version should I get?
+ A: I occasionally tag Releases (https://github.com/ocornut/imgui/releases) but it is generally safe
+ and recommended to sync to master/latest. The library is fairly stable and regressions tend to be
+ fixed fast when reported. You may also peak at the 'docking' branch which includes:
+ - Docking/Merging features (https://github.com/ocornut/imgui/issues/2109)
+ - Multi-viewport features (https://github.com/ocornut/imgui/issues/1542)
+ Many projects are using this branch and it is kept in sync with master regularly.
+
+ Q: Who uses Dear ImGui?
+ A: See "Quotes" (https://github.com/ocornut/imgui/wiki/Quotes) and
+ "Software using Dear ImGui" (https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages
+ for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+
+ Q: Why the odd dual naming, "Dear ImGui" vs "ImGui"?
+ A: The library started its life as "ImGui" due to the fact that I didn't give it a proper name when
+ when I released 1.0, and had no particular expectation that it would take off. However, the term IMGUI
+ (immediate-mode graphical user interface) was coined before and is being used in variety of other
+ situations (e.g. Unity uses it own implementation of the IMGUI paradigm).
+ To reduce the ambiguity without affecting existing code bases, I have decided on an alternate,
+ longer name "Dear ImGui" that people can use to refer to this specific library.
+ Please try to refer to this library as "Dear ImGui".
+
Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure (e.g. if (ImGui::GetIO().WantCaptureMouse) { ... } )
- When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application.
@@ -664,8 +702,8 @@
Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated.
+ Q: Why are multiple widgets reacting when I interact with a single one?
Q: How can I have multiple widgets with the same label or with an empty label?
- Q: I have multiple widgets with the same label, and only the first one works. Why is that?
A: A primer on labels and the ID Stack...
Dear ImGui internally need to uniquely identify UI elements.
@@ -1344,7 +1382,7 @@
char* ImStrdup(const char* str)
{
size_t len = strlen(str);
- void* buf = ImGui::MemAlloc(len + 1);
+ void* buf = IM_ALLOC(len + 1);
return (char*)memcpy(buf, (const void*)str, len + 1);
}
@@ -1354,8 +1392,8 @@
size_t src_size = strlen(src) + 1;
if (dst_buf_size < src_size)
{
- ImGui::MemFree(dst);
- dst = (char*)ImGui::MemAlloc(src_size);
+ IM_FREE(dst);
+ dst = (char*)IM_ALLOC(src_size);
if (p_dst_size)
*p_dst_size = src_size;
}
@@ -1571,7 +1609,7 @@
}
// Load file content into memory
-// Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
+// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()
void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes)
{
IM_ASSERT(filename && file_open_mode);
@@ -1590,7 +1628,7 @@
}
size_t file_size = (size_t)file_size_signed;
- void* file_data = ImGui::MemAlloc(file_size + padding_bytes);
+ void* file_data = IM_ALLOC(file_size + padding_bytes);
if (file_data == NULL)
{
fclose(f);
@@ -1599,7 +1637,7 @@
if (fread(file_data, 1, file_size, f) != file_size)
{
fclose(f);
- ImGui::MemFree(file_data);
+ IM_FREE(file_data);
return NULL;
}
if (padding_bytes > 0)
@@ -3024,6 +3062,7 @@
return ImMax(wrap_pos_x - pos.x, 1.0f);
}
+// IM_ALLOC() == ImGui::MemAlloc()
void* ImGui::MemAlloc(size_t size)
{
if (ImGuiContext* ctx = GImGui)
@@ -3031,6 +3070,7 @@
return GImAllocatorAllocFunc(size, GImAllocatorUserData);
}
+// IM_FREE() == ImGui::MemFree()
void ImGui::MemFree(void* ptr)
{
if (ptr)
@@ -9790,7 +9830,7 @@
if (!file_data)
return;
LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
- ImGui::MemFree(file_data);
+ IM_FREE(file_data);
}
ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
@@ -9814,7 +9854,7 @@
// For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy..
if (ini_size == 0)
ini_size = strlen(ini_data);
- char* buf = (char*)ImGui::MemAlloc(ini_size + 1);
+ char* buf = (char*)IM_ALLOC(ini_size + 1);
char* buf_end = buf + ini_size;
memcpy(buf, ini_data, ini_size);
buf[ini_size] = 0;
@@ -9861,7 +9901,7 @@
entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
}
}
- ImGui::MemFree(buf);
+ IM_FREE(buf);
g.SettingsLoaded = true;
DockContextOnLoadSettings(&g);
}
diff --git a/imgui.h b/imgui.h
index f990e06..4613625 100644
--- a/imgui.h
+++ b/imgui.h
@@ -13,6 +13,7 @@
// Forward declarations and basic types
// ImGui API (Dear ImGui end-user API)
// Flags & Enumerations
+// Memory allocations macros
// ImVector<>
// ImGuiStyle
// ImGuiIO
@@ -1256,6 +1257,22 @@
};
//-----------------------------------------------------------------------------
+// Helpers: Memory allocations macros
+// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE()
+// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
+// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions.
+//-----------------------------------------------------------------------------
+
+struct ImNewDummy {};
+inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; }
+inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new()
+#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE)
+#define IM_FREE(_PTR) ImGui::MemFree(_PTR)
+#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR)
+#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
+template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }
+
+//-----------------------------------------------------------------------------
// Helper: ImVector<>
// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug).
// You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it.
@@ -1280,7 +1297,7 @@
inline ImVector() { Size = Capacity = 0; Data = NULL; }
inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); }
inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; }
- inline ~ImVector() { if (Data) ImGui::MemFree(Data); }
+ inline ~ImVector() { if (Data) IM_FREE(Data); }
inline bool empty() const { return Size == 0; }
inline int size() const { return Size; }
@@ -1289,7 +1306,7 @@
inline T& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; }
inline const T& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; }
- inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } }
+ inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } }
inline T* begin() { return Data; }
inline const T* begin() const { return Data; }
inline T* end() { return Data + Size; }
@@ -1303,7 +1320,7 @@
inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; }
inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; }
- inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); ImGui::MemFree(Data); } Data = new_data; Capacity = new_capacity; }
+ inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; }
// NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden.
inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; }
@@ -1639,16 +1656,6 @@
// Helpers
//-----------------------------------------------------------------------------
-// Helper: IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() macros to call MemAlloc + Placement New, Placement Delete + MemFree
-// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
-// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions.
-struct ImNewDummy {};
-inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; }
-inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new()
-#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR)
-#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
-template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }
-
// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame.
// Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text("This will be called only once per frame");
struct ImGuiOnceUponAFrame
diff --git a/imgui_draw.cpp b/imgui_draw.cpp
index 7ea5b9f..1ac5220 100644
--- a/imgui_draw.cpp
+++ b/imgui_draw.cpp
@@ -130,8 +130,8 @@
#ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
-#define STBTT_malloc(x,u) ((void)(u), ImGui::MemAlloc(x))
-#define STBTT_free(x,u) ((void)(u), ImGui::MemFree(x))
+#define STBTT_malloc(x,u) ((void)(u), IM_ALLOC(x))
+#define STBTT_free(x,u) ((void)(u), IM_FREE(x))
#define STBTT_assert(x) IM_ASSERT(x)
#define STBTT_fmod(x,y) ImFmod(x,y)
#define STBTT_sqrt(x) ImSqrt(x)
@@ -1465,7 +1465,7 @@
for (int i = 0; i < ConfigData.Size; i++)
if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas)
{
- ImGui::MemFree(ConfigData[i].FontData);
+ IM_FREE(ConfigData[i].FontData);
ConfigData[i].FontData = NULL;
}
@@ -1486,9 +1486,9 @@
{
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
if (TexPixelsAlpha8)
- ImGui::MemFree(TexPixelsAlpha8);
+ IM_FREE(TexPixelsAlpha8);
if (TexPixelsRGBA32)
- ImGui::MemFree(TexPixelsRGBA32);
+ IM_FREE(TexPixelsRGBA32);
TexPixelsAlpha8 = NULL;
TexPixelsRGBA32 = NULL;
}
@@ -1534,7 +1534,7 @@
GetTexDataAsAlpha8(&pixels, NULL, NULL);
if (pixels)
{
- TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)TexWidth * (size_t)TexHeight * 4);
+ TexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4);
const unsigned char* src = pixels;
unsigned int* dst = TexPixelsRGBA32;
for (int n = TexWidth * TexHeight; n > 0; n--)
@@ -1566,7 +1566,7 @@
new_font_cfg.DstFont = Fonts.back();
if (!new_font_cfg.FontDataOwnedByAtlas)
{
- new_font_cfg.FontData = ImGui::MemAlloc(new_font_cfg.FontDataSize);
+ new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize);
new_font_cfg.FontDataOwnedByAtlas = true;
memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);
}
@@ -1651,7 +1651,7 @@
ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
{
const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data);
- unsigned char* buf_decompressed_data = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);
+ unsigned char* buf_decompressed_data = (unsigned char *)IM_ALLOC(buf_decompressed_size);
stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);
ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
@@ -1663,10 +1663,10 @@
ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
{
int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
- void* compressed_ttf = ImGui::MemAlloc((size_t)compressed_ttf_size);
+ void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size);
Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
- ImGui::MemFree(compressed_ttf);
+ IM_FREE(compressed_ttf);
return font;
}
@@ -1966,7 +1966,7 @@
// 7. Allocate texture
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
- atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
+ atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight);
memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
spc.pixels = atlas->TexPixelsAlpha8;
spc.height = atlas->TexHeight;
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index ad43c68..9bedf3f 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -98,6 +98,11 @@
-----------------------------------------------------------------------
Breaking Changes:
+- Examples: Vulkan: Added MinImageCount/ImageCount fields in ImGui_ImplVulkan_InitInfo, required
+ during initialization to specify the number of in-flight image requested by swap chains.
+ (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam]
+- Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely
+ on them but it is possible you have!).
Other Changes:
- InputText: Fixed selection background starts rendering one frame after the cursor movement
@@ -108,11 +113,15 @@
- GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419)
- GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero.
- Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood]
+- Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert
+ to using the ImGui::MemAlloc()/MemFree() calls directly.
- Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized
GL function loaders early, and help users understand what they are missing. (#2421)
- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop.
+- Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int).
- Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
+- Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam]
- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454)
- Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott]
- Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott]
diff --git a/docs/README.md b/docs/README.md
index febacf0..ba48517 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -219,29 +219,32 @@
**Where is the documentation?**
-- The documentation is at the top of imgui.cpp + effectively imgui.h.
-- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output.
-- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder.
-- We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
-- Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ applications and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ - We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
**Which version should I get?**
I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
-You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Several projects are using this branch and it is kept in sync with master regularly.
+You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Many projects are using this branch and it is kept in sync with master regularly.
**Who uses Dear ImGui?**
-See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) pages for an (incomplete) list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
**Why the odd dual naming, "Dear ImGui" vs "ImGui"?**
-The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would taker off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library in ambiguous situations. Please try to refer to it as "Dear ImGui".
+The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would take off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). To reduce this ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library. Please try to refer to this library as "Dear ImGui".
**How can I tell whether to dispatch mouse/keyboard to imgui or to my application?**
**How can I display an image? What is ImTextureID, how does it works?**
-
**How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.**
+
**Why are multiple widgets reacting when I interact with a single one? How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...**
**How can I use my own math types instead of ImVec2/ImVec4?**
**How can I load a different font than the default?**
**How can I easily use icons in my application?**
@@ -254,7 +257,7 @@
**I integrated Dear ImGui in my engine and some elements are disappearing when I move windows around..**
**How can I help?**
-See the FAQ in imgui.cpp for answers.
+See the FAQ in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) for answers.
**Can you create elaborate/serious tools with Dear ImGui?**
diff --git a/docs/issue_template.md b/docs/issue_template.md
index 6d88b27..21f0c1a 100644
--- a/docs/issue_template.md
+++ b/docs/issue_template.md
@@ -4,11 +4,11 @@
https://github.com/ocornut/imgui/issues/2261
2. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/LOADING FONTS, please post on the "Getting Started" Discourse forum:
-https://discourse.dearimgui.org/c/getting-started
+https://discourse.dearimgui.org
-3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
+3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
-4. Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users, unless they browse the site.
+4. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.
5. Delete points 1-5 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue.
diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp
index 6f2c4cd..c1548ff 100644
--- a/examples/example_glfw_vulkan/main.cpp
+++ b/examples/example_glfw_vulkan/main.cpp
@@ -1,6 +1,13 @@
// 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"
@@ -23,19 +30,21 @@
#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 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_WindowData g_WindowData;
-static bool g_ResizeWanted = false;
-static int g_ResizeWidth = 0, g_ResizeHeight = 0;
+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)
{
@@ -107,6 +116,7 @@
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);
@@ -183,7 +193,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -211,14 +223,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -231,15 +241,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -260,7 +276,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -283,7 +299,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -292,18 +308,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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)
@@ -313,14 +330,14 @@
static void glfw_resize_callback(GLFWwindow*, int w, int h)
{
- g_ResizeWanted = true;
- g_ResizeWidth = w;
- g_ResizeHeight = h;
+ g_SwapChainRebuild = true;
+ g_SwapChainResizeWidth = w;
+ g_SwapChainResizeHeight = h;
}
int main(int, char**)
{
- // Setup window
+ // Setup GLFW window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
return 1;
@@ -347,8 +364,8 @@
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glfwSetFramebufferSizeCallback(window, glfw_resize_callback);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
@@ -384,6 +401,8 @@
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);
@@ -429,7 +448,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -445,10 +464,13 @@
// - 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();
- if (g_ResizeWanted)
+
+ if (g_SwapChainRebuild)
{
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, g_ResizeWidth, g_ResizeHeight);
- g_ResizeWanted = false;
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -514,6 +536,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
glfwDestroyWindow(window);
diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp
index 42ab4a6..077a825 100644
--- a/examples/example_sdl_vulkan/main.cpp
+++ b/examples/example_sdl_vulkan/main.cpp
@@ -1,6 +1,13 @@
// dear imgui: standalone example application for SDL2 + 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_sdl.h"
#include "imgui_impl_vulkan.h"
@@ -15,17 +22,21 @@
#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 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_WindowData g_WindowData;
+static ImGui_ImplVulkanH_Window g_MainWindowData;
+static uint32_t 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)
{
@@ -97,6 +108,7 @@
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);
@@ -173,7 +185,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -201,14 +215,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -221,15 +233,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -250,7 +268,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -273,7 +291,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -282,18 +300,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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
}
int main(int, char**)
@@ -331,8 +350,8 @@
// Create Framebuffers
int w, h;
SDL_GetWindowSize(window, &w, &h);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
ImGui::CreateContext();
@@ -366,6 +385,8 @@
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);
@@ -411,7 +432,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -434,7 +455,19 @@
if (event.type == SDL_QUIT)
done = true;
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED && event.window.windowID == SDL_GetWindowID(window))
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, (int)event.window.data1, (int)event.window.data2);
+ {
+ g_SwapChainResizeWidth = (int)event.window.data1;
+ g_SwapChainResizeHeight = (int)event.window.data2;
+ g_SwapChainRebuild = true;
+ }
+ }
+
+ if (g_SwapChainRebuild)
+ {
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -500,6 +533,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
SDL_DestroyWindow(window);
diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp
index 5911878..39ec861 100644
--- a/examples/imgui_impl_vulkan.cpp
+++ b/examples/imgui_impl_vulkan.cpp
@@ -12,8 +12,17 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2019-XX-XX: *BREAKING CHANGE*: Vulkan: Added ImageCount/MinImageCount fields in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetMinImageCount().
+// 2019-XX-XX: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper.
// 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
// 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int).
// 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display.
@@ -35,46 +44,61 @@
#include "imgui_impl_vulkan.h"
#include
-// Vulkan data
-static const VkAllocationCallbacks* g_Allocator = NULL;
-static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE;
-static VkInstance g_Instance = 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 VkPipelineCache g_PipelineCache = VK_NULL_HANDLE;
-static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
-static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
-static void (*g_CheckVkResultFn)(VkResult err) = NULL;
-
-static VkDeviceSize g_BufferMemoryAlignment = 256;
-static VkPipelineCreateFlags g_PipelineCreateFlags = 0;
-
-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;
-
-// Frame data
-struct FrameDataForRender
+// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_FrameRenderBuffers
{
- VkDeviceMemory VertexBufferMemory;
- VkDeviceMemory IndexBufferMemory;
- VkDeviceSize VertexBufferSize;
- VkDeviceSize IndexBufferSize;
- VkBuffer VertexBuffer;
- VkBuffer IndexBuffer;
+ VkDeviceMemory VertexBufferMemory;
+ VkDeviceMemory IndexBufferMemory;
+ VkDeviceSize VertexBufferSize;
+ VkDeviceSize IndexBufferSize;
+ VkBuffer VertexBuffer;
+ VkBuffer IndexBuffer;
};
-static int g_FrameIndex = 0;
-static FrameDataForRender g_FramesDataBuffers[IMGUI_VK_QUEUED_FRAMES] = {};
+
+// Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_WindowRenderBuffers
+{
+ uint32_t Index;
+ uint32_t Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* FrameRenderBuffers;
+};
+
+// Vulkan data
+static ImGui_ImplVulkan_InitInfo g_VulkanInitInfo = {};
+static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
+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
-static VkSampler g_FontSampler = VK_NULL_HANDLE;
-static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
-static VkImage g_FontImage = VK_NULL_HANDLE;
-static VkImageView g_FontView = VK_NULL_HANDLE;
-static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
-static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+static VkSampler g_FontSampler = VK_NULL_HANDLE;
+static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
+static VkImage g_FontImage = VK_NULL_HANDLE;
+static VkImageView g_FontView = VK_NULL_HANDLE;
+static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
+static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+
+// Render buffers
+static ImGui_ImplVulkanH_WindowRenderBuffers g_MainWindowRenderBuffers;
+
+// Forward Declarations
+bool ImGui_ImplVulkan_CreateDeviceObjects();
+void ImGui_ImplVulkan_DestroyDeviceObjects();
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
+
+//-----------------------------------------------------------------------------
+// SHADERS
+//-----------------------------------------------------------------------------
// Forward Declarations
static void ImGui_ImplVulkan_InitPlatformInterface();
@@ -185,10 +209,15 @@
0x00010038
};
+//-----------------------------------------------------------------------------
+// FUNCTIONS
+//-----------------------------------------------------------------------------
+
static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkPhysicalDeviceMemoryProperties prop;
- vkGetPhysicalDeviceMemoryProperties(g_PhysicalDevice, &prop);
+ vkGetPhysicalDeviceMemoryProperties(v->PhysicalDevice, &prop);
for (uint32_t i = 0; i < prop.memoryTypeCount; i++)
if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<CheckVkResultFn)
+ v->CheckVkResultFn(err);
}
static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
if (buffer != VK_NULL_HANDLE)
- vkDestroyBuffer(g_Device, buffer, g_Allocator);
- if (buffer_memory)
- vkFreeMemory(g_Device, buffer_memory, g_Allocator);
+ vkDestroyBuffer(v->Device, buffer, v->Allocator);
+ if (buffer_memory != VK_NULL_HANDLE)
+ vkFreeMemory(v->Device, buffer_memory, v->Allocator);
VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / g_BufferMemoryAlignment + 1) * g_BufferMemoryAlignment;
VkBufferCreateInfo buffer_info = {};
@@ -215,20 +246,20 @@
buffer_info.size = vertex_buffer_size_aligned;
buffer_info.usage = usage;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &buffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &buffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, buffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, buffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &buffer_memory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &buffer_memory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, buffer, buffer_memory, 0);
+ err = vkBindBufferMemory(v->Device, buffer, buffer_memory, 0);
check_vk_result(err);
p_buffer_size = new_size;
}
@@ -243,25 +274,38 @@
if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount == 0)
return;
- VkResult err;
- FrameDataForRender* fd = &g_FramesDataBuffers[g_FrameIndex];
- g_FrameIndex = (g_FrameIndex + 1) % IM_ARRAYSIZE(g_FramesDataBuffers);
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
- // Create the Vertex and Index buffers:
+ // Allocate array to store enough vertex/index buffers
+ ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &g_MainWindowRenderBuffers;
+ if (wrb->FrameRenderBuffers == NULL)
+ {
+ wrb->Index = 0;
+ wrb->Count = v->ImageCount;
+ wrb->FrameRenderBuffers = (ImGui_ImplVulkanH_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ }
+ IM_ASSERT(wrb->Count == v->ImageCount);
+ wrb->Index = (wrb->Index + 1) % wrb->Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index];
+
+ VkResult err;
+
+ // Create or resize the vertex/index buffers
size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);
size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx);
- if (fd->VertexBuffer == VK_NULL_HANDLE || fd->VertexBufferSize < vertex_size)
- CreateOrResizeBuffer(fd->VertexBuffer, fd->VertexBufferMemory, fd->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
- if (fd->IndexBuffer == VK_NULL_HANDLE || fd->IndexBufferSize < index_size)
- CreateOrResizeBuffer(fd->IndexBuffer, fd->IndexBufferMemory, fd->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
+ if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size)
+ CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+ if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size)
+ CreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
// Upload vertex/index data into a single contiguous GPU buffer
{
ImDrawVert* vtx_dst = NULL;
ImDrawIdx* idx_dst = NULL;
- err = vkMapMemory(g_Device, fd->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
+ err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
check_vk_result(err);
- err = vkMapMemory(g_Device, fd->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
+ err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
check_vk_result(err);
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
@@ -273,15 +317,15 @@
}
VkMappedMemoryRange range[2] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[0].memory = fd->VertexBufferMemory;
+ range[0].memory = rb->VertexBufferMemory;
range[0].size = VK_WHOLE_SIZE;
range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[1].memory = fd->IndexBufferMemory;
+ range[1].memory = rb->IndexBufferMemory;
range[1].size = VK_WHOLE_SIZE;
- err = vkFlushMappedMemoryRanges(g_Device, 2, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 2, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, fd->VertexBufferMemory);
- vkUnmapMemory(g_Device, fd->IndexBufferMemory);
+ vkUnmapMemory(v->Device, rb->VertexBufferMemory);
+ vkUnmapMemory(v->Device, rb->IndexBufferMemory);
}
// Bind pipeline and descriptor sets:
@@ -293,10 +337,10 @@
// Bind Vertex And Index Buffer:
{
- VkBuffer vertex_buffers[1] = { fd->VertexBuffer };
+ VkBuffer vertex_buffers[1] = { rb->VertexBuffer };
VkDeviceSize vertex_offset[1] = { 0 };
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset);
- vkCmdBindIndexBuffer(command_buffer, fd->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
+ vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
}
// Setup viewport:
@@ -379,6 +423,7 @@
bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
@@ -404,17 +449,17 @@
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- err = vkCreateImage(g_Device, &info, g_Allocator, &g_FontImage);
+ err = vkCreateImage(v->Device, &info, v->Allocator, &g_FontImage);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetImageMemoryRequirements(g_Device, g_FontImage, &req);
+ vkGetImageMemoryRequirements(v->Device, g_FontImage, &req);
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_FontMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_FontMemory);
check_vk_result(err);
- err = vkBindImageMemory(g_Device, g_FontImage, g_FontMemory, 0);
+ err = vkBindImageMemory(v->Device, g_FontImage, g_FontMemory, 0);
check_vk_result(err);
}
@@ -428,7 +473,7 @@
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.levelCount = 1;
info.subresourceRange.layerCount = 1;
- err = vkCreateImageView(g_Device, &info, g_Allocator, &g_FontView);
+ err = vkCreateImageView(v->Device, &info, v->Allocator, &g_FontView);
check_vk_result(err);
}
@@ -444,7 +489,7 @@
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
- vkUpdateDescriptorSets(g_Device, 1, write_desc, 0, NULL);
+ vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
// Create the Upload Buffer:
@@ -454,34 +499,34 @@
buffer_info.size = upload_size;
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_UploadBuffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &g_UploadBuffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, g_UploadBuffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, g_UploadBuffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_UploadBufferMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_UploadBufferMemory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, g_UploadBuffer, g_UploadBufferMemory, 0);
+ err = vkBindBufferMemory(v->Device, g_UploadBuffer, g_UploadBufferMemory, 0);
check_vk_result(err);
}
// Upload to Buffer:
{
char* map = NULL;
- err = vkMapMemory(g_Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
+ err = vkMapMemory(v->Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
check_vk_result(err);
memcpy(map, pixels, upload_size);
VkMappedMemoryRange range[1] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[0].memory = g_UploadBufferMemory;
range[0].size = upload_size;
- err = vkFlushMappedMemoryRanges(g_Device, 1, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 1, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, g_UploadBufferMemory);
+ vkUnmapMemory(v->Device, g_UploadBufferMemory);
}
// Copy to Image:
@@ -530,6 +575,7 @@
bool ImGui_ImplVulkan_CreateDeviceObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
VkShaderModule vert_module;
VkShaderModule frag_module;
@@ -540,13 +586,13 @@
vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
vert_info.codeSize = sizeof(__glsl_shader_vert_spv);
vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv;
- err = vkCreateShaderModule(g_Device, &vert_info, g_Allocator, &vert_module);
+ err = vkCreateShaderModule(v->Device, &vert_info, v->Allocator, &vert_module);
check_vk_result(err);
VkShaderModuleCreateInfo frag_info = {};
frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
frag_info.codeSize = sizeof(__glsl_shader_frag_spv);
frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv;
- err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module);
+ err = vkCreateShaderModule(v->Device, &frag_info, v->Allocator, &frag_module);
check_vk_result(err);
}
@@ -563,7 +609,7 @@
info.minLod = -1000;
info.maxLod = 1000;
info.maxAnisotropy = 1.0f;
- err = vkCreateSampler(g_Device, &info, g_Allocator, &g_FontSampler);
+ err = vkCreateSampler(v->Device, &info, v->Allocator, &g_FontSampler);
check_vk_result(err);
}
@@ -579,7 +625,7 @@
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
info.bindingCount = 1;
info.pBindings = binding;
- err = vkCreateDescriptorSetLayout(g_Device, &info, g_Allocator, &g_DescriptorSetLayout);
+ err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &g_DescriptorSetLayout);
check_vk_result(err);
}
@@ -587,10 +633,10 @@
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- alloc_info.descriptorPool = g_DescriptorPool;
+ alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &g_DescriptorSetLayout;
- err = vkAllocateDescriptorSets(g_Device, &alloc_info, &g_DescriptorSet);
+ err = vkAllocateDescriptorSets(v->Device, &alloc_info, &g_DescriptorSet);
check_vk_result(err);
}
@@ -608,7 +654,7 @@
layout_info.pSetLayouts = set_layout;
layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = push_constants;
- err = vkCreatePipelineLayout(g_Device, &layout_info, g_Allocator, &g_PipelineLayout);
+ err = vkCreatePipelineLayout(v->Device, &layout_info, v->Allocator, &g_PipelineLayout);
check_vk_result(err);
}
@@ -706,49 +752,43 @@
info.pDynamicState = &dynamic_state;
info.layout = g_PipelineLayout;
info.renderPass = g_RenderPass;
- err = vkCreateGraphicsPipelines(g_Device, g_PipelineCache, 1, &info, g_Allocator, &g_Pipeline);
+ err = vkCreateGraphicsPipelines(v->Device, v->PipelineCache, 1, &info, v->Allocator, &g_Pipeline);
check_vk_result(err);
- vkDestroyShaderModule(g_Device, vert_module, g_Allocator);
- vkDestroyShaderModule(g_Device, frag_module, g_Allocator);
+ vkDestroyShaderModule(v->Device, vert_module, v->Allocator);
+ vkDestroyShaderModule(v->Device, frag_module, v->Allocator);
return true;
}
-void ImGui_ImplVulkan_InvalidateFontUploadObjects()
+void ImGui_ImplVulkan_DestroyFontUploadObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
if (g_UploadBuffer)
{
- vkDestroyBuffer(g_Device, g_UploadBuffer, g_Allocator);
+ vkDestroyBuffer(v->Device, g_UploadBuffer, v->Allocator);
g_UploadBuffer = VK_NULL_HANDLE;
}
if (g_UploadBufferMemory)
{
- vkFreeMemory(g_Device, g_UploadBufferMemory, g_Allocator);
+ vkFreeMemory(v->Device, g_UploadBufferMemory, v->Allocator);
g_UploadBufferMemory = VK_NULL_HANDLE;
}
}
-void ImGui_ImplVulkan_InvalidateDeviceObjects()
+void ImGui_ImplVulkan_DestroyDeviceObjects()
{
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
- for (int i = 0; i < IM_ARRAYSIZE(g_FramesDataBuffers); i++)
- {
- FrameDataForRender* fd = &g_FramesDataBuffers[i];
- if (fd->VertexBuffer) { vkDestroyBuffer (g_Device, fd->VertexBuffer, g_Allocator); fd->VertexBuffer = VK_NULL_HANDLE; }
- if (fd->VertexBufferMemory) { vkFreeMemory (g_Device, fd->VertexBufferMemory, g_Allocator); fd->VertexBufferMemory = VK_NULL_HANDLE; }
- if (fd->IndexBuffer) { vkDestroyBuffer (g_Device, fd->IndexBuffer, g_Allocator); fd->IndexBuffer = VK_NULL_HANDLE; }
- if (fd->IndexBufferMemory) { vkFreeMemory (g_Device, fd->IndexBufferMemory, g_Allocator); fd->IndexBufferMemory = VK_NULL_HANDLE; }
- }
-
- if (g_FontView) { vkDestroyImageView(g_Device, g_FontView, g_Allocator); g_FontView = VK_NULL_HANDLE; }
- if (g_FontImage) { vkDestroyImage(g_Device, g_FontImage, g_Allocator); g_FontImage = VK_NULL_HANDLE; }
- if (g_FontMemory) { vkFreeMemory(g_Device, g_FontMemory, g_Allocator); g_FontMemory = VK_NULL_HANDLE; }
- if (g_FontSampler) { vkDestroySampler(g_Device, g_FontSampler, g_Allocator); g_FontSampler = VK_NULL_HANDLE; }
- if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(g_Device, g_DescriptorSetLayout, g_Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
- if (g_PipelineLayout) { vkDestroyPipelineLayout(g_Device, g_PipelineLayout, g_Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
- if (g_Pipeline) { vkDestroyPipeline(g_Device, g_Pipeline, g_Allocator); g_Pipeline = VK_NULL_HANDLE; }
+ if (g_FontView) { vkDestroyImageView(v->Device, g_FontView, v->Allocator); g_FontView = VK_NULL_HANDLE; }
+ if (g_FontImage) { vkDestroyImage(v->Device, g_FontImage, v->Allocator); g_FontImage = VK_NULL_HANDLE; }
+ if (g_FontMemory) { vkFreeMemory(v->Device, g_FontMemory, v->Allocator); g_FontMemory = VK_NULL_HANDLE; }
+ if (g_FontSampler) { vkDestroySampler(v->Device, g_FontSampler, v->Allocator); g_FontSampler = VK_NULL_HANDLE; }
+ if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, g_DescriptorSetLayout, v->Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
+ if (g_PipelineLayout) { vkDestroyPipelineLayout(v->Device, g_PipelineLayout, v->Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
+ if (g_Pipeline) { vkDestroyPipeline(v->Device, g_Pipeline, v->Allocator); g_Pipeline = VK_NULL_HANDLE; }
}
bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass)
@@ -763,19 +803,12 @@
IM_ASSERT(info->Device != VK_NULL_HANDLE);
IM_ASSERT(info->Queue != VK_NULL_HANDLE);
IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE);
+ IM_ASSERT(info->MinImageCount >= 2);
+ IM_ASSERT(info->ImageCount >= info->MinImageCount);
IM_ASSERT(render_pass != VK_NULL_HANDLE);
- g_Instance = info->Instance;
- g_PhysicalDevice = info->PhysicalDevice;
- g_Device = info->Device;
- g_QueueFamily = info->QueueFamily;
- g_Queue = info->Queue;
+ g_VulkanInitInfo = *info;
g_RenderPass = render_pass;
- g_PipelineCache = info->PipelineCache;
- g_DescriptorPool = info->DescriptorPool;
- g_Allocator = info->Allocator;
- g_CheckVkResultFn = info->CheckVkResultFn;
-
ImGui_ImplVulkan_CreateDeviceObjects();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
@@ -787,16 +820,30 @@
void ImGui_ImplVulkan_Shutdown()
{
ImGui_ImplVulkan_ShutdownPlatformInterface();
- ImGui_ImplVulkan_InvalidateDeviceObjects();
+ ImGui_ImplVulkan_DestroyDeviceObjects();
}
void ImGui_ImplVulkan_NewFrame()
{
}
+void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
+{
+ IM_ASSERT(min_image_count >= 2);
+ if (g_VulkanInitInfo.MinImageCount == min_image_count)
+ return;
+
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ VkResult err = vkDeviceWaitIdle(v->Device);
+ check_vk_result(err);
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ g_VulkanInitInfo.MinImageCount = min_image_count;
+}
+
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -804,40 +851,12 @@
// 2) the upcoming multi-viewport feature will need them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-#include // malloc
-
-ImGui_ImplVulkanH_FrameData::ImGui_ImplVulkanH_FrameData()
-{
- BackbufferIndex = 0;
- CommandPool = VK_NULL_HANDLE;
- CommandBuffer = VK_NULL_HANDLE;
- Fence = VK_NULL_HANDLE;
- ImageAcquiredSemaphore = VK_NULL_HANDLE;
- RenderCompleteSemaphore = VK_NULL_HANDLE;
-}
-
-ImGui_ImplVulkanH_WindowData::ImGui_ImplVulkanH_WindowData()
-{
- Width = Height = 0;
- Swapchain = VK_NULL_HANDLE;
- Surface = VK_NULL_HANDLE;
- memset(&SurfaceFormat, 0, sizeof(SurfaceFormat));
- PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
- RenderPass = VK_NULL_HANDLE;
- ClearEnable = true;
- memset(&ClearValue, 0, sizeof(ClearValue));
- BackBufferCount = 0;
- memset(&BackBuffer, 0, sizeof(BackBuffer));
- memset(&BackBufferView, 0, sizeof(BackBufferView));
- memset(&Framebuffer, 0, sizeof(Framebuffer));
- FrameIndex = 0;
-}
-
VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space)
{
IM_ASSERT(request_formats != NULL);
@@ -904,7 +923,7 @@
return VK_PRESENT_MODE_FIFO_KHR; // Always available
}
-void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator)
{
IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE);
(void)physical_device;
@@ -912,9 +931,10 @@
// Create Command Buffers
VkResult err;
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i];
{
VkCommandPoolCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
@@ -942,9 +962,9 @@
{
VkSemaphoreCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- err = vkCreateSemaphore(device, &info, allocator, &fd->ImageAcquiredSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->ImageAcquiredSemaphore);
check_vk_result(err);
- err = vkCreateSemaphore(device, &info, allocator, &fd->RenderCompleteSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->RenderCompleteSemaphore);
check_vk_result(err);
}
}
@@ -962,24 +982,26 @@
return 1;
}
-void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h)
+// Also destroy old swap chain and in-flight frames data, if any.
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count)
{
- uint32_t min_image_count = 2; // FIXME: this should become a function parameter
-
VkResult err;
VkSwapchainKHR old_swapchain = wd->Swapchain;
err = vkDeviceWaitIdle(device);
check_vk_result(err);
+ // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one.
// Destroy old Framebuffer
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- if (wd->BackBufferView[i])
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- if (wd->Framebuffer[i])
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- wd->BackBufferCount = 0;
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
+ wd->ImageCount = 0;
if (wd->RenderPass)
vkDestroyRenderPass(device, wd->RenderPass, allocator);
@@ -1023,10 +1045,21 @@
}
err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, NULL);
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, NULL);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, wd->BackBuffer);
+ VkImage backbuffers[16] = {};
+ IM_ASSERT(wd->ImageCount >= min_image_count);
+ IM_ASSERT(wd->ImageCount < IM_ARRAYSIZE(backbuffers));
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers);
check_vk_result(err);
+
+ IM_ASSERT(wd->Frames == NULL);
+ wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount);
+ wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->ImageCount);
+ memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount);
+ memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->ImageCount);
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
+ wd->Frames[i].Backbuffer = backbuffers[i];
}
if (old_swapchain)
vkDestroySwapchainKHR(device, old_swapchain, allocator);
@@ -1080,10 +1113,11 @@
info.components.a = VK_COMPONENT_SWIZZLE_A;
VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
info.subresourceRange = image_range;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- info.image = wd->BackBuffer[i];
- err = vkCreateImageView(device, &info, allocator, &wd->BackBufferView[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ info.image = fd->Backbuffer;
+ err = vkCreateImageView(device, &info, allocator, &fd->BackbufferView);
check_vk_result(err);
}
}
@@ -1099,38 +1133,82 @@
info.width = wd->Width;
info.height = wd->Height;
info.layers = 1;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- attachment[0] = wd->BackBufferView[i];
- err = vkCreateFramebuffer(device, &info, allocator, &wd->Framebuffer[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ attachment[0] = fd->BackbufferView;
+ err = vkCreateFramebuffer(device, &info, allocator, &fd->Framebuffer);
check_vk_result(err);
}
}
}
-void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count)
+{
+ (void)instance;
+ ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count);
+ ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator)
{
vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals)
//vkQueueWaitIdle(g_Queue);
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
- vkDestroyFence(device, fd->Fence, allocator);
- vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
- vkDestroyCommandPool(device, fd->CommandPool, allocator);
- vkDestroySemaphore(device, fd->ImageAcquiredSemaphore, allocator);
- vkDestroySemaphore(device, fd->RenderCompleteSemaphore, allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
- {
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
- }
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
vkDestroyRenderPass(device, wd->RenderPass, allocator);
vkDestroySwapchainKHR(device, wd->Swapchain, allocator);
vkDestroySurfaceKHR(instance, wd->Surface, allocator);
- *wd = ImGui_ImplVulkanH_WindowData();
+
+ *wd = ImGui_ImplVulkanH_Window();
+}
+
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroyFence(device, fd->Fence, allocator);
+ vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
+ vkDestroyCommandPool(device, fd->CommandPool, allocator);
+ fd->Fence = VK_NULL_HANDLE;
+ fd->CommandBuffer = VK_NULL_HANDLE;
+ fd->CommandPool = VK_NULL_HANDLE;
+
+ vkDestroyImageView(device, fd->BackbufferView, allocator);
+ vkDestroyFramebuffer(device, fd->Framebuffer, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator);
+ vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator);
+ fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;
+}
+
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; }
+ if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; }
+ if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; }
+ if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; }
+ buffers->VertexBufferSize = 0;
+ buffers->IndexBufferSize = 0;
+}
+
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ for (uint32_t n = 0; n < buffers->Count; n++)
+ ImGui_ImplVulkanH_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator);
+ IM_FREE(buffers->FrameRenderBuffers);
+ buffers->FrameRenderBuffers = NULL;
+ buffers->Index = 0;
+ buffers->Count = 0;
}
//--------------------------------------------------------------------------------------------------------
diff --git a/examples/imgui_impl_vulkan.h b/examples/imgui_impl_vulkan.h
index ec45dbe..0389af5 100644
--- a/examples/imgui_impl_vulkan.h
+++ b/examples/imgui_impl_vulkan.h
@@ -12,24 +12,32 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
#pragma once
#include
-#define IMGUI_VK_QUEUED_FRAMES 2
-
-// Please zero-clear before use.
+// Initialization data, for ImGui_ImplVulkan_Init()
+// [Please zero-clear before use!]
struct ImGui_ImplVulkan_InitInfo
{
- VkInstance Instance;
- VkPhysicalDevice PhysicalDevice;
- VkDevice Device;
- uint32_t QueueFamily;
- VkQueue Queue;
- VkPipelineCache PipelineCache;
- VkDescriptorPool DescriptorPool;
- const VkAllocationCallbacks* Allocator;
- void (*CheckVkResultFn)(VkResult err);
+ VkInstance Instance;
+ VkPhysicalDevice PhysicalDevice;
+ VkDevice Device;
+ uint32_t QueueFamily;
+ VkQueue Queue;
+ VkPipelineCache PipelineCache;
+ VkDescriptorPool DescriptorPool;
+ uint32_t MinImageCount; // >= 2
+ uint32_t ImageCount; // >= MinImageCount
+ const VkAllocationCallbacks* Allocator;
+ void (*CheckVkResultFn)(VkResult err);
};
// Called by user code
@@ -38,16 +46,13 @@
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
-IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateFontUploadObjects();
-
-// Called by ImGui_ImplVulkan_Init() might be useful elsewhere.
-IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateDeviceObjects();
-IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateDeviceObjects();
+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)
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -55,38 +60,44 @@
// 2) the multi-viewport / platform window implementation needs them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-struct ImGui_ImplVulkanH_FrameData;
-struct ImGui_ImplVulkanH_WindowData;
+struct ImGui_ImplVulkanH_Frame;
+struct ImGui_ImplVulkanH_Window;
-IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
-IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h);
-IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
+// Helpers
+IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wnd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator);
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
// Helper structure to hold the data needed by one rendering frame
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
-struct ImGui_ImplVulkanH_FrameData
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_Frame
{
- uint32_t BackbufferIndex; // Keep track of recently rendered swapchain frame indices
VkCommandPool CommandPool;
VkCommandBuffer CommandBuffer;
VkFence Fence;
+ VkImage Backbuffer;
+ VkImageView BackbufferView;
+ VkFramebuffer Framebuffer;
+};
+
+struct ImGui_ImplVulkanH_FrameSemaphores
+{
VkSemaphore ImageAcquiredSemaphore;
VkSemaphore RenderCompleteSemaphore;
-
- IMGUI_IMPL_API ImGui_ImplVulkanH_FrameData();
};
// Helper structure to hold the data needed by one rendering context into one OS window
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
-struct ImGui_ImplVulkanH_WindowData
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+struct ImGui_ImplVulkanH_Window
{
int Width;
int Height;
@@ -97,13 +108,17 @@
VkRenderPass RenderPass;
bool ClearEnable;
VkClearValue ClearValue;
- uint32_t BackBufferCount;
- VkImage BackBuffer[16];
- VkImageView BackBufferView[16];
- VkFramebuffer Framebuffer[16];
- uint32_t FrameIndex;
- ImGui_ImplVulkanH_FrameData Frames[IMGUI_VK_QUEUED_FRAMES];
+ uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
+ uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
+ uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
+ ImGui_ImplVulkanH_Frame* Frames;
+ ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
- IMGUI_IMPL_API ImGui_ImplVulkanH_WindowData();
+ ImGui_ImplVulkanH_Window()
+ {
+ memset(this, 0, sizeof(*this));
+ PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
+ ClearEnable = true;
+ }
};
diff --git a/imgui.cpp b/imgui.cpp
index c96b2d8..65ea119 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -37,9 +37,14 @@
- Using gamepad/keyboard navigation controls.
- API BREAKING CHANGES (read me when you update!)
- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
+ - Where is the documentation?
+ - Which version should I get?
+ - Who uses Dear ImGui?
+ - Why the odd dual naming, "Dear ImGui" vs "ImGui"?
- How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
- How can I display an image? What is ImTextureID, how does it works?
- - How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.
+ - Why are multiple widgets reacting when I interact with a single one? How can I have
+ multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...
- How can I use my own math types instead of ImVec2/ImVec4?
- How can I load a different font than the default?
- How can I easily use icons in my application?
@@ -563,6 +568,39 @@
FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
======================================
+ Q: Where is the documentation?
+ A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/
+ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments
+ associated to it.
+
+ Q: Which version should I get?
+ A: I occasionally tag Releases (https://github.com/ocornut/imgui/releases) but it is generally safe
+ and recommended to sync to master/latest. The library is fairly stable and regressions tend to be
+ fixed fast when reported. You may also peak at the 'docking' branch which includes:
+ - Docking/Merging features (https://github.com/ocornut/imgui/issues/2109)
+ - Multi-viewport features (https://github.com/ocornut/imgui/issues/1542)
+ Many projects are using this branch and it is kept in sync with master regularly.
+
+ Q: Who uses Dear ImGui?
+ A: See "Quotes" (https://github.com/ocornut/imgui/wiki/Quotes) and
+ "Software using Dear ImGui" (https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages
+ for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+
+ Q: Why the odd dual naming, "Dear ImGui" vs "ImGui"?
+ A: The library started its life as "ImGui" due to the fact that I didn't give it a proper name when
+ when I released 1.0, and had no particular expectation that it would take off. However, the term IMGUI
+ (immediate-mode graphical user interface) was coined before and is being used in variety of other
+ situations (e.g. Unity uses it own implementation of the IMGUI paradigm).
+ To reduce the ambiguity without affecting existing code bases, I have decided on an alternate,
+ longer name "Dear ImGui" that people can use to refer to this specific library.
+ Please try to refer to this library as "Dear ImGui".
+
Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure (e.g. if (ImGui::GetIO().WantCaptureMouse) { ... } )
- When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application.
@@ -664,8 +702,8 @@
Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated.
+ Q: Why are multiple widgets reacting when I interact with a single one?
Q: How can I have multiple widgets with the same label or with an empty label?
- Q: I have multiple widgets with the same label, and only the first one works. Why is that?
A: A primer on labels and the ID Stack...
Dear ImGui internally need to uniquely identify UI elements.
@@ -1344,7 +1382,7 @@
char* ImStrdup(const char* str)
{
size_t len = strlen(str);
- void* buf = ImGui::MemAlloc(len + 1);
+ void* buf = IM_ALLOC(len + 1);
return (char*)memcpy(buf, (const void*)str, len + 1);
}
@@ -1354,8 +1392,8 @@
size_t src_size = strlen(src) + 1;
if (dst_buf_size < src_size)
{
- ImGui::MemFree(dst);
- dst = (char*)ImGui::MemAlloc(src_size);
+ IM_FREE(dst);
+ dst = (char*)IM_ALLOC(src_size);
if (p_dst_size)
*p_dst_size = src_size;
}
@@ -1571,7 +1609,7 @@
}
// Load file content into memory
-// Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
+// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()
void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes)
{
IM_ASSERT(filename && file_open_mode);
@@ -1590,7 +1628,7 @@
}
size_t file_size = (size_t)file_size_signed;
- void* file_data = ImGui::MemAlloc(file_size + padding_bytes);
+ void* file_data = IM_ALLOC(file_size + padding_bytes);
if (file_data == NULL)
{
fclose(f);
@@ -1599,7 +1637,7 @@
if (fread(file_data, 1, file_size, f) != file_size)
{
fclose(f);
- ImGui::MemFree(file_data);
+ IM_FREE(file_data);
return NULL;
}
if (padding_bytes > 0)
@@ -3024,6 +3062,7 @@
return ImMax(wrap_pos_x - pos.x, 1.0f);
}
+// IM_ALLOC() == ImGui::MemAlloc()
void* ImGui::MemAlloc(size_t size)
{
if (ImGuiContext* ctx = GImGui)
@@ -3031,6 +3070,7 @@
return GImAllocatorAllocFunc(size, GImAllocatorUserData);
}
+// IM_FREE() == ImGui::MemFree()
void ImGui::MemFree(void* ptr)
{
if (ptr)
@@ -9790,7 +9830,7 @@
if (!file_data)
return;
LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
- ImGui::MemFree(file_data);
+ IM_FREE(file_data);
}
ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
@@ -9814,7 +9854,7 @@
// For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy..
if (ini_size == 0)
ini_size = strlen(ini_data);
- char* buf = (char*)ImGui::MemAlloc(ini_size + 1);
+ char* buf = (char*)IM_ALLOC(ini_size + 1);
char* buf_end = buf + ini_size;
memcpy(buf, ini_data, ini_size);
buf[ini_size] = 0;
@@ -9861,7 +9901,7 @@
entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
}
}
- ImGui::MemFree(buf);
+ IM_FREE(buf);
g.SettingsLoaded = true;
DockContextOnLoadSettings(&g);
}
diff --git a/imgui.h b/imgui.h
index f990e06..4613625 100644
--- a/imgui.h
+++ b/imgui.h
@@ -13,6 +13,7 @@
// Forward declarations and basic types
// ImGui API (Dear ImGui end-user API)
// Flags & Enumerations
+// Memory allocations macros
// ImVector<>
// ImGuiStyle
// ImGuiIO
@@ -1256,6 +1257,22 @@
};
//-----------------------------------------------------------------------------
+// Helpers: Memory allocations macros
+// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE()
+// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
+// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions.
+//-----------------------------------------------------------------------------
+
+struct ImNewDummy {};
+inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; }
+inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new()
+#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE)
+#define IM_FREE(_PTR) ImGui::MemFree(_PTR)
+#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR)
+#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
+template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }
+
+//-----------------------------------------------------------------------------
// Helper: ImVector<>
// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug).
// You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it.
@@ -1280,7 +1297,7 @@
inline ImVector() { Size = Capacity = 0; Data = NULL; }
inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); }
inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; }
- inline ~ImVector() { if (Data) ImGui::MemFree(Data); }
+ inline ~ImVector() { if (Data) IM_FREE(Data); }
inline bool empty() const { return Size == 0; }
inline int size() const { return Size; }
@@ -1289,7 +1306,7 @@
inline T& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; }
inline const T& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; }
- inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } }
+ inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } }
inline T* begin() { return Data; }
inline const T* begin() const { return Data; }
inline T* end() { return Data + Size; }
@@ -1303,7 +1320,7 @@
inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; }
inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; }
- inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); ImGui::MemFree(Data); } Data = new_data; Capacity = new_capacity; }
+ inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; }
// NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden.
inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; }
@@ -1639,16 +1656,6 @@
// Helpers
//-----------------------------------------------------------------------------
-// Helper: IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() macros to call MemAlloc + Placement New, Placement Delete + MemFree
-// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
-// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions.
-struct ImNewDummy {};
-inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; }
-inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new()
-#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR)
-#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
-template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }
-
// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame.
// Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text("This will be called only once per frame");
struct ImGuiOnceUponAFrame
diff --git a/imgui_draw.cpp b/imgui_draw.cpp
index 7ea5b9f..1ac5220 100644
--- a/imgui_draw.cpp
+++ b/imgui_draw.cpp
@@ -130,8 +130,8 @@
#ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
-#define STBTT_malloc(x,u) ((void)(u), ImGui::MemAlloc(x))
-#define STBTT_free(x,u) ((void)(u), ImGui::MemFree(x))
+#define STBTT_malloc(x,u) ((void)(u), IM_ALLOC(x))
+#define STBTT_free(x,u) ((void)(u), IM_FREE(x))
#define STBTT_assert(x) IM_ASSERT(x)
#define STBTT_fmod(x,y) ImFmod(x,y)
#define STBTT_sqrt(x) ImSqrt(x)
@@ -1465,7 +1465,7 @@
for (int i = 0; i < ConfigData.Size; i++)
if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas)
{
- ImGui::MemFree(ConfigData[i].FontData);
+ IM_FREE(ConfigData[i].FontData);
ConfigData[i].FontData = NULL;
}
@@ -1486,9 +1486,9 @@
{
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
if (TexPixelsAlpha8)
- ImGui::MemFree(TexPixelsAlpha8);
+ IM_FREE(TexPixelsAlpha8);
if (TexPixelsRGBA32)
- ImGui::MemFree(TexPixelsRGBA32);
+ IM_FREE(TexPixelsRGBA32);
TexPixelsAlpha8 = NULL;
TexPixelsRGBA32 = NULL;
}
@@ -1534,7 +1534,7 @@
GetTexDataAsAlpha8(&pixels, NULL, NULL);
if (pixels)
{
- TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)TexWidth * (size_t)TexHeight * 4);
+ TexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4);
const unsigned char* src = pixels;
unsigned int* dst = TexPixelsRGBA32;
for (int n = TexWidth * TexHeight; n > 0; n--)
@@ -1566,7 +1566,7 @@
new_font_cfg.DstFont = Fonts.back();
if (!new_font_cfg.FontDataOwnedByAtlas)
{
- new_font_cfg.FontData = ImGui::MemAlloc(new_font_cfg.FontDataSize);
+ new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize);
new_font_cfg.FontDataOwnedByAtlas = true;
memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);
}
@@ -1651,7 +1651,7 @@
ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
{
const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data);
- unsigned char* buf_decompressed_data = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);
+ unsigned char* buf_decompressed_data = (unsigned char *)IM_ALLOC(buf_decompressed_size);
stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);
ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
@@ -1663,10 +1663,10 @@
ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
{
int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
- void* compressed_ttf = ImGui::MemAlloc((size_t)compressed_ttf_size);
+ void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size);
Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
- ImGui::MemFree(compressed_ttf);
+ IM_FREE(compressed_ttf);
return font;
}
@@ -1966,7 +1966,7 @@
// 7. Allocate texture
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
- atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
+ atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight);
memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
spc.pixels = atlas->TexPixelsAlpha8;
spc.height = atlas->TexHeight;
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 4a485d9..fbd6f7c 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -3571,7 +3571,7 @@
const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0;
const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW;
const int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1;
- char* clipboard_data = (char*)MemAlloc(clipboard_data_len * sizeof(char));
+ char* clipboard_data = (char*)IM_ALLOC(clipboard_data_len * sizeof(char));
ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie);
SetClipboardText(clipboard_data);
MemFree(clipboard_data);
@@ -3590,7 +3590,7 @@
{
// Filter pasted buffer
const int clipboard_len = (int)strlen(clipboard);
- ImWchar* clipboard_filtered = (ImWchar*)MemAlloc((clipboard_len+1) * sizeof(ImWchar));
+ ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len+1) * sizeof(ImWchar));
int clipboard_filtered_len = 0;
for (const char* s = clipboard; *s; )
{
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index ad43c68..9bedf3f 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -98,6 +98,11 @@
-----------------------------------------------------------------------
Breaking Changes:
+- Examples: Vulkan: Added MinImageCount/ImageCount fields in ImGui_ImplVulkan_InitInfo, required
+ during initialization to specify the number of in-flight image requested by swap chains.
+ (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam]
+- Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely
+ on them but it is possible you have!).
Other Changes:
- InputText: Fixed selection background starts rendering one frame after the cursor movement
@@ -108,11 +113,15 @@
- GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419)
- GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero.
- Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood]
+- Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert
+ to using the ImGui::MemAlloc()/MemFree() calls directly.
- Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized
GL function loaders early, and help users understand what they are missing. (#2421)
- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop.
+- Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int).
- Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
+- Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam]
- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454)
- Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott]
- Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott]
diff --git a/docs/README.md b/docs/README.md
index febacf0..ba48517 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -219,29 +219,32 @@
**Where is the documentation?**
-- The documentation is at the top of imgui.cpp + effectively imgui.h.
-- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output.
-- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder.
-- We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
-- Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ applications and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ - We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
**Which version should I get?**
I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
-You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Several projects are using this branch and it is kept in sync with master regularly.
+You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Many projects are using this branch and it is kept in sync with master regularly.
**Who uses Dear ImGui?**
-See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) pages for an (incomplete) list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
**Why the odd dual naming, "Dear ImGui" vs "ImGui"?**
-The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would taker off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library in ambiguous situations. Please try to refer to it as "Dear ImGui".
+The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would take off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). To reduce this ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library. Please try to refer to this library as "Dear ImGui".
**How can I tell whether to dispatch mouse/keyboard to imgui or to my application?**
**How can I display an image? What is ImTextureID, how does it works?**
-
**How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.**
+
**Why are multiple widgets reacting when I interact with a single one? How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...**
**How can I use my own math types instead of ImVec2/ImVec4?**
**How can I load a different font than the default?**
**How can I easily use icons in my application?**
@@ -254,7 +257,7 @@
**I integrated Dear ImGui in my engine and some elements are disappearing when I move windows around..**
**How can I help?**
-See the FAQ in imgui.cpp for answers.
+See the FAQ in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) for answers.
**Can you create elaborate/serious tools with Dear ImGui?**
diff --git a/docs/issue_template.md b/docs/issue_template.md
index 6d88b27..21f0c1a 100644
--- a/docs/issue_template.md
+++ b/docs/issue_template.md
@@ -4,11 +4,11 @@
https://github.com/ocornut/imgui/issues/2261
2. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/LOADING FONTS, please post on the "Getting Started" Discourse forum:
-https://discourse.dearimgui.org/c/getting-started
+https://discourse.dearimgui.org
-3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
+3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
-4. Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users, unless they browse the site.
+4. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.
5. Delete points 1-5 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue.
diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp
index 6f2c4cd..c1548ff 100644
--- a/examples/example_glfw_vulkan/main.cpp
+++ b/examples/example_glfw_vulkan/main.cpp
@@ -1,6 +1,13 @@
// 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"
@@ -23,19 +30,21 @@
#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 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_WindowData g_WindowData;
-static bool g_ResizeWanted = false;
-static int g_ResizeWidth = 0, g_ResizeHeight = 0;
+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)
{
@@ -107,6 +116,7 @@
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);
@@ -183,7 +193,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -211,14 +223,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -231,15 +241,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -260,7 +276,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -283,7 +299,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -292,18 +308,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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)
@@ -313,14 +330,14 @@
static void glfw_resize_callback(GLFWwindow*, int w, int h)
{
- g_ResizeWanted = true;
- g_ResizeWidth = w;
- g_ResizeHeight = h;
+ g_SwapChainRebuild = true;
+ g_SwapChainResizeWidth = w;
+ g_SwapChainResizeHeight = h;
}
int main(int, char**)
{
- // Setup window
+ // Setup GLFW window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
return 1;
@@ -347,8 +364,8 @@
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glfwSetFramebufferSizeCallback(window, glfw_resize_callback);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
@@ -384,6 +401,8 @@
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);
@@ -429,7 +448,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -445,10 +464,13 @@
// - 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();
- if (g_ResizeWanted)
+
+ if (g_SwapChainRebuild)
{
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, g_ResizeWidth, g_ResizeHeight);
- g_ResizeWanted = false;
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -514,6 +536,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
glfwDestroyWindow(window);
diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp
index 42ab4a6..077a825 100644
--- a/examples/example_sdl_vulkan/main.cpp
+++ b/examples/example_sdl_vulkan/main.cpp
@@ -1,6 +1,13 @@
// dear imgui: standalone example application for SDL2 + 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_sdl.h"
#include "imgui_impl_vulkan.h"
@@ -15,17 +22,21 @@
#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 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_WindowData g_WindowData;
+static ImGui_ImplVulkanH_Window g_MainWindowData;
+static uint32_t 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)
{
@@ -97,6 +108,7 @@
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);
@@ -173,7 +185,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -201,14 +215,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -221,15 +233,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -250,7 +268,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -273,7 +291,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -282,18 +300,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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
}
int main(int, char**)
@@ -331,8 +350,8 @@
// Create Framebuffers
int w, h;
SDL_GetWindowSize(window, &w, &h);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
ImGui::CreateContext();
@@ -366,6 +385,8 @@
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);
@@ -411,7 +432,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -434,7 +455,19 @@
if (event.type == SDL_QUIT)
done = true;
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED && event.window.windowID == SDL_GetWindowID(window))
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, (int)event.window.data1, (int)event.window.data2);
+ {
+ g_SwapChainResizeWidth = (int)event.window.data1;
+ g_SwapChainResizeHeight = (int)event.window.data2;
+ g_SwapChainRebuild = true;
+ }
+ }
+
+ if (g_SwapChainRebuild)
+ {
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -500,6 +533,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
SDL_DestroyWindow(window);
diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp
index 5911878..39ec861 100644
--- a/examples/imgui_impl_vulkan.cpp
+++ b/examples/imgui_impl_vulkan.cpp
@@ -12,8 +12,17 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2019-XX-XX: *BREAKING CHANGE*: Vulkan: Added ImageCount/MinImageCount fields in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetMinImageCount().
+// 2019-XX-XX: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper.
// 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
// 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int).
// 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display.
@@ -35,46 +44,61 @@
#include "imgui_impl_vulkan.h"
#include
-// Vulkan data
-static const VkAllocationCallbacks* g_Allocator = NULL;
-static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE;
-static VkInstance g_Instance = 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 VkPipelineCache g_PipelineCache = VK_NULL_HANDLE;
-static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
-static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
-static void (*g_CheckVkResultFn)(VkResult err) = NULL;
-
-static VkDeviceSize g_BufferMemoryAlignment = 256;
-static VkPipelineCreateFlags g_PipelineCreateFlags = 0;
-
-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;
-
-// Frame data
-struct FrameDataForRender
+// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_FrameRenderBuffers
{
- VkDeviceMemory VertexBufferMemory;
- VkDeviceMemory IndexBufferMemory;
- VkDeviceSize VertexBufferSize;
- VkDeviceSize IndexBufferSize;
- VkBuffer VertexBuffer;
- VkBuffer IndexBuffer;
+ VkDeviceMemory VertexBufferMemory;
+ VkDeviceMemory IndexBufferMemory;
+ VkDeviceSize VertexBufferSize;
+ VkDeviceSize IndexBufferSize;
+ VkBuffer VertexBuffer;
+ VkBuffer IndexBuffer;
};
-static int g_FrameIndex = 0;
-static FrameDataForRender g_FramesDataBuffers[IMGUI_VK_QUEUED_FRAMES] = {};
+
+// Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_WindowRenderBuffers
+{
+ uint32_t Index;
+ uint32_t Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* FrameRenderBuffers;
+};
+
+// Vulkan data
+static ImGui_ImplVulkan_InitInfo g_VulkanInitInfo = {};
+static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
+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
-static VkSampler g_FontSampler = VK_NULL_HANDLE;
-static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
-static VkImage g_FontImage = VK_NULL_HANDLE;
-static VkImageView g_FontView = VK_NULL_HANDLE;
-static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
-static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+static VkSampler g_FontSampler = VK_NULL_HANDLE;
+static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
+static VkImage g_FontImage = VK_NULL_HANDLE;
+static VkImageView g_FontView = VK_NULL_HANDLE;
+static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
+static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+
+// Render buffers
+static ImGui_ImplVulkanH_WindowRenderBuffers g_MainWindowRenderBuffers;
+
+// Forward Declarations
+bool ImGui_ImplVulkan_CreateDeviceObjects();
+void ImGui_ImplVulkan_DestroyDeviceObjects();
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
+
+//-----------------------------------------------------------------------------
+// SHADERS
+//-----------------------------------------------------------------------------
// Forward Declarations
static void ImGui_ImplVulkan_InitPlatformInterface();
@@ -185,10 +209,15 @@
0x00010038
};
+//-----------------------------------------------------------------------------
+// FUNCTIONS
+//-----------------------------------------------------------------------------
+
static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkPhysicalDeviceMemoryProperties prop;
- vkGetPhysicalDeviceMemoryProperties(g_PhysicalDevice, &prop);
+ vkGetPhysicalDeviceMemoryProperties(v->PhysicalDevice, &prop);
for (uint32_t i = 0; i < prop.memoryTypeCount; i++)
if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<CheckVkResultFn)
+ v->CheckVkResultFn(err);
}
static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
if (buffer != VK_NULL_HANDLE)
- vkDestroyBuffer(g_Device, buffer, g_Allocator);
- if (buffer_memory)
- vkFreeMemory(g_Device, buffer_memory, g_Allocator);
+ vkDestroyBuffer(v->Device, buffer, v->Allocator);
+ if (buffer_memory != VK_NULL_HANDLE)
+ vkFreeMemory(v->Device, buffer_memory, v->Allocator);
VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / g_BufferMemoryAlignment + 1) * g_BufferMemoryAlignment;
VkBufferCreateInfo buffer_info = {};
@@ -215,20 +246,20 @@
buffer_info.size = vertex_buffer_size_aligned;
buffer_info.usage = usage;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &buffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &buffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, buffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, buffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &buffer_memory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &buffer_memory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, buffer, buffer_memory, 0);
+ err = vkBindBufferMemory(v->Device, buffer, buffer_memory, 0);
check_vk_result(err);
p_buffer_size = new_size;
}
@@ -243,25 +274,38 @@
if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount == 0)
return;
- VkResult err;
- FrameDataForRender* fd = &g_FramesDataBuffers[g_FrameIndex];
- g_FrameIndex = (g_FrameIndex + 1) % IM_ARRAYSIZE(g_FramesDataBuffers);
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
- // Create the Vertex and Index buffers:
+ // Allocate array to store enough vertex/index buffers
+ ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &g_MainWindowRenderBuffers;
+ if (wrb->FrameRenderBuffers == NULL)
+ {
+ wrb->Index = 0;
+ wrb->Count = v->ImageCount;
+ wrb->FrameRenderBuffers = (ImGui_ImplVulkanH_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ }
+ IM_ASSERT(wrb->Count == v->ImageCount);
+ wrb->Index = (wrb->Index + 1) % wrb->Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index];
+
+ VkResult err;
+
+ // Create or resize the vertex/index buffers
size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);
size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx);
- if (fd->VertexBuffer == VK_NULL_HANDLE || fd->VertexBufferSize < vertex_size)
- CreateOrResizeBuffer(fd->VertexBuffer, fd->VertexBufferMemory, fd->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
- if (fd->IndexBuffer == VK_NULL_HANDLE || fd->IndexBufferSize < index_size)
- CreateOrResizeBuffer(fd->IndexBuffer, fd->IndexBufferMemory, fd->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
+ if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size)
+ CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+ if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size)
+ CreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
// Upload vertex/index data into a single contiguous GPU buffer
{
ImDrawVert* vtx_dst = NULL;
ImDrawIdx* idx_dst = NULL;
- err = vkMapMemory(g_Device, fd->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
+ err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
check_vk_result(err);
- err = vkMapMemory(g_Device, fd->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
+ err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
check_vk_result(err);
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
@@ -273,15 +317,15 @@
}
VkMappedMemoryRange range[2] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[0].memory = fd->VertexBufferMemory;
+ range[0].memory = rb->VertexBufferMemory;
range[0].size = VK_WHOLE_SIZE;
range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[1].memory = fd->IndexBufferMemory;
+ range[1].memory = rb->IndexBufferMemory;
range[1].size = VK_WHOLE_SIZE;
- err = vkFlushMappedMemoryRanges(g_Device, 2, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 2, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, fd->VertexBufferMemory);
- vkUnmapMemory(g_Device, fd->IndexBufferMemory);
+ vkUnmapMemory(v->Device, rb->VertexBufferMemory);
+ vkUnmapMemory(v->Device, rb->IndexBufferMemory);
}
// Bind pipeline and descriptor sets:
@@ -293,10 +337,10 @@
// Bind Vertex And Index Buffer:
{
- VkBuffer vertex_buffers[1] = { fd->VertexBuffer };
+ VkBuffer vertex_buffers[1] = { rb->VertexBuffer };
VkDeviceSize vertex_offset[1] = { 0 };
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset);
- vkCmdBindIndexBuffer(command_buffer, fd->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
+ vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
}
// Setup viewport:
@@ -379,6 +423,7 @@
bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
@@ -404,17 +449,17 @@
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- err = vkCreateImage(g_Device, &info, g_Allocator, &g_FontImage);
+ err = vkCreateImage(v->Device, &info, v->Allocator, &g_FontImage);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetImageMemoryRequirements(g_Device, g_FontImage, &req);
+ vkGetImageMemoryRequirements(v->Device, g_FontImage, &req);
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_FontMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_FontMemory);
check_vk_result(err);
- err = vkBindImageMemory(g_Device, g_FontImage, g_FontMemory, 0);
+ err = vkBindImageMemory(v->Device, g_FontImage, g_FontMemory, 0);
check_vk_result(err);
}
@@ -428,7 +473,7 @@
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.levelCount = 1;
info.subresourceRange.layerCount = 1;
- err = vkCreateImageView(g_Device, &info, g_Allocator, &g_FontView);
+ err = vkCreateImageView(v->Device, &info, v->Allocator, &g_FontView);
check_vk_result(err);
}
@@ -444,7 +489,7 @@
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
- vkUpdateDescriptorSets(g_Device, 1, write_desc, 0, NULL);
+ vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
// Create the Upload Buffer:
@@ -454,34 +499,34 @@
buffer_info.size = upload_size;
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_UploadBuffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &g_UploadBuffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, g_UploadBuffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, g_UploadBuffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_UploadBufferMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_UploadBufferMemory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, g_UploadBuffer, g_UploadBufferMemory, 0);
+ err = vkBindBufferMemory(v->Device, g_UploadBuffer, g_UploadBufferMemory, 0);
check_vk_result(err);
}
// Upload to Buffer:
{
char* map = NULL;
- err = vkMapMemory(g_Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
+ err = vkMapMemory(v->Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
check_vk_result(err);
memcpy(map, pixels, upload_size);
VkMappedMemoryRange range[1] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[0].memory = g_UploadBufferMemory;
range[0].size = upload_size;
- err = vkFlushMappedMemoryRanges(g_Device, 1, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 1, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, g_UploadBufferMemory);
+ vkUnmapMemory(v->Device, g_UploadBufferMemory);
}
// Copy to Image:
@@ -530,6 +575,7 @@
bool ImGui_ImplVulkan_CreateDeviceObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
VkShaderModule vert_module;
VkShaderModule frag_module;
@@ -540,13 +586,13 @@
vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
vert_info.codeSize = sizeof(__glsl_shader_vert_spv);
vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv;
- err = vkCreateShaderModule(g_Device, &vert_info, g_Allocator, &vert_module);
+ err = vkCreateShaderModule(v->Device, &vert_info, v->Allocator, &vert_module);
check_vk_result(err);
VkShaderModuleCreateInfo frag_info = {};
frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
frag_info.codeSize = sizeof(__glsl_shader_frag_spv);
frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv;
- err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module);
+ err = vkCreateShaderModule(v->Device, &frag_info, v->Allocator, &frag_module);
check_vk_result(err);
}
@@ -563,7 +609,7 @@
info.minLod = -1000;
info.maxLod = 1000;
info.maxAnisotropy = 1.0f;
- err = vkCreateSampler(g_Device, &info, g_Allocator, &g_FontSampler);
+ err = vkCreateSampler(v->Device, &info, v->Allocator, &g_FontSampler);
check_vk_result(err);
}
@@ -579,7 +625,7 @@
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
info.bindingCount = 1;
info.pBindings = binding;
- err = vkCreateDescriptorSetLayout(g_Device, &info, g_Allocator, &g_DescriptorSetLayout);
+ err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &g_DescriptorSetLayout);
check_vk_result(err);
}
@@ -587,10 +633,10 @@
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- alloc_info.descriptorPool = g_DescriptorPool;
+ alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &g_DescriptorSetLayout;
- err = vkAllocateDescriptorSets(g_Device, &alloc_info, &g_DescriptorSet);
+ err = vkAllocateDescriptorSets(v->Device, &alloc_info, &g_DescriptorSet);
check_vk_result(err);
}
@@ -608,7 +654,7 @@
layout_info.pSetLayouts = set_layout;
layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = push_constants;
- err = vkCreatePipelineLayout(g_Device, &layout_info, g_Allocator, &g_PipelineLayout);
+ err = vkCreatePipelineLayout(v->Device, &layout_info, v->Allocator, &g_PipelineLayout);
check_vk_result(err);
}
@@ -706,49 +752,43 @@
info.pDynamicState = &dynamic_state;
info.layout = g_PipelineLayout;
info.renderPass = g_RenderPass;
- err = vkCreateGraphicsPipelines(g_Device, g_PipelineCache, 1, &info, g_Allocator, &g_Pipeline);
+ err = vkCreateGraphicsPipelines(v->Device, v->PipelineCache, 1, &info, v->Allocator, &g_Pipeline);
check_vk_result(err);
- vkDestroyShaderModule(g_Device, vert_module, g_Allocator);
- vkDestroyShaderModule(g_Device, frag_module, g_Allocator);
+ vkDestroyShaderModule(v->Device, vert_module, v->Allocator);
+ vkDestroyShaderModule(v->Device, frag_module, v->Allocator);
return true;
}
-void ImGui_ImplVulkan_InvalidateFontUploadObjects()
+void ImGui_ImplVulkan_DestroyFontUploadObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
if (g_UploadBuffer)
{
- vkDestroyBuffer(g_Device, g_UploadBuffer, g_Allocator);
+ vkDestroyBuffer(v->Device, g_UploadBuffer, v->Allocator);
g_UploadBuffer = VK_NULL_HANDLE;
}
if (g_UploadBufferMemory)
{
- vkFreeMemory(g_Device, g_UploadBufferMemory, g_Allocator);
+ vkFreeMemory(v->Device, g_UploadBufferMemory, v->Allocator);
g_UploadBufferMemory = VK_NULL_HANDLE;
}
}
-void ImGui_ImplVulkan_InvalidateDeviceObjects()
+void ImGui_ImplVulkan_DestroyDeviceObjects()
{
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
- for (int i = 0; i < IM_ARRAYSIZE(g_FramesDataBuffers); i++)
- {
- FrameDataForRender* fd = &g_FramesDataBuffers[i];
- if (fd->VertexBuffer) { vkDestroyBuffer (g_Device, fd->VertexBuffer, g_Allocator); fd->VertexBuffer = VK_NULL_HANDLE; }
- if (fd->VertexBufferMemory) { vkFreeMemory (g_Device, fd->VertexBufferMemory, g_Allocator); fd->VertexBufferMemory = VK_NULL_HANDLE; }
- if (fd->IndexBuffer) { vkDestroyBuffer (g_Device, fd->IndexBuffer, g_Allocator); fd->IndexBuffer = VK_NULL_HANDLE; }
- if (fd->IndexBufferMemory) { vkFreeMemory (g_Device, fd->IndexBufferMemory, g_Allocator); fd->IndexBufferMemory = VK_NULL_HANDLE; }
- }
-
- if (g_FontView) { vkDestroyImageView(g_Device, g_FontView, g_Allocator); g_FontView = VK_NULL_HANDLE; }
- if (g_FontImage) { vkDestroyImage(g_Device, g_FontImage, g_Allocator); g_FontImage = VK_NULL_HANDLE; }
- if (g_FontMemory) { vkFreeMemory(g_Device, g_FontMemory, g_Allocator); g_FontMemory = VK_NULL_HANDLE; }
- if (g_FontSampler) { vkDestroySampler(g_Device, g_FontSampler, g_Allocator); g_FontSampler = VK_NULL_HANDLE; }
- if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(g_Device, g_DescriptorSetLayout, g_Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
- if (g_PipelineLayout) { vkDestroyPipelineLayout(g_Device, g_PipelineLayout, g_Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
- if (g_Pipeline) { vkDestroyPipeline(g_Device, g_Pipeline, g_Allocator); g_Pipeline = VK_NULL_HANDLE; }
+ if (g_FontView) { vkDestroyImageView(v->Device, g_FontView, v->Allocator); g_FontView = VK_NULL_HANDLE; }
+ if (g_FontImage) { vkDestroyImage(v->Device, g_FontImage, v->Allocator); g_FontImage = VK_NULL_HANDLE; }
+ if (g_FontMemory) { vkFreeMemory(v->Device, g_FontMemory, v->Allocator); g_FontMemory = VK_NULL_HANDLE; }
+ if (g_FontSampler) { vkDestroySampler(v->Device, g_FontSampler, v->Allocator); g_FontSampler = VK_NULL_HANDLE; }
+ if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, g_DescriptorSetLayout, v->Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
+ if (g_PipelineLayout) { vkDestroyPipelineLayout(v->Device, g_PipelineLayout, v->Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
+ if (g_Pipeline) { vkDestroyPipeline(v->Device, g_Pipeline, v->Allocator); g_Pipeline = VK_NULL_HANDLE; }
}
bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass)
@@ -763,19 +803,12 @@
IM_ASSERT(info->Device != VK_NULL_HANDLE);
IM_ASSERT(info->Queue != VK_NULL_HANDLE);
IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE);
+ IM_ASSERT(info->MinImageCount >= 2);
+ IM_ASSERT(info->ImageCount >= info->MinImageCount);
IM_ASSERT(render_pass != VK_NULL_HANDLE);
- g_Instance = info->Instance;
- g_PhysicalDevice = info->PhysicalDevice;
- g_Device = info->Device;
- g_QueueFamily = info->QueueFamily;
- g_Queue = info->Queue;
+ g_VulkanInitInfo = *info;
g_RenderPass = render_pass;
- g_PipelineCache = info->PipelineCache;
- g_DescriptorPool = info->DescriptorPool;
- g_Allocator = info->Allocator;
- g_CheckVkResultFn = info->CheckVkResultFn;
-
ImGui_ImplVulkan_CreateDeviceObjects();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
@@ -787,16 +820,30 @@
void ImGui_ImplVulkan_Shutdown()
{
ImGui_ImplVulkan_ShutdownPlatformInterface();
- ImGui_ImplVulkan_InvalidateDeviceObjects();
+ ImGui_ImplVulkan_DestroyDeviceObjects();
}
void ImGui_ImplVulkan_NewFrame()
{
}
+void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
+{
+ IM_ASSERT(min_image_count >= 2);
+ if (g_VulkanInitInfo.MinImageCount == min_image_count)
+ return;
+
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ VkResult err = vkDeviceWaitIdle(v->Device);
+ check_vk_result(err);
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ g_VulkanInitInfo.MinImageCount = min_image_count;
+}
+
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -804,40 +851,12 @@
// 2) the upcoming multi-viewport feature will need them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-#include // malloc
-
-ImGui_ImplVulkanH_FrameData::ImGui_ImplVulkanH_FrameData()
-{
- BackbufferIndex = 0;
- CommandPool = VK_NULL_HANDLE;
- CommandBuffer = VK_NULL_HANDLE;
- Fence = VK_NULL_HANDLE;
- ImageAcquiredSemaphore = VK_NULL_HANDLE;
- RenderCompleteSemaphore = VK_NULL_HANDLE;
-}
-
-ImGui_ImplVulkanH_WindowData::ImGui_ImplVulkanH_WindowData()
-{
- Width = Height = 0;
- Swapchain = VK_NULL_HANDLE;
- Surface = VK_NULL_HANDLE;
- memset(&SurfaceFormat, 0, sizeof(SurfaceFormat));
- PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
- RenderPass = VK_NULL_HANDLE;
- ClearEnable = true;
- memset(&ClearValue, 0, sizeof(ClearValue));
- BackBufferCount = 0;
- memset(&BackBuffer, 0, sizeof(BackBuffer));
- memset(&BackBufferView, 0, sizeof(BackBufferView));
- memset(&Framebuffer, 0, sizeof(Framebuffer));
- FrameIndex = 0;
-}
-
VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space)
{
IM_ASSERT(request_formats != NULL);
@@ -904,7 +923,7 @@
return VK_PRESENT_MODE_FIFO_KHR; // Always available
}
-void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator)
{
IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE);
(void)physical_device;
@@ -912,9 +931,10 @@
// Create Command Buffers
VkResult err;
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i];
{
VkCommandPoolCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
@@ -942,9 +962,9 @@
{
VkSemaphoreCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- err = vkCreateSemaphore(device, &info, allocator, &fd->ImageAcquiredSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->ImageAcquiredSemaphore);
check_vk_result(err);
- err = vkCreateSemaphore(device, &info, allocator, &fd->RenderCompleteSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->RenderCompleteSemaphore);
check_vk_result(err);
}
}
@@ -962,24 +982,26 @@
return 1;
}
-void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h)
+// Also destroy old swap chain and in-flight frames data, if any.
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count)
{
- uint32_t min_image_count = 2; // FIXME: this should become a function parameter
-
VkResult err;
VkSwapchainKHR old_swapchain = wd->Swapchain;
err = vkDeviceWaitIdle(device);
check_vk_result(err);
+ // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one.
// Destroy old Framebuffer
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- if (wd->BackBufferView[i])
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- if (wd->Framebuffer[i])
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- wd->BackBufferCount = 0;
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
+ wd->ImageCount = 0;
if (wd->RenderPass)
vkDestroyRenderPass(device, wd->RenderPass, allocator);
@@ -1023,10 +1045,21 @@
}
err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, NULL);
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, NULL);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, wd->BackBuffer);
+ VkImage backbuffers[16] = {};
+ IM_ASSERT(wd->ImageCount >= min_image_count);
+ IM_ASSERT(wd->ImageCount < IM_ARRAYSIZE(backbuffers));
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers);
check_vk_result(err);
+
+ IM_ASSERT(wd->Frames == NULL);
+ wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount);
+ wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->ImageCount);
+ memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount);
+ memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->ImageCount);
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
+ wd->Frames[i].Backbuffer = backbuffers[i];
}
if (old_swapchain)
vkDestroySwapchainKHR(device, old_swapchain, allocator);
@@ -1080,10 +1113,11 @@
info.components.a = VK_COMPONENT_SWIZZLE_A;
VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
info.subresourceRange = image_range;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- info.image = wd->BackBuffer[i];
- err = vkCreateImageView(device, &info, allocator, &wd->BackBufferView[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ info.image = fd->Backbuffer;
+ err = vkCreateImageView(device, &info, allocator, &fd->BackbufferView);
check_vk_result(err);
}
}
@@ -1099,38 +1133,82 @@
info.width = wd->Width;
info.height = wd->Height;
info.layers = 1;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- attachment[0] = wd->BackBufferView[i];
- err = vkCreateFramebuffer(device, &info, allocator, &wd->Framebuffer[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ attachment[0] = fd->BackbufferView;
+ err = vkCreateFramebuffer(device, &info, allocator, &fd->Framebuffer);
check_vk_result(err);
}
}
}
-void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count)
+{
+ (void)instance;
+ ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count);
+ ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator)
{
vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals)
//vkQueueWaitIdle(g_Queue);
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
- vkDestroyFence(device, fd->Fence, allocator);
- vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
- vkDestroyCommandPool(device, fd->CommandPool, allocator);
- vkDestroySemaphore(device, fd->ImageAcquiredSemaphore, allocator);
- vkDestroySemaphore(device, fd->RenderCompleteSemaphore, allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
- {
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
- }
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
vkDestroyRenderPass(device, wd->RenderPass, allocator);
vkDestroySwapchainKHR(device, wd->Swapchain, allocator);
vkDestroySurfaceKHR(instance, wd->Surface, allocator);
- *wd = ImGui_ImplVulkanH_WindowData();
+
+ *wd = ImGui_ImplVulkanH_Window();
+}
+
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroyFence(device, fd->Fence, allocator);
+ vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
+ vkDestroyCommandPool(device, fd->CommandPool, allocator);
+ fd->Fence = VK_NULL_HANDLE;
+ fd->CommandBuffer = VK_NULL_HANDLE;
+ fd->CommandPool = VK_NULL_HANDLE;
+
+ vkDestroyImageView(device, fd->BackbufferView, allocator);
+ vkDestroyFramebuffer(device, fd->Framebuffer, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator);
+ vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator);
+ fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;
+}
+
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; }
+ if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; }
+ if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; }
+ if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; }
+ buffers->VertexBufferSize = 0;
+ buffers->IndexBufferSize = 0;
+}
+
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ for (uint32_t n = 0; n < buffers->Count; n++)
+ ImGui_ImplVulkanH_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator);
+ IM_FREE(buffers->FrameRenderBuffers);
+ buffers->FrameRenderBuffers = NULL;
+ buffers->Index = 0;
+ buffers->Count = 0;
}
//--------------------------------------------------------------------------------------------------------
diff --git a/examples/imgui_impl_vulkan.h b/examples/imgui_impl_vulkan.h
index ec45dbe..0389af5 100644
--- a/examples/imgui_impl_vulkan.h
+++ b/examples/imgui_impl_vulkan.h
@@ -12,24 +12,32 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
#pragma once
#include
-#define IMGUI_VK_QUEUED_FRAMES 2
-
-// Please zero-clear before use.
+// Initialization data, for ImGui_ImplVulkan_Init()
+// [Please zero-clear before use!]
struct ImGui_ImplVulkan_InitInfo
{
- VkInstance Instance;
- VkPhysicalDevice PhysicalDevice;
- VkDevice Device;
- uint32_t QueueFamily;
- VkQueue Queue;
- VkPipelineCache PipelineCache;
- VkDescriptorPool DescriptorPool;
- const VkAllocationCallbacks* Allocator;
- void (*CheckVkResultFn)(VkResult err);
+ VkInstance Instance;
+ VkPhysicalDevice PhysicalDevice;
+ VkDevice Device;
+ uint32_t QueueFamily;
+ VkQueue Queue;
+ VkPipelineCache PipelineCache;
+ VkDescriptorPool DescriptorPool;
+ uint32_t MinImageCount; // >= 2
+ uint32_t ImageCount; // >= MinImageCount
+ const VkAllocationCallbacks* Allocator;
+ void (*CheckVkResultFn)(VkResult err);
};
// Called by user code
@@ -38,16 +46,13 @@
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
-IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateFontUploadObjects();
-
-// Called by ImGui_ImplVulkan_Init() might be useful elsewhere.
-IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateDeviceObjects();
-IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateDeviceObjects();
+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)
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -55,38 +60,44 @@
// 2) the multi-viewport / platform window implementation needs them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-struct ImGui_ImplVulkanH_FrameData;
-struct ImGui_ImplVulkanH_WindowData;
+struct ImGui_ImplVulkanH_Frame;
+struct ImGui_ImplVulkanH_Window;
-IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
-IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h);
-IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
+// Helpers
+IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wnd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator);
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
// Helper structure to hold the data needed by one rendering frame
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
-struct ImGui_ImplVulkanH_FrameData
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_Frame
{
- uint32_t BackbufferIndex; // Keep track of recently rendered swapchain frame indices
VkCommandPool CommandPool;
VkCommandBuffer CommandBuffer;
VkFence Fence;
+ VkImage Backbuffer;
+ VkImageView BackbufferView;
+ VkFramebuffer Framebuffer;
+};
+
+struct ImGui_ImplVulkanH_FrameSemaphores
+{
VkSemaphore ImageAcquiredSemaphore;
VkSemaphore RenderCompleteSemaphore;
-
- IMGUI_IMPL_API ImGui_ImplVulkanH_FrameData();
};
// Helper structure to hold the data needed by one rendering context into one OS window
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
-struct ImGui_ImplVulkanH_WindowData
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+struct ImGui_ImplVulkanH_Window
{
int Width;
int Height;
@@ -97,13 +108,17 @@
VkRenderPass RenderPass;
bool ClearEnable;
VkClearValue ClearValue;
- uint32_t BackBufferCount;
- VkImage BackBuffer[16];
- VkImageView BackBufferView[16];
- VkFramebuffer Framebuffer[16];
- uint32_t FrameIndex;
- ImGui_ImplVulkanH_FrameData Frames[IMGUI_VK_QUEUED_FRAMES];
+ uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
+ uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
+ uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
+ ImGui_ImplVulkanH_Frame* Frames;
+ ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
- IMGUI_IMPL_API ImGui_ImplVulkanH_WindowData();
+ ImGui_ImplVulkanH_Window()
+ {
+ memset(this, 0, sizeof(*this));
+ PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
+ ClearEnable = true;
+ }
};
diff --git a/imgui.cpp b/imgui.cpp
index c96b2d8..65ea119 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -37,9 +37,14 @@
- Using gamepad/keyboard navigation controls.
- API BREAKING CHANGES (read me when you update!)
- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
+ - Where is the documentation?
+ - Which version should I get?
+ - Who uses Dear ImGui?
+ - Why the odd dual naming, "Dear ImGui" vs "ImGui"?
- How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
- How can I display an image? What is ImTextureID, how does it works?
- - How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.
+ - Why are multiple widgets reacting when I interact with a single one? How can I have
+ multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...
- How can I use my own math types instead of ImVec2/ImVec4?
- How can I load a different font than the default?
- How can I easily use icons in my application?
@@ -563,6 +568,39 @@
FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
======================================
+ Q: Where is the documentation?
+ A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/
+ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments
+ associated to it.
+
+ Q: Which version should I get?
+ A: I occasionally tag Releases (https://github.com/ocornut/imgui/releases) but it is generally safe
+ and recommended to sync to master/latest. The library is fairly stable and regressions tend to be
+ fixed fast when reported. You may also peak at the 'docking' branch which includes:
+ - Docking/Merging features (https://github.com/ocornut/imgui/issues/2109)
+ - Multi-viewport features (https://github.com/ocornut/imgui/issues/1542)
+ Many projects are using this branch and it is kept in sync with master regularly.
+
+ Q: Who uses Dear ImGui?
+ A: See "Quotes" (https://github.com/ocornut/imgui/wiki/Quotes) and
+ "Software using Dear ImGui" (https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages
+ for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+
+ Q: Why the odd dual naming, "Dear ImGui" vs "ImGui"?
+ A: The library started its life as "ImGui" due to the fact that I didn't give it a proper name when
+ when I released 1.0, and had no particular expectation that it would take off. However, the term IMGUI
+ (immediate-mode graphical user interface) was coined before and is being used in variety of other
+ situations (e.g. Unity uses it own implementation of the IMGUI paradigm).
+ To reduce the ambiguity without affecting existing code bases, I have decided on an alternate,
+ longer name "Dear ImGui" that people can use to refer to this specific library.
+ Please try to refer to this library as "Dear ImGui".
+
Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure (e.g. if (ImGui::GetIO().WantCaptureMouse) { ... } )
- When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application.
@@ -664,8 +702,8 @@
Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated.
+ Q: Why are multiple widgets reacting when I interact with a single one?
Q: How can I have multiple widgets with the same label or with an empty label?
- Q: I have multiple widgets with the same label, and only the first one works. Why is that?
A: A primer on labels and the ID Stack...
Dear ImGui internally need to uniquely identify UI elements.
@@ -1344,7 +1382,7 @@
char* ImStrdup(const char* str)
{
size_t len = strlen(str);
- void* buf = ImGui::MemAlloc(len + 1);
+ void* buf = IM_ALLOC(len + 1);
return (char*)memcpy(buf, (const void*)str, len + 1);
}
@@ -1354,8 +1392,8 @@
size_t src_size = strlen(src) + 1;
if (dst_buf_size < src_size)
{
- ImGui::MemFree(dst);
- dst = (char*)ImGui::MemAlloc(src_size);
+ IM_FREE(dst);
+ dst = (char*)IM_ALLOC(src_size);
if (p_dst_size)
*p_dst_size = src_size;
}
@@ -1571,7 +1609,7 @@
}
// Load file content into memory
-// Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
+// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()
void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes)
{
IM_ASSERT(filename && file_open_mode);
@@ -1590,7 +1628,7 @@
}
size_t file_size = (size_t)file_size_signed;
- void* file_data = ImGui::MemAlloc(file_size + padding_bytes);
+ void* file_data = IM_ALLOC(file_size + padding_bytes);
if (file_data == NULL)
{
fclose(f);
@@ -1599,7 +1637,7 @@
if (fread(file_data, 1, file_size, f) != file_size)
{
fclose(f);
- ImGui::MemFree(file_data);
+ IM_FREE(file_data);
return NULL;
}
if (padding_bytes > 0)
@@ -3024,6 +3062,7 @@
return ImMax(wrap_pos_x - pos.x, 1.0f);
}
+// IM_ALLOC() == ImGui::MemAlloc()
void* ImGui::MemAlloc(size_t size)
{
if (ImGuiContext* ctx = GImGui)
@@ -3031,6 +3070,7 @@
return GImAllocatorAllocFunc(size, GImAllocatorUserData);
}
+// IM_FREE() == ImGui::MemFree()
void ImGui::MemFree(void* ptr)
{
if (ptr)
@@ -9790,7 +9830,7 @@
if (!file_data)
return;
LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
- ImGui::MemFree(file_data);
+ IM_FREE(file_data);
}
ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
@@ -9814,7 +9854,7 @@
// For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy..
if (ini_size == 0)
ini_size = strlen(ini_data);
- char* buf = (char*)ImGui::MemAlloc(ini_size + 1);
+ char* buf = (char*)IM_ALLOC(ini_size + 1);
char* buf_end = buf + ini_size;
memcpy(buf, ini_data, ini_size);
buf[ini_size] = 0;
@@ -9861,7 +9901,7 @@
entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
}
}
- ImGui::MemFree(buf);
+ IM_FREE(buf);
g.SettingsLoaded = true;
DockContextOnLoadSettings(&g);
}
diff --git a/imgui.h b/imgui.h
index f990e06..4613625 100644
--- a/imgui.h
+++ b/imgui.h
@@ -13,6 +13,7 @@
// Forward declarations and basic types
// ImGui API (Dear ImGui end-user API)
// Flags & Enumerations
+// Memory allocations macros
// ImVector<>
// ImGuiStyle
// ImGuiIO
@@ -1256,6 +1257,22 @@
};
//-----------------------------------------------------------------------------
+// Helpers: Memory allocations macros
+// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE()
+// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
+// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions.
+//-----------------------------------------------------------------------------
+
+struct ImNewDummy {};
+inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; }
+inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new()
+#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE)
+#define IM_FREE(_PTR) ImGui::MemFree(_PTR)
+#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR)
+#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
+template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }
+
+//-----------------------------------------------------------------------------
// Helper: ImVector<>
// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug).
// You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it.
@@ -1280,7 +1297,7 @@
inline ImVector() { Size = Capacity = 0; Data = NULL; }
inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); }
inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; }
- inline ~ImVector() { if (Data) ImGui::MemFree(Data); }
+ inline ~ImVector() { if (Data) IM_FREE(Data); }
inline bool empty() const { return Size == 0; }
inline int size() const { return Size; }
@@ -1289,7 +1306,7 @@
inline T& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; }
inline const T& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; }
- inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } }
+ inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } }
inline T* begin() { return Data; }
inline const T* begin() const { return Data; }
inline T* end() { return Data + Size; }
@@ -1303,7 +1320,7 @@
inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; }
inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; }
- inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); ImGui::MemFree(Data); } Data = new_data; Capacity = new_capacity; }
+ inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; }
// NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden.
inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; }
@@ -1639,16 +1656,6 @@
// Helpers
//-----------------------------------------------------------------------------
-// Helper: IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() macros to call MemAlloc + Placement New, Placement Delete + MemFree
-// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
-// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions.
-struct ImNewDummy {};
-inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; }
-inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new()
-#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR)
-#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
-template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }
-
// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame.
// Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text("This will be called only once per frame");
struct ImGuiOnceUponAFrame
diff --git a/imgui_draw.cpp b/imgui_draw.cpp
index 7ea5b9f..1ac5220 100644
--- a/imgui_draw.cpp
+++ b/imgui_draw.cpp
@@ -130,8 +130,8 @@
#ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
-#define STBTT_malloc(x,u) ((void)(u), ImGui::MemAlloc(x))
-#define STBTT_free(x,u) ((void)(u), ImGui::MemFree(x))
+#define STBTT_malloc(x,u) ((void)(u), IM_ALLOC(x))
+#define STBTT_free(x,u) ((void)(u), IM_FREE(x))
#define STBTT_assert(x) IM_ASSERT(x)
#define STBTT_fmod(x,y) ImFmod(x,y)
#define STBTT_sqrt(x) ImSqrt(x)
@@ -1465,7 +1465,7 @@
for (int i = 0; i < ConfigData.Size; i++)
if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas)
{
- ImGui::MemFree(ConfigData[i].FontData);
+ IM_FREE(ConfigData[i].FontData);
ConfigData[i].FontData = NULL;
}
@@ -1486,9 +1486,9 @@
{
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
if (TexPixelsAlpha8)
- ImGui::MemFree(TexPixelsAlpha8);
+ IM_FREE(TexPixelsAlpha8);
if (TexPixelsRGBA32)
- ImGui::MemFree(TexPixelsRGBA32);
+ IM_FREE(TexPixelsRGBA32);
TexPixelsAlpha8 = NULL;
TexPixelsRGBA32 = NULL;
}
@@ -1534,7 +1534,7 @@
GetTexDataAsAlpha8(&pixels, NULL, NULL);
if (pixels)
{
- TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)TexWidth * (size_t)TexHeight * 4);
+ TexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4);
const unsigned char* src = pixels;
unsigned int* dst = TexPixelsRGBA32;
for (int n = TexWidth * TexHeight; n > 0; n--)
@@ -1566,7 +1566,7 @@
new_font_cfg.DstFont = Fonts.back();
if (!new_font_cfg.FontDataOwnedByAtlas)
{
- new_font_cfg.FontData = ImGui::MemAlloc(new_font_cfg.FontDataSize);
+ new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize);
new_font_cfg.FontDataOwnedByAtlas = true;
memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);
}
@@ -1651,7 +1651,7 @@
ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
{
const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data);
- unsigned char* buf_decompressed_data = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);
+ unsigned char* buf_decompressed_data = (unsigned char *)IM_ALLOC(buf_decompressed_size);
stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);
ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
@@ -1663,10 +1663,10 @@
ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
{
int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
- void* compressed_ttf = ImGui::MemAlloc((size_t)compressed_ttf_size);
+ void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size);
Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
- ImGui::MemFree(compressed_ttf);
+ IM_FREE(compressed_ttf);
return font;
}
@@ -1966,7 +1966,7 @@
// 7. Allocate texture
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
- atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
+ atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight);
memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
spc.pixels = atlas->TexPixelsAlpha8;
spc.height = atlas->TexHeight;
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 4a485d9..fbd6f7c 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -3571,7 +3571,7 @@
const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0;
const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW;
const int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1;
- char* clipboard_data = (char*)MemAlloc(clipboard_data_len * sizeof(char));
+ char* clipboard_data = (char*)IM_ALLOC(clipboard_data_len * sizeof(char));
ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie);
SetClipboardText(clipboard_data);
MemFree(clipboard_data);
@@ -3590,7 +3590,7 @@
{
// Filter pasted buffer
const int clipboard_len = (int)strlen(clipboard);
- ImWchar* clipboard_filtered = (ImWchar*)MemAlloc((clipboard_len+1) * sizeof(ImWchar));
+ ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len+1) * sizeof(ImWchar));
int clipboard_filtered_len = 0;
for (const char* s = clipboard; *s; )
{
diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp
index 012eae7..4a579ed 100644
--- a/misc/freetype/imgui_freetype.cpp
+++ b/misc/freetype/imgui_freetype.cpp
@@ -398,7 +398,7 @@
const int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024;
int buf_bitmap_current_used_bytes = 0;
ImVector buf_bitmap_buffers;
- buf_bitmap_buffers.push_back((unsigned char*)ImGui::MemAlloc(BITMAP_BUFFERS_CHUNK_SIZE));
+ buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));
// 4. Gather glyphs sizes so we can pack them in our virtual canvas.
// 8. Render/rasterize font characters into the texture
@@ -440,7 +440,7 @@
if (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE)
{
buf_bitmap_current_used_bytes = 0;
- buf_bitmap_buffers.push_back((unsigned char*)ImGui::MemAlloc(BITMAP_BUFFERS_CHUNK_SIZE));
+ buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));
}
// Blit rasterized pixels to our temporary buffer and keep a pointer to it.
@@ -493,7 +493,7 @@
// 7. Allocate texture
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
- atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
+ atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight);
memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
// 8. Copy rasterized font characters back into the main texture
@@ -557,7 +557,7 @@
// Cleanup
for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++)
- ImGui::MemFree(buf_bitmap_buffers[buf_i]);
+ IM_FREE(buf_bitmap_buffers[buf_i]);
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
src_tmp_array[src_i].~ImFontBuildSrcDataFT();
@@ -567,8 +567,8 @@
}
// Default memory allocators
-static void* ImFreeTypeDefaultAllocFunc(size_t size, void* user_data) { IM_UNUSED(user_data); return ImGui::MemAlloc(size); }
-static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { IM_UNUSED(user_data); ImGui::MemFree(ptr); }
+static void* ImFreeTypeDefaultAllocFunc(size_t size, void* user_data) { IM_UNUSED(user_data); return IM_ALLOC(size); }
+static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_FREE(ptr); }
// Current memory allocators
static void* (*GImFreeTypeAllocFunc)(size_t size, void* user_data) = ImFreeTypeDefaultAllocFunc;
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index ad43c68..9bedf3f 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -98,6 +98,11 @@
-----------------------------------------------------------------------
Breaking Changes:
+- Examples: Vulkan: Added MinImageCount/ImageCount fields in ImGui_ImplVulkan_InitInfo, required
+ during initialization to specify the number of in-flight image requested by swap chains.
+ (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam]
+- Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely
+ on them but it is possible you have!).
Other Changes:
- InputText: Fixed selection background starts rendering one frame after the cursor movement
@@ -108,11 +113,15 @@
- GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419)
- GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero.
- Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood]
+- Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert
+ to using the ImGui::MemAlloc()/MemFree() calls directly.
- Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized
GL function loaders early, and help users understand what they are missing. (#2421)
- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop.
+- Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int).
- Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
+- Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam]
- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454)
- Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott]
- Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott]
diff --git a/docs/README.md b/docs/README.md
index febacf0..ba48517 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -219,29 +219,32 @@
**Where is the documentation?**
-- The documentation is at the top of imgui.cpp + effectively imgui.h.
-- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output.
-- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder.
-- We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
-- Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ applications and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+ - We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
**Which version should I get?**
I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
-You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Several projects are using this branch and it is kept in sync with master regularly.
+You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Many projects are using this branch and it is kept in sync with master regularly.
**Who uses Dear ImGui?**
-See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) pages for an (incomplete) list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
**Why the odd dual naming, "Dear ImGui" vs "ImGui"?**
-The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would taker off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library in ambiguous situations. Please try to refer to it as "Dear ImGui".
+The library started its life as "ImGui" due to the fact that I didn't give it a proper name when I released 1.0 and had no particular expectation that it would take off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations (e.g. Unity uses it own implementation of the IMGUI paradigm). To reduce this ambiguity without affecting existing codebases, I have decided on an alternate, longer name "Dear ImGui" that people can use to refer to this specific library. Please try to refer to this library as "Dear ImGui".
**How can I tell whether to dispatch mouse/keyboard to imgui or to my application?**
**How can I display an image? What is ImTextureID, how does it works?**
-
**How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.**
+
**Why are multiple widgets reacting when I interact with a single one? How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...**
**How can I use my own math types instead of ImVec2/ImVec4?**
**How can I load a different font than the default?**
**How can I easily use icons in my application?**
@@ -254,7 +257,7 @@
**I integrated Dear ImGui in my engine and some elements are disappearing when I move windows around..**
**How can I help?**
-See the FAQ in imgui.cpp for answers.
+See the FAQ in [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) for answers.
**Can you create elaborate/serious tools with Dear ImGui?**
diff --git a/docs/issue_template.md b/docs/issue_template.md
index 6d88b27..21f0c1a 100644
--- a/docs/issue_template.md
+++ b/docs/issue_template.md
@@ -4,11 +4,11 @@
https://github.com/ocornut/imgui/issues/2261
2. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/LOADING FONTS, please post on the "Getting Started" Discourse forum:
-https://discourse.dearimgui.org/c/getting-started
+https://discourse.dearimgui.org
-3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
+3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
-4. Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users, unless they browse the site.
+4. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.
5. Delete points 1-5 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue.
diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp
index 6f2c4cd..c1548ff 100644
--- a/examples/example_glfw_vulkan/main.cpp
+++ b/examples/example_glfw_vulkan/main.cpp
@@ -1,6 +1,13 @@
// 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"
@@ -23,19 +30,21 @@
#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 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_WindowData g_WindowData;
-static bool g_ResizeWanted = false;
-static int g_ResizeWidth = 0, g_ResizeHeight = 0;
+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)
{
@@ -107,6 +116,7 @@
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);
@@ -183,7 +193,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -211,14 +223,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -231,15 +241,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -260,7 +276,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -283,7 +299,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -292,18 +308,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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)
@@ -313,14 +330,14 @@
static void glfw_resize_callback(GLFWwindow*, int w, int h)
{
- g_ResizeWanted = true;
- g_ResizeWidth = w;
- g_ResizeHeight = h;
+ g_SwapChainRebuild = true;
+ g_SwapChainResizeWidth = w;
+ g_SwapChainResizeHeight = h;
}
int main(int, char**)
{
- // Setup window
+ // Setup GLFW window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
return 1;
@@ -347,8 +364,8 @@
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glfwSetFramebufferSizeCallback(window, glfw_resize_callback);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
@@ -384,6 +401,8 @@
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);
@@ -429,7 +448,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -445,10 +464,13 @@
// - 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();
- if (g_ResizeWanted)
+
+ if (g_SwapChainRebuild)
{
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, g_ResizeWidth, g_ResizeHeight);
- g_ResizeWanted = false;
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -514,6 +536,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
glfwDestroyWindow(window);
diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp
index 42ab4a6..077a825 100644
--- a/examples/example_sdl_vulkan/main.cpp
+++ b/examples/example_sdl_vulkan/main.cpp
@@ -1,6 +1,13 @@
// dear imgui: standalone example application for SDL2 + 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_sdl.h"
#include "imgui_impl_vulkan.h"
@@ -15,17 +22,21 @@
#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 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_WindowData g_WindowData;
+static ImGui_ImplVulkanH_Window g_MainWindowData;
+static uint32_t 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)
{
@@ -97,6 +108,7 @@
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);
@@ -173,7 +185,9 @@
}
}
-static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR surface, int width, int height)
+// 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;
@@ -201,14 +215,12 @@
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
- ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(g_PhysicalDevice, g_Device, g_QueueFamily, wd, g_Allocator);
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, width, height);
+ IM_ASSERT(g_MinImageCount >= 2);
+ ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
}
static void CleanupVulkan()
{
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- ImGui_ImplVulkanH_DestroyWindowData(g_Instance, g_Device, wd, g_Allocator);
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
@@ -221,15 +233,21 @@
vkDestroyInstance(g_Instance, g_Allocator);
}
-static void FrameRender(ImGui_ImplVulkanH_WindowData* wd)
+static void CleanupVulkanWindow()
+{
+ ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
+}
+
+static void FrameRender(ImGui_ImplVulkanH_Window* wd)
{
VkResult err;
- VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore;
+ 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_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ 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);
@@ -250,7 +268,7 @@
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
- info.framebuffer = wd->Framebuffer[wd->FrameIndex];
+ info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
@@ -273,7 +291,7 @@
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
- info.pSignalSemaphores = &fd->RenderCompleteSemaphore;
+ info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
@@ -282,18 +300,19 @@
}
}
-static void FramePresent(ImGui_ImplVulkanH_WindowData* wd)
+static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[wd->FrameIndex];
+ VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
- info.pWaitSemaphores = &fd->RenderCompleteSemaphore;
+ 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
}
int main(int, char**)
@@ -331,8 +350,8 @@
// Create Framebuffers
int w, h;
SDL_GetWindowSize(window, &w, &h);
- ImGui_ImplVulkanH_WindowData* wd = &g_WindowData;
- SetupVulkanWindowData(wd, surface, w, h);
+ ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
+ SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
ImGui::CreateContext();
@@ -366,6 +385,8 @@
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);
@@ -411,7 +432,7 @@
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
}
bool show_demo_window = true;
@@ -434,7 +455,19 @@
if (event.type == SDL_QUIT)
done = true;
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED && event.window.windowID == SDL_GetWindowID(window))
- ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, (int)event.window.data1, (int)event.window.data2);
+ {
+ g_SwapChainResizeWidth = (int)event.window.data1;
+ g_SwapChainResizeHeight = (int)event.window.data2;
+ g_SwapChainRebuild = true;
+ }
+ }
+
+ if (g_SwapChainRebuild)
+ {
+ g_SwapChainRebuild = false;
+ ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
+ ImGui_ImplVulkanH_CreateWindow(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
@@ -500,6 +533,8 @@
ImGui_ImplVulkan_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
+
+ CleanupVulkanWindow();
CleanupVulkan();
SDL_DestroyWindow(window);
diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp
index 5911878..39ec861 100644
--- a/examples/imgui_impl_vulkan.cpp
+++ b/examples/imgui_impl_vulkan.cpp
@@ -12,8 +12,17 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2019-XX-XX: *BREAKING CHANGE*: Vulkan: Added ImageCount/MinImageCount fields in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetMinImageCount().
+// 2019-XX-XX: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper.
// 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
// 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int).
// 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display.
@@ -35,46 +44,61 @@
#include "imgui_impl_vulkan.h"
#include
-// Vulkan data
-static const VkAllocationCallbacks* g_Allocator = NULL;
-static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE;
-static VkInstance g_Instance = 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 VkPipelineCache g_PipelineCache = VK_NULL_HANDLE;
-static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
-static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
-static void (*g_CheckVkResultFn)(VkResult err) = NULL;
-
-static VkDeviceSize g_BufferMemoryAlignment = 256;
-static VkPipelineCreateFlags g_PipelineCreateFlags = 0;
-
-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;
-
-// Frame data
-struct FrameDataForRender
+// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_FrameRenderBuffers
{
- VkDeviceMemory VertexBufferMemory;
- VkDeviceMemory IndexBufferMemory;
- VkDeviceSize VertexBufferSize;
- VkDeviceSize IndexBufferSize;
- VkBuffer VertexBuffer;
- VkBuffer IndexBuffer;
+ VkDeviceMemory VertexBufferMemory;
+ VkDeviceMemory IndexBufferMemory;
+ VkDeviceSize VertexBufferSize;
+ VkDeviceSize IndexBufferSize;
+ VkBuffer VertexBuffer;
+ VkBuffer IndexBuffer;
};
-static int g_FrameIndex = 0;
-static FrameDataForRender g_FramesDataBuffers[IMGUI_VK_QUEUED_FRAMES] = {};
+
+// Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_WindowRenderBuffers
+{
+ uint32_t Index;
+ uint32_t Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* FrameRenderBuffers;
+};
+
+// Vulkan data
+static ImGui_ImplVulkan_InitInfo g_VulkanInitInfo = {};
+static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
+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
-static VkSampler g_FontSampler = VK_NULL_HANDLE;
-static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
-static VkImage g_FontImage = VK_NULL_HANDLE;
-static VkImageView g_FontView = VK_NULL_HANDLE;
-static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
-static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+static VkSampler g_FontSampler = VK_NULL_HANDLE;
+static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
+static VkImage g_FontImage = VK_NULL_HANDLE;
+static VkImageView g_FontView = VK_NULL_HANDLE;
+static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
+static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+
+// Render buffers
+static ImGui_ImplVulkanH_WindowRenderBuffers g_MainWindowRenderBuffers;
+
+// Forward Declarations
+bool ImGui_ImplVulkan_CreateDeviceObjects();
+void ImGui_ImplVulkan_DestroyDeviceObjects();
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
+
+//-----------------------------------------------------------------------------
+// SHADERS
+//-----------------------------------------------------------------------------
// Forward Declarations
static void ImGui_ImplVulkan_InitPlatformInterface();
@@ -185,10 +209,15 @@
0x00010038
};
+//-----------------------------------------------------------------------------
+// FUNCTIONS
+//-----------------------------------------------------------------------------
+
static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkPhysicalDeviceMemoryProperties prop;
- vkGetPhysicalDeviceMemoryProperties(g_PhysicalDevice, &prop);
+ vkGetPhysicalDeviceMemoryProperties(v->PhysicalDevice, &prop);
for (uint32_t i = 0; i < prop.memoryTypeCount; i++)
if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<CheckVkResultFn)
+ v->CheckVkResultFn(err);
}
static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
if (buffer != VK_NULL_HANDLE)
- vkDestroyBuffer(g_Device, buffer, g_Allocator);
- if (buffer_memory)
- vkFreeMemory(g_Device, buffer_memory, g_Allocator);
+ vkDestroyBuffer(v->Device, buffer, v->Allocator);
+ if (buffer_memory != VK_NULL_HANDLE)
+ vkFreeMemory(v->Device, buffer_memory, v->Allocator);
VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / g_BufferMemoryAlignment + 1) * g_BufferMemoryAlignment;
VkBufferCreateInfo buffer_info = {};
@@ -215,20 +246,20 @@
buffer_info.size = vertex_buffer_size_aligned;
buffer_info.usage = usage;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &buffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &buffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, buffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, buffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &buffer_memory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &buffer_memory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, buffer, buffer_memory, 0);
+ err = vkBindBufferMemory(v->Device, buffer, buffer_memory, 0);
check_vk_result(err);
p_buffer_size = new_size;
}
@@ -243,25 +274,38 @@
if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount == 0)
return;
- VkResult err;
- FrameDataForRender* fd = &g_FramesDataBuffers[g_FrameIndex];
- g_FrameIndex = (g_FrameIndex + 1) % IM_ARRAYSIZE(g_FramesDataBuffers);
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
- // Create the Vertex and Index buffers:
+ // Allocate array to store enough vertex/index buffers
+ ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &g_MainWindowRenderBuffers;
+ if (wrb->FrameRenderBuffers == NULL)
+ {
+ wrb->Index = 0;
+ wrb->Count = v->ImageCount;
+ wrb->FrameRenderBuffers = (ImGui_ImplVulkanH_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ }
+ IM_ASSERT(wrb->Count == v->ImageCount);
+ wrb->Index = (wrb->Index + 1) % wrb->Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index];
+
+ VkResult err;
+
+ // Create or resize the vertex/index buffers
size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);
size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx);
- if (fd->VertexBuffer == VK_NULL_HANDLE || fd->VertexBufferSize < vertex_size)
- CreateOrResizeBuffer(fd->VertexBuffer, fd->VertexBufferMemory, fd->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
- if (fd->IndexBuffer == VK_NULL_HANDLE || fd->IndexBufferSize < index_size)
- CreateOrResizeBuffer(fd->IndexBuffer, fd->IndexBufferMemory, fd->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
+ if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size)
+ CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+ if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size)
+ CreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
// Upload vertex/index data into a single contiguous GPU buffer
{
ImDrawVert* vtx_dst = NULL;
ImDrawIdx* idx_dst = NULL;
- err = vkMapMemory(g_Device, fd->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
+ err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
check_vk_result(err);
- err = vkMapMemory(g_Device, fd->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
+ err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
check_vk_result(err);
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
@@ -273,15 +317,15 @@
}
VkMappedMemoryRange range[2] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[0].memory = fd->VertexBufferMemory;
+ range[0].memory = rb->VertexBufferMemory;
range[0].size = VK_WHOLE_SIZE;
range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
- range[1].memory = fd->IndexBufferMemory;
+ range[1].memory = rb->IndexBufferMemory;
range[1].size = VK_WHOLE_SIZE;
- err = vkFlushMappedMemoryRanges(g_Device, 2, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 2, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, fd->VertexBufferMemory);
- vkUnmapMemory(g_Device, fd->IndexBufferMemory);
+ vkUnmapMemory(v->Device, rb->VertexBufferMemory);
+ vkUnmapMemory(v->Device, rb->IndexBufferMemory);
}
// Bind pipeline and descriptor sets:
@@ -293,10 +337,10 @@
// Bind Vertex And Index Buffer:
{
- VkBuffer vertex_buffers[1] = { fd->VertexBuffer };
+ VkBuffer vertex_buffers[1] = { rb->VertexBuffer };
VkDeviceSize vertex_offset[1] = { 0 };
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset);
- vkCmdBindIndexBuffer(command_buffer, fd->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
+ vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
}
// Setup viewport:
@@ -379,6 +423,7 @@
bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
@@ -404,17 +449,17 @@
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- err = vkCreateImage(g_Device, &info, g_Allocator, &g_FontImage);
+ err = vkCreateImage(v->Device, &info, v->Allocator, &g_FontImage);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetImageMemoryRequirements(g_Device, g_FontImage, &req);
+ vkGetImageMemoryRequirements(v->Device, g_FontImage, &req);
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_FontMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_FontMemory);
check_vk_result(err);
- err = vkBindImageMemory(g_Device, g_FontImage, g_FontMemory, 0);
+ err = vkBindImageMemory(v->Device, g_FontImage, g_FontMemory, 0);
check_vk_result(err);
}
@@ -428,7 +473,7 @@
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.levelCount = 1;
info.subresourceRange.layerCount = 1;
- err = vkCreateImageView(g_Device, &info, g_Allocator, &g_FontView);
+ err = vkCreateImageView(v->Device, &info, v->Allocator, &g_FontView);
check_vk_result(err);
}
@@ -444,7 +489,7 @@
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
- vkUpdateDescriptorSets(g_Device, 1, write_desc, 0, NULL);
+ vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
// Create the Upload Buffer:
@@ -454,34 +499,34 @@
buffer_info.size = upload_size;
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_UploadBuffer);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &g_UploadBuffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(g_Device, g_UploadBuffer, &req);
+ vkGetBufferMemoryRequirements(v->Device, g_UploadBuffer, &req);
g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
- err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_UploadBufferMemory);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_UploadBufferMemory);
check_vk_result(err);
- err = vkBindBufferMemory(g_Device, g_UploadBuffer, g_UploadBufferMemory, 0);
+ err = vkBindBufferMemory(v->Device, g_UploadBuffer, g_UploadBufferMemory, 0);
check_vk_result(err);
}
// Upload to Buffer:
{
char* map = NULL;
- err = vkMapMemory(g_Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
+ err = vkMapMemory(v->Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
check_vk_result(err);
memcpy(map, pixels, upload_size);
VkMappedMemoryRange range[1] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[0].memory = g_UploadBufferMemory;
range[0].size = upload_size;
- err = vkFlushMappedMemoryRanges(g_Device, 1, range);
+ err = vkFlushMappedMemoryRanges(v->Device, 1, range);
check_vk_result(err);
- vkUnmapMemory(g_Device, g_UploadBufferMemory);
+ vkUnmapMemory(v->Device, g_UploadBufferMemory);
}
// Copy to Image:
@@ -530,6 +575,7 @@
bool ImGui_ImplVulkan_CreateDeviceObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err;
VkShaderModule vert_module;
VkShaderModule frag_module;
@@ -540,13 +586,13 @@
vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
vert_info.codeSize = sizeof(__glsl_shader_vert_spv);
vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv;
- err = vkCreateShaderModule(g_Device, &vert_info, g_Allocator, &vert_module);
+ err = vkCreateShaderModule(v->Device, &vert_info, v->Allocator, &vert_module);
check_vk_result(err);
VkShaderModuleCreateInfo frag_info = {};
frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
frag_info.codeSize = sizeof(__glsl_shader_frag_spv);
frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv;
- err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module);
+ err = vkCreateShaderModule(v->Device, &frag_info, v->Allocator, &frag_module);
check_vk_result(err);
}
@@ -563,7 +609,7 @@
info.minLod = -1000;
info.maxLod = 1000;
info.maxAnisotropy = 1.0f;
- err = vkCreateSampler(g_Device, &info, g_Allocator, &g_FontSampler);
+ err = vkCreateSampler(v->Device, &info, v->Allocator, &g_FontSampler);
check_vk_result(err);
}
@@ -579,7 +625,7 @@
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
info.bindingCount = 1;
info.pBindings = binding;
- err = vkCreateDescriptorSetLayout(g_Device, &info, g_Allocator, &g_DescriptorSetLayout);
+ err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &g_DescriptorSetLayout);
check_vk_result(err);
}
@@ -587,10 +633,10 @@
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- alloc_info.descriptorPool = g_DescriptorPool;
+ alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &g_DescriptorSetLayout;
- err = vkAllocateDescriptorSets(g_Device, &alloc_info, &g_DescriptorSet);
+ err = vkAllocateDescriptorSets(v->Device, &alloc_info, &g_DescriptorSet);
check_vk_result(err);
}
@@ -608,7 +654,7 @@
layout_info.pSetLayouts = set_layout;
layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = push_constants;
- err = vkCreatePipelineLayout(g_Device, &layout_info, g_Allocator, &g_PipelineLayout);
+ err = vkCreatePipelineLayout(v->Device, &layout_info, v->Allocator, &g_PipelineLayout);
check_vk_result(err);
}
@@ -706,49 +752,43 @@
info.pDynamicState = &dynamic_state;
info.layout = g_PipelineLayout;
info.renderPass = g_RenderPass;
- err = vkCreateGraphicsPipelines(g_Device, g_PipelineCache, 1, &info, g_Allocator, &g_Pipeline);
+ err = vkCreateGraphicsPipelines(v->Device, v->PipelineCache, 1, &info, v->Allocator, &g_Pipeline);
check_vk_result(err);
- vkDestroyShaderModule(g_Device, vert_module, g_Allocator);
- vkDestroyShaderModule(g_Device, frag_module, g_Allocator);
+ vkDestroyShaderModule(v->Device, vert_module, v->Allocator);
+ vkDestroyShaderModule(v->Device, frag_module, v->Allocator);
return true;
}
-void ImGui_ImplVulkan_InvalidateFontUploadObjects()
+void ImGui_ImplVulkan_DestroyFontUploadObjects()
{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
if (g_UploadBuffer)
{
- vkDestroyBuffer(g_Device, g_UploadBuffer, g_Allocator);
+ vkDestroyBuffer(v->Device, g_UploadBuffer, v->Allocator);
g_UploadBuffer = VK_NULL_HANDLE;
}
if (g_UploadBufferMemory)
{
- vkFreeMemory(g_Device, g_UploadBufferMemory, g_Allocator);
+ vkFreeMemory(v->Device, g_UploadBufferMemory, v->Allocator);
g_UploadBufferMemory = VK_NULL_HANDLE;
}
}
-void ImGui_ImplVulkan_InvalidateDeviceObjects()
+void ImGui_ImplVulkan_DestroyDeviceObjects()
{
- ImGui_ImplVulkan_InvalidateFontUploadObjects();
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
- for (int i = 0; i < IM_ARRAYSIZE(g_FramesDataBuffers); i++)
- {
- FrameDataForRender* fd = &g_FramesDataBuffers[i];
- if (fd->VertexBuffer) { vkDestroyBuffer (g_Device, fd->VertexBuffer, g_Allocator); fd->VertexBuffer = VK_NULL_HANDLE; }
- if (fd->VertexBufferMemory) { vkFreeMemory (g_Device, fd->VertexBufferMemory, g_Allocator); fd->VertexBufferMemory = VK_NULL_HANDLE; }
- if (fd->IndexBuffer) { vkDestroyBuffer (g_Device, fd->IndexBuffer, g_Allocator); fd->IndexBuffer = VK_NULL_HANDLE; }
- if (fd->IndexBufferMemory) { vkFreeMemory (g_Device, fd->IndexBufferMemory, g_Allocator); fd->IndexBufferMemory = VK_NULL_HANDLE; }
- }
-
- if (g_FontView) { vkDestroyImageView(g_Device, g_FontView, g_Allocator); g_FontView = VK_NULL_HANDLE; }
- if (g_FontImage) { vkDestroyImage(g_Device, g_FontImage, g_Allocator); g_FontImage = VK_NULL_HANDLE; }
- if (g_FontMemory) { vkFreeMemory(g_Device, g_FontMemory, g_Allocator); g_FontMemory = VK_NULL_HANDLE; }
- if (g_FontSampler) { vkDestroySampler(g_Device, g_FontSampler, g_Allocator); g_FontSampler = VK_NULL_HANDLE; }
- if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(g_Device, g_DescriptorSetLayout, g_Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
- if (g_PipelineLayout) { vkDestroyPipelineLayout(g_Device, g_PipelineLayout, g_Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
- if (g_Pipeline) { vkDestroyPipeline(g_Device, g_Pipeline, g_Allocator); g_Pipeline = VK_NULL_HANDLE; }
+ if (g_FontView) { vkDestroyImageView(v->Device, g_FontView, v->Allocator); g_FontView = VK_NULL_HANDLE; }
+ if (g_FontImage) { vkDestroyImage(v->Device, g_FontImage, v->Allocator); g_FontImage = VK_NULL_HANDLE; }
+ if (g_FontMemory) { vkFreeMemory(v->Device, g_FontMemory, v->Allocator); g_FontMemory = VK_NULL_HANDLE; }
+ if (g_FontSampler) { vkDestroySampler(v->Device, g_FontSampler, v->Allocator); g_FontSampler = VK_NULL_HANDLE; }
+ if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, g_DescriptorSetLayout, v->Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
+ if (g_PipelineLayout) { vkDestroyPipelineLayout(v->Device, g_PipelineLayout, v->Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
+ if (g_Pipeline) { vkDestroyPipeline(v->Device, g_Pipeline, v->Allocator); g_Pipeline = VK_NULL_HANDLE; }
}
bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass)
@@ -763,19 +803,12 @@
IM_ASSERT(info->Device != VK_NULL_HANDLE);
IM_ASSERT(info->Queue != VK_NULL_HANDLE);
IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE);
+ IM_ASSERT(info->MinImageCount >= 2);
+ IM_ASSERT(info->ImageCount >= info->MinImageCount);
IM_ASSERT(render_pass != VK_NULL_HANDLE);
- g_Instance = info->Instance;
- g_PhysicalDevice = info->PhysicalDevice;
- g_Device = info->Device;
- g_QueueFamily = info->QueueFamily;
- g_Queue = info->Queue;
+ g_VulkanInitInfo = *info;
g_RenderPass = render_pass;
- g_PipelineCache = info->PipelineCache;
- g_DescriptorPool = info->DescriptorPool;
- g_Allocator = info->Allocator;
- g_CheckVkResultFn = info->CheckVkResultFn;
-
ImGui_ImplVulkan_CreateDeviceObjects();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
@@ -787,16 +820,30 @@
void ImGui_ImplVulkan_Shutdown()
{
ImGui_ImplVulkan_ShutdownPlatformInterface();
- ImGui_ImplVulkan_InvalidateDeviceObjects();
+ ImGui_ImplVulkan_DestroyDeviceObjects();
}
void ImGui_ImplVulkan_NewFrame()
{
}
+void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
+{
+ IM_ASSERT(min_image_count >= 2);
+ if (g_VulkanInitInfo.MinImageCount == min_image_count)
+ return;
+
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ VkResult err = vkDeviceWaitIdle(v->Device);
+ check_vk_result(err);
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ g_VulkanInitInfo.MinImageCount = min_image_count;
+}
+
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -804,40 +851,12 @@
// 2) the upcoming multi-viewport feature will need them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-#include // malloc
-
-ImGui_ImplVulkanH_FrameData::ImGui_ImplVulkanH_FrameData()
-{
- BackbufferIndex = 0;
- CommandPool = VK_NULL_HANDLE;
- CommandBuffer = VK_NULL_HANDLE;
- Fence = VK_NULL_HANDLE;
- ImageAcquiredSemaphore = VK_NULL_HANDLE;
- RenderCompleteSemaphore = VK_NULL_HANDLE;
-}
-
-ImGui_ImplVulkanH_WindowData::ImGui_ImplVulkanH_WindowData()
-{
- Width = Height = 0;
- Swapchain = VK_NULL_HANDLE;
- Surface = VK_NULL_HANDLE;
- memset(&SurfaceFormat, 0, sizeof(SurfaceFormat));
- PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
- RenderPass = VK_NULL_HANDLE;
- ClearEnable = true;
- memset(&ClearValue, 0, sizeof(ClearValue));
- BackBufferCount = 0;
- memset(&BackBuffer, 0, sizeof(BackBuffer));
- memset(&BackBufferView, 0, sizeof(BackBufferView));
- memset(&Framebuffer, 0, sizeof(Framebuffer));
- FrameIndex = 0;
-}
-
VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space)
{
IM_ASSERT(request_formats != NULL);
@@ -904,7 +923,7 @@
return VK_PRESENT_MODE_FIFO_KHR; // Always available
}
-void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator)
{
IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE);
(void)physical_device;
@@ -912,9 +931,10 @@
// Create Command Buffers
VkResult err;
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i];
{
VkCommandPoolCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
@@ -942,9 +962,9 @@
{
VkSemaphoreCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- err = vkCreateSemaphore(device, &info, allocator, &fd->ImageAcquiredSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->ImageAcquiredSemaphore);
check_vk_result(err);
- err = vkCreateSemaphore(device, &info, allocator, &fd->RenderCompleteSemaphore);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->RenderCompleteSemaphore);
check_vk_result(err);
}
}
@@ -962,24 +982,26 @@
return 1;
}
-void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h)
+// Also destroy old swap chain and in-flight frames data, if any.
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count)
{
- uint32_t min_image_count = 2; // FIXME: this should become a function parameter
-
VkResult err;
VkSwapchainKHR old_swapchain = wd->Swapchain;
err = vkDeviceWaitIdle(device);
check_vk_result(err);
+ // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one.
// Destroy old Framebuffer
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- if (wd->BackBufferView[i])
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- if (wd->Framebuffer[i])
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- wd->BackBufferCount = 0;
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
+ wd->ImageCount = 0;
if (wd->RenderPass)
vkDestroyRenderPass(device, wd->RenderPass, allocator);
@@ -1023,10 +1045,21 @@
}
err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, NULL);
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, NULL);
check_vk_result(err);
- err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->BackBufferCount, wd->BackBuffer);
+ VkImage backbuffers[16] = {};
+ IM_ASSERT(wd->ImageCount >= min_image_count);
+ IM_ASSERT(wd->ImageCount < IM_ARRAYSIZE(backbuffers));
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers);
check_vk_result(err);
+
+ IM_ASSERT(wd->Frames == NULL);
+ wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount);
+ wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->ImageCount);
+ memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount);
+ memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->ImageCount);
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
+ wd->Frames[i].Backbuffer = backbuffers[i];
}
if (old_swapchain)
vkDestroySwapchainKHR(device, old_swapchain, allocator);
@@ -1080,10 +1113,11 @@
info.components.a = VK_COMPONENT_SWIZZLE_A;
VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
info.subresourceRange = image_range;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- info.image = wd->BackBuffer[i];
- err = vkCreateImageView(device, &info, allocator, &wd->BackBufferView[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ info.image = fd->Backbuffer;
+ err = vkCreateImageView(device, &info, allocator, &fd->BackbufferView);
check_vk_result(err);
}
}
@@ -1099,38 +1133,82 @@
info.width = wd->Width;
info.height = wd->Height;
info.layers = 1;
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- attachment[0] = wd->BackBufferView[i];
- err = vkCreateFramebuffer(device, &info, allocator, &wd->Framebuffer[i]);
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ attachment[0] = fd->BackbufferView;
+ err = vkCreateFramebuffer(device, &info, allocator, &fd->Framebuffer);
check_vk_result(err);
}
}
}
-void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator)
+void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count)
+{
+ (void)instance;
+ ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count);
+ ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator)
{
vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals)
//vkQueueWaitIdle(g_Queue);
- for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++)
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
{
- ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i];
- vkDestroyFence(device, fd->Fence, allocator);
- vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
- vkDestroyCommandPool(device, fd->CommandPool, allocator);
- vkDestroySemaphore(device, fd->ImageAcquiredSemaphore, allocator);
- vkDestroySemaphore(device, fd->RenderCompleteSemaphore, allocator);
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
}
- for (uint32_t i = 0; i < wd->BackBufferCount; i++)
- {
- vkDestroyImageView(device, wd->BackBufferView[i], allocator);
- vkDestroyFramebuffer(device, wd->Framebuffer[i], allocator);
- }
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
vkDestroyRenderPass(device, wd->RenderPass, allocator);
vkDestroySwapchainKHR(device, wd->Swapchain, allocator);
vkDestroySurfaceKHR(instance, wd->Surface, allocator);
- *wd = ImGui_ImplVulkanH_WindowData();
+
+ *wd = ImGui_ImplVulkanH_Window();
+}
+
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroyFence(device, fd->Fence, allocator);
+ vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
+ vkDestroyCommandPool(device, fd->CommandPool, allocator);
+ fd->Fence = VK_NULL_HANDLE;
+ fd->CommandBuffer = VK_NULL_HANDLE;
+ fd->CommandPool = VK_NULL_HANDLE;
+
+ vkDestroyImageView(device, fd->BackbufferView, allocator);
+ vkDestroyFramebuffer(device, fd->Framebuffer, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator);
+ vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator);
+ fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;
+}
+
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; }
+ if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; }
+ if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; }
+ if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; }
+ buffers->VertexBufferSize = 0;
+ buffers->IndexBufferSize = 0;
+}
+
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ for (uint32_t n = 0; n < buffers->Count; n++)
+ ImGui_ImplVulkanH_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator);
+ IM_FREE(buffers->FrameRenderBuffers);
+ buffers->FrameRenderBuffers = NULL;
+ buffers->Index = 0;
+ buffers->Count = 0;
}
//--------------------------------------------------------------------------------------------------------
diff --git a/examples/imgui_impl_vulkan.h b/examples/imgui_impl_vulkan.h
index ec45dbe..0389af5 100644
--- a/examples/imgui_impl_vulkan.h
+++ b/examples/imgui_impl_vulkan.h
@@ -12,24 +12,32 @@
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+// 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.
+
#pragma once
#include
-#define IMGUI_VK_QUEUED_FRAMES 2
-
-// Please zero-clear before use.
+// Initialization data, for ImGui_ImplVulkan_Init()
+// [Please zero-clear before use!]
struct ImGui_ImplVulkan_InitInfo
{
- VkInstance Instance;
- VkPhysicalDevice PhysicalDevice;
- VkDevice Device;
- uint32_t QueueFamily;
- VkQueue Queue;
- VkPipelineCache PipelineCache;
- VkDescriptorPool DescriptorPool;
- const VkAllocationCallbacks* Allocator;
- void (*CheckVkResultFn)(VkResult err);
+ VkInstance Instance;
+ VkPhysicalDevice PhysicalDevice;
+ VkDevice Device;
+ uint32_t QueueFamily;
+ VkQueue Queue;
+ VkPipelineCache PipelineCache;
+ VkDescriptorPool DescriptorPool;
+ uint32_t MinImageCount; // >= 2
+ uint32_t ImageCount; // >= MinImageCount
+ const VkAllocationCallbacks* Allocator;
+ void (*CheckVkResultFn)(VkResult err);
};
// Called by user code
@@ -38,16 +46,13 @@
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
-IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateFontUploadObjects();
-
-// Called by ImGui_ImplVulkan_Init() might be useful elsewhere.
-IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateDeviceObjects();
-IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateDeviceObjects();
+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)
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
@@ -55,38 +60,44 @@
// 2) the multi-viewport / platform window implementation needs them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
-// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
-// (those functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
-struct ImGui_ImplVulkanH_FrameData;
-struct ImGui_ImplVulkanH_WindowData;
+struct ImGui_ImplVulkanH_Frame;
+struct ImGui_ImplVulkanH_Window;
-IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, uint32_t queue_family, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
-IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h);
-IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator);
+// Helpers
+IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wnd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator);
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
// Helper structure to hold the data needed by one rendering frame
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
-struct ImGui_ImplVulkanH_FrameData
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_Frame
{
- uint32_t BackbufferIndex; // Keep track of recently rendered swapchain frame indices
VkCommandPool CommandPool;
VkCommandBuffer CommandBuffer;
VkFence Fence;
+ VkImage Backbuffer;
+ VkImageView BackbufferView;
+ VkFramebuffer Framebuffer;
+};
+
+struct ImGui_ImplVulkanH_FrameSemaphores
+{
VkSemaphore ImageAcquiredSemaphore;
VkSemaphore RenderCompleteSemaphore;
-
- IMGUI_IMPL_API ImGui_ImplVulkanH_FrameData();
};
// Helper structure to hold the data needed by one rendering context into one OS window
-// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.)
-struct ImGui_ImplVulkanH_WindowData
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+struct ImGui_ImplVulkanH_Window
{
int Width;
int Height;
@@ -97,13 +108,17 @@
VkRenderPass RenderPass;
bool ClearEnable;
VkClearValue ClearValue;
- uint32_t BackBufferCount;
- VkImage BackBuffer[16];
- VkImageView BackBufferView[16];
- VkFramebuffer Framebuffer[16];
- uint32_t FrameIndex;
- ImGui_ImplVulkanH_FrameData Frames[IMGUI_VK_QUEUED_FRAMES];
+ uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
+ uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
+ uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
+ ImGui_ImplVulkanH_Frame* Frames;
+ ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
- IMGUI_IMPL_API ImGui_ImplVulkanH_WindowData();
+ ImGui_ImplVulkanH_Window()
+ {
+ memset(this, 0, sizeof(*this));
+ PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
+ ClearEnable = true;
+ }
};
diff --git a/imgui.cpp b/imgui.cpp
index c96b2d8..65ea119 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -37,9 +37,14 @@
- Using gamepad/keyboard navigation controls.
- API BREAKING CHANGES (read me when you update!)
- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
+ - Where is the documentation?
+ - Which version should I get?
+ - Who uses Dear ImGui?
+ - Why the odd dual naming, "Dear ImGui" vs "ImGui"?
- How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
- How can I display an image? What is ImTextureID, how does it works?
- - How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.
+ - Why are multiple widgets reacting when I interact with a single one? How can I have
+ multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...
- How can I use my own math types instead of ImVec2/ImVec4?
- How can I load a different font than the default?
- How can I easily use icons in my application?
@@ -563,6 +568,39 @@
FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
======================================
+ Q: Where is the documentation?
+ A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
+ - Run the examples/ and explore them.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/
+ folder to explain how to integrate Dear ImGui with your own engine/application.
+ - Your programming IDE is your friend, find the type or function declaration to find comments
+ associated to it.
+
+ Q: Which version should I get?
+ A: I occasionally tag Releases (https://github.com/ocornut/imgui/releases) but it is generally safe
+ and recommended to sync to master/latest. The library is fairly stable and regressions tend to be
+ fixed fast when reported. You may also peak at the 'docking' branch which includes:
+ - Docking/Merging features (https://github.com/ocornut/imgui/issues/2109)
+ - Multi-viewport features (https://github.com/ocornut/imgui/issues/1542)
+ Many projects are using this branch and it is kept in sync with master regularly.
+
+ Q: Who uses Dear ImGui?
+ A: See "Quotes" (https://github.com/ocornut/imgui/wiki/Quotes) and
+ "Software using Dear ImGui" (https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages
+ for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
+
+ Q: Why the odd dual naming, "Dear ImGui" vs "ImGui"?
+ A: The library started its life as "ImGui" due to the fact that I didn't give it a proper name when
+ when I released 1.0, and had no particular expectation that it would take off. However, the term IMGUI
+ (immediate-mode graphical user interface) was coined before and is being used in variety of other
+ situations (e.g. Unity uses it own implementation of the IMGUI paradigm).
+ To reduce the ambiguity without affecting existing code bases, I have decided on an alternate,
+ longer name "Dear ImGui" that people can use to refer to this specific library.
+ Please try to refer to this library as "Dear ImGui".
+
Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure (e.g. if (ImGui::GetIO().WantCaptureMouse) { ... } )
- When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application.
@@ -664,8 +702,8 @@
Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated.
+ Q: Why are multiple widgets reacting when I interact with a single one?
Q: How can I have multiple widgets with the same label or with an empty label?
- Q: I have multiple widgets with the same label, and only the first one works. Why is that?
A: A primer on labels and the ID Stack...
Dear ImGui internally need to uniquely identify UI elements.
@@ -1344,7 +1382,7 @@
char* ImStrdup(const char* str)
{
size_t len = strlen(str);
- void* buf = ImGui::MemAlloc(len + 1);
+ void* buf = IM_ALLOC(len + 1);
return (char*)memcpy(buf, (const void*)str, len + 1);
}
@@ -1354,8 +1392,8 @@
size_t src_size = strlen(src) + 1;
if (dst_buf_size < src_size)
{
- ImGui::MemFree(dst);
- dst = (char*)ImGui::MemAlloc(src_size);
+ IM_FREE(dst);
+ dst = (char*)IM_ALLOC(src_size);
if (p_dst_size)
*p_dst_size = src_size;
}
@@ -1571,7 +1609,7 @@
}
// Load file content into memory
-// Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
+// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()
void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes)
{
IM_ASSERT(filename && file_open_mode);
@@ -1590,7 +1628,7 @@
}
size_t file_size = (size_t)file_size_signed;
- void* file_data = ImGui::MemAlloc(file_size + padding_bytes);
+ void* file_data = IM_ALLOC(file_size + padding_bytes);
if (file_data == NULL)
{
fclose(f);
@@ -1599,7 +1637,7 @@
if (fread(file_data, 1, file_size, f) != file_size)
{
fclose(f);
- ImGui::MemFree(file_data);
+ IM_FREE(file_data);
return NULL;
}
if (padding_bytes > 0)
@@ -3024,6 +3062,7 @@
return ImMax(wrap_pos_x - pos.x, 1.0f);
}
+// IM_ALLOC() == ImGui::MemAlloc()
void* ImGui::MemAlloc(size_t size)
{
if (ImGuiContext* ctx = GImGui)
@@ -3031,6 +3070,7 @@
return GImAllocatorAllocFunc(size, GImAllocatorUserData);
}
+// IM_FREE() == ImGui::MemFree()
void ImGui::MemFree(void* ptr)
{
if (ptr)
@@ -9790,7 +9830,7 @@
if (!file_data)
return;
LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
- ImGui::MemFree(file_data);
+ IM_FREE(file_data);
}
ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
@@ -9814,7 +9854,7 @@
// For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy..
if (ini_size == 0)
ini_size = strlen(ini_data);
- char* buf = (char*)ImGui::MemAlloc(ini_size + 1);
+ char* buf = (char*)IM_ALLOC(ini_size + 1);
char* buf_end = buf + ini_size;
memcpy(buf, ini_data, ini_size);
buf[ini_size] = 0;
@@ -9861,7 +9901,7 @@
entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
}
}
- ImGui::MemFree(buf);
+ IM_FREE(buf);
g.SettingsLoaded = true;
DockContextOnLoadSettings(&g);
}
diff --git a/imgui.h b/imgui.h
index f990e06..4613625 100644
--- a/imgui.h
+++ b/imgui.h
@@ -13,6 +13,7 @@
// Forward declarations and basic types
// ImGui API (Dear ImGui end-user API)
// Flags & Enumerations
+// Memory allocations macros
// ImVector<>
// ImGuiStyle
// ImGuiIO
@@ -1256,6 +1257,22 @@
};
//-----------------------------------------------------------------------------
+// Helpers: Memory allocations macros
+// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE()
+// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
+// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions.
+//-----------------------------------------------------------------------------
+
+struct ImNewDummy {};
+inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; }
+inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new()
+#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE)
+#define IM_FREE(_PTR) ImGui::MemFree(_PTR)
+#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR)
+#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
+template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }
+
+//-----------------------------------------------------------------------------
// Helper: ImVector<>
// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug).
// You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it.
@@ -1280,7 +1297,7 @@
inline ImVector() { Size = Capacity = 0; Data = NULL; }
inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); }
inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; }
- inline ~ImVector() { if (Data) ImGui::MemFree(Data); }
+ inline ~ImVector() { if (Data) IM_FREE(Data); }
inline bool empty() const { return Size == 0; }
inline int size() const { return Size; }
@@ -1289,7 +1306,7 @@
inline T& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; }
inline const T& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; }
- inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } }
+ inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } }
inline T* begin() { return Data; }
inline const T* begin() const { return Data; }
inline T* end() { return Data + Size; }
@@ -1303,7 +1320,7 @@
inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; }
inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; }
- inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); ImGui::MemFree(Data); } Data = new_data; Capacity = new_capacity; }
+ inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; }
// NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden.
inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; }
@@ -1639,16 +1656,6 @@
// Helpers
//-----------------------------------------------------------------------------
-// Helper: IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() macros to call MemAlloc + Placement New, Placement Delete + MemFree
-// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
-// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions.
-struct ImNewDummy {};
-inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; }
-inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new()
-#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR)
-#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
-template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }
-
// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame.
// Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text("This will be called only once per frame");
struct ImGuiOnceUponAFrame
diff --git a/imgui_draw.cpp b/imgui_draw.cpp
index 7ea5b9f..1ac5220 100644
--- a/imgui_draw.cpp
+++ b/imgui_draw.cpp
@@ -130,8 +130,8 @@
#ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
-#define STBTT_malloc(x,u) ((void)(u), ImGui::MemAlloc(x))
-#define STBTT_free(x,u) ((void)(u), ImGui::MemFree(x))
+#define STBTT_malloc(x,u) ((void)(u), IM_ALLOC(x))
+#define STBTT_free(x,u) ((void)(u), IM_FREE(x))
#define STBTT_assert(x) IM_ASSERT(x)
#define STBTT_fmod(x,y) ImFmod(x,y)
#define STBTT_sqrt(x) ImSqrt(x)
@@ -1465,7 +1465,7 @@
for (int i = 0; i < ConfigData.Size; i++)
if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas)
{
- ImGui::MemFree(ConfigData[i].FontData);
+ IM_FREE(ConfigData[i].FontData);
ConfigData[i].FontData = NULL;
}
@@ -1486,9 +1486,9 @@
{
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
if (TexPixelsAlpha8)
- ImGui::MemFree(TexPixelsAlpha8);
+ IM_FREE(TexPixelsAlpha8);
if (TexPixelsRGBA32)
- ImGui::MemFree(TexPixelsRGBA32);
+ IM_FREE(TexPixelsRGBA32);
TexPixelsAlpha8 = NULL;
TexPixelsRGBA32 = NULL;
}
@@ -1534,7 +1534,7 @@
GetTexDataAsAlpha8(&pixels, NULL, NULL);
if (pixels)
{
- TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)TexWidth * (size_t)TexHeight * 4);
+ TexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4);
const unsigned char* src = pixels;
unsigned int* dst = TexPixelsRGBA32;
for (int n = TexWidth * TexHeight; n > 0; n--)
@@ -1566,7 +1566,7 @@
new_font_cfg.DstFont = Fonts.back();
if (!new_font_cfg.FontDataOwnedByAtlas)
{
- new_font_cfg.FontData = ImGui::MemAlloc(new_font_cfg.FontDataSize);
+ new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize);
new_font_cfg.FontDataOwnedByAtlas = true;
memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);
}
@@ -1651,7 +1651,7 @@
ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
{
const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data);
- unsigned char* buf_decompressed_data = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);
+ unsigned char* buf_decompressed_data = (unsigned char *)IM_ALLOC(buf_decompressed_size);
stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);
ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
@@ -1663,10 +1663,10 @@
ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
{
int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
- void* compressed_ttf = ImGui::MemAlloc((size_t)compressed_ttf_size);
+ void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size);
Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
- ImGui::MemFree(compressed_ttf);
+ IM_FREE(compressed_ttf);
return font;
}
@@ -1966,7 +1966,7 @@
// 7. Allocate texture
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
- atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
+ atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight);
memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
spc.pixels = atlas->TexPixelsAlpha8;
spc.height = atlas->TexHeight;
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 4a485d9..fbd6f7c 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -3571,7 +3571,7 @@
const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0;
const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW;
const int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1;
- char* clipboard_data = (char*)MemAlloc(clipboard_data_len * sizeof(char));
+ char* clipboard_data = (char*)IM_ALLOC(clipboard_data_len * sizeof(char));
ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie);
SetClipboardText(clipboard_data);
MemFree(clipboard_data);
@@ -3590,7 +3590,7 @@
{
// Filter pasted buffer
const int clipboard_len = (int)strlen(clipboard);
- ImWchar* clipboard_filtered = (ImWchar*)MemAlloc((clipboard_len+1) * sizeof(ImWchar));
+ ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len+1) * sizeof(ImWchar));
int clipboard_filtered_len = 0;
for (const char* s = clipboard; *s; )
{
diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp
index 012eae7..4a579ed 100644
--- a/misc/freetype/imgui_freetype.cpp
+++ b/misc/freetype/imgui_freetype.cpp
@@ -398,7 +398,7 @@
const int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024;
int buf_bitmap_current_used_bytes = 0;
ImVector buf_bitmap_buffers;
- buf_bitmap_buffers.push_back((unsigned char*)ImGui::MemAlloc(BITMAP_BUFFERS_CHUNK_SIZE));
+ buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));
// 4. Gather glyphs sizes so we can pack them in our virtual canvas.
// 8. Render/rasterize font characters into the texture
@@ -440,7 +440,7 @@
if (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE)
{
buf_bitmap_current_used_bytes = 0;
- buf_bitmap_buffers.push_back((unsigned char*)ImGui::MemAlloc(BITMAP_BUFFERS_CHUNK_SIZE));
+ buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));
}
// Blit rasterized pixels to our temporary buffer and keep a pointer to it.
@@ -493,7 +493,7 @@
// 7. Allocate texture
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
- atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
+ atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight);
memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
// 8. Copy rasterized font characters back into the main texture
@@ -557,7 +557,7 @@
// Cleanup
for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++)
- ImGui::MemFree(buf_bitmap_buffers[buf_i]);
+ IM_FREE(buf_bitmap_buffers[buf_i]);
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
src_tmp_array[src_i].~ImFontBuildSrcDataFT();
@@ -567,8 +567,8 @@
}
// Default memory allocators
-static void* ImFreeTypeDefaultAllocFunc(size_t size, void* user_data) { IM_UNUSED(user_data); return ImGui::MemAlloc(size); }
-static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { IM_UNUSED(user_data); ImGui::MemFree(ptr); }
+static void* ImFreeTypeDefaultAllocFunc(size_t size, void* user_data) { IM_UNUSED(user_data); return IM_ALLOC(size); }
+static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_FREE(ptr); }
// Current memory allocators
static void* (*GImFreeTypeAllocFunc)(size_t size, void* user_data) = ImFreeTypeDefaultAllocFunc;
diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h
index 9df5780..b4b0fd6 100644
--- a/misc/freetype/imgui_freetype.h
+++ b/misc/freetype/imgui_freetype.h
@@ -29,7 +29,7 @@
IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0);
- // By default ImGuiFreeType will use ImGui::MemAlloc()/MemFree().
+ // By default ImGuiFreeType will use IM_ALLOC()/IM_FREE().
// However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired:
IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL);
}