Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add glfw wgpu desktop and multiviewport support #7132

Closed
wants to merge 100 commits into from
Closed
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
6fda112
Create WGPU structure for multiviewports
Zelif Dec 12, 2023
e7b5f87
Adding Multiviewport to WGPU
Zelif Dec 12, 2023
e5cf10b
Update imgui_impl_wgpu.cpp
Zelif Dec 15, 2023
62cfa98
Update imgui_impl_wgpu.cpp
Zelif Dec 15, 2023
fff4391
Add Cmake files
Zelif Dec 15, 2023
ad666db
Update example_emscripten_wgpu demo
Zelif Dec 15, 2023
b271eff
Update CMakeLists.txt
Zelif Dec 15, 2023
82d92aa
Fix memory leak when rendering window
Zelif Dec 28, 2023
e92aa28
Fix memory leak in render function
Zelif Dec 28, 2023
c770f20
Merge branch 'docking' into Add-glfw-wgpu-example
Zelif Dec 28, 2023
3de52f8
Update index.html
Zelif Dec 28, 2023
44c7dfc
Menus, Popup: Amend c3f8f4d for static analyzer warning ("condition a…
ocornut Feb 27, 2024
0573513
Windows: Scrollbar visibility decision uses current size when both si…
ocornut Feb 28, 2024
c623669
Added link to crawlable wiki
ocornut Feb 28, 2024
04f4001
Docs: added a mini wiki index in main source files.
ocornut Feb 29, 2024
1ff90c5
ImDrawList: add PathFillConcave(), AddConcavePolyFilled() (#760)
thedmd Jan 3, 2024
fbf45ad
ImDrawList: add PathFillConcave(), AddConcavePolyFilled(): amends (#760)
ocornut Jan 9, 2024
6b7358e
InputText: adding clarifying note about ImGuiInputTextCallbackData::B…
ocornut Mar 4, 2024
65dc67f
Windows: Double-click to collapse may be disabled via key-ownership m…
ocornut Mar 5, 2024
fd75685
Merge branch 'master' into docking
ocornut Mar 5, 2024
fc570ac
Examples: WGPU: fixed initialization of WGPURenderPassColorAttachment…
kevle Mar 6, 2024
286cd5b
Internals, InputText: removed ImGuiInputSource_Clipboard. (#4005)
ocornut Mar 7, 2024
3c435c0
Inputs: (Breaking) More formally obsoleted GetKeyIndex() when IMGUI_D…
ocornut Mar 8, 2024
da29b77
Backends: SDL3: Fix leak of SDL_GetGamepads() return value (#7381)
edmonds Mar 11, 2024
9d9ca37
Docking: Fix C++26 zealous warnings (#7383, #7089)
ocornut Mar 11, 2024
adcc321
Revert "Docking: Fix C++26 zealous warnings (#7383, #7089)" + Disable…
ocornut Mar 11, 2024
40df3db
Tweaking terminology
ocornut Mar 17, 2024
0a1f5b9
Demo: Two minor fixes (unchecked BeginTooltip + incorrect height cons…
cfillion Mar 18, 2024
868facf
ImDrawList: (Breaking) merge float radius_x/radius_y parameters into …
cfillion Mar 18, 2024
085781f
Merge branch 'master' into docking
ocornut Mar 19, 2024
8be48a4
Backends: WebGPU: Avoid using -1u literal (#7436)
eliemichel Mar 25, 2024
38ddfb2
Tables: Angled headers: fixed border hit box extending beyond non-scr…
cfillion Mar 18, 2024
29ff159
Tables: Angled headers: fixed borders not moving back up after TableA…
cfillion Mar 18, 2024
f080228
Tables: Angled headers: fixed table contents overflowing when a list …
cfillion Mar 18, 2024
cf4c10b
Style: added ImGuiStyleVar_TabBorderSize, ImGuiStyleVar_TableAngledHe…
cfillion Mar 17, 2024
5c5ae80
Comments
ocornut Mar 26, 2024
37b37fc
DrawList: Allow AddText() to accept null ranges. (#3615, 7391)
ocornut Mar 27, 2024
976dc23
Windows: extend outer resize borders to the edges when there are no c…
cfillion Mar 25, 2024
515b437
Child windows: look at the parent window's flags to decide whether to…
cfillion Mar 25, 2024
742e534
Child Windows: adjust resizing limits to match window padding rather …
ocornut Mar 27, 2024
9638c28
Internals: adding ImGuiNavMoveFlags_NoClearActiveId even though there…
ocornut Mar 27, 2024
25a492f
ProgressBar: Fixed passing fraction==NaN from leading to a crash. (#7…
ocornut Mar 29, 2024
d3c3514
Tables: Fixed auto-width columns when using synced-instances of same …
ocornut Mar 29, 2024
9a2b598
ListBox: Fixed text-baseline offset when using SameLine()+Text() afte…
ocornut Apr 3, 2024
0bf134a
Refactor moving ID stack functions to their own section.
ocornut Apr 3, 2024
f959c41
Refactor moving ID stack functions to their own section (part 2)
ocornut Apr 3, 2024
e7712ff
Out of courtesy/consistency move all the DebugHookIdInfo compares int…
ocornut Apr 3, 2024
4f9ba19
Drags, Sliders, Inputs: Reactivated decimal point replacement for Sli…
GamingMinds-DanielC Mar 11, 2024
231cbee
Version 1.90.5
ocornut Apr 11, 2024
1db579d
Merge branch 'master' into docking
ocornut Apr 11, 2024
f790d51
Silent zealous/stupid warning introduced by Clang 16 (shipping with V…
ocornut Apr 12, 2024
76bc1b8
Extracted part of NewFrame() into SetupDrawListSharedData() for docum…
ocornut Apr 15, 2024
3caa79c
Version 1.90.6 WIP
ocornut Apr 15, 2024
c1743ee
Docking: when io.ConfigDockingWithShift is enabled, fixed help toolti…
ocornut Apr 15, 2024
dad1689
Examples: SDL3: amend for removal of SDL_RENDERER_ACCELERATED.
ocornut Apr 15, 2024
fab96a6
Backends: SDL3: Re-enable calling SDL_StartTextInput()/SDL_StopTextIn…
Green-Sky Mar 28, 2024
daecfff
Text, DrawList: Improved handling of long single-line wrapped text. (…
ocornut Apr 15, 2024
b475309
Fonts: Fixed font ascent and descent calculation when a font hits exa…
GamingMinds-DanielC Mar 14, 2024
f9df6bf
Examples: GLFW+WebGPU: added support for WebGPU-native/Dawn (#7435, #…
eliasdaler Mar 24, 2024
80a5fdb
Examples: GLFW+WebGPU: Fixed condition for when to recreate swapchain…
JulesFouchy Apr 5, 2024
648278c
Examples: GLFW+WebGPU: Amends. (#7435, #7132)
ocornut Apr 16, 2024
7b8107e
Examples: GLFW+WebGPU: Rename example_emscripten_wgpu/ to example_glf…
ocornut Apr 16, 2024
4cb0fe3
Merge branch 'master' into docking
ocornut Apr 16, 2024
9ec299e
Backends: OpenGL: Detect ES3 contexts on desktop based on version str…
ocornut Apr 16, 2024
eba46cb
Drag and Drop: assert when nesting BeginDragDropSource() and BeginDr…
ocornut Apr 17, 2024
361432a
TreeNode: fixed layout so that TreeNode("") or TreeNode("##HiddenLabe…
ocornut Apr 18, 2024
fa0120e
Windows: Fixed subsequent Begin() append calls from setting last item…
ocornut Apr 18, 2024
b555984
Merge branch 'master' into docking
ocornut Apr 18, 2024
07e8ff9
Backends: Win32: Fixed a warning + moved header cruft below Changelog.
ocornut Apr 18, 2024
b720c0f
Backends: Vulkan: Added convenience support for Volk via IMGUI_IMPL_V…
ocornut Apr 19, 2024
da18fcb
Internals: ensure ButtonBehavior() is called with non 0 id.
ocornut Apr 23, 2024
baaaaea
Demo: tweak TreeNode demo.
ocornut Apr 24, 2024
b8a44b1
TreeNode: added ImGuiTreeNodeFlags_SpanTextWidth. (#6937)
dimateos Oct 17, 2023
c895e98
ProgressBar: added indeterminate mode by passing an animated negative…
gan74 Apr 24, 2024
913151c
Demo: move progress bars to their own section.
ocornut Apr 24, 2024
a60387a
Backends: GLFW: Add define guards for glfw native defines. (#7536)
fknfilewalker Apr 29, 2024
6ef4f67
ImDrawList: moved cold fields lower in the structure so hot fields ar…
ocornut Apr 30, 2024
50b2ff0
ImGuiIO: moved IMGUI_DISABLE_OBSOLETE_KEYIO block lower in the struct…
ocornut Apr 30, 2024
5717f0a
Merge branch 'master' into docking
ocornut Apr 30, 2024
558c57a
Fixed static analyzer warning "Pointer to local array 'overlay_buf' i…
ocornut Apr 30, 2024
9d6818d
Docking: comments, clairfy why we store style override on dragged win…
ocornut Apr 30, 2024
49e70e6
Backends: Vulkan: Stripped misleading leftover of ImGui_ImplVulkanH_W…
ocornut Apr 30, 2024
ebb8d78
Backends: Vulkan: Create a custom pipeline for secondary viewports. (…
skaman Apr 12, 2023
b30df88
Table: Angled Headers: internal refactor to facilitate changing angle…
ocornut Apr 30, 2024
4bb7567
Tables: Angled headers: fixed multi-line label display when angle is …
ocornut May 2, 2024
fc4d818
Tables: Angled headers: added TableAngledHeadersTextAlign, ImGuiStyle…
thedmd Apr 30, 2024
6ebbecc
Realign assignments.
ocornut May 3, 2024
0c9c12c
InnerClipRect use ImFloor() matching docking branch (fix c41868531 fo…
ocornut May 3, 2024
0b30947
Windows: Changed default ClipRect to extend to windows' left and righ…
ocornut May 3, 2024
2f2d507
Merge branch 'master' into docking
ocornut May 3, 2024
f5d1852
Viewports: fixed outer-right edge of MenuBar clipping rectangle off b…
cfillion May 3, 2024
9a7f1b1
Added MultiViewport WebGPU
Zelif May 4, 2024
8d08e0b
Updated wgpu example for multiviewport
Zelif May 4, 2024
ecdae77
Add Cmake files
Zelif Dec 15, 2023
6cd66dd
Update example_emscripten_wgpu demo
Zelif Dec 15, 2023
ec89c07
Update CMakeLists.txt
Zelif Dec 15, 2023
a3abb1f
Fix memory leak in render function
Zelif Dec 28, 2023
80d21d0
Update index.html
Zelif Dec 28, 2023
69730ea
Removed old Files
Zelif May 4, 2024
8ff415b
Merge branch 'Add-glfw-wgpu-example' of https://github.com/Zelif/imgu…
Zelif May 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
210 changes: 209 additions & 1 deletion backends/imgui_impl_wgpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2023-12-12: Add support for multi viewports.
// 2023-07-13: Use WGPUShaderModuleWGSLDescriptor's code instead of source. use WGPUMipmapFilterMode_Linear instead of WGPUFilterMode_Linear. (#6602)
// 2023-04-11: Align buffer sizes. Use WGSL shaders instead of precompiled SPIR-V.
// 2023-04-11: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
Expand All @@ -38,6 +39,7 @@
#include "imgui_impl_wgpu.h"
#include <limits.h>
#include <webgpu/webgpu.h>
#include <memory>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be removed if ImGui_ImplWGPU_CreateWindow is not included in the backend.


// Dear ImGui prototypes from imgui_internal.h
extern ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed = 0);
Expand Down Expand Up @@ -72,8 +74,22 @@ struct Uniforms
float Gamma;
};

// Forward declarations for multi-viewport support
static void ImGui_ImplWGPU_InitPlatformInterface();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ocornut, maybe it's worth renaming everything from WGPU to WebGPU? "wgpu" is a name of the Rust implementation and I see "WebGPU" being used everywhere (except for C API, which I find unfortunate).

Otherwise people might think that this backend can only be used with wgpu and not with Dawn.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had chosen to go with WGPU purely based on how the C API was naming things, so yeah WebGPU is fine to go with as well.

static void ImGui_ImplWGPU_ShutdownPlatformInterface();

// For multi-viewport support:
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
struct ImGui_ImplWGPU_ViewportData
{
ImGui_ImplWGPUH_Window Window;
ImGui_ImplWGPU_ViewportData() { }
~ImGui_ImplWGPU_ViewportData() { }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These constructor and destructors are unnecessary and can be removed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was a hang over of when I did have objects in there, yup should have been deleted

};

struct ImGui_ImplWGPU_Data
{
WGPUInstance wgpuInstance = nullptr;
WGPUDevice wgpuDevice = nullptr;
WGPUQueue defaultQueue = nullptr;
WGPUTextureFormat renderTargetFormat = WGPUTextureFormat_Undefined;
Expand Down Expand Up @@ -211,6 +227,25 @@ static void SafeRelease(WGPUTexture& res)
wgpuTextureRelease(res);
res = nullptr;
}
static void SafeRelease(WGPURenderPassEncoder& res)
{
if (res)
wgpuRenderPassEncoderRelease(res);
res = nullptr;
}
static void SafeRelease(WGPUCommandBuffer& res)
{
if (res)
wgpuCommandBufferRelease(res);
res = nullptr;
}
static void SafeRelease(WGPUCommandEncoder& res)
{
if (res)
wgpuCommandEncoderRelease(res);
res = nullptr;
}


static void SafeRelease(RenderResources& res)
{
Expand All @@ -230,6 +265,18 @@ static void SafeRelease(FrameResources& res)
SafeRelease(res.IndexBufferHost);
SafeRelease(res.VertexBufferHost);
}
static void SafeRelease(WGPUSwapChain& res)
{
if (res)
wgpuSwapChainRelease(res);
res = nullptr;
}
static void SafeRelease(WGPUSurface& res)
{
if (res)
wgpuSurfaceRelease(res);
res = nullptr;
}

static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(const char* wgsl_source)
{
Expand Down Expand Up @@ -699,7 +746,7 @@ void ImGui_ImplWGPU_InvalidateDeviceObjects()
SafeRelease(bd->pFrameResources[i]);
}

bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format, WGPUTextureFormat depth_format)
bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format, WGPUTextureFormat depth_format, WGPUInstance instance)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
Expand All @@ -709,7 +756,11 @@ bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextur
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_webgpu";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
#ifndef __EMSCRIPTEN__
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // Enable multiviewport on desktop.
#endif

bd->wgpuInstance = instance;
bd->wgpuDevice = device;
bd->defaultQueue = wgpuDeviceGetQueue(bd->wgpuDevice);
bd->renderTargetFormat = rt_format;
Expand Down Expand Up @@ -739,6 +790,12 @@ bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextur
fr->VertexBufferSize = 5000;
}

if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
IM_ASSERT(instance != nullptr && "WGPUInstance required for multi viewport!");
ImGui_ImplWGPU_InitPlatformInterface();
}

return true;
}

Expand All @@ -756,6 +813,10 @@ void ImGui_ImplWGPU_Shutdown()
bd->numFramesInFlight = 0;
bd->frameIndex = UINT_MAX;

// Clean up windows
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
ImGui_ImplWGPU_ShutdownPlatformInterface();

io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
Expand All @@ -769,6 +830,153 @@ void ImGui_ImplWGPU_NewFrame()
ImGui_ImplWGPU_CreateDeviceObjects();
}

//--------------------------------------------------------------------------------------------------------
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
//--------------------------------------------------------------------------------------------------------


static void ImGui_ImplWGPU_CreateWindow(ImGuiViewport* viewport)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be moved out of the backend and user should provide this instead - there's no easy way to handle this for every platform/WebGPU impl.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

100% this is the main thing I was struggling with trying to fix, would it be just a callback that a user would need to assign to ?

{
ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData();
ImGui_ImplWGPU_ViewportData* vd = IM_NEW(ImGui_ImplWGPU_ViewportData)();
viewport->RendererUserData = vd;

WGPUChainedStruct chainedDescriptor = {};
// ------ ISSUE unknown for linux and apple -------------
#ifndef __EMSCRIPTEN__
#ifdef _WIN32
chainedDescriptor.sType = WGPUSType_SurfaceDescriptorFromWindowsHWND;
std::unique_ptr<WGPUSurfaceDescriptorFromWindowsHWND> surfaceDescFromHandle = std::make_unique<WGPUSurfaceDescriptorFromWindowsHWND>();
surfaceDescFromHandle->hwnd = viewport->PlatformHandleRaw;
#elif defined(__APPLE__)
chainedDescriptor.sType = WGPUSType_SurfaceDescriptorFromMetalLayer;
std::unique_ptr<WGPUSurfaceDescriptorFromMetalLayer> surfaceDescFromHandle = std::make_unique<WGPUSurfaceDescriptorFromMetalLayer>();
NSWindow* ns_window = viewport->PlatformHandleRaw;
[ns_window.contentView setWantsLayer : YES];
metal_layer = [CAMetalLayer layer];
[ns_window.contentView setLayer : metal_layer] ;
surfaceDescFromHandle->layer = metal_layer;
// #elif defined(DAWN_USE_WAYLAND)
// struct wl_display* wayland_display = glfwGetWaylandDisplay();
// struct wl_surface* wayland_surface = glfwGetWaylandWindow(window);
// chainedDescriptor.sType = WGPUSType_SurfaceDescriptorFromWindowsHWND;
// std::unique_ptr<WGPUSurfaceDescriptorFromWaylandSurface> surfaceDescFromHandle = std::make_unique<WGPUSurfaceDescriptorFromWaylandSurface>();
// surfaceDescFromHandle->display = wayland_display;
// surfaceDescFromHandle->surface = wayland_surface;
// #else
// Display* x11_display = glfwGetX11Display();
// Window x11_window = glfwGetX11Window((GLFWwindow*) viewport->PlatformHandle);
// chainedDescriptor.sType = WGPUSType_SurfaceDescriptorFromXlibWindow;
// std::unique_ptr<WGPUSurfaceDescriptorFromXlibWindow> surfaceDescFromHandle = std::make_unique<WGPUSurfaceDescriptorFromXlibWindow>();
// surfaceDescFromHandle->display = x11_display;
// surfaceDescFromHandle->window = x11_window;
#endif
// ------------------------------------------------------

surfaceDescFromHandle->chain = chainedDescriptor;
WGPUSurfaceDescriptor surfaceDescriptor = {};
surfaceDescriptor.nextInChain = &surfaceDescFromHandle->chain;

vd->Window.surface = wgpuInstanceCreateSurface(bd->wgpuInstance, &surfaceDescriptor);
#endif
WGPUSwapChainDescriptor swapDescriptor = {};
swapDescriptor.usage = WGPUTextureUsage_RenderAttachment;
swapDescriptor.format = bd->renderTargetFormat;
swapDescriptor.width = viewport->Size.x;
swapDescriptor.height = viewport->Size.y;
swapDescriptor.presentMode = WGPUPresentMode_Fifo;

vd->Window.swapChain = wgpuDeviceCreateSwapChain(bd->wgpuDevice, vd->Window.surface, &swapDescriptor);
}


static void ImGui_ImplWGPU_DestroyWindow(ImGuiViewport* viewport)
{
if (ImGui_ImplWGPU_ViewportData* vd = (ImGui_ImplWGPU_ViewportData*)viewport->RendererUserData)
{
SafeRelease(vd->Window.swapChain);
SafeRelease(vd->Window.surface);
IM_DELETE(vd);
}
viewport->RendererUserData = nullptr;
}


static void ImGui_ImplWGPU_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
{
ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData();
ImGui_ImplWGPU_ViewportData* vd = (ImGui_ImplWGPU_ViewportData*)viewport->RendererUserData;

SafeRelease(vd->Window.swapChain);

WGPUSwapChainDescriptor swapDescriptor = {};
swapDescriptor.usage = WGPUTextureUsage_RenderAttachment;
swapDescriptor.format = bd->renderTargetFormat;
swapDescriptor.width = size.x;
swapDescriptor.height = size.y;
swapDescriptor.presentMode = WGPUPresentMode_Fifo;

vd->Window.swapChain = wgpuDeviceCreateSwapChain(bd->wgpuDevice, vd->Window.surface, &swapDescriptor);
}

static void ImGui_ImplWGPU_RenderWindow(ImGuiViewport* viewport, void*)
{
ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData();
ImGui_ImplWGPU_ViewportData* vd = (ImGui_ImplWGPU_ViewportData*)viewport->RendererUserData;

ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
WGPURenderPassColorAttachment color_attachments = {};
color_attachments.view = wgpuSwapChainGetCurrentTextureView(vd->Window.swapChain);
color_attachments.loadOp = WGPULoadOp_Clear;
color_attachments.storeOp = WGPUStoreOp_Store;
color_attachments.clearValue = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't work without this:

color_attachments.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a new requirement imposed in a version of dawn that I had yet to work with, If that is required then putting it in should be done.


WGPURenderPassDescriptor render_pass_desc = {};
render_pass_desc.colorAttachmentCount = 1;
render_pass_desc.colorAttachments = &color_attachments;
render_pass_desc.depthStencilAttachment = nullptr;

WGPUCommandEncoderDescriptor enc_desc = {};
WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(bd->wgpuDevice, &enc_desc);

WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &render_pass_desc);
ImGui_ImplWGPU_RenderDrawData(viewport->DrawData, pass);
wgpuRenderPassEncoderEnd(pass);

WGPUCommandBufferDescriptor cmd_buffer_desc = {};
WGPUCommandBuffer cmd_buffer = wgpuCommandEncoderFinish(encoder, &cmd_buffer_desc);
WGPUQueue queue = wgpuDeviceGetQueue(bd->wgpuDevice);
wgpuQueueSubmit(queue, 1, &cmd_buffer);

SafeRelease(color_attachments.view);
SafeRelease(pass);
SafeRelease(encoder);
SafeRelease(cmd_buffer);
}

static void ImGui_ImplWGPU_SwapBuffers(ImGuiViewport* viewport, void*)
{
ImGui_ImplWGPU_ViewportData* vd = (ImGui_ImplWGPU_ViewportData*)viewport->RendererUserData;
wgpuSwapChainPresent(vd->Window.swapChain);
}

void ImGui_ImplWGPU_InitPlatformInterface()
{
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.Renderer_CreateWindow = ImGui_ImplWGPU_CreateWindow;
platform_io.Renderer_DestroyWindow = ImGui_ImplWGPU_DestroyWindow;
platform_io.Renderer_SetWindowSize = ImGui_ImplWGPU_SetWindowSize;
platform_io.Renderer_RenderWindow = ImGui_ImplWGPU_RenderWindow;
platform_io.Renderer_SwapBuffers = ImGui_ImplWGPU_SwapBuffers;
}

void ImGui_ImplWGPU_ShutdownPlatformInterface()
{
ImGui::DestroyPlatformWindows();
}

//-----------------------------------------------------------------------------

#endif // #ifndef IMGUI_DISABLE
15 changes: 14 additions & 1 deletion backends/imgui_impl_wgpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

#include <webgpu/webgpu.h>

IMGUI_IMPL_API bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format, WGPUTextureFormat depth_format = WGPUTextureFormat_Undefined);
IMGUI_IMPL_API bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format, WGPUTextureFormat depth_format = WGPUTextureFormat_Undefined, WGPUInstance instance = nullptr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably needs a comment which will explain why "instance" is optional here (so that people don't need to read the implementation to know that).

IMGUI_IMPL_API void ImGui_ImplWGPU_Shutdown();
IMGUI_IMPL_API void ImGui_ImplWGPU_NewFrame();
IMGUI_IMPL_API void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder pass_encoder);
Expand All @@ -31,4 +31,17 @@ IMGUI_IMPL_API void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURen
IMGUI_IMPL_API void ImGui_ImplWGPU_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplWGPU_CreateDeviceObjects();

// 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 engine/app.)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's not meant to be used by other people, then maybe let's move it into the example's main.cpp?

Actually, it would be pretty handy since you'll be able to use Dawn's webgpu_glfw.h + CreateSurfaceForWindow function that they provide.

struct ImGui_ImplWGPUH_Window
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "H" stand for in this name?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helper would be my assumption similar to some of the other questions, the vulkan one had a similar naming convention. I feel using the vulkan backend to base my PR was a bad idea xD

{
WGPUSwapChain swapChain;
WGPUSurface surface;

ImGui_ImplWGPUH_Window()
{
memset((void*)this, 0, sizeof(*this));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably do

    WGPUSwapChain       swapChain = nullptr;
    WGPUSurface         surface = nullptr;

or

ImGui_ImplWGPUH_Window() : swapChain(nullptr), surface(nullptr) {}

If doing the former, the default constructor can be removed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another hang over from copying the vulkan code as it did a similar thing.

}
};

#endif // #ifndef IMGUI_DISABLE
64 changes: 64 additions & 0 deletions examples/example_emscripten_wgpu/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Example usage:
# cmake -B build -g "Ninja"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better to list all steps and explain that you need to have Dawn cloned at "external/libraries/dawn":

mkdir build && cd build
cmake ..
cmake --build .

The second step would look like this, if you add an option to specify Dawn's dir:

cmake .. -DIMGUI_DAWN_DIR=<dir of cloned Dawn repo>


cmake_minimum_required(VERSION 3.10.2)
project(imgui_example_emscripten_wgpu C CXX)

if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE)
endif()

set(CMAKE_CXX_STANDARD 17)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't Dear ImGui still C++11? (I see that other examples are) - what are some C++17 features that you need here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another hangup on copying from the vulkan cmake (might want to check the vulkan backend and examples to maybe nip those unless they are needed I assume)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DVK_PROTOTYPES")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_PROTOTYPES")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really needed? Compiled fine without this for me.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah these are not needed, was me being sloppy checking the cmake. (again copied from vulkan but this time I think vulkan needs those)


set(BUILD_TESTING OFF)
set(BUILD_TESTING_STATIC OFF)
set(BUILD_TESTING_SHARED OFF)

# Dear ImGui
set(IMGUI_DIR ../../)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better do this:

set(IMGUI_DIR "${CMAKE_CURRENT_LIST_DIR}/../..")
  1. CMAKE_CURRENT_LIST_DIR usage says clearly what the path is relative to
  2. The use of quotes makes it work for paths where CMAKE_CURRENT_LIST_DIR might be a path with spaces in it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, might want to do the same change in the vulkan example too.

include_directories(${IMGUI_DIR} ${IMGUI_DIR}/backends ..)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to use this:

target_include_directories(example_emscripten_wgpu PRIVATE ${IMGUI_DIR} ${IMGUI_DIR}/backends)


# Libraries
if(EMSCRIPTEN)
set(LIBRARIES glfw)
add_compile_options(-sDISABLE_EXCEPTION_CATCHING=1 -DIMGUI_DISABLE_FILE_FUNCTIONS=1)
else()
# Dawn wgpu desktop
set(DAWN_FETCH_DEPENDENCIES ON)
add_subdirectory("external/libraries/dawn" dawn EXCLUDE_FROM_ALL) # point this to up to date dawn repo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would probably be better to allow users to set DAWN_DIR variable and use that instead so that

  1. The library can be outside of Dear ImGui's source path
  2. You could clearly print the error if the variable is not set.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was unsure the best approach to handle this, might need to account for wgpu-native as well (which I had not)

set(LIBRARIES webgpu_dawn webgpu_cpp webgpu_glfw glfw)
endif()

add_executable(example_emscripten_wgpu
main.cpp
${IMGUI_DIR}/backends/imgui_impl_glfw.cpp
${IMGUI_DIR}/backends/imgui_impl_wgpu.cpp
${IMGUI_DIR}/imgui.cpp
${IMGUI_DIR}/imgui_draw.cpp
${IMGUI_DIR}/imgui_demo.cpp
${IMGUI_DIR}/imgui_tables.cpp
${IMGUI_DIR}/imgui_widgets.cpp
)

# Libraries
if(EMSCRIPTEN)
set_target_properties(example_emscripten_wgpu PROPERTIES OUTPUT_NAME "index")
set_target_properties(example_emscripten_wgpu PROPERTIES SUFFIX ".html")
set_target_properties(example_emscripten_wgpu PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/web)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --shell-file ${CMAKE_SOURCE_DIR}/../libs/emscripten/shell_minimal.html")

target_link_options(example_emscripten_wgpu PRIVATE
"-sUSE_WEBGPU=1"
"-sUSE_GLFW=3"
"-sWASM=1"
"-sALLOW_MEMORY_GROWTH=1"
"-sNO_EXIT_RUNTIME=0"
"-sASSERTIONS=1"
"-sDISABLE_EXCEPTION_CATCHING=1"
"-sNO_FILESYSTEM=1"
)
endif()

target_link_libraries(example_emscripten_wgpu ${LIBRARIES})