diff --git a/CMakeLists.txt b/CMakeLists.txt index 398b36eb..73975dbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ cmake_dependent_option(GLFW_USE_HYBRID_HPG "Force use of high-performance GPU on "WIN32" OFF) cmake_dependent_option(USE_MSVC_RUNTIME_LIBRARY_DLL "Use MSVC runtime library DLL" ON "MSVC" OFF) +option(GLFW_BUILD_WEBGPU "Build support for WebGPU" OFF) set(GLFW_LIBRARY_TYPE "${GLFW_LIBRARY_TYPE}" CACHE STRING "Library type override for GLFW (SHARED, STATIC, OBJECT, or empty to follow BUILD_SHARED_LIBS)") @@ -66,6 +67,9 @@ endif() if (GLFW_BUILD_X11) message(STATUS "Including X11 support") endif() +if (GLFW_BUILD_WEBGPU) + message(STATUS "Including WebGPU support") +endif() #-------------------------------------------------------------------- # Apply Microsoft C runtime library option diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 79b06288..fa1a6d72 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -247,6 +247,10 @@ extern "C" { #endif /* OpenGL and OpenGL ES headers */ +#if defined(GLFW_INCLUDE_WEBGPU) + #include +#endif /* webgpu header */ + #if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL) /* GLFW_DLL must be defined by applications that are linking against the DLL * version of the GLFW library. _GLFW_BUILD_DLL is defined by the GLFW @@ -6525,6 +6529,29 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window #endif /*VK_VERSION_1_0*/ +#if defined(WEBGPU_H_) + +/*! @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. + * + * @since Added in version 3.4. + * + * @ingroup webgpu + */ +GLFWAPI WGPUSurface glfwCreateWindowWGPUSurface(WGPUInstance instance, GLFWwindow* window); + +#endif /* WEBGPU_H_ */ /************************************************************************* * Global definition cleanup diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1a085b2b..62c71312 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,9 +3,10 @@ add_library(glfw ${GLFW_LIBRARY_TYPE} "${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h" "${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h" internal.h platform.h mappings.h - context.c init.c input.c monitor.c platform.c vulkan.c window.c - egl_context.c osmesa_context.c null_platform.h null_joystick.h - null_init.c null_monitor.c null_window.c null_joystick.c) + context.c init.c input.c monitor.c platform.c vulkan.c webgpu.c + window.c egl_context.c osmesa_context.c null_platform.h + null_joystick.h null_init.c null_monitor.c null_window.c + null_joystick.c) # The time, thread and module code is shared between all backends on a given OS, # including the null backend, which still needs those bits to be functional @@ -283,6 +284,15 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Linux") target_compile_definitions(glfw PRIVATE _DEFAULT_SOURCE) endif() +if (GLFW_BUILD_WEBGPU) + target_compile_definitions(glfw PRIVATE _GLFW_BUILD_WEBGPU) + if (GLFW_BUILD_COCOA) + target_compile_options(glfw PRIVATE -x objective-c) + target_link_libraries(glfw PRIVATE "-framework QuartzCore") + set(glfw_PKG_LIBS "${glfw_PKG_LIBS} -framework QuartzCore") + endif () +endif () + if (GLFW_BUILD_SHARED_LIBRARY) if (WIN32) if (MINGW) diff --git a/src/webgpu.c b/src/webgpu.c new file mode 100644 index 00000000..3191da0f --- /dev/null +++ b/src/webgpu.c @@ -0,0 +1,198 @@ +//======================================================================== +// GLFW 3.4 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2022-2024 Elie Michel and the +// wgpu-native authors. +// Most of the code from this file comes from the wgpu-native triangle example: +// https://github.com/gfx-rs/wgpu-native/blob/master/examples/triangle/main.c +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +#if defined(_GLFW_BUILD_WEBGPU) + +#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 +# include +#endif + +#ifndef __EMSCRIPTEN__ +# include +#endif + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +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); + +# ifdef WEBGPU_BACKEND_DAWN + WGPUSurfaceSourceXlibWindow fromXlibWindow; + fromXlibWindow.chain.sType = WGPUSType_SurfaceSourceXlibWindow; +# else + WGPUSurfaceDescriptorFromXlibWindow fromXlibWindow; + fromXlibWindow.chain.sType = WGPUSType_SurfaceDescriptorFromXlibWindow; +# endif + fromXlibWindow.chain.next = NULL; + fromXlibWindow.display = x11_display; + fromXlibWindow.window = x11_window; + + WGPUSurfaceDescriptor surfaceDescriptor; + surfaceDescriptor.nextInChain = &fromXlibWindow.chain; + surfaceDescriptor.label = NULL; + + 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); + +# ifdef WEBGPU_BACKEND_DAWN + WGPUSurfaceSourceWaylandSurface fromWaylandSurface; + fromWaylandSurface.chain.sType = WGPUSType_SurfaceSourceWaylandSurface; +# else + WGPUSurfaceDescriptorFromWaylandSurface fromWaylandSurface; + fromWaylandSurface.chain.sType = WGPUSType_SurfaceDescriptorFromWaylandSurface; +# endif + fromWaylandSurface.chain.next = NULL; + fromWaylandSurface.display = wayland_display; + fromWaylandSurface.surface = wayland_surface; + + WGPUSurfaceDescriptor surfaceDescriptor; + surfaceDescriptor.nextInChain = &fromWaylandSurface.chain; + surfaceDescriptor.label = NULL; + + 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] ; + +# ifdef WEBGPU_BACKEND_DAWN + WGPUSurfaceSourceMetalLayer fromMetalLayer; + fromMetalLayer.chain.sType = WGPUSType_SurfaceSourceMetalLayer; +# else + WGPUSurfaceDescriptorFromMetalLayer fromMetalLayer; + fromMetalLayer.chain.sType = WGPUSType_SurfaceDescriptorFromMetalLayer; +# endif + fromMetalLayer.chain.next = NULL; + fromMetalLayer.layer = metal_layer; + + WGPUSurfaceDescriptor surfaceDescriptor; + surfaceDescriptor.nextInChain = &fromMetalLayer.chain; + surfaceDescriptor.label = NULL; + + 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); + +# ifdef WEBGPU_BACKEND_DAWN + WGPUSurfaceSourceWindowsHWND fromWindowsHWND; + fromWindowsHWND.chain.sType = WGPUSType_SurfaceSourceWindowsHWND; +# else + WGPUSurfaceDescriptorFromWindowsHWND fromWindowsHWND; + fromWindowsHWND.chain.sType = WGPUSType_SurfaceDescriptorFromWindowsHWND; +# endif + fromWindowsHWND.chain.next = NULL; + fromWindowsHWND.hinstance = hinstance; + fromWindowsHWND.hwnd = hwnd; + + WGPUSurfaceDescriptor surfaceDescriptor; + surfaceDescriptor.nextInChain = &fromWindowsHWND.chain; + surfaceDescriptor.label = NULL; + + return wgpuInstanceCreateSurface(instance, &surfaceDescriptor); + } +#endif // GLFW_EXPOSE_NATIVE_X11 + +#ifdef GLFW_EXPOSE_NATIVE_EMSCRIPTEN + case GLFW_PLATFORM_EMSCRIPTEN: { +# ifdef WEBGPU_BACKEND_DAWN + WGPUSurfaceSourceCanvasHTMLSelector_Emscripten fromCanvasHTMLSelector; + fromCanvasHTMLSelector.chain.sType = WGPUSType_SurfaceSourceCanvasHTMLSelector_Emscripten; +# else + WGPUSurfaceDescriptorFromCanvasHTMLSelector fromCanvasHTMLSelector; + fromCanvasHTMLSelector.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector; +# endif + fromCanvasHTMLSelector.chain.next = NULL; + fromCanvasHTMLSelector.selector = "canvas"; + + WGPUSurfaceDescriptor surfaceDescriptor; + surfaceDescriptor.nextInChain = &fromCanvasHTMLSelector.chain; + surfaceDescriptor.label = NULL; + + return wgpuInstanceCreateSurface(instance, &surfaceDescriptor); + } +#endif // GLFW_EXPOSE_NATIVE_X11 + + default: + // Unsupported platform + return NULL; + } +} + +#endif /* _GLFW_BUILD_WEBGPU */