diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f2b6f594e..65de90bff0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -383,7 +383,8 @@ dep_option(SDL_RENDER_GPU "Enable the SDL_GPU render driver" ON "SDL_RE dep_option(SDL_VIVANTE "Use Vivante EGL video driver" ON "${UNIX_SYS};SDL_CPU_ARM32" OFF) dep_option(SDL_VULKAN "Enable Vulkan support" "${SDL_VULKAN_DEFAULT}" "SDL_VIDEO;ANDROID OR APPLE OR LINUX OR FREEBSD OR OPENBSD OR WINDOWS OR CYGWIN" OFF) dep_option(SDL_WGPU "Enable experimental WGPU support" "${SDL_WGPU_DEFAULT}" "SDL_VIDEO" OFF) -dep_option(SDL_WGPU_STATIC "Statically link wgpu_native" OFF "SDL_WGPU" OFF) +dep_option(SDL_WGPU_STATIC "Statically link the WebGPU library" OFF "SDL_WGPU" OFF) +option_string(SDL_WGPU_LIB "The library which SDL will use for WebGPU. Either 'wgpu-native' or 'dawn'" "wgpu-native") dep_option(SDL_RENDER_VULKAN "Enable the Vulkan render driver" ON "SDL_RENDER;SDL_VULKAN" OFF) dep_option(SDL_METAL "Enable Metal support" ON "APPLE" OFF) set_option(SDL_OPENVR "Use OpenVR video driver" OFF) @@ -3538,22 +3539,33 @@ elseif(NGAGE) ) endif() -# wgpu_native static linking shenanigans +# webgpu static linking shenanigans if (SDL_WGPU_STATIC) - find_library( - WGPU_STATIC_LIB NAMES wgpu_native wgpu_native.lib libwgpu_native - HINTS ${WGPU_STATIC_LIB_DIR} ${CMAKE_SOURCE_DIR} - REQUIRED - ) - - # FIXME: i don't know how to make it look nice like everything else :( - message("-- wgpu_native -> ${WGPU_STATIC_LIB}") + if (HAVE_DAWN) + find_library( + WGPU_STATIC_LIB NAMES libwebgpu_dawn webgpu_dawn + HINTS ${WGPU_STATIC_LIB_DIR} ${CMAKE_SOURCE_DIR} + REQUIRED + ) + message("-- Using Dawn as WebGPU implementation") + elseif(HAVE_WGPU_NATIVE) + find_library( + WGPU_STATIC_LIB NAMES libwgpu_native wgpu_native + HINTS ${WGPU_STATIC_LIB_DIR} ${CMAKE_SOURCE_DIR} + REQUIRED + ) + message("-- Using wgpu-native (statically linked) as WebGPU implementation") + endif() if (SDL_STATIC) target_link_libraries(SDL3-static PRIVATE ${WGPU_STATIC_LIB}) elseif (SDL_SHARED) target_link_libraries(SDL3-shared PRIVATE ${WGPU_STATIC_LIB}) endif() +elseif (HAVE_WGPU_NATIVE) +# We don't have to do anything here, +# but we'll still message that we're using wgpu-native (dyn) as our WebGPU lib. +message("-- Using wgpu-native (dynamically linked) as WebGPU implementation") endif() sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/SDL_dialog.c) diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake index e2eebbb364..69be8ae055 100644 --- a/cmake/sdlchecks.cmake +++ b/cmake/sdlchecks.cmake @@ -946,8 +946,39 @@ macro(CheckWGPU) if(SDL_WGPU) set(SDL_VIDEO_WGPU 1) + if(SDL_WGPU_LIB STREQUAL "dawn") + set(WGPU_DAWN 1) + set(HAVE_DAWN TRUE) + + # Dawn's a C++ library, so we'll have to enable C++ + enable_language(CXX) + + # Dawn includes + if(HAVE_WAYLAND) + sdl_sources("${SDL3_SOURCE_DIR}/src/video/wayland/SDL_waylandwgpu_dawn.cpp") + endif() + + if(HAVE_X11) + sdl_sources("${SDL3_SOURCE_DIR}/src/video/x11/SDL_x11wgpu_dawn.cpp") + endif() + + if(WINDOWS) + sdl_sources("${SDL3_SOURCE_DIR}/src/video/windows/SDL_windowswgpu_dawn.cpp") + endif() + + elseif(SDL_WGPU_LIB STREQUAL "wgpu-native") + set(WGPU_NATIVE 1) + set(HAVE_WGPU_NATIVE TRUE) + else() + message(FATAL_ERROR "SDL_WGPU_LIB is neither 'wgpu-native' nor 'dawn'!") + endif() + if(SDL_WGPU_STATIC) set(WGPU_STATIC 1) + elseif(SDL_WGPU_LIB STREQUAL "dawn") + # SDL's been configured to use Dawn & dynamic linking, however; Dawn does not support dynamic linking. + # FIXME: I don't know if this should error out? Maybe just toggle on static link and warn the user? + message(FATAL_ERROR "SDL has been configured to use Dawn as its WebGPU implementation, however, it has also been configured to dynamically link the WebGPU library.\nDawn does not support dynamic linking.") endif() endif() endmacro() diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake index 14cae20c62..0940b88f51 100644 --- a/include/build_config/SDL_build_config.h.cmake +++ b/include/build_config/SDL_build_config.h.cmake @@ -490,6 +490,8 @@ /* Enable experimental WGPU support */ #cmakedefine SDL_VIDEO_WGPU 1 #cmakedefine WGPU_STATIC 1 +#cmakedefine WGPU_NATIVE 1 +#cmakedefine WGPU_DAWN 1 /* Enable GPU support */ #cmakedefine SDL_GPU_D3D11 1 diff --git a/src/video/SDL_wgpu_defs.h b/src/video/SDL_wgpu_defs.h index 72c2018485..7e9b7b8fb3 100644 --- a/src/video/SDL_wgpu_defs.h +++ b/src/video/SDL_wgpu_defs.h @@ -30,6 +30,15 @@ #include "SDL_internal.h" +// define to prevent C++ name mangling on extern functions +#ifdef WGPU_DAWN +#define WGPU_EXTERN extern "C" +#endif + +#ifdef WGPU_NATIVE +#define WGPU_EXTERN extern +#endif + #ifndef WEBGPU_H_ #define NO_WEBGPU_HEADER #endif @@ -104,8 +113,6 @@ typedef struct WGPUSurfaceSourceWindowsHWND { typedef WGPUSurface (*WGPUProcInstanceCreateSurface)(WGPUInstance instance, WGPUSurfaceDescriptor const *descriptor) WGPU_FUNCTION_ATTRIBUTE; -#if defined(WGPU_STATIC) -extern WGPUSurface wgpuInstanceCreateSurface(WGPUInstance instance, WGPUSurfaceDescriptor const * descriptor) WGPU_FUNCTION_ATTRIBUTE; -#endif +WGPU_EXTERN WGPUSurface wgpuInstanceCreateSurface(WGPUInstance instance, WGPUSurfaceDescriptor const * descriptor) WGPU_FUNCTION_ATTRIBUTE; #endif diff --git a/src/video/wayland/SDL_waylandwgpu.h b/src/video/wayland/SDL_waylandwgpu.h index b84853e74a..5d1953d6a1 100644 --- a/src/video/wayland/SDL_waylandwgpu.h +++ b/src/video/wayland/SDL_waylandwgpu.h @@ -4,7 +4,19 @@ #include #if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_WAYLAND) -extern WGPUSurface Wayland_WGPU_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, WGPUInstance instance); + +// Dawn's a C++ lib so we'll have to do this to prevent any name mangling. +#ifdef __cplusplus +extern "C" { +#else +extern +#endif + +WGPUSurface Wayland_WGPU_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, WGPUInstance instance); + +#ifdef __cplusplus +} +#endif #endif diff --git a/src/video/wayland/SDL_waylandwgpu_dawn.cpp b/src/video/wayland/SDL_waylandwgpu_dawn.cpp new file mode 100644 index 0000000000..85c5f3ee07 --- /dev/null +++ b/src/video/wayland/SDL_waylandwgpu_dawn.cpp @@ -0,0 +1,46 @@ +// NOTE: +// Dawn's a C++ library. +// So, if you want to use C++, you have to have a .cpp file. +// The code in this file is largely identical to the native one. +// A couple changes though: +// C++ isn't a fan of forward declaring enums, so we can't use SDL_waylandvideo.h, +// but that's fine; we're not using anything that isn't in SDL_sysvideo.h. +// I also had to add a cast for SDL_GetPointerProperty to wl_display/surface. + +#include "SDL_internal.h" + +#if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_WAYLAND) && defined(WGPU_DAWN) + +#include "../SDL_wgpu_defs.h" +#include "../SDL_sysvideo.h" + +#include "SDL_waylandwgpu.h" + +#include + +WGPUSurface +Wayland_WGPU_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, WGPUInstance instance) +{ + SDL_PropertiesID windowProperties = SDL_GetWindowProperties(window); + + struct wl_display *display = (wl_display*)SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, 0); + struct wl_surface *surface = (wl_surface*)SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, 0); + + WGPUSurfaceDescriptor desc; + WGPUSurfaceSourceWaylandSurface source; + + source.chain.sType = WGPUSType_SurfaceSourceWaylandSurface; + source.chain.next = NULL; + source.surface = surface; + source.display = display; + + // TODO: I don't know the convention on what label the surface should have? + // I'll just leave it NULL for now. - TheStickmahn + desc.label = (WGPUStringView){ NULL, WGPU_STRLEN }; + desc.nextInChain = &source.chain; + + // Dawn doesn't support dynamically loading, so we're just always using wgpuInstanceCreateSurface. + return wgpuInstanceCreateSurface(instance, &desc); +} + +#endif diff --git a/src/video/wayland/SDL_waylandwgpu.c b/src/video/wayland/SDL_waylandwgpu_native.c similarity index 98% rename from src/video/wayland/SDL_waylandwgpu.c rename to src/video/wayland/SDL_waylandwgpu_native.c index 5abe848907..32b2adddc6 100644 --- a/src/video/wayland/SDL_waylandwgpu.c +++ b/src/video/wayland/SDL_waylandwgpu_native.c @@ -1,6 +1,6 @@ #include "SDL_internal.h" -#if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_WAYLAND) +#if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_WAYLAND) && defined(WGPU_NATIVE) #include "SDL_waylandvideo.h" #include "../SDL_wgpu_defs.h" diff --git a/src/video/windows/SDL_windowswgpu.h b/src/video/windows/SDL_windowswgpu.h index be899ec27f..2cccf4ac29 100644 --- a/src/video/windows/SDL_windowswgpu.h +++ b/src/video/windows/SDL_windowswgpu.h @@ -6,7 +6,20 @@ #include #if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_WINDOWS) -extern WGPUSurface WIN_WGPU_CreateSurface(SDL_VSDL_VideoDevice *_this, SDL_Window *window, WGPUInstance instance); + +// Dawn's a C++ lib so we'll have to do this to prevent any name mangling. +#ifdef __cplusplus +extern "C" { +#else +extern +#endif + +WGPUSurface WIN_WGPU_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, WGPUInstance instance); + +#ifdef __cplusplus +} +#endif + #endif #endif // SDL_windowswgpu_h_ diff --git a/src/video/windows/SDL_windowswgpu_dawn.cpp b/src/video/windows/SDL_windowswgpu_dawn.cpp new file mode 100644 index 0000000000..960847aee5 --- /dev/null +++ b/src/video/windows/SDL_windowswgpu_dawn.cpp @@ -0,0 +1,32 @@ +// NOTE: Again, Dawn's a C++ library. + +#include "SDL_internal.h" + +#if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_WINDOWS) && defined(WGPU_NATIVE) +#include "SDL_windowsvideo.h" + +#include "../SDL_wgpu_defs.h" +#include "SDL_windoiwswgpu.h" + +WGPUSurface WIN_WGPU_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, WGPUInstance instance) +{ + SDL_PropertiesID windowProperties = SDL_GetWindowProperties(window); + + void *hwnd = SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WIN32_HWND_POINTER, 0); + void *hinstance = SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WIN32_INSTANCE_POINTER, 0); + + WGPUSurfaceDescriptor desc; + WGPUSurfaceSourceWindowsHWND source; + + source.hwnd = hwnd; + source.hinstance = hinstance; + source.chain.sType = WGPUSType_SurfaceSourceXlibWindow; + source.chain.next = NULL; + + desc.label = (WGPUStringView){ NULL, WGPU_STRLEN }; + desc.nextInChain = &source.chain; + + return wgpuInstanceCreateSurface(instance, &desc); +} + +#endif diff --git a/src/video/windows/SDL_windowswgpu.c b/src/video/windows/SDL_windowswgpu_native.c similarity index 98% rename from src/video/windows/SDL_windowswgpu.c rename to src/video/windows/SDL_windowswgpu_native.c index f0bcf4efb4..ea850b05b6 100644 --- a/src/video/windows/SDL_windowswgpu.c +++ b/src/video/windows/SDL_windowswgpu_native.c @@ -1,7 +1,7 @@ #include "SDL_internal.h" -#if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_WINDOWS) +#if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_WINDOWS) && defined(WGPU_NATIVE) #include "SDL_windowsvideo.h" #include "../SDL_wgpu_defs.h" diff --git a/src/video/x11/SDL_x11wgpu.h b/src/video/x11/SDL_x11wgpu.h index 11a1beb9ca..03c2318c5e 100644 --- a/src/video/x11/SDL_x11wgpu.h +++ b/src/video/x11/SDL_x11wgpu.h @@ -1,10 +1,22 @@ -#ifndef SDL_x11wgpu_h_ -#define SDL_x11wgpu_h_ +#ifndef SDL_waylandwgpu_h_ +#define SDL_waylandwgpu_h_ #include #if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_X11) -extern WGPUSurface X11_WGPU_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, WGPUInstance instance); + +#ifdef __cplusplus +extern "C" { +#else +extern #endif -#endif // SDL_x11wgpu_h_ +WGPUSurface X11_WGPU_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, WGPUInstance instance); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif // SDL_waylandwgpu_h_ diff --git a/src/video/x11/SDL_x11wgpu_dawn.cpp b/src/video/x11/SDL_x11wgpu_dawn.cpp new file mode 100644 index 0000000000..756d8f5032 --- /dev/null +++ b/src/video/x11/SDL_x11wgpu_dawn.cpp @@ -0,0 +1,37 @@ +// NOTE: Again, Dawn is a C++ library. +// We had to remove SDL_x11video.h since that uses the register keyword which was removed in C++17. +// That means we can't use Display, but that's not an issue since we're using a pointer to Display, which is a struct. +// We'll just make it a generic struct pointer. + +#include "SDL_internal.h" + +#if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_X11) && defined(WGPU_DAWN) + +#include "../SDL_wgpu_defs.h" +#include "../SDL_sysvideo.h" + +#include "SDL_x11wgpu.h" + +#include + +WGPUSurface X11_WGPU_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, WGPUInstance instance) +{ + SDL_PropertiesID windowProperties = SDL_GetWindowProperties(window); + + struct Display *x11_display = (Display*)SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, 0); + int x11_window = SDL_GetNumberProperty(windowProperties, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); + WGPUSurfaceDescriptor desc; + WGPUSurfaceSourceXlibWindow source; + + source.window = x11_window; + source.display = x11_display; + source.chain.sType = WGPUSType_SurfaceSourceXlibWindow; + source.chain.next = NULL; + + desc.label = (WGPUStringView){ NULL, WGPU_STRLEN }; + desc.nextInChain = &source.chain; + + return wgpuInstanceCreateSurface(instance, &desc); +} + +#endif diff --git a/src/video/x11/SDL_x11wgpu.c b/src/video/x11/SDL_x11wgpu_native.c similarity index 95% rename from src/video/x11/SDL_x11wgpu.c rename to src/video/x11/SDL_x11wgpu_native.c index 417e63b868..65be39bf84 100644 --- a/src/video/x11/SDL_x11wgpu.c +++ b/src/video/x11/SDL_x11wgpu_native.c @@ -1,6 +1,7 @@ #include "SDL_internal.h" -#if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_X11) +#if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_X11) && defined(WGPU_NATIVE) + #include "SDL_x11video.h" #include "../SDL_wgpu_defs.h"