Atlas - SDL_rpivideo.c
Home / ext / SDL2 / src / video / raspberry Lines: 1 | Size: 12725 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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#if 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 "SDL_version.h" 36#include "SDL_syswm.h" 37#include "SDL_loadso.h" 38#include "SDL_events.h" 39#include "../../events/SDL_mouse_c.h" 40#include "../../events/SDL_keyboard_c.h" 41#include "SDL_hints.h" 42 43#ifdef SDL_INPUT_LINUXEV 44#include "../../core/linux/SDL_evdev.h" 45#endif 46 47/* RPI declarations */ 48#include "SDL_rpivideo.h" 49#include "SDL_rpievents_c.h" 50#include "SDL_rpiopengles.h" 51#include "SDL_rpimouse.h" 52 53static int 54RPI_Available(void) 55{ 56 return 1; 57} 58 59static void 60RPI_Destroy(SDL_VideoDevice * device) 61{ 62 SDL_free(device->driverdata); 63 SDL_free(device); 64} 65 66static int 67RPI_GetRefreshRate() 68{ 69 TV_DISPLAY_STATE_T tvstate; 70 if (vc_tv_get_display_state( &tvstate ) == 0) { 71 //The width/height parameters are in the same position in the union 72 //for HDMI and SDTV 73 HDMI_PROPERTY_PARAM_T property; 74 property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE; 75 vc_tv_hdmi_get_property(&property); 76 return property.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC ? 77 tvstate.display.hdmi.frame_rate * (1000.0f/1001.0f) : 78 tvstate.display.hdmi.frame_rate; 79 } 80 return 60; /* Failed to get display state, default to 60 */ 81} 82 83static SDL_VideoDevice * 84RPI_Create() 85{ 86 SDL_VideoDevice *device; 87 SDL_VideoData *phdata; 88 89 /* Initialize SDL_VideoDevice structure */ 90 device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); 91 if (device == NULL) { 92 SDL_OutOfMemory(); 93 return NULL; 94 } 95 96 /* Initialize internal data */ 97 phdata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData)); 98 if (phdata == NULL) { 99 SDL_OutOfMemory(); 100 SDL_free(device); 101 return NULL; 102 } 103 104 device->driverdata = phdata; 105 106 /* Setup amount of available displays */ 107 device->num_displays = 0; 108 109 /* Set device free function */ 110 device->free = RPI_Destroy; 111 112 /* Setup all functions which we can handle */ 113 device->VideoInit = RPI_VideoInit; 114 device->VideoQuit = RPI_VideoQuit; 115 device->GetDisplayModes = RPI_GetDisplayModes; 116 device->SetDisplayMode = RPI_SetDisplayMode; 117 device->CreateSDLWindow = RPI_CreateWindow; 118 device->CreateSDLWindowFrom = RPI_CreateWindowFrom; 119 device->SetWindowTitle = RPI_SetWindowTitle; 120 device->SetWindowIcon = RPI_SetWindowIcon; 121 device->SetWindowPosition = RPI_SetWindowPosition; 122 device->SetWindowSize = RPI_SetWindowSize; 123 device->ShowWindow = RPI_ShowWindow; 124 device->HideWindow = RPI_HideWindow; 125 device->RaiseWindow = RPI_RaiseWindow; 126 device->MaximizeWindow = RPI_MaximizeWindow; 127 device->MinimizeWindow = RPI_MinimizeWindow; 128 device->RestoreWindow = RPI_RestoreWindow; 129 device->SetWindowGrab = RPI_SetWindowGrab; 130 device->DestroyWindow = RPI_DestroyWindow; 131#if 0 132 device->GetWindowWMInfo = RPI_GetWindowWMInfo; 133#endif 134 device->GL_LoadLibrary = RPI_GLES_LoadLibrary; 135 device->GL_GetProcAddress = RPI_GLES_GetProcAddress; 136 device->GL_UnloadLibrary = RPI_GLES_UnloadLibrary; 137 device->GL_CreateContext = RPI_GLES_CreateContext; 138 device->GL_MakeCurrent = RPI_GLES_MakeCurrent; 139 device->GL_SetSwapInterval = RPI_GLES_SetSwapInterval; 140 device->GL_GetSwapInterval = RPI_GLES_GetSwapInterval; 141 device->GL_SwapWindow = RPI_GLES_SwapWindow; 142 device->GL_DeleteContext = RPI_GLES_DeleteContext; 143 device->GL_DefaultProfileConfig = RPI_GLES_DefaultProfileConfig; 144 145 device->PumpEvents = RPI_PumpEvents; 146 147 return device; 148} 149 150VideoBootStrap RPI_bootstrap = { 151 "RPI", 152 "RPI Video Driver", 153 RPI_Available, 154 RPI_Create 155}; 156 157/*****************************************************************************/ 158/* SDL Video and Display initialization/handling functions */ 159/*****************************************************************************/ 160int 161RPI_VideoInit(_THIS) 162{ 163 SDL_VideoDisplay display; 164 SDL_DisplayMode current_mode; 165 SDL_DisplayData *data; 166 uint32_t w,h; 167 168 /* Initialize BCM Host */ 169 bcm_host_init(); 170 171 SDL_zero(current_mode); 172 173 if (graphics_get_display_size( 0, &w, &h) < 0) { 174 return -1; 175 } 176 177 current_mode.w = w; 178 current_mode.h = h; 179 current_mode.refresh_rate = RPI_GetRefreshRate(); 180 /* 32 bpp for default */ 181 current_mode.format = SDL_PIXELFORMAT_ABGR8888; 182 183 current_mode.driverdata = NULL; 184 185 SDL_zero(display); 186 display.desktop_mode = current_mode; 187 display.current_mode = current_mode; 188 189 /* Allocate display internal data */ 190 data = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData)); 191 if (data == NULL) { 192 return SDL_OutOfMemory(); 193 } 194 195 data->dispman_display = vc_dispmanx_display_open( 0 /* LCD */); 196 197 display.driverdata = data; 198 199 SDL_AddVideoDisplay(&display); 200 201#ifdef SDL_INPUT_LINUXEV 202 if (SDL_EVDEV_Init() < 0) { 203 return -1; 204 } 205#endif 206 207 RPI_InitMouse(_this); 208 209 return 1; 210} 211 212void 213RPI_VideoQuit(_THIS) 214{ 215#ifdef SDL_INPUT_LINUXEV 216 SDL_EVDEV_Quit(); 217#endif 218} 219 220void 221RPI_GetDisplayModes(_THIS, SDL_VideoDisplay * display) 222{ 223 /* Only one display mode available, the current one */ 224 SDL_AddDisplayMode(display, &display->current_mode); 225} 226 227int 228RPI_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) 229{ 230 return 0; 231} 232 233static void 234RPI_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data) 235{ 236 SDL_WindowData *wdata = ((SDL_WindowData *) data); 237 238 SDL_LockMutex(wdata->vsync_cond_mutex); 239 SDL_CondSignal(wdata->vsync_cond); 240 SDL_UnlockMutex(wdata->vsync_cond_mutex); 241} 242 243int 244RPI_CreateWindow(_THIS, SDL_Window * window) 245{ 246 SDL_WindowData *wdata; 247 SDL_VideoDisplay *display; 248 SDL_DisplayData *displaydata; 249 VC_RECT_T dst_rect; 250 VC_RECT_T src_rect; 251 VC_DISPMANX_ALPHA_T dispman_alpha; 252 DISPMANX_UPDATE_HANDLE_T dispman_update; 253 uint32_t layer = SDL_RPI_VIDEOLAYER; 254 const char *env; 255 256 /* Disable alpha, otherwise the app looks composed with whatever dispman is showing (X11, console,etc) */ 257 dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; 258 dispman_alpha.opacity = 0xFF; 259 dispman_alpha.mask = 0; 260 261 /* Allocate window internal data */ 262 wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData)); 263 if (wdata == NULL) { 264 return SDL_OutOfMemory(); 265 } 266 display = SDL_GetDisplayForWindow(window); 267 displaydata = (SDL_DisplayData *) display->driverdata; 268 269 /* Windows have one size for now */ 270 window->w = display->desktop_mode.w; 271 window->h = display->desktop_mode.h; 272 273 /* OpenGL ES is the law here, buddy */ 274 window->flags |= SDL_WINDOW_OPENGL; 275 276 /* Create a dispman element and associate a window to it */ 277 dst_rect.x = 0; 278 dst_rect.y = 0; 279 dst_rect.width = window->w; 280 dst_rect.height = window->h; 281 282 src_rect.x = 0; 283 src_rect.y = 0; 284 src_rect.width = window->w << 16; 285 src_rect.height = window->h << 16; 286 287 env = SDL_GetHint(SDL_HINT_RPI_VIDEO_LAYER); 288 if (env) { 289 layer = SDL_atoi(env); 290 } 291 292 dispman_update = vc_dispmanx_update_start( 0 ); 293 wdata->dispman_window.element = vc_dispmanx_element_add (dispman_update, 294 displaydata->dispman_display, 295 layer /* layer */, 296 &dst_rect, 297 0 /*src*/, 298 &src_rect, 299 DISPMANX_PROTECTION_NONE, 300 &dispman_alpha /*alpha*/, 301 0 /*clamp*/, 302 0 /*transform*/); 303 wdata->dispman_window.width = window->w; 304 wdata->dispman_window.height = window->h; 305 vc_dispmanx_update_submit_sync(dispman_update); 306 307 if (!_this->egl_data) { 308 if (SDL_GL_LoadLibrary(NULL) < 0) { 309 return -1; 310 } 311 } 312 wdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) &wdata->dispman_window); 313 314 if (wdata->egl_surface == EGL_NO_SURFACE) { 315 return SDL_SetError("Could not create GLES window surface"); 316 } 317 318 /* Start generating vsync callbacks if necesary */ 319 wdata->double_buffer = SDL_FALSE; 320 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) { 321 wdata->vsync_cond = SDL_CreateCond(); 322 wdata->vsync_cond_mutex = SDL_CreateMutex(); 323 wdata->double_buffer = SDL_TRUE; 324 vc_dispmanx_vsync_callback(displaydata->dispman_display, RPI_vsync_callback, (void*)wdata); 325 } 326 327 /* Setup driver data for this window */ 328 window->driverdata = wdata; 329 330 /* One window, it always has focus */ 331 SDL_SetMouseFocus(window); 332 SDL_SetKeyboardFocus(window); 333 334 /* Window has been successfully created */ 335 return 0; 336} 337 338void 339RPI_DestroyWindow(_THIS, SDL_Window * window) 340{ 341 SDL_WindowData *data = (SDL_WindowData *) window->driverdata; 342 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); 343 SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata; 344 345 if(data) { 346 if (data->double_buffer) { 347 /* Wait for vsync, and then stop vsync callbacks and destroy related stuff, if needed */ 348 SDL_LockMutex(data->vsync_cond_mutex); 349 SDL_CondWait(data->vsync_cond, data->vsync_cond_mutex); 350 SDL_UnlockMutex(data->vsync_cond_mutex); 351 352 vc_dispmanx_vsync_callback(displaydata->dispman_display, NULL, NULL); 353 354 SDL_DestroyCond(data->vsync_cond); 355 SDL_DestroyMutex(data->vsync_cond_mutex); 356 } 357 358#if SDL_VIDEO_OPENGL_EGL 359 if (data->egl_surface != EGL_NO_SURFACE) { 360 SDL_EGL_DestroySurface(_this, data->egl_surface); 361 } 362#endif 363 SDL_free(data); 364 window->driverdata = NULL; 365 } 366} 367 368int 369RPI_CreateWindowFrom(_THIS, SDL_Window * window, const void *data) 370{ 371 return -1; 372} 373 374void 375RPI_SetWindowTitle(_THIS, SDL_Window * window) 376{ 377} 378void 379RPI_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon) 380{ 381} 382void 383RPI_SetWindowPosition(_THIS, SDL_Window * window) 384{ 385} 386void 387RPI_SetWindowSize(_THIS, SDL_Window * window) 388{ 389} 390void 391RPI_ShowWindow(_THIS, SDL_Window * window) 392{ 393} 394void 395RPI_HideWindow(_THIS, SDL_Window * window) 396{ 397} 398void 399RPI_RaiseWindow(_THIS, SDL_Window * window) 400{ 401} 402void 403RPI_MaximizeWindow(_THIS, SDL_Window * window) 404{ 405} 406void 407RPI_MinimizeWindow(_THIS, SDL_Window * window) 408{ 409} 410void 411RPI_RestoreWindow(_THIS, SDL_Window * window) 412{ 413} 414void 415RPI_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed) 416{ 417 418} 419 420/*****************************************************************************/ 421/* SDL Window Manager function */ 422/*****************************************************************************/ 423#if 0 424SDL_bool 425RPI_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info) 426{ 427 if (info->version.major <= SDL_MAJOR_VERSION) { 428 return SDL_TRUE; 429 } else { 430 SDL_SetError("application not compiled with SDL %d.%d", 431 SDL_MAJOR_VERSION, SDL_MINOR_VERSION); 432 return SDL_FALSE; 433 } 434 435 /* Failed to get window manager information */ 436 return SDL_FALSE; 437} 438#endif 439 440#endif /* SDL_VIDEO_DRIVER_RPI */ 441 442/* vi: set ts=4 sw=4 expandtab: */ 443[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.