Skip to content

WebGPU GLFW, SDL2 and SDL3 examples - #8381

Closed
BrutPitt wants to merge 4 commits into
ocornut:masterfrom
BrutPitt:master
Closed

WebGPU GLFW, SDL2 and SDL3 examples#8381
BrutPitt wants to merge 4 commits into
ocornut:masterfrom
BrutPitt:master

Conversation

@BrutPitt

@BrutPitt BrutPitt commented Feb 7, 2025

Copy link
Copy Markdown
Contributor

As already anticipated here, I send you the PR with the example GLFW in which the Swap-Chain was removed in favor of SurfaceConfigure.

But given the little troubles with GLFW (Validation Layer messages), I wanted to check with SDL2 if everything worked well.
So I created a function to acquire the surface in a native way on SDL.
It works and has been tested (with ImGui SDL2 WebGPU example) in Windows, Linux (X11) and Emscripten
There is also the possibility with Linux (Wayland) , but I haven't tried it yet.

The ImGui SDL2 WebGPU example works well: the web version is live here (obviously a browser with webGPU capabilities is required)

In SDL2 everything works perfectly and there are no warnings from the Validation Layer: it was tested in Linux, Windows and EMSCRIPTEN*

@ocornut ocornut added backends web emscripten, wgpu etc. labels Feb 10, 2025
@ocornut

ocornut commented Feb 10, 2025

Copy link
Copy Markdown
Owner

