Misc amends (8381)

This commit is contained in:
ocornut
2025-09-24 16:41:25 +02:00
parent 46ca8bc16f
commit 4deba36e83
11 changed files with 388 additions and 402 deletions

View File

@@ -117,6 +117,10 @@
#define GLFW_EXPOSE_NATIVE_COCOA
#endif
#include <GLFW/glfw3native.h>
#ifdef IMGUI_IMPL_WEBGPU_BACKEND_WGPU
#include <Foundation/Foundation.h>
#include <QuartzCore/CAMetalLayer.h>
#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 <GLFW/glfw3native.h>
// 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 <Foundation/Foundation.h>
#include <QuartzCore/CAMetalLayer.h>
#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 = {};
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.display = x11_display;
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.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.hinstance = hinstance;
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__)

View File

@@ -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 <webgpu/webgpu.h>
WGPUSurface ImGui_ImplGLFW_CreateWGPUSurface_Helper(WGPUInstance instance, GLFWwindow* window);
WGPUSurface ImGui_ImplGLFW_CreateWGPUSurface(WGPUInstance instance, GLFWwindow* window);
#endif

View File

@@ -912,74 +912,66 @@ void ImGui_ImplSDL2_NewFrame()
#include <QuartzCore/CAMetalLayer.h>
#endif
WGPUSurface ImGui_ImplSDL2_CreateWGPUSurface_Helper(WGPUInstance instance, SDL_Window* window)
WGPUSurface ImGui_ImplSDL2_CreateWGPUSurface(WGPUInstance instance, SDL_Window* window)
{
WGPUSurfaceDescriptor surfaceDescriptor = {};
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.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.display = sysWMInfo.info.x11.display;
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.hinstance = sysWMInfo.info.win.hinstance;
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;
}

View File

@@ -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 <webgpu/webgpu.h>
WGPUSurface ImGui_ImplSDL2_CreateWGPUSurface_Helper(WGPUInstance instance, SDL_Window* window);
WGPUSurface ImGui_ImplSDL2_CreateWGPUSurface(WGPUInstance instance, SDL_Window* window);
#endif
#endif // #ifndef IMGUI_DISABLE

View File

@@ -854,51 +854,50 @@ void ImGui_ImplSDL3_NewFrame()
# include <windows.h>
#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;
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;
}

View File

@@ -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 <webgpu/webgpu.h>
WGPUSurface ImGui_ImplSDL3_CreateWGPUSurface_Helper(WGPUInstance instance, SDL_Window* window);
WGPUSurface ImGui_ImplSDL3_CreateWGPUSurface(WGPUInstance instance, SDL_Window* window);
#endif
#endif // #ifndef IMGUI_DISABLE

View File

@@ -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

View File

@@ -28,13 +28,10 @@
#ifndef IMGUI_DISABLE
#include <webgpu/webgpu.h>
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
// DAWN "wgpu::" classes (e.g. used in Validation Layers Callbacks)
#include <webgpu/webgpu_cpp.h>
#include <webgpu/webgpu_cpp.h> // 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 <webgpu/wgpu.h>
#include <webgpu/wgpu.h> // 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

View File

@@ -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 <stdio.h>
#include <stdlib.h>
#include <GLFW/glfw3.h>
// This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details.
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
#include <emscripten/html5_webgpu.h>
#endif
#include <webgpu/webgpu.h>
#include <webgpu/webgpu_cpp.h>
#include "../libs/emscripten/emscripten_mainloop_stub.h"
#include <emscripten.h>
#include <emscripten/html5.h>
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
#include <emscripten/html5_webgpu.h>
#endif
#include <webgpu/webgpu.h>
#include <webgpu/webgpu_cpp.h>
#include "../libs/emscripten/emscripten_mainloop_stub.h"
#else
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
#include <webgpu/webgpu_glfw.h>
#endif
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
#include <webgpu/webgpu_glfw.h>
#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;

View File

@@ -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 <stdio.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
#include <emscripten/html5_webgpu.h>
#endif
#include "../libs/emscripten/emscripten_mainloop_stub.h"
#endif
#include <SDL.h>
#include <webgpu/webgpu.h>
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
#include <webgpu/webgpu_cpp.h>
#endif
// This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details.
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
#include <emscripten/html5_webgpu.h>
#endif
#include "../libs/emscripten/emscripten_mainloop_stub.h"
#endif
// Global WebGPU required states
#include <webgpu/webgpu.h>
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
#include <webgpu/webgpu_cpp.h>
#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;

View File

@@ -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 <stdio.h>
#include <stdlib.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
#include <emscripten/html5_webgpu.h>
#endif
#include "../libs/emscripten/emscripten_mainloop_stub.h"
#endif
#include <SDL3/SDL.h>
#include <webgpu/webgpu.h>
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
#include <webgpu/webgpu_cpp.h>
#endif
// This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details.
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
#include <emscripten/html5_webgpu.h>
#endif
#include "../libs/emscripten/emscripten_mainloop_stub.h"
#endif
// Global WebGPU required states
#include <webgpu/webgpu.h>
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
#include <webgpu/webgpu_cpp.h>
#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;
@@ -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,7 +497,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;