Skip to content

Commit 92b2df4

Browse files
authored
Merge pull request #11 from nfginola/main
backend: Support Vulkan
2 parents 939afa3 + 5ea0cab commit 92b2df4

File tree

7 files changed

+2405
-0
lines changed

7 files changed

+2405
-0
lines changed

build.zig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub const Backend = enum {
44
no_backend,
55
glfw_wgpu,
66
glfw_opengl3,
7+
glfw_vulkan,
78
glfw_dx12,
89
win32_dx12,
910
glfw,
@@ -335,6 +336,19 @@ pub fn build(b: *std.Build) void {
335336
else => {},
336337
}
337338
},
339+
.glfw_vulkan => {
340+
if (b.lazyDependency("zglfw", .{})) |zglfw| {
341+
imgui.addIncludePath(zglfw.path("libs/glfw/include"));
342+
}
343+
344+
imgui.addCSourceFiles(.{
345+
.files = &.{
346+
"libs/imgui/backends/imgui_impl_glfw.cpp",
347+
"libs/imgui/backends/imgui_impl_vulkan.cpp",
348+
},
349+
.flags = &(cflags.* ++ .{ "-DVK_NO_PROTOTYPES", "-DZGUI_DEGAMMA" }),
350+
});
351+
},
338352
.glfw => {
339353
if (b.lazyDependency("zglfw", .{})) |zglfw| {
340354
imgui.addIncludePath(zglfw.path("libs/glfw/include"));

libs/imgui/backends/imgui_impl_vulkan.cpp

Lines changed: 2032 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
// dear imgui: Renderer Backend for Vulkan
2+
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
3+
4+
// Implemented features:
5+
// [x] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions.
6+
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
7+
// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
8+
9+
// Important: on 32-bit systems, user texture binding is only supported if your imconfig file has '#define ImTextureID ImU64'.
10+
// See imgui_impl_vulkan.cpp file for details.
11+
12+
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
13+
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
14+
15+
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
16+
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
17+
// Learn about Dear ImGui:
18+
// - FAQ https://dearimgui.com/faq
19+
// - Getting Started https://dearimgui.com/getting-started
20+
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
21+
// - Introduction, links and more at the top of imgui.cpp
22+
23+
// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
24+
// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.
25+
// You will use those if you want to use this rendering backend in your engine/app.
26+
// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
27+
// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
28+
// Read comments in imgui_impl_vulkan.h.
29+
30+
#pragma once
31+
#ifndef IMGUI_DISABLE
32+
#include "imgui.h" // IMGUI_IMPL_API
33+
34+
// [Configuration] in order to use a custom Vulkan function loader:
35+
// (1) You'll need to disable default Vulkan function prototypes.
36+
// We provide a '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' convenience configuration flag.
37+
// In order to make sure this is visible from the imgui_impl_vulkan.cpp compilation unit:
38+
// - Add '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' in your imconfig.h file
39+
// - Or as a compilation flag in your build system
40+
// - Or uncomment here (not recommended because you'd be modifying imgui sources!)
41+
// - Do not simply add it in a .cpp file!
42+
// (2) Call ImGui_ImplVulkan_LoadFunctions() before ImGui_ImplVulkan_Init() with your custom function.
43+
// If you have no idea what this is, leave it alone!
44+
//#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES
45+
46+
// Convenience support for Volk
47+
// (you can also technically use IMGUI_IMPL_VULKAN_NO_PROTOTYPES + wrap Volk via ImGui_ImplVulkan_LoadFunctions().)
48+
//#define IMGUI_IMPL_VULKAN_USE_VOLK
49+
50+
#if defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES) && !defined(VK_NO_PROTOTYPES)
51+
#define VK_NO_PROTOTYPES
52+
#endif
53+
#if defined(VK_USE_PLATFORM_WIN32_KHR) && !defined(NOMINMAX)
54+
#define NOMINMAX
55+
#endif
56+
57+
// Vulkan includes
58+
#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
59+
#include <volk.h>
60+
#else
61+
#include <vulkan/vulkan.h>
62+
#endif
63+
#if defined(VK_VERSION_1_3) || defined(VK_KHR_dynamic_rendering)
64+
#define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
65+
#endif
66+
67+
// FIX(zig-gamedev) - Match PipelineRenderingCreateInfo structure for compatibility
68+
typedef struct unusedVkPipelineRenderingCreateInfo {
69+
uint32_t sType;
70+
const void* pNext;
71+
uint32_t viewMask;
72+
uint32_t colorAttachmentCount;
73+
const uint32_t* pColorAttachmentFormats;
74+
uint32_t depthAttachmentFormat;
75+
uint32_t stencilAttachmentFormat;
76+
} unusedVkPipelineRenderingCreateInfo;
77+
78+
// Initialization data, for ImGui_ImplVulkan_Init()
79+
// - VkDescriptorPool should be created with VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
80+
// and must contain a pool size large enough to hold an ImGui VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor.
81+
// - When using dynamic rendering, set UseDynamicRendering=true and fill PipelineRenderingCreateInfo structure.
82+
// [Please zero-clear before use!]
83+
struct ImGui_ImplVulkan_InitInfo
84+
{
85+
VkInstance Instance;
86+
VkPhysicalDevice PhysicalDevice;
87+
VkDevice Device;
88+
uint32_t QueueFamily;
89+
VkQueue Queue;
90+
VkDescriptorPool DescriptorPool; // See requirements in note above
91+
VkRenderPass RenderPass; // Ignored if using dynamic rendering
92+
uint32_t MinImageCount; // >= 2
93+
uint32_t ImageCount; // >= MinImageCount
94+
VkSampleCountFlagBits MSAASamples; // 0 defaults to VK_SAMPLE_COUNT_1_BIT
95+
96+
// (Optional)
97+
VkPipelineCache PipelineCache;
98+
uint32_t Subpass;
99+
100+
// (Optional) Dynamic Rendering
101+
// Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3.
102+
bool UseDynamicRendering;
103+
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
104+
VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo;
105+
#else
106+
unusedVkPipelineRenderingCreateInfo PipelineRenderingCreateInfo;
107+
#endif
108+
109+
// (Optional) Allocation, Debugging
110+
const VkAllocationCallbacks* Allocator;
111+
void (*CheckVkResultFn)(VkResult err);
112+
VkDeviceSize MinAllocationSize; // Minimum allocation size. Set to 1024*1024 to satisfy zealous best practices validation layer and waste a little memory.
113+
};
114+
115+
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
116+
// FIX(zig-gamedev)
117+
extern "C" {
118+
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info);
119+
IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
120+
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
121+
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE);
122+
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture();
123+
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontsTexture();
124+
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
125+
126+
// Optional: load Vulkan functions with a custom function loader
127+
// This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES
128+
IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = nullptr);
129+
}
130+
131+
// Register a texture (VkDescriptorSet == ImTextureID)
132+
// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem
133+
// Please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions.
134+
IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout);
135+
IMGUI_IMPL_API void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set);
136+
137+
//-------------------------------------------------------------------------
138+
// Internal / Miscellaneous Vulkan Helpers
139+
// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
140+
//-------------------------------------------------------------------------
141+
// You probably do NOT need to use or care about those functions.
142+
// Those functions only exist because:
143+
// 1) they facilitate the readability and maintenance of the multiple main.cpp examples files.
144+
// 2) the multi-viewport / platform window implementation needs them internally.
145+
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
146+
// but it is too much code to duplicate everywhere so we exceptionally expose them.
147+
//
148+
// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
149+
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
150+
// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
151+
//-------------------------------------------------------------------------
152+
153+
struct ImGui_ImplVulkanH_Frame;
154+
struct ImGui_ImplVulkanH_Window;
155+
156+
// Helpers
157+
IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
158+
IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator);
159+
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
160+
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
161+
IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
162+
163+
// Helper structure to hold the data needed by one rendering frame
164+
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
165+
// [Please zero-clear before use!]
166+
struct ImGui_ImplVulkanH_Frame
167+
{
168+
VkCommandPool CommandPool;
169+
VkCommandBuffer CommandBuffer;
170+
VkFence Fence;
171+
VkImage Backbuffer;
172+
VkImageView BackbufferView;
173+
VkFramebuffer Framebuffer;
174+
};
175+
176+
struct ImGui_ImplVulkanH_FrameSemaphores
177+
{
178+
VkSemaphore ImageAcquiredSemaphore;
179+
VkSemaphore RenderCompleteSemaphore;
180+
};
181+
182+
// Helper structure to hold the data needed by one rendering context into one OS window
183+
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
184+
struct ImGui_ImplVulkanH_Window
185+
{
186+
int Width;
187+
int Height;
188+
VkSwapchainKHR Swapchain;
189+
VkSurfaceKHR Surface;
190+
VkSurfaceFormatKHR SurfaceFormat;
191+
VkPresentModeKHR PresentMode;
192+
VkRenderPass RenderPass;
193+
bool UseDynamicRendering;
194+
bool ClearEnable;
195+
VkClearValue ClearValue;
196+
uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
197+
uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
198+
uint32_t SemaphoreCount; // Number of simultaneous in-flight frames + 1, to be able to use it in vkAcquireNextImageKHR
199+
uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
200+
ImGui_ImplVulkanH_Frame* Frames;
201+
ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
202+
203+
ImGui_ImplVulkanH_Window()
204+
{
205+
memset((void*)this, 0, sizeof(*this));
206+
PresentMode = (VkPresentModeKHR)~0; // Ensure we get an error if user doesn't set this.
207+
ClearEnable = true;
208+
}
209+
};
210+
211+
#endif // #ifndef IMGUI_DISABLE

