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