summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-01-28 01:10:05 +0100
committerskal <pascal.massimino@gmail.com>2026-01-28 01:10:05 +0100
commit6cd6fb41ed44bd37bd05e5a4abf23661605c00df (patch)
treef3c5fb237b71bc6ad2d67dea62324b2edede51c3
parenta7bcf5e9cd6884d010b5cec0146293a0515242fc (diff)
refactor(gpu): Integrate WebGPU via system wgpu-native and glfw3webgpu
Replaces the complex wgpu-native submodule and manual platform-specific surface creation with a system-wide wgpu-native install (via Homebrew) and the glfw3webgpu helper library. - Updates scripts/project_init.sh to fetch glfw3webgpu and ensure wgpu-native is installed. - Refactors CMakeLists.txt to link against the system wgpu-native library. - Simplifies src/platform.cc to use glfwCreateWindowWGPUSurface. - Simplifies src/gpu/gpu.cc to use standard WebGPU headers. - Updates FETCH_DEPS.md with new installation instructions. - Updates PROJECT_CONTEXT.md with the new integration strategy.
-rw-r--r--CMakeLists.txt85
-rw-r--r--FETCH_DEPS.md31
-rw-r--r--PROJECT_CONTEXT.md5
-rwxr-xr-xscripts/project_init.sh25
-rw-r--r--src/platform.cc78
-rw-r--r--third_party/glfw3webgpu/glfw3webgpu.c181
-rw-r--r--third_party/glfw3webgpu/glfw3webgpu.h62
7 files changed, 332 insertions, 135 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b06bd6d..fc4ea81 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,30 +6,22 @@ option(DEMO_SIZE_OPT "Enable size optimization flags" OFF)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
-# Search in both debug and release
-set(WGPU_SEARCH_PATHS
- ${CMAKE_CURRENT_SOURCE_DIR}/third_party/wgpu-native/target/debug
- ${CMAKE_CURRENT_SOURCE_DIR}/third_party/wgpu-native/target/release
-)
-
-find_library(
- WGPU_LIBRARY NAMES libwgpu_native.a wgpu_native.lib wgpu_native
- HINTS ${WGPU_SEARCH_PATHS}
- REQUIRED
-)
+# Find wgpu-native (system install)
+find_library(WGPU_LIBRARY NAMES wgpu_native libwgpu_native REQUIRED)
+find_path(WGPU_INCLUDE_DIR NAMES webgpu.h PATH_SUFFIXES webgpu-headers REQUIRED)
include_directories(
src
third_party
- third_party/wgpu-native/ffi
- third_party/wgpu-native/ffi/webgpu-headers
+ ${WGPU_INCLUDE_DIR}
+ third_party/glfw3webgpu
)
find_package(glfw3 REQUIRED)
set(DEMO_LIBS glfw ${WGPU_LIBRARY})
-# Platform-specific dependencies for wgpu-native
+# Platform-specific dependencies
if (APPLE)
set_source_files_properties(src/platform.cc PROPERTIES COMPILE_FLAGS "-x objective-c++")
list(APPEND DEMO_LIBS
@@ -52,6 +44,7 @@ add_executable(demo64k
src/audio/idct.cc
src/audio/window.cc
src/audio/synth.cc
+ third_party/glfw3webgpu/glfw3webgpu.c
)
target_link_libraries(demo64k PRIVATE ${DEMO_LIBS})
@@ -86,31 +79,57 @@ if(DEMO_BUILD_TESTS)
target_include_directories(test_synth PRIVATE src)
add_test(NAME SynthEngineTest COMMAND test_synth)
- add_executable(test_spectool
- src/tests/test_spectool.cc
- src/audio/audio.cc
- src/audio/window.cc
- src/audio/fdct.cc
- src/audio/synth.cc
- src/audio/idct.cc
- )
- target_include_directories(test_spectool PRIVATE src third_party)
+ add_executable(test_spectool
+
+ src/tests/test_spectool.cc
+
+ src/audio/audio.cc
+
+ src/audio/window.cc
+
+ src/audio/fdct.cc
+
+ src/audio/synth.cc
+
+ src/audio/idct.cc
+
+ third_party/glfw3webgpu/glfw3webgpu.c
+
+ )
+
+ target_include_directories(test_spectool PRIVATE
+
+ src
+
+ third_party
+
+ ${WGPU_INCLUDE_DIR}
+
+ third_party/glfw3webgpu
+
+ )
target_link_libraries(test_spectool PRIVATE ${DEMO_LIBS})
add_test(NAME SpectoolEndToEndTest COMMAND test_spectool)
endif()
option(DEMO_BUILD_TOOLS "Build tools" OFF)
if(DEMO_BUILD_TOOLS)
- add_executable(spectool
- tools/spectool.cc
- src/platform.cc
- src/audio/audio.cc
- src/audio/fdct.cc
- src/audio/idct.cc
- src/audio/window.cc
- src/audio/synth.cc
- )
- target_include_directories(spectool PRIVATE src third_party)
+ add_executable(spectool
+ tools/spectool.cc
+ src/platform.cc
+ src/audio/audio.cc
+ src/audio/fdct.cc
+ src/audio/idct.cc
+ src/audio/window.cc
+ src/audio/synth.cc
+ third_party/glfw3webgpu/glfw3webgpu.c
+ )
+ target_include_directories(spectool PRIVATE
+ src
+ third_party
+ ${WGPU_INCLUDE_DIR}
+ third_party/glfw3webgpu
+ )
target_link_libraries(spectool PRIVATE ${DEMO_LIBS})
add_executable(specview
diff --git a/FETCH_DEPS.md b/FETCH_DEPS.md
index 3d5cc0e..24cbf08 100644
--- a/FETCH_DEPS.md
+++ b/FETCH_DEPS.md
@@ -35,8 +35,19 @@ third_party/miniaudio.h
WebGPU implementation via wgpu-native.
-Source:
-https://github.com/gfx-rs/wgpu-native
+### Installation
+
+**macOS:**
+```bash
+brew install wgpu-native
+```
+
+**Other platforms:**
+Please install `wgpu-native` such that `libwgpu_native` (static or shared) is in your library path and headers are in your include path (under `webgpu/`).
+
+## glfw3webgpu
+
+Helper library for creating WebGPU surfaces from GLFW windows.
### Automatic fetch
@@ -44,18 +55,4 @@ Use one of the provided scripts:
- scripts/project_init.sh
- scripts/project_init.bat
-These scripts will run `git submodule update --init --recursive` to fetch `wgpu-native` and then build its static library.
-
-### Manual fetch
-
-Run the following commands in the project root directory:
-```bash
-git submodule add https://github.com/gfx-rs/wgpu-native third_party/wgpu-native
-git submodule update --init --recursive
-cd third_party/wgpu-native
-make lib-native # Requires Rust toolchain and LLVM/Clang to be installed.
-cd ../..
-```
-
-Expected static library location (for linking):
-- `third_party/wgpu-native/target/release/libwgpu_native.a` (or platform equivalent like `.lib` or `.dylib`)
+These scripts will download `glfw3webgpu.h` and `glfw3webgpu.c` into `third_party/glfw3webgpu`.
diff --git a/PROJECT_CONTEXT.md b/PROJECT_CONTEXT.md
index 1ee929c..39f050c 100644
--- a/PROJECT_CONTEXT.md
+++ b/PROJECT_CONTEXT.md
@@ -49,6 +49,11 @@ Incoming tasks in no particular order:
- `spectool`: A command-line tool for analyzing WAV/MP3 files into `.spec` spectrogram format and for playing back `.spec` files through the synth engine.
- `specview`: A command-line tool for visualizing `.spec` spectrogram files in ASCII art.
+### WebGPU Integration:
+- **Strategy**: Uses system-installed `wgpu-native` (e.g., via Homebrew) for the implementation.
+- **Surface Creation**: Uses `glfw3webgpu` helper library to abstract platform-specific surface creation from GLFW windows, keeping the codebase clean and cross-platform.
+- **Headers**: Uses standard `<webgpu.h>` provided by the system install.
+
### Coding Style:
- **Standard**: Adopted a consistent coding style enforced by `.clang-format`.
- **Rules**: 2-space indentation, no tabs, 80-column line limit.
diff --git a/scripts/project_init.sh b/scripts/project_init.sh
index db24c8f..549e146 100755
--- a/scripts/project_init.sh
+++ b/scripts/project_init.sh
@@ -14,19 +14,26 @@ else
echo "miniaudio.h already present."
fi
-# wgpu-native submodule
-if [ ! -d third_party/wgpu-native ]; then
- echo "Fetching wgpu-native submodule..."
- git submodule update --init --recursive
+# glfw3webgpu (helper for GLFW + WebGPU)
+mkdir -p third_party/glfw3webgpu
+if [ ! -f third_party/glfw3webgpu/glfw3webgpu.h ]; then
+ echo "Fetching glfw3webgpu..."
+ curl -L https://raw.githubusercontent.com/eliemichel/glfw3webgpu/main/glfw3webgpu.h -o third_party/glfw3webgpu/glfw3webgpu.h
+ curl -L https://raw.githubusercontent.com/eliemichel/glfw3webgpu/main/glfw3webgpu.c -o third_party/glfw3webgpu/glfw3webgpu.c
else
- echo "wgpu-native submodule already present."
+ echo "glfw3webgpu already present."
fi
-if [ ! -f third_party/wgpu-native/target/release/libwgpu_native.a ]; then
- echo "Building wgpu-native static library..."
- (cd third_party/wgpu-native && make lib-native)
+# Check for wgpu-native (system install)
+if command -v brew >/dev/null 2>&1; then
+ if ! brew list wgpu-native >/dev/null 2>&1; then
+ echo "Warning: wgpu-native not found via brew. Installing..."
+ brew install wgpu-native
+ else
+ echo "wgpu-native found (via brew)."
+ fi
else
- echo "wgpu-native static library already built."
+ echo "Warning: Homebrew not found. Ensure wgpu-native is installed manually."
fi
echo "Done."
diff --git a/src/platform.cc b/src/platform.cc
index 09cc7ac..fa49b53 100644
--- a/src/platform.cc
+++ b/src/platform.cc
@@ -1,22 +1,7 @@
#include "platform.h"
-
-#ifdef _WIN32
-#define GLFW_EXPOSE_NATIVE_WIN32
-#elif defined(__APPLE__)
-#define GLFW_EXPOSE_NATIVE_COCOA
-#else
-#define GLFW_EXPOSE_NATIVE_X11
-#define GLFW_EXPOSE_NATIVE_WAYLAND
-#endif
+#include "glfw3webgpu.h"
#include <GLFW/glfw3.h>
-#include <GLFW/glfw3native.h>
-
-#ifdef __APPLE__
-#import <QuartzCore/CAMetalLayer.h>
-#import <AppKit/NSWindow.h>
-#import <AppKit/NSView.h>
-#endif
static GLFWwindow *window = nullptr;
static int windowed_x, windowed_y, windowed_w, windowed_h;
@@ -82,64 +67,5 @@ GLFWwindow *platform_get_window() { return window; }
double platform_get_time() { return glfwGetTime(); }
WGPUSurface platform_create_wgpu_surface(WGPUInstance instance) {
-#if defined(GLFW_EXPOSE_NATIVE_COCOA)
- id metal_layer = NULL;
- NSWindow *ns_window = glfwGetCocoaWindow(window);
- [ns_window.contentView setWantsLayer:YES];
- metal_layer = [CAMetalLayer layer];
- [ns_window.contentView setLayer:metal_layer];
-
- WGPUSurfaceSourceMetalLayer metal_src = {};
- metal_src.chain.sType = WGPUSType_SurfaceSourceMetalLayer;
- metal_src.layer = metal_layer;
-
- WGPUSurfaceDescriptor surface_desc = {};
- surface_desc.nextInChain = (const WGPUChainedStruct *)&metal_src;
-
- return wgpuInstanceCreateSurface(instance, &surface_desc);
-
-#elif defined(GLFW_EXPOSE_NATIVE_WIN32)
- HWND hwnd = glfwGetWin32Window(window);
- HINSTANCE hinstance = GetModuleHandle(NULL);
-
- WGPUSurfaceSourceWindowsHWND win_src = {};
- win_src.chain.sType = WGPUSType_SurfaceSourceWindowsHWND;
- win_src.hinstance = hinstance;
- win_src.hwnd = hwnd;
-
- WGPUSurfaceDescriptor surface_desc = {};
- surface_desc.nextInChain = (const WGPUChainedStruct *)&win_src;
-
- return wgpuInstanceCreateSurface(instance, &surface_desc);
-
-#elif defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_WAYLAND)
- if (glfwGetPlatform() == GLFW_PLATFORM_X11) {
- Display *x11_display = glfwGetX11Display();
- Window x11_window = glfwGetX11Window(window);
-
- WGPUSurfaceSourceXlibWindow x11_src = {};
- x11_src.chain.sType = WGPUSType_SurfaceSourceXlibWindow;
- x11_src.display = x11_display;
- x11_src.window = x11_window;
-
- WGPUSurfaceDescriptor surface_desc = {};
- surface_desc.nextInChain = (const WGPUChainedStruct *)&x11_src;
-
- return wgpuInstanceCreateSurface(instance, &surface_desc);
- } else if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) {
- struct wl_display *wayland_display = glfwGetWaylandDisplay();
- struct wl_surface *wayland_surface = glfwGetWaylandWindow(window);
-
- WGPUSurfaceSourceWaylandSurface wl_src = {};
- wl_src.chain.sType = WGPUSType_SurfaceSourceWaylandSurface;
- wl_src.display = wayland_display;
- wl_src.surface = wayland_surface;
-
- WGPUSurfaceDescriptor surface_desc = {};
- surface_desc.nextInChain = (const WGPUChainedStruct *)&wl_src;
-
- return wgpuInstanceCreateSurface(instance, &surface_desc);
- }
-#endif
- return nullptr;
+ return glfwCreateWindowWGPUSurface(instance, window);
}
diff --git a/third_party/glfw3webgpu/glfw3webgpu.c b/third_party/glfw3webgpu/glfw3webgpu.c
new file mode 100644
index 0000000..27bf9ec
--- /dev/null
+++ b/third_party/glfw3webgpu/glfw3webgpu.c
@@ -0,0 +1,181 @@
+/**
+ * This is an extension of GLFW for WebGPU, abstracting away the details of
+ * OS-specific operations.
+ *
+ * This file is part of the "Learn WebGPU for C++" book.
+ * https://eliemichel.github.io/LearnWebGPU
+ *
+ * Most of this code comes from the wgpu-native triangle example:
+ * https://github.com/gfx-rs/wgpu-native/blob/master/examples/triangle/main.c
+ *
+ * MIT License
+ * Copyright (c) 2022-2025 Elie Michel and the wgpu-native authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "glfw3webgpu.h"
+
+#include <webgpu.h>
+
+#include <GLFW/glfw3.h>
+
+#ifdef __EMSCRIPTEN__
+# define GLFW_EXPOSE_NATIVE_EMSCRIPTEN
+# ifndef GLFW_PLATFORM_EMSCRIPTEN // not defined in older versions of emscripten
+# define GLFW_PLATFORM_EMSCRIPTEN 0
+# endif
+#else // __EMSCRIPTEN__
+# ifdef _GLFW_X11
+# define GLFW_EXPOSE_NATIVE_X11
+# endif
+# ifdef _GLFW_WAYLAND
+# define GLFW_EXPOSE_NATIVE_WAYLAND
+# endif
+# ifdef _GLFW_COCOA
+# define GLFW_EXPOSE_NATIVE_COCOA
+# endif
+# ifdef _GLFW_WIN32
+# define GLFW_EXPOSE_NATIVE_WIN32
+# endif
+#endif // __EMSCRIPTEN__
+
+#ifdef GLFW_EXPOSE_NATIVE_COCOA
+# include <Foundation/Foundation.h>
+# include <QuartzCore/CAMetalLayer.h>
+#endif
+
+#ifndef __EMSCRIPTEN__
+# include <GLFW/glfw3native.h>
+#endif
+
+WGPUSurface glfwCreateWindowWGPUSurface(WGPUInstance instance, GLFWwindow* window) {
+#ifndef __EMSCRIPTEN__
+ switch (glfwGetPlatform()) {
+#else
+ // glfwGetPlatform is not available in older versions of emscripten
+ switch (GLFW_PLATFORM_EMSCRIPTEN) {
+#endif
+
+#ifdef GLFW_EXPOSE_NATIVE_X11
+ case GLFW_PLATFORM_X11: {
+ Display* x11_display = glfwGetX11Display();
+ Window x11_window = glfwGetX11Window(window);
+
+ WGPUSurfaceSourceXlibWindow fromXlibWindow;
+ fromXlibWindow.chain.sType = WGPUSType_SurfaceSourceXlibWindow;
+ fromXlibWindow.chain.next = NULL;
+ fromXlibWindow.display = x11_display;
+ fromXlibWindow.window = x11_window;
+
+ WGPUSurfaceDescriptor surfaceDescriptor;
+ surfaceDescriptor.nextInChain = &fromXlibWindow.chain;
+ surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
+
+ return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
+ }
+#endif // GLFW_EXPOSE_NATIVE_X11
+
+#ifdef GLFW_EXPOSE_NATIVE_WAYLAND
+ case GLFW_PLATFORM_WAYLAND: {
+ struct wl_display* wayland_display = glfwGetWaylandDisplay();
+ struct wl_surface* wayland_surface = glfwGetWaylandWindow(window);
+
+ WGPUSurfaceSourceWaylandSurface fromWaylandSurface;
+ fromWaylandSurface.chain.sType = WGPUSType_SurfaceSourceWaylandSurface;
+ fromWaylandSurface.chain.next = NULL;
+ fromWaylandSurface.display = wayland_display;
+ fromWaylandSurface.surface = wayland_surface;
+
+ WGPUSurfaceDescriptor surfaceDescriptor;
+ surfaceDescriptor.nextInChain = &fromWaylandSurface.chain;
+ surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
+
+ return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
+ }
+#endif // GLFW_EXPOSE_NATIVE_WAYLAND
+
+#ifdef GLFW_EXPOSE_NATIVE_COCOA
+ case GLFW_PLATFORM_COCOA: {
+ id metal_layer = [CAMetalLayer layer];
+ NSWindow* ns_window = glfwGetCocoaWindow(window);
+ [ns_window.contentView setWantsLayer : YES] ;
+ [ns_window.contentView setLayer : metal_layer] ;
+
+ WGPUSurfaceSourceMetalLayer fromMetalLayer;
+ fromMetalLayer.chain.sType = WGPUSType_SurfaceSourceMetalLayer;
+ fromMetalLayer.chain.next = NULL;
+ fromMetalLayer.layer = metal_layer;
+
+ WGPUSurfaceDescriptor surfaceDescriptor;
+ surfaceDescriptor.nextInChain = &fromMetalLayer.chain;
+ surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
+
+ return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
+ }
+#endif // GLFW_EXPOSE_NATIVE_COCOA
+
+#ifdef GLFW_EXPOSE_NATIVE_WIN32
+ case GLFW_PLATFORM_WIN32: {
+ HWND hwnd = glfwGetWin32Window(window);
+ HINSTANCE hinstance = GetModuleHandle(NULL);
+
+ WGPUSurfaceSourceWindowsHWND fromWindowsHWND;
+ fromWindowsHWND.chain.sType = WGPUSType_SurfaceSourceWindowsHWND;
+ fromWindowsHWND.chain.next = NULL;
+ fromWindowsHWND.hinstance = hinstance;
+ fromWindowsHWND.hwnd = hwnd;
+
+ WGPUSurfaceDescriptor surfaceDescriptor;
+ surfaceDescriptor.nextInChain = &fromWindowsHWND.chain;
+ surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
+
+ return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
+ }
+#endif // GLFW_EXPOSE_NATIVE_WIN32
+
+#ifdef GLFW_EXPOSE_NATIVE_EMSCRIPTEN
+ case GLFW_PLATFORM_EMSCRIPTEN: {
+# ifdef WEBGPU_BACKEND_EMDAWNWEBGPU
+ WGPUEmscriptenSurfaceSourceCanvasHTMLSelector fromCanvasHTMLSelector;
+ fromCanvasHTMLSelector.chain.sType = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector;
+ fromCanvasHTMLSelector.selector = (WGPUStringView){ "canvas", WGPU_STRLEN };
+# else
+ WGPUSurfaceDescriptorFromCanvasHTMLSelector fromCanvasHTMLSelector;
+ fromCanvasHTMLSelector.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector;
+ fromCanvasHTMLSelector.selector = "canvas";
+# endif
+ fromCanvasHTMLSelector.chain.next = NULL;
+
+ WGPUSurfaceDescriptor surfaceDescriptor;
+ surfaceDescriptor.nextInChain = &fromCanvasHTMLSelector.chain;
+# ifdef WEBGPU_BACKEND_EMDAWNWEBGPU
+ surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
+# else
+ surfaceDescriptor.label = NULL;
+# endif
+ return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
+ }
+#endif // GLFW_EXPOSE_NATIVE_EMSCRIPTEN
+
+ default:
+ // Unsupported platform
+ return NULL;
+ }
+}
diff --git a/third_party/glfw3webgpu/glfw3webgpu.h b/third_party/glfw3webgpu/glfw3webgpu.h
new file mode 100644
index 0000000..729afcc
--- /dev/null
+++ b/third_party/glfw3webgpu/glfw3webgpu.h
@@ -0,0 +1,62 @@
+/**
+ * This is an extension of GLFW for WebGPU, abstracting away the details of
+ * OS-specific operations.
+ *
+ * This file is part of the "Learn WebGPU for C++" book.
+ * https://eliemichel.github.io/LearnWebGPU
+ *
+ * MIT License
+ * Copyright (c) 2022-2024 Elie Michel and the wgpu-native authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _glfw3_webgpu_h_
+#define _glfw3_webgpu_h_
+
+#include <webgpu.h>
+#include <GLFW/glfw3.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! @brief Creates a WebGPU surface for the specified window.
+ *
+ * This function creates a WGPUSurface object for the specified window.
+ *
+ * If the surface cannot be created, this function returns `NULL`.
+ *
+ * It is the responsibility of the caller to destroy the window surface. The
+ * window surface must be destroyed using `wgpuSurfaceRelease`.
+ *
+ * @param[in] instance The WebGPU instance to create the surface in.
+ * @param[in] window The window to create the surface for.
+ * @return The handle of the surface. This is set to `NULL` if an error
+ * occurred.
+ *
+ * @ingroup webgpu
+ */
+WGPUSurface glfwCreateWindowWGPUSurface(WGPUInstance instance, GLFWwindow* window);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _glfw3_webgpu_h_