mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-06-22 22:11:55 +00:00
Emscripten support for SDL_WGPU.
Congratulations; you can now use WebGPU on the Web. I'll make an example eventually, but it's midnight in Sweden and I gotta go to bed.
This commit is contained in:
parent
ea6a51fed7
commit
355ff8cf8d
6 changed files with 130 additions and 42 deletions
|
|
@ -23,12 +23,12 @@ add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
|
|||
if(SDL3_MAINPROJECT)
|
||||
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(is_multi_config)
|
||||
# The first item in CMAKE_CONFIGURATION_TYPES is the default configuration
|
||||
if(DEFINED CMAKE_CONFIGURATION_TYPES AND "RelWithDebInfo" IN_LIST CMAKE_CONFIGURATION_TYPES)
|
||||
list(REMOVE_ITEM CMAKE_CONFIGURATION_TYPES "RelWithDebInfo")
|
||||
list(INSERT CMAKE_CONFIGURATION_TYPES 0 "RelWithDebInfo")
|
||||
set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING "CMake configuration types" FORCE)
|
||||
endif()
|
||||
# The first item in CMAKE_CONFIGURATION_TYPES is the default configuration
|
||||
if(DEFINED CMAKE_CONFIGURATION_TYPES AND "RelWithDebInfo" IN_LIST CMAKE_CONFIGURATION_TYPES)
|
||||
list(REMOVE_ITEM CMAKE_CONFIGURATION_TYPES "RelWithDebInfo")
|
||||
list(INSERT CMAKE_CONFIGURATION_TYPES 0 "RelWithDebInfo")
|
||||
set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING "CMake configuration types" FORCE)
|
||||
endif()
|
||||
else()
|
||||
if(cmake_build_type_undefined)
|
||||
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "CMake build type" FORCE)
|
||||
|
|
@ -411,13 +411,13 @@ endif()
|
|||
|
||||
# TODO: I'm firing blind here, I have no idea what the SDL convensions on static linking or finding libraries is.
|
||||
if(APPLE OR LINUX OR FREEBSD OR OPENBSD)
|
||||
# unix-style, default search path should be /usr/lib/
|
||||
# unix-style, default search path should be /usr/lib/
|
||||
set(DEFAULT_WGPU_LIB_SEARCH_PATH "/usr/lib/")
|
||||
elseif(WINDOWS)
|
||||
# Windows has no real analogue to Unix's /usr/lib, so we're just gonna search the source dir.
|
||||
# Windows has no real analogue to Unix's /usr/lib, so we're just gonna search the source dir.
|
||||
set(DEFAULT_WGPU_LIB_SEARCH_PATH ${CMAKE_SOURCE_DIR})
|
||||
else()
|
||||
# Same as Windows, we're searching the source path.
|
||||
# Same as Windows, we're searching the source path.
|
||||
set(DEFAULT_WGPU_LIB_SEARCH_PATH ${CMAKE_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
|
|
@ -580,10 +580,10 @@ check_linker_supports_version_file(HAVE_WL_VERSION_SCRIPT)
|
|||
if(HAVE_WL_VERSION_SCRIPT)
|
||||
sdl_shared_link_options("-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/dynapi/SDL_dynapi.sym")
|
||||
else()
|
||||
# When building with tcc on Linux+glibc or Android, avoid emitting an error
|
||||
# for lack of support of the version-script linker flag: the option will be
|
||||
# silently ignored by the compiler and the build will still succeed.
|
||||
if(((LINUX AND LIBC_IS_GLIBC) OR ANDROID) AND (NOT USE_TCC))
|
||||
# When building with tcc on Linux+glibc or Android, avoid emitting an error
|
||||
# for lack of support of the version-script linker flag: the option will be
|
||||
# silently ignored by the compiler and the build will still succeed.
|
||||
if(((LINUX AND LIBC_IS_GLIBC) OR ANDROID) AND (NOT USE_TCC))
|
||||
message(FATAL_ERROR "Linker does not support '-Wl,--version-script=xxx.sym'. This is required on the current host platform (${SDL_CMAKE_PLATFORM}).")
|
||||
endif()
|
||||
endif()
|
||||
|
|
@ -946,8 +946,8 @@ if(SDL_ASSEMBLY)
|
|||
|
||||
if(SDL_ARMSVE2)
|
||||
cmake_push_check_state()
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -march=armv8-a+sve2")
|
||||
check_arm_source_compiles([==[
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -march=armv8-a+sve2")
|
||||
check_arm_source_compiles([==[
|
||||
#include <arm_sve.h>
|
||||
svuint32_t sve2_test(svuint32_t a, svuint32_t b) {
|
||||
return svadd_u32_x(svptrue_b32(), a, b);
|
||||
|
|
@ -956,13 +956,13 @@ if(SDL_ASSEMBLY)
|
|||
sve2_test(svdup_u32(0), svdup_u32(0));
|
||||
return 0;
|
||||
}]==] COMPILER_SUPPORTS_ARMSVE2)
|
||||
if(COMPILER_SUPPORTS_ARMSVE2)
|
||||
# IMPORTANT: As not all AArch64 processors support SVE2, we only
|
||||
# attach the following compilation option to SVE
|
||||
# dedicated source files.
|
||||
set(SVE2_MARCH_FLAG "-march=armv8-a+sve2")
|
||||
set(HAVE_ARMSVE2 TRUE)
|
||||
endif()
|
||||
if(COMPILER_SUPPORTS_ARMSVE2)
|
||||
# IMPORTANT: As not all AArch64 processors support SVE2, we only
|
||||
# attach the following compilation option to SVE
|
||||
# dedicated source files.
|
||||
set(SVE2_MARCH_FLAG "-march=armv8-a+sve2")
|
||||
set(HAVE_ARMSVE2 TRUE)
|
||||
endif()
|
||||
cmake_pop_check_state()
|
||||
|
||||
if(HAVE_ARMSVE2)
|
||||
|
|
@ -1736,6 +1736,7 @@ elseif(EMSCRIPTEN)
|
|||
# project. Uncomment at will for verbose cross-compiling -I/../ path info.
|
||||
sdl_compile_options(PRIVATE "-Wno-warn-absolute-paths")
|
||||
|
||||
CheckWGPU()
|
||||
if(NOT SDL_EMSCRIPTEN_PERSISTENT_PATH STREQUAL "")
|
||||
set(SDL_EMSCRIPTEN_PERSISTENT_PATH_STRING "${SDL_EMSCRIPTEN_PERSISTENT_PATH}")
|
||||
sdl_link_dependency(idbfs LIBS idbfs.js)
|
||||
|
|
@ -1876,20 +1877,20 @@ elseif(UNIX AND NOT (APPLE OR RISCOS OR HAIKU OR CYGWIN))
|
|||
|
||||
if(SDL_AUDIO)
|
||||
if(NETBSD)
|
||||
set(SDL_AUDIO_DRIVER_NETBSD 1)
|
||||
sdl_glob_sources(
|
||||
set(SDL_AUDIO_DRIVER_NETBSD 1)
|
||||
sdl_glob_sources(
|
||||
"${SDL3_SOURCE_DIR}/src/audio/netbsd/*.c"
|
||||
"${SDL3_SOURCE_DIR}/src/audio/netbsd/*.h"
|
||||
)
|
||||
set(HAVE_SDL_AUDIO TRUE)
|
||||
set(HAVE_SDL_AUDIO TRUE)
|
||||
elseif(QNX AND (CMAKE_SYSTEM_VERSION VERSION_LESS "8.0.0"))
|
||||
set(SDL_AUDIO_DRIVER_QNX 1)
|
||||
sdl_glob_sources(
|
||||
set(SDL_AUDIO_DRIVER_QNX 1)
|
||||
sdl_glob_sources(
|
||||
"${SDL3_SOURCE_DIR}/src/audio/qnx/*.c"
|
||||
"${SDL3_SOURCE_DIR}/src/audio/qnx/*.h"
|
||||
)
|
||||
sdl_link_dependency(asound LIBS asound)
|
||||
set(HAVE_SDL_AUDIO TRUE)
|
||||
sdl_link_dependency(asound LIBS asound)
|
||||
set(HAVE_SDL_AUDIO TRUE)
|
||||
endif()
|
||||
CheckOSS()
|
||||
CheckALSA()
|
||||
|
|
@ -2276,7 +2277,7 @@ elseif(WINDOWS OR CYGWIN)
|
|||
if(SDL_DIRECTX)
|
||||
cmake_push_check_state()
|
||||
if(DEFINED MSVC_VERSION AND NOT ${MSVC_VERSION} LESS 1700)
|
||||
set(USE_WINSDK_DIRECTX TRUE)
|
||||
set(USE_WINSDK_DIRECTX TRUE)
|
||||
endif()
|
||||
if(NOT (MINGW OR CYGWIN) AND NOT USE_WINSDK_DIRECTX)
|
||||
if("$ENV{DXSDK_DIR}" STREQUAL "")
|
||||
|
|
@ -3542,12 +3543,27 @@ endif()
|
|||
# webgpu static linking shenanigans
|
||||
if (SDL_WGPU_STATIC)
|
||||
if (HAVE_DAWN)
|
||||
if (EMSCRIPTEN)
|
||||
# You see, I pulled what's called a "big stupid"
|
||||
# I assumed that Dawn and Emdawnwebgpu were the same thing, so I added dawn support to SDL_WGPU.
|
||||
# Turns out, no it isn't. (sorta)
|
||||
# It's its own library and everything.
|
||||
# I'm still gonna keep the native Dawn support since I strictly adhere to the sunk cost fallacy.
|
||||
find_library(
|
||||
WGPU_STATIC_LIB NAMES libemdawnwebgpu_c.a emdawnwebgpu_c
|
||||
HINTS ${WGPU_STATIC_LIB_DIR} ${CMAKE_SOURCE_DIR}
|
||||
REQUIRED
|
||||
)
|
||||
message("-- Using Emdawnwebgpu as WebGPU implementation")
|
||||
else()
|
||||
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")
|
||||
endif()
|
||||
|
||||
elseif(HAVE_WGPU_NATIVE)
|
||||
find_library(
|
||||
WGPU_STATIC_LIB NAMES libwgpu_native wgpu_native
|
||||
|
|
@ -3563,9 +3579,9 @@ if (SDL_WGPU_STATIC)
|
|||
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")
|
||||
# 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)
|
||||
|
|
|
|||
|
|
@ -166,8 +166,8 @@ macro(CheckPipewire)
|
|||
sdl_link_dependency(pipewire LIBS PkgConfig::PC_PIPEWIRE PKG_CONFIG_PREFIX PC_PIPEWIRE PKG_CONFIG_SPECS ${PipeWire_PKG_CONFIG_SPEC})
|
||||
endif()
|
||||
set(HAVE_SDL_AUDIO TRUE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Requires:
|
||||
|
|
@ -620,24 +620,24 @@ macro(CheckLibThai)
|
|||
endmacro()
|
||||
|
||||
macro(WaylandProtocolGen _SCANNER _CODE_MODE _XML _PROTL)
|
||||
set(_WAYLAND_PROT_C_CODE "${CMAKE_CURRENT_BINARY_DIR}/wayland-generated-protocols/${_PROTL}-protocol.c")
|
||||
set(_WAYLAND_PROT_H_CODE "${CMAKE_CURRENT_BINARY_DIR}/wayland-generated-protocols/${_PROTL}-client-protocol.h")
|
||||
set(_WAYLAND_PROT_C_CODE "${CMAKE_CURRENT_BINARY_DIR}/wayland-generated-protocols/${_PROTL}-protocol.c")
|
||||
set(_WAYLAND_PROT_H_CODE "${CMAKE_CURRENT_BINARY_DIR}/wayland-generated-protocols/${_PROTL}-client-protocol.h")
|
||||
|
||||
add_custom_command(
|
||||
add_custom_command(
|
||||
OUTPUT "${_WAYLAND_PROT_H_CODE}"
|
||||
DEPENDS "${_XML}"
|
||||
COMMAND "${_SCANNER}"
|
||||
ARGS client-header "${_XML}" "${_WAYLAND_PROT_H_CODE}"
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
add_custom_command(
|
||||
OUTPUT "${_WAYLAND_PROT_C_CODE}"
|
||||
DEPENDS "${_WAYLAND_PROT_H_CODE}"
|
||||
COMMAND "${_SCANNER}"
|
||||
ARGS "${_CODE_MODE}" "${_XML}" "${_WAYLAND_PROT_C_CODE}"
|
||||
)
|
||||
|
||||
sdl_sources("${_WAYLAND_PROT_C_CODE}")
|
||||
sdl_sources("${_WAYLAND_PROT_C_CODE}")
|
||||
endmacro()
|
||||
|
||||
# Requires:
|
||||
|
|
@ -758,7 +758,7 @@ macro(CheckWayland)
|
|||
sdl_link_dependency(libdecor INCLUDES $<TARGET_PROPERTY:PkgConfig::PC_LIBDECOR,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
else()
|
||||
sdl_link_dependency(libdecor LIBS PkgConfig::PC_LIBDECOR PKG_CONFIG_PREFIX PC_LIBDECOR PKG_CONFIG_SPECS ${LibDecor_PKG_CONFIG_SPEC})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
@ -966,7 +966,15 @@ macro(CheckWGPU)
|
|||
sdl_sources("${SDL3_SOURCE_DIR}/src/video/windows/SDL_windowswgpu_dawn.cpp")
|
||||
endif()
|
||||
|
||||
if(EMSCRIPTEN)
|
||||
sdl_sources("${SDL3_SOURCE_DIR}/src/video/emscripten/SDL_emscriptenwgpu_dawn.cpp")
|
||||
endif()
|
||||
|
||||
elseif(SDL_WGPU_LIB STREQUAL "wgpu-native")
|
||||
if(EMSCRIPTEN)
|
||||
# wgpu-native doesn't support Emscripten. That's the entire reason we have Dawn.
|
||||
message(FATAL_ERROR "wgpu-native doesn't support Emscripten! Use Dawn instead.")
|
||||
endif()
|
||||
set(WGPU_NATIVE 1)
|
||||
set(HAVE_WGPU_NATIVE TRUE)
|
||||
else()
|
||||
|
|
|
|||
|
|
@ -53,8 +53,7 @@
|
|||
#define WGPU_STRLEN (SIZE_MAX)
|
||||
#endif
|
||||
|
||||
typedef enum WGPUSType
|
||||
{
|
||||
typedef enum WGPUSType {
|
||||
WGPUSType_ShaderSourceSPIRV = 0x00000001,
|
||||
WGPUSType_ShaderSourceWGSL = 0x00000002,
|
||||
WGPUSType_RenderPassMaxDrawCount = 0x00000003,
|
||||
|
|
@ -71,6 +70,8 @@ typedef enum WGPUSType
|
|||
WGPUSType_ExternalTextureBindingEntry = 0x0000000E,
|
||||
WGPUSType_CompatibilityModeLimits = 0x0000000F,
|
||||
WGPUSType_TextureBindingViewDimension = 0x00000010,
|
||||
WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector = 0x00040000,
|
||||
WGPUSType_DawnCompilationMessageUtf16 = 0x0005003F,
|
||||
WGPUSType_Force32 = 0x7FFFFFFF
|
||||
} WGPUSType;
|
||||
|
||||
|
|
@ -111,6 +112,11 @@ typedef struct WGPUSurfaceSourceWindowsHWND {
|
|||
void * hwnd;
|
||||
} WGPUSurfaceSourceWindowsHWND;
|
||||
|
||||
typedef struct WGPUEmscriptenSurfaceSourceCanvasHTMLSelector {
|
||||
WGPUChainedStruct chain;
|
||||
WGPUStringView selector;
|
||||
} WGPUEmscriptenSurfaceSourceCanvasHTMLSelector;
|
||||
|
||||
typedef WGPUSurface (*WGPUProcInstanceCreateSurface)(WGPUInstance instance, WGPUSurfaceDescriptor const *descriptor) WGPU_FUNCTION_ATTRIBUTE;
|
||||
|
||||
WGPU_EXTERN WGPUSurface wgpuInstanceCreateSurface(WGPUInstance instance, WGPUSurfaceDescriptor const * descriptor) WGPU_FUNCTION_ATTRIBUTE;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "SDL_emscriptenframebuffer.h"
|
||||
#include "SDL_emscriptenevents.h"
|
||||
#include "SDL_emscriptenmouse.h"
|
||||
#include "SDL_emscriptenwgpu.h"
|
||||
|
||||
#define EMSCRIPTENVID_DRIVER_NAME "emscripten"
|
||||
|
||||
|
|
@ -187,6 +188,8 @@ static SDL_VideoDevice *Emscripten_CreateDevice(void)
|
|||
device->GL_SwapWindow = Emscripten_GLES_SwapWindow;
|
||||
device->GL_DestroyContext = Emscripten_GLES_DestroyContext;
|
||||
|
||||
device->WGPU_CreateSurface = Emscripten_WGPU_CreateSurface;
|
||||
|
||||
device->free = Emscripten_DeleteDevice;
|
||||
|
||||
Emscripten_ListenSystemTheme();
|
||||
|
|
|
|||
23
src/video/emscripten/SDL_emscriptenwgpu.h
Normal file
23
src/video/emscripten/SDL_emscriptenwgpu.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef SDL_emscriptenwgpu_h_
|
||||
#define SDL_emscriptenwgpu_h_
|
||||
|
||||
#include <SDL3/SDL_wgpu.h>
|
||||
|
||||
#if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_EMSCRIPTEN)
|
||||
|
||||
// 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 Emscripten_WGPU_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, WGPUInstance instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif // SDL_emscriptenwgpu_h_
|
||||
32
src/video/emscripten/SDL_emscriptenwgpu_dawn.cpp
Normal file
32
src/video/emscripten/SDL_emscriptenwgpu_dawn.cpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#include "SDL_internal.h"
|
||||
|
||||
#if defined(SDL_VIDEO_WGPU) && defined(SDL_VIDEO_DRIVER_EMSCRIPTEN) && defined(WGPU_DAWN)
|
||||
|
||||
#include "../SDL_wgpu_defs.h"
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
#include "SDL_emscriptenwgpu.h"
|
||||
|
||||
#include <SDL3/SDL_wgpu.h>
|
||||
|
||||
WGPUSurface
|
||||
Emscripten_WGPU_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, WGPUInstance instance)
|
||||
{
|
||||
SDL_PropertiesID windowProperties = SDL_GetWindowProperties(window);
|
||||
|
||||
const char *canvas = SDL_GetStringProperty(windowProperties, SDL_PROP_WINDOW_EMSCRIPTEN_CANVAS_ID_STRING, 0);
|
||||
|
||||
WGPUSurfaceDescriptor desc;
|
||||
WGPUEmscriptenSurfaceSourceCanvasHTMLSelector source;
|
||||
|
||||
source.selector.data = canvas;
|
||||
source.chain.sType = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector;
|
||||
source.chain.next = NULL;
|
||||
|
||||
desc.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||
desc.nextInChain = &source.chain;
|
||||
|
||||
return wgpuInstanceCreateSurface(instance, &desc);
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue