diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b51ae96..f7d2bb76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,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)") @@ -75,6 +76,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 58b395cd..9a45689f 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 @@ -6396,6 +6400,30 @@ 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 `wgpuSurfaceDrop` (wgpu-native) or + * `wgpuSurfaceRelease` (Dawn/emscripten). + * + * @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 01f191c9..8a77ac8c 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 @@ -249,7 +250,7 @@ endif() # source files that VS will build (Clang ignores this because we set -std=c99) if (CMAKE_C_COMPILER_ID STREQUAL "GNU") set_source_files_properties(context.c init.c input.c monitor.c platform.c vulkan.c - window.c null_init.c null_joystick.c null_monitor.c + webgpu.c window.c null_init.c null_joystick.c null_monitor.c null_window.c win32_init.c win32_joystick.c win32_module.c win32_monitor.c win32_time.c win32_thread.c win32_window.c wgl_context.c egl_context.c osmesa_context.c PROPERTIES @@ -321,6 +322,14 @@ if (GLFW_BUILD_X11 OR GLFW_BUILD_WAYLAND) endif() endif() +if (GLFW_BUILD_WEBGPU) + target_compile_definitions(glfw PRIVATE _GLFW_BUILD_WEBGPU) + if (APPLE) + target_compile_options(glfw PRIVATE -x objective-c) + target_link_libraries(glfw PRIVATE "-framework Cocoa" "-framework CoreVideo" "-framework IOKit" "-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..28448722 --- /dev/null +++ b/src/webgpu.c @@ -0,0 +1,164 @@ +//======================================================================== +// GLFW 3.4 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2022-2023 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) + +#include + +#define WGPU_TARGET_MACOS 1 +#define WGPU_TARGET_LINUX_X11 2 +#define WGPU_TARGET_WINDOWS 3 +#define WGPU_TARGET_LINUX_WAYLAND 4 + +#if defined(_WIN32) +#define WGPU_TARGET WGPU_TARGET_WINDOWS +#elif defined(__APPLE__) +#define WGPU_TARGET WGPU_TARGET_MACOS +#elif defined(_GLFW_WAYLAND) +#define WGPU_TARGET WGPU_TARGET_LINUX_WAYLAND +#else +#define WGPU_TARGET WGPU_TARGET_LINUX_X11 +#endif + +#if WGPU_TARGET == WGPU_TARGET_MACOS +#include +#include +#endif + +#include +#if WGPU_TARGET == WGPU_TARGET_MACOS +#define GLFW_EXPOSE_NATIVE_COCOA +#elif WGPU_TARGET == WGPU_TARGET_LINUX_X11 +#define GLFW_EXPOSE_NATIVE_X11 +#elif WGPU_TARGET == WGPU_TARGET_LINUX_WAYLAND +#define GLFW_EXPOSE_NATIVE_WAYLAND +#elif WGPU_TARGET == WGPU_TARGET_WINDOWS +#define GLFW_EXPOSE_NATIVE_WIN32 +#endif +#include + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI WGPUSurface glfwCreateWindowWGPUSurface(WGPUInstance instance, GLFWwindow* window) { +#if WGPU_TARGET == WGPU_TARGET_MACOS + { + id metal_layer = NULL; + NSWindow* ns_window = glfwGetCocoaWindow(window); + [ns_window.contentView setWantsLayer : YES] ; + metal_layer = [CAMetalLayer layer]; + [ns_window.contentView setLayer : metal_layer] ; + return wgpuInstanceCreateSurface( + instance, + &(WGPUSurfaceDescriptor){ + .label = NULL, + .nextInChain = + (const WGPUChainedStruct*)&( + WGPUSurfaceDescriptorFromMetalLayer) { + .chain = + (WGPUChainedStruct){ + .next = NULL, + .sType = WGPUSType_SurfaceDescriptorFromMetalLayer, + }, + .layer = metal_layer, + }, + }); + } +#elif WGPU_TARGET == WGPU_TARGET_LINUX_X11 + { + Display* x11_display = glfwGetX11Display(); + Window x11_window = glfwGetX11Window(window); + return wgpuInstanceCreateSurface( + instance, + &(WGPUSurfaceDescriptor){ + .label = NULL, + .nextInChain = + (const WGPUChainedStruct*)&( + WGPUSurfaceDescriptorFromXlibWindow) { + .chain = + (WGPUChainedStruct){ + .next = NULL, + .sType = WGPUSType_SurfaceDescriptorFromXlibWindow, + }, + .display = x11_display, + .window = x11_window, + }, + }); + } +#elif WGPU_TARGET == WGPU_TARGET_LINUX_WAYLAND + { + struct wl_display* wayland_display = glfwGetWaylandDisplay(); + struct wl_surface* wayland_surface = glfwGetWaylandWindow(window); + return wgpuInstanceCreateSurface( + instance, + &(WGPUSurfaceDescriptor){ + .label = NULL, + .nextInChain = + (const WGPUChainedStruct*)&( + WGPUSurfaceDescriptorFromWaylandSurface) { + .chain = + (WGPUChainedStruct){ + .next = NULL, + .sType = + WGPUSType_SurfaceDescriptorFromWaylandSurface, +}, +.display = wayland_display, +.surface = wayland_surface, + }, + }); + } +#elif WGPU_TARGET == WGPU_TARGET_WINDOWS + { + HWND hwnd = glfwGetWin32Window(window); + HINSTANCE hinstance = GetModuleHandle(NULL); + return wgpuInstanceCreateSurface( + instance, + &(WGPUSurfaceDescriptor){ + .label = NULL, + .nextInChain = + (const WGPUChainedStruct*)&( + WGPUSurfaceDescriptorFromWindowsHWND) { + .chain = + (WGPUChainedStruct){ + .next = NULL, + .sType = WGPUSType_SurfaceDescriptorFromWindowsHWND, + }, + .hinstance = hinstance, + .hwnd = hwnd, + }, + }); + } +#else +#error "Unsupported WGPU_TARGET" +#endif +} +#endif /* _GLFW_BUILD_WEBGPU */