From eebbf3457ccb7ebca9a83cd77e8673a5f822e772 Mon Sep 17 00:00:00 2001
From: Charlie Birks <[EMAIL REDACTED]>
Date: Fri, 25 Feb 2022 17:19:25 +0000
Subject: [PATCH 001/153] emscripten: Use emscripten_webgl_ API directly
---
src/video/emscripten/SDL_emscriptenopengles.c | 138 +++++++++++-------
src/video/emscripten/SDL_emscriptenopengles.h | 16 +-
src/video/emscripten/SDL_emscriptenvideo.c | 24 ---
src/video/emscripten/SDL_emscriptenvideo.h | 7 -
4 files changed, 96 insertions(+), 89 deletions(-)
diff --git a/src/video/emscripten/SDL_emscriptenopengles.c b/src/video/emscripten/SDL_emscriptenopengles.c
index 10c6285cf325..a3219372c147 100644
--- a/src/video/emscripten/SDL_emscriptenopengles.c
+++ b/src/video/emscripten/SDL_emscriptenopengles.c
@@ -20,83 +20,123 @@
*/
#include "../../SDL_internal.h"
-#if SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL
+#if SDL_VIDEO_DRIVER_EMSCRIPTEN
#include <emscripten/emscripten.h>
+#include <emscripten/html5_webgl.h>
#include <GLES2/gl2.h>
#include "SDL_emscriptenvideo.h"
#include "SDL_emscriptenopengles.h"
#include "SDL_hints.h"
-#define LOAD_FUNC(NAME) _this->egl_data->NAME = NAME;
-/* EGL implementation of SDL OpenGL support */
+int
+Emscripten_GLES_LoadLibrary(_THIS, const char *path)
+{
+ return 0;
+}
+
+void
+Emscripten_GLES_UnloadLibrary(_THIS)
+{
+}
+
+void *
+Emscripten_GLES_GetProcAddress(_THIS, const char *proc)
+{
+ return emscripten_webgl_get_proc_address(proc);
+}
int
-Emscripten_GLES_LoadLibrary(_THIS, const char *path) {
- /*we can't load EGL dynamically*/
- _this->egl_data = (struct SDL_EGL_VideoData *) SDL_calloc(1, sizeof(SDL_EGL_VideoData));
- if (!_this->egl_data) {
- return SDL_OutOfMemory();
+Emscripten_GLES_SetSwapInterval(_THIS, int interval)
+{
+ if (interval < 0) {
+ return SDL_SetError("Late swap tearing currently unsupported");
+ } else if(interval == 0) {
+ emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, 0);
+ } else {
+ emscripten_set_main_loop_timing(EM_TIMING_RAF, interval);
}
- /* Emscripten forces you to manually cast eglGetProcAddress to the real
- function type; grep for "__eglMustCastToProperFunctionPointerType" in
- Emscripten's egl.h for details. */
- _this->egl_data->eglGetProcAddress = (void *(EGLAPIENTRY *)(const char *)) eglGetProcAddress;
-
- LOAD_FUNC(eglGetDisplay);
- LOAD_FUNC(eglInitialize);
- LOAD_FUNC(eglTerminate);
- LOAD_FUNC(eglChooseConfig);
- LOAD_FUNC(eglGetConfigAttrib);
- LOAD_FUNC(eglCreateContext);
- LOAD_FUNC(eglDestroyContext);
- LOAD_FUNC(eglCreateWindowSurface);
- LOAD_FUNC(eglDestroySurface);
- LOAD_FUNC(eglMakeCurrent);
- LOAD_FUNC(eglSwapBuffers);
- LOAD_FUNC(eglSwapInterval);
- LOAD_FUNC(eglWaitNative);
- LOAD_FUNC(eglWaitGL);
- LOAD_FUNC(eglBindAPI);
- LOAD_FUNC(eglQueryString);
- LOAD_FUNC(eglGetError);
-
- _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (!_this->egl_data->egl_display) {
- return SDL_SetError("Could not get EGL display");
- }
-
- if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
- return SDL_SetError("Could not initialize EGL");
+ return 0;
+}
+
+int
+Emscripten_GLES_GetSwapInterval(_THIS)
+{
+ int mode, value;
+
+ emscripten_get_main_loop_timing(&mode, &value);
+
+ if(mode == EM_TIMING_RAF)
+ return value;
+
+ return 0;
+}
+
+SDL_GLContext
+Emscripten_GLES_CreateContext(_THIS, SDL_Window * window)
+{
+ SDL_WindowData *window_data;
+
+ EmscriptenWebGLContextAttributes attribs;
+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context;
+
+ emscripten_webgl_init_context_attributes(&attribs);
+
+ attribs.alpha = _this->gl_config.alpha_size > 0;
+ attribs.depth = _this->gl_config.depth_size > 0;
+ attribs.stencil = _this->gl_config.stencil_size > 0;
+ attribs.antialias = _this->gl_config.multisamplebuffers == 1;
+
+ if(_this->gl_config.major_version == 3)
+ attribs.majorVersion = 2; /* WebGL 2.0 ~= GLES 3.0 */
+
+ window_data = (SDL_WindowData *) window->driverdata;
+ context = emscripten_webgl_create_context(window_data->canvas_id, &attribs);
+
+ if (context < 0) {
+ SDL_SetError("Could not create webgl context");
+ return NULL;
}
- if (path) {
- SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1);
- } else {
- *_this->gl_config.driver_path = '\0';
+ if (emscripten_webgl_make_context_current(context) != EMSCRIPTEN_RESULT_SUCCESS) {
+ emscripten_webgl_destroy_context(context);
+ return NULL;
}
-
- return 0;
+
+
+ return (SDL_GLContext)context;
}
-SDL_EGL_CreateContext_impl(Emscripten)
-SDL_EGL_MakeCurrent_impl(Emscripten)
+void
+Emscripten_GLES_DeleteContext(_THIS, SDL_GLContext context)
+{
+ emscripten_webgl_destroy_context((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)context);
+}
int
Emscripten_GLES_SwapWindow(_THIS, SDL_Window * window)
{
- EGLBoolean ret = SDL_EGL_SwapBuffers(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, SDL_TRUE)) {
/* give back control to browser for screen refresh */
emscripten_sleep(0);
}
- return ret;
+ return 0;
+}
+
+int
+Emscripten_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
+{
+ /* ignores window, as it isn't possible to reuse contexts across canvases */
+ if (emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)context) != EMSCRIPTEN_RESULT_SUCCESS) {
+ return SDL_SetError("Unable to make context current");
+ }
+ return 0;
}
-#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL */
+#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/emscripten/SDL_emscriptenopengles.h b/src/video/emscripten/SDL_emscriptenopengles.h
index 9d178f6902d9..6d58ac10dfd4 100644
--- a/src/video/emscripten/SDL_emscriptenopengles.h
+++ b/src/video/emscripten/SDL_emscriptenopengles.h
@@ -23,25 +23,23 @@
#ifndef SDL_emscriptenopengles_h_
#define SDL_emscriptenopengles_h_
-#if SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL
+#if SDL_VIDEO_DRIVER_EMSCRIPTEN
#include "../SDL_sysvideo.h"
-#include "../SDL_egl_c.h"
/* OpenGLES functions */
-#define Emscripten_GLES_GetAttribute SDL_EGL_GetAttribute
-#define Emscripten_GLES_GetProcAddress SDL_EGL_GetProcAddress
-#define Emscripten_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
-#define Emscripten_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
-#define Emscripten_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
-#define Emscripten_GLES_DeleteContext SDL_EGL_DeleteContext
extern int Emscripten_GLES_LoadLibrary(_THIS, const char *path);
+extern void Emscripten_GLES_UnloadLibrary(_THIS);
+extern void * Emscripten_GLES_GetProcAddress(_THIS, const char *proc);
+extern int Emscripten_GLES_SetSwapInterval(_THIS, int interval);
+extern int Emscripten_GLES_GetSwapInterval(_THIS);
extern SDL_GLContext Emscripten_GLES_CreateContext(_THIS, SDL_Window * window);
+extern void Emscripten_GLES_DeleteContext(_THIS, SDL_GLContext context);
extern int Emscripten_GLES_SwapWindow(_THIS, SDL_Window * window);
extern int Emscripten_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
-#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL */
+#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
#endif /* SDL_emscriptenopengles_h_ */
diff --git a/src/video/emscripten/SDL_emscriptenvideo.c b/src/video/emscripten/SDL_emscriptenvideo.c
index 550031d3fbea..46813a721798 100644
--- a/src/video/emscripten/SDL_emscriptenvideo.c
+++ b/src/video/emscripten/SDL_emscriptenvideo.c
@@ -27,7 +27,6 @@
#include "SDL_hints.h"
#include "../SDL_sysvideo.h"
#include "../SDL_pixels_c.h"
-#include "../SDL_egl_c.h"
#include "../../events/SDL_events_c.h"
#include "SDL_emscriptenvideo.h"
@@ -110,7 +109,6 @@ Emscripten_CreateDevice(void)
device->UpdateWindowFramebuffer = Emscripten_UpdateWindowFramebuffer;
device->DestroyWindowFramebuffer = Emscripten_DestroyWindowFramebuffer;
-#if SDL_VIDEO_OPENGL_EGL
device->GL_LoadLibrary = Emscripten_GLES_LoadLibrary;
device->GL_GetProcAddress = Emscripten_GLES_GetProcAddress;
device->GL_UnloadLibrary = Emscripten_GLES_UnloadLibrary;
@@ -120,7 +118,6 @@ Emscripten_CreateDevice(void)
device->GL_GetSwapInterval = Emscripten_GLES_GetSwapInterval;
device->GL_SwapWindow = Emscripten_GLES_SwapWindow;
device->GL_DeleteContext = Emscripten_GLES_DeleteContext;
-#endif
device->free = Emscripten_DeleteDevice;
@@ -259,21 +256,6 @@ Emscripten_CreateWindow(_THIS, SDL_Window * window)
}
}
-#if SDL_VIDEO_OPENGL_EGL
- if (window->flags & SDL_WINDOW_OPENGL) {
- if (!_this->egl_data) {
- if (SDL_GL_LoadLibrary(NULL) < 0) {
- return -1;
- }
- }
- wdata->egl_surface = SDL_EGL_CreateSurface(_this, 0);
-
- if (wdata->egl_surface == EGL_NO_SURFACE) {
- return SDL_SetError("Could not create GLES window surface");
- }
- }
-#endif
-
wdata->window = window;
/* Setup driver data for this window */
@@ -329,12 +311,6 @@ Emscripten_DestroyWindow(_THIS, SDL_Window * window)
data = (SDL_WindowData *) window->driverdata;
Emscripten_UnregisterEventHandlers(data);
-#if SDL_VIDEO_OPENGL_EGL
- if (data->egl_surface != EGL_NO_SURFACE) {
- SDL_EGL_DestroySurface(_this, data->egl_surface);
- data->egl_surface = EGL_NO_SURFACE;
- }
-#endif
/* We can't destroy the canvas, so resize it to zero instead */
emscripten_set_canvas_element_size(data->canvas_id, 0, 0);
diff --git a/src/video/emscripten/SDL_emscriptenvideo.h b/src/video/emscripten/SDL_emscriptenvideo.h
index e87788d3f815..20481235e5b5 100644
--- a/src/video/emscripten/SDL_emscriptenvideo.h
+++ b/src/video/emscripten/SDL_emscriptenvideo.h
@@ -28,15 +28,8 @@
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
-#if SDL_VIDEO_OPENGL_EGL
-#include <EGL/egl.h>
-#endif
-
typedef struct SDL_WindowData
{
-#if SDL_VIDEO_OPENGL_EGL
- EGLSurface egl_surface;
-#endif
SDL_Window *window;
SDL_Surface *surface;
From 539efc1bbaec197cb0d6663824fd29fd71060785 Mon Sep 17 00:00:00 2001
From: Charlie Birks <charlie@daft.games>
Date: Sat, 26 Feb 2022 12:24:32 +0000
Subject: [PATCH 002/153] emscripten: Return an error for webgl context
limitations
---
src/video/emscripten/SDL_emscriptenopengles.c | 30 ++++++++++++++++++-
src/video/emscripten/SDL_emscriptenvideo.h | 2 ++
2 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/src/video/emscripten/SDL_emscriptenopengles.c b/src/video/emscripten/SDL_emscriptenopengles.c
index a3219372c147..ccec124ce20f 100644
--- a/src/video/emscripten/SDL_emscriptenopengles.c
+++ b/src/video/emscripten/SDL_emscriptenopengles.c
@@ -94,6 +94,12 @@ Emscripten_GLES_CreateContext(_THIS, SDL_Window * window)
attribs.majorVersion = 2; /* WebGL 2.0 ~= GLES 3.0 */
window_data = (SDL_WindowData *) window->driverdata;
+
+ if (window_data->gl_context) {
+ SDL_SetError("Cannot create multiple webgl contexts per window");
+ return NULL;
+ }
+
context = emscripten_webgl_create_context(window_data->canvas_id, &attribs);
if (context < 0) {
@@ -106,6 +112,7 @@ Emscripten_GLES_CreateContext(_THIS, SDL_Window * window)
return NULL;
}
+ window_data->gl_context = (SDL_GLContext)context;
return (SDL_GLContext)context;
}
@@ -113,6 +120,18 @@ Emscripten_GLES_CreateContext(_THIS, SDL_Window * window)
void
Emscripten_GLES_DeleteContext(_THIS, SDL_GLContext context)
{
+ SDL_Window *window;
+
+ /* remove the context from its window */
+ for (window = _this->windows; window != NULL; window = window->next) {
+ SDL_WindowData *window_data;
+ window_data = (SDL_WindowData *) window->driverdata;
+
+ if (window_data->gl_context == context) {
+ window_data->gl_context = NULL;
+ }
+ }
+
emscripten_webgl_destroy_context((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)context);
}
@@ -129,7 +148,16 @@ Emscripten_GLES_SwapWindow(_THIS, SDL_Window * window)
int
Emscripten_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
{
- /* ignores window, as it isn't possible to reuse contexts across canvases */
+ /* it isn't possible to reuse contexts across canvases */
+ if (window && context) {
+ SDL_WindowData *window_data;
+ window_data = (SDL_WindowData *) window->driverdata;
+
+ if (context != window_data->gl_context) {
+ return SDL_SetError("Cannot make context current to another window");
+ }
+ }
+
if (emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)context) != EMSCRIPTEN_RESULT_SUCCESS) {
return SDL_SetError("Unable to make context current");
}
diff --git a/src/video/emscripten/SDL_emscriptenvideo.h b/src/video/emscripten/SDL_emscriptenvideo.h
index 20481235e5b5..4cd0a5ce59e2 100644
--- a/src/video/emscripten/SDL_emscriptenvideo.h
+++ b/src/video/emscripten/SDL_emscriptenvideo.h
@@ -33,6 +33,8 @@ typedef struct SDL_WindowData
SDL_Window *window;
SDL_Surface *surface;
+ SDL_GLContext gl_context;
+
char *canvas_id;
float pixel_ratio;
From b5aedaad5923edd88ca33e6dab4b86503e8cb0f3 Mon Sep 17 00:00:00 2001
From: Charlie Birks <charlie@daftgames.net>
Date: Sun, 8 Apr 2018 16:54:29 +0100
Subject: [PATCH 003/153] emscripten: Modify UpdateWindowFramebuffer
To work with multiple canvases
---
src/video/emscripten/SDL_emscriptenframebuffer.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/video/emscripten/SDL_emscriptenframebuffer.c b/src/video/emscripten/SDL_emscriptenframebuffer.c
index 03fea04efa30..05e4aa7453f2 100644
--- a/src/video/emscripten/SDL_emscriptenframebuffer.c
+++ b/src/video/emscripten/SDL_emscriptenframebuffer.c
@@ -75,12 +75,15 @@ int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rec
var w = $0;
var h = $1;
var pixels = $2;
+ var canvasId = UTF8ToString($3);
+ var canvas = document.querySelector(canvasId);
+ //TODO: this should store a context per canvas
if (!Module['SDL2']) Module['SDL2'] = {};
var SDL2 = Module['SDL2'];
- if (SDL2.ctxCanvas !== Module['canvas']) {
- SDL2.ctx = Module['createContext'](Module['canvas'], false, true);
- SDL2.ctxCanvas = Module['canvas'];
+ if (SDL2.ctxCanvas !== canvas) {
+ SDL2.ctx = Module['createContext'](canvas, false, true);
+ SDL2.ctxCanvas = canvas;
}
if (SDL2.w !== w || SDL2.h !== h || SDL2.imageCtx !== SDL2.ctx) {
SDL2.image = SDL2.ctx.createImageData(w, h);
@@ -156,7 +159,7 @@ int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rec
}
SDL2.ctx.putImageData(SDL2.image, 0, 0);
- }, surface->w, surface->h, surface->pixels);
+ }, surface->w, surface->h, surface->pixels, data->canvas_id);
if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, SDL_TRUE)) {
/* give back control to browser for screen refresh */
From d75fb0995dcf533bbc03bdac1c7d41caad678d68 Mon Sep 17 00:00:00 2001
From: Charlie Birks <charlie@daft.games>
Date: Sat, 26 Feb 2022 14:52:08 +0000
Subject: [PATCH 004/153] emscripten: Add a hint for specifying the canvas
selector
Now that we're not going through EGL, this is easy
---
include/SDL_hints.h | 9 +++++++++
src/video/emscripten/SDL_emscriptenvideo.c | 8 +++++++-
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index 48f4f3689a70..6fee3e5fce47 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -366,6 +366,15 @@ extern "C" {
*/
#define SDL_HINT_EMSCRIPTEN_ASYNCIFY "SDL_EMSCRIPTEN_ASYNCIFY"
+/**
+ * \brief Specify the CSS selector used for the "default" window/canvas
+ *
+ * This hint only applies to the emscripten platform
+ *
+ * The default value is "#canvas"
+ */
+#define SDL_HINT_EMSCRIPTEN_CANVAS_SELECTOR "SDL_EMSCRIPTEN_CANVAS_SELECTOR"
+
/**
* \brief override the binding element for keyboard inputs for Emscripten builds
*
diff --git a/src/video/emscripten/SDL_emscriptenvideo.c b/src/video/emscripten/SDL_emscriptenvideo.c
index 46813a721798..c8efac48f850 100644
--- a/src/video/emscripten/SDL_emscriptenvideo.c
+++ b/src/video/emscripten/SDL_emscriptenvideo.c
@@ -215,6 +215,7 @@ Emscripten_CreateWindow(_THIS, SDL_Window * window)
SDL_WindowData *wdata;
double scaled_w, scaled_h;
double css_w, css_h;
+ const char *selector;
/* Allocate window internal data */
wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
@@ -222,7 +223,12 @@ Emscripten_CreateWindow(_THIS, SDL_Window * window)
return SDL_OutOfMemory();
}
- wdata->canvas_id = SDL_strdup("#canvas");
+ selector = SDL_GetHint(SDL_HINT_EMSCRIPTEN_CANVAS_SELECTOR);
+ if (!selector) {
+ selector = "#canvas";
+ }
+
+ wdata->canvas_id = SDL_strdup(selector);
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
wdata->pixel_ratio = emscripten_get_device_pixel_ratio();
From 0dfc829a6b75b5a3c4c1d49fb943b622c12d67bc Mon Sep 17 00:00:00 2001
From: Sam Lantinga <slouken@libsdl.org>
Date: Thu, 10 Nov 2022 19:16:53 -0800
Subject: [PATCH 005/153] Added simple BLE Steam Controller support on all
platforms
This is still disabled by default via the hint SDL_HINT_JOYSTICK_HIDAPI_STEAM
---
Makefile.os2 | 2 +-
Makefile.w32 | 2 +-
VisualC-GDK/SDL/SDL.vcxproj | 1 +
VisualC-GDK/SDL/SDL.vcxproj.filters | 3 ++
VisualC/SDL/SDL.vcxproj | 1 +
VisualC/SDL/SDL.vcxproj.filters | 3 ++
Xcode/SDL/SDL.xcodeproj/project.pbxproj | 6 +++
include/SDL_hints.h | 2 +-
src/joystick/hidapi/SDL_hidapi_steam.c | 48 +++++++++++++++-------
src/joystick/hidapi/SDL_hidapijoystick_c.h | 6 +--
test/testgamecontroller.c | 1 +
11 files changed, 53 insertions(+), 22 deletions(-)
diff --git a/Makefile.os2 b/Makefile.os2
index 76b2b398dfe9..6ec172b37d5e 100644
--- a/Makefile.os2
+++ b/Makefile.os2
@@ -94,7 +94,7 @@ SRCS+= SDL_systimer.c
SRCS+= SDL_sysloadso.c
SRCS+= SDL_sysfilesystem.c
SRCS+= SDL_os2joystick.c SDL_syshaptic.c SDL_sysjoystick.c SDL_virtualjoystick.c
-SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_combined.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps3.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_shield.c SDL_hidapi_stadia.c SDL_hidapi_switch.c SDL_hidapi_wii.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c
+SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_combined.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps3.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_shield.c SDL_hidapi_stadia.c SDL_hidapi_steam.c SDL_hidapi_switch.c SDL_hidapi_wii.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c
SRCS+= SDL_dummyaudio.c SDL_diskaudio.c
SRCS+= SDL_nullvideo.c SDL_nullframebuffer.c SDL_nullevents.c
SRCS+= SDL_dummysensor.c
diff --git a/Makefile.w32 b/Makefile.w32
index 68c3a3731598..407bfd2a0110 100644
--- a/Makefile.w32
+++ b/Makefile.w32
@@ -73,7 +73,7 @@ SRCS+= SDL_systimer.c
SRCS+= SDL_sysloadso.c
SRCS+= SDL_sysfilesystem.c
SRCS+= SDL_syshaptic.c SDL_sysjoystick.c SDL_virtualjoystick.c
-SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_combined.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps3.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_shield.c SDL_hidapi_stadia.c SDL_hidapi_switch.c SDL_hidapi_wii.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c
+SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_combined.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps3.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_shield.c SDL_hidapi_stadia.c SDL_hidapi_steam.c SDL_hidapi_switch.c SDL_hidapi_wii.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c
SRCS+= SDL_dummyaudio.c SDL_diskaudio.c
SRCS+= SDL_nullvideo.c SDL_nullframebuffer.c SDL_nullevents.c
SRCS+= SDL_dummysensor.c
diff --git a/VisualC-GDK/SDL/SDL.vcxproj b/VisualC-GDK/SDL/SDL.vcxproj
index e3966e693d6a..c8208b41f7e8 100644
--- a/VisualC-GDK/SDL/SDL.vcxproj
+++ b/VisualC-GDK/SDL/SDL.vcxproj
@@ -600,6 +600,7 @@
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_rumble.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_shield.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_stadia.c" />
+ <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_steam.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_wii.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
diff --git a/VisualC-GDK/SDL/SDL.vcxproj.filters b/VisualC-GDK/SDL/SDL.vcxproj.filters
index 0c02e0796564..02dc97ef30f0 100644
--- a/VisualC-GDK/SDL/SDL.vcxproj.filters
+++ b/VisualC-GDK/SDL/SDL.vcxproj.filters
@@ -1078,6 +1078,9 @@
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_stadia.c">
<Filter>joystick\hidapi</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_steam.c">
+ <Filter>joystick\hidapi</Filter>
+ </ClCompile>
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c">
<Filter>joystick\hidapi</Filter>
</ClCompile>
diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj
index e3b66d1cb16a..2c85790e2cab 100644
--- a/VisualC/SDL/SDL.vcxproj
+++ b/VisualC/SDL/SDL.vcxproj
@@ -491,6 +491,7 @@
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_rumble.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_shield.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_stadia.c" />
+ <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_steam.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_wii.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters
index 167e40d29769..082e257b4547 100644
--- a/VisualC/SDL/SDL.vcxproj.filters
+++ b/VisualC/SDL/SDL.vcxproj.filters
@@ -1069,6 +1069,9 @@
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_stadia.c">
<Filter>joystick\hidapi</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_steam.c">
+ <Filter>joystick\hidapi</Filter>
+ </ClCompile>
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c">
<Filter>joystick\hidapi</Filter>
</ClCompile>
diff --git a/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/Xcode/SDL/SDL.xcodeproj/project.pbxproj
index 9c086f1ff2ec..a0741e06c9e9 100644
--- a/Xcode/SDL/SDL.xcodeproj/project.pbxproj
+++ b/Xcode/SDL/SDL.xcodeproj/project.pbxproj
@@ -3393,6 +3393,9 @@
F323060528939F6400E66D30 /* SDL_hidapi_combined.c in Sources */ = {isa = PBXBuildFile; fileRef = F32305FE28939F6400E66D30 /* SDL_hidapi_combined.c */; };
F323060628939F6400E66D30 /* SDL_hidapi_combined.c in Sources */ = {isa = PBXBuildFile; fileRef = F32305FE28939F6400E66D30 /* SDL_hidapi_combined.c */; };
F323060728939F6400E66D30 /* SDL_hidapi_combined.c in Sources */ = {isa = PBXBuildFile; fileRef = F32305FE28939F6400E66D30 /* SDL_hidapi_combined.c */; };
+ F34B9895291DEFF500AAC96E /* SDL_hidapi_steam.c in Sources */ = {isa = PBXBuildFile; fileRef = A75FDAAC23E2795C00529352 /* SDL_hidapi_steam.c */; };
+ F34B9896291DEFF700AAC96E /* SDL_hidapi_steam.c in Sources */ = {isa = PBXBuildFile; fileRef = A75FDAAC23E2795C00529352 /* SDL_hidapi_steam.c */; };
+ F34B9897291DEFFA00AAC96E /* SDL_hidapi_steam.c in Sources */ = {isa = PBXBuildFile; fileRef = A75FDAAC23E2795C00529352 /* SDL_hidapi_steam.c */; };
F3631C6424884ACF004F28EA /* SDL_locale.h in Headers */ = {isa = PBXBuildFile; fileRef = 566E26792462701100718109 /* SDL_locale.h */; settings = {ATTRIBUTES = (Public, ); }; };
F3631C652488534E004F28EA /* SDL_locale.h in Headers */ = {isa = PBXBuildFile; fileRef = 566E26792462701100718109 /* SDL_locale.h */; settings = {ATTRIBUTES = (Public, ); }; };
F376F6192559B29300CFC0BC /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F376F6182559B29300CFC0BC /* OpenGLES.framework */; platformFilter = ios; };
@@ -8909,6 +8912,7 @@
A7D8BBD923E2574800DCD162 /* SDL_uikitmessagebox.m in Sources */,
A7D8AD2923E2514100DCD162 /* SDL_vulkan_utils.c in Sources */,
A7D8A95123E2514000DCD162 /* SDL_spinlock.c in Sources */,
+ F34B9895291DEFF500AAC96E /* SDL_hidapi_steam.c in Sources */,
A7D8BAAF23E2514400DCD162 /* s_atan.c in Sources */,
A7D8B75223E2514300DCD162 /* SDL_sysloadso.c in Sources */,
A7D8BBE123E2574800DCD162 /* SDL_uikitopenglview.m in Sources */,
@@ -9103,6 +9107,7 @@
A7D8B41F23E2514300DCD162 /* SDL_systls.c in Sources */,
A7D8AD2C23E2514100DCD162 /* SDL_vulkan_utils.c in Sources */,
A7D8A95423E2514000DCD162 /* SDL_spinlock.c in Sources */,
+ F34B9896291DEFF700AAC96E /* SDL_hidapi_steam.c in Sources */,
A7D8BAB223E2514400DCD162 /* s_atan.c in Sources */,
F3A490A12554D38600E92A8B /* SDL_hidapi_ps5.c in Sources */,
A7D8B75523E2514300DCD162 /* SDL_sysloadso.c in Sources */,
@@ -9297,6 +9302,7 @@
A7D8AD2E23E2514100DCD162 /* SDL_vulkan_utils.c in Sources */,
A7D8A95623E2514000DCD162 /* SDL_spinlock.c in Sources */,
A7D8BAB423E2514400DCD162 /* s_atan.c in Sources */,
+ F34B9897291DEFFA00AAC96E /* SDL_hidapi_steam.c in Sources */,
A7D8B75723E2514300DCD162 /* SDL_sysloadso.c in Sources */,
F3A490A42554D38600E92A8B /* SDL_hidapi_ps5.c in Sources */,
A7D8B98B23E2514400DCD162 /* SDL_render_metal.m in Sources */,
diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index ce2225440fb3..d51525936c4b 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -817,7 +817,7 @@ extern "C" {
#define SDL_HINT_JOYSTICK_HIDAPI_STADIA "SDL_JOYSTICK_HIDAPI_STADIA"
/**
- * \brief A variable controlling whether the HIDAPI driver for Steam Controllers should be used.
+ * \brief A variable controlling whether the HIDAPI driver for Bluetooth Steam Controllers should be used.
*
* This variable can be set to the following values:
* "0" - HIDAPI driver is not used
diff --git a/src/joystick/hidapi/SDL_hidapi_steam.c b/src/joystick/hidapi/SDL_hidapi_steam.c
index 7b497fa9594e..9221d12e887a 100644
--- a/src/joystick/hidapi/SDL_hidapi_steam.c
+++ b/src/joystick/hidapi/SDL_hidapi_steam.c
@@ -356,30 +356,41 @@ static int GetFeatureReport( SDL_hid_device *dev, unsigned char uBuffer[65] )
if ( bBle )
{
int nRetries = 0;
- uint8_t uSegmentBuffer[ MAX_REPORT_SEGMENT_SIZE ];
+ uint8_t uSegmentBuffer[ MAX_REPORT_SEGMENT_SIZE + 1 ];
+ uint8_t ucBytesToRead = MAX_REPORT_SEGMENT_SIZE;
+ uint8_t ucDataStartOffset = 0;
SteamControllerPacketAssembler assembler;
InitializeSteamControllerPacketAssembler( &assembler );
+ // On Windows and macOS, BLE devices get 2 copies of the feature report ID, one that is removed by ReadFeatureReport,
+ // and one that's included in the buffer we receive. We pad the bytes to read and skip over the report ID
+ // if necessary.
+#if defined(__WIN32__) || defined(__MACOSX__)
+ ++ucBytesToRead;
+ ++ucDataStartOffset;
+#endif
+
while( nRetries < BLE_MAX_READ_RETRIES )
{
SDL_memset( uSegmentBuffer, 0, sizeof( uSegmentBuffer ) );
uSegmentBuffer[ 0 ] = BLE_REPORT_NUMBER;
- nRet = SDL_hid_get_feature_report( dev, uSegmentBuffer, sizeof( uSegmentBuffer ) );
+ nRet = SDL_hid_get_feature_report( dev, uSegmentBuffer, ucBytesToRead );
+
DPRINTF( "GetFeatureReport ble ret=%d\n", nRet );
HEXDUMP( uSegmentBuffer, nRet );
// Zero retry counter if we got data
- if ( nRet > 2 && ( uSegmentBuffer[ 1 ] & REPORT_SEGMENT_DATA_FLAG ) )
+ if ( nRet > 2 && ( uSegmentBuffer[ ucDataStartOffset + 1 ] & REPORT_SEGMENT_DATA_FLAG ) )
nRetries = 0;
else
nRetries++;
-
+
if ( nRet > 0 )
{
int nPacketLength = WriteSegmentToSteamControllerPacketAssembler( &assembler,
- uSegmentBuffer,
- nRet );
+ uSegmentBuffer + ucDataStartOffset,
+ nRet - ucDataStartOffset );
if ( nPacketLength > 0 && nPacketLength < 65 )
{
@@ -424,7 +435,8 @@ static bool ResetSteamController( SDL_hid_device *dev, bool bSuppressErrorSpew,
{
// Firmware quirk: Set Feature and Get Feature requests always require a 65-byte buffer.
unsigned char buf[65];
- int res = -1, i;
+ unsigned int i;
+ int res = -1;
int nSettings = 0;
int nAttributesLength;
FeatureReportMsg *msg;
@@ -803,8 +815,8 @@ static void FormatStatePacketUntilGyro( SteamControllerStateInternal_t *pState,
pState->sRightPadX = clamp(nRightPadX + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
pState->sRightPadY = clamp(nRightPadY + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
- pState->sTriggerL = (unsigned short)RemapValClamped( (pStatePacket->ButtonTriggerData.Triggers.nLeft << 7) | pStatePacket->ButtonTriggerData.Triggers.nLeft, 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
- pState->sTriggerR = (unsigned short)RemapValClamped( (pStatePacket->ButtonTriggerData.Triggers.nRight << 7) | pStatePacket->ButtonTriggerData.Triggers.nRight, 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
+ pState->sTriggerL = (unsigned short)RemapValClamped( (float)((pStatePacket->ButtonTriggerData.Triggers.nLeft << 7) | pStatePacket->ButtonTriggerData.Triggers.nLeft), 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
+ pState->sTriggerR = (unsigned short)RemapValClamped( (float)((pStatePacket->ButtonTriggerData.Triggers.nRight << 7) | pStatePacket->ButtonTriggerData.Triggers.nRight), 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
}
@@ -827,8 +839,8 @@ static bool UpdateBLESteamControllerState( const uint8_t *pData, int nDataSize,
if ( ucOptionDataMask & k_EBLEButtonChunk2 )
{
// The middle 2 bytes of the button bits over the wire are triggers when over the wire and non-SC buttons in the internal controller state packet
- pState->sTriggerL = (unsigned short)RemapValClamped( ( pData[ 0 ] << 7 ) | pData[ 0 ], 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
- pState->sTrigge
(Patch may be truncated, please check the link at the top of this post.)