From 5a079a2d114f96d4847d1ee305d5b7c16eeec50e Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 27 Dec 2025 12:03:39 -0800 Subject: Initial commit --- .../SDL-3.2.8/src/video/raspberry/SDL_rpievents.c | 43 +++ .../src/video/raspberry/SDL_rpievents_c.h | 29 ++ .../SDL-3.2.8/src/video/raspberry/SDL_rpimouse.c | 314 +++++++++++++++++ .../SDL-3.2.8/src/video/raspberry/SDL_rpimouse.h | 40 +++ .../src/video/raspberry/SDL_rpiopengles.c | 65 ++++ .../src/video/raspberry/SDL_rpiopengles.h | 47 +++ .../SDL-3.2.8/src/video/raspberry/SDL_rpivideo.c | 376 +++++++++++++++++++++ .../SDL-3.2.8/src/video/raspberry/SDL_rpivideo.h | 89 +++++ 8 files changed, 1003 insertions(+) create mode 100644 contrib/SDL-3.2.8/src/video/raspberry/SDL_rpievents.c create mode 100644 contrib/SDL-3.2.8/src/video/raspberry/SDL_rpievents_c.h create mode 100644 contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.c create mode 100644 contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.h create mode 100644 contrib/SDL-3.2.8/src/video/raspberry/SDL_rpiopengles.c create mode 100644 contrib/SDL-3.2.8/src/video/raspberry/SDL_rpiopengles.h create mode 100644 contrib/SDL-3.2.8/src/video/raspberry/SDL_rpivideo.c create mode 100644 contrib/SDL-3.2.8/src/video/raspberry/SDL_rpivideo.h (limited to 'contrib/SDL-3.2.8/src/video/raspberry') 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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_DRIVER_RPI + +#include "../../events/SDL_events_c.h" +#include "../../events/SDL_keyboard_c.h" +#include "../SDL_sysvideo.h" +#include "SDL_rpivideo.h" +#include "SDL_rpievents_c.h" + +#ifdef SDL_INPUT_LINUXEV +#include "../../core/linux/SDL_evdev.h" +#endif + +void RPI_PumpEvents(SDL_VideoDevice *_this) +{ +#ifdef SDL_INPUT_LINUXEV + SDL_EVDEV_Poll(); +#endif +} + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_rpievents_c_h_ +#define SDL_rpievents_c_h_ + +#include "SDL_rpivideo.h" + +void RPI_PumpEvents(SDL_VideoDevice *_this); + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_DRIVER_RPI + +#include "SDL_rpivideo.h" +#include "SDL_rpimouse.h" + +#include "../SDL_sysvideo.h" +#include "../../events/SDL_mouse_c.h" +#include "../../events/default_cursor.h" + +// Copied from vc_vchi_dispmanx.h which is bugged and tries to include a non existing file +// Attributes changes flag mask +#define ELEMENT_CHANGE_LAYER (1 << 0) +#define ELEMENT_CHANGE_OPACITY (1 << 1) +#define ELEMENT_CHANGE_DEST_RECT (1 << 2) +#define ELEMENT_CHANGE_SRC_RECT (1 << 3) +#define ELEMENT_CHANGE_MASK_RESOURCE (1 << 4) +#define ELEMENT_CHANGE_TRANSFORM (1 << 5) +// End copied from vc_vchi_dispmanx.h + +static SDL_Cursor *RPI_CreateDefaultCursor(void); +static SDL_Cursor *RPI_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y); +static bool RPI_ShowCursor(SDL_Cursor *cursor); +static bool RPI_MoveCursor(SDL_Cursor *cursor); +static void RPI_FreeCursor(SDL_Cursor *cursor); + +static SDL_Cursor *global_cursor; + +static SDL_Cursor *RPI_CreateDefaultCursor(void) +{ + return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY); +} + +// Create a cursor from a surface +static SDL_Cursor *RPI_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y) +{ + int rc; + SDL_CursorData *curdata; + SDL_Cursor *cursor; + VC_RECT_T dst_rect; + Uint32 dummy; + + SDL_assert(surface->format == SDL_PIXELFORMAT_ARGB8888); + SDL_assert(surface->pitch == surface->w * 4); + + cursor = (SDL_Cursor *)SDL_calloc(1, sizeof(*cursor)); + if (!cursor) { + return NULL; + } + curdata = (SDL_CursorData *)SDL_calloc(1, sizeof(*curdata)); + if (!curdata) { + SDL_free(cursor); + return NULL; + } + + curdata->hot_x = hot_x; + curdata->hot_y = hot_y; + curdata->w = surface->w; + curdata->h = surface->h; + + // This usage is inspired by Wayland/Weston RPI code, how they figured this out is anyone's guess + curdata->resource = vc_dispmanx_resource_create(VC_IMAGE_ARGB8888, surface->w | (surface->pitch << 16), surface->h | (surface->h << 16), &dummy); + SDL_assert(curdata->resource); + vc_dispmanx_rect_set(&dst_rect, 0, 0, curdata->w, curdata->h); + /* A note from Weston: + * vc_dispmanx_resource_write_data() ignores ifmt, + * rect.x, rect.width, and uses stride only for computing + * the size of the transfer as rect.height * stride. + * Therefore we can only write rows starting at x=0. + */ + rc = vc_dispmanx_resource_write_data(curdata->resource, VC_IMAGE_ARGB8888, surface->pitch, surface->pixels, &dst_rect); + SDL_assert(rc == DISPMANX_SUCCESS); + + cursor->internal = curdata; + + return cursor; +} + +// Show the specified cursor, or hide if cursor is NULL +static bool RPI_ShowCursor(SDL_Cursor *cursor) +{ + int rc; + DISPMANX_UPDATE_HANDLE_T update; + SDL_CursorData *curdata; + VC_RECT_T src_rect, dst_rect; + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_DisplayData *data; + VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE /* flags */, 255 /*opacity 0->255*/, 0 /* mask */ }; + uint32_t layer = SDL_RPI_MOUSELAYER; + const char *hint; + + if (cursor != global_cursor) { + if (global_cursor) { + curdata = global_cursor->internal; + if (curdata && curdata->element > DISPMANX_NO_HANDLE) { + update = vc_dispmanx_update_start(0); + SDL_assert(update); + rc = vc_dispmanx_element_remove(update, curdata->element); + SDL_assert(rc == DISPMANX_SUCCESS); + rc = vc_dispmanx_update_submit_sync(update); + SDL_assert(rc == DISPMANX_SUCCESS); + curdata->element = DISPMANX_NO_HANDLE; + } + } + global_cursor = cursor; + } + + if (!cursor) { + return true; + } + + curdata = cursor->internal; + if (!curdata) { + return false; + } + + if (!mouse->focus) { + return false; + } + + data = SDL_GetDisplayDriverDataForWindow(mouse->focus); + if (!data) { + return false; + } + + if (curdata->element == DISPMANX_NO_HANDLE) { + vc_dispmanx_rect_set(&src_rect, 0, 0, curdata->w << 16, curdata->h << 16); + vc_dispmanx_rect_set(&dst_rect, mouse->x - curdata->hot_x, mouse->y - curdata->hot_y, curdata->w, curdata->h); + + update = vc_dispmanx_update_start(0); + SDL_assert(update); + + hint = SDL_GetHint(SDL_HINT_RPI_VIDEO_LAYER); + if (hint) { + layer = SDL_atoi(hint) + 1; + } + + curdata->element = vc_dispmanx_element_add(update, + data->dispman_display, + layer, + &dst_rect, + curdata->resource, + &src_rect, + DISPMANX_PROTECTION_NONE, + &alpha, + DISPMANX_NO_HANDLE, // clamp + DISPMANX_NO_ROTATE); + SDL_assert(curdata->element > DISPMANX_NO_HANDLE); + rc = vc_dispmanx_update_submit_sync(update); + SDL_assert(rc == DISPMANX_SUCCESS); + } + + return true; +} + +// Free a window manager cursor +static void RPI_FreeCursor(SDL_Cursor *cursor) +{ + int rc; + DISPMANX_UPDATE_HANDLE_T update; + SDL_CursorData *curdata; + + if (cursor) { + curdata = cursor->internal; + + if (curdata) { + if (curdata->element != DISPMANX_NO_HANDLE) { + update = vc_dispmanx_update_start(0); + SDL_assert(update); + rc = vc_dispmanx_element_remove(update, curdata->element); + SDL_assert(rc == DISPMANX_SUCCESS); + rc = vc_dispmanx_update_submit_sync(update); + SDL_assert(rc == DISPMANX_SUCCESS); + } + + if (curdata->resource != DISPMANX_NO_HANDLE) { + rc = vc_dispmanx_resource_delete(curdata->resource); + SDL_assert(rc == DISPMANX_SUCCESS); + } + + SDL_free(cursor->internal); + } + SDL_free(cursor); + if (cursor == global_cursor) { + global_cursor = NULL; + } + } +} + +static bool RPI_WarpMouseGlobalGraphically(float x, float y) +{ + int rc; + SDL_CursorData *curdata; + DISPMANX_UPDATE_HANDLE_T update; + VC_RECT_T dst_rect; + VC_RECT_T src_rect; + SDL_Mouse *mouse = SDL_GetMouse(); + + if (!mouse || !mouse->cur_cursor || !mouse->cur_cursor->internal) { + return true; + } + + curdata = mouse->cur_cursor->internal; + if (curdata->element == DISPMANX_NO_HANDLE) { + return true; + } + + update = vc_dispmanx_update_start(0); + if (!update) { + return true; + } + + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = curdata->w << 16; + src_rect.height = curdata->h << 16; + dst_rect.x = (int)x - curdata->hot_x; + dst_rect.y = (int)y - curdata->hot_y; + dst_rect.width = curdata->w; + dst_rect.height = curdata->h; + + rc = vc_dispmanx_element_change_attributes( + update, + curdata->element, + 0, + 0, + 0, + &dst_rect, + &src_rect, + DISPMANX_NO_HANDLE, + DISPMANX_NO_ROTATE); + if (rc != DISPMANX_SUCCESS) { + return SDL_SetError("vc_dispmanx_element_change_attributes() failed"); + } + + // Submit asynchronously, otherwise the performance suffers a lot + rc = vc_dispmanx_update_submit(update, 0, NULL); + if (rc != DISPMANX_SUCCESS) { + return SDL_SetError("vc_dispmanx_update_submit() failed"); + } + return true; +} + +static bool RPI_WarpMouseGlobal(float x, float y) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (!mouse || !mouse->cur_cursor || !mouse->cur_cursor->internal) { + return true; + } + + // Update internal mouse position. + SDL_SendMouseMotion(0, mouse->focus, SDL_GLOBAL_MOUSE_ID, false, x, y); + + return RPI_WarpMouseGlobalGraphically(x, y); +} + +static bool RPI_WarpMouse(SDL_Window *window, float x, float y) +{ + return RPI_WarpMouseGlobal(x, y); +} + +void RPI_InitMouse(SDL_VideoDevice *_this) +{ + /* FIXME: Using UDEV it should be possible to scan all mice + * but there's no point in doing so as there's no multimice support...yet! + */ + SDL_Mouse *mouse = SDL_GetMouse(); + + mouse->CreateCursor = RPI_CreateCursor; + mouse->ShowCursor = RPI_ShowCursor; + mouse->MoveCursor = RPI_MoveCursor; + mouse->FreeCursor = RPI_FreeCursor; + mouse->WarpMouse = RPI_WarpMouse; + mouse->WarpMouseGlobal = RPI_WarpMouseGlobal; + + SDL_SetDefaultCursor(RPI_CreateDefaultCursor()); +} + +void RPI_QuitMouse(SDL_VideoDevice *_this) +{ +} + +// This is called when a mouse motion event occurs +static bool RPI_MoveCursor(SDL_Cursor *cursor) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + /* We must NOT call SDL_SendMouseMotion() on the next call or we will enter recursivity, + * so we create a version of WarpMouseGlobal without it. */ + return RPI_WarpMouseGlobalGraphically(mouse->x, mouse->y); +} + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_RPI_mouse_h_ +#define SDL_RPI_mouse_h_ + +#include "../SDL_sysvideo.h" + +struct SDL_CursorData +{ + DISPMANX_RESOURCE_HANDLE_T resource; + DISPMANX_ELEMENT_HANDLE_T element; + int hot_x, hot_y; + int w, h; +}; + +#define SDL_RPI_CURSORDATA(curs) RPI_CursorData *curdata = (RPI_CursorData *)((curs) ? (curs)->internal : NULL) + +extern void RPI_InitMouse(SDL_VideoDevice *_this); +extern void RPI_QuitMouse(SDL_VideoDevice *_this); + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#if defined(SDL_VIDEO_DRIVER_RPI) && defined(SDL_VIDEO_OPENGL_EGL) + +#include "SDL_rpivideo.h" +#include "SDL_rpiopengles.h" + +// EGL implementation of SDL OpenGL support + +void RPI_GLES_DefaultProfileConfig(SDL_VideoDevice *_this, int *mask, int *major, int *minor) +{ + *mask = SDL_GL_CONTEXT_PROFILE_ES; + *major = 2; + *minor = 0; +} + +bool RPI_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path) +{ + return SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY, 0); +} + +bool RPI_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ + SDL_WindowData *wdata = window->internal; + + if (!(_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, wdata->egl_surface))) { + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "eglSwapBuffers failed."); + return true; + } + + /* Wait immediately for vsync (as if we only had two buffers), for low input-lag scenarios. + * Run your SDL program with "SDL_RPI_DOUBLE_BUFFER=1 " to enable this. */ + if (wdata->double_buffer) { + SDL_LockMutex(wdata->vsync_cond_mutex); + SDL_WaitCondition(wdata->vsync_cond, wdata->vsync_cond_mutex); + SDL_UnlockMutex(wdata->vsync_cond_mutex); + } + + return true; +} + +SDL_EGL_CreateContext_impl(RPI) +SDL_EGL_MakeCurrent_impl(RPI) + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef SDL_rpiopengles_h_ +#define SDL_rpiopengles_h_ + +#if defined(SDL_VIDEO_DRIVER_RPI) && defined(SDL_VIDEO_OPENGL_EGL) + +#include "../SDL_sysvideo.h" +#include "../SDL_egl_c.h" + +// OpenGLES functions +#define RPI_GLES_GetAttribute SDL_EGL_GetAttribute +#define RPI_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal +#define RPI_GLES_UnloadLibrary SDL_EGL_UnloadLibrary +#define RPI_GLES_SetSwapInterval SDL_EGL_SetSwapInterval +#define RPI_GLES_GetSwapInterval SDL_EGL_GetSwapInterval +#define RPI_GLES_DestroyContext SDL_EGL_DestroyContext + +extern bool RPI_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path); +extern SDL_GLContext RPI_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window); +extern bool RPI_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window); +extern bool RPI_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context); +extern void RPI_GLES_DefaultProfileConfig(SDL_VideoDevice *_this, int *mask, int *major, int *minor); + +#endif // SDL_VIDEO_DRIVER_RPI && SDL_VIDEO_OPENGL_EGL + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_DRIVER_RPI + +/* References + * http://elinux.org/RPi_VideoCore_APIs + * https://github.com/raspberrypi/firmware/blob/master/opt/vc/src/hello_pi/hello_triangle/triangle.c + * http://cgit.freedesktop.org/wayland/weston/tree/src/rpi-renderer.c + * http://cgit.freedesktop.org/wayland/weston/tree/src/compositor-rpi.c + */ + +// SDL internals +#include "../SDL_sysvideo.h" +#include "../../events/SDL_mouse_c.h" +#include "../../events/SDL_keyboard_c.h" + +#ifdef SDL_INPUT_LINUXEV +#include "../../core/linux/SDL_evdev.h" +#endif + +// RPI declarations +#include "SDL_rpivideo.h" +#include "SDL_rpievents_c.h" +#include "SDL_rpiopengles.h" +#include "SDL_rpimouse.h" + +static void RPI_Destroy(SDL_VideoDevice *device) +{ + SDL_free(device->internal); + SDL_free(device); +} + +static void RPI_GetRefreshRate(int *numerator, int *denominator) +{ + TV_DISPLAY_STATE_T tvstate; + if (vc_tv_get_display_state(&tvstate) == 0) { + // The width/height parameters are in the same position in the union + // for HDMI and SDTV + HDMI_PROPERTY_PARAM_T property; + property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE; + vc_tv_hdmi_get_property(&property); + if (property.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC) { + *numerator = tvstate.display.hdmi.frame_rate * 1000; + *denominator = 1001; + } else { + *numerator = tvstate.display.hdmi.frame_rate; + *denominator = 1; + } + return; + } + + // Failed to get display state, default to 60 + *numerator = 60; + *denominator = 1; +} + +static SDL_VideoDevice *RPI_Create(void) +{ + SDL_VideoDevice *device; + SDL_VideoData *phdata; + + // Initialize SDL_VideoDevice structure + device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice)); + if (!device) { + return NULL; + } + + // Initialize internal data + phdata = (SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData)); + if (!phdata) { + SDL_free(device); + return NULL; + } + + device->internal = phdata; + + // Setup amount of available displays + device->num_displays = 0; + + // Set device free function + device->free = RPI_Destroy; + + // Setup all functions which we can handle + device->VideoInit = RPI_VideoInit; + device->VideoQuit = RPI_VideoQuit; + device->CreateSDLWindow = RPI_CreateWindow; + device->SetWindowTitle = RPI_SetWindowTitle; + device->SetWindowPosition = RPI_SetWindowPosition; + device->SetWindowSize = RPI_SetWindowSize; + device->ShowWindow = RPI_ShowWindow; + device->HideWindow = RPI_HideWindow; + device->RaiseWindow = RPI_RaiseWindow; + device->MaximizeWindow = RPI_MaximizeWindow; + device->MinimizeWindow = RPI_MinimizeWindow; + device->RestoreWindow = RPI_RestoreWindow; + device->DestroyWindow = RPI_DestroyWindow; + device->GL_LoadLibrary = RPI_GLES_LoadLibrary; + device->GL_GetProcAddress = RPI_GLES_GetProcAddress; + device->GL_UnloadLibrary = RPI_GLES_UnloadLibrary; + device->GL_CreateContext = RPI_GLES_CreateContext; + device->GL_MakeCurrent = RPI_GLES_MakeCurrent; + device->GL_SetSwapInterval = RPI_GLES_SetSwapInterval; + device->GL_GetSwapInterval = RPI_GLES_GetSwapInterval; + device->GL_SwapWindow = RPI_GLES_SwapWindow; + device->GL_DestroyContext = RPI_GLES_DestroyContext; + device->GL_DefaultProfileConfig = RPI_GLES_DefaultProfileConfig; + + device->PumpEvents = RPI_PumpEvents; + + return device; +} + +VideoBootStrap RPI_bootstrap = { + "rpi", + "RPI Video Driver", + RPI_Create, + NULL, // no ShowMessageBox implementation + false +}; + +/*****************************************************************************/ +// SDL Video and Display initialization/handling functions +/*****************************************************************************/ + +static void AddDispManXDisplay(const int display_id) +{ + DISPMANX_MODEINFO_T modeinfo; + DISPMANX_DISPLAY_HANDLE_T handle; + SDL_VideoDisplay display; + SDL_DisplayMode mode; + SDL_DisplayData *data; + + handle = vc_dispmanx_display_open(display_id); + if (!handle) { + return; // this display isn't available + } + + if (vc_dispmanx_display_get_info(handle, &modeinfo) < 0) { + vc_dispmanx_display_close(handle); + return; + } + + // RPI_GetRefreshRate() doesn't distinguish between displays. I'm not sure the hardware distinguishes either + SDL_zero(mode); + mode.w = modeinfo.width; + mode.h = modeinfo.height; + RPI_GetRefreshRate(&mode.refresh_rate_numerator, &mode.refresh_rate_denominator); + + // 32 bpp for default + mode.format = SDL_PIXELFORMAT_ABGR8888; + + SDL_zero(display); + display.desktop_mode = mode; + + // Allocate display internal data + data = (SDL_DisplayData *)SDL_calloc(1, sizeof(SDL_DisplayData)); + if (!data) { + vc_dispmanx_display_close(handle); + return; // oh well + } + + data->dispman_display = handle; + + display.internal = data; + + SDL_AddVideoDisplay(&display, false); +} + +bool RPI_VideoInit(SDL_VideoDevice *_this) +{ + // Initialize BCM Host + bcm_host_init(); + + AddDispManXDisplay(DISPMANX_ID_MAIN_LCD); // your default display + AddDispManXDisplay(DISPMANX_ID_FORCE_OTHER); // an "other" display...maybe DSI-connected screen while HDMI is your main + +#ifdef SDL_INPUT_LINUXEV + if (!SDL_EVDEV_Init()) { + return false; + } +#endif + + RPI_InitMouse(_this); + + return true; +} + +void RPI_VideoQuit(SDL_VideoDevice *_this) +{ +#ifdef SDL_INPUT_LINUXEV + SDL_EVDEV_Quit(); +#endif +} + +static void RPI_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data) +{ + SDL_WindowData *wdata = (SDL_WindowData *)data; + + SDL_LockMutex(wdata->vsync_cond_mutex); + SDL_SignalCondition(wdata->vsync_cond); + SDL_UnlockMutex(wdata->vsync_cond_mutex); +} + +bool RPI_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) +{ + SDL_WindowData *wdata; + SDL_VideoDisplay *display; + SDL_DisplayData *displaydata; + VC_RECT_T dst_rect; + VC_RECT_T src_rect; + VC_DISPMANX_ALPHA_T dispman_alpha; + DISPMANX_UPDATE_HANDLE_T dispman_update; + uint32_t layer = SDL_RPI_VIDEOLAYER; + const char *env; + + // Disable alpha, otherwise the app looks composed with whatever dispman is showing (X11, console,etc) + dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; + dispman_alpha.opacity = 0xFF; + dispman_alpha.mask = 0; + + // Allocate window internal data + wdata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData)); + if (!wdata) { + return false; + } + display = SDL_GetVideoDisplayForWindow(window); + displaydata = display->internal; + + // Windows have one size for now + window->w = display->desktop_mode.w; + window->h = display->desktop_mode.h; + + // OpenGL ES is the law here, buddy + window->flags |= SDL_WINDOW_OPENGL; + + // Create a dispman element and associate a window to it + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.width = window->w; + dst_rect.height = window->h; + + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = window->w << 16; + src_rect.height = window->h << 16; + + env = SDL_GetHint(SDL_HINT_RPI_VIDEO_LAYER); + if (env) { + layer = SDL_atoi(env); + } + + dispman_update = vc_dispmanx_update_start(0); + wdata->dispman_window.element = vc_dispmanx_element_add(dispman_update, + displaydata->dispman_display, + layer /* layer */, + &dst_rect, + 0 /*src*/, + &src_rect, + DISPMANX_PROTECTION_NONE, + &dispman_alpha /*alpha*/, + 0 /*clamp*/, + 0 /*transform*/); + wdata->dispman_window.width = window->w; + wdata->dispman_window.height = window->h; + vc_dispmanx_update_submit_sync(dispman_update); + + if (!_this->egl_data) { + if (!SDL_GL_LoadLibrary(NULL)) { + return false; + } + } + wdata->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)&wdata->dispman_window); + + if (wdata->egl_surface == EGL_NO_SURFACE) { + return SDL_SetError("Could not create GLES window surface"); + } + + // Start generating vsync callbacks if necessary + wdata->double_buffer = false; + if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, false)) { + wdata->vsync_cond = SDL_CreateCondition(); + wdata->vsync_cond_mutex = SDL_CreateMutex(); + wdata->double_buffer = true; + vc_dispmanx_vsync_callback(displaydata->dispman_display, RPI_vsync_callback, (void *)wdata); + } + + // Setup driver data for this window + window->internal = wdata; + + // One window, it always has focus + SDL_SetMouseFocus(window); + SDL_SetKeyboardFocus(window); + + // Window has been successfully created + return true; +} + +void RPI_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ + SDL_WindowData *data = window->internal; + SDL_DisplayData *displaydata = SDL_GetDisplayDriverDataForWindow(window); + + if (data) { + if (data->double_buffer) { + // Wait for vsync, and then stop vsync callbacks and destroy related stuff, if needed + SDL_LockMutex(data->vsync_cond_mutex); + SDL_WaitCondition(data->vsync_cond, data->vsync_cond_mutex); + SDL_UnlockMutex(data->vsync_cond_mutex); + + vc_dispmanx_vsync_callback(displaydata->dispman_display, NULL, NULL); + + SDL_DestroyCondition(data->vsync_cond); + SDL_DestroyMutex(data->vsync_cond_mutex); + } + +#ifdef SDL_VIDEO_OPENGL_EGL + if (data->egl_surface != EGL_NO_SURFACE) { + SDL_EGL_DestroySurface(_this, data->egl_surface); + } +#endif + SDL_free(data); + window->internal = NULL; + } +} + +void RPI_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +bool RPI_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window) +{ + return SDL_Unsupported(); +} +void RPI_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +void RPI_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +void RPI_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +void RPI_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +void RPI_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +void RPI_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +void RPI_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ +} + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_rpivideo_h +#define SDL_rpivideo_h + +#include "SDL_internal.h" +#include "../SDL_sysvideo.h" + +#include +#include + +struct SDL_VideoData +{ + uint32_t egl_refcount; // OpenGL ES reference count +}; + +struct SDL_DisplayData +{ + DISPMANX_DISPLAY_HANDLE_T dispman_display; +}; + +struct SDL_WindowData +{ + EGL_DISPMANX_WINDOW_T dispman_window; +#ifdef SDL_VIDEO_OPENGL_EGL + EGLSurface egl_surface; +#endif + + // Vsync callback cond and mutex + SDL_Condition *vsync_cond; + SDL_Mutex *vsync_cond_mutex; + bool double_buffer; +}; + +#define SDL_RPI_VIDEOLAYER 10000 // High enough so to occlude everything +#define SDL_RPI_MOUSELAYER SDL_RPI_VIDEOLAYER + 1 + +/****************************************************************************/ +// SDL_VideoDevice functions declaration +/****************************************************************************/ + +// Display and window functions +extern bool RPI_VideoInit(SDL_VideoDevice *_this); +extern void RPI_VideoQuit(SDL_VideoDevice *_this); +extern bool RPI_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display); +extern bool RPI_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode); +extern bool RPI_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props); +extern void RPI_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window); +extern bool RPI_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window); +extern void RPI_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window); +extern void RPI_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window); +extern void RPI_HideWindow(SDL_VideoDevice *_this, SDL_Window *window); +extern void RPI_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window); +extern void RPI_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window); +extern void RPI_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window); +extern void RPI_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window); +extern void RPI_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window); + +// OpenGL/OpenGL ES functions +extern bool RPI_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path); +extern SDL_FunctionPointer RPI_GLES_GetProcAddress(SDL_VideoDevice *_this, const char *proc); +extern void RPI_GLES_UnloadLibrary(SDL_VideoDevice *_this); +extern SDL_GLContext RPI_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window); +extern bool RPI_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context); +extern bool RPI_GLES_SetSwapInterval(SDL_VideoDevice *_this, int interval); +extern bool RPI_GLES_GetSwapInterval(SDL_VideoDevice *_this); +extern bool RPI_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window); +extern bool RPI_GLES_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context); + +#endif // SDL_rpivideo_h -- cgit v1.2.3