src/backend_glfw.zig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ pub fn initOpenGL(
1919
}
2020
}
2121

22+
pub fn initVulkan(
23+
window: *const anyopaque, // zglfw.Window
24+
) void {
25+
if (!ImGui_ImplGlfw_InitForVulkan(window, true)) {
26+
unreachable;
27+
}
28+
}
29+
2230
pub fn deinit() void {
2331
ImGui_ImplGlfw_Shutdown();
2432
}
@@ -31,5 +39,6 @@ pub fn newFrame() void {
3139
// (they include few custom changes).
3240
extern fn ImGui_ImplGlfw_InitForOther(window: *const anyopaque, install_callbacks: bool) bool;
3341
extern fn ImGui_ImplGlfw_InitForOpenGL(window: *const anyopaque, install_callbacks: bool) bool;
42+
extern fn ImGui_ImplGlfw_InitForVulkan(window: *const anyopaque, install_callbacks: bool) bool;
3443
extern fn ImGui_ImplGlfw_NewFrame() void;
3544
extern fn ImGui_ImplGlfw_Shutdown() void;

src/backend_glfw_vulkan.zig

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
const gui = @import("gui.zig");
2+
const backend_glfw = @import("backend_glfw.zig");
3+
const backend_vulkan = @import("backend_vulkan.zig");
4+
5+
pub const VkHandle = backend_vulkan.VkHandle;
6+
pub const VkPipelineRenderingCreateInfo = backend_vulkan.VkPipelineRenderingCreateInfo;
7+
pub const ImGui_ImplVulkan_InitInfo = backend_vulkan.ImGui_ImplVulkan_InitInfo;
8+
9+
pub fn init(init_info: ImGui_ImplVulkan_InitInfo, window: *const anyopaque) void {
10+
backend_glfw.initVulkan(window);
11+
backend_vulkan.init(init_info);
12+
}
13+
14+
pub fn loadFunctions(
15+
loader: fn (function_name: [*:0]const u8, user_data: ?*anyopaque) callconv(.C) ?*anyopaque,
16+
user_data: ?*anyopaque,
17+
) bool {
18+
return backend_vulkan.loadFunctions(loader, user_data);
19+
}
20+
21+
pub fn deinit() void {
22+
backend_vulkan.deinit();
23+
backend_glfw.deinit();
24+
}
25+
26+
pub fn newFrame(
27+
fb_width: u32,
28+
fb_height: u32,
29+
) void {
30+
backend_glfw.newFrame();
31+
backend_vulkan.newFrame();
32+
33+
gui.io.setDisplaySize(@as(f32, @floatFromInt(fb_width)), @as(f32, @floatFromInt(fb_height)));
34+
gui.io.setDisplayFramebufferScale(1.0, 1.0);
35+
36+
gui.newFrame();
37+
}
38+
39+
pub fn render(
40+
command_buffer: VkHandle,
41+
) void {
42+
gui.render();
43+
backend_vulkan.render(command_buffer);
44+
}
45+
46+
pub fn set_min_image_count(min_image_count: u32) void {
47+
backend_vulkan.set_min_image_count(min_image_count);
48+
}

0 commit comments

Comments
 (0)