2025-10-09 18:54:16 +02:00
// Dear ImGui: standalone example application for GLFW + WebGPU
2024-04-16 12:08:45 +02:00
// - Emscripten is supported for publishing on web. See https://emscripten.org.
// - Dawn is used as a WebGPU implementation on desktop.
2023-09-11 13:47:08 +02:00
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
2021-01-28 11:37:34 +01:00
# include "imgui.h"
# include "imgui_impl_glfw.h"
# include "imgui_impl_wgpu.h"
# include <stdio.h>
2025-10-31 18:58:05 +01:00
# include <stdlib.h>
2025-10-09 18:54:16 +02:00
# include <GLFW/glfw3.h>
2024-03-24 14:18:10 +01:00
2025-10-09 18:54:16 +02:00
// This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details.
2024-01-22 14:20:24 +01:00
# ifdef __EMSCRIPTEN__
2021-01-28 11:37:34 +01:00
# include <emscripten.h>
# include <emscripten/html5.h>
2025-10-09 18:54:16 +02:00
# include "../libs/emscripten/emscripten_mainloop_stub.h"
2024-01-22 14:20:24 +01:00
# endif
2025-11-03 19:04:44 +01:00
# include <webgpu/webgpu.h>
# if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
# include <webgpu/webgpu_cpp.h>
2025-10-31 18:58:05 +01:00
# endif
2021-01-28 11:37:34 +01:00
2025-10-09 18:54:16 +02:00
// Data
2025-10-16 19:10:10 +02:00
static WGPUInstance wgpu_instance = nullptr ;
static WGPUDevice wgpu_device = nullptr ;
static WGPUSurface wgpu_surface = nullptr ;
2025-10-31 18:58:05 +01:00
static WGPUQueue wgpu_queue = nullptr ;
static WGPUSurfaceConfiguration wgpu_surface_configuration = { } ;
2025-10-16 19:10:10 +02:00
static int wgpu_surface_width = 1280 ;
static int wgpu_surface_height = 800 ;
2021-01-28 11:37:34 +01:00
2021-01-28 12:11:26 +01:00
// Forward declarations
2026-02-16 18:04:07 +01:00
static bool InitWGPU ( GLFWwindow * window ) ;
WGPUSurface CreateWGPUSurface ( const WGPUInstance & instance , GLFWwindow * window ) ;
2024-01-22 14:20:24 +01:00
static void glfw_error_callback ( int error , const char * description )
{
printf ( " GLFW Error %d: %s \n " , error , description ) ;
}
2025-10-16 19:10:10 +02:00
static void ResizeSurface ( int width , int height )
{
2025-10-31 18:58:05 +01:00
wgpu_surface_configuration . width = wgpu_surface_width = width ;
wgpu_surface_configuration . height = wgpu_surface_height = height ;
wgpuSurfaceConfigure ( wgpu_surface , & wgpu_surface_configuration ) ;
2025-10-16 19:10:10 +02:00
}
2023-02-02 16:27:33 +01:00
// Main code
2021-01-28 11:37:34 +01:00
int main ( int , char * * )
{
2024-01-22 14:20:24 +01:00
glfwSetErrorCallback ( glfw_error_callback ) ;
2021-01-28 11:37:34 +01:00
if ( ! glfwInit ( ) )
return 1 ;
// Make sure GLFW does not initialize any graphics context.
2023-02-02 16:27:33 +01:00
// This needs to be done explicitly later.
2021-01-28 11:37:34 +01:00
glfwWindowHint ( GLFW_CLIENT_API , GLFW_NO_API ) ;
2025-10-09 18:54:16 +02:00
// Create window
float main_scale = ImGui_ImplGlfw_GetContentScaleForMonitor ( glfwGetPrimaryMonitor ( ) ) ; // Valid on GLFW 3.3+ only
2026-03-23 16:12:39 +01:00
wgpu_surface_width = ( int ) ( wgpu_surface_width * main_scale ) ;
wgpu_surface_height = ( int ) ( wgpu_surface_height * main_scale ) ;
2025-10-09 18:54:16 +02:00
GLFWwindow * window = glfwCreateWindow ( wgpu_surface_width , wgpu_surface_height , " Dear ImGui GLFW+WebGPU example " , nullptr , nullptr ) ;
2024-01-22 14:20:24 +01:00
if ( window = = nullptr )
2021-01-28 11:37:34 +01:00
return 1 ;
// Initialize the WebGPU environment
2024-03-24 14:18:10 +01:00
if ( ! InitWGPU ( window ) )
2021-01-28 12:11:26 +01:00
{
2025-10-09 18:54:16 +02:00
glfwDestroyWindow ( window ) ;
2021-01-28 11:37:34 +01:00
glfwTerminate ( ) ;
return 1 ;
}
2025-10-31 18:58:05 +01:00
2021-01-28 11:37:34 +01:00
glfwShowWindow ( window ) ;
// Setup Dear ImGui context
IMGUI_CHECKVERSION ( ) ;
ImGui : : CreateContext ( ) ;
ImGuiIO & io = ImGui : : GetIO ( ) ; ( void ) io ;
2023-03-10 18:35:03 +01:00
io . ConfigFlags | = ImGuiConfigFlags_NavEnableKeyboard ; // Enable Keyboard Controls
io . ConfigFlags | = ImGuiConfigFlags_NavEnableGamepad ; // Enable Gamepad Controls
2021-01-28 11:37:34 +01:00
// Setup Dear ImGui style
ImGui : : StyleColorsDark ( ) ;
2022-07-06 20:58:20 +02:00
//ImGui::StyleColorsLight();
2021-01-28 11:37:34 +01:00
2025-10-09 18:54:16 +02:00
// 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)
2026-01-22 14:28:46 +01:00
style . FontScaleDpi = main_scale ; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
2025-10-09 18:54:16 +02:00
2021-01-28 11:37:34 +01:00
// Setup Platform/Renderer backends
2021-02-10 17:27:33 +01:00
ImGui_ImplGlfw_InitForOther ( window , true ) ;
2024-01-22 14:20:24 +01:00
# ifdef __EMSCRIPTEN__
2024-07-08 15:53:23 +02:00
ImGui_ImplGlfw_InstallEmscriptenCallbacks ( window , " #canvas " ) ;
2024-01-22 14:20:24 +01:00
# endif
2024-01-22 14:46:41 +01:00
ImGui_ImplWGPU_InitInfo init_info ;
init_info . Device = wgpu_device ;
init_info . NumFramesInFlight = 3 ;
2025-10-31 18:58:05 +01:00
init_info . RenderTargetFormat = wgpu_surface_configuration . format ;
2024-01-22 14:46:41 +01:00
init_info . DepthStencilFormat = WGPUTextureFormat_Undefined ;
ImGui_ImplWGPU_Init ( & init_info ) ;
2021-01-28 11:37:34 +01:00
// Load Fonts
2026-02-12 18:36:22 +01:00
// - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap().
2025-12-23 17:44:18 +01:00
// This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold.
// - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
// - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit).
// - Read 'docs/FONTS.md' for more instructions and details.
// - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering.
2021-01-28 11:37:34 +01:00
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
2025-10-09 18:54:16 +02:00
// - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details.
2025-06-06 16:36:58 +02:00
//style.FontSizeBase = 20.0f;
2025-12-23 17:44:18 +01:00
//io.Fonts->AddFontDefaultVector();
//io.Fonts->AddFontDefaultBitmap();
2021-01-28 11:37:34 +01:00
# ifndef IMGUI_DISABLE_FILE_FUNCTIONS
2025-06-06 16:36:58 +02:00
//io.Fonts->AddFontFromFileTTF("fonts/segoeui.ttf");
//io.Fonts->AddFontFromFileTTF("fonts/DroidSans.ttf");
//io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf");
//io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf");
//ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/ArialUni.ttf");
2023-04-11 11:25:14 +02:00
//IM_ASSERT(font != nullptr);
2021-01-28 11:37:34 +01:00
# endif
2024-01-22 14:20:24 +01:00
// Our state
bool show_demo_window = true ;
bool show_another_window = false ;
ImVec4 clear_color = ImVec4 ( 0.45f , 0.55f , 0.60f , 1.00f ) ;
// Main loop
# 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 ( ! glfwWindowShouldClose ( window ) )
# endif
{
// 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.
glfwPollEvents ( ) ;
2024-07-31 17:47:38 +02:00
if ( glfwGetWindowAttrib ( window , GLFW_ICONIFIED ) ! = 0 )
{
ImGui_ImplGlfw_Sleep ( 10 ) ;
continue ;
}
2024-01-22 14:20:24 +01:00
// React to changes in screen size
int width , height ;
glfwGetFramebufferSize ( ( GLFWwindow * ) window , & width , & height ) ;
2025-10-09 18:54:16 +02:00
if ( width ! = wgpu_surface_width | | height ! = wgpu_surface_height )
ResizeSurface ( width , height ) ;
2024-01-22 14:20:24 +01:00
2025-10-31 18:58:05 +01:00
// Check surface status for error. If texture is not optimal, try to reconfigure the surface.
WGPUSurfaceTexture surface_texture ;
wgpuSurfaceGetCurrentTexture ( wgpu_surface , & surface_texture ) ;
if ( ImGui_ImplWGPU_IsSurfaceStatusError ( surface_texture . status ) )
{
fprintf ( stderr , " Unrecoverable Surface Texture status=%#.8x \n " , surface_texture . status ) ;
abort ( ) ;
}
if ( ImGui_ImplWGPU_IsSurfaceStatusSubOptimal ( surface_texture . status ) )
{
if ( surface_texture . texture )
wgpuTextureRelease ( surface_texture . texture ) ;
if ( width > 0 & & height > 0 )
ResizeSurface ( width , height ) ;
continue ;
}
2024-01-22 14:20:24 +01:00
// Start the Dear ImGui frame
ImGui_ImplWGPU_NewFrame ( ) ;
ImGui_ImplGlfw_NewFrame ( ) ;
ImGui : : NewFrame ( ) ;
// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
if ( show_demo_window )
ImGui : : ShowDemoWindow ( & show_demo_window ) ;
// 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
{
static float f = 0.0f ;
static int counter = 0 ;
ImGui : : Begin ( " Hello, world! " ) ; // Create a window called "Hello, world!" and append into it.
ImGui : : Text ( " This is some useful text. " ) ; // Display some text (you can use a format strings too)
ImGui : : Checkbox ( " Demo Window " , & show_demo_window ) ; // Edit bools storing our window open/close state
ImGui : : Checkbox ( " Another Window " , & show_another_window ) ;
ImGui : : SliderFloat ( " float " , & f , 0.0f , 1.0f ) ; // Edit 1 float using a slider from 0.0f to 1.0f
ImGui : : ColorEdit3 ( " clear color " , ( float * ) & clear_color ) ; // Edit 3 floats representing a color
if ( ImGui : : Button ( " Button " ) ) // Buttons return true when clicked (most widgets return true when edited/activated)
counter + + ;
ImGui : : SameLine ( ) ;
ImGui : : Text ( " counter = %d " , counter ) ;
ImGui : : Text ( " Application average %.3f ms/frame (%.1f FPS) " , 1000.0f / io . Framerate , io . Framerate ) ;
ImGui : : End ( ) ;
}
// 3. Show another simple window.
if ( show_another_window )
{
ImGui : : Begin ( " Another Window " , & show_another_window ) ; // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
ImGui : : Text ( " Hello from another window! " ) ;
if ( ImGui : : Button ( " Close Me " ) )
show_another_window = false ;
ImGui : : End ( ) ;
}
// Rendering
ImGui : : Render ( ) ;
2025-10-31 18:58:05 +01:00
WGPUTextureViewDescriptor view_desc = { } ;
view_desc . format = wgpu_surface_configuration . format ;
view_desc . dimension = WGPUTextureViewDimension_2D ;
view_desc . mipLevelCount = WGPU_MIP_LEVEL_COUNT_UNDEFINED ;
view_desc . arrayLayerCount = WGPU_ARRAY_LAYER_COUNT_UNDEFINED ;
view_desc . aspect = WGPUTextureAspect_All ;
WGPUTextureView texture_view = wgpuTextureCreateView ( surface_texture . texture , & view_desc ) ;
2024-03-24 14:18:10 +01:00
2024-01-22 14:20:24 +01:00
WGPURenderPassColorAttachment color_attachments = { } ;
2024-03-06 13:44:37 +01:00
color_attachments . depthSlice = WGPU_DEPTH_SLICE_UNDEFINED ;
2024-01-22 14:20:24 +01:00
color_attachments . loadOp = WGPULoadOp_Clear ;
color_attachments . storeOp = WGPUStoreOp_Store ;
color_attachments . clearValue = { clear_color . x * clear_color . w , clear_color . y * clear_color . w , clear_color . z * clear_color . w , clear_color . w } ;
2025-10-31 18:58:05 +01:00
color_attachments . view = texture_view ;
2024-01-22 14:20:24 +01:00
WGPURenderPassDescriptor render_pass_desc = { } ;
render_pass_desc . colorAttachmentCount = 1 ;
render_pass_desc . colorAttachments = & color_attachments ;
render_pass_desc . depthStencilAttachment = nullptr ;
WGPUCommandEncoderDescriptor enc_desc = { } ;
WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder ( wgpu_device , & enc_desc ) ;
WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass ( encoder , & render_pass_desc ) ;
ImGui_ImplWGPU_RenderDrawData ( ImGui : : GetDrawData ( ) , pass ) ;
wgpuRenderPassEncoderEnd ( pass ) ;
WGPUCommandBufferDescriptor cmd_buffer_desc = { } ;
WGPUCommandBuffer cmd_buffer = wgpuCommandEncoderFinish ( encoder , & cmd_buffer_desc ) ;
2025-10-09 18:54:16 +02:00
wgpuQueueSubmit ( wgpu_queue , 1 , & cmd_buffer ) ;
2024-03-24 14:18:10 +01:00
# ifndef __EMSCRIPTEN__
2025-10-31 18:58:05 +01:00
wgpuSurfacePresent ( wgpu_surface ) ;
// Tick needs to be called in Dawn to display validation errors
# if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
wgpuDeviceTick ( wgpu_device ) ;
2024-03-24 14:18:10 +01:00
# endif
2025-10-31 18:58:05 +01:00
# endif
wgpuTextureViewRelease ( texture_view ) ;
2024-03-24 14:18:10 +01:00
wgpuRenderPassEncoderRelease ( pass ) ;
wgpuCommandEncoderRelease ( encoder ) ;
wgpuCommandBufferRelease ( cmd_buffer ) ;
2024-01-22 14:20:24 +01:00
}
# ifdef __EMSCRIPTEN__
EMSCRIPTEN_MAINLOOP_END ;
# endif
// Cleanup
ImGui_ImplWGPU_Shutdown ( ) ;
ImGui_ImplGlfw_Shutdown ( ) ;
ImGui : : DestroyContext ( ) ;
2025-10-31 18:58:05 +01:00
wgpuSurfaceUnconfigure ( wgpu_surface ) ;
wgpuSurfaceRelease ( wgpu_surface ) ;
wgpuQueueRelease ( wgpu_queue ) ;
wgpuDeviceRelease ( wgpu_device ) ;
wgpuInstanceRelease ( wgpu_instance ) ;
2024-01-22 14:20:24 +01:00
glfwDestroyWindow ( window ) ;
glfwTerminate ( ) ;
2021-01-28 11:37:34 +01:00
return 0 ;
}
2025-10-31 18:58:05 +01:00
# if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
static WGPUAdapter RequestAdapter ( wgpu : : Instance & instance )
2024-04-16 12:08:45 +02:00
{
2025-10-31 18:58:05 +01:00
wgpu : : Adapter acquired_adapter ;
wgpu : : RequestAdapterOptions adapter_options ;
auto onRequestAdapter = [ & ] ( wgpu : : RequestAdapterStatus status , wgpu : : Adapter adapter , wgpu : : StringView message )
2024-04-16 12:08:45 +02:00
{
2025-10-31 18:58:05 +01:00
if ( status ! = wgpu : : RequestAdapterStatus : : Success )
{
printf ( " Failed to get an adapter: %s \n " , message . data ) ;
return ;
}
acquired_adapter = std : : move ( adapter ) ;
2025-10-16 19:10:10 +02:00
} ;
2025-10-31 18:58:05 +01:00
// Synchronously (wait until) acquire Adapter
wgpu : : Future waitAdapterFunc { instance . RequestAdapter ( & adapter_options , wgpu : : CallbackMode : : WaitAnyOnly , onRequestAdapter ) } ;
wgpu : : WaitStatus waitStatusAdapter = instance . WaitAny ( waitAdapterFunc , UINT64_MAX ) ;
IM_ASSERT ( acquired_adapter ! = nullptr & & waitStatusAdapter = = wgpu : : WaitStatus : : Success & & " Error on Adapter request " ) ;
return acquired_adapter . MoveToCHandle ( ) ;
2024-04-16 12:08:45 +02:00
}
2025-10-31 18:58:05 +01:00
static WGPUDevice RequestDevice ( wgpu : : Instance & instance , wgpu : : Adapter & adapter )
2024-04-16 12:08:45 +02:00
{
2025-10-31 18:58:05 +01:00
// Set device callback functions
wgpu : : DeviceDescriptor device_desc ;
device_desc . SetDeviceLostCallback ( wgpu : : CallbackMode : : AllowSpontaneous ,
[ ] ( const wgpu : : Device & , wgpu : : DeviceLostReason type , wgpu : : StringView msg ) { fprintf ( stderr , " %s error: %s \n " , ImGui_ImplWGPU_GetDeviceLostReasonName ( ( WGPUDeviceLostReason ) type ) , msg . data ) ; }
) ;
device_desc . SetUncapturedErrorCallback (
[ ] ( const wgpu : : Device & , wgpu : : ErrorType type , wgpu : : StringView msg ) { fprintf ( stderr , " %s error: %s \n " , ImGui_ImplWGPU_GetErrorTypeName ( ( WGPUErrorType ) type ) , msg . data ) ; }
) ;
wgpu : : Device acquired_device ;
auto onRequestDevice = [ & ] ( wgpu : : RequestDeviceStatus status , wgpu : : Device local_device , wgpu : : StringView message )
2024-04-16 12:08:45 +02:00
{
2025-10-31 18:58:05 +01:00
if ( status ! = wgpu : : RequestDeviceStatus : : Success )
{
printf ( " Failed to get an device: %s \n " , message . data ) ;
return ;
}
acquired_device = std : : move ( local_device ) ;
2024-04-16 12:08:45 +02:00
} ;
2025-10-31 18:58:05 +01:00
// Synchronously (wait until) get Device
wgpu : : Future waitDeviceFunc { adapter . RequestDevice ( & device_desc , wgpu : : CallbackMode : : WaitAnyOnly , onRequestDevice ) } ;
wgpu : : WaitStatus waitStatusDevice = instance . WaitAny ( waitDeviceFunc , UINT64_MAX ) ;
IM_ASSERT ( acquired_device ! = nullptr & & waitStatusDevice = = wgpu : : WaitStatus : : Success & & " Error on Device request " ) ;
return acquired_device . MoveToCHandle ( ) ;
2024-04-16 12:08:45 +02:00
}
2026-03-21 00:36:24 +01:00
# elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
2025-10-31 18:58:05 +01:00
static void handle_request_adapter ( WGPURequestAdapterStatus status , WGPUAdapter adapter , WGPUStringView message , void * userdata1 , void * userdata2 )
{
2026-03-23 16:12:39 +01:00
IM_UNUSED ( userdata2 ) ;
2025-10-31 18:58:05 +01:00
if ( status = = WGPURequestAdapterStatus_Success )
{
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 )
{
2026-03-23 16:12:39 +01:00
IM_UNUSED ( userdata2 ) ;
2025-10-31 18:58:05 +01:00
if ( status = = WGPURequestDeviceStatus_Success )
{
WGPUDevice * extDevice = ( WGPUDevice * ) userdata1 ;
* extDevice = device ;
}
else
{
printf ( " Request_device status=%#.8x message=%.*s \n " , status , ( int ) message . length , message . data ) ;
}
}
static WGPUAdapter RequestAdapter ( WGPUInstance & instance )
{
WGPURequestAdapterOptions adapter_options = { } ;
2026-02-20 15:54:56 +01:00
WGPUAdapter local_adapter = nullptr ;
2025-10-31 18:58:05 +01:00
WGPURequestAdapterCallbackInfo adapterCallbackInfo = { } ;
2026-02-20 15:54:56 +01:00
adapterCallbackInfo . mode = WGPUCallbackMode_WaitAnyOnly ;
2025-10-31 18:58:05 +01:00
adapterCallbackInfo . callback = handle_request_adapter ;
adapterCallbackInfo . userdata1 = & local_adapter ;
2026-02-20 15:54:56 +01:00
WGPUFuture future = wgpuInstanceRequestAdapter ( instance , & adapter_options , adapterCallbackInfo ) ;
WGPUFutureWaitInfo waitInfo = { future , false } ;
wgpuInstanceWaitAny ( instance , 1 , & waitInfo , ~ 0ull ) ;
2025-10-31 18:58:05 +01:00
IM_ASSERT ( local_adapter & & " Error on Adapter request " ) ;
return local_adapter ;
}
2026-02-20 15:54:56 +01:00
static WGPUDevice RequestDevice ( WGPUInstance & instance , WGPUAdapter & adapter )
2025-10-31 18:58:05 +01:00
{
2026-02-20 15:54:56 +01:00
WGPUDevice local_device = nullptr ;
2025-10-31 18:58:05 +01:00
WGPURequestDeviceCallbackInfo deviceCallbackInfo = { } ;
2026-02-20 15:54:56 +01:00
deviceCallbackInfo . mode = WGPUCallbackMode_WaitAnyOnly ;
2025-10-31 18:58:05 +01:00
deviceCallbackInfo . callback = handle_request_device ;
deviceCallbackInfo . userdata1 = & local_device ;
2026-02-20 15:54:56 +01:00
WGPUFuture future = wgpuAdapterRequestDevice ( adapter , nullptr , deviceCallbackInfo ) ;
WGPUFutureWaitInfo waitInfo = { future , false } ;
wgpuInstanceWaitAny ( instance , 1 , & waitInfo , ~ 0ull ) ;
2025-10-31 18:58:05 +01:00
IM_ASSERT ( local_device & & " Error on Device request " ) ;
return local_device ;
}
# endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU
2024-04-16 12:08:45 +02:00
2026-02-16 18:04:07 +01:00
bool InitWGPU ( GLFWwindow * window )
2021-01-28 11:37:34 +01:00
{
2025-10-31 18:58:05 +01:00
WGPUTextureFormat preferred_fmt = WGPUTextureFormat_Undefined ; // acquired from SurfaceCapabilities
2024-03-24 14:18:10 +01:00
2025-10-31 18:58:05 +01:00
// Google DAWN backend: Adapter and Device acquisition, Surface creation
# if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
wgpu : : InstanceDescriptor instance_desc = { } ;
static constexpr wgpu : : InstanceFeatureName timedWaitAny = wgpu : : InstanceFeatureName : : TimedWaitAny ;
instance_desc . requiredFeatureCount = 1 ;
instance_desc . requiredFeatures = & timedWaitAny ;
wgpu : : Instance instance = wgpu : : CreateInstance ( & instance_desc ) ;
wgpu : : Adapter adapter = RequestAdapter ( instance ) ;
ImGui_ImplWGPU_DebugPrintAdapterInfo ( adapter . Get ( ) ) ;
2021-01-28 11:37:34 +01:00
2025-10-31 18:58:05 +01:00
wgpu_device = RequestDevice ( instance , adapter ) ;
// Create the surface.
# ifdef __EMSCRIPTEN__
wgpu : : EmscriptenSurfaceSourceCanvasHTMLSelector canvas_desc = { } ;
2025-10-09 18:54:16 +02:00
canvas_desc . selector = " #canvas " ;
2025-10-31 18:58:05 +01:00
2021-01-28 12:11:26 +01:00
wgpu : : SurfaceDescriptor surface_desc = { } ;
2025-10-09 18:54:16 +02:00
surface_desc . nextInChain = & canvas_desc ;
2025-10-31 18:58:05 +01:00
wgpu_surface = instance . CreateSurface ( & surface_desc ) . MoveToCHandle ( ) ;
2024-03-24 14:18:10 +01:00
# else
2025-10-31 18:58:05 +01:00
wgpu_surface = CreateWGPUSurface ( instance . Get ( ) , window ) ;
# endif
if ( ! wgpu_surface )
2025-10-16 19:10:10 +02:00
return false ;
2025-10-31 18:58:05 +01:00
// Moving Dawn objects into WGPU handles
wgpu_instance = instance . MoveToCHandle ( ) ;
WGPUSurfaceCapabilities surface_capabilities = { } ;
wgpuSurfaceGetCapabilities ( wgpu_surface , adapter . Get ( ) , & surface_capabilities ) ;
preferred_fmt = surface_capabilities . formats [ 0 ] ;
// WGPU backend: Adapter and Device acquisition, Surface creation
2026-03-21 00:36:24 +01:00
# elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
2026-02-20 15:54:56 +01:00
WGPUInstanceDescriptor instanceDesc = { } ;
WGPUInstanceFeatureName timedWaitAny = WGPUInstanceFeatureName_TimedWaitAny ;
instanceDesc . requiredFeatureCount = 1 ;
instanceDesc . requiredFeatures = & timedWaitAny ;
wgpu_instance = wgpuCreateInstance ( & instanceDesc ) ;
2025-10-31 18:58:05 +01:00
2026-03-21 00:36:24 +01:00
# if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
2025-10-31 18:58:05 +01:00
wgpuSetLogCallback (
[ ] ( WGPULogLevel level , WGPUStringView msg , void * userdata ) { fprintf ( stderr , " %s: %.*s \n " , ImGui_ImplWGPU_GetLogLevelName ( level ) , ( int ) msg . length , msg . data ) ; } , nullptr
) ;
wgpuSetLogLevel ( WGPULogLevel_Warn ) ;
2026-03-21 00:36:24 +01:00
# endif
2025-10-31 18:58:05 +01:00
WGPUAdapter adapter = RequestAdapter ( wgpu_instance ) ;
ImGui_ImplWGPU_DebugPrintAdapterInfo ( adapter ) ;
2026-02-20 15:54:56 +01:00
wgpu_device = RequestDevice ( wgpu_instance , adapter ) ;
2025-10-16 19:10:10 +02:00
2025-10-31 18:58:05 +01:00
// Create the surface.
wgpu_surface = CreateWGPUSurface ( wgpu_instance , window ) ;
if ( ! wgpu_surface )
2024-03-24 14:18:10 +01:00
return false ;
2025-10-31 18:58:05 +01:00
WGPUSurfaceCapabilities surface_capabilities = { } ;
wgpuSurfaceGetCapabilities ( wgpu_surface , adapter , & surface_capabilities ) ;
preferred_fmt = surface_capabilities . formats [ 0 ] ;
# endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU
wgpu_surface_configuration . presentMode = WGPUPresentMode_Fifo ;
wgpu_surface_configuration . alphaMode = WGPUCompositeAlphaMode_Auto ;
wgpu_surface_configuration . usage = WGPUTextureUsage_RenderAttachment ;
wgpu_surface_configuration . width = wgpu_surface_width ;
wgpu_surface_configuration . height = wgpu_surface_height ;
wgpu_surface_configuration . device = wgpu_device ;
wgpu_surface_configuration . format = preferred_fmt ;
wgpuSurfaceConfigure ( wgpu_surface , & wgpu_surface_configuration ) ;
wgpu_queue = wgpuDeviceGetQueue ( wgpu_device ) ;
2021-01-28 11:37:34 +01:00
return true ;
}
2025-11-01 10:41:59 +01:00
// GLFW helper to create a WebGPU surface, used only in WGPU-Native. DAWN-Native already has a built-in function
// As of today (2025/10) 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 nor available with EMSCRIPTEN.
2025-11-07 13:24:10 +01:00
# ifndef __EMSCRIPTEN__
2025-11-01 10:41:59 +01:00
# if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
# define GLFW_HAS_X11_OR_WAYLAND 1
# else
# define GLFW_HAS_X11_OR_WAYLAND 0
# endif
# ifdef _WIN32
# undef APIENTRY
# ifndef GLFW_EXPOSE_NATIVE_WIN32 // for glfwGetWin32Window()
# define GLFW_EXPOSE_NATIVE_WIN32
# endif
# elif defined(__APPLE__)
# ifndef GLFW_EXPOSE_NATIVE_COCOA // for glfwGetCocoaWindow()
# define GLFW_EXPOSE_NATIVE_COCOA
# endif
# elif GLFW_HAS_X11_OR_WAYLAND
# ifndef GLFW_EXPOSE_NATIVE_X11 // for glfwGetX11Display(), glfwGetX11Window() on Freedesktop (Linux, BSD, etc.)
# define GLFW_EXPOSE_NATIVE_X11
# endif
# ifndef GLFW_EXPOSE_NATIVE_WAYLAND
# if defined(__has_include) && __has_include(<wayland-client.h>)
# define GLFW_EXPOSE_NATIVE_WAYLAND
# endif
# endif
# endif
# include <GLFW/glfw3native.h>
# undef Status // X11 headers are leaking this and also 'Success', 'Always', 'None', all used in DAWN api. Add #undef if necessary.
WGPUSurface CreateWGPUSurface ( const WGPUInstance & instance , GLFWwindow * window )
{
ImGui_ImplWGPU_CreateSurfaceInfo create_info = { } ;
create_info . Instance = instance ;
# if defined(GLFW_EXPOSE_NATIVE_COCOA)
{
create_info . System = " cocoa " ;
create_info . RawWindow = ( void * ) glfwGetCocoaWindow ( window ) ;
return ImGui_ImplWGPU_CreateWGPUSurfaceHelper ( & create_info ) ;
}
# elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
if ( glfwGetPlatform ( ) = = GLFW_PLATFORM_WAYLAND )
{
create_info . System = " wayland " ;
create_info . RawDisplay = ( void * ) glfwGetWaylandDisplay ( ) ;
create_info . RawSurface = ( void * ) glfwGetWaylandWindow ( window ) ;
return ImGui_ImplWGPU_CreateWGPUSurfaceHelper ( & create_info ) ;
}
# elif defined(GLFW_EXPOSE_NATIVE_X11)
if ( glfwGetPlatform ( ) = = GLFW_PLATFORM_X11 )
{
create_info . System = " x11 " ;
create_info . RawWindow = ( void * ) glfwGetX11Window ( window ) ;
create_info . RawDisplay = ( void * ) glfwGetX11Display ( ) ;
return ImGui_ImplWGPU_CreateWGPUSurfaceHelper ( & create_info ) ;
}
# elif defined(GLFW_EXPOSE_NATIVE_WIN32)
{
create_info . System = " win32 " ;
create_info . RawWindow = ( void * ) glfwGetWin32Window ( window ) ;
create_info . RawInstance = ( void * ) : : GetModuleHandle ( NULL ) ;
return ImGui_ImplWGPU_CreateWGPUSurfaceHelper ( & create_info ) ;
}
# else
# error "Unsupported WebGPU native platform!"
return nullptr ;
2026-03-23 16:12:39 +01:00
# endif
2025-11-01 10:41:59 +01:00
}
2025-11-07 13:24:10 +01:00
# endif // #ifndef __EMSCRIPTEN__