1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 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
RPI_Available(void)54 RPI_Available(void)
55 {
56 return 1;
57 }
58
59 static void
RPI_Destroy(SDL_VideoDevice * device)60 RPI_Destroy(SDL_VideoDevice * device)
61 {
62 /* SDL_VideoData *phdata = (SDL_VideoData *) device->driverdata; */
63
64 if (device->driverdata != NULL) {
65 device->driverdata = NULL;
66 }
67 }
68
69 static SDL_VideoDevice *
RPI_Create()70 RPI_Create()
71 {
72 SDL_VideoDevice *device;
73 SDL_VideoData *phdata;
74
75 /* Initialize SDL_VideoDevice structure */
76 device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
77 if (device == NULL) {
78 SDL_OutOfMemory();
79 return NULL;
80 }
81
82 /* Initialize internal data */
83 phdata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
84 if (phdata == NULL) {
85 SDL_OutOfMemory();
86 SDL_free(device);
87 return NULL;
88 }
89
90 device->driverdata = phdata;
91
92 /* Setup amount of available displays */
93 device->num_displays = 0;
94
95 /* Set device free function */
96 device->free = RPI_Destroy;
97
98 /* Setup all functions which we can handle */
99 device->VideoInit = RPI_VideoInit;
100 device->VideoQuit = RPI_VideoQuit;
101 device->GetDisplayModes = RPI_GetDisplayModes;
102 device->SetDisplayMode = RPI_SetDisplayMode;
103 device->CreateWindow = RPI_CreateWindow;
104 device->CreateWindowFrom = RPI_CreateWindowFrom;
105 device->SetWindowTitle = RPI_SetWindowTitle;
106 device->SetWindowIcon = RPI_SetWindowIcon;
107 device->SetWindowPosition = RPI_SetWindowPosition;
108 device->SetWindowSize = RPI_SetWindowSize;
109 device->ShowWindow = RPI_ShowWindow;
110 device->HideWindow = RPI_HideWindow;
111 device->RaiseWindow = RPI_RaiseWindow;
112 device->MaximizeWindow = RPI_MaximizeWindow;
113 device->MinimizeWindow = RPI_MinimizeWindow;
114 device->RestoreWindow = RPI_RestoreWindow;
115 device->SetWindowGrab = RPI_SetWindowGrab;
116 device->DestroyWindow = RPI_DestroyWindow;
117 device->GetWindowWMInfo = RPI_GetWindowWMInfo;
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_DeleteContext = RPI_GLES_DeleteContext;
127
128 device->PumpEvents = RPI_PumpEvents;
129
130 return device;
131 }
132
133 VideoBootStrap RPI_bootstrap = {
134 "RPI",
135 "RPI Video Driver",
136 RPI_Available,
137 RPI_Create
138 };
139
140 /*****************************************************************************/
141 /* SDL Video and Display initialization/handling functions */
142 /*****************************************************************************/
143 int
RPI_VideoInit(_THIS)144 RPI_VideoInit(_THIS)
145 {
146 SDL_VideoDisplay display;
147 SDL_DisplayMode current_mode;
148 SDL_DisplayData *data;
149 uint32_t w,h;
150
151 /* Initialize BCM Host */
152 bcm_host_init();
153
154 SDL_zero(current_mode);
155
156 if (graphics_get_display_size( 0, &w, &h) < 0) {
157 return -1;
158 }
159
160 current_mode.w = w;
161 current_mode.h = h;
162 /* FIXME: Is there a way to tell the actual refresh rate? */
163 current_mode.refresh_rate = 60;
164 /* 32 bpp for default */
165 current_mode.format = SDL_PIXELFORMAT_ABGR8888;
166
167 current_mode.driverdata = NULL;
168
169 SDL_zero(display);
170 display.desktop_mode = current_mode;
171 display.current_mode = current_mode;
172
173 /* Allocate display internal data */
174 data = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
175 if (data == NULL) {
176 return SDL_OutOfMemory();
177 }
178
179 data->dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
180
181 display.driverdata = data;
182
183 SDL_AddVideoDisplay(&display);
184
185 #ifdef SDL_INPUT_LINUXEV
186 SDL_EVDEV_Init();
187 #endif
188
189 RPI_InitMouse(_this);
190
191 return 1;
192 }
193
194 void
RPI_VideoQuit(_THIS)195 RPI_VideoQuit(_THIS)
196 {
197 #ifdef SDL_INPUT_LINUXEV
198 SDL_EVDEV_Quit();
199 #endif
200 }
201
202 void
RPI_GetDisplayModes(_THIS,SDL_VideoDisplay * display)203 RPI_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
204 {
205 /* Only one display mode available, the current one */
206 SDL_AddDisplayMode(display, &display->current_mode);
207 }
208
209 int
RPI_SetDisplayMode(_THIS,SDL_VideoDisplay * display,SDL_DisplayMode * mode)210 RPI_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
211 {
212 return 0;
213 }
214
215 int
RPI_CreateWindow(_THIS,SDL_Window * window)216 RPI_CreateWindow(_THIS, SDL_Window * window)
217 {
218 SDL_WindowData *wdata;
219 SDL_VideoDisplay *display;
220 SDL_DisplayData *displaydata;
221 VC_RECT_T dst_rect;
222 VC_RECT_T src_rect;
223 VC_DISPMANX_ALPHA_T dispman_alpha;
224 DISPMANX_UPDATE_HANDLE_T dispman_update;
225 uint32_t layer = SDL_RPI_VIDEOLAYER;
226 const char *env;
227
228 /* Disable alpha, otherwise the app looks composed with whatever dispman is showing (X11, console,etc) */
229 dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
230 dispman_alpha.opacity = 0xFF;
231 dispman_alpha.mask = 0;
232
233 /* Allocate window internal data */
234 wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
235 if (wdata == NULL) {
236 return SDL_OutOfMemory();
237 }
238 display = SDL_GetDisplayForWindow(window);
239 displaydata = (SDL_DisplayData *) display->driverdata;
240
241 /* Windows have one size for now */
242 window->w = display->desktop_mode.w;
243 window->h = display->desktop_mode.h;
244
245 /* OpenGL ES is the law here, buddy */
246 window->flags |= SDL_WINDOW_OPENGL;
247
248 /* Create a dispman element and associate a window to it */
249 dst_rect.x = 0;
250 dst_rect.y = 0;
251 dst_rect.width = window->w;
252 dst_rect.height = window->h;
253
254 src_rect.x = 0;
255 src_rect.y = 0;
256 src_rect.width = window->w << 16;
257 src_rect.height = window->h << 16;
258
259 env = SDL_GetHint(SDL_HINT_RPI_VIDEO_LAYER);
260 if (env) {
261 layer = SDL_atoi(env);
262 }
263
264 dispman_update = vc_dispmanx_update_start( 0 );
265 wdata->dispman_window.element = vc_dispmanx_element_add (dispman_update,
266 displaydata->dispman_display,
267 layer /* layer */,
268 &dst_rect,
269 0 /*src*/,
270 &src_rect,
271 DISPMANX_PROTECTION_NONE,
272 &dispman_alpha /*alpha*/,
273 0 /*clamp*/,
274 0 /*transform*/);
275 wdata->dispman_window.width = window->w;
276 wdata->dispman_window.height = window->h;
277 vc_dispmanx_update_submit_sync(dispman_update);
278
279 if (!_this->egl_data) {
280 if (SDL_GL_LoadLibrary(NULL) < 0) {
281 return -1;
282 }
283 }
284 wdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) &wdata->dispman_window);
285
286 if (wdata->egl_surface == EGL_NO_SURFACE) {
287 return SDL_SetError("Could not create GLES window surface");
288 }
289
290 /* Setup driver data for this window */
291 window->driverdata = wdata;
292
293 /* One window, it always has focus */
294 SDL_SetMouseFocus(window);
295 SDL_SetKeyboardFocus(window);
296
297 /* Window has been successfully created */
298 return 0;
299 }
300
301 void
RPI_DestroyWindow(_THIS,SDL_Window * window)302 RPI_DestroyWindow(_THIS, SDL_Window * window)
303 {
304 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
305 if(data) {
306 #if SDL_VIDEO_OPENGL_EGL
307 if (data->egl_surface != EGL_NO_SURFACE) {
308 SDL_EGL_DestroySurface(_this, data->egl_surface);
309 }
310 #endif
311 SDL_free(data);
312 window->driverdata = NULL;
313 }
314 }
315
316 int
RPI_CreateWindowFrom(_THIS,SDL_Window * window,const void * data)317 RPI_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
318 {
319 return -1;
320 }
321
322 void
RPI_SetWindowTitle(_THIS,SDL_Window * window)323 RPI_SetWindowTitle(_THIS, SDL_Window * window)
324 {
325 }
326 void
RPI_SetWindowIcon(_THIS,SDL_Window * window,SDL_Surface * icon)327 RPI_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
328 {
329 }
330 void
RPI_SetWindowPosition(_THIS,SDL_Window * window)331 RPI_SetWindowPosition(_THIS, SDL_Window * window)
332 {
333 }
334 void
RPI_SetWindowSize(_THIS,SDL_Window * window)335 RPI_SetWindowSize(_THIS, SDL_Window * window)
336 {
337 }
338 void
RPI_ShowWindow(_THIS,SDL_Window * window)339 RPI_ShowWindow(_THIS, SDL_Window * window)
340 {
341 }
342 void
RPI_HideWindow(_THIS,SDL_Window * window)343 RPI_HideWindow(_THIS, SDL_Window * window)
344 {
345 }
346 void
RPI_RaiseWindow(_THIS,SDL_Window * window)347 RPI_RaiseWindow(_THIS, SDL_Window * window)
348 {
349 }
350 void
RPI_MaximizeWindow(_THIS,SDL_Window * window)351 RPI_MaximizeWindow(_THIS, SDL_Window * window)
352 {
353 }
354 void
RPI_MinimizeWindow(_THIS,SDL_Window * window)355 RPI_MinimizeWindow(_THIS, SDL_Window * window)
356 {
357 }
358 void
RPI_RestoreWindow(_THIS,SDL_Window * window)359 RPI_RestoreWindow(_THIS, SDL_Window * window)
360 {
361 }
362 void
RPI_SetWindowGrab(_THIS,SDL_Window * window,SDL_bool grabbed)363 RPI_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
364 {
365
366 }
367
368 /*****************************************************************************/
369 /* SDL Window Manager function */
370 /*****************************************************************************/
371 SDL_bool
RPI_GetWindowWMInfo(_THIS,SDL_Window * window,struct SDL_SysWMinfo * info)372 RPI_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info)
373 {
374 if (info->version.major <= SDL_MAJOR_VERSION) {
375 return SDL_TRUE;
376 } else {
377 SDL_SetError("application not compiled with SDL %d.%d\n",
378 SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
379 return SDL_FALSE;
380 }
381
382 /* Failed to get window manager information */
383 return SDL_FALSE;
384 }
385
386 #endif /* SDL_VIDEO_DRIVER_RPI */
387
388 /* vi: set ts=4 sw=4 expandtab: */
389