Hello,
Could you ensure the new symbols use matching code style?

  • surfaceConfiguration -> wgpu_surface_configuration

  • surfaceResize() -> ResizeSurface()

  • wgpuSurfaceConfigure( wgpu_surface, (WGPUSurfaceConfiguration *) &surfaceConfiguration ); -> wgpuSurfaceConfigure(wgpu_surface, (WGPUSurfaceConfiguration*)&surfaceConfiguration);

  • etc.

  • brace on new line

  • Can you clarify why the RequestAdapter() stuff needs to be changed? Is e.g. std::move() an absolute requirement (spoiler: I don't know what it does) ?

  • Could the new callback have declared signatures instead of using lambdas?

Thank you!

@ocornut

ocornut commented Feb 10, 2025

Copy link
Copy Markdown
Owner

In addition, if I try to compile example_glfw_wgpu/ BEFORE your change using Dawn, I get many other errors (which are not the one you are aiming to fix).

imgui_impl_wgpu.cpp(66,41): error C2187: syntax error: 'WGPUComputeState' was unexpected here [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(273,5): error C2065: 'WGPUShaderSourceWGSL': undeclared identifier [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(273,26): error C2146: syntax error: missing ';' before identifier 'wgsl_desc' [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(273,26): error C2065: 'wgsl_desc': undeclared identifier [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(273,36): error C3079: an initializer list cannot be used as the right operand of this assignment operator [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(274,5): error C2065: 'wgsl_desc': undeclared identifier [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(274,29): error C2065: 'WGPUSType_ShaderSourceWGSL': undeclared identifier [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(275,5): error C2065: 'wgsl_desc': undeclared identifier [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(275,37): error C2065: 'WGPU_STRLEN': undeclared identifier [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(283,62): error C2065: 'wgsl_desc': undeclared identifier [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(288,39): error C2065: 'WGPU_STRLEN': undeclared identifier [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(288,29): error C2440: '=': cannot convert from 'initializer list' to 'const char *' [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
      imgui_impl_wgpu.cpp(288,29):
      The initializer contains too many elements
imgui_impl_wgpu.cpp(405,13): error C2065: 'WGPU_STRLEN': undeclared identifier [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(432,13): error C2065: 'WGPU_STRLEN': undeclared identifier [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(545,55): error C2065: 'WGPU_STRLEN': undeclared identifier [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(545,26): error C2440: '=': cannot convert from 'initializer list' to 'const char *' [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
      imgui_impl_wgpu.cpp(545,26):
      The initializer contains too many elements

imgui_impl_wgpu.cpp(612,9): error C2065: 'WGPU_STRLEN': undeclared identifier [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
imgui_impl_wgpu.cpp(720,45): error C2065: 'WGPUOptionalBool_False': undeclared identifier [C:\Omar\Work\imgui\examples\example_glfw_wgpu\build\example_glfw_wgpu.vcxproj]
  imgui_widgets.cpp
  Generating Code...

Yet my copy of Dawn appears to be up to date, so I am quite confused about the build process it seems.

@BrutPitt

BrutPitt commented Feb 10, 2025

Copy link
Copy Markdown
Contributor Author

Hi Omar, let me start with your last message.

I tried to compile the GLFW example under Windows, again, and continue to get NO errors.
I tried also to:

  • delete DAWN and re-clone it entirely
  • delete all sources and re-clone they entirely
  • delete all CMake cache and previous generated files
  • in the end have compiled with: VS2022 (from CMakeFile), with CLion (from CMakeFile) and also directly from command line, and to do this I followed the directives contained in the CMakeFile.txt (file not touched by me) step by step, and which I report below:
# Building for desktop (WebGPU-native) with Dawn:
#  1. git clone https://github.com/google/dawn dawn
#  2. cmake -B build -DIMGUI_DAWN_DIR=dawn
#  3. cmake --build build

and always I get NO errors.

I add, for full completeness, after cloning DAWN I run python tools/fetch_dawn_dependencies.py --use-test-deps command (before to compile), as reported here (googlesource site)

I also noticed that in your report appears example_glfw_wgpu.vcxproj that I don't find from me, nor before, nor after.
I also opened imgui_examples.sln, but it does not contain example_glfw_wgpu.
So I also generated, from CMake, an imgui_example_glfw_wgpu.sln (and obviously also relative .vcxproj), and again get NO errors to compile it

Screenshot 2025-02-10 220006

 

  • For this I ask you which procedure did you follow to compile the example?

 

Moreover, I checked the state of the "undeclared identifier" that you report, and they exist (in my copy of dawn):
e.g. WGPUOptionalBool_False in webgpu.h

Screenshot at 2025-02-10 22-19-02

And, searching the net, I found that WGPUOptionalBool_False was declared lately, in DAWN, but already (at least) from September:
#7969

This seemed to me the most important thing to clarify as soon possible, later I reply to your questions

P.S.
In this reply I focused only on Windows, because of the .vcxproj extension, but obviously it compile with success also in Linux and emscripten

@BrutPitt

BrutPitt commented Feb 11, 2025

Copy link
Copy Markdown
Contributor Author

About your questions:

About code style

No problem to use your code style.

About changes in RequestAdapter/Device

RequestAdapter was changed because wgpuInstanceRequestAdapter has been changed from Google Dawn:

Currently this is the wgpuInstanceRequestAdapter prototype, it accepts THREE parameters:

WGPUFuture wgpuInstanceRequestAdapter(WGPUInstance instance, WGPU_NULLABLE WGPURequestAdapterOptions const * options, WGPURequestAdapterCallbackInfo callbackInfo) WGPU_FUNCTION_ATTRIBUTE;

In the previous code wgpuInstanceRequestAdapter used FOUR parameters :

 WGPUAdapter adapter;
    wgpuInstanceRequestAdapter(instance, nullptr, onAdapterRequestEnded, (void*)&adapter);
    return adapter;                                                            ^^^^^^^^^

The 4th parameter was removed from google DAWN

Same for wgpuInstanceRequestDevice

WGPU_EXPORT WGPUFuture wgpuAdapterRequestDevice(WGPUAdapter adapter, WGPU_NULLABLE WGPUDeviceDescriptor const * options, WGPURequestDeviceCallbackInfo callbackInfo) WGPU_FUNCTION_ATTRIBUTE;

About std::move

I make just a little example:

    std::string str1 {"AAAAAA"};
    std::string str2 {"BBBBBB"};

    std::string str1_out = str1;
    std::string str2_out = std::move(str2);

The first assignment call the copy constructor/operator: it copy the full string "AAAAAA" into str1_out.
The second move the reference of str2 into str2_out and simply set str2 in a valid but unspecified state
Both str1_out and str2_out will have what is expected, but str2_out with less work for the CPU.
So std::move, move the reference of an object into another, and this is very useful when a local object must to be moved/assigned to a global variable, when it's near to end its scope and then it will not be needed anymore (frequently used in lambda).

(I'm sorry for the short and simplistic explanation: std::move is a "bit" more complex)

  • I'm sorry, this had escaped me, so I add:

Absolute requirement, no.
I went to see the class constructor and the assignment operator and, using std::move, the "release" functions (e.g. WGPURelease) are avoided on an object which will soon be destroyed.

And again:
I tried with the simple assignment and all works (obviously), but I receive this warning from Clang-Tidy:
"Parameter 'adapter' is passed by value and only copied once; consider moving it to avoid unnecessary copies"

About callback

In principle, no problem, but (to understand well) you want that I remove all lambdas, not only the validation layers callbacks, right?

@PathogenDavid

PathogenDavid commented Feb 11, 2025

Copy link
Copy Markdown
Contributor

Just to give an extra data point, I was able to successfully build and run example_glfw_wgpu on Windows using @BrutPitt's instructions and google/dawn@2a84206.

I've never worked with WebGPU on this machine so the Dawn clone was as fresh as can be. I don't have depot_tools or any other Chromium-specific stuff installed.

This is with Windows 10 22H2, CMake 3.30.2, Python 3.12.5, Visual Studio 2022 17.12.4 (latest). I also have Visual Studio 2022 17.13.0p2.1 and Ninja 1.12.1 on this machine, but I don't think either were used while building the example.

I add, for full completeness, after cloning DAWN I run python tools/fetch_dawn_dependencies.py --use-test-deps command (before to compile), as reported here (googlesource site)

I also ran this as per your mention, although judging by our CMakeLists it shouldn't actually be necessary.

(Also for @ocornut's sake: If you're like me and habitually add --recursive to your git clone commands. Definitely don't do that with Dawn unless you hate bandwidth, time, and storage space. It also might not actually work since their tooling probably doesn't expect you to do it.)

@BrutPitt

BrutPitt commented Feb 11, 2025

Copy link
Copy Markdown
Contributor Author

@ocornut

About SDL2 WebGPU example attached.

As mentioned it uses a "made by me" module sdl2wgpu.cpp with SDL native calls to get SDL_SysWMinfo data to pass wgpuInstanceCreateSurface call.
And despite being a widely mentioned and used method to acquire the info from/of WM to create Surface, I know is not an official DAWN wgpu procedure.
*and currently I tested it only on Windows, Linux (X11) and emscripten, and the macOS procedure has yet to be written

But I made and attached it exclusively to "present" an example without messages from the Validation Layer and consider/test the correct procedure also/already used in GLFW.

So, give the premises, if you prefer, I take it off from the PR.
Possibly, after, I add it as "un-official" SDL2 imgui WGPU example on my account

@PathogenDavid

This is with Windows 10 22H2, CMake 3.30.2, Python 3.12.5, Visual Studio 2022 17.12.4 (latest). I also have Visual Studio 2022 17.13.0p2.1 and Ninja 1.12.1 on this machine, but I don't think either were used while building the example.

You did well to specify the developer tools releases and OS
Personally tested on/with:

  • Windows 11 24H2
  • CMake > 3.30: bundled compiler versions (CLion/VS) and also last official 3.31.5 release (for command line build and to generate .sln)
  • VS v17.12.3
  • Builder: bundled Ninja on CLion 2024.3.2, otherwise MSbuild

I add, for full completeness, after cloning DAWN I run python tools/fetch_dawn_dependencies.py --use-test-deps command (before to compile), as reported here (googlesource site)

I also ran this as per your mention, although judging by our CMakeLists it shouldn't actually be necessary.

Confirm that this is not necessary (on Linux I don't used it), and therefore is not necessary to insert this step in the CMake procedure, but given the doubts I wanted to follow all the "official" steps

@BrutPitt

BrutPitt commented Feb 12, 2025

Copy link
Copy Markdown
Contributor Author

Last commit changes:

If you prefer RequestAdaper and RequestDevice declared as functions would have this code, in a #ifndef __EMSCRIPTEN__ block:

#ifndef __EMSCRIPTEN__
static wgpu::Adapter localAdapter;   // currently used as local declaration in InitWGPU, both
static wgpu::Device localDevice;

void RequestAdapter(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;
    }
    localAdapter = std::move(adapter);
}

void RequestDevice(wgpu::RequestDeviceStatus status, wgpu::Device device, wgpu::StringView message)
{
    if (status != wgpu::RequestDeviceStatus::Success)
    {
        printf("Failed to get an device: %s\n", message.data);
        return;
    }
    localDevice = std::move(device);
}
#endif

Added notes:

  • I unified the two #ifdef __EMSCRIPTEN__ blocks in IntWGPU: now - before (previous/current imgui WGPU example)

@BrutPitt

BrutPitt commented Feb 17, 2025

Copy link
Copy Markdown
Contributor Author

Hi, Omar.

It's frustrating to work on Dawn: last branch, downloaded Saturday, causes "segmentation fault" on WebGPU Vulkan backend.
And also all the DAWN examples (HelloTriangle, Anemometer, etc) have the same problem: on my PCs this happens with NVidia RTX 3080 (Linux) and AMD RX 6700 XT (Windows 11).
I have included in the code a way to force a backendType change to D3D11 (or D3D12), for Windows, as workaround.
Currently, have no option for Linux where Vulkan is the only option.
This does not happens in Emscripten

Edit - current problem is reported here:
https://issues.chromium.org/issues/397448368

About the GLFW example

Exploring the Dawn Source Code (the documentation is poor) I made some optimizations and correction to the example:

A new function has been inserted to directly create the device, without the use of callbacks
It is not used anywhere, there is only this note: - Synchronous adapter.CreateDevice(const wgpu::DeviceDescriptor*) may be called.

Currently there is no similar option for Adapter, not for wgpu::Instance class, but only from dawn::native::Instance, this is an example of implementation:

	// Declare DAWN RAII instead of wgpu::Instance
    dawn::native::Instance instance(&instanceDescriptor);

    // Enumerate all devices
    std::vector<dawn::native::Adapter> adapterList = instance.EnumerateAdapters((WGPURequestAdapterOptions*) nullptr);
    assert(!adapterList.empty());

    // we get first available
    dawn::native::Adapter localAdapter { adapterList[0] };

But works only with DAWN (even if it does not involve the EMISCRIPTEN side), for this I currently did not use it

About GLFW viewport error:

It occurs only on window resize, not always, and only when enlarging.

Validation error: Viewport bounds (x: 0.000000, y: 0.000000, width: 1757.999878, height: 1259.000000) are not contained in the render target dimensions (1758 x 1256).
 - While encoding [RenderPassEncoder (unlabeled)].SetViewport(0.000000, 0.000000, 1757.999878, 1259.000000, 0.000000, 1.000000).
 - While finishing [CommandEncoder (unlabeled)].

This because, currently, GLFW does not manage the framebuffer, but only the frame size: it's the example that deals with the downsizing of the framebuffer/Surface, based on the FrameSize acquired through GLFW:

  • First, when the window is resized, the example resize the Surface (framebuffer).
  • Then, ImGui calls glfwGetFramebufferSize from ImGui_ImplGLFW_NewFrame to set io.DisplaySize, but really gets only the "frame size" of the window, which can also be varied in the meantime, during the window drag, respect to Surface resized previously from example.
  • End, ImGui_ImplWGPU_RenderDrawData calls wgpuRenderPassEncoderSetViewport with the DisplaySize parameters, and if the Viewport is bigger of the Surface dimensions, an error occurs.

To avoid a further bothersome inconvenience that happens in this situation:
Viewport bounds (x: 0.000000, y: 0.000000, width: 747.000000, height: 864.000061) are not contained in the render target dimensions (747 x 864).
e.g. Viewport width: 864.000061 vs Surface width: 864, that happens from this call: wgpuRenderPassEncoderSetViewport(ctx, 0, 0, draw_data->FramebufferScale.x * draw_data->DisplaySize.x, draw_data->FramebufferScale.y * draw_data->DisplaySize.y, 0, 1);
A workaround (without to distort ImGui behavior) is to set the Surface just a pixel bigger of that acquired by FrameSize

This not happens in SDL because the "frame size" not change asynchronously, but only after aSDL_PollEvent call, so two calls of SDL_GetWindowSize, in the same iteration cycle, get the same sizes

The only option that works with GLFW is the one in which the example passes the Surface sizes to ImGui_ImplGLFW_NewFrame, but this distorts the current ImGui method and moreover, sooner or later, GLFW will be adapted to the WebGPU platform.

Anyway here there is an online GLFW EMSCRIPTEN example where I have modified ImGui_ImplGLFW_NewFrame that acquires the correct FrameBufferSize from the example, and all works fine.
(tested with last Google Chrome Canary, with Unsafe WebGPU Support - Enabled)

Currently the SDL example hasn't been changed yet

{ WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, pos), 0 },
{ WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, uv), 1 },
{ WGPUVertexFormat_Unorm8x4, (uint64_t)offsetof(ImDrawVert, col), 2 },
#endif

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this fix compatible with the VertexAttribute struct in the Rust implementation? https://docs.rs/wgpu/latest/wgpu/struct.VertexAttribute.html

As far as I know, the nextInChain field at the front is exclusive to the Google Dawn implementation. I think #ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN should be used here.

Comment thread backends/imgui_impl_wgpu.cpp Outdated
@alan-j-hu

Copy link
Copy Markdown
Contributor

I made a distinct PR for the issue mentioned above at #8438.

Because I'm working with IMGUI and Dawn and this is a compile error, I would prefer to have this fix merged sooner (if this larger PR takes longer to merge). I'm unsure if this is bad etiquette, feel free to disregard.

@BrutPitt

BrutPitt commented Mar 4, 2025

Copy link
Copy Markdown
Contributor Author

Current status of example_glfw_wgpu

First of all: the problem in DAWN with VK_KHR_cooperative_matrix (Vulkan backend) was solved.
https://issues.chromium.org/issues/397448368
(helped to find it)

Windows 11 (24H2)

All works fine - no problems, nor in native, nor in web

  • Native tested with backends: Vulkan / DX12 / DX11
  • Web tested in Chrome-Canary v.135

MacOS (Sequoia 15.3.1)

All works fine - no problems, nor in native, nor in web

  • Native tested with Metal backend
  • Web tested in Safary technology preview (Release 214 / WebKit 20622.1.2.111.3)

Linux Wayland (Gnome 47 / KDE-Plasma 6.3.1)

All works fine - no problems, nor in native, nor in web

  • Native tested with Vulkan backend
  • Web tested in Chrome-Canary v.135

Linux X11

Native have problems both: X11 on Xorg (WM: marco / xfwm4) and also X11 on Wayland

  • Validation Layer messages due different surface size (described here) continue to appear
  • Now the app sometime crashes on resizing window (due backend error), but it happens also with DAWN internal samples (e.g. ManualSurfaceTest)
  • Native tested with Vulkan backend

No problems in Web browser

  • Web tested in Chrome-Canary v.135

Note

The problems remain only in the X11 native.
Also the previous problem (Validation Layer messages due different surface size) was eliminated both in Web (EMSCRIPTEN) and in Linux Wayland.
It was not my merit: the example remained (practically) the same.

About example_sdl2_wgpu

Same tests done and same behavior as the example_glfw_wgpu, with the only differences:
always and only in Linux X11

  • in X11, the warnings of the Validation Layer (different surface size) do NOT appear.
  • in Linux works only X11 on X11 and Wayland on Wayland: X11 on Wayland seg-fault on Surface creation
  • now (here too, as in GLFW example) the app sometime crashes on resizing window (due internal backend error)

All tests are performed and compiled with:
DAWN 4dc49409e47bda9c777ccaa4028993361f8187cf 01 - Mar - 2025
Web release: EMSCRIPTEN v.4.0.4

@BrutPitt

BrutPitt commented Mar 25, 2025

Copy link
Copy Markdown
Contributor Author

Last commits add check_surface_texture_status function to check the WGPUSurfaceTexture .status and recreate the Surface in case of "not optimal" (bad) status.
Now the check doesn't crash anymore thanks to the patch released yesterday by DWAN (following the bug report I had opened about 2 weeks ago)
It also fixes the texture handle return value in case of "texture lost" status.

Now the examples work well.

Only the problem of the validation layer messages remains, and only in GLFW example running in X11.
But there must be an inherent problem in X11 (as also I have reported here)

In the meantime I added others WGPU / ImGui examples:

ImGuIZMO.quat WebGPU examples

And a very simple wgpu imgui mandelbrot example just to test and support (with and w/o imgui) the [bug report opened](https://issues.chromium.org/issues/403297812

@Starkium

Starkium commented Jun 4, 2025

Copy link
Copy Markdown

has there been any testing with SDL3, webgpu, and IMGUI? I didn't see an example, and this seemed to be closest. I'm using webgpu-native personally, but I could adapt it.

@ypujante

ypujante commented Jun 9, 2025

Copy link
Copy Markdown
Contributor

@ocornut I am not sure what is the status of this PR, but I just wanted to let you know that in Emscripten 4.0.10 (which was just released), the flag -sUSE_WEBGPU=1 is now deprecated and has a replacement: --use-port=emdawnwebgpu (which MUST be used both in compile and link phase, so the EMS flag in Makefile.emscripten).

The good news is that using this new syntax allow for using a much more recent version of Dawb/WebGPU both for the desktop and for Emscripten (v20250531.224602) as of Emscripten 4.0.10 and that includes all the API changes...

@BrutPitt

BrutPitt commented Jun 10, 2025

Copy link
Copy Markdown
Contributor Author

@ocornut I am not sure what is the status of this PR, but I just wanted to let you know that in Emscripten 4.0.10 (which was just released), the flag -sUSE_WEBGPU=1 is now deprecated and has a replacement: --use-port=emdawnwebgpu (which MUST be used both in compile and link phase, so the EMS flag in Makefile.emscripten).

That's correct.
But this method anyway existed also before EMSCRIPTEN version 4.0.10: the only difference is that now it becomes "official".
First you need Before it was necessary to download, install and configure separately emdawnwebgpu, (that was "unofficial" fork of EMSCRIPTEN for WebGPU developed by Google Dawn, now official in EMSCRIPTEN 4.0.10)

So currently remain always and anyway 4 development methods:

  • NATIVE: using DAWN or WGPU SDK (some minimal differences in structures and functions calls)
  • WEB: using EMSCRIPTEN
    • with --use-port=emdawnwebgpu flag (NEW available and official in EMSCRIPTEN)), using DAWN SDK (structures and functions calls)
    • with -sUSE_WEBGPU=1 flag, using WGPU SDK (structures and functions calls, now deprecated)

In the next few days I will also modify the examples (mentioned in this thread) to adapt them to the new version of EMSCRIPTEN

@ypujante

Copy link
Copy Markdown
Contributor

First you need to download, install and configure separately emdawnwebgpu, (that was "unofficial" fork of EMSCRIPTEN for WebGPU developed by Google Dawn, now official in EMSCRIPTEN 4.0.10)

Just to clarify, with --use-port=emdawnwebgpu you do not download the (emdawnwebgpu) project separately. That is the beauty of Emscripten ports: it does it for you. Prior to 4.0.10, you are correct that you could use it but you had to download it. Now it is just a matter of changing which flag to use (and of course fix the API changes...). Looking forward to this PR landing in master as I need it for own project.

@BrutPitt

BrutPitt commented Jun 11, 2025

Copy link
Copy Markdown
Contributor Author

Just to clarify, with --use-port=emdawnwebgpu you do not download the (emdawnwebgpu) project separately. That is the beauty of Emscripten ports: it does it for you. Prior to 4.0.10, you are correct that you could use it but you had to download it.

Sorry, my bad ... (my bad English, in this case)
I meant to say (as you rightly pointed out): Before Emscripten 4.0.10 was necessary to download, install and configure separately emdawnwebgpu (even for this complex and precarious mechanism I had not integrated it in the examples)... obviously now it's finally integrated in EMSCRIPTEN and it's an "official" option.
(in Italian first and before have same phoneme/word.. my mistake)

Thanks for the clarification.

Now it is just a matter of changing which flag to use (and of course fix the API changes...). Looking forward to this PR landing in master as I need it for own project.

I just started working: I plan it can be ready tomorrow or the day after tomorrow.

Comment thread examples/example_glfw_wgpu/main.cpp Outdated

// Synchronously (wait until) acquire Adapter
auto waitedAdapterFunc { instance.RequestAdapter(&adapterOptions, wgpu::CallbackMode::WaitAnyOnly, onRequestAdapter) };
instance.WaitAny(waitedAdapterFunc, UINT64_MAX);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does this work in Emscripten? Doesn't it require to use -sASYNCIFY=1?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Does this work in Emscripten? Doesn't it require to use -sASYNCIFY=1?

Yes, it's required.
As I just posted below:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would there be a way to avoid waiting on the cpp side? Adding -sASINCIFY is not a trivial change as it has some serious consequences (see doc)

1 (default): Run binaryen’s Asyncify pass to transform the code using asyncify. This emits a normal wasm file in the end, so it works everywhere, but it has a significant cost in terms of code size and speed. See https://emscripten.org/docs/porting/asyncify.html

Prior to this change, I could use ImGui (and I do) without using asyncify.

I suppose this change is only affecting the example and is not in the webgpu backend as far as I can tell so I guess I can try to find a way to initialize WebGPU in my project without relying on WaitAny / asyncify

@BrutPitt BrutPitt Jun 12, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, I meant in this example it is required, it's required by WaitAny

Before it was not necessary, because async() was set externally, via JS

I don't know if it will be possible to use WaitAny in the future without -sASYNCIFY=1 (with the previous method): based on this comment WaitAny (emwgpuWaitAny) will be removed via prepocessor, without the above EMSCRIPTEN flag

I suppose this change is only affecting the example and is not in the webgpu backend as far as I can tell so I guess I can try to find a way to initialize WebGPU in my project without relying on WaitAny / asyncify

asyncify should only be about the Future data type (like WGPUFutureWaitInfo parameter of WaitAny)

@BrutPitt BrutPitt Jun 13, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't know if it will be possible to use WaitAny in the future without -sASYNCIFY=1 (with the previous method): based on this comment WaitAny (emwgpuWaitAny) will be removed via prepocessor, without the above EMSCRIPTEN flag

Thinking about it, it's actually doable:
Here is the "old" ImGui example_glfw_wgpu, adapted with few changes to EMSCRIPEN 4.0.10 with "--use-port=emdawnwebgpu" flag and linked w/o -sASINCIFY=1
https://github.com/BrutPitt/myRepos/tree/master/wgpu_examples/example_glfw_wgpu

I hope it can be useful to you

(async() module is only for the Adapter and Device acquisition, done externally, in the HTML template via JS)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for providing an example that works without ASINCIFY!

@ocornut

ocornut commented Jun 12, 2025

Copy link
Copy Markdown
Owner

FYI i have just added support for the new ImGuiBackendFlags_RendererHasTextures protocol in the WebGPU/WGPU backend: 571dae9, which is likely to create conflicts with this PR. Please rebase over latest as you cleanup. Thank you.

@BrutPitt

BrutPitt commented Jun 12, 2025

Copy link
Copy Markdown
Contributor Author

About changes

  • It was necessary to comment on this #define from imgui_impl_wgpu.cpp: now Google Down code can be used both in Native and EMSCRIPTEN with "--use-port=emdawnwebgpu" flag mode with few differences.

    • ToDo: better #define discrimination / identificatione between IMGUI_IMPL_WEBGPU_BACKEND_DAWN / IMGUI_IMPL_WEBGPU_BACKEND_WGPU and EMSCRIPTEN (for both)
  • I had to modify the HTML "template" file for EMSCRIPTEN:
    whoever wrote the first version of the example, inserted the Adapter and Device acquisition in JavaScript inside the HTML file.
    In DAWN this is no longer necessary: ​​Native and WEB share the same code for Adapter and Device initialization, while for EMSCRIPTEN with -sUSE_WEBGPU=1 flag, I brought internally the JavaScript initialization inside the EM_ASYNC_JS macro

    • It would also be possible to eliminate the inline JS code and use only the CPP, even if it is slightly longer
  • I kept the initialization bool InitWGPU(GLFWwindow* window) separate, in different defines (different EMSCRIPTEN flags), for better reading and code management, even if some assignments are repeated.
    (Obviously there is no contraindication to integrating them into a single function)

  • Changes in CMakeFiles.txt

throw Error("WebGPU not supported.");
}

const adapter = await navigator.gpu.requestAdapter();

@ypujante ypujante Jun 13, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I noticed that you introduced support for both --use-port=emdawnwebgpu and -sUSE_WEBGPU=1 via CMake option. But this code removes the adapter/device entirely from the JavaScript section. How does it work with -sUSE_WEBGPU=1 then? I thought it was required as there was no other way to obtain the device.

@BrutPitt BrutPitt Jun 13, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

As reported in previous post, I moved it internally in the CPP source code, using EMSCRIPTEN EM_ASYNC_JS macro to call JS code directly from C/CPP

Then I call it here

I had to use EM_ASYNC_JSmacro (which then mandatory requires -sASINCIFY=1), instead of EM_JS, because await mandatory requires it

@BrutPitt BrutPitt Jun 13, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I thought it was required as there was no other way to obtain the device.

Using JS is not the only method to acquire Adaper and Device using -sUSE_WEBGPU=1 flag, of course it can also be done via C/CPP, but it's just longer:

// Adapter and device request functions
WGPUAdapter requestAdapter(WGPUInstance instance, WGPURequestAdapterOptions const * options) {
    struct UserData {
        WGPUAdapter adapter = nullptr;
        bool adapterAcquired = false;
    } userData;

    auto onAdapterRequest = [](WGPURequestAdapterStatus status, WGPUAdapter adapter, char const * message, void * pUserData) {
        if (status == WGPURequestAdapterStatus_Success) ((UserData *) pUserData)->adapter = adapter;
        else                                            printf("Could not get WebGPU adapter: %s \n", message);

        ((UserData *) pUserData)->adapterAcquired = true;
    };

    wgpuInstanceRequestAdapter(instance,  options,  onAdapterRequest, &userData);

    while (!userData.adapterAcquired)  emscripten_sleep(100);   // wait until adapter is acquired
    assert(userData.adapter!=nullptr);                          // sanity check
    return userData.adapter;
}

WGPUDevice requestDevice(WGPUAdapter adapter, WGPUDeviceDescriptor const * descriptor) {
    struct UserData {
        WGPUDevice device = nullptr;
        bool deviceAcquired = false;
    } userData;

    auto onDeviceRequest = [](WGPURequestDeviceStatus status, WGPUDevice device, char const * message, void * pUserData) {
        if (status == WGPURequestDeviceStatus_Success) ((UserData *) pUserData)->device = device;
        else                                           printf("Could not get WebGPU device: %s \n", message);

        ((UserData *) pUserData)->deviceAcquired = true;
    };

    wgpuAdapterRequestDevice(adapter, descriptor, onDeviceRequest, &userData);

    while (!userData.deviceAcquired) emscripten_sleep(100);     // wait until device is acquired
    assert(userData.device!=nullptr);                           // sanity check

    return userData.device;
}

Subsequently to acquire Adapter and Device:

    wgpu::Adapter adapter(requestAdapter(instance.Get(), {}));
    wgpu::Device device(requestDevice(adapter.Get(), {}));;

N.B.
This code has not been tested on this example
I took this from another code of mine, it should work the same, but it might also need some adaptation.

P.S.
Also this code requires -sASINCIFY=1 because emscripten_sleep requires it

@ypujante

Copy link
Copy Markdown
Contributor

@BrutPitt When you think you are done with your PR, I will be more than happy to test the Emscripten part locally if you want. Just let me know.

@ypujante

Copy link
Copy Markdown
Contributor

To follow up on the use of ASYNCIFY, I changed my example code (on a branch for now) to get rid of ASYNCIFY entirely. You can see for yourself how I did it.

The idea is to use WaitAny but with a timeout of 0 and "wait" until the device is initialized using the Emscripten main loop.

Is it convoluted compared to the ASYNCIFY version, absolutely! But the end result is pretty dramatic:

// compiled in -O2 mode
// without ASYNCIFY
-rwxr-xr-x@ 1 ypujante  staff  39552 Jun 15 08:51 index.wasm
// with ASYNCIFY
-rwxr-xr-x@ 1 ypujante  staff  56754 Jun 15 08:52 index.wasm

I am not suggesting we should change it for ImGui but my original concern about introducing ASYNCIFY is valid. Like I pointed out, this change is only in the example code, not in the backend code so I am not too worried about it. And for people who care, there are other ways to do it. So I am good on my end.

@BrutPitt

BrutPitt commented Jun 15, 2025

Copy link
Copy Markdown
Contributor Author

Briefly about latest changes.
I will comment, soon, more specifically and directly on the commit changes.
Mostly changes in imgui_impl_wgpu.cpp (although very few and almost exclusively concern the use of #define)

Now the example covers all 4 compilation methods:

  • Native / Desktop:
    • Google DAWN
    • WGPU-Native
  • WEB: using EMSCRIPTEN
    • with --use-port=emdawnwebgpu flag (official EMSCRIPTEN >= 4.0.10), that it uses Google DAWN
    • with -sUSE_WEBGPU=1 flag, that it uses an "outated" WGPU functions calls and structures (deprecated in EMSCRIPTEN >= 4.0.10)

The differences between the four methods concern mostly the acquisition of Adapter and Device and the creation of the Surface (in WebGPU initialization)
Now they are systematically divided in two distinct sections (between DAWN initialization and WGPU initialization at the end of the main.cpp file) and each one internally includes both Native and WEB (via EMSCRIPTEN).
This allowed me to separate the executing code of IMGUI which is (practically) UNIQUE for all 4 methods.

Support for WGPU-Native has been introduced.

Neither the previous code, nor my subsequent changes, supported WGPU-Native directly (it was only done through EMSCRIPTEN: obviously I'm talking about the example_glfw_wgpu code)

To allow this I had to introduce a new file: glfw_wgpu.c
In WGPU-Native there is no internal support for GLFW (as there is in DAWN), but each example (in the official WGPU-Native repo) integrates a similar piece of code.
I simply created a function from it (making it even more "readable") to allow the use of GLFW, and I put it in an external file, to avoid confusion with the IMGUI example/code

@ocornut
This is obviously a personal design, based on the (my personal) best integration of the 4 methods.
Of course your point of view will be centered on the best solution for IMGUI and I am aware that it might not even coincide.

I await feedback, requests, suggestions and criticisms from everyone

The example currently has been tested in:

  • Linux X11/Wayland (all 4 build methods)
  • Windows 11, only Native/Desktop (both DAWN and WGPU, also compiled with VS2022 and CLion, using MS compiler for both)

P.S.
I will probably refine and optimize the code in the next few days, as well as testing it on MacOS.
The SDL2 version has not been modified yet, I await feedback on these changes first

ocornut added a commit that referenced this pull request Nov 3, 2025
ocornut pushed a commit that referenced this pull request Nov 3, 2025
@ocornut

ocornut commented Nov 3, 2025

Copy link
Copy Markdown
Owner

I also optimized the headers in all main.cpp
(== removed #include #include <webgpu/webgpu.h>`)

I don't think this is good nor required. We want optimize headers or library ccode from unnecessarily including headers that are not needed. But we also want example code to be explicit and self-documenting, and the main.cpp can include this even if imgui_impl_wgpu.h already does.

CreateWGPUSurface (in main.cpp)
I moved it to the bottom of the file.
I know you don't like it when I “move” functions ;-) , but there's a good reason for it:
First, let's remove these lines.
#undef Status // X11 headers are leaking this.
#undef Success // X11 headers are leaking this.

Previously it was explicit that this is the workaround. So user carrying things into their file would find the solution at a glance. Now the situation is that user modifying the code might get into this "new" issue and not know what to do. I applied a modified commit with the #undef Status from imgui code + comments about the leak.

I also fixed a few more inconsistencies (e.g. made declaration statics).

Further changes should be made in a new PR probably.

@BrutPitt

BrutPitt commented Nov 4, 2025

Copy link
Copy Markdown
Contributor Author

I also optimized the headers in all main.cpp
(== removed #include #include <webgpu/webgpu.h>`)

I don't think this is good nor required. We want optimize headers or library ccode from unnecessarily including headers that are not needed. But we also want example code to be explicit and self-documenting, and the main.cpp can include this even if imgui_impl_wgpu.h already does.

CreateWGPUSurface (in main.cpp)
I moved it to the bottom of the file.
I know you don't like it when I “move” functions ;-) , but there's a good reason for it:
First, let's remove these lines.
#undef Status // X11 headers are leaking this.
#undef Success // X11 headers are leaking this.

Previously it was explicit that this is the workaround. So user carrying things into their file would find the solution at a glance. Now the situation is that user modifying the code might get into this "new" issue and not know what to do. I applied a modified commit with the #undef Status from imgui code + comments about the leak.

I also fixed a few more inconsistencies (e.g. made declaration statics).

Further changes should be made in a new PR probably.

OK
Just two last thing, this line:

#if !defined(__EMSCRIPTEN__) && (defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN))

It can simply be:

#if !defined(__EMSCRIPTEN__)

*In Native, at least one IMGUI_IMPL_WEBGPU_BACKEND_XXXX must be defined
(same thing in imgui_impl_wgpu)

Just to clarify the mechanism:
One of the two: IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU is always selected based on the choice of IMGUI_DAWN_DIR or IMGUI_WGPU_DIR (respectively).
(I preferred not to include additional build options, but to select based on the chosen library.)

And this also occurs in EMSCRIPTEN to differentiate the new syntax (IMGUI_IMPL_WEBGPU_BACKEND_DAWN+__EMSCRIPTEN__) from the old/deprecated one (IMGUI_IMPL_WEBGPU_BACKEND_WGPU+__EMSCRIPTEN__).
(Here too, I preferred to avoid adding further definitions, given that the code will be merged when it becomes unique.)

That said, it is important to note that by forcing this (it was already selected/controlled by the CMake option):

#if (__EMSCRIPTEN_major__ >= 4) && (__EMSCRIPTEN_minor__ >= 0) && (__EMSCRIPTEN_tiny__ >= 10)
#define IMGUI_IMPL_WEBGPU_BACKEND_DAWN
#else
#define IMGUI_IMPL_WEBGPU_BACKEND_WGPU
#endif

You avoid the possibility of building the example (or any other project) with the old (deprecated) syntax even with EMS >= 4.0.10.
Currently, this possibility was left open, as described in the README:

Generate Emscripten forcing -sUSE_WEBGPU=1 deprecated flag even with EMS >= 4.0.10

  • emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="-sUSE_WEBGPU=1" -B where_to_build_dir
    • it set IMGUI_IMPL_WEBGPU_BACKEND_WGPU compiler define

(and even the code in imgui_impl_wgpu would currently be set up to do so)

Of course it's fine, but it was important to point out that the above CMake option is no longer valid: will end up generating a compilation error with EMS >= 4.0.10

... really the last thing:

You may want to add in imgui_impl_wgpu:

#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) && !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
#error at least one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN and IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be defined!
#endif

in addition to the control that already exists:

#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) == defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
#error Exactly one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be defined!
#endif

Currently, this is also true in EMS.
In the event of EMS code unification and the removal of IMGUI_IMPL_WEBGPU_BACKEND_XXXX in EMS (no longer necessary), it will be possible to differentiate EMSCRIPTEN from Native.

CMake already checks both things (for all examples), but obviously imgui_impl_wgpu will be used (alone) in other projects.
(Hopefully) the final/global unification (final WebGPU specifications) will not require any code differentiation, but currently it is necessary to know “which” code you are dealing with.

@ocornut

ocornut commented Nov 7, 2025

Copy link
Copy Markdown
Owner

Pushed a simplification 86daa89

@ypujante

ypujante commented Nov 7, 2025

Copy link
Copy Markdown
Contributor

@ocornut @BrutPitt I just wanted to point out that -sUSE_WEBGPU was completely removed from Emscripten v 4.0.18 (see ChangeLog). Honestly I am a bit surprised that it was removed so quickly after being deprecated... but it has. Which makes this PR and changes quite valuable...

Intrets pushed a commit to Intrets/imgui that referenced this pull request Jan 1, 2026
Intrets pushed a commit to Intrets/imgui that referenced this pull request Jan 1, 2026
@ocornut

ocornut commented Feb 19, 2026

Copy link
Copy Markdown
Owner

@BrutPitt do you know why <emscripten/html5_webgpu.h> doesn't seem to exist in Emscripten 5.0.1 but it works with Emscripten 5.0.0 ?

Using --use-port=contrib.glfw3 --use-port=emdawnwebgpu

main.cpp:23:10: fatal error: 'emscripten/html5_webgpu.h' file not found
   23 | #include <emscripten/html5_webgpu.h>

https://github.com/ocornut/imgui/actions/runs/22188320971/job/64168427672

@ypujante

Copy link
Copy Markdown
Contributor

With --use-port=emdawnwebgpu you are supposed to use

#include <webgpu/webgpu.h>
#include <webgpu/webgpu_cpp.h>

I do not know exactly what happened, but my guess is that emscripten/html5_webgpu.h was used by -sUSE_WEBGPU which was deprecated and removed many months ago. They must have cleaned the leftovers file...

@ocornut

ocornut commented Feb 19, 2026

Copy link
Copy Markdown
Owner

If I use those includes then:

em++  -DIMGUI_DISABLE_FILE_FUNCTIONS -I../.. -I../../backends -Wall -Wformat -Os  -s USE_SDL=2 -s DISABLE_EXCEPTION_CATCHING=1 --use-port=emdawnwebgpu  -c -o main.o main.cpp
main.cpp:446:5: error: unknown type name 'WGPUSurfaceDescriptorFromCanvasHTMLSelector'
  446 |     WGPUSurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {};
      |     ^
main.cpp:447:37: error: use of undeclared identifier 'WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector'
  447 |     html_surface_desc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector;
      |                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:455:21: error: use of undeclared identifier 'wgpuSurfaceGetPreferredFormat'
  455 |     preferred_fmt = wgpuSurfaceGetPreferredFormat(wgpu_surface, {} /* adapter */);
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

@ypujante

Copy link
Copy Markdown
Contributor

I am currently traveling and I have very limited access. You can take a look at this example I have which was adapted from the ImGui one to use ImGui as a port. But the logic for webgpu should be the same...

@r-lyeh

r-lyeh commented Feb 22, 2026

Copy link
Copy Markdown
Contributor

While working on #9257 I learned about how to compile with latest emscripten 5.0.1. Attaching diff in case that helps. tl-dr? remove most of the __EMSCRIPTEN__ branches we have in code.

Here is the Dawn codepath fixed:

C:\prj\imgui\examples\example_glfw_wgpu>emcc main.cpp -I ..\..\ -I ..\..\backends --use-port=emdawnwebgpu -DIMGUI_IMPL_WEBGPU_BACKEND_DAWN ..\..\imgui.cpp ..\..\imgui_demo.cpp ..\..\imgui_draw.cpp ..\..\imgui_tables.cpp ..\..\imgui_widgets.cpp ..\..\backends\imgui_impl_wgpu.cpp ..\..\backends\imgui_impl_glfw.cpp -s USE_GLFW=3 -s ASYNCIFY -s ASYNCIFY_STACK_SIZE=8192 -o index.html && emrun index.html

diff --git a/examples/example_glfw_wgpu/main.cpp b/examples/example_glfw_wgpu/main.cpp
index 02e3bfeda..67a8fa642 100644
--- a/examples/example_glfw_wgpu/main.cpp
+++ b/examples/example_glfw_wgpu/main.cpp
@@ -19,9 +19,6 @@
 #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
 
@@ -461,30 +458,14 @@ static bool InitWGPU(GLFWwindow* window)
     instanceDesc.requiredFeatures = &timedWaitAny;
     wgpu_instance = wgpuCreateInstance(&instanceDesc);
 
-#ifdef __EMSCRIPTEN__
-    getAdapterAndDeviceViaJS();
-
-    wgpu_device = emscripten_webgpu_get_device();
-    IM_ASSERT(wgpu_device != nullptr && "Error creating the Device");
-
-    WGPUSurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {};
-    html_surface_desc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector;
-    html_surface_desc.selector = "#canvas";
-
-    WGPUSurfaceDescriptor surface_desc = {};
-    surface_desc.nextInChain = &html_surface_desc.chain;
-
-    // Create the surface.
-    wgpu_surface = wgpuInstanceCreateSurface(wgpu_instance, &surface_desc);
-    preferred_fmt = wgpuSurfaceGetPreferredFormat(wgpu_surface, {} /* adapter */);
-#else // __EMSCRIPTEN__
-
+#ifndef __EMSCRIPTEN__
 #if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
     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);
 #endif
+#endif // __EMSCRIPTEN__
 
     WGPUAdapter adapter = RequestAdapter(wgpu_instance);
     ImGui_ImplWGPU_DebugPrintAdapterInfo(adapter);
@@ -500,7 +481,6 @@ static bool InitWGPU(GLFWwindow* window)
     wgpuSurfaceGetCapabilities(wgpu_surface, adapter, &surface_capabilities);
 
     preferred_fmt = surface_capabilities.formats[0];
-#endif // __EMSCRIPTEN__
 #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU
 
     wgpu_surface_configuration.presentMode = WGPUPresentMode_Fifo;

@r-lyeh

r-lyeh commented Feb 22, 2026

Copy link
Copy Markdown
Contributor

Also this compiler error while trying to fix the the emcc+webgpu backend, hinting that pure webgpu is no longer supported as far as I could read:

emcc: error: invalid command line setting `-sUSE_WEBGPU=1`: No longer supported; replaced by --use-port=emdawnwebgpu, which implements a newer (but incompatible) version of webgpu.h - see tools/ports/emdawnwebgpu.py

probably would be good to allow that codepath only if emcc <= 5.0.0

@ypujante

Copy link
Copy Markdown
Contributor

@r-lyeh this option was removed well before 5.0.0 (the version numbering in Emscripten is completely meaningless and does not follow any breaking API changes unfortunately...)

@ocornut

ocornut commented Feb 23, 2026

Copy link
Copy Markdown
Owner

@r-lyeh I cannot seem to get this patch to work there are too many other changes involved in main.cpp and in backend e.g.

# em++  -DIMGUI_DISABLE_FILE_FUNCTIONS -I../.. -I../../backends -Wall -Wformat -Os  -s USE_SDL=3 -s DISABLE_EXCEPTION_CATCHING=1 --use-port=emdawnwebgpu  -c -o imgui_impl_wgpu.o ../../backends/imgui_impl_wgpu.cpp

../../backends/imgui_impl_wgpu.cpp:260:8: error: unknown type name 'WGPUProgrammableStageDescriptor'
  260 | static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(const char* wgsl_source)
      |        ^
../../backends/imgui_impl_wgpu.cpp:277:5: error: unknown type name 'WGPUProgrammableStageDescriptor'
  277 |     WGPUProgrammableStageDescriptor stage_desc = {};
      |     ^
../../backends/imgui_impl_wgpu.cpp:704:5: error: unknown type name 'WGPUProgrammableStageDescriptor'
  704 |     WGPUProgrammableStageDescriptor vertex_shader_desc = ImGui_ImplWGPU_CreateShaderModule(__shader_vert_wgsl);
      |     ^
../../backends/imgui_impl_wgpu.cpp:716:11: error: cannot initialize a member subobject of type 'WGPUChainedStruct *' (aka 'struct WGPUChainedStruct *') with an rvalue of
      type 'WGPUVertexFormat'
  716 |         { WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, pos), 0 },
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~
../../backends/imgui_impl_wgpu.cpp:716:39: error: cannot initialize a member subobject of type 'WGPUVertexFormat' (aka 'enum WGPUVertexFormat') with an rvalue of type
      'uint64_t' (aka 'unsigned long long')
  716 |         { WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, pos), 0 },
      |                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../../backends/imgui_impl_wgpu.cpp:717:11: error: cannot initialize a member subobject of type 'WGPUChainedStruct *' (aka 'struct WGPUChainedStruct *') with an rvalue of
      type 'WGPUVertexFormat'
  717 |         { WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, uv),  1 },

Feel free to add changes to your WGVK PR if it compiles with everything I would extract changes out of it.

@ypujante

ypujante commented Feb 23, 2026

Copy link
Copy Markdown
Contributor

I also wanted to point out that I posted in this very thread about -sUSE_WEBGPU being removed... see post...

@ocornut

ocornut commented Feb 23, 2026

Copy link
Copy Markdown
Owner

No-one can humanly parse a 143 messages topic especially when GitHub enforce collapsing by default :(
Anyhow, we don't use -sUSE_WEBGPU in our builds but technically still support Emscripten < 4.0.10. As we introduce fixes for 5.0.1+ i don't mind removing <4.0.10 code. Any explicit fix PR welcome.

@ypujante

Copy link
Copy Markdown
Contributor

@ocornut It is version 4.0.18 for the flag. I can take a look at the PR next week (as I am traveling this week)

@ocornut

ocornut commented Feb 24, 2026

Copy link
Copy Markdown
Owner

The flag was marked obsolete in 4.0.10 and still supported, and 4.0.18 removed it.
Either way I am happy to move forward and stop supporting < 4.0.18 to keep some sanity with that always-moving target.
But right now none of the example are building with latest Emscripten and I have no idea what to do.

I am totally confused as where you are finding documentation about WebGPU api. Every time I search for a keyword I land on sub-standard amount of information.

@ypujante

ypujante commented Feb 24, 2026

Copy link
Copy Markdown
Contributor

@ocornut I am not the one who worked on this PR and I do not know the code well enough. Maybe @BrutPitt could help? As I mentioned I am traveling and cannot take a look at it at the moment, but I should have some spare cycles next week and don't mind getting rid of the old way to at the minimum clean up the code.

I know it might not be a suggestion you like but when I ported WebGPU Shader Toy from -sUSE_WEBGPU to --use-port=emdawnwebgu I did ask AI to help with fixing the errors I was seeing (I didn't apply the answers blindly, but that helped with the explanation of what had changed)

@ocornut

ocornut commented Feb 24, 2026

Copy link
Copy Markdown
Owner

Ah it turns out the main reason was the version check was incorrect:

#ifdef __EMSCRIPTEN_MAJOR__
#if (__EMSCRIPTEN_MAJOR__ >= 4) && (__EMSCRIPTEN_MINOR__ >= 0) && (__EMSCRIPTEN_TINY__ >= 10)
#define IMGUI_IMPL_WEBGPU_BACKEND_DAWN
[...]

This would fail with 5.0.0+.

Fixed with 2b415e6

Now all examples are building for me. SDL3 doesn't run tho.

@ypujante

Copy link
Copy Markdown
Contributor

Glad you found a quick fix! Another casualty of nonsensical Emscripten version numbering...

@ocornut

ocornut commented Feb 24, 2026

Copy link
Copy Markdown
Owner

Glad you found a quick fix! Another casualty of nonsensical Emscripten version numbering...

To be fair that was my mistake, the logic was wrong.

dear imgui use IMGUI_VERSION_NUM which is easier to use because it is a single number but make it less obvious to support LTS on old versions (which dear imgui doesn't do anyhow).

@ypujante

ypujante commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

@ocornut

Anyhow, we don't use -sUSE_WEBGPU in our builds but technically still support Emscripten < 4.0.10. As we introduce fixes for 5.0.1+ i don't mind removing <4.0.10 code. Any explicit fix PR welcome.

I have now some free time and I am going to spend time on "cleaning" up the code of -sUSE_WEBGPU. Please speak up if you don't want this anymore or if somebody else is working on it. I wouldn't want to be wasting time.

This will require dropping support for Emscripten < 4.0.18 (released on 2025/10/24)

Thanks

@ypujante

ypujante commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

Sorry I was wrong about dropping support for 4.0.18. Since the new port was introduced in 4.0.10, no change is required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backends web emscripten, wgpu etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants