diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index b0ce7f66..4c3ed1e4 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -115,6 +115,10 @@ extern "C" { * VK_USE_PLATFORM_WIN32_KHR) so we offer our replacement symbols after it. */ +#if defined(GLFW_INCLUDE_WEBGPU) + #include +#endif /* WebGPU header */ + /* It is customary to use APIENTRY for OpenGL function pointer declarations on * all platforms. Additionally, the Windows OpenGL header needs APIENTRY. */ @@ -6530,6 +6534,41 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window #endif /*VK_VERSION_1_0*/ +#if defined(WEBGPU_H_) + +/*! @brief Provide the address of the `wgpuInstanceCreateSurface` function to GLFW. + * + * This function passes the address provided for the `wgpuInstanceCreateSurface` function + * to GLFW. + * + * @param[in] addr The address of the `wgpuInstanceCreateSurface` function. + * + * @since Added in version 3.5 + * + * @ingroup webgpu + */ +GLFWAPI void glfwSetWGPUInstanceCreateSurfaceAddr(WGPUSurface (*addr)(WGPUInstance, const WGPUSurfaceDescriptor*)); + +/*! @brief Creates a WebGPU surface for the specified window. + * + * This function creates a WebGPU surface for the specified window. + * + * If the surface could not be created this function returns `NULL`. + * + * It is the callers responsibility to destroy the surface. The 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 `NULL` if an error occurred. + * + * @since Added in version 3.5 + * + * @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 2cbe8a73..0b482ac3 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 @@ -128,7 +129,8 @@ set_target_properties(glfw PROPERTIES C_STANDARD 99 C_EXTENSIONS OFF DEFINE_SYMBOL _GLFW_BUILD_DLL - FOLDER "GLFW3") + FOLDER "GLFW3" + EXPORT_COMPILE_COMMANDS ON) target_include_directories(glfw PUBLIC "$" diff --git a/src/cocoa_init.m b/src/cocoa_init.m index 15dc4ec4..0df7a330 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -564,7 +564,8 @@ GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform) .getEGLNativeWindow = _glfwGetEGLNativeWindowCocoa, .getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsCocoa, .getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportCocoa, - .createWindowSurface = _glfwCreateWindowSurfaceCocoa + .createWindowSurface = _glfwCreateWindowSurfaceCocoa, + .createWindowWGPUSurface = _glfwCreateWindowWGPUSurfaceCocoa }; *platform = cocoa; diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 4d1d66ae..f7fa7b6f 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -276,6 +276,8 @@ void _glfwGetRequiredInstanceExtensionsCocoa(char** extensions); GLFWbool _glfwGetPhysicalDevicePresentationSupportCocoa(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); VkResult _glfwCreateWindowSurfaceCocoa(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); +WGPUSurface _glfwCreateWindowWGPUSurfaceCocoa(WGPUInstance instance, _GLFWwindow* window); + void _glfwFreeMonitorCocoa(_GLFWmonitor* monitor); void _glfwGetMonitorPosCocoa(_GLFWmonitor* monitor, int* xpos, int* ypos); void _glfwGetMonitorContentScaleCocoa(_GLFWmonitor* monitor, float* xscale, float* yscale); diff --git a/src/cocoa_window.m b/src/cocoa_window.m index e69b5fe0..e5dc0af3 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -2020,6 +2020,28 @@ VkResult _glfwCreateWindowSurfaceCocoa(VkInstance instance, } // autoreleasepool } +typedef struct WGPUSurfaceSourceMetalLayer +{ + WGPUChainedStruct chain; + void * layer; +} WGPUSurfaceSourceMetalLayer; + +WGPUSurface _glfwCreateWindowWGPUSurfaceCocoa(WGPUInstance instance, _GLFWwindow* window) +{ + [window->ns.view setLayer:window->ns.layer]; + [window->ns.view setWantsLayer:YES]; + + WGPUSurfaceSourceMetalLayer metalSurface; + metalSurface.chain.next = NULL; + metalSurface.chain.sType = WGPUSType_SurfaceSourceMetalLayer; + metalSurface.layer = window->ns.layer; + + WGPUSurfaceDescriptor surfaceDescriptor; + surfaceDescriptor.nextInChain = &metalSurface.chain; + surfaceDescriptor.label = (WGPUStringView){ NULL, SIZE_MAX }; + + return wgpuInstanceCreateSurface(instance, &surfaceDescriptor); +} ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// diff --git a/src/internal.h b/src/internal.h index 4f097aa8..5e409f5a 100644 --- a/src/internal.h +++ b/src/internal.h @@ -331,6 +331,46 @@ typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,con typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*); #define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr +// forward declare WebGPU types +typedef struct WGPUInstanceImpl* WGPUInstance; +typedef struct WGPUSurfaceImpl* WGPUSurface; + +typedef struct WGPUStringView +{ + char const * data; + size_t length; +} WGPUStringView; + +typedef enum WGPUSType +{ + WGPUSType_ShaderSourceSPIRV = 0x00000001, + WGPUSType_ShaderSourceWGSL = 0x00000002, + WGPUSType_RenderPassMaxDrawCount = 0x00000003, + WGPUSType_SurfaceSourceMetalLayer = 0x00000004, + WGPUSType_SurfaceSourceWindowsHWND = 0x00000005, + WGPUSType_SurfaceSourceXlibWindow = 0x00000006, + WGPUSType_SurfaceSourceWaylandSurface = 0x00000007, + WGPUSType_SurfaceSourceAndroidNativeWindow = 0x00000008, + WGPUSType_SurfaceSourceXCBWindow = 0x00000009, + WGPUSType_Force32 = 0x7FFFFFFF +} WGPUSType; + +typedef struct WGPUChainedStruct +{ + struct WGPUChainedStruct const * next; + WGPUSType sType; +} WGPUChainedStruct; + +typedef struct WGPUSurfaceDescriptor +{ + WGPUChainedStruct const * nextInChain; + WGPUStringView label; +} WGPUSurfaceDescriptor; + +typedef WGPUSurface (*PFN_wgpuInstanceCreateSurface)(WGPUInstance, const WGPUSurfaceDescriptor*); + +#define wgpuInstanceCreateSurface _glfw.wgpu.instanceCreateSurface + #include "platform.h" #define GLFW_NATIVE_INCLUDE_NONE @@ -759,6 +799,8 @@ struct _GLFWplatform void (*getRequiredInstanceExtensions)(char**); GLFWbool (*getPhysicalDevicePresentationSupport)(VkInstance,VkPhysicalDevice,uint32_t); VkResult (*createWindowSurface)(VkInstance,_GLFWwindow*,const VkAllocationCallbacks*,VkSurfaceKHR*); + // webgpu + WGPUSurface (*createWindowWGPUSurface)(WGPUInstance, _GLFWwindow*); }; // Library global data @@ -875,6 +917,10 @@ struct _GLFWlibrary GLFWbool EXT_headless_surface; } vk; + struct { + PFN_wgpuInstanceCreateSurface instanceCreateSurface; + } wgpu; + struct { GLFWmonitorfun monitor; GLFWjoystickfun joystick; diff --git a/src/webgpu.c b/src/webgpu.c new file mode 100644 index 00000000..e4155220 --- /dev/null +++ b/src/webgpu.c @@ -0,0 +1,56 @@ +//======================================================================== +// GLFW 3.5 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) Sebastian Dawid +// +// 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. +// +//======================================================================== + +#include "internal.h" + +#include +#include + +GLFWAPI void glfwSetWGPUInstanceCreateSurfaceAddr(WGPUSurface (*addr)(WGPUInstance, const WGPUSurfaceDescriptor*)) +{ + _GLFW_REQUIRE_INIT() + _glfw.wgpu.instanceCreateSurface = addr; +} + +GLFWAPI WGPUSurface glfwCreateWindowWGPUSurface(WGPUInstance instance, GLFWwindow* handle) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL) + + _GLFWwindow* window = (_GLFWwindow*)handle; + + assert(window != NULL); + assert(instance != NULL); + assert(_glfw.wgpu.instanceCreateSurface != NULL); + + if (window->context.client != GLFW_NO_API) + { + _glfwInputError(GLFW_INVALID_VALUE, + "WebGPU: Window surface creation requires the window to have the client API set to GLFW_NO_API"); + return NULL; + }; + + return _glfw.platform.createWindowWGPUSurface(instance, window); +} diff --git a/src/win32_init.c b/src/win32_init.c index 6b6e9d08..1a66b976 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -669,7 +669,8 @@ GLFWbool _glfwConnectWin32(int platformID, _GLFWplatform* platform) .getEGLNativeWindow = _glfwGetEGLNativeWindowWin32, .getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsWin32, .getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportWin32, - .createWindowSurface = _glfwCreateWindowSurfaceWin32 + .createWindowSurface = _glfwCreateWindowSurfaceWin32, + .createWindowWGPUSurface = _glfwCreateWindowWGPUSurfaceWin32 }; *platform = win32; diff --git a/src/win32_platform.h b/src/win32_platform.h index 49cceba6..905c86bb 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -544,6 +544,8 @@ void _glfwGetRequiredInstanceExtensionsWin32(char** extensions); GLFWbool _glfwGetPhysicalDevicePresentationSupportWin32(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); +WGPUSurface _glfwCreateWindowWGPUSurfaceWin32(WGPUInstance instance, _GLFWwindow* window); + void _glfwFreeMonitorWin32(_GLFWmonitor* monitor); void _glfwGetMonitorPosWin32(_GLFWmonitor* monitor, int* xpos, int* ypos); void _glfwGetMonitorContentScaleWin32(_GLFWmonitor* monitor, float* xscale, float* yscale); diff --git a/src/win32_window.c b/src/win32_window.c index 26f9684b..1a1f6ecd 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -2562,6 +2562,28 @@ VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance, return err; } +typedef struct WGPUSurfaceSourceWindowsHWND +{ + WGPUChainedStruct chain; + void * hinstance; + void * hwnd; +} WGPUSurfaceSourceWindowsHWND; + +WGPUSurface _glfwCreateWindowWGPUSurfaceWin32(WGPUInstance instance, _GLFWwindow *window) +{ + WGPUSurfaceSourceWindowsHWND windowsSurface; + windowsSurface.chain.sType = WGPUSType_SurfaceSourceWindowsHWND; + windowsSurface.chain.next = NULL; + windowsSurface.hinstance = _glfw.win32.instance; + windowsSurface.hwnd = window->win32.handle; + + WGPUSurfaceDescriptor surfaceDescriptor; + surfaceDescriptor.nextInChain = &windowsSurface.chain; + surfaceDescriptor.label = (WGPUStringView){ NULL, SIZE_MAX }; + + return wgpuInstanceCreateSurface(instance, &surfaceDescriptor); +} + GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); diff --git a/src/wl_init.c b/src/wl_init.c index ef9e4503..f6490c91 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -515,7 +515,8 @@ GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform) .getEGLNativeWindow = _glfwGetEGLNativeWindowWayland, .getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsWayland, .getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportWayland, - .createWindowSurface = _glfwCreateWindowSurfaceWayland + .createWindowSurface = _glfwCreateWindowSurfaceWayland, + .createWindowWGPUSurface = _glfwCreateWindowWGPUSurfaceWayland }; void* module = _glfwPlatformLoadModule("libwayland-client.so.0"); diff --git a/src/wl_platform.h b/src/wl_platform.h index c3e45693..1f910319 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -678,6 +678,8 @@ void _glfwGetRequiredInstanceExtensionsWayland(char** extensions); GLFWbool _glfwGetPhysicalDevicePresentationSupportWayland(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); VkResult _glfwCreateWindowSurfaceWayland(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); +WGPUSurface _glfwCreateWindowWGPUSurfaceWayland(WGPUInstance instance, _GLFWwindow* window); + void _glfwFreeMonitorWayland(_GLFWmonitor* monitor); void _glfwGetMonitorPosWayland(_GLFWmonitor* monitor, int* xpos, int* ypos); void _glfwGetMonitorContentScaleWayland(_GLFWmonitor* monitor, float* xscale, float* yscale); diff --git a/src/wl_window.c b/src/wl_window.c index 4220d17e..86e4e062 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -3324,6 +3324,27 @@ VkResult _glfwCreateWindowSurfaceWayland(VkInstance instance, return err; } +typedef struct WGPUSurfaceSourceWaylandSurface +{ + WGPUChainedStruct chain; + void * display; + void * surface; +} WGPUSurfaceSourceWaylandSurface; + +WGPUSurface _glfwCreateWindowWGPUSurfaceWayland(WGPUInstance instance, _GLFWwindow* window) +{ + WGPUSurfaceSourceWaylandSurface waylandSurface; + waylandSurface.chain.sType = WGPUSType_SurfaceSourceWaylandSurface; + waylandSurface.chain.next = NULL; + waylandSurface.surface = window->wl.surface; + waylandSurface.display = _glfw.wl.display; + + WGPUSurfaceDescriptor surfaceDescriptor; + surfaceDescriptor.nextInChain = &waylandSurface.chain; + surfaceDescriptor.label = (WGPUStringView){ NULL, SIZE_MAX }; + + return wgpuInstanceCreateSurface(instance, &surfaceDescriptor); +} ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// diff --git a/src/x11_init.c b/src/x11_init.c index 6b34c263..c90babe1 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -1246,7 +1246,8 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform) .getEGLNativeWindow = _glfwGetEGLNativeWindowX11, .getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsX11, .getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportX11, - .createWindowSurface = _glfwCreateWindowSurfaceX11 + .createWindowSurface = _glfwCreateWindowSurfaceX11, + .createWindowWGPUSurface = _glfwCreateWindowWGPUSurfaceX11 }; // HACK: If the application has left the locale as "C" then both wide diff --git a/src/x11_platform.h b/src/x11_platform.h index 30326c5b..af1ad314 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -963,6 +963,8 @@ void _glfwGetRequiredInstanceExtensionsX11(char** extensions); GLFWbool _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); VkResult _glfwCreateWindowSurfaceX11(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); +WGPUSurface _glfwCreateWindowWGPUSurfaceX11(WGPUInstance instance, _GLFWwindow* window); + void _glfwFreeMonitorX11(_GLFWmonitor* monitor); void _glfwGetMonitorPosX11(_GLFWmonitor* monitor, int* xpos, int* ypos); void _glfwGetMonitorContentScaleX11(_GLFWmonitor* monitor, float* xscale, float* yscale); diff --git a/src/x11_window.c b/src/x11_window.c index 322349f0..72a1a6b0 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -3282,6 +3282,55 @@ VkResult _glfwCreateWindowSurfaceX11(VkInstance instance, } } +typedef struct WGPUSurfaceSourceXCBWindow +{ + WGPUChainedStruct chain; + void * connection; + uint32_t window; +} WGPUSurfaceSourceXCBWindow; + +typedef struct WGPUSurfaceSourceXlibWindow +{ + WGPUChainedStruct chain; + void * display; + uint64_t window; +} WGPUSurfaceSourceXlibWindow; + +WGPUSurface _glfwCreateWindowWGPUSurfaceX11(WGPUInstance instance, _GLFWwindow* window) +{ + WGPUSurfaceDescriptor surfaceDescriptor; + + if (_glfw.x11.x11xcb.handle) + { + WGPUSurfaceSourceXCBWindow xcbSurface; + xcbSurface.chain.sType = WGPUSType_SurfaceSourceXCBWindow; + xcbSurface.chain.next = NULL; + xcb_connection_t* connection = XGetXCBConnection(_glfw.x11.display); + if (!connection) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to retrieve XCB connection"); + return NULL; + } + xcbSurface.connection = connection; + xcbSurface.window = window->x11.handle; + surfaceDescriptor.nextInChain = &xcbSurface.chain; + } + else + { + WGPUSurfaceSourceXlibWindow xlibSurface; + xlibSurface.chain.sType = WGPUSType_SurfaceSourceXlibWindow; + xlibSurface.chain.next = NULL; + xlibSurface.display = _glfw.x11.display; + xlibSurface.window = window->x11.handle; + surfaceDescriptor.nextInChain = &xlibSurface.chain; + } + + surfaceDescriptor.label = (WGPUStringView){ NULL, SIZE_MAX }; + + return wgpuInstanceCreateSurface(instance, &surfaceDescriptor); +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW native API //////