SDL  2.0
SDL_rpivideo.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 #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 
53 static int
54 RPI_Available(void)
55 {
56  return 1;
57 }
58 
59 static void
60 RPI_Destroy(SDL_VideoDevice * device)
61 {
62  SDL_free(device->driverdata);
63  SDL_free(device);
64 }
65 
66 static int
67 RPI_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 
83 static SDL_VideoDevice *
84 RPI_Create()
85 {
87  SDL_VideoData *phdata;
88 
89  /* Initialize SDL_VideoDevice structure */
90  device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
91  if (device == NULL) {
93  return NULL;
94  }
95 
96  /* Initialize internal data */
97  phdata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
98  if (phdata == NULL) {
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;
123  device->ShowWindow = RPI_ShowWindow;
124  device->HideWindow = RPI_HideWindow;
125  device->RaiseWindow = RPI_RaiseWindow;
131 #if 0
133 #endif
143  device->GL_DefaultProfileConfig = RPI_GLES_DefaultProfileConfig;
144 
145  device->PumpEvents = RPI_PumpEvents;
146 
147  return device;
148 }
149 
151  "RPI",
152  "RPI Video Driver",
153  RPI_Available,
154  RPI_Create
155 };
156 
157 /*****************************************************************************/
158 /* SDL Video and Display initialization/handling functions */
159 /*****************************************************************************/
160 int
162 {
163  SDL_VideoDisplay display;
164  SDL_DisplayMode current_mode;
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 
208 
209  return 1;
210 }
211 
212 void
214 {
215 #ifdef SDL_INPUT_LINUXEV
216  SDL_EVDEV_Quit();
217 #endif
218 }
219 
220 void
222 {
223  /* Only one display mode available, the current one */
224  SDL_AddDisplayMode(display, &display->current_mode);
225 }
226 
227 int
229 {
230  return 0;
231 }
232 
233 static void
234 RPI_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data)
235 {
236  SDL_WindowData *wdata = ((SDL_WindowData *) data);
237 
239  SDL_CondSignal(wdata->vsync_cond);
241 }
242 
243 int
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;
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 
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;
321  wdata->vsync_cond = SDL_CreateCond();
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 
338 void
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 */
351 
352  vc_dispmanx_vsync_callback(displaydata->dispman_display, NULL, NULL);
353 
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 
368 int
369 RPI_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
370 {
371  return -1;
372 }
373 
374 void
376 {
377 }
378 void
380 {
381 }
382 void
384 {
385 }
386 void
388 {
389 }
390 void
392 {
393 }
394 void
396 {
397 }
398 void
400 {
401 }
402 void
404 {
405 }
406 void
408 {
409 }
410 void
412 {
413 }
414 void
415 RPI_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
416 {
417 
418 }
419 
420 /*****************************************************************************/
421 /* SDL Window Manager function */
422 /*****************************************************************************/
423 #if 0
424 SDL_bool
425 RPI_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",
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: */
#define SDL_RPI_VIDEOLAYER
Definition: SDL_rpivideo.h:59
SDL_cond * vsync_cond
Definition: SDL_rpivideo.h:53
#define SDL_MINOR_VERSION
Definition: SDL_version.h:61
SDL_bool double_buffer
#define SDL_LockMutex
void RPI_DestroyWindow(_THIS, SDL_Window *window)
void RPI_RestoreWindow(_THIS, SDL_Window *window)
void(* RestoreWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:227
void * RPI_GLES_GetProcAddress(_THIS, const char *proc)
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:630
int RPI_CreateWindowFrom(_THIS, SDL_Window *window, const void *data)
void RPI_SetWindowTitle(_THIS, SDL_Window *window)
#define EGL_NO_SURFACE
Definition: egl.h:100
void RPI_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed)
int RPI_GLES_LoadLibrary(_THIS, const char *path)
#define SDL_MAJOR_VERSION
Definition: SDL_version.h:60
void(* free)(_THIS)
Definition: SDL_sysvideo.h:390
GLfloat GLfloat GLfloat GLfloat h
#define SDL_CreateMutex
void RPI_GLES_UnloadLibrary(_THIS)
void RPI_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
A collection of pixels used in software blitting.
Definition: SDL_surface.h:69
int(* GL_SetSwapInterval)(_THIS, int interval)
Definition: SDL_sysvideo.h:260
SDL_mutex * vsync_cond_mutex
Definition: SDL_rpivideo.h:54
int RPI_GLES_MakeCurrent(_THIS, SDL_Window *window, SDL_GLContext context)
void(* ShowWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:222
The structure that defines a display mode.
Definition: SDL_video.h:53
#define SDL_GetHint
SDL_version version
Definition: SDL_syswm.h:196
Uint8 major
Definition: SDL_version.h:53
void(* SetWindowSize)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:215
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
void RPI_RaiseWindow(_THIS, SDL_Window *window)
GLenum GLuint GLint GLint layer
int RPI_GLES_GetSwapInterval(_THIS)
void RPI_MaximizeWindow(_THIS, SDL_Window *window)
#define SDL_DestroyCond
void SDL_SetMouseFocus(SDL_Window *window)
Definition: SDL_mouse.c:151
#define SDL_GL_LoadLibrary
#define SDL_CondSignal
#define SDL_CondWait
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display)
Definition: SDL_video.c:606
int(* GL_LoadLibrary)(_THIS, const char *path)
Definition: SDL_sysvideo.h:254
int RPI_VideoInit(_THIS)
int(* SetDisplayMode)(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
Definition: SDL_sysvideo.h:204
#define SDL_GetHintBoolean
void RPI_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon)
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
EGLNativeWindowType NativeWindowType
Definition: eglplatform.h:112
void(* HideWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:223
static SDL_AudioDeviceID device
Definition: loopwave.c:37
void(* RaiseWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:224
SDL_bool(* GetWindowWMInfo)(_THIS, SDL_Window *window, struct SDL_SysWMinfo *info)
Definition: SDL_sysvideo.h:247
SDL_GLContext(* GL_CreateContext)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:257
#define _THIS
void RPI_PumpEvents(_THIS)
int(* GL_MakeCurrent)(_THIS, SDL_Window *window, SDL_GLContext context)
Definition: SDL_sysvideo.h:258
#define SDL_free
EGL_DISPMANX_WINDOW_T dispman_window
Definition: SDL_rpivideo.h:47
void * driverdata
Definition: SDL_video.h:59
void RPI_HideWindow(_THIS, SDL_Window *window)
void RPI_SetWindowSize(_THIS, SDL_Window *window)
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:132
GLenum mode
GLubyte GLubyte GLubyte GLubyte w
void(* DestroyWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:234
void RPI_GLES_DeleteContext(_THIS, SDL_GLContext context)
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
void(* SetWindowIcon)(_THIS, SDL_Window *window, SDL_Surface *icon)
Definition: SDL_sysvideo.h:213
#define SDL_CreateCond
DISPMANX_DISPLAY_HANDLE_T dispman_display
Definition: SDL_rpivideo.h:41
void RPI_VideoQuit(_THIS)
#define SDL_atoi
void(* GL_UnloadLibrary)(_THIS)
Definition: SDL_sysvideo.h:256
void(* GetDisplayModes)(_THIS, SDL_VideoDisplay *display)
Definition: SDL_sysvideo.h:196
VideoBootStrap RPI_bootstrap
#define NULL
Definition: begin_code.h:164
int(* CreateSDLWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:210
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:139
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:131
unsigned int uint32_t
void(* VideoQuit)(_THIS)
Definition: SDL_sysvideo.h:166
void RPI_ShowWindow(_THIS, SDL_Window *window)
void RPI_MinimizeWindow(_THIS, SDL_Window *window)
#define SDL_SetError
#define SDL_HINT_RPI_VIDEO_LAYER
Tell SDL which Dispmanx layer to use on a Raspberry PI.
Definition: SDL_hints.h:843
#define SDL_DestroyMutex
#define SDL_calloc
int RPI_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1073
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
void(* SetWindowPosition)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:214
int(* GL_SwapWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:262
#define SDL_HINT_VIDEO_DOUBLE_BUFFER
Tell the video driver that we only want a double buffer.
Definition: SDL_hints.h:861
The type used to identify a window.
Definition: SDL_sysvideo.h:73
SDL_GLContext RPI_GLES_CreateContext(_THIS, SDL_Window *window)
void(* MinimizeWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:226
int RPI_CreateWindow(_THIS, SDL_Window *window)
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:743
int(* VideoInit)(_THIS)
Definition: SDL_sysvideo.h:160
int(* CreateSDLWindowFrom)(_THIS, SDL_Window *window, const void *data)
Definition: SDL_sysvideo.h:211
#define SDL_UnlockMutex
void * driverdata
Definition: SDL_sysvideo.h:111
void(* GL_DeleteContext)(_THIS, SDL_GLContext context)
Definition: SDL_sysvideo.h:263
void(* GL_DefaultProfileConfig)(_THIS, int *mask, int *major, int *minor)
Definition: SDL_sysvideo.h:264
Uint32 format
Definition: SDL_video.h:55
void(* SetWindowTitle)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:212
int(* GL_GetSwapInterval)(_THIS)
Definition: SDL_sysvideo.h:261
void(* MaximizeWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:225
Uint32 flags
Definition: SDL_sysvideo.h:83
SDL_bool RPI_GetWindowWMInfo(_THIS, SDL_Window *window, struct SDL_SysWMinfo *info)
void RPI_SetWindowPosition(_THIS, SDL_Window *window)
void(* SetWindowGrab)(_THIS, SDL_Window *window, SDL_bool grabbed)
Definition: SDL_sysvideo.h:233
void RPI_InitMouse(_THIS)
int RPI_GLES_SwapWindow(_THIS, SDL_Window *window)
void *(* GL_GetProcAddress)(_THIS, const char *proc)
Definition: SDL_sysvideo.h:255
EGLSurface egl_surface
void(* PumpEvents)(_THIS)
Definition: SDL_sysvideo.h:280
int RPI_GLES_SetSwapInterval(_THIS, int interval)