summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/video/raspberry
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/video/raspberry
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/video/raspberry')
-rw-r--r--contrib/SDL-3.2.8/src/video/raspberry/SDL_rpievents.c43
-rw-r--r--contrib/SDL-3.2.8/src/video/raspberry/SDL_rpievents_c.h29
-rw-r--r--contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.c314
-rw-r--r--contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.h40
-rw-r--r--contrib/SDL-3.2.8/src/video/raspberry/SDL_rpiopengles.c65
-rw-r--r--contrib/SDL-3.2.8/src/video/raspberry/SDL_rpiopengles.h47
-rw-r--r--contrib/SDL-3.2.8/src/video/raspberry/SDL_rpivideo.c376
-rw-r--r--contrib/SDL-3.2.8/src/video/raspberry/SDL_rpivideo.h89
8 files changed, 1003 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpievents.c b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpievents.c
new file mode 100644
index 0000000..bb4f49d
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpievents.c
@@ -0,0 +1,43 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22#include "SDL_internal.h"
23
24#ifdef SDL_VIDEO_DRIVER_RPI
25
26#include "../../events/SDL_events_c.h"
27#include "../../events/SDL_keyboard_c.h"
28#include "../SDL_sysvideo.h"
29#include "SDL_rpivideo.h"
30#include "SDL_rpievents_c.h"
31
32#ifdef SDL_INPUT_LINUXEV
33#include "../../core/linux/SDL_evdev.h"
34#endif
35
36void RPI_PumpEvents(SDL_VideoDevice *_this)
37{
38#ifdef SDL_INPUT_LINUXEV
39 SDL_EVDEV_Poll();
40#endif
41}
42
43#endif // SDL_VIDEO_DRIVER_RPI
diff --git a/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpievents_c.h b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpievents_c.h
new file mode 100644
index 0000000..6aceae6
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpievents_c.h
@@ -0,0 +1,29 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22#ifndef SDL_rpievents_c_h_
23#define SDL_rpievents_c_h_
24
25#include "SDL_rpivideo.h"
26
27void RPI_PumpEvents(SDL_VideoDevice *_this);
28
29#endif // SDL_rpievents_c_h_
diff --git a/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.c b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.c
new file mode 100644
index 0000000..925b734
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.c
@@ -0,0 +1,314 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#ifdef SDL_VIDEO_DRIVER_RPI
24
25#include "SDL_rpivideo.h"
26#include "SDL_rpimouse.h"
27
28#include "../SDL_sysvideo.h"
29#include "../../events/SDL_mouse_c.h"
30#include "../../events/default_cursor.h"
31
32// Copied from vc_vchi_dispmanx.h which is bugged and tries to include a non existing file
33// Attributes changes flag mask
34#define ELEMENT_CHANGE_LAYER (1 << 0)
35#define ELEMENT_CHANGE_OPACITY (1 << 1)
36#define ELEMENT_CHANGE_DEST_RECT (1 << 2)
37#define ELEMENT_CHANGE_SRC_RECT (1 << 3)
38#define ELEMENT_CHANGE_MASK_RESOURCE (1 << 4)
39#define ELEMENT_CHANGE_TRANSFORM (1 << 5)
40// End copied from vc_vchi_dispmanx.h
41
42static SDL_Cursor *RPI_CreateDefaultCursor(void);
43static SDL_Cursor *RPI_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y);
44static bool RPI_ShowCursor(SDL_Cursor *cursor);
45static bool RPI_MoveCursor(SDL_Cursor *cursor);
46static void RPI_FreeCursor(SDL_Cursor *cursor);
47
48static SDL_Cursor *global_cursor;
49
50static SDL_Cursor *RPI_CreateDefaultCursor(void)
51{
52 return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
53}
54
55// Create a cursor from a surface
56static SDL_Cursor *RPI_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
57{
58 int rc;
59 SDL_CursorData *curdata;
60 SDL_Cursor *cursor;
61 VC_RECT_T dst_rect;
62 Uint32 dummy;
63
64 SDL_assert(surface->format == SDL_PIXELFORMAT_ARGB8888);
65 SDL_assert(surface->pitch == surface->w * 4);
66
67 cursor = (SDL_Cursor *)SDL_calloc(1, sizeof(*cursor));
68 if (!cursor) {
69 return NULL;
70 }
71 curdata = (SDL_CursorData *)SDL_calloc(1, sizeof(*curdata));
72 if (!curdata) {
73 SDL_free(cursor);
74 return NULL;
75 }
76
77 curdata->hot_x = hot_x;
78 curdata->hot_y = hot_y;
79 curdata->w = surface->w;
80 curdata->h = surface->h;
81
82 // This usage is inspired by Wayland/Weston RPI code, how they figured this out is anyone's guess
83 curdata->resource = vc_dispmanx_resource_create(VC_IMAGE_ARGB8888, surface->w | (surface->pitch << 16), surface->h | (surface->h << 16), &dummy);
84 SDL_assert(curdata->resource);
85 vc_dispmanx_rect_set(&dst_rect, 0, 0, curdata->w, curdata->h);
86 /* A note from Weston:
87 * vc_dispmanx_resource_write_data() ignores ifmt,
88 * rect.x, rect.width, and uses stride only for computing
89 * the size of the transfer as rect.height * stride.
90 * Therefore we can only write rows starting at x=0.
91 */
92 rc = vc_dispmanx_resource_write_data(curdata->resource, VC_IMAGE_ARGB8888, surface->pitch, surface->pixels, &dst_rect);
93 SDL_assert(rc == DISPMANX_SUCCESS);
94
95 cursor->internal = curdata;
96
97 return cursor;
98}
99
100// Show the specified cursor, or hide if cursor is NULL
101static bool RPI_ShowCursor(SDL_Cursor *cursor)
102{
103 int rc;
104 DISPMANX_UPDATE_HANDLE_T update;
105 SDL_CursorData *curdata;
106 VC_RECT_T src_rect, dst_rect;
107 SDL_Mouse *mouse = SDL_GetMouse();
108 SDL_DisplayData *data;
109 VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE /* flags */, 255 /*opacity 0->255*/, 0 /* mask */ };
110 uint32_t layer = SDL_RPI_MOUSELAYER;
111 const char *hint;
112
113 if (cursor != global_cursor) {
114 if (global_cursor) {
115 curdata = global_cursor->internal;
116 if (curdata && curdata->element > DISPMANX_NO_HANDLE) {
117 update = vc_dispmanx_update_start(0);
118 SDL_assert(update);
119 rc = vc_dispmanx_element_remove(update, curdata->element);
120 SDL_assert(rc == DISPMANX_SUCCESS);
121 rc = vc_dispmanx_update_submit_sync(update);
122 SDL_assert(rc == DISPMANX_SUCCESS);
123 curdata->element = DISPMANX_NO_HANDLE;
124 }
125 }
126 global_cursor = cursor;
127 }
128
129 if (!cursor) {
130 return true;
131 }
132
133 curdata = cursor->internal;
134 if (!curdata) {
135 return false;
136 }
137
138 if (!mouse->focus) {
139 return false;
140 }
141
142 data = SDL_GetDisplayDriverDataForWindow(mouse->focus);
143 if (!data) {
144 return false;
145 }
146
147 if (curdata->element == DISPMANX_NO_HANDLE) {
148 vc_dispmanx_rect_set(&src_rect, 0, 0, curdata->w << 16, curdata->h << 16);
149 vc_dispmanx_rect_set(&dst_rect, mouse->x - curdata->hot_x, mouse->y - curdata->hot_y, curdata->w, curdata->h);
150
151 update = vc_dispmanx_update_start(0);
152 SDL_assert(update);
153
154 hint = SDL_GetHint(SDL_HINT_RPI_VIDEO_LAYER);
155 if (hint) {
156 layer = SDL_atoi(hint) + 1;
157 }
158
159 curdata->element = vc_dispmanx_element_add(update,
160 data->dispman_display,
161 layer,
162 &dst_rect,
163 curdata->resource,
164 &src_rect,
165 DISPMANX_PROTECTION_NONE,
166 &alpha,
167 DISPMANX_NO_HANDLE, // clamp
168 DISPMANX_NO_ROTATE);
169 SDL_assert(curdata->element > DISPMANX_NO_HANDLE);
170 rc = vc_dispmanx_update_submit_sync(update);
171 SDL_assert(rc == DISPMANX_SUCCESS);
172 }
173
174 return true;
175}
176
177// Free a window manager cursor
178static void RPI_FreeCursor(SDL_Cursor *cursor)
179{
180 int rc;
181 DISPMANX_UPDATE_HANDLE_T update;
182 SDL_CursorData *curdata;
183
184 if (cursor) {
185 curdata = cursor->internal;
186
187 if (curdata) {
188 if (curdata->element != DISPMANX_NO_HANDLE) {
189 update = vc_dispmanx_update_start(0);
190 SDL_assert(update);
191 rc = vc_dispmanx_element_remove(update, curdata->element);
192 SDL_assert(rc == DISPMANX_SUCCESS);
193 rc = vc_dispmanx_update_submit_sync(update);
194 SDL_assert(rc == DISPMANX_SUCCESS);
195 }
196
197 if (curdata->resource != DISPMANX_NO_HANDLE) {
198 rc = vc_dispmanx_resource_delete(curdata->resource);
199 SDL_assert(rc == DISPMANX_SUCCESS);
200 }
201
202 SDL_free(cursor->internal);
203 }
204 SDL_free(cursor);
205 if (cursor == global_cursor) {
206 global_cursor = NULL;
207 }
208 }
209}
210
211static bool RPI_WarpMouseGlobalGraphically(float x, float y)
212{
213 int rc;
214 SDL_CursorData *curdata;
215 DISPMANX_UPDATE_HANDLE_T update;
216 VC_RECT_T dst_rect;
217 VC_RECT_T src_rect;
218 SDL_Mouse *mouse = SDL_GetMouse();
219
220 if (!mouse || !mouse->cur_cursor || !mouse->cur_cursor->internal) {
221 return true;
222 }
223
224 curdata = mouse->cur_cursor->internal;
225 if (curdata->element == DISPMANX_NO_HANDLE) {
226 return true;
227 }
228
229 update = vc_dispmanx_update_start(0);
230 if (!update) {
231 return true;
232 }
233
234 src_rect.x = 0;
235 src_rect.y = 0;
236 src_rect.width = curdata->w << 16;
237 src_rect.height = curdata->h << 16;
238 dst_rect.x = (int)x - curdata->hot_x;
239 dst_rect.y = (int)y - curdata->hot_y;
240 dst_rect.width = curdata->w;
241 dst_rect.height = curdata->h;
242
243 rc = vc_dispmanx_element_change_attributes(
244 update,
245 curdata->element,
246 0,
247 0,
248 0,
249 &dst_rect,
250 &src_rect,
251 DISPMANX_NO_HANDLE,
252 DISPMANX_NO_ROTATE);
253 if (rc != DISPMANX_SUCCESS) {
254 return SDL_SetError("vc_dispmanx_element_change_attributes() failed");
255 }
256
257 // Submit asynchronously, otherwise the performance suffers a lot
258 rc = vc_dispmanx_update_submit(update, 0, NULL);
259 if (rc != DISPMANX_SUCCESS) {
260 return SDL_SetError("vc_dispmanx_update_submit() failed");
261 }
262 return true;
263}
264
265static bool RPI_WarpMouseGlobal(float x, float y)
266{
267 SDL_Mouse *mouse = SDL_GetMouse();
268
269 if (!mouse || !mouse->cur_cursor || !mouse->cur_cursor->internal) {
270 return true;
271 }
272
273 // Update internal mouse position.
274 SDL_SendMouseMotion(0, mouse->focus, SDL_GLOBAL_MOUSE_ID, false, x, y);
275
276 return RPI_WarpMouseGlobalGraphically(x, y);
277}
278
279static bool RPI_WarpMouse(SDL_Window *window, float x, float y)
280{
281 return RPI_WarpMouseGlobal(x, y);
282}
283
284void RPI_InitMouse(SDL_VideoDevice *_this)
285{
286 /* FIXME: Using UDEV it should be possible to scan all mice
287 * but there's no point in doing so as there's no multimice support...yet!
288 */
289 SDL_Mouse *mouse = SDL_GetMouse();
290
291 mouse->CreateCursor = RPI_CreateCursor;
292 mouse->ShowCursor = RPI_ShowCursor;
293 mouse->MoveCursor = RPI_MoveCursor;
294 mouse->FreeCursor = RPI_FreeCursor;
295 mouse->WarpMouse = RPI_WarpMouse;
296 mouse->WarpMouseGlobal = RPI_WarpMouseGlobal;
297
298 SDL_SetDefaultCursor(RPI_CreateDefaultCursor());
299}
300
301void RPI_QuitMouse(SDL_VideoDevice *_this)
302{
303}
304
305// This is called when a mouse motion event occurs
306static bool RPI_MoveCursor(SDL_Cursor *cursor)
307{
308 SDL_Mouse *mouse = SDL_GetMouse();
309 /* We must NOT call SDL_SendMouseMotion() on the next call or we will enter recursivity,
310 * so we create a version of WarpMouseGlobal without it. */
311 return RPI_WarpMouseGlobalGraphically(mouse->x, mouse->y);
312}
313
314#endif // SDL_VIDEO_DRIVER_RPI
diff --git a/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.h b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.h
new file mode 100644
index 0000000..4b5b95c
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.h
@@ -0,0 +1,40 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22#ifndef SDL_RPI_mouse_h_
23#define SDL_RPI_mouse_h_
24
25#include "../SDL_sysvideo.h"
26
27struct SDL_CursorData
28{
29 DISPMANX_RESOURCE_HANDLE_T resource;
30 DISPMANX_ELEMENT_HANDLE_T element;
31 int hot_x, hot_y;
32 int w, h;
33};
34
35#define SDL_RPI_CURSORDATA(curs) RPI_CursorData *curdata = (RPI_CursorData *)((curs) ? (curs)->internal : NULL)
36
37extern void RPI_InitMouse(SDL_VideoDevice *_this);
38extern void RPI_QuitMouse(SDL_VideoDevice *_this);
39
40#endif // SDL_RPI_mouse_h_
diff --git a/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpiopengles.c b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpiopengles.c
new file mode 100644
index 0000000..0561d8b
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpiopengles.c
@@ -0,0 +1,65 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#if defined(SDL_VIDEO_DRIVER_RPI) && defined(SDL_VIDEO_OPENGL_EGL)
24
25#include "SDL_rpivideo.h"
26#include "SDL_rpiopengles.h"
27
28// EGL implementation of SDL OpenGL support
29
30void RPI_GLES_DefaultProfileConfig(SDL_VideoDevice *_this, int *mask, int *major, int *minor)
31{
32 *mask = SDL_GL_CONTEXT_PROFILE_ES;
33 *major = 2;
34 *minor = 0;
35}
36
37bool RPI_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path)
38{
39 return SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY, 0);
40}
41
42bool RPI_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
43{
44 SDL_WindowData *wdata = window->internal;
45
46 if (!(_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, wdata->egl_surface))) {
47 SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "eglSwapBuffers failed.");
48 return true;
49 }
50
51 /* Wait immediately for vsync (as if we only had two buffers), for low input-lag scenarios.
52 * Run your SDL program with "SDL_RPI_DOUBLE_BUFFER=1 <program_name>" to enable this. */
53 if (wdata->double_buffer) {
54 SDL_LockMutex(wdata->vsync_cond_mutex);
55 SDL_WaitCondition(wdata->vsync_cond, wdata->vsync_cond_mutex);
56 SDL_UnlockMutex(wdata->vsync_cond_mutex);
57 }
58
59 return true;
60}
61
62SDL_EGL_CreateContext_impl(RPI)
63SDL_EGL_MakeCurrent_impl(RPI)
64
65#endif // SDL_VIDEO_DRIVER_RPI && SDL_VIDEO_OPENGL_EGL
diff --git a/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpiopengles.h b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpiopengles.h
new file mode 100644
index 0000000..f6f0396
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpiopengles.h
@@ -0,0 +1,47 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#ifndef SDL_rpiopengles_h_
24#define SDL_rpiopengles_h_
25
26#if defined(SDL_VIDEO_DRIVER_RPI) && defined(SDL_VIDEO_OPENGL_EGL)
27
28#include "../SDL_sysvideo.h"
29#include "../SDL_egl_c.h"
30
31// OpenGLES functions
32#define RPI_GLES_GetAttribute SDL_EGL_GetAttribute
33#define RPI_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal
34#define RPI_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
35#define RPI_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
36#define RPI_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
37#define RPI_GLES_DestroyContext SDL_EGL_DestroyContext
38
39extern bool RPI_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
40extern SDL_GLContext RPI_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
41extern bool RPI_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
42extern bool RPI_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
43extern void RPI_GLES_DefaultProfileConfig(SDL_VideoDevice *_this, int *mask, int *major, int *minor);
44
45#endif // SDL_VIDEO_DRIVER_RPI && SDL_VIDEO_OPENGL_EGL
46
47#endif // SDL_rpiopengles_h_
diff --git a/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpivideo.c b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpivideo.c
new file mode 100644
index 0000000..d313f9e
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpivideo.c
@@ -0,0 +1,376 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22#include "SDL_internal.h"
23
24#ifdef SDL_VIDEO_DRIVER_RPI
25
26/* References
27 * http://elinux.org/RPi_VideoCore_APIs
28 * https://github.com/raspberrypi/firmware/blob/master/opt/vc/src/hello_pi/hello_triangle/triangle.c
29 * http://cgit.freedesktop.org/wayland/weston/tree/src/rpi-renderer.c
30 * http://cgit.freedesktop.org/wayland/weston/tree/src/compositor-rpi.c
31 */
32
33// SDL internals
34#include "../SDL_sysvideo.h"
35#include "../../events/SDL_mouse_c.h"
36#include "../../events/SDL_keyboard_c.h"
37
38#ifdef SDL_INPUT_LINUXEV
39#include "../../core/linux/SDL_evdev.h"
40#endif
41
42// RPI declarations
43#include "SDL_rpivideo.h"
44#include "SDL_rpievents_c.h"
45#include "SDL_rpiopengles.h"
46#include "SDL_rpimouse.h"
47
48static void RPI_Destroy(SDL_VideoDevice *device)
49{
50 SDL_free(device->internal);
51 SDL_free(device);
52}
53
54static void RPI_GetRefreshRate(int *numerator, int *denominator)
55{
56 TV_DISPLAY_STATE_T tvstate;
57 if (vc_tv_get_display_state(&tvstate) == 0) {
58 // The width/height parameters are in the same position in the union
59 // for HDMI and SDTV
60 HDMI_PROPERTY_PARAM_T property;
61 property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
62 vc_tv_hdmi_get_property(&property);
63 if (property.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC) {
64 *numerator = tvstate.display.hdmi.frame_rate * 1000;
65 *denominator = 1001;
66 } else {
67 *numerator = tvstate.display.hdmi.frame_rate;
68 *denominator = 1;
69 }
70 return;
71 }
72
73 // Failed to get display state, default to 60
74 *numerator = 60;
75 *denominator = 1;
76}
77
78static SDL_VideoDevice *RPI_Create(void)
79{
80 SDL_VideoDevice *device;
81 SDL_VideoData *phdata;
82
83 // Initialize SDL_VideoDevice structure
84 device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
85 if (!device) {
86 return NULL;
87 }
88
89 // Initialize internal data
90 phdata = (SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData));
91 if (!phdata) {
92 SDL_free(device);
93 return NULL;
94 }
95
96 device->internal = phdata;
97
98 // Setup amount of available displays
99 device->num_displays = 0;
100
101 // Set device free function
102 device->free = RPI_Destroy;
103
104 // Setup all functions which we can handle
105 device->VideoInit = RPI_VideoInit;
106 device->VideoQuit = RPI_VideoQuit;
107 device->CreateSDLWindow = RPI_CreateWindow;
108 device->SetWindowTitle = RPI_SetWindowTitle;
109 device->SetWindowPosition = RPI_SetWindowPosition;
110 device->SetWindowSize = RPI_SetWindowSize;
111 device->ShowWindow = RPI_ShowWindow;
112 device->HideWindow = RPI_HideWindow;
113 device->RaiseWindow = RPI_RaiseWindow;
114 device->MaximizeWindow = RPI_MaximizeWindow;
115 device->MinimizeWindow = RPI_MinimizeWindow;
116 device->RestoreWindow = RPI_RestoreWindow;
117 device->DestroyWindow = RPI_DestroyWindow;
118 device->GL_LoadLibrary = RPI_GLES_LoadLibrary;
119 device->GL_GetProcAddress = RPI_GLES_GetProcAddress;
120 device->GL_UnloadLibrary = RPI_GLES_UnloadLibrary;
121 device->GL_CreateContext = RPI_GLES_CreateContext;
122 device->GL_MakeCurrent = RPI_GLES_MakeCurrent;
123 device->GL_SetSwapInterval = RPI_GLES_SetSwapInterval;
124 device->GL_GetSwapInterval = RPI_GLES_GetSwapInterval;
125 device->GL_SwapWindow = RPI_GLES_SwapWindow;
126 device->GL_DestroyContext = RPI_GLES_DestroyContext;
127 device->GL_DefaultProfileConfig = RPI_GLES_DefaultProfileConfig;
128
129 device->PumpEvents = RPI_PumpEvents;
130
131 return device;
132}
133
134VideoBootStrap RPI_bootstrap = {
135 "rpi",
136 "RPI Video Driver",
137 RPI_Create,
138 NULL, // no ShowMessageBox implementation
139 false
140};
141
142/*****************************************************************************/
143// SDL Video and Display initialization/handling functions
144/*****************************************************************************/
145
146static void AddDispManXDisplay(const int display_id)
147{
148 DISPMANX_MODEINFO_T modeinfo;
149 DISPMANX_DISPLAY_HANDLE_T handle;
150 SDL_VideoDisplay display;
151 SDL_DisplayMode mode;
152 SDL_DisplayData *data;
153
154 handle = vc_dispmanx_display_open(display_id);
155 if (!handle) {
156 return; // this display isn't available
157 }
158
159 if (vc_dispmanx_display_get_info(handle, &modeinfo) < 0) {
160 vc_dispmanx_display_close(handle);
161 return;
162 }
163
164 // RPI_GetRefreshRate() doesn't distinguish between displays. I'm not sure the hardware distinguishes either
165 SDL_zero(mode);
166 mode.w = modeinfo.width;
167 mode.h = modeinfo.height;
168 RPI_GetRefreshRate(&mode.refresh_rate_numerator, &mode.refresh_rate_denominator);
169
170 // 32 bpp for default
171 mode.format = SDL_PIXELFORMAT_ABGR8888;
172
173 SDL_zero(display);
174 display.desktop_mode = mode;
175
176 // Allocate display internal data
177 data = (SDL_DisplayData *)SDL_calloc(1, sizeof(SDL_DisplayData));
178 if (!data) {
179 vc_dispmanx_display_close(handle);
180 return; // oh well
181 }
182
183 data->dispman_display = handle;
184
185 display.internal = data;
186
187 SDL_AddVideoDisplay(&display, false);
188}
189
190bool RPI_VideoInit(SDL_VideoDevice *_this)
191{
192 // Initialize BCM Host
193 bcm_host_init();
194
195 AddDispManXDisplay(DISPMANX_ID_MAIN_LCD); // your default display
196 AddDispManXDisplay(DISPMANX_ID_FORCE_OTHER); // an "other" display...maybe DSI-connected screen while HDMI is your main
197
198#ifdef SDL_INPUT_LINUXEV
199 if (!SDL_EVDEV_Init()) {
200 return false;
201 }
202#endif
203
204 RPI_InitMouse(_this);
205
206 return true;
207}
208
209void RPI_VideoQuit(SDL_VideoDevice *_this)
210{
211#ifdef SDL_INPUT_LINUXEV
212 SDL_EVDEV_Quit();
213#endif
214}
215
216static void RPI_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data)
217{
218 SDL_WindowData *wdata = (SDL_WindowData *)data;
219
220 SDL_LockMutex(wdata->vsync_cond_mutex);
221 SDL_SignalCondition(wdata->vsync_cond);
222 SDL_UnlockMutex(wdata->vsync_cond_mutex);
223}
224
225bool RPI_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props)
226{
227 SDL_WindowData *wdata;
228 SDL_VideoDisplay *display;
229 SDL_DisplayData *displaydata;
230 VC_RECT_T dst_rect;
231 VC_RECT_T src_rect;
232 VC_DISPMANX_ALPHA_T dispman_alpha;
233 DISPMANX_UPDATE_HANDLE_T dispman_update;
234 uint32_t layer = SDL_RPI_VIDEOLAYER;
235 const char *env;
236
237 // Disable alpha, otherwise the app looks composed with whatever dispman is showing (X11, console,etc)
238 dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
239 dispman_alpha.opacity = 0xFF;
240 dispman_alpha.mask = 0;
241
242 // Allocate window internal data
243 wdata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData));
244 if (!wdata) {
245 return false;
246 }
247 display = SDL_GetVideoDisplayForWindow(window);
248 displaydata = display->internal;
249
250 // Windows have one size for now
251 window->w = display->desktop_mode.w;
252 window->h = display->desktop_mode.h;
253
254 // OpenGL ES is the law here, buddy
255 window->flags |= SDL_WINDOW_OPENGL;
256
257 // Create a dispman element and associate a window to it
258 dst_rect.x = 0;
259 dst_rect.y = 0;
260 dst_rect.width = window->w;
261 dst_rect.height = window->h;
262
263 src_rect.x = 0;
264 src_rect.y = 0;
265 src_rect.width = window->w << 16;
266 src_rect.height = window->h << 16;
267
268 env = SDL_GetHint(SDL_HINT_RPI_VIDEO_LAYER);
269 if (env) {
270 layer = SDL_atoi(env);
271 }
272
273 dispman_update = vc_dispmanx_update_start(0);
274 wdata->dispman_window.element = vc_dispmanx_element_add(dispman_update,
275 displaydata->dispman_display,
276 layer /* layer */,
277 &dst_rect,
278 0 /*src*/,
279 &src_rect,
280 DISPMANX_PROTECTION_NONE,
281 &dispman_alpha /*alpha*/,
282 0 /*clamp*/,
283 0 /*transform*/);
284 wdata->dispman_window.width = window->w;
285 wdata->dispman_window.height = window->h;
286 vc_dispmanx_update_submit_sync(dispman_update);
287
288 if (!_this->egl_data) {
289 if (!SDL_GL_LoadLibrary(NULL)) {
290 return false;
291 }
292 }
293 wdata->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)&wdata->dispman_window);
294
295 if (wdata->egl_surface == EGL_NO_SURFACE) {
296 return SDL_SetError("Could not create GLES window surface");
297 }
298
299 // Start generating vsync callbacks if necessary
300 wdata->double_buffer = false;
301 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, false)) {
302 wdata->vsync_cond = SDL_CreateCondition();
303 wdata->vsync_cond_mutex = SDL_CreateMutex();
304 wdata->double_buffer = true;
305 vc_dispmanx_vsync_callback(displaydata->dispman_display, RPI_vsync_callback, (void *)wdata);
306 }
307
308 // Setup driver data for this window
309 window->internal = wdata;
310
311 // One window, it always has focus
312 SDL_SetMouseFocus(window);
313 SDL_SetKeyboardFocus(window);
314
315 // Window has been successfully created
316 return true;
317}
318
319void RPI_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
320{
321 SDL_WindowData *data = window->internal;
322 SDL_DisplayData *displaydata = SDL_GetDisplayDriverDataForWindow(window);
323
324 if (data) {
325 if (data->double_buffer) {
326 // Wait for vsync, and then stop vsync callbacks and destroy related stuff, if needed
327 SDL_LockMutex(data->vsync_cond_mutex);
328 SDL_WaitCondition(data->vsync_cond, data->vsync_cond_mutex);
329 SDL_UnlockMutex(data->vsync_cond_mutex);
330
331 vc_dispmanx_vsync_callback(displaydata->dispman_display, NULL, NULL);
332
333 SDL_DestroyCondition(data->vsync_cond);
334 SDL_DestroyMutex(data->vsync_cond_mutex);
335 }
336
337#ifdef SDL_VIDEO_OPENGL_EGL
338 if (data->egl_surface != EGL_NO_SURFACE) {
339 SDL_EGL_DestroySurface(_this, data->egl_surface);
340 }
341#endif
342 SDL_free(data);
343 window->internal = NULL;
344 }
345}
346
347void RPI_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window)
348{
349}
350bool RPI_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window)
351{
352 return SDL_Unsupported();
353}
354void RPI_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window)
355{
356}
357void RPI_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
358{
359}
360void RPI_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
361{
362}
363void RPI_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window)
364{
365}
366void RPI_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
367{
368}
369void RPI_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
370{
371}
372void RPI_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window)
373{
374}
375
376#endif // SDL_VIDEO_DRIVER_RPI
diff --git a/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpivideo.h b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpivideo.h
new file mode 100644
index 0000000..c154655
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpivideo.h
@@ -0,0 +1,89 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22#ifndef SDL_rpivideo_h
23#define SDL_rpivideo_h
24
25#include "SDL_internal.h"
26#include "../SDL_sysvideo.h"
27
28#include <bcm_host.h>
29#include <SDL3/SDL_egl.h>
30
31struct SDL_VideoData
32{
33 uint32_t egl_refcount; // OpenGL ES reference count
34};
35
36struct SDL_DisplayData
37{
38 DISPMANX_DISPLAY_HANDLE_T dispman_display;
39};
40
41struct SDL_WindowData
42{
43 EGL_DISPMANX_WINDOW_T dispman_window;
44#ifdef SDL_VIDEO_OPENGL_EGL
45 EGLSurface egl_surface;
46#endif
47
48 // Vsync callback cond and mutex
49 SDL_Condition *vsync_cond;
50 SDL_Mutex *vsync_cond_mutex;
51 bool double_buffer;
52};
53
54#define SDL_RPI_VIDEOLAYER 10000 // High enough so to occlude everything
55#define SDL_RPI_MOUSELAYER SDL_RPI_VIDEOLAYER + 1
56
57/****************************************************************************/
58// SDL_VideoDevice functions declaration
59/****************************************************************************/
60
61// Display and window functions
62extern bool RPI_VideoInit(SDL_VideoDevice *_this);
63extern void RPI_VideoQuit(SDL_VideoDevice *_this);
64extern bool RPI_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
65extern bool RPI_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
66extern bool RPI_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props);
67extern void RPI_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
68extern bool RPI_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window);
69extern void RPI_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window);
70extern void RPI_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window);
71extern void RPI_HideWindow(SDL_VideoDevice *_this, SDL_Window *window);
72extern void RPI_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window);
73extern void RPI_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
74extern void RPI_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
75extern void RPI_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window);
76extern void RPI_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
77
78// OpenGL/OpenGL ES functions
79extern bool RPI_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
80extern SDL_FunctionPointer RPI_GLES_GetProcAddress(SDL_VideoDevice *_this, const char *proc);
81extern void RPI_GLES_UnloadLibrary(SDL_VideoDevice *_this);
82extern SDL_GLContext RPI_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
83extern bool RPI_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
84extern bool RPI_GLES_SetSwapInterval(SDL_VideoDevice *_this, int interval);
85extern bool RPI_GLES_GetSwapInterval(SDL_VideoDevice *_this);
86extern bool RPI_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
87extern bool RPI_GLES_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context);
88
89#endif // SDL_rpivideo_h