Began work on WGPU video backend

Currently only supports Wayland, and it's quite..... bad

This is a DRAFT! Just a small proof-of-concept.

I'll submit a draft PR to the SDL project to see if I should continue
development.

If this is greenlit, I might making consider a WGPU SDL_GPU backend if
wgpu-native is in a good enough state (maybe Dawn if it isn't?)

No promises though! Don't get angry at me if I don't!

Current known issues:
1: Error handling is sparse.
2: It only supports the shared library version of wgpu-native, and it
does that by just loading it whenever it needs to do something
3: wgpu-native is bad and doesn't implement wgpuGetProcAddress so we're
just using SDL_LoadFunction instead. I'd much prefer using the native
wgpuGetProcAddress but alas....
This commit is contained in:
The Stickmahn 2026-05-30 10:25:18 +02:00
parent 687a59f277
commit 7e733d0934
15 changed files with 6999 additions and 99 deletions

View file

@ -287,6 +287,8 @@ endif()
set(SDL_VULKAN_DEFAULT ON)
set(SDL_WGPU_DEFAULT ON)
set(SDL_X11_XRANDR_DEFAULT ON)
if(SOLARIS)
set(SDL_VULKAN_DEFAULT OFF)
@ -380,6 +382,7 @@ dep_option(SDL_RENDER_METAL "Enable the Metal render driver" ON "SDL_REND
dep_option(SDL_RENDER_GPU "Enable the SDL_GPU render driver" ON "SDL_RENDER;SDL_GPU" OFF)
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" ON)
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)
@ -936,7 +939,7 @@ if(SDL_ASSEMBLY)
}]==] COMPILER_SUPPORTS_ARMSVE2)
if(COMPILER_SUPPORTS_ARMSVE2)
# IMPORTANT: As not all AArch64 processors support SVE2, we only
# attach the following compilation option to SVE
# attach the following compilation option to SVE
# dedicated source files.
set(SVE2_MARCH_FLAG "-march=armv8-a+sve2")
set(HAVE_ARMSVE2 TRUE)
@ -1896,6 +1899,7 @@ elseif(UNIX AND NOT (APPLE OR RISCOS OR HAIKU OR CYGWIN))
CheckVivante()
CheckVulkan()
CheckQNXScreen()
CheckWGPU()
endif()
if(SDL_TRAY)

View file

@ -942,6 +942,12 @@ macro(CheckVulkan)
endif()
endmacro()
macro(CheckWGPU)
if(SDL_WGPU)
set(SDL_VIDEO_WGPU 1)
endif()
endmacro()
# Requires:
# - EGL
macro(CheckQNXScreen)

View file

@ -85,6 +85,7 @@
#include <SDL3/SDL_tray.h>
#include <SDL3/SDL_touch.h>
#include <SDL3/SDL_version.h>
#include <SDL3/SDL_wgpu.h>
#include <SDL3/SDL_video.h>
#include <SDL3/SDL_oldnames.h>

42
include/SDL3/SDL_wgpu.h Normal file
View file

@ -0,0 +1,42 @@
/**
* # CategoryWGPU
*
* Experimental support for the wgpu-native C bindings.
*/
#ifndef SDL_wgpu_h_
#define SDL_wgpu_h_
#include <SDL3/SDL_video.h>
#include <SDL3/SDL_begin_code.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef WEBGPU_H_
#define WGPU_OBJECT_ATTRIBUTE(object) typedef struct object##Impl *object;
#endif
WGPU_OBJECT_ATTRIBUTE(WGPUSurface)
WGPU_OBJECT_ATTRIBUTE(WGPUInstance)
#undef WGPU_OBJECT_ATTRIBUTE
/**
* Create a new WGPU surface.
*
* \param window The window which the surface will attach itself to.
* \param instance The WGPU instance.
*
* \returns A WGPUSurface. Can be NULL if there was a failure.
*/
extern SDL_DECLSPEC WGPUSurface SDLCALL SDL_WGPU_CreateSurface(SDL_Window *window, WGPUInstance instance);
#ifdef __cplusplus
}
#endif
#include <SDL3/SDL_close_code.h>
#endif // SDL_wgpu_h_

View file

@ -487,6 +487,9 @@
/* Enable Metal support */
#cmakedefine SDL_VIDEO_METAL 1
/* Enable experimental WGPU support */
#cmakedefine SDL_VIDEO_WGPU 1
/* Enable GPU support */
#cmakedefine SDL_GPU_D3D11 1
#cmakedefine SDL_GPU_D3D12 1

View file

@ -1290,3 +1290,4 @@ _SDL_LoadJPG
_SDL_HasSVE2
_SDL_GamepadHasCapSense
_SDL_GetGamepadCapSense
_SDL_WGPU_CreateSurface

View file

@ -1291,6 +1291,7 @@ SDL3_0.0.0 {
SDL_HasSVE2;
SDL_GamepadHasCapSense;
SDL_GetGamepadCapSense;
SDL_WGPU_CreateSurface;
# extra symbols go here (don't modify this line)
local: *;
};

View file

@ -1317,3 +1317,4 @@
#define SDL_HasSVE2 SDL_HasSVE2_REAL
#define SDL_GamepadHasCapSense SDL_GamepadHasCapSense_REAL
#define SDL_GetGamepadCapSense SDL_GetGamepadCapSense_REAL
#define SDL_WGPU_CreateSurface SDL_WGPU_CreateSurface_REAL

View file

@ -1325,3 +1325,4 @@ SDL_DYNAPI_PROC(SDL_Surface*,SDL_LoadJPG,(const char *a),(a),return)
SDL_DYNAPI_PROC(bool,SDL_HasSVE2,(void),(),return)
SDL_DYNAPI_PROC(bool,SDL_GamepadHasCapSense,(SDL_Gamepad *a,SDL_GamepadCapSenseType b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_GetGamepadCapSense,(SDL_Gamepad *a,SDL_GamepadCapSenseType b),(a,b),return)
SDL_DYNAPI_PROC(WGPUSurface,SDL_WGPU_CreateSurface,(SDL_Window *a,WGPUInstance b),(a,b),return)

View file

@ -24,6 +24,7 @@
#define SDL_sysvideo_h_
#include <SDL3/SDL_vulkan.h>
#include <SDL3/SDL_wgpu.h>
#include "SDL_surface_c.h"
@ -352,6 +353,12 @@ struct SDL_VideoDevice
void (*Metal_DestroyView)(SDL_VideoDevice *_this, SDL_MetalView view);
void *(*Metal_GetLayer)(SDL_VideoDevice *_this, SDL_MetalView view);
/* * * */
/*
* Experimental WGPU support
*/
WGPUSurface (*WGPU_CreateSurface)(SDL_VideoDevice *_this, SDL_Window *window, WGPUInstance instance);
/* * * */
/*
* Event manager functions

View file

@ -23,20 +23,22 @@
// The high-level video driver subsystem
#include "SDL_sysvideo.h"
#include "SDL_clipboard_c.h"
#include "SDL_egl_c.h"
#include "SDL_surface_c.h"
#include "SDL_pixels_c.h"
#include "SDL_rect_c.h"
#include "SDL_video_c.h"
#include "../events/SDL_events_c.h"
#include "../SDL_hints_c.h"
#include "../SDL_properties_c.h"
#include "../timer/SDL_timer_c.h"
#include "../camera/SDL_camera_c.h"
#include "../render/SDL_sysrender.h"
#include "../events/SDL_events_c.h"
#include "../main/SDL_main_callbacks.h"
#include "../render/SDL_sysrender.h"
#include "../timer/SDL_timer_c.h"
#include "SDL_clipboard_c.h"
#include "SDL_egl_c.h"
#include "SDL_pixels_c.h"
#include "SDL_rect_c.h"
#include "SDL_surface_c.h"
#include "SDL_sysvideo.h"
#include "SDL_video_c.h"
#include <SDL3/SDL_wgpu.h>
#ifdef SDL_VIDEO_OPENGL
#include <SDL3/SDL_opengl.h>
@ -158,25 +160,25 @@ static VideoBootStrap *bootstrap[] = {
NULL
};
#define CHECK_WINDOW_MAGIC(window, result) \
CHECK_PARAM(!_this) { \
SDL_UninitializedVideo(); \
return result; \
} \
CHECK_PARAM(!SDL_ObjectValid(window, SDL_OBJECT_TYPE_WINDOW)) { \
SDL_SetError("Invalid window"); \
return result; \
#define CHECK_WINDOW_MAGIC(window, result) \
CHECK_PARAM (!_this) { \
SDL_UninitializedVideo(); \
return result; \
} \
CHECK_PARAM (!SDL_ObjectValid(window, SDL_OBJECT_TYPE_WINDOW)) { \
SDL_SetError("Invalid window"); \
return result; \
}
#define CHECK_DISPLAY_MAGIC(display, result) \
CHECK_PARAM(!display) { \
return result; \
} \
#define CHECK_DISPLAY_MAGIC(display, result) \
CHECK_PARAM (!display) { \
return result; \
}
#define CHECK_WINDOW_NOT_POPUP(window, result) \
CHECK_PARAM(SDL_WINDOW_IS_POPUP(window)) { \
SDL_SetError("Operation invalid on popup windows"); \
return result; \
#define CHECK_WINDOW_NOT_POPUP(window, result) \
CHECK_PARAM (SDL_WINDOW_IS_POPUP(window)) { \
SDL_SetError("Operation invalid on popup windows"); \
return result; \
}
#if defined(SDL_PLATFORM_MACOS) && defined(SDL_VIDEO_DRIVER_COCOA)
@ -339,7 +341,7 @@ static bool SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window,
if (render_driver && *render_driver) {
render_driver_copy = SDL_strdup(render_driver);
render_driver = render_driver_copy;
if (render_driver_copy) { // turn any "software" requests into "xxxxxxxx" so we don't end up in infinite recursion.
if (render_driver_copy) { // turn any "software" requests into "xxxxxxxx" so we don't end up in infinite recursion.
char *prev = render_driver_copy;
char *ptr = prev;
while ((ptr = SDL_strchr(ptr, ',')) != NULL) {
@ -606,7 +608,7 @@ int SDL_GetNumVideoDrivers(void)
const char *SDL_GetVideoDriver(int index)
{
CHECK_PARAM(index < 0 || index >= SDL_GetNumVideoDrivers()) {
CHECK_PARAM (index < 0 || index >= SDL_GetNumVideoDrivers()) {
SDL_InvalidParamError("index");
return NULL;
}
@ -665,7 +667,7 @@ bool SDL_VideoInit(const char *driver_name)
while (driver_attempt && *driver_attempt != 0 && !video) {
const char *driver_attempt_end = SDL_strchr(driver_attempt, ',');
size_t driver_attempt_len = (driver_attempt_end) ? (driver_attempt_end - driver_attempt)
: SDL_strlen(driver_attempt);
: SDL_strlen(driver_attempt);
for (i = 0; bootstrap[i]; ++i) {
if (!bootstrap[i]->is_preferred &&
@ -1067,7 +1069,7 @@ bool SDL_GetDisplayBounds(SDL_DisplayID displayID, SDL_Rect *rect)
CHECK_DISPLAY_MAGIC(display, false);
CHECK_PARAM(!rect) {
CHECK_PARAM (!rect) {
return SDL_InvalidParamError("rect");
}
@ -1103,7 +1105,7 @@ bool SDL_GetDisplayUsableBounds(SDL_DisplayID displayID, SDL_Rect *rect)
CHECK_DISPLAY_MAGIC(display, false);
CHECK_PARAM(!rect) {
CHECK_PARAM (!rect) {
return SDL_InvalidParamError("rect");
}
@ -1376,7 +1378,7 @@ SDL_DisplayMode **SDL_GetFullscreenDisplayModes(SDL_DisplayID displayID, int *co
bool SDL_GetClosestFullscreenDisplayMode(SDL_DisplayID displayID, int w, int h, float refresh_rate, bool include_high_density_modes, SDL_DisplayMode *result)
{
CHECK_PARAM(!result) {
CHECK_PARAM (!result) {
return SDL_InvalidParamError("closest"); // Parameter `result` is called `closest` in the header.
}
@ -1452,7 +1454,7 @@ static bool DisplayModeChanged(const SDL_DisplayMode *old_mode, const SDL_Displa
{
return ((old_mode->displayID && old_mode->displayID != new_mode->displayID) ||
(old_mode->format && old_mode->format != new_mode->format) ||
(old_mode->w && old_mode->h && (old_mode->w != new_mode->w ||old_mode->h != new_mode->h)) ||
(old_mode->w && old_mode->h && (old_mode->w != new_mode->w || old_mode->h != new_mode->h)) ||
(old_mode->pixel_density != 0.0f && old_mode->pixel_density != new_mode->pixel_density) ||
(old_mode->refresh_rate != 0.0f && old_mode->refresh_rate != new_mode->refresh_rate));
}
@ -1673,7 +1675,7 @@ void SDL_GlobalToRelativeForWindow(SDL_Window *window, int abs_x, int abs_y, int
SDL_DisplayID SDL_GetDisplayForPoint(const SDL_Point *point)
{
CHECK_PARAM(!point) {
CHECK_PARAM (!point) {
SDL_InvalidParamError("point");
return 0;
}
@ -1683,7 +1685,7 @@ SDL_DisplayID SDL_GetDisplayForPoint(const SDL_Point *point)
SDL_DisplayID SDL_GetDisplayForRect(const SDL_Rect *rect)
{
CHECK_PARAM(!rect) {
CHECK_PARAM (!rect) {
SDL_InvalidParamError("rect");
return 0;
}
@ -2247,7 +2249,7 @@ void SDL_ToggleDragAndDropSupport(void)
}
}
SDL_Window ** SDLCALL SDL_GetWindows(int *count)
SDL_Window **SDLCALL SDL_GetWindows(int *count)
{
if (count) {
*count = 0;
@ -2350,29 +2352,30 @@ static bool SDL_DllNotSupported(const char *name)
return SDL_SetError("No dynamic %s support in current SDL video driver (%s)", name, _this->name);
}
static struct {
static struct
{
const char *property_name;
SDL_WindowFlags flag;
bool invert_value;
} SDL_WindowFlagProperties[] = {
{ SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN, SDL_WINDOW_ALWAYS_ON_TOP, false },
{ SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN, SDL_WINDOW_BORDERLESS, false },
{ SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN, SDL_WINDOW_NOT_FOCUSABLE, true },
{ SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, SDL_WINDOW_FULLSCREEN, false },
{ SDL_PROP_WINDOW_CREATE_HIDDEN_BOOLEAN, SDL_WINDOW_HIDDEN, false },
{ SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, SDL_WINDOW_HIGH_PIXEL_DENSITY, false },
{ SDL_PROP_WINDOW_CREATE_MAXIMIZED_BOOLEAN, SDL_WINDOW_MAXIMIZED, false },
{ SDL_PROP_WINDOW_CREATE_MENU_BOOLEAN, SDL_WINDOW_POPUP_MENU, false },
{ SDL_PROP_WINDOW_CREATE_METAL_BOOLEAN, SDL_WINDOW_METAL, false },
{ SDL_PROP_WINDOW_CREATE_MINIMIZED_BOOLEAN, SDL_WINDOW_MINIMIZED, false },
{ SDL_PROP_WINDOW_CREATE_MODAL_BOOLEAN, SDL_WINDOW_MODAL, false },
{ SDL_PROP_WINDOW_CREATE_MOUSE_GRABBED_BOOLEAN, SDL_WINDOW_MOUSE_GRABBED, false },
{ SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, SDL_WINDOW_OPENGL, false },
{ SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, SDL_WINDOW_RESIZABLE, false },
{ SDL_PROP_WINDOW_CREATE_TRANSPARENT_BOOLEAN, SDL_WINDOW_TRANSPARENT, false },
{ SDL_PROP_WINDOW_CREATE_TOOLTIP_BOOLEAN, SDL_WINDOW_TOOLTIP, false },
{ SDL_PROP_WINDOW_CREATE_UTILITY_BOOLEAN, SDL_WINDOW_UTILITY, false },
{ SDL_PROP_WINDOW_CREATE_VULKAN_BOOLEAN, SDL_WINDOW_VULKAN, false }
{ SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN, SDL_WINDOW_ALWAYS_ON_TOP, false },
{ SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN, SDL_WINDOW_BORDERLESS, false },
{ SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN, SDL_WINDOW_NOT_FOCUSABLE, true },
{ SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, SDL_WINDOW_FULLSCREEN, false },
{ SDL_PROP_WINDOW_CREATE_HIDDEN_BOOLEAN, SDL_WINDOW_HIDDEN, false },
{ SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, SDL_WINDOW_HIGH_PIXEL_DENSITY, false },
{ SDL_PROP_WINDOW_CREATE_MAXIMIZED_BOOLEAN, SDL_WINDOW_MAXIMIZED, false },
{ SDL_PROP_WINDOW_CREATE_MENU_BOOLEAN, SDL_WINDOW_POPUP_MENU, false },
{ SDL_PROP_WINDOW_CREATE_METAL_BOOLEAN, SDL_WINDOW_METAL, false },
{ SDL_PROP_WINDOW_CREATE_MINIMIZED_BOOLEAN, SDL_WINDOW_MINIMIZED, false },
{ SDL_PROP_WINDOW_CREATE_MODAL_BOOLEAN, SDL_WINDOW_MODAL, false },
{ SDL_PROP_WINDOW_CREATE_MOUSE_GRABBED_BOOLEAN, SDL_WINDOW_MOUSE_GRABBED, false },
{ SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, SDL_WINDOW_OPENGL, false },
{ SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, SDL_WINDOW_RESIZABLE, false },
{ SDL_PROP_WINDOW_CREATE_TRANSPARENT_BOOLEAN, SDL_WINDOW_TRANSPARENT, false },
{ SDL_PROP_WINDOW_CREATE_TOOLTIP_BOOLEAN, SDL_WINDOW_TOOLTIP, false },
{ SDL_PROP_WINDOW_CREATE_UTILITY_BOOLEAN, SDL_WINDOW_UTILITY, false },
{ SDL_PROP_WINDOW_CREATE_VULKAN_BOOLEAN, SDL_WINDOW_VULKAN, false }
};
static SDL_WindowFlags SDL_GetWindowFlagProperties(SDL_PropertiesID props)
@ -2576,7 +2579,7 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
window->constrain_popup = SDL_GetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN, true);
if (!_this->SetWindowFillDocument) {
window->flags &= ~SDL_WINDOW_FILL_DOCUMENT; // not an error, just unsupported here, so remove the flag.
window->flags &= ~SDL_WINDOW_FILL_DOCUMENT; // not an error, just unsupported here, so remove the flag.
}
if (_this->windows) {
@ -2977,7 +2980,7 @@ bool SDL_SetWindowIcon(SDL_Window *window, SDL_Surface *icon)
{
CHECK_WINDOW_MAGIC(window, false);
CHECK_PARAM(!icon) {
CHECK_PARAM (!icon) {
return SDL_InvalidParamError("icon");
}
@ -3185,10 +3188,10 @@ bool SDL_SetWindowSize(SDL_Window *window, int w, int h)
{
CHECK_WINDOW_MAGIC(window, false);
CHECK_PARAM(w <= 0) {
CHECK_PARAM (w <= 0) {
return SDL_InvalidParamError("w");
}
CHECK_PARAM(h <= 0) {
CHECK_PARAM (h <= 0) {
return SDL_InvalidParamError("h");
}
@ -3338,14 +3341,14 @@ bool SDL_GetWindowSizeInPixels(SDL_Window *window, int *w, int *h)
bool SDL_SetWindowMinimumSize(SDL_Window *window, int min_w, int min_h)
{
CHECK_WINDOW_MAGIC(window, false);
CHECK_PARAM(min_w < 0) {
CHECK_PARAM (min_w < 0) {
return SDL_InvalidParamError("min_w");
}
CHECK_PARAM(min_h < 0) {
CHECK_PARAM (min_h < 0) {
return SDL_InvalidParamError("min_h");
}
CHECK_PARAM((window->max_w && min_w > window->max_w) || (window->max_h && min_h > window->max_h)) {
CHECK_PARAM ((window->max_w && min_w > window->max_w) || (window->max_h && min_h > window->max_h)) {
return SDL_SetError("SDL_SetWindowMinimumSize(): Tried to set minimum size larger than maximum size");
}
@ -3377,10 +3380,10 @@ bool SDL_GetWindowMinimumSize(SDL_Window *window, int *min_w, int *min_h)
bool SDL_SetWindowMaximumSize(SDL_Window *window, int max_w, int max_h)
{
CHECK_WINDOW_MAGIC(window, false);
CHECK_PARAM(max_w < 0) {
CHECK_PARAM (max_w < 0) {
return SDL_InvalidParamError("max_w");
}
CHECK_PARAM(max_h < 0) {
CHECK_PARAM (max_h < 0) {
return SDL_InvalidParamError("max_h");
}
@ -3748,7 +3751,7 @@ bool SDL_UpdateWindowSurface(SDL_Window *window)
}
bool SDL_UpdateWindowSurfaceRects(SDL_Window *window, const SDL_Rect *rects,
int numrects)
int numrects)
{
CHECK_WINDOW_MAGIC(window, false);
@ -4177,7 +4180,7 @@ bool SDL_SetWindowProgressState(SDL_Window *window, SDL_ProgressState state)
CHECK_WINDOW_MAGIC(window, false);
CHECK_WINDOW_NOT_POPUP(window, false);
CHECK_PARAM(state < SDL_PROGRESS_STATE_NONE || state > SDL_PROGRESS_STATE_ERROR) {
CHECK_PARAM (state < SDL_PROGRESS_STATE_NONE || state > SDL_PROGRESS_STATE_ERROR) {
return SDL_InvalidParamError("state");
}
@ -4426,7 +4429,7 @@ static bool SDL_ShouldMinimizeOnFocusLoss(SDL_Window *window)
#if defined(SDL_PLATFORM_MACOS) && defined(SDL_VIDEO_DRIVER_COCOA)
if (SDL_strcmp(_this->name, "cocoa") == 0) { // don't do this for X11, etc
if (Cocoa_IsShowingModalDialog(window)) {
return false; // modal system dialogs can live over fullscreen windows, don't minimize.
return false; // modal system dialogs can live over fullscreen windows, don't minimize.
} else if (Cocoa_IsWindowInFullscreenSpace(window)) {
return false;
}
@ -4504,7 +4507,7 @@ void SDL_RemoveWindowRenderer(SDL_Window *window, SDL_Renderer *renderer)
void SDL_DestroyWindow(SDL_Window *window)
{
CHECK_WINDOW_MAGIC(window,);
CHECK_WINDOW_MAGIC(window, );
window->is_destroying = true;
@ -4693,7 +4696,7 @@ void SDL_VideoQuit(void)
_this->VideoQuit(_this);
for (i = _this->num_displays; i--; ) {
for (i = _this->num_displays; i--;) {
SDL_VideoDisplay *display = _this->displays[i];
SDL_DelVideoDisplay(display->id, false);
}
@ -4805,12 +4808,12 @@ void SDL_GL_UnloadLibrary(void)
}
#if defined(SDL_VIDEO_OPENGL) || defined(SDL_VIDEO_OPENGL_ES) || defined(SDL_VIDEO_OPENGL_ES2)
typedef GLenum (APIENTRY* PFNGLGETERRORPROC) (void);
typedef void (APIENTRY* PFNGLGETINTEGERVPROC) (GLenum pname, GLint *params);
typedef const GLubyte *(APIENTRY* PFNGLGETSTRINGPROC) (GLenum name);
typedef void (APIENTRY* PFNGLENABLEPROC) (GLenum cap);
typedef GLenum(APIENTRY *PFNGLGETERRORPROC)(void);
typedef void(APIENTRY *PFNGLGETINTEGERVPROC)(GLenum pname, GLint *params);
typedef const GLubyte *(APIENTRY *PFNGLGETSTRINGPROC)(GLenum name);
typedef void(APIENTRY *PFNGLENABLEPROC)(GLenum cap);
#ifndef SDL_VIDEO_OPENGL
typedef const GLubyte *(APIENTRY* PFNGLGETSTRINGIPROC) (GLenum name, GLuint index);
typedef const GLubyte *(APIENTRY *PFNGLGETSTRINGIPROC)(GLenum name, GLuint index);
#endif
static SDL_INLINE bool isAtLeastGL3(const char *verstr)
@ -5146,7 +5149,7 @@ bool SDL_GL_GetAttribute(SDL_GLAttr attr, int *value)
GLenum attachmentattrib = 0;
#endif
CHECK_PARAM(!value) {
CHECK_PARAM (!value) {
return SDL_InvalidParamError("value");
}
@ -5336,7 +5339,7 @@ bool SDL_GL_GetAttribute(SDL_GLAttr attr, int *value)
if (attachmentattrib && isAtLeastGL3((const char *)glGetStringFunc(GL_VERSION))) {
// glGetFramebufferAttachmentParameteriv needs to operate on the window framebuffer for this, so bind FBO 0 if necessary.
GLint current_fbo = 0;
PFNGLGETINTEGERVPROC glGetIntegervFunc = (PFNGLGETINTEGERVPROC) SDL_GL_GetProcAddress("glGetIntegerv");
PFNGLGETINTEGERVPROC glGetIntegervFunc = (PFNGLGETINTEGERVPROC)SDL_GL_GetProcAddress("glGetIntegerv");
PFNGLBINDFRAMEBUFFERPROC glBindFramebufferFunc = (PFNGLBINDFRAMEBUFFERPROC)SDL_GL_GetProcAddress("glBindFramebuffer");
if (glGetIntegervFunc && glBindFramebufferFunc) {
glGetIntegervFunc(GL_DRAW_FRAMEBUFFER_BINDING, &current_fbo);
@ -5439,14 +5442,14 @@ SDL_GLContext SDL_GL_CreateContext(SDL_Window *window)
#if defined(SDL_VIDEO_OPENGL) || defined(SDL_VIDEO_OPENGL_ES) || defined(SDL_VIDEO_OPENGL_ES2)
// try to force the window framebuffer to the requested sRGB state.
if (srgb_requested != -1) {
PFNGLENABLEPROC glToggleFunc = (PFNGLENABLEPROC) SDL_GL_GetProcAddress(srgb_requested ? "glEnable" : "glDisable");
PFNGLENABLEPROC glToggleFunc = (PFNGLENABLEPROC)SDL_GL_GetProcAddress(srgb_requested ? "glEnable" : "glDisable");
PFNGLGETSTRINGPROC glGetStringFunc = (PFNGLGETSTRINGPROC)SDL_GL_GetProcAddress("glGetString");
if (glToggleFunc && glGetStringFunc) {
bool supported = false;
if (_this->gl_config.profile_mask & SDL_GL_CONTEXT_PROFILE_ES) {
supported = SDL_GL_ExtensionSupported("GL_EXT_sRGB_write_control"); // GL_FRAMEBUFFER_SRGB is not core in any GLES version at the moment.
supported = SDL_GL_ExtensionSupported("GL_EXT_sRGB_write_control"); // GL_FRAMEBUFFER_SRGB is not core in any GLES version at the moment.
} else {
supported = isAtLeastGL3((const char *)glGetStringFunc(GL_VERSION)) || // no extensions needed in OpenGL 3+.
supported = isAtLeastGL3((const char *)glGetStringFunc(GL_VERSION)) || // no extensions needed in OpenGL 3+.
SDL_GL_ExtensionSupported("GL_EXT_framebuffer_sRGB") ||
SDL_GL_ExtensionSupported("GL_ARB_framebuffer_sRGB");
}
@ -5587,8 +5590,8 @@ bool SDL_GL_SetSwapInterval(int interval)
bool SDL_GL_GetSwapInterval(int *interval)
{
CHECK_PARAM(!interval) {
return SDL_InvalidParamError("interval");
CHECK_PARAM (!interval) {
return SDL_InvalidParamError("interval");
}
*interval = 0;
@ -5621,10 +5624,10 @@ bool SDL_GL_SwapWindow(SDL_Window *window)
bool SDL_GL_DestroyContext(SDL_GLContext context)
{
CHECK_PARAM(!_this) {
CHECK_PARAM (!_this) {
return SDL_UninitializedVideo();
}
CHECK_PARAM(!context) {
CHECK_PARAM (!context) {
return SDL_InvalidParamError("context");
}
@ -5964,10 +5967,10 @@ bool SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID)
SDL_Window *current_window;
SDL_MessageBoxData mbdata;
CHECK_PARAM(!messageboxdata) {
CHECK_PARAM (!messageboxdata) {
return SDL_InvalidParamError("messageboxdata");
}
CHECK_PARAM(messageboxdata->numbuttons < 0) {
CHECK_PARAM (messageboxdata->numbuttons < 0) {
return SDL_SetError("Invalid number of buttons");
}
@ -6031,7 +6034,7 @@ bool SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID)
while (driver_attempt && (*driver_attempt != 0) && !result) {
const char *driver_attempt_end = SDL_strchr(driver_attempt, ',');
size_t driver_attempt_len = (driver_attempt_end) ? (driver_attempt_end - driver_attempt)
: SDL_strlen(driver_attempt);
: SDL_strlen(driver_attempt);
for (int i = 0; bootstrap[i]; ++i) {
if (bootstrap[i]->ShowMessageBox && (driver_attempt_len == SDL_strlen(bootstrap[i]->name)) &&
(SDL_strncasecmp(bootstrap[i]->name, driver_attempt, driver_attempt_len) == 0)) {
@ -6294,15 +6297,15 @@ void SDL_Vulkan_UnloadLibrary(void)
}
}
char const * const *SDL_Vulkan_GetInstanceExtensions(Uint32 *count)
char const *const *SDL_Vulkan_GetInstanceExtensions(Uint32 *count)
{
return _this->Vulkan_GetInstanceExtensions(_this, count);
}
bool SDL_Vulkan_CreateSurface(SDL_Window *window,
VkInstance instance,
const struct VkAllocationCallbacks *allocator,
VkSurfaceKHR *surface)
VkInstance instance,
const struct VkAllocationCallbacks *allocator,
VkSurfaceKHR *surface)
{
CHECK_WINDOW_MAGIC(window, false);
@ -6311,11 +6314,11 @@ bool SDL_Vulkan_CreateSurface(SDL_Window *window,
return false;
}
CHECK_PARAM(!instance) {
CHECK_PARAM (!instance) {
return SDL_InvalidParamError("instance");
}
CHECK_PARAM(!surface) {
CHECK_PARAM (!surface) {
return SDL_InvalidParamError("surface");
}
@ -6349,20 +6352,20 @@ void SDL_Vulkan_DestroySurface(VkInstance instance,
}
bool SDL_Vulkan_GetPresentationSupport(VkInstance instance,
VkPhysicalDevice physicalDevice,
Uint32 queueFamilyIndex)
VkPhysicalDevice physicalDevice,
Uint32 queueFamilyIndex)
{
CHECK_PARAM(!_this) {
CHECK_PARAM (!_this) {
SDL_UninitializedVideo();
return false;
}
CHECK_PARAM(!instance) {
CHECK_PARAM (!instance) {
SDL_InvalidParamError("instance");
return false;
}
CHECK_PARAM(!physicalDevice) {
CHECK_PARAM (!physicalDevice) {
SDL_InvalidParamError("physicalDevice");
return false;
}
@ -6413,7 +6416,7 @@ void SDL_Metal_DestroyView(SDL_MetalView view)
void *SDL_Metal_GetLayer(SDL_MetalView view)
{
if (_this && _this->Metal_GetLayer) {
CHECK_PARAM(!view) {
CHECK_PARAM (!view) {
SDL_InvalidParamError("view");
return NULL;
}
@ -6424,6 +6427,11 @@ void *SDL_Metal_GetLayer(SDL_MetalView view)
}
}
WGPUSurface SDL_WGPU_CreateSurface(SDL_Window *window, WGPUInstance instance)
{
return _this->WGPU_CreateSurface(_this, window, instance);
}
#if defined(SDL_VIDEO_DRIVER_X11) || defined(SDL_VIDEO_DRIVER_WAYLAND) || defined(SDL_VIDEO_DRIVER_EMSCRIPTEN)
const char *SDL_GetCSSCursorName(SDL_SystemCursor id, const char **fallback_name)
{

View file

@ -37,6 +37,7 @@
#include "SDL_waylandvideo.h"
#include "SDL_waylandvulkan.h"
#include "SDL_waylandwindow.h"
#include "SDL_waylandwgpu.h"
#include <fcntl.h>
#include <sys/types.h>
@ -756,6 +757,9 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols)
device->Vulkan_GetPresentationSupport = Wayland_Vulkan_GetPresentationSupport;
#endif
#ifdef SDL_VIDEO_WGPU
device->WGPU_CreateSurface = Wayland_WGPU_CreateSurface;
#endif
device->free = Wayland_DeleteDevice;
device->device_caps = VIDEO_DEVICE_CAPS_MODE_SWITCHING_EMULATED |

View file

@ -0,0 +1,60 @@
#include "SDL_internal.h"
#if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_WAYLAND)
#include "SDL_waylandvideo.h"
#include "SDL_waylandwgpu.h"
SDL_ELF_NOTE_DLOPEN(
"wayland-wgpu",
"Support for wgpu-native on wayland backend",
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
"libwgpu_native.so")
WGPUSurface Wayland_WGPU_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, WGPUInstance instance)
{
SDL_PropertiesID windowProperties = SDL_GetWindowProperties(window);
struct wl_display *display = SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, 0);
struct wl_surface *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;
// FIXME: wgpuGetProcAddress isn't implemented, so we'll have to use SDL_LoadFunction instead and just hope nothing goes badly
//
// WGPUProcGetProcAddress getProcAddr = (WGPUProcGetProcAddress)SDL_LoadFunction(SDL_LoadObject("libwgpu_native.so"), "wgpuGetProcAddress");
// WGPUProcInstanceCreateSurface proc = (WGPUProcInstanceCreateSurface)getProcAddr((WGPUStringView){"wgpuInstanceCreateSurface", 25});
SDL_SharedObject *wgpuLib = SDL_LoadObject("libwgpu_native.so");
if (wgpuLib == NULL) {
SDL_SetError("Failed to load wgpu-native shared library 'libwgpu_native.so'");
goto fail;
}
WGPUProcInstanceCreateSurface proc = (WGPUProcInstanceCreateSurface)SDL_LoadFunction(wgpuLib, "wgpuInstanceCreateSurface");
if (proc == NULL) {
SDL_SetError("Failed to load function 'wgpuInstanceCreateSurface' from loaded wgpu-native library!");
goto fail;
}
return proc(instance, &desc);
fail:
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Failed to create WGPU surface: %s", SDL_GetError());
return NULL;
}
#endif

View file

@ -0,0 +1,14 @@
#ifndef SDL_waylandwgpu_h_
#define SDL_waylandwgpu_h_
// NOTE: Not sure if I'm allowed to do this.
#include "../webgpu/webgpu.h"
#include <SDL3/SDL_wgpu.h>
#if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_WAYLAND)
extern WGPUSurface Wayland_WGPU_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, WGPUInstance instance);
#endif
#endif // SDL_waylandwgpu_h_

6747
src/video/webgpu/webgpu.h Normal file

File diff suppressed because it is too large Load diff