diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index fd7cabe27..2e0ec756c 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -117,6 +117,10 @@ #define GLFW_EXPOSE_NATIVE_COCOA #endif #include +#ifdef IMGUI_IMPL_WEBGPU_BACKEND_WGPU +#include +#include +#endif #elif !defined(__EMSCRIPTEN__) #ifndef GLFW_EXPOSE_NATIVE_X11 // for glfwGetX11Window() on Freedesktop (Linux, BSD, etc.) #define GLFW_EXPOSE_NATIVE_X11 @@ -1049,97 +1053,77 @@ void ImGui_ImplGlfw_InstallEmscriptenCallbacks(GLFWwindow* window, const char* c } #endif // #ifdef EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 -// GLFW helper to create a WebGPU surface, used only in WGPU-Native, DAWN-Native already has a built-in function +// GLFW helper to create a WebGPU surface, used only in WGPU-Native. DAWN-Native already has a built-in function // At current date (jun/2025) there is no "official" support in GLFW to create a surface for WebGPU backend // This stub uses "low level" GLFW calls to acquire information from a specific Window Manager. -// Currently supported platforms: Windows / Linux (X11 and Wayland) / MacOS -// Not necessary/available with EMSCRIPTEN -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) && !defined(__EMSCRIPTEN__) -// GLFW native necessary to get information about current platform / Window Manager -#include -// MacOS specific: is necessary to compile with "-x objective-c++" flags +// Currently supported platforms: Windows / Linux (X11 and Wayland) / MacOS. Not necessary/available with EMSCRIPTEN +// MacOS specific: need to compile with "-x objective-c++" flags // (e.g. using cmake: set_source_files_properties(${IMGUI_DIR}/backends/imgui_impl_glfw.cpp PROPERTIES COMPILE_FLAGS "-x objective-c++") ) -#if defined(GLFW_EXPOSE_NATIVE_COCOA) -#include -#include -#endif - -WGPUSurface ImGui_ImplGLFW_CreateWGPUSurface_Helper(WGPUInstance instance, GLFWwindow* window) +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) && !defined(__EMSCRIPTEN__) +WGPUSurface ImGui_ImplGLFW_CreateWGPUSurface(WGPUInstance instance, GLFWwindow* window) { WGPUSurfaceDescriptor surfaceDescriptor = {}; - WGPUChainedStruct chainedStruct = {}; - + WGPUChainedStruct chainedStruct = {}; WGPUSurface surface = {}; #if defined(GLFW_EXPOSE_NATIVE_COCOA) { id metal_layer = NULL; - NSWindow *ns_window = glfwGetCocoaWindow(window); + NSWindow* ns_window = glfwGetCocoaWindow(window); [ns_window.contentView setWantsLayer:YES]; metal_layer = [CAMetalLayer layer]; [ns_window.contentView setLayer:metal_layer]; - chainedStruct.sType = WGPUSType_SurfaceSourceMetalLayer; - WGPUSurfaceSourceMetalLayer surfaceMetal = {}; surfaceMetal.chain = chainedStruct; surfaceMetal.layer = metal_layer; - surfaceDescriptor.nextInChain = &surfaceMetal.chain; surface = wgpuInstanceCreateSurface(instance, &surfaceDescriptor); } #elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) && defined(GLFW_EXPOSE_NATIVE_X11) - if (glfwGetPlatform() == GLFW_PLATFORM_X11) { - Display *x11_display = glfwGetX11Display(); + if (glfwGetPlatform() == GLFW_PLATFORM_X11) + { + Display* x11_display = glfwGetX11Display(); Window x11_window = glfwGetX11Window(window); - chainedStruct.sType = WGPUSType_SurfaceSourceXlibWindow; - WGPUSurfaceSourceXlibWindow surfaceXlib = {}; - surfaceXlib.chain = chainedStruct; + surfaceXlib.chain = chainedStruct; surfaceXlib.display = x11_display; - surfaceXlib.window = x11_window; - + surfaceXlib.window = x11_window; surfaceDescriptor.nextInChain = &surfaceXlib.chain; surface = wgpuInstanceCreateSurface(instance, &surfaceDescriptor); } - if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) { - struct wl_display *wayland_display = glfwGetWaylandDisplay(); - struct wl_surface *wayland_surface = glfwGetWaylandWindow(window); - + if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) + { + struct wl_display* wayland_display = glfwGetWaylandDisplay(); + struct wl_surface* wayland_surface = glfwGetWaylandWindow(window); chainedStruct.sType = WGPUSType_SurfaceSourceWaylandSurface; - WGPUSurfaceSourceWaylandSurface surfaceWayland = {}; - surfaceWayland.chain = chainedStruct; + surfaceWayland.chain = chainedStruct; surfaceWayland.display = wayland_display; surfaceWayland.surface = wayland_surface; - surfaceDescriptor.nextInChain = &surfaceWayland.chain; surface = wgpuInstanceCreateSurface(instance, &surfaceDescriptor); } #elif defined(GLFW_EXPOSE_NATIVE_WIN32) { HWND hwnd = glfwGetWin32Window(window); - HINSTANCE hinstance = GetModuleHandle(NULL); - + HINSTANCE hinstance = ::GetModuleHandle(NULL); chainedStruct.sType = WGPUSType_SurfaceSourceWindowsHWND; - WGPUSurfaceSourceWindowsHWND surfaceHWND = {}; - surfaceHWND.chain = chainedStruct; + surfaceHWND.chain = chainedStruct; surfaceHWND.hinstance = hinstance; - surfaceHWND.hwnd = hwnd; - + surfaceHWND.hwnd = hwnd; surfaceDescriptor.nextInChain = &surfaceHWND.chain; surface = wgpuInstanceCreateSurface(instance, &surfaceDescriptor); } #elif -#error "Unsupported GLFW/WebGPU native platform" +#error "Unsupported GLFW+WebGPU native platform" #endif return surface; } #endif // defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) && !defined(__EMSCRIPTEN__) - //----------------------------------------------------------------------------- #if defined(__clang__) diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index 65f21d29c..92d84ab91 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -66,10 +66,10 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_Sleep(int milliseconds); IMGUI_IMPL_API float ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window); IMGUI_IMPL_API float ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor); -// GLFW helper to create a WebGPU surface for Native/Desktop applications: used only in WGPU-Native, DAWN-Native already has a built-in function +// GLFW helpers for native/desktop WebGPU applications (used only in WGPU-Native, DAWN-Native already has a built-in function) #if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) && !defined(__EMSCRIPTEN__) #include -WGPUSurface ImGui_ImplGLFW_CreateWGPUSurface_Helper(WGPUInstance instance, GLFWwindow* window); +WGPUSurface ImGui_ImplGLFW_CreateWGPUSurface(WGPUInstance instance, GLFWwindow* window); #endif diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 48eab80d1..85b06da53 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -912,74 +912,66 @@ void ImGui_ImplSDL2_NewFrame() #include #endif -WGPUSurface ImGui_ImplSDL2_CreateWGPUSurface_Helper(WGPUInstance instance, SDL_Window* window) +WGPUSurface ImGui_ImplSDL2_CreateWGPUSurface(WGPUInstance instance, SDL_Window* window) { WGPUSurfaceDescriptor surfaceDescriptor = {}; - WGPUChainedStruct chainedStruct = {}; + WGPUChainedStruct chainedStruct = {}; + WGPUSurface surface = {}; + SDL_SysWMinfo sysWMInfo; SDL_VERSION(&sysWMInfo.version); SDL_GetWindowWMInfo(window, &sysWMInfo); - WGPUSurface surface = {}; - #if defined(SDL_VIDEO_DRIVER_WAYLAND) || defined(SDL_VIDEO_DRIVER_X11) - const char *vidDrv = SDL_GetHint(SDL_HINT_VIDEODRIVER); - if(!vidDrv) return NULL; - - if(tolower(vidDrv[0])=='w' && tolower(vidDrv[1])=='a' && tolower(vidDrv[2])=='y' && - tolower(vidDrv[3])=='l' && tolower(vidDrv[4])=='a' && tolower(vidDrv[5])=='n' && tolower(vidDrv[6])=='d') { // wayland + const char* video_driver = SDL_GetHint(SDL_HINT_VIDEODRIVER); + if (!video_driver) + return nullptr; + if (strncmp(video_driver, "wayland", 7) == 0) + { chainedStruct.sType = WGPUSType_SurfaceSourceWaylandSurface; - WGPUSurfaceSourceWaylandSurface surfaceWayland = {}; - surfaceWayland.chain = chainedStruct; + surfaceWayland.chain = chainedStruct; surfaceWayland.display = sysWMInfo.info.wl.display; surfaceWayland.surface = sysWMInfo.info.wl.surface; - surfaceDescriptor.nextInChain = &surfaceWayland.chain; surface = wgpuInstanceCreateSurface(instance, &surfaceDescriptor); - - } else { // x11 + } + else + { chainedStruct.sType = WGPUSType_SurfaceSourceXlibWindow; - WGPUSurfaceSourceXlibWindow surfaceXlib = {}; - surfaceXlib.chain = chainedStruct; + surfaceXlib.chain = chainedStruct; surfaceXlib.display = sysWMInfo.info.x11.display; - surfaceXlib.window = sysWMInfo.info.x11.window; - + surfaceXlib.window = sysWMInfo.info.x11.window; surfaceDescriptor.nextInChain = &surfaceXlib.chain; surface = wgpuInstanceCreateSurface(instance, &surfaceDescriptor); } #elif defined(SDL_VIDEO_DRIVER_WINDOWS) { chainedStruct.sType = WGPUSType_SurfaceSourceWindowsHWND; - WGPUSurfaceSourceWindowsHWND surfaceHWND = {}; - surfaceHWND.chain = chainedStruct; + surfaceHWND.chain = chainedStruct; surfaceHWND.hinstance = sysWMInfo.info.win.hinstance; - surfaceHWND.hwnd = sysWMInfo.info.win.window; - + surfaceHWND.hwnd = sysWMInfo.info.win.window; surfaceDescriptor.nextInChain = &surfaceHWND.chain; surface = wgpuInstanceCreateSurface(instance, &surfaceDescriptor); } #elif defined(SDL_VIDEO_DRIVER_COCOA) { id metal_layer = [CAMetalLayer layer]; - NSWindow *ns_window = sysWMInfo.info.cocoa.window; + NSWindow* ns_window = sysWMInfo.info.cocoa.window; [ns_window.contentView setWantsLayer:YES]; [ns_window.contentView setLayer:metal_layer]; - chainedStruct.sType = WGPUSType_SurfaceSourceMetalLayer; - WGPUSurfaceSourceMetalLayer surfaceMetal = {}; surfaceMetal.chain = chainedStruct; surfaceMetal.layer = metal_layer; - surfaceDescriptor.nextInChain = &surfaceMetal.chain; surface = wgpuInstanceCreateSurface(instance, &surfaceDescriptor); } #else - #error "Unsupported SDL2/WebGPU Backend" + #error "Unsupported SDL2+WebGPU Backend" #endif return surface; } diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index fe7806a84..0cae300a7 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -47,10 +47,10 @@ IMGUI_IMPL_API float ImGui_ImplSDL2_GetContentScaleForDisplay(int display_ind enum ImGui_ImplSDL2_GamepadMode { ImGui_ImplSDL2_GamepadMode_AutoFirst, ImGui_ImplSDL2_GamepadMode_AutoAll, ImGui_ImplSDL2_GamepadMode_Manual }; IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array = nullptr, int manual_gamepads_count = -1); -// SDL2 helper to create a WebGPU surface (exclusively!) for Native/Desktop applications: available only together with WebGPU/WGPU backend +// SDL2 helpers for native/desktop WebGPU applications. #if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) && !defined(__EMSCRIPTEN__) #include -WGPUSurface ImGui_ImplSDL2_CreateWGPUSurface_Helper(WGPUInstance instance, SDL_Window* window); +WGPUSurface ImGui_ImplSDL2_CreateWGPUSurface(WGPUInstance instance, SDL_Window* window); #endif #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 28b1df81a..df5d23a98 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -854,51 +854,50 @@ void ImGui_ImplSDL3_NewFrame() # include #endif -WGPUSurface ImGui_ImplSDL3_CreateWGPUSurface_Helper(WGPUInstance instance, SDL_Window* window) { +WGPUSurface ImGui_ImplSDL3_CreateWGPUSurface(WGPUInstance instance, SDL_Window* window) +{ SDL_PropertiesID propertiesID = SDL_GetWindowProperties(window); WGPUSurfaceDescriptor surfaceDescriptor = {}; - WGPUSurface surface = {}; #if defined(SDL_PLATFORM_MACOS) { id metal_layer = NULL; - NSWindow *ns_window = (__bridge NSWindow *)SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL); + NSWindow* ns_window = (__bridge NSWindow*)SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL); if (!ns_window) return NULL; [ns_window.contentView setWantsLayer : YES]; metal_layer = [CAMetalLayer layer]; [ns_window.contentView setLayer : metal_layer]; - WGPUSurfaceSourceMetalLayer surfaceMetal = {}; surfaceMetal.chain.sType = WGPUSType_SurfaceSourceMetalLayer; surfaceMetal.layer = metal_layer; - surfaceDescriptor.nextInChain = &surfaceMetal.chain; surface = wgpuInstanceCreateSurface(instance, &surfaceDescriptor); } #elif defined(SDL_PLATFORM_LINUX) - if (!SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland")) { - void *w_display = SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, NULL); - void *w_surface = SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL); - if (!w_display || !w_surface) return NULL; - + if (!SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland")) + { + void* w_display = SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, NULL); + void* w_surface = SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL); + if (!w_display || !w_surface) + return NULL; WGPUSurfaceSourceWaylandSurface surfaceWayland = {}; surfaceWayland.chain.sType = WGPUSType_SurfaceSourceWaylandSurface; surfaceWayland.display = w_display; surfaceWayland.surface = w_surface; - surfaceDescriptor.nextInChain = &surfaceWayland.chain; surface = wgpuInstanceCreateSurface(instance, &surfaceDescriptor); - } else if (!SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11")) { - void *x_display = SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL); + } + else if (!SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11")) + { + void* x_display = SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL); uint64_t x_window = SDL_GetNumberProperty(propertiesID, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); - if (!x_display || !x_window) return NULL; - + if (!x_display || !x_window) + return NULL; WGPUSurfaceSourceXlibWindow surfaceXlib = {}; surfaceXlib.chain.sType = WGPUSType_SurfaceSourceXlibWindow; surfaceXlib.display = x_display; - surfaceXlib.window = x_window; - + surfaceXlib.window = x_window; surfaceDescriptor.nextInChain = &surfaceXlib.chain; surface = wgpuInstanceCreateSurface(instance, &surfaceDescriptor); } @@ -906,19 +905,18 @@ WGPUSurface ImGui_ImplSDL3_CreateWGPUSurface_Helper(WGPUInstance instance, SDL_W #elif defined(SDL_PLATFORM_WIN32) { HWND hwnd = (HWND)SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); - if (!hwnd) return NULL; - HINSTANCE hinstance = GetModuleHandle(NULL); - + if (!hwnd) + return NULL; + HINSTANCE hinstance = ::GetModuleHandle(NULL); WGPUSurfaceSourceWindowsHWND surfaceHWND = {}; surfaceHWND.chain.sType = WGPUSType_SurfaceSourceWindowsHWND; surfaceHWND.hinstance = hinstance; surfaceHWND.hwnd = hwnd; - surfaceDescriptor.nextInChain = &surfaceHWND.chain; surface = wgpuInstanceCreateSurface(instance, &surfaceDescriptor); } #else - #error "Unsupported SDL3/WebGPU Backend" + #error "Unsupported SDL3+WebGPU Backend" #endif return surface; } diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index d515077f1..ef4cc93bc 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -44,10 +44,10 @@ IMGUI_IMPL_API bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event); enum ImGui_ImplSDL3_GamepadMode { ImGui_ImplSDL3_GamepadMode_AutoFirst, ImGui_ImplSDL3_GamepadMode_AutoAll, ImGui_ImplSDL3_GamepadMode_Manual }; IMGUI_IMPL_API void ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode mode, SDL_Gamepad** manual_gamepads_array = nullptr, int manual_gamepads_count = -1); -// SDL3 helper to create a WebGPU surface for Native/Desktop applications: available only with WebGPU/WGPU backend +// SDL2 helpers for native/desktop WebGPU applications. #if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) && !defined(__EMSCRIPTEN__) #include -WGPUSurface ImGui_ImplSDL3_CreateWGPUSurface_Helper(WGPUInstance instance, SDL_Window* window); +WGPUSurface ImGui_ImplSDL3_CreateWGPUSurface(WGPUInstance instance, SDL_Window* window); #endif #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 5d3d0a7bf..c021df74f 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -840,17 +840,17 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info) ImGui_ImplWGPU_Data* bd = IM_NEW(ImGui_ImplWGPU_Data)(); io.BackendRendererUserData = (void*)bd; #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) - #if defined(__EMSCRIPTEN__) - io.BackendRendererName = "imgui_impl_webgpu_dawn_emscripten"; // compiled & linked using EMSCRIPTEN with "--use-port=emdawnwebgpu" flag - #else - io.BackendRendererName = "imgui_impl_webgpu_dawn"; // DAWN-Native - #endif +#if defined(__EMSCRIPTEN__) + io.BackendRendererName = "imgui_impl_wgpu (Dawn, Emscripten)"; // compiled & linked using EMSCRIPTEN with "--use-port=emdawnwebgpu" flag +#else + io.BackendRendererName = "imgui_impl_wgpu (Dawn)"; // DAWN-Native +#endif #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) - #if defined(__EMSCRIPTEN__) - io.BackendRendererName = "imgui_impl_webgpu_wgpu_emscripten"; // linked using EMSCRIPTEN with "-sUSE_WEBGPU=1" flag, deprecated from EMSCRIPTEN 4.0.10 - #else - io.BackendRendererName = "imgui_impl_webgpu_wgpu"; // WGPU-Native - #endif +#if defined(__EMSCRIPTEN__) + io.BackendRendererName = "imgui_impl_wgpu (WGPU, Emscripten)"; // linked using EMSCRIPTEN with "-sUSE_WEBGPU=1" flag, deprecated from EMSCRIPTEN 4.0.10 +#else + io.BackendRendererName = "imgui_impl_wgpu (WGPU)"; // WGPU-Native +#endif #endif io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. @@ -915,74 +915,16 @@ void ImGui_ImplWGPU_NewFrame() IM_ASSERT(0 && "ImGui_ImplWGPU_CreateDeviceObjects() failed!"); } +//----------------------------------------------------------------------------- // WebGPU Helpers +//----------------------------------------------------------------------------- -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) -// DAWN Validation Layer callback: reason for device loss -void ImGui_ImplWGPU_DAWN_DeviceLostCallback_Helper(const wgpu::Device&, wgpu::DeviceLostReason reason, wgpu::StringView message) -{ - const char* reasonName = ""; - switch (reason) { - case wgpu::DeviceLostReason::Unknown: reasonName = "Unknown"; break; - case wgpu::DeviceLostReason::Destroyed: reasonName = "Destroyed"; break; - case wgpu::DeviceLostReason::CallbackCancelled: reasonName = "InstanceDropped"; break; - case wgpu::DeviceLostReason::FailedCreation: reasonName = "FailedCreation"; break; - default: reasonName = "UNREACHABLE"; break; - } - fprintf(stderr, "%s device message: %s\n", reasonName, message.data); -} -// DAWN Validation Layer callback: print error type -void ImGui_ImplWGPU_DAWN_ErrorCallback_Helper(const wgpu::Device&, wgpu::ErrorType type, wgpu::StringView message) -{ - const char* errorTypeName = ""; - switch (type) { - case wgpu::ErrorType::Validation: errorTypeName = "Validation"; break; - case wgpu::ErrorType::OutOfMemory: errorTypeName = "Out of memory"; break; - case wgpu::ErrorType::Unknown: errorTypeName = "Unknown"; break; - case wgpu::ErrorType::Internal: errorTypeName = "Internal"; break; - default: errorTypeName = "UNREACHABLE"; break; - } - fprintf(stderr, "%s error: %s\n", errorTypeName, message.data); -} -#elif !defined(__EMSCRIPTEN__) -// WGPU-Native LOG callback: print information based on request level -void ImGui_ImplWGPU_WGPU_LogCallback_Helper(WGPULogLevel level, WGPUStringView message, void *userdata) -{ - const char *level_str = ""; - switch (level) { - case WGPULogLevel_Error: level_str = "error"; break; - case WGPULogLevel_Warn: level_str = "warn"; break; - case WGPULogLevel_Info: level_str = "info"; break; - case WGPULogLevel_Debug: level_str = "debug"; break; - case WGPULogLevel_Trace: level_str = "trace"; break; - default: level_str = "unknown_level"; - } - fprintf(stderr, "[wgpu] [%s] %.*s\n", level_str, (int) message.length, message.data); -} -#endif - -/// Print Adapter info -///@param[in] adapter const WGPUAdapter & : reference to acquired and valid WGPUAdapter -///@note The function prints: "selected Adapter - drivers version, BackendType (#)" -void ImGui_ImplWGPU_PrintAdapterInfo_Helper(const WGPUAdapter &adapter) -{ - WGPUAdapterInfo info = {}; - wgpuAdapterGetInfo(adapter, &info); -#ifdef __EMSCRIPTEN__ - printf("BackendType (%u)\n", info.backendType); -#else - printf("Using: %.*s - %.*s, BackendType (%u)\n", (int) info.device.length, info.device.data, (int) info.description.length, info.description.data, info.backendType); -#endif -} - -/// Check if the Status of SurfaceTexture is Optimal -///@param[in] status WGPUSurfaceGetCurrentTextureStatus : current WGPUSurfaceTexture .status (value to check) -///@return true (bool) : SurfaceTexture have an optimal status and we can use it -///@return false (bool) : it's necessary to re-configure the SurfaceTexture -///@note : with "unrecoverable error" the program aborts +// Check if the status of surface texture is optimal +// Return true when the surface texture has an optimal status and we can use it, false if it's necessary to reconfigure the surface teture. +// FIXME: Can abort on unrecoverable errors. bool ImGui_ImplWGPU_CheckSurfaceTextureOptimalStatus_Helper(WGPUSurfaceGetCurrentTextureStatus status) { - switch ( status ) + switch (status) { #if defined(__EMSCRIPTEN__) && !defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) case WGPUSurfaceGetCurrentTextureStatus_Success: @@ -995,7 +937,6 @@ bool ImGui_ImplWGPU_CheckSurfaceTextureOptimalStatus_Helper(WGPUSurfaceGetCurren case WGPUSurfaceGetCurrentTextureStatus_Timeout: case WGPUSurfaceGetCurrentTextureStatus_Outdated: case WGPUSurfaceGetCurrentTextureStatus_Lost: - // if the status is NOT Optimal it's necessary try to reconfigure the surface return false; // Unrecoverable errors #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) @@ -1007,14 +948,75 @@ bool ImGui_ImplWGPU_CheckSurfaceTextureOptimalStatus_Helper(WGPUSurfaceGetCurren case WGPUSurfaceGetCurrentTextureStatus_Force32: // Fatal error fprintf(stderr, "Unrecoverable Error Check Surface Texture status=%#.8x\n", status); - abort(); - - default: // should never be reached + IM_ASSERT(0); + return false; + default: + // Should never be reached fprintf(stderr, "Unexpected Error Check Surface Texture status=%#.8x\n", status); - abort(); + IM_ASSERT(0); + return false; } } + +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) +// DAWN Validation Layer callback: reason for device loss +void ImGui_ImplWGPU_DAWN_DeviceLostCallback_Helper(const wgpu::Device&, wgpu::DeviceLostReason reason, wgpu::StringView msg) +{ + const char* reasonName = ""; + switch (reason) + { + case wgpu::DeviceLostReason::Unknown: reasonName = "Unknown"; break; + case wgpu::DeviceLostReason::Destroyed: reasonName = "Destroyed"; break; + case wgpu::DeviceLostReason::CallbackCancelled: reasonName = "InstanceDropped"; break; + case wgpu::DeviceLostReason::FailedCreation: reasonName = "FailedCreation"; break; + default: reasonName = "UNREACHABLE"; break; + } + fprintf(stderr, "%s device message: %s\n", reasonName, msg.data); +} +// DAWN Validation Layer callback: print error type +void ImGui_ImplWGPU_DAWN_ErrorCallback_Helper(const wgpu::Device&, wgpu::ErrorType type, wgpu::StringView msg) +{ + const char* errorTypeName = ""; + switch (type) + { + case wgpu::ErrorType::Validation: errorTypeName = "Validation"; break; + case wgpu::ErrorType::OutOfMemory: errorTypeName = "Out of memory"; break; + case wgpu::ErrorType::Unknown: errorTypeName = "Unknown"; break; + case wgpu::ErrorType::Internal: errorTypeName = "Internal"; break; + default: errorTypeName = "UNREACHABLE"; break; + } + fprintf(stderr, "%s error: %s\n", errorTypeName, msg.data); +} +#elif !defined(__EMSCRIPTEN__) +// WGPU-Native LOG callback: print information based on request level +void ImGui_ImplWGPU_WGPU_LogCallback_Helper(WGPULogLevel level, WGPUStringView msg, void* userdata) +{ + const char* level_str = ""; + switch (level) + { + case WGPULogLevel_Error: level_str = "error"; break; + case WGPULogLevel_Warn: level_str = "warn"; break; + case WGPULogLevel_Info: level_str = "info"; break; + case WGPULogLevel_Debug: level_str = "debug"; break; + case WGPULogLevel_Trace: level_str = "trace"; break; + default: level_str = "unknown_level"; + } + fprintf(stderr, "[wgpu] [%s] %.*s\n", level_str, (int)msg.length, msg.data); +} +#endif + +void ImGui_ImplWGPU_PrintAdapterInfo_Helper(const WGPUAdapter& adapter) +{ + WGPUAdapterInfo info = {}; + wgpuAdapterGetInfo(adapter, &info); +#ifdef __EMSCRIPTEN__ + printf("BackendType (%u)\n", info.backendType); +#else + printf("Using: %.*s - %.*s, BackendType (%u)\n", (int)info.device.length, info.device.data, (int)info.description.length, info.description.data, info.backendType); +#endif +} + //----------------------------------------------------------------------------- #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index 51be03f96..167a9580c 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -28,13 +28,10 @@ #ifndef IMGUI_DISABLE #include - #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) -// DAWN "wgpu::" classes (e.g. used in Validation Layers Callbacks) -#include +#include // for wgpu::Device, wgpu::DeviceLostReason, wgpu::ErrorType used by validation layer callbacks. #elif !defined(__EMSCRIPTEN__) -// WGPU-Native specific data structure (e.g. used in WGPULogLevel) -#include +#include // WGPULogLevel #endif // Initialization data, for ImGui_ImplWGPU_Init() @@ -76,20 +73,14 @@ struct ImGui_ImplWGPU_RenderState WGPURenderPassEncoder RenderPassEncoder; }; -// WebGPU Helpers - -// Check if the Status of SurfaceTexture is Optimal -bool ImGui_ImplWGPU_CheckSurfaceTextureOptimalStatus_Helper(WGPUSurfaceGetCurrentTextureStatus status); -// Print Adapter info -void ImGui_ImplWGPU_PrintAdapterInfo_Helper(const WGPUAdapter &adapter); +// (Optional) WebGPU Helpers +bool ImGui_ImplWGPU_CheckSurfaceTextureOptimalStatus_Helper(WGPUSurfaceGetCurrentTextureStatus status); // Check if the status of surface texture is optimal +void ImGui_ImplWGPU_PrintAdapterInfo_Helper(const WGPUAdapter& adapter); #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) // DAWN both Native / EMSCRIPTEN -// DAWN Validation Layer callback: reason for device loss -void ImGui_ImplWGPU_DAWN_DeviceLostCallback_Helper(const wgpu::Device&, wgpu::DeviceLostReason reason, wgpu::StringView message); -// DAWN Validation Layer callback: print error type -void ImGui_ImplWGPU_DAWN_ErrorCallback_Helper(const wgpu::Device&, wgpu::ErrorType type, wgpu::StringView message); +void ImGui_ImplWGPU_DAWN_DeviceLostCallback_Helper(const wgpu::Device&, wgpu::DeviceLostReason reason, wgpu::StringView msg);// DAWN Validation Layer callback: reason for device loss +void ImGui_ImplWGPU_DAWN_ErrorCallback_Helper(const wgpu::Device&, wgpu::ErrorType type, wgpu::StringView msg); // DAWN Validation Layer callback: print error type #elif !defined(__EMSCRIPTEN__) // WGPU-Native -// WGPU-Native LOG callback: print information based on request level -void ImGui_ImplWGPU_WGPU_LogCallback_Helper(WGPULogLevel level, WGPUStringView message, void *userdata); +void ImGui_ImplWGPU_WGPU_LogCallback_Helper(WGPULogLevel level, WGPUStringView msg, void* userdata); // WGPU-Native log callback: print information based on request level. #endif #endif // #ifndef IMGUI_DISABLE diff --git a/examples/example_glfw_wgpu/main.cpp b/examples/example_glfw_wgpu/main.cpp index 0c1570958..342dccd53 100644 --- a/examples/example_glfw_wgpu/main.cpp +++ b/examples/example_glfw_wgpu/main.cpp @@ -1,4 +1,4 @@ -// Dear ImGui: standalone example application for using GLFW + WebGPU +// Dear ImGui: standalone example application for GLFW + WebGPU // - Emscripten is supported for publishing on web. See https://emscripten.org. // - Dawn is used as a WebGPU implementation on desktop. @@ -13,24 +13,25 @@ #include "imgui_impl_wgpu.h" #include #include - #include + +// This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details. #ifdef __EMSCRIPTEN__ - #include - #include - #if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) - #include - #endif - #include - #include - #include "../libs/emscripten/emscripten_mainloop_stub.h" +#include +#include +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) +#include +#endif +#include +#include +#include "../libs/emscripten/emscripten_mainloop_stub.h" #else - #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) - #include - #endif +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) +#include +#endif #endif -// Global WebGPU required states +// Data static WGPUInstance wgpu_instance = nullptr; static WGPUDevice wgpu_device = nullptr; static WGPUSurface wgpu_surface = nullptr; @@ -51,15 +52,14 @@ static void ResizeSurface(int width, int height) { wgpu_surface_configuration.width = wgpu_surface_width = width; wgpu_surface_configuration.height = wgpu_surface_height = height; - wgpuSurfaceConfigure(wgpu_surface, &wgpu_surface_configuration); } -static void ReleaseTextureAndConfigureSurface(WGPUTexture &texture, int fb_width, int fb_height) +static void ReleaseTextureAndConfigureSurface(WGPUTexture& texture, int fb_width, int fb_height) { if (texture) wgpuTextureRelease(texture); - if ( fb_width > 0 && fb_height > 0 ) + if (fb_width > 0 && fb_height > 0) ResizeSurface(fb_width, fb_height); } @@ -68,21 +68,26 @@ int main(int, char**) { glfwSetErrorCallback(glfw_error_callback); if (!glfwInit()) - return EXIT_FAILURE; + return 1; // Make sure GLFW does not initialize any graphics context. // This needs to be done explicitly later. glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + + // Create window + float main_scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor()); // Valid on GLFW 3.3+ only // FIXME-WGPU: Verify + wgpu_surface_width *= main_scale; + wgpu_surface_height *= main_scale; GLFWwindow* window = glfwCreateWindow(wgpu_surface_width, wgpu_surface_height, "Dear ImGui GLFW+WebGPU example", nullptr, nullptr); if (window == nullptr) - return EXIT_FAILURE; + return 1; // Initialize the WebGPU environment if (!InitWGPU(window)) { glfwDestroyWindow(window); glfwTerminate(); - return EXIT_FAILURE; + return 1; } glfwShowWindow(window); @@ -98,6 +103,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplGlfw_InitForOther(window, true); #ifdef __EMSCRIPTEN__ @@ -114,19 +124,18 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. If you like the default font but want it to scale better, consider using the 'ProggyVector' from the same author! // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - // - Emscripten allows preloading a file or folder to be accessible at runtime. See Makefile for details. + // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); #ifndef IMGUI_DISABLE_FILE_FUNCTIONS - //io.Fonts->AddFontFromFileTTF("fonts/segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf", 15.0f); - //io.Fonts->AddFontFromFileTTF("fonts/ProggyTiny.ttf", 10.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); #endif @@ -162,7 +171,7 @@ int main(int, char**) glfwGetFramebufferSize((GLFWwindow*)window, &width, &height); if (width != wgpu_surface_width || height != wgpu_surface_height) { - ImGui_ImplWGPU_InvalidateDeviceObjects(); + ImGui_ImplWGPU_InvalidateDeviceObjects(); // FIXME-WGPU: Why doing this? this will recreate all font textures etc. ResizeSurface(width, height); ImGui_ImplWGPU_CreateDeviceObjects(); } @@ -170,8 +179,9 @@ int main(int, char**) WGPUSurfaceTexture surfaceTexture; wgpuSurfaceGetCurrentTexture(wgpu_surface, &surfaceTexture); - // Check SurfaceTexture status, if NOT optimal status we try to re-configure Surface - if (!ImGui_ImplWGPU_CheckSurfaceTextureOptimalStatus_Helper(surfaceTexture.status)) { + // Check if surface texture is not optimal and try to re-configure Surface + if (!ImGui_ImplWGPU_CheckSurfaceTextureOptimalStatus_Helper(surfaceTexture.status)) + { ReleaseTextureAndConfigureSurface(surfaceTexture.texture, width, height); continue; } @@ -284,17 +294,17 @@ int main(int, char**) glfwDestroyWindow(window); glfwTerminate(); - return EXIT_SUCCESS; + return 0; } - #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) -static WGPUAdapter GetAdapter(wgpu::Instance &instance) +static WGPUAdapter GetAdapter(wgpu::Instance& instance) { wgpu::Adapter acquiredAdapter; wgpu::RequestAdapterOptions adapterOptions; - auto onRequestAdapter = [&](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter, wgpu::StringView message) { + auto onRequestAdapter = [&](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter, wgpu::StringView message) + { if (status != wgpu::RequestAdapterStatus::Success) { printf("Failed to get an adapter: %s\n", message.data); @@ -306,7 +316,7 @@ static WGPUAdapter GetAdapter(wgpu::Instance &instance) // Synchronously (wait until) acquire Adapter wgpu::Future waitAdapterFunc { instance.RequestAdapter(&adapterOptions, wgpu::CallbackMode::WaitAnyOnly, onRequestAdapter) }; wgpu::WaitStatus waitStatusAdapter = instance.WaitAny(waitAdapterFunc, UINT64_MAX); - assert(acquiredAdapter != nullptr && waitStatusAdapter == wgpu::WaitStatus::Success && "Error on Adapter request"); + IM_ASSERT(acquiredAdapter != nullptr && waitStatusAdapter == wgpu::WaitStatus::Success && "Error on Adapter request"); #ifndef NDEBUG ImGui_ImplWGPU_PrintAdapterInfo_Helper(acquiredAdapter.Get()); #endif @@ -321,7 +331,8 @@ static WGPUDevice GetDevice(wgpu::Instance &instance, wgpu::Adapter &adapter) deviceDesc.SetUncapturedErrorCallback(ImGui_ImplWGPU_DAWN_ErrorCallback_Helper); wgpu::Device acquiredDevice; - auto onRequestDevice = [&](wgpu::RequestDeviceStatus status, wgpu::Device localDevice, wgpu::StringView message) { + auto onRequestDevice = [&](wgpu::RequestDeviceStatus status, wgpu::Device localDevice, wgpu::StringView message) + { if (status != wgpu::RequestDeviceStatus::Success) { printf("Failed to get an device: %s\n", message.data); @@ -333,7 +344,7 @@ static WGPUDevice GetDevice(wgpu::Instance &instance, wgpu::Adapter &adapter) // Synchronously (wait until) get Device wgpu::Future waitDeviceFunc { adapter.RequestDevice(&deviceDesc, wgpu::CallbackMode::WaitAnyOnly, onRequestDevice) }; wgpu::WaitStatus waitStatusDevice = instance.WaitAny(waitDeviceFunc, UINT64_MAX); - assert(acquiredDevice != nullptr && waitStatusDevice == wgpu::WaitStatus::Success && "Error on Device request"); + IM_ASSERT(acquiredDevice != nullptr && waitStatusDevice == wgpu::WaitStatus::Success && "Error on Device request"); return acquiredDevice.MoveToCHandle(); } #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) @@ -348,29 +359,33 @@ EM_ASYNC_JS( void, getAdapterAndDeviceViaJS, (), Module.preinitializedWebGPUDevice = device; } ); #else // __EMSCRIPTEN__ -static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void *userdata1, void *userdata2) +static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) { if (status == WGPURequestAdapterStatus_Success) { - WGPUAdapter *extAdapter = (WGPUAdapter *) userdata1; + WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1; *extAdapter = adapter; } else + { printf("Request_adapter status=%#.8x message=%.*s\n", status, (int) message.length, message.data); + } } -static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void *userdata1, void *userdata2) +static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2) { if (status == WGPURequestDeviceStatus_Success) { - WGPUDevice *extDevice = (WGPUDevice *) userdata1; + WGPUDevice* extDevice = (WGPUDevice*)userdata1; *extDevice = device; } else + { printf("Request_device status=%#.8x message=%.*s\n", status, (int) message.length, message.data); + } } -static WGPUAdapter GetAdapter(WGPUInstance &instance) +static WGPUAdapter GetAdapter(WGPUInstance& instance) { WGPURequestAdapterOptions adapterOptions = {}; @@ -380,8 +395,8 @@ static WGPUAdapter GetAdapter(WGPUInstance &instance) adapterCallbackInfo.userdata1 = &localAdapter; wgpuInstanceRequestAdapter(wgpu_instance, &adapterOptions, adapterCallbackInfo); - assert(localAdapter && "Error on Adapter request"); + IM_ASSERT(localAdapter && "Error on Adapter request"); #ifndef NDEBUG ImGui_ImplWGPU_PrintAdapterInfo_Helper(localAdapter); #endif @@ -389,7 +404,7 @@ static WGPUAdapter GetAdapter(WGPUInstance &instance) return localAdapter; } -static WGPUDevice GetDevice(WGPUAdapter &adapter) +static WGPUDevice GetDevice(WGPUAdapter& adapter) { static WGPUDevice localDevice; WGPURequestDeviceCallbackInfo deviceCallbackInfo = {}; @@ -397,7 +412,7 @@ static WGPUDevice GetDevice(WGPUAdapter &adapter) deviceCallbackInfo.userdata1 = &localDevice; wgpuAdapterRequestDevice(adapter, NULL, deviceCallbackInfo); - assert(localDevice && "Error on Device request"); + IM_ASSERT(localDevice && "Error on Device request"); return localDevice; } @@ -426,7 +441,7 @@ static bool InitWGPU(void* window) surfaceDesc.nextInChain = &canvasDesc; wgpu::Surface surface = instance.CreateSurface(&surfaceDesc); #else - wgpu::Surface surface = wgpu::glfw::CreateSurfaceForWindow(instance, (GLFWwindow *) window); + wgpu::Surface surface = wgpu::glfw::CreateSurfaceForWindow(instance, (GLFWwindow*)window); #endif if (!surface) return false; @@ -448,7 +463,7 @@ static bool InitWGPU(void* window) getAdapterAndDeviceViaJS(); wgpu_device = emscripten_webgpu_get_device(); - assert(wgpu_device != nullptr && "Error creating the Device"); + IM_ASSERT(wgpu_device != nullptr && "Error creating the Device"); WGPUSurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {}; html_surface_desc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector; @@ -468,8 +483,7 @@ static bool InitWGPU(void* window) wgpu_device = GetDevice(adapter); // Create the surface. - wgpu_surface = ImGui_ImplGLFW_CreateWGPUSurface_Helper( wgpu_instance, (GLFWwindow*) window); - + wgpu_surface = ImGui_ImplGLFW_CreateWGPUSurface(wgpu_instance, (GLFWwindow*)window); if (!wgpu_surface) return false; @@ -489,7 +503,6 @@ static bool InitWGPU(void* window) wgpu_surface_configuration.format = preferred_fmt; wgpuSurfaceConfigure(wgpu_surface, &wgpu_surface_configuration); - wgpu_queue = wgpuDeviceGetQueue(wgpu_device); return true; diff --git a/examples/example_sdl2_wgpu/main.cpp b/examples/example_sdl2_wgpu/main.cpp index bdcc5a6c6..6237c333c 100755 --- a/examples/example_sdl2_wgpu/main.cpp +++ b/examples/example_sdl2_wgpu/main.cpp @@ -1,4 +1,4 @@ -// Dear ImGui: standalone example application for using GLFW + WebGPU +// Dear ImGui: standalone example application for using SDL2 + WebGPU // - Emscripten is supported for publishing on web. See https://emscripten.org. // - Dawn is used as a WebGPU implementation on desktop. @@ -8,40 +8,35 @@ // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). // - Introduction, links and more at the top of imgui.cpp - #include "imgui.h" #include "imgui_impl_sdl2.h" #include "imgui_impl_wgpu.h" #include - -#ifdef __EMSCRIPTEN__ -#include -#include - #if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) - #include - #endif - -#include "../libs/emscripten/emscripten_mainloop_stub.h" -#endif - #include -#include -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) - #include -#endif // This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details. #ifdef __EMSCRIPTEN__ +#include +#include +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) +#include +#endif +#include "../libs/emscripten/emscripten_mainloop_stub.h" #endif -// Global WebGPU required states +#include +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) +#include +#endif + +// Data WGPUInstance wgpu_instance = nullptr; WGPUDevice wgpu_device = nullptr; WGPUSurface wgpu_surface = nullptr; WGPUQueue wgpu_queue = nullptr; WGPUSurfaceConfiguration wgpu_surface_configuration {}; int wgpu_surface_width = 1280; -int wgpu_surface_height = 720; +int wgpu_surface_height = 800; // Forward declarations static bool InitWGPU(void* window); @@ -50,33 +45,33 @@ static void ResizeSurface(int width, int height) { wgpu_surface_configuration.width = wgpu_surface_width = width; wgpu_surface_configuration.height = wgpu_surface_height = height; - - wgpuSurfaceConfigure( wgpu_surface, (WGPUSurfaceConfiguration *) &wgpu_surface_configuration ); + wgpuSurfaceConfigure(wgpu_surface, (WGPUSurfaceConfiguration*)&wgpu_surface_configuration); } -static void ReleaseTextureAndConfigureSurface(WGPUTexture &texture, int fb_width, int fb_height) +static void ReleaseTextureAndConfigureSurface(WGPUTexture& texture, int fb_width, int fb_height) { if (texture) wgpuTextureRelease(texture); - if ( fb_width > 0 && fb_height > 0 ) + if (fb_width > 0 && fb_height > 0) ResizeSurface(fb_width, fb_height); } // Main code int main(int, char**) { + // Setup SDL #if defined(__linux__) - // it's necessary to specify "x11" or "wayland": default is "x11" it works also in wayland + // It's necessary to specify "x11" or "wayland": default is "x11" it works also in wayland + // Or comment the line and export SDL_VIDEODRIVER environment variable: + // export SDL_VIDEODRIVER=wayland // To set wayland session type + // export SDL_VIDEODRIVER=$XDG_SESSION_TYPE // To get current session type from WM: x11 | wayland SDL_SetHint(SDL_HINT_VIDEODRIVER, "x11"); - // or comment the previous line and export SDL_VIDEODRIVER environment variable: - // export SDL_VIDEODRIVER=wayland (to set wayland session type) - // export SDL_VIDEODRIVER=$XDG_SESSION_TYPE (to get current session type from WM: x11 | wayland) #endif - // Init SDL - SDL_Init(SDL_INIT_VIDEO); - SDL_Window *window = SDL_CreateWindow("Dear ImGui SDL2+WebGPU example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, wgpu_surface_width, wgpu_surface_height, SDL_WINDOW_RESIZABLE); + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER); + // Create window + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+WebGPU example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, wgpu_surface_width, wgpu_surface_height, SDL_WINDOW_RESIZABLE); // Initialize WGPU InitWGPU(window); @@ -92,9 +87,13 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplSDL2_InitForOther(window); - ImGui_ImplWGPU_InitInfo init_info; init_info.Device = wgpu_device; init_info.NumFramesInFlight = 3; @@ -106,19 +105,18 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. - // - Read 'docs/FONTS.md' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. If you like the default font but want it to scale better, consider using the 'ProggyVector' from the same author! // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - // - Emscripten allows preloading a file or folder to be accessible at runtime. See Makefile for details. + // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); #ifndef IMGUI_DISABLE_FILE_FUNCTIONS - //io.Fonts->AddFontFromFileTTF("fonts/segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf", 15.0f); - //io.Fonts->AddFontFromFileTTF("fonts/ProggyTiny.ttf", 10.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); #endif @@ -127,48 +125,48 @@ int main(int, char**) bool show_another_window = false; ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); - SDL_Event event; - bool canCloseWindow = false; // Main loop + bool done = false; #ifdef __EMSCRIPTEN__ // For an Emscripten build we are disabling file-system access, so let's not attempt to do a fopen() of the imgui.ini file. // You may manually call LoadIniSettingsFromMemory() to load settings from your own storage. io.IniFilename = nullptr; EMSCRIPTEN_MAINLOOP_BEGIN #else - while (!canCloseWindow) + while (!done) #endif { - while (SDL_PollEvent(&event)) - { - ImGui_ImplSDL2_ProcessEvent(&event); - if (event.type == SDL_QUIT || - (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && - event.window.windowID == SDL_GetWindowID(window))) - canCloseWindow = true; - } // Poll and handle events (inputs, window resize, etc.) // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. + SDL_Event event; + while (SDL_PollEvent(&event)) + { + ImGui_ImplSDL2_ProcessEvent(&event); + if (event.type == SDL_QUIT) + done = true; + if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) + done = true; + } // React to changes in screen size int width, height; SDL_GetWindowSize(window, &width, &height); if (width != wgpu_surface_width || height != wgpu_surface_height) { - ImGui_ImplWGPU_InvalidateDeviceObjects(); + ImGui_ImplWGPU_InvalidateDeviceObjects(); // FIXME-WGPU: Why doing this? this will recreate all font textures etc. ResizeSurface(width, height); ImGui_ImplWGPU_CreateDeviceObjects(); - //continue; } WGPUSurfaceTexture surfaceTexture; wgpuSurfaceGetCurrentTexture(wgpu_surface, &surfaceTexture); - // Check SurfaceTexture status, if NOT optimal status we try to re-configure Surface - if (!ImGui_ImplWGPU_CheckSurfaceTextureOptimalStatus_Helper(surfaceTexture.status)) { + // Check if surface texture is not optimal and try to re-configure Surface + if (!ImGui_ImplWGPU_CheckSurfaceTextureOptimalStatus_Helper(surfaceTexture.status)) + { ReleaseTextureAndConfigureSurface(surfaceTexture.texture, width, height); continue; } @@ -277,20 +275,20 @@ int main(int, char**) wgpuDeviceRelease(wgpu_device); wgpuInstanceRelease(wgpu_instance); - // Terminate SDL SDL_DestroyWindow(window); SDL_Quit(); - return EXIT_SUCCESS; + return 0; } #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) -static WGPUAdapter GetAdapter(wgpu::Instance &instance) +static WGPUAdapter GetAdapter(wgpu::Instance& instance) { wgpu::Adapter acquiredAdapter; wgpu::RequestAdapterOptions adapterOptions; - auto onRequestAdapter = [&](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter, wgpu::StringView message) { + auto onRequestAdapter = [&](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter, wgpu::StringView message) + { if (status != wgpu::RequestAdapterStatus::Success) { printf("Failed to get an adapter: %s\n", message.data); @@ -302,7 +300,7 @@ static WGPUAdapter GetAdapter(wgpu::Instance &instance) // Synchronously (wait until) acquire Adapter wgpu::Future waitAdapterFunc { instance.RequestAdapter(&adapterOptions, wgpu::CallbackMode::WaitAnyOnly, onRequestAdapter) }; wgpu::WaitStatus waitStatusAdapter = instance.WaitAny(waitAdapterFunc, UINT64_MAX); - assert(acquiredAdapter != nullptr && waitStatusAdapter == wgpu::WaitStatus::Success && "Error on Adapter request"); + IM_ASSERT(acquiredAdapter != nullptr && waitStatusAdapter == wgpu::WaitStatus::Success && "Error on Adapter request"); #ifndef NDEBUG ImGui_ImplWGPU_PrintAdapterInfo_Helper(acquiredAdapter.Get()); #endif @@ -317,7 +315,8 @@ static WGPUDevice GetDevice(wgpu::Instance &instance, wgpu::Adapter &adapter) deviceDesc.SetUncapturedErrorCallback(ImGui_ImplWGPU_DAWN_ErrorCallback_Helper); wgpu::Device acquiredDevice; - auto onRequestDevice = [&](wgpu::RequestDeviceStatus status, wgpu::Device localDevice, wgpu::StringView message) { + auto onRequestDevice = [&](wgpu::RequestDeviceStatus status, wgpu::Device localDevice, wgpu::StringView message) + { if (status != wgpu::RequestDeviceStatus::Success) { printf("Failed to get an device: %s\n", message.data); @@ -329,7 +328,7 @@ static WGPUDevice GetDevice(wgpu::Instance &instance, wgpu::Adapter &adapter) // Synchronously (wait until) get Device wgpu::Future waitDeviceFunc { adapter.RequestDevice(&deviceDesc, wgpu::CallbackMode::WaitAnyOnly, onRequestDevice) }; wgpu::WaitStatus waitStatusDevice = instance.WaitAny(waitDeviceFunc, UINT64_MAX); - assert(acquiredDevice != nullptr && waitStatusDevice == wgpu::WaitStatus::Success && "Error on Device request"); + IM_ASSERT(acquiredDevice != nullptr && waitStatusDevice == wgpu::WaitStatus::Success && "Error on Device request"); return acquiredDevice.MoveToCHandle(); } #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) @@ -337,36 +336,40 @@ static WGPUDevice GetDevice(wgpu::Instance &instance, wgpu::Adapter &adapter) // Adapter and device initialization via JS EM_ASYNC_JS( void, getAdapterAndDeviceViaJS, (), { - if (!navigator.gpu) throw Error("WebGPU not supported."); - + if (!navigator.gpu) + throw Error("WebGPU not supported."); const adapter = await navigator.gpu.requestAdapter(); const device = await adapter.requestDevice(); Module.preinitializedWebGPUDevice = device; } ); #else // __EMSCRIPTEN__ -static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void *userdata1, void *userdata2) +static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) { if (status == WGPURequestAdapterStatus_Success) { - WGPUAdapter *extAdapter = (WGPUAdapter *) userdata1; + WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1; *extAdapter = adapter; } else - printf("Request_adapter status=%#.8x message=%.*s\n", status, (int) message.length, message.data); + { + printf("Request_adapter status=%#.8x message=%.*s\n", status, (int)message.length, message.data); + } } -static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void *userdata1, void *userdata2) +static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2) { if (status == WGPURequestDeviceStatus_Success) { - WGPUDevice *extDevice = (WGPUDevice *) userdata1; + WGPUDevice* extDevice = (WGPUDevice*)userdata1; *extDevice = device; } else - printf("Request_device status=%#.8x message=%.*s\n", status, (int) message.length, message.data); + { + printf("Request_device status=%#.8x message=%.*s\n", status, (int)message.length, message.data); + } } -static WGPUAdapter GetAdapter(WGPUInstance &instance) +static WGPUAdapter GetAdapter(WGPUInstance& instance) { WGPURequestAdapterOptions adapterOptions = {}; @@ -376,7 +379,7 @@ static WGPUAdapter GetAdapter(WGPUInstance &instance) adapterCallbackInfo.userdata1 = &localAdapter; wgpuInstanceRequestAdapter(wgpu_instance, &adapterOptions, adapterCallbackInfo); - assert(localAdapter && "Error on Adapter request"); + IM_ASSERT(localAdapter && "Error on Adapter request"); #ifndef NDEBUG ImGui_ImplWGPU_PrintAdapterInfo_Helper(localAdapter); @@ -393,7 +396,7 @@ static WGPUDevice GetDevice(WGPUAdapter &adapter) deviceCallbackInfo.userdata1 = &localDevice; wgpuAdapterRequestDevice(adapter, NULL, deviceCallbackInfo); - assert(localDevice && "Error on Device request"); + IM_ASSERT(localDevice && "Error on Device request"); return localDevice; } @@ -420,9 +423,9 @@ static bool InitWGPU(void* window) wgpu::SurfaceDescriptor surfaceDesc = {}; surfaceDesc.nextInChain = &canvasDesc; - wgpu::Surface surface = instance.CreateSurface(&surfaceDesc) ; + wgpu::Surface surface = instance.CreateSurface(&surfaceDesc); #else - wgpu::Surface surface = ImGui_ImplSDL2_CreateWGPUSurface_Helper(instance.Get(), (SDL_Window *) window); + wgpu::Surface surface = ImGui_ImplSDL2_CreateWGPUSurface(instance.Get(), (SDL_Window*)window); #endif if (!surface) return false; @@ -464,8 +467,7 @@ static bool InitWGPU(void* window) wgpu_device = GetDevice(adapter); // Create the surface. - wgpu_surface = ImGui_ImplSDL2_CreateWGPUSurface_Helper(wgpu_instance, (SDL_Window *) window); - + wgpu_surface = ImGui_ImplSDL2_CreateWGPUSurface(wgpu_instance, (SDL_Window*)window); if (!wgpu_surface) return false; diff --git a/examples/example_sdl3_wgpu/main.cpp b/examples/example_sdl3_wgpu/main.cpp index 4642de47f..cc373855f 100755 --- a/examples/example_sdl3_wgpu/main.cpp +++ b/examples/example_sdl3_wgpu/main.cpp @@ -1,4 +1,4 @@ -// Dear ImGui: standalone example application for using GLFW + WebGPU +// Dear ImGui: standalone example application for using SDL3 + WebGPU // - Emscripten is supported for publishing on web. See https://emscripten.org. // - Dawn is used as a WebGPU implementation on desktop. @@ -14,36 +14,31 @@ #include "imgui_impl_wgpu.h" #include #include - -#ifdef __EMSCRIPTEN__ -#include -#include - #if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) - #include - #endif - -#include "../libs/emscripten/emscripten_mainloop_stub.h" -#endif - #include -#include -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) - #include -#endif - // This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details. #ifdef __EMSCRIPTEN__ +#include +#include +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) +#include +#endif +#include "../libs/emscripten/emscripten_mainloop_stub.h" #endif -// Global WebGPU required states +#include +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) +#include +#endif + +// Data WGPUInstance wgpu_instance = nullptr; WGPUDevice wgpu_device = nullptr; WGPUSurface wgpu_surface = nullptr; WGPUQueue wgpu_queue = nullptr; WGPUSurfaceConfiguration wgpu_surface_configuration {}; int wgpu_surface_width = 1280; -int wgpu_surface_height = 720; +int wgpu_surface_height = 800; // Forward declarations static bool InitWGPU(void* window); @@ -52,38 +47,36 @@ void ResizeSurface(int width, int height) { wgpu_surface_configuration.width = wgpu_surface_width = width; wgpu_surface_configuration.height = wgpu_surface_height = height; - - wgpuSurfaceConfigure( wgpu_surface, (WGPUSurfaceConfiguration *) &wgpu_surface_configuration ); + wgpuSurfaceConfigure( wgpu_surface, (WGPUSurfaceConfiguration*)&wgpu_surface_configuration ); } -static void ReleaseTextureAndConfigureSurface(WGPUTexture &texture, int fb_width, int fb_height) +static void ReleaseTextureAndConfigureSurface(WGPUTexture& texture, int fb_width, int fb_height) { if (texture) wgpuTextureRelease(texture); - if ( fb_width > 0 && fb_height > 0 ) + if (fb_width > 0 && fb_height > 0) ResizeSurface(fb_width, fb_height); } // Main code int main(int, char**) { -#if defined(__linux__) - // SDL3 default is "x11" (it works also in "wayland"), uncomment the line below to use "wayland" - // SDL_SetHint(SDL_HINT_VIDEO_DRIVER, "wayland"); -#endif - - // Init SDL - if (!SDL_Init(SDL_INIT_VIDEO )) + // Setup SDL + // [If using SDL_MAIN_USE_CALLBACKS: all code below until the main loop starts would likely be your SDL_AppInit() function] + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) { printf("Error: SDL_Init(): %s\n", SDL_GetError()); - return EXIT_FAILURE; + return 1; } + + // Create SDL window graphics context + float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); // FIXME-WGPU: Test this? SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE; SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+WebGPU example", wgpu_surface_width, wgpu_surface_height, window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); - return EXIT_FAILURE; + return 1; } // Initialize WGPU @@ -100,6 +93,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplSDL3_InitForOther(window); @@ -114,19 +112,18 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. - // - Read 'docs/FONTS.md' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. If you like the default font but want it to scale better, consider using the 'ProggyVector' from the same author! // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - // - Emscripten allows preloading a file or folder to be accessible at runtime. See Makefile for details. + // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); #ifndef IMGUI_DISABLE_FILE_FUNCTIONS - //io.Fonts->AddFontFromFileTTF("fonts/segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf", 15.0f); - //io.Fonts->AddFontFromFileTTF("fonts/ProggyTiny.ttf", 10.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); #endif @@ -135,47 +132,50 @@ int main(int, char**) bool show_another_window = false; ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); - SDL_Event event; - bool canCloseWindow = false; // Main loop + bool done = false; #ifdef __EMSCRIPTEN__ // For an Emscripten build we are disabling file-system access, so let's not attempt to do a fopen() of the imgui.ini file. // You may manually call LoadIniSettingsFromMemory() to load settings from your own storage. io.IniFilename = nullptr; EMSCRIPTEN_MAINLOOP_BEGIN #else - while (!canCloseWindow) + while (!done) #endif { - while (SDL_PollEvent(&event)) - { - ImGui_ImplSDL3_ProcessEvent(&event); - if (event.type == SDL_EVENT_QUIT || - (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window))) - canCloseWindow = true; - } // Poll and handle events (inputs, window resize, etc.) // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. + // [If using SDL_MAIN_USE_CALLBACKS: call ImGui_ImplSDL3_ProcessEvent() from your SDL_AppEvent() function] + SDL_Event event; + while (SDL_PollEvent(&event)) + { + ImGui_ImplSDL3_ProcessEvent(&event); + if (event.type == SDL_EVENT_QUIT) + done = true; + if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) + done = true; + } + // [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppIterate() function] // React to changes in screen size int width, height; SDL_GetWindowSize(window, &width, &height); if (width != wgpu_surface_width || height != wgpu_surface_height) { - ImGui_ImplWGPU_InvalidateDeviceObjects(); + ImGui_ImplWGPU_InvalidateDeviceObjects(); // FIXME-WGPU: Why doing this? this will recreate all font textures etc. ResizeSurface(width, height); ImGui_ImplWGPU_CreateDeviceObjects(); - //continue; } WGPUSurfaceTexture surfaceTexture; wgpuSurfaceGetCurrentTexture(wgpu_surface, &surfaceTexture); - // Check SurfaceTexture status, if NOT optimal status we try to re-configure Surface - if (!ImGui_ImplWGPU_CheckSurfaceTextureOptimalStatus_Helper(surfaceTexture.status)) { + // Check if surface texture is not optimal and try to re-configure Surface + if (!ImGui_ImplWGPU_CheckSurfaceTextureOptimalStatus_Helper(surfaceTexture.status)) + { ReleaseTextureAndConfigureSurface(surfaceTexture.texture, width, height); continue; } @@ -274,6 +274,7 @@ int main(int, char**) #endif // Cleanup + // [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppQuit() function] ImGui_ImplWGPU_Shutdown(); ImGui_ImplSDL3_Shutdown(); ImGui::DestroyContext(); @@ -284,39 +285,39 @@ int main(int, char**) wgpuDeviceRelease(wgpu_device); wgpuInstanceRelease(wgpu_instance); - // Terminate SDL SDL_DestroyWindow(window); SDL_Quit(); - return EXIT_SUCCESS; + return 0; } #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) -static WGPUAdapter GetAdapter(wgpu::Instance &instance) +static WGPUAdapter GetAdapter(wgpu::Instance& instance) { wgpu::Adapter acquiredAdapter; wgpu::RequestAdapterOptions adapterOptions; - auto onRequestAdapter = [&](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter, wgpu::StringView message) { + auto onRequestAdapter = [&](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter, wgpu::StringView message) + { if (status != wgpu::RequestAdapterStatus::Success) { printf("Failed to get an adapter: %s\n", message.data); return; } - acquiredAdapter = std::move(adapter); + acquiredAdapter = std::move(adapter); // FIXME-WGPU: no need to use std::move? }; // Synchronously (wait until) acquire Adapter wgpu::Future waitAdapterFunc { instance.RequestAdapter(&adapterOptions, wgpu::CallbackMode::WaitAnyOnly, onRequestAdapter) }; wgpu::WaitStatus waitStatusAdapter = instance.WaitAny(waitAdapterFunc, UINT64_MAX); - assert(acquiredAdapter != nullptr && waitStatusAdapter == wgpu::WaitStatus::Success && "Error on Adapter request"); + IM_ASSERT(acquiredAdapter != nullptr && waitStatusAdapter == wgpu::WaitStatus::Success && "Error on Adapter request"); #ifndef NDEBUG ImGui_ImplWGPU_PrintAdapterInfo_Helper(acquiredAdapter.Get()); #endif return acquiredAdapter.MoveToCHandle(); } -static WGPUDevice GetDevice(wgpu::Instance &instance, wgpu::Adapter &adapter) +static WGPUDevice GetDevice(wgpu::Instance &instance, wgpu::Adapter& adapter) { // Set device callback functions wgpu::DeviceDescriptor deviceDesc; @@ -324,7 +325,8 @@ static WGPUDevice GetDevice(wgpu::Instance &instance, wgpu::Adapter &adapter) deviceDesc.SetUncapturedErrorCallback(ImGui_ImplWGPU_DAWN_ErrorCallback_Helper); wgpu::Device acquiredDevice; - auto onRequestDevice = [&](wgpu::RequestDeviceStatus status, wgpu::Device localDevice, wgpu::StringView message) { + auto onRequestDevice = [&](wgpu::RequestDeviceStatus status, wgpu::Device localDevice, wgpu::StringView message) + { if (status != wgpu::RequestDeviceStatus::Success) { printf("Failed to get an device: %s\n", message.data); @@ -336,7 +338,7 @@ static WGPUDevice GetDevice(wgpu::Instance &instance, wgpu::Adapter &adapter) // Synchronously (wait until) get Device wgpu::Future waitDeviceFunc { adapter.RequestDevice(&deviceDesc, wgpu::CallbackMode::WaitAnyOnly, onRequestDevice) }; wgpu::WaitStatus waitStatusDevice = instance.WaitAny(waitDeviceFunc, UINT64_MAX); - assert(acquiredDevice != nullptr && waitStatusDevice == wgpu::WaitStatus::Success && "Error on Device request"); + IM_ASSERT(acquiredDevice != nullptr && waitStatusDevice == wgpu::WaitStatus::Success && "Error on Device request"); return acquiredDevice.MoveToCHandle(); } #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) @@ -344,36 +346,40 @@ static WGPUDevice GetDevice(wgpu::Instance &instance, wgpu::Adapter &adapter) // Adapter and device initialization via JS EM_ASYNC_JS( void, getAdapterAndDeviceViaJS, (), { - if (!navigator.gpu) throw Error("WebGPU not supported."); - + if (!navigator.gpu) + throw Error("WebGPU not supported."); const adapter = await navigator.gpu.requestAdapter(); const device = await adapter.requestDevice(); Module.preinitializedWebGPUDevice = device; } ); #else // __EMSCRIPTEN__ -static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void *userdata1, void *userdata2) +static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) { if (status == WGPURequestAdapterStatus_Success) { - WGPUAdapter *extAdapter = (WGPUAdapter *) userdata1; + WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1; *extAdapter = adapter; } else - printf("Request_adapter status=%#.8x message=%.*s\n", status, (int) message.length, message.data); + { + printf("Request_adapter status=%#.8x message=%.*s\n", status, (int)message.length, message.data); + } } -static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void *userdata1, void *userdata2) +static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2) { if (status == WGPURequestDeviceStatus_Success) { - WGPUDevice *extDevice = (WGPUDevice *) userdata1; + WGPUDevice* extDevice = (WGPUDevice*)userdata1; *extDevice = device; } else - printf("Request_device status=%#.8x message=%.*s\n", status, (int) message.length, message.data); + { + printf("Request_device status=%#.8x message=%.*s\n", status, (int message.length, message.data); + } } -static WGPUAdapter GetAdapter(WGPUInstance &instance) +static WGPUAdapter GetAdapter(WGPUInstance& instance) { WGPURequestAdapterOptions adapterOptions = {}; @@ -383,7 +389,7 @@ static WGPUAdapter GetAdapter(WGPUInstance &instance) adapterCallbackInfo.userdata1 = &localAdapter; wgpuInstanceRequestAdapter(wgpu_instance, &adapterOptions, adapterCallbackInfo); - assert(localAdapter && "Error on Adapter request"); + IM_ASSERT(localAdapter && "Error on Adapter request"); #ifndef NDEBUG ImGui_ImplWGPU_PrintAdapterInfo_Helper(localAdapter); @@ -392,7 +398,7 @@ static WGPUAdapter GetAdapter(WGPUInstance &instance) return localAdapter; } -static WGPUDevice GetDevice(WGPUAdapter &adapter) +static WGPUDevice GetDevice(WGPUAdapter& adapter) { static WGPUDevice localDevice; WGPURequestDeviceCallbackInfo deviceCallbackInfo = {}; @@ -400,7 +406,7 @@ static WGPUDevice GetDevice(WGPUAdapter &adapter) deviceCallbackInfo.userdata1 = &localDevice; wgpuAdapterRequestDevice(adapter, NULL, deviceCallbackInfo); - assert(localDevice && "Error on Device request"); + IM_ASSERT(localDevice && "Error on Device request"); return localDevice; } @@ -429,7 +435,7 @@ static bool InitWGPU(void* window) surfaceDesc.nextInChain = &canvasDesc; wgpu::Surface surface = instance.CreateSurface(&surfaceDesc) ; #else - wgpu::Surface surface = ImGui_ImplSDL3_CreateWGPUSurface_Helper(instance.Get(), (SDL_Window *) window); + wgpu::Surface surface = ImGui_ImplSDL3_CreateWGPUSurface(instance.Get(), (SDL_Window*)window); #endif if (!surface) return false; @@ -450,7 +456,7 @@ static bool InitWGPU(void* window) #ifdef __EMSCRIPTEN__ getAdapterAndDeviceViaJS(); - wgpu_device = emscripten_webgpu_get_device(); + wgpu_device = emscripten_webgpu_get_device(); assert(wgpu_device != nullptr && "Error creating the Device"); WGPUSurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {}; @@ -471,8 +477,7 @@ static bool InitWGPU(void* window) wgpu_device = GetDevice(adapter); // Create the surface. - wgpu_surface = ImGui_ImplSDL3_CreateWGPUSurface_Helper(wgpu_instance, (SDL_Window *) window); - + wgpu_surface = ImGui_ImplSDL3_CreateWGPUSurface(wgpu_instance, (SDL_Window*)window); if (!wgpu_surface) return false; @@ -492,8 +497,7 @@ static bool InitWGPU(void* window) wgpu_surface_configuration.format = preferred_fmt; wgpuSurfaceConfigure(wgpu_surface, &wgpu_surface_configuration); - - wgpu_queue = wgpuDeviceGetQueue(wgpu_device); + wgpu_queue = wgpuDeviceGetQueue(wgpu_device); return true; }