1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 2017 BlackBerry Limited
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 #include "../SDL_sysvideo.h"
23 #include "sdl_qnx.h"
24 
25 static screen_context_t context;
26 static screen_event_t   event;
27 
28 /**
29  * Initializes the QNX video plugin.
30  * Creates the Screen context and event handles used for all window operations
31  * by the plugin.
32  * @param   _THIS
33  * @return  0 if successful, -1 on error
34  */
35 static int
videoInit(_THIS)36 videoInit(_THIS)
37 {
38     SDL_VideoDisplay display;
39 
40     if (screen_create_context(&context, 0) < 0) {
41         return -1;
42     }
43 
44     if (screen_create_event(&event) < 0) {
45         return -1;
46     }
47 
48     SDL_zero(display);
49 
50     if (SDL_AddVideoDisplay(&display) < 0) {
51         return -1;
52     }
53 
54     _this->num_displays = 1;
55     return 0;
56 }
57 
58 static void
videoQuit(_THIS)59 videoQuit(_THIS)
60 {
61 }
62 
63 /**
64  * Creates a new native Screen window and associates it with the given SDL
65  * window.
66  * @param   _THIS
67  * @param   window  SDL window to initialize
68  * @return  0 if successful, -1 on error
69  */
70 static int
createWindow(_THIS,SDL_Window * window)71 createWindow(_THIS, SDL_Window *window)
72 {
73     window_impl_t   *impl;
74     int             size[2];
75     int             numbufs;
76     int             format;
77     int             usage;
78 
79     impl = SDL_calloc(1, sizeof(*impl));
80     if (impl == NULL) {
81         return -1;
82     }
83 
84     // Create a native window.
85     if (screen_create_window(&impl->window, context) < 0) {
86         goto fail;
87     }
88 
89     // Set the native window's size to match the SDL window.
90     size[0] = window->w;
91     size[1] = window->h;
92 
93     if (screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_SIZE,
94                                       size) < 0) {
95         goto fail;
96     }
97 
98     if (screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_SOURCE_SIZE,
99                                       size) < 0) {
100         goto fail;
101     }
102 
103     // Create window buffer(s).
104     if (window->flags & SDL_WINDOW_OPENGL) {
105         if (glGetConfig(&impl->conf, &format) < 0) {
106             goto fail;
107         }
108         numbufs = 2;
109 
110         usage = SCREEN_USAGE_OPENGL_ES2;
111         if (screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_USAGE,
112                                           &usage) < 0) {
113             return -1;
114         }
115     } else {
116         format = SCREEN_FORMAT_RGBX8888;
117         numbufs = 1;
118     }
119 
120     // Set pixel format.
121     if (screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_FORMAT,
122                                       &format) < 0) {
123         goto fail;
124     }
125 
126     // Create buffer(s).
127     if (screen_create_window_buffers(impl->window, numbufs) < 0) {
128         goto fail;
129     }
130 
131     window->driverdata = impl;
132     return 0;
133 
134 fail:
135     if (impl->window) {
136         screen_destroy_window(impl->window);
137     }
138 
139     SDL_free(impl);
140     return -1;
141 }
142 
143 /**
144  * Gets a pointer to the Screen buffer associated with the given window. Note
145  * that the buffer is actually created in createWindow().
146  * @param       _THIS
147  * @param       window  SDL window to get the buffer for
148  * @param[out]  pixles  Holds a pointer to the window's buffer
149  * @param[out]  format  Holds the pixel format for the buffer
150  * @param[out]  pitch   Holds the number of bytes per line
151  * @return  0 if successful, -1 on error
152  */
153 static int
createWindowFramebuffer(_THIS,SDL_Window * window,Uint32 * format,void ** pixels,int * pitch)154 createWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format,
155                         void ** pixels, int *pitch)
156 {
157     window_impl_t   *impl = (window_impl_t *)window->driverdata;
158     screen_buffer_t buffer;
159 
160     // Get a pointer to the buffer's memory.
161     if (screen_get_window_property_pv(impl->window, SCREEN_PROPERTY_BUFFERS,
162                                       (void **)&buffer) < 0) {
163         return -1;
164     }
165 
166     if (screen_get_buffer_property_pv(buffer, SCREEN_PROPERTY_POINTER,
167                                       pixels) < 0) {
168         return -1;
169     }
170 
171     // Set format and pitch.
172     if (screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_STRIDE,
173                                       pitch) < 0) {
174         return -1;
175     }
176 
177     *format = SDL_PIXELFORMAT_RGB888;
178     return 0;
179 }
180 
181 /**
182  * Informs the window manager that the window needs to be updated.
183  * @param   _THIS
184  * @param   window      The window to update
185  * @param   rects       An array of reectangular areas to update
186  * @param   numrects    Rect array length
187  * @return  0 if successful, -1 on error
188  */
189 static int
updateWindowFramebuffer(_THIS,SDL_Window * window,const SDL_Rect * rects,int numrects)190 updateWindowFramebuffer(_THIS, SDL_Window *window, const SDL_Rect *rects,
191                         int numrects)
192 {
193     window_impl_t   *impl = (window_impl_t *)window->driverdata;
194     screen_buffer_t buffer;
195 
196     if (screen_get_window_property_pv(impl->window, SCREEN_PROPERTY_BUFFERS,
197                                       (void **)&buffer) < 0) {
198         return -1;
199     }
200 
201     screen_post_window(impl->window, buffer, numrects, (int *)rects, 0);
202     screen_flush_context(context, 0);
203     return 0;
204 }
205 
206 /**
207  * Runs the main event loop.
208  * @param   _THIS
209  */
210 static void
pumpEvents(_THIS)211 pumpEvents(_THIS)
212 {
213     int             type;
214 
215     for (;;) {
216         if (screen_get_event(context, event, 0) < 0) {
217             break;
218         }
219 
220         if (screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type)
221             < 0) {
222             break;
223         }
224 
225         if (type == SCREEN_EVENT_NONE) {
226             break;
227         }
228 
229         switch (type) {
230         case SCREEN_EVENT_KEYBOARD:
231             handleKeyboardEvent(event);
232             break;
233 
234         default:
235             break;
236         }
237     }
238 }
239 
240 /**
241  * Updates the size of the native window using the geometry of the SDL window.
242  * @param   _THIS
243  * @param   window  SDL window to update
244  */
245 static void
setWindowSize(_THIS,SDL_Window * window)246 setWindowSize(_THIS, SDL_Window *window)
247 {
248     window_impl_t   *impl = (window_impl_t *)window->driverdata;
249     int             size[2];
250 
251     size[0] = window->w;
252     size[1] = window->h;
253 
254     screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_SIZE, size);
255     screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_SOURCE_SIZE,
256                                   size);
257 }
258 
259 /**
260  * Makes the native window associated with the given SDL window visible.
261  * @param   _THIS
262  * @param   window  SDL window to update
263  */
264 static void
showWindow(_THIS,SDL_Window * window)265 showWindow(_THIS, SDL_Window *window)
266 {
267     window_impl_t   *impl = (window_impl_t *)window->driverdata;
268     const int       visible = 1;
269 
270     screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_VISIBLE,
271                                   &visible);
272 }
273 
274 /**
275  * Makes the native window associated with the given SDL window invisible.
276  * @param   _THIS
277  * @param   window  SDL window to update
278  */
279 static void
hideWindow(_THIS,SDL_Window * window)280 hideWindow(_THIS, SDL_Window *window)
281 {
282     window_impl_t   *impl = (window_impl_t *)window->driverdata;
283     const int       visible = 0;
284 
285     screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_VISIBLE,
286         &visible);
287 }
288 
289 /**
290  * Destroys the native window associated with the given SDL window.
291  * @param   _THIS
292  * @param   window  SDL window that is being destroyed
293  */
294 static void
destroyWindow(_THIS,SDL_Window * window)295 destroyWindow(_THIS, SDL_Window *window)
296 {
297     window_impl_t   *impl = (window_impl_t *)window->driverdata;
298 
299     if (impl) {
300         screen_destroy_window(impl->window);
301         window->driverdata = NULL;
302     }
303 }
304 
305 /**
306  * Frees the plugin object created by createDevice().
307  * @param   device  Plugin object to free
308  */
309 static void
deleteDevice(SDL_VideoDevice * device)310 deleteDevice(SDL_VideoDevice *device)
311 {
312     SDL_free(device);
313 }
314 
315 /**
316  * Creates the QNX video plugin used by SDL.
317  * @param   devindex    Unused
318  * @return  Initialized device if successful, NULL otherwise
319  */
320 static SDL_VideoDevice *
createDevice(int devindex)321 createDevice(int devindex)
322 {
323     SDL_VideoDevice *device;
324 
325     device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
326     if (device == NULL) {
327         return NULL;
328     }
329 
330     device->driverdata = NULL;
331     device->VideoInit = videoInit;
332     device->VideoQuit = videoQuit;
333     device->CreateSDLWindow = createWindow;
334     device->CreateWindowFramebuffer = createWindowFramebuffer;
335     device->UpdateWindowFramebuffer = updateWindowFramebuffer;
336     device->SetWindowSize = setWindowSize;
337     device->ShowWindow = showWindow;
338     device->HideWindow = hideWindow;
339     device->PumpEvents = pumpEvents;
340     device->DestroyWindow = destroyWindow;
341 
342     device->GL_LoadLibrary = glLoadLibrary;
343     device->GL_GetProcAddress = glGetProcAddress;
344     device->GL_CreateContext = glCreateContext;
345     device->GL_SetSwapInterval = glSetSwapInterval;
346     device->GL_SwapWindow = glSwapWindow;
347     device->GL_MakeCurrent = glMakeCurrent;
348     device->GL_DeleteContext = glDeleteContext;
349     device->GL_UnloadLibrary = glUnloadLibrary;
350 
351     device->free = deleteDevice;
352     return device;
353 }
354 
355 static int
available()356 available()
357 {
358     return 1;
359 }
360 
361 VideoBootStrap QNX_bootstrap = {
362     "qnx", "QNX Screen",
363     available, createDevice
364 };
365