1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2020 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 SDL_VIDEO_DRIVER_VIVANTE
24 
25 /* SDL internals */
26 #include "../SDL_sysvideo.h"
27 #include "SDL_version.h"
28 #include "SDL_syswm.h"
29 #include "SDL_loadso.h"
30 #include "SDL_events.h"
31 #include "../../events/SDL_events_c.h"
32 
33 #ifdef SDL_INPUT_LINUXEV
34 #include "../../core/linux/SDL_evdev.h"
35 #endif
36 
37 #include "SDL_vivantevideo.h"
38 #include "SDL_vivanteplatform.h"
39 #include "SDL_vivanteopengles.h"
40 #include "SDL_vivantevulkan.h"
41 
42 
43 static int
VIVANTE_Available(void)44 VIVANTE_Available(void)
45 {
46     return 1;
47 }
48 
49 static void
VIVANTE_Destroy(SDL_VideoDevice * device)50 VIVANTE_Destroy(SDL_VideoDevice * device)
51 {
52     if (device->driverdata != NULL) {
53         SDL_free(device->driverdata);
54         device->driverdata = NULL;
55     }
56 }
57 
58 static SDL_VideoDevice *
VIVANTE_Create()59 VIVANTE_Create()
60 {
61     SDL_VideoDevice *device;
62     SDL_VideoData *data;
63 
64     /* Initialize SDL_VideoDevice structure */
65     device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
66     if (device == NULL) {
67         SDL_OutOfMemory();
68         return NULL;
69     }
70 
71     /* Initialize internal data */
72     data = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
73     if (data == NULL) {
74         SDL_OutOfMemory();
75         SDL_free(device);
76         return NULL;
77     }
78 
79     device->driverdata = data;
80 
81     /* Setup amount of available displays */
82     device->num_displays = 0;
83 
84     /* Set device free function */
85     device->free = VIVANTE_Destroy;
86 
87     /* Setup all functions which we can handle */
88     device->VideoInit = VIVANTE_VideoInit;
89     device->VideoQuit = VIVANTE_VideoQuit;
90     device->GetDisplayModes = VIVANTE_GetDisplayModes;
91     device->SetDisplayMode = VIVANTE_SetDisplayMode;
92     device->CreateSDLWindow = VIVANTE_CreateWindow;
93     device->SetWindowTitle = VIVANTE_SetWindowTitle;
94     device->SetWindowPosition = VIVANTE_SetWindowPosition;
95     device->SetWindowSize = VIVANTE_SetWindowSize;
96     device->ShowWindow = VIVANTE_ShowWindow;
97     device->HideWindow = VIVANTE_HideWindow;
98     device->DestroyWindow = VIVANTE_DestroyWindow;
99     device->GetWindowWMInfo = VIVANTE_GetWindowWMInfo;
100 
101 #if SDL_VIDEO_OPENGL_EGL
102     device->GL_LoadLibrary = VIVANTE_GLES_LoadLibrary;
103     device->GL_GetProcAddress = VIVANTE_GLES_GetProcAddress;
104     device->GL_UnloadLibrary = VIVANTE_GLES_UnloadLibrary;
105     device->GL_CreateContext = VIVANTE_GLES_CreateContext;
106     device->GL_MakeCurrent = VIVANTE_GLES_MakeCurrent;
107     device->GL_SetSwapInterval = VIVANTE_GLES_SetSwapInterval;
108     device->GL_GetSwapInterval = VIVANTE_GLES_GetSwapInterval;
109     device->GL_SwapWindow = VIVANTE_GLES_SwapWindow;
110     device->GL_DeleteContext = VIVANTE_GLES_DeleteContext;
111 #endif
112 
113 #if SDL_VIDEO_VULKAN
114     device->Vulkan_LoadLibrary = VIVANTE_Vulkan_LoadLibrary;
115     device->Vulkan_UnloadLibrary = VIVANTE_Vulkan_UnloadLibrary;
116     device->Vulkan_GetInstanceExtensions = VIVANTE_Vulkan_GetInstanceExtensions;
117     device->Vulkan_CreateSurface = VIVANTE_Vulkan_CreateSurface;
118 #endif
119 
120     device->PumpEvents = VIVANTE_PumpEvents;
121 
122     return device;
123 }
124 
125 VideoBootStrap VIVANTE_bootstrap = {
126     "vivante",
127     "Vivante EGL Video Driver",
128     VIVANTE_Available,
129     VIVANTE_Create
130 };
131 
132 /*****************************************************************************/
133 /* SDL Video and Display initialization/handling functions                   */
134 /*****************************************************************************/
135 
136 static int
VIVANTE_AddVideoDisplays(_THIS)137 VIVANTE_AddVideoDisplays(_THIS)
138 {
139     SDL_VideoData *videodata = _this->driverdata;
140     SDL_VideoDisplay display;
141     SDL_DisplayMode current_mode;
142     SDL_DisplayData *data;
143     int pitch = 0, bpp = 0;
144     unsigned long pixels = 0;
145 
146     data = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
147     if (data == NULL) {
148         return SDL_OutOfMemory();
149     }
150 
151     SDL_zero(current_mode);
152 #if SDL_VIDEO_DRIVER_VIVANTE_VDK
153     data->native_display = vdkGetDisplay(videodata->vdk_private);
154 
155     vdkGetDisplayInfo(data->native_display, &current_mode.w, &current_mode.h, &pixels, &pitch, &bpp);
156 #else
157     data->native_display = videodata->fbGetDisplayByIndex(0);
158 
159     videodata->fbGetDisplayInfo(data->native_display, &current_mode.w, &current_mode.h, &pixels, &pitch, &bpp);
160 #endif /* SDL_VIDEO_DRIVER_VIVANTE_VDK */
161 
162     switch (bpp)
163     {
164     default: /* Is another format used? */
165     case 32:
166         current_mode.format = SDL_PIXELFORMAT_ARGB8888;
167         break;
168     case 16:
169         current_mode.format = SDL_PIXELFORMAT_RGB565;
170         break;
171     }
172     /* FIXME: How do we query refresh rate? */
173     current_mode.refresh_rate = 60;
174 
175     SDL_zero(display);
176     display.name = VIVANTE_GetDisplayName(_this);
177     display.desktop_mode = current_mode;
178     display.current_mode = current_mode;
179     display.driverdata = data;
180     SDL_AddVideoDisplay(&display);
181     return 0;
182 }
183 
184 int
VIVANTE_VideoInit(_THIS)185 VIVANTE_VideoInit(_THIS)
186 {
187     SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
188 
189 #if SDL_VIDEO_DRIVER_VIVANTE_VDK
190     videodata->vdk_private = vdkInitialize();
191     if (!videodata->vdk_private) {
192         return SDL_SetError("vdkInitialize() failed");
193     }
194 #else
195     videodata->egl_handle = SDL_LoadObject("libEGL.so.1");
196     if (!videodata->egl_handle) {
197         videodata->egl_handle = SDL_LoadObject("libEGL.so");
198         if (!videodata->egl_handle) {
199             return -1;
200         }
201     }
202 #define LOAD_FUNC(NAME) \
203     videodata->NAME = SDL_LoadFunction(videodata->egl_handle, #NAME); \
204     if (!videodata->NAME) return -1;
205 
206     LOAD_FUNC(fbGetDisplay);
207     LOAD_FUNC(fbGetDisplayByIndex);
208     LOAD_FUNC(fbGetDisplayGeometry);
209     LOAD_FUNC(fbGetDisplayInfo);
210     LOAD_FUNC(fbDestroyDisplay);
211     LOAD_FUNC(fbCreateWindow);
212     LOAD_FUNC(fbGetWindowGeometry);
213     LOAD_FUNC(fbGetWindowInfo);
214     LOAD_FUNC(fbDestroyWindow);
215 #endif
216 
217     if (VIVANTE_SetupPlatform(_this) < 0) {
218         return -1;
219     }
220 
221     if (VIVANTE_AddVideoDisplays(_this) < 0) {
222         return -1;
223     }
224 
225     VIVANTE_UpdateDisplayScale(_this);
226 
227 #ifdef SDL_INPUT_LINUXEV
228     if (SDL_EVDEV_Init() < 0) {
229         return -1;
230     }
231 #endif
232 
233     return 0;
234 }
235 
236 void
VIVANTE_VideoQuit(_THIS)237 VIVANTE_VideoQuit(_THIS)
238 {
239     SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
240 
241 #ifdef SDL_INPUT_LINUXEV
242     SDL_EVDEV_Quit();
243 #endif
244 
245     VIVANTE_CleanupPlatform(_this);
246 
247 #if SDL_VIDEO_DRIVER_VIVANTE_VDK
248     if (videodata->vdk_private) {
249         vdkExit(videodata->vdk_private);
250         videodata->vdk_private = NULL;
251     }
252 #else
253     if (videodata->egl_handle) {
254         SDL_UnloadObject(videodata->egl_handle);
255         videodata->egl_handle = NULL;
256     }
257 #endif
258 }
259 
260 void
VIVANTE_GetDisplayModes(_THIS,SDL_VideoDisplay * display)261 VIVANTE_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
262 {
263     /* Only one display mode available, the current one */
264     SDL_AddDisplayMode(display, &display->current_mode);
265 }
266 
267 int
VIVANTE_SetDisplayMode(_THIS,SDL_VideoDisplay * display,SDL_DisplayMode * mode)268 VIVANTE_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
269 {
270     return 0;
271 }
272 
273 int
VIVANTE_CreateWindow(_THIS,SDL_Window * window)274 VIVANTE_CreateWindow(_THIS, SDL_Window * window)
275 {
276     SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
277     SDL_DisplayData *displaydata;
278     SDL_WindowData *data;
279 
280     displaydata = SDL_GetDisplayDriverData(0);
281 
282     /* Allocate window internal data */
283     data = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
284     if (data == NULL) {
285         return SDL_OutOfMemory();
286     }
287 
288     /* Setup driver data for this window */
289     window->driverdata = data;
290 
291 #if SDL_VIDEO_DRIVER_VIVANTE_VDK
292     data->native_window = vdkCreateWindow(displaydata->native_display, window->x, window->y, window->w, window->h);
293 #else
294     data->native_window = videodata->fbCreateWindow(displaydata->native_display, window->x, window->y, window->w, window->h);
295 #endif
296     if (!data->native_window) {
297         return SDL_SetError("VIVANTE: Can't create native window");
298     }
299 
300 #if SDL_VIDEO_OPENGL_EGL
301     if (window->flags & SDL_WINDOW_OPENGL) {
302         data->egl_surface = SDL_EGL_CreateSurface(_this, data->native_window);
303         if (data->egl_surface == EGL_NO_SURFACE) {
304             return SDL_SetError("VIVANTE: Can't create EGL surface");
305         }
306     } else {
307         data->egl_surface = EGL_NO_SURFACE;
308     }
309 #endif
310 
311     /* Window has been successfully created */
312     return 0;
313 }
314 
315 void
VIVANTE_DestroyWindow(_THIS,SDL_Window * window)316 VIVANTE_DestroyWindow(_THIS, SDL_Window * window)
317 {
318     SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
319     SDL_WindowData *data;
320 
321     data = window->driverdata;
322     if (data) {
323 #if SDL_VIDEO_OPENGL_EGL
324         if (data->egl_surface != EGL_NO_SURFACE) {
325             SDL_EGL_DestroySurface(_this, data->egl_surface);
326         }
327 #endif
328 
329         if (data->native_window) {
330 #if SDL_VIDEO_DRIVER_VIVANTE_VDK
331             vdkDestroyWindow(data->native_window);
332 #else
333             videodata->fbDestroyWindow(data->native_window);
334 #endif
335         }
336 
337         SDL_free(data);
338     }
339     window->driverdata = NULL;
340 }
341 
342 void
VIVANTE_SetWindowTitle(_THIS,SDL_Window * window)343 VIVANTE_SetWindowTitle(_THIS, SDL_Window * window)
344 {
345 #if SDL_VIDEO_DRIVER_VIVANTE_VDK
346     SDL_WindowData *data = window->driverdata;
347     vdkSetWindowTitle(data->native_window, window->title);
348 #endif
349 }
350 
351 void
VIVANTE_SetWindowPosition(_THIS,SDL_Window * window)352 VIVANTE_SetWindowPosition(_THIS, SDL_Window * window)
353 {
354     /* FIXME */
355 }
356 
357 void
VIVANTE_SetWindowSize(_THIS,SDL_Window * window)358 VIVANTE_SetWindowSize(_THIS, SDL_Window * window)
359 {
360     /* FIXME */
361 }
362 
363 void
VIVANTE_ShowWindow(_THIS,SDL_Window * window)364 VIVANTE_ShowWindow(_THIS, SDL_Window * window)
365 {
366 #if SDL_VIDEO_DRIVER_VIVANTE_VDK
367     SDL_WindowData *data = window->driverdata;
368     vdkShowWindow(data->native_window);
369 #endif
370     SDL_SetMouseFocus(window);
371     SDL_SetKeyboardFocus(window);
372 }
373 
374 void
VIVANTE_HideWindow(_THIS,SDL_Window * window)375 VIVANTE_HideWindow(_THIS, SDL_Window * window)
376 {
377 #if SDL_VIDEO_DRIVER_VIVANTE_VDK
378     SDL_WindowData *data = window->driverdata;
379     vdkHideWindow(data->native_window);
380 #endif
381 }
382 
383 /*****************************************************************************/
384 /* SDL Window Manager function                                               */
385 /*****************************************************************************/
386 SDL_bool
VIVANTE_GetWindowWMInfo(_THIS,SDL_Window * window,struct SDL_SysWMinfo * info)387 VIVANTE_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info)
388 {
389     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
390     SDL_DisplayData *displaydata = SDL_GetDisplayDriverData(0);
391 
392     if (info->version.major == SDL_MAJOR_VERSION &&
393         info->version.minor == SDL_MINOR_VERSION) {
394         info->subsystem = SDL_SYSWM_VIVANTE;
395         info->info.vivante.display = displaydata->native_display;
396         info->info.vivante.window = data->native_window;
397         return SDL_TRUE;
398     } else {
399         SDL_SetError("Application not compiled with SDL %d.%d",
400                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
401         return SDL_FALSE;
402     }
403 }
404 
405 /*****************************************************************************/
406 /* SDL event functions                                                       */
407 /*****************************************************************************/
VIVANTE_PumpEvents(_THIS)408 void VIVANTE_PumpEvents(_THIS)
409 {
410 #ifdef SDL_INPUT_LINUXEV
411     SDL_EVDEV_Poll();
412 #endif
413 }
414 
415 #endif /* SDL_VIDEO_DRIVER_VIVANTE */
416 
417 /* vi: set ts=4 sw=4 expandtab: */
418