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_DIRECTFB
24
25 #include "SDL_DirectFB_video.h"
26 #include "SDL_DirectFB_modes.h"
27
28 #define DFB_MAX_MODES 200
29
30 struct screen_callback_t
31 {
32 int numscreens;
33 DFBScreenID screenid[DFB_MAX_SCREENS];
34 DFBDisplayLayerID gralayer[DFB_MAX_SCREENS];
35 DFBDisplayLayerID vidlayer[DFB_MAX_SCREENS];
36 int aux; /* auxiliary integer for callbacks */
37 };
38
39 struct modes_callback_t
40 {
41 int nummodes;
42 SDL_DisplayMode *modelist;
43 };
44
45 static DFBEnumerationResult
EnumModesCallback(int width,int height,int bpp,void * data)46 EnumModesCallback(int width, int height, int bpp, void *data)
47 {
48 struct modes_callback_t *modedata = (struct modes_callback_t *) data;
49 SDL_DisplayMode mode;
50
51 mode.w = width;
52 mode.h = height;
53 mode.refresh_rate = 0;
54 mode.driverdata = NULL;
55 mode.format = SDL_PIXELFORMAT_UNKNOWN;
56
57 if (modedata->nummodes < DFB_MAX_MODES) {
58 modedata->modelist[modedata->nummodes++] = mode;
59 }
60
61 return DFENUM_OK;
62 }
63
64 static DFBEnumerationResult
EnumScreensCallback(DFBScreenID screen_id,DFBScreenDescription desc,void * callbackdata)65 EnumScreensCallback(DFBScreenID screen_id, DFBScreenDescription desc,
66 void *callbackdata)
67 {
68 struct screen_callback_t *devdata = (struct screen_callback_t *) callbackdata;
69
70 devdata->screenid[devdata->numscreens++] = screen_id;
71 return DFENUM_OK;
72 }
73
74 static DFBEnumerationResult
EnumLayersCallback(DFBDisplayLayerID layer_id,DFBDisplayLayerDescription desc,void * callbackdata)75 EnumLayersCallback(DFBDisplayLayerID layer_id, DFBDisplayLayerDescription desc,
76 void *callbackdata)
77 {
78 struct screen_callback_t *devdata = (struct screen_callback_t *) callbackdata;
79
80 if (desc.caps & DLCAPS_SURFACE) {
81 if ((desc.type & DLTF_GRAPHICS) && (desc.type & DLTF_VIDEO)) {
82 if (devdata->vidlayer[devdata->aux] == -1)
83 devdata->vidlayer[devdata->aux] = layer_id;
84 } else if (desc.type & DLTF_GRAPHICS) {
85 if (devdata->gralayer[devdata->aux] == -1)
86 devdata->gralayer[devdata->aux] = layer_id;
87 }
88 }
89 return DFENUM_OK;
90 }
91
92 static void
CheckSetDisplayMode(_THIS,SDL_VideoDisplay * display,DFB_DisplayData * data,SDL_DisplayMode * mode)93 CheckSetDisplayMode(_THIS, SDL_VideoDisplay * display, DFB_DisplayData * data, SDL_DisplayMode * mode)
94 {
95 SDL_DFB_DEVICEDATA(_this);
96 DFBDisplayLayerConfig config;
97 DFBDisplayLayerConfigFlags failed;
98
99 SDL_DFB_CHECKERR(data->layer->SetCooperativeLevel(data->layer,
100 DLSCL_ADMINISTRATIVE));
101 config.width = mode->w;
102 config.height = mode->h;
103 config.pixelformat = DirectFB_SDLToDFBPixelFormat(mode->format);
104 config.flags = DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT;
105 if (devdata->use_yuv_underlays) {
106 config.flags |= DLCONF_OPTIONS;
107 config.options = DLOP_ALPHACHANNEL;
108 }
109 failed = 0;
110 data->layer->TestConfiguration(data->layer, &config, &failed);
111 SDL_DFB_CHECKERR(data->layer->SetCooperativeLevel(data->layer,
112 DLSCL_SHARED));
113 if (failed == 0)
114 {
115 SDL_AddDisplayMode(display, mode);
116 SDL_DFB_LOG("Mode %d x %d Added\n", mode->w, mode->h);
117 }
118 else
119 SDL_DFB_ERR("Mode %d x %d not available: %x\n", mode->w,
120 mode->h, failed);
121
122 return;
123 error:
124 return;
125 }
126
127
128 void
DirectFB_SetContext(_THIS,SDL_Window * window)129 DirectFB_SetContext(_THIS, SDL_Window *window)
130 {
131 #if (DFB_VERSION_ATLEAST(1,0,0))
132 /* FIXME: does not work on 1.0/1.2 with radeon driver
133 * the approach did work with the matrox driver
134 * This has simply no effect.
135 */
136
137 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
138 DFB_DisplayData *dispdata = (DFB_DisplayData *) display->driverdata;
139
140 /* FIXME: should we handle the error */
141 if (dispdata->vidIDinuse)
142 SDL_DFB_CHECK(dispdata->vidlayer->SwitchContext(dispdata->vidlayer,
143 DFB_TRUE));
144 #endif
145 }
146
147 void
DirectFB_InitModes(_THIS)148 DirectFB_InitModes(_THIS)
149 {
150 SDL_DFB_DEVICEDATA(_this);
151 IDirectFBDisplayLayer *layer = NULL;
152 SDL_VideoDisplay display;
153 DFB_DisplayData *dispdata = NULL;
154 SDL_DisplayMode mode;
155 DFBGraphicsDeviceDescription caps;
156 DFBDisplayLayerConfig dlc;
157 struct screen_callback_t *screencbdata;
158
159 int tcw[DFB_MAX_SCREENS];
160 int tch[DFB_MAX_SCREENS];
161 int i;
162 DFBResult ret;
163
164 SDL_DFB_ALLOC_CLEAR(screencbdata, sizeof(*screencbdata));
165
166 screencbdata->numscreens = 0;
167
168 for (i = 0; i < DFB_MAX_SCREENS; i++) {
169 screencbdata->gralayer[i] = -1;
170 screencbdata->vidlayer[i] = -1;
171 }
172
173 SDL_DFB_CHECKERR(devdata->dfb->EnumScreens(devdata->dfb, &EnumScreensCallback,
174 screencbdata));
175
176 for (i = 0; i < screencbdata->numscreens; i++) {
177 IDirectFBScreen *screen;
178
179 SDL_DFB_CHECKERR(devdata->dfb->GetScreen(devdata->dfb,
180 screencbdata->screenid
181 [i], &screen));
182
183 screencbdata->aux = i;
184 SDL_DFB_CHECKERR(screen->EnumDisplayLayers(screen, &EnumLayersCallback,
185 screencbdata));
186 screen->GetSize(screen, &tcw[i], &tch[i]);
187
188 screen->Release(screen);
189 }
190
191 /* Query card capabilities */
192
193 devdata->dfb->GetDeviceDescription(devdata->dfb, &caps);
194
195 for (i = 0; i < screencbdata->numscreens; i++) {
196 SDL_DFB_CHECKERR(devdata->dfb->GetDisplayLayer(devdata->dfb,
197 screencbdata->gralayer
198 [i], &layer));
199
200 SDL_DFB_CHECKERR(layer->SetCooperativeLevel(layer,
201 DLSCL_ADMINISTRATIVE));
202 layer->EnableCursor(layer, 1);
203 SDL_DFB_CHECKERR(layer->SetCursorOpacity(layer, 0xC0));
204
205 if (devdata->use_yuv_underlays) {
206 dlc.flags = DLCONF_PIXELFORMAT | DLCONF_OPTIONS;
207 dlc.pixelformat = DSPF_ARGB;
208 dlc.options = DLOP_ALPHACHANNEL;
209
210 ret = layer->SetConfiguration(layer, &dlc);
211 if (ret != DFB_OK) {
212 /* try AiRGB if the previous failed */
213 dlc.pixelformat = DSPF_AiRGB;
214 SDL_DFB_CHECKERR(layer->SetConfiguration(layer, &dlc));
215 }
216 }
217
218 /* Query layer configuration to determine the current mode and pixelformat */
219 dlc.flags = DLCONF_ALL;
220 SDL_DFB_CHECKERR(layer->GetConfiguration(layer, &dlc));
221
222 mode.format = DirectFB_DFBToSDLPixelFormat(dlc.pixelformat);
223
224 if (mode.format == SDL_PIXELFORMAT_UNKNOWN) {
225 SDL_DFB_ERR("Unknown dfb pixelformat %x !\n", dlc.pixelformat);
226 goto error;
227 }
228
229 mode.w = dlc.width;
230 mode.h = dlc.height;
231 mode.refresh_rate = 0;
232 mode.driverdata = NULL;
233
234 SDL_DFB_ALLOC_CLEAR(dispdata, sizeof(*dispdata));
235
236 dispdata->layer = layer;
237 dispdata->pixelformat = dlc.pixelformat;
238 dispdata->cw = tcw[i];
239 dispdata->ch = tch[i];
240
241 /* YUV - Video layer */
242
243 dispdata->vidID = screencbdata->vidlayer[i];
244 dispdata->vidIDinuse = 0;
245
246 SDL_zero(display);
247
248 display.desktop_mode = mode;
249 display.current_mode = mode;
250 display.driverdata = dispdata;
251
252 #if (DFB_VERSION_ATLEAST(1,2,0))
253 dlc.flags =
254 DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT |
255 DLCONF_OPTIONS;
256 ret = layer->SetConfiguration(layer, &dlc);
257 #endif
258
259 SDL_DFB_CHECKERR(layer->SetCooperativeLevel(layer, DLSCL_SHARED));
260
261 SDL_AddVideoDisplay(&display);
262 }
263 SDL_DFB_FREE(screencbdata);
264 return;
265 error:
266 /* FIXME: Cleanup not complete, Free existing displays */
267 SDL_DFB_FREE(dispdata);
268 SDL_DFB_RELEASE(layer);
269 return;
270 }
271
272 void
DirectFB_GetDisplayModes(_THIS,SDL_VideoDisplay * display)273 DirectFB_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
274 {
275 SDL_DFB_DEVICEDATA(_this);
276 DFB_DisplayData *dispdata = (DFB_DisplayData *) display->driverdata;
277 SDL_DisplayMode mode;
278 struct modes_callback_t data;
279 int i;
280
281 data.nummodes = 0;
282 /* Enumerate the available fullscreen modes */
283 SDL_DFB_CALLOC(data.modelist, DFB_MAX_MODES, sizeof(SDL_DisplayMode));
284 SDL_DFB_CHECKERR(devdata->dfb->EnumVideoModes(devdata->dfb,
285 EnumModesCallback, &data));
286
287 for (i = 0; i < data.nummodes; ++i) {
288 mode = data.modelist[i];
289
290 mode.format = SDL_PIXELFORMAT_ARGB8888;
291 CheckSetDisplayMode(_this, display, dispdata, &mode);
292 mode.format = SDL_PIXELFORMAT_RGB888;
293 CheckSetDisplayMode(_this, display, dispdata, &mode);
294 mode.format = SDL_PIXELFORMAT_RGB24;
295 CheckSetDisplayMode(_this, display, dispdata, &mode);
296 mode.format = SDL_PIXELFORMAT_RGB565;
297 CheckSetDisplayMode(_this, display, dispdata, &mode);
298 mode.format = SDL_PIXELFORMAT_INDEX8;
299 CheckSetDisplayMode(_this, display, dispdata, &mode);
300 }
301
302 SDL_DFB_FREE(data.modelist);
303 error:
304 return;
305 }
306
307 int
DirectFB_SetDisplayMode(_THIS,SDL_VideoDisplay * display,SDL_DisplayMode * mode)308 DirectFB_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
309 {
310 /*
311 * FIXME: video mode switch is currently broken for 1.2.0
312 *
313 */
314
315 SDL_DFB_DEVICEDATA(_this);
316 DFB_DisplayData *data = (DFB_DisplayData *) display->driverdata;
317 DFBDisplayLayerConfig config, rconfig;
318 DFBDisplayLayerConfigFlags fail = 0;
319
320 SDL_DFB_CHECKERR(data->layer->SetCooperativeLevel(data->layer,
321 DLSCL_ADMINISTRATIVE));
322
323 SDL_DFB_CHECKERR(data->layer->GetConfiguration(data->layer, &config));
324 config.flags = DLCONF_WIDTH | DLCONF_HEIGHT;
325 if (mode->format != SDL_PIXELFORMAT_UNKNOWN) {
326 config.flags |= DLCONF_PIXELFORMAT;
327 config.pixelformat = DirectFB_SDLToDFBPixelFormat(mode->format);
328 data->pixelformat = config.pixelformat;
329 }
330 config.width = mode->w;
331 config.height = mode->h;
332
333 if (devdata->use_yuv_underlays) {
334 config.flags |= DLCONF_OPTIONS;
335 config.options = DLOP_ALPHACHANNEL;
336 }
337
338 data->layer->TestConfiguration(data->layer, &config, &fail);
339
340 if (fail &
341 (DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT |
342 DLCONF_OPTIONS)) {
343 SDL_DFB_ERR("Error setting mode %dx%d-%x\n", mode->w, mode->h,
344 mode->format);
345 return -1;
346 }
347
348 config.flags &= ~fail;
349 SDL_DFB_CHECKERR(data->layer->SetConfiguration(data->layer, &config));
350 #if (DFB_VERSION_ATLEAST(1,2,0))
351 /* Need to call this twice ! */
352 SDL_DFB_CHECKERR(data->layer->SetConfiguration(data->layer, &config));
353 #endif
354
355 /* Double check */
356 SDL_DFB_CHECKERR(data->layer->GetConfiguration(data->layer, &rconfig));
357 SDL_DFB_CHECKERR(data->
358 layer->SetCooperativeLevel(data->layer, DLSCL_SHARED));
359
360 if ((config.width != rconfig.width) || (config.height != rconfig.height)
361 || ((mode->format != SDL_PIXELFORMAT_UNKNOWN)
362 && (config.pixelformat != rconfig.pixelformat))) {
363 SDL_DFB_ERR("Error setting mode %dx%d-%x\n", mode->w, mode->h,
364 mode->format);
365 return -1;
366 }
367
368 data->pixelformat = rconfig.pixelformat;
369 data->cw = config.width;
370 data->ch = config.height;
371 display->current_mode = *mode;
372
373 return 0;
374 error:
375 return -1;
376 }
377
378 void
DirectFB_QuitModes(_THIS)379 DirectFB_QuitModes(_THIS)
380 {
381 SDL_DisplayMode tmode;
382 int i;
383
384 for (i = 0; i < _this->num_displays; ++i) {
385 SDL_VideoDisplay *display = &_this->displays[i];
386 DFB_DisplayData *dispdata = (DFB_DisplayData *) display->driverdata;
387
388 SDL_GetDesktopDisplayMode(i, &tmode);
389 tmode.format = SDL_PIXELFORMAT_UNKNOWN;
390 DirectFB_SetDisplayMode(_this, display, &tmode);
391
392 SDL_GetDesktopDisplayMode(i, &tmode);
393 DirectFB_SetDisplayMode(_this, display, &tmode);
394
395 if (dispdata->layer) {
396 SDL_DFB_CHECK(dispdata->
397 layer->SetCooperativeLevel(dispdata->layer,
398 DLSCL_ADMINISTRATIVE));
399 SDL_DFB_CHECK(dispdata->
400 layer->SetCursorOpacity(dispdata->layer, 0x00));
401 SDL_DFB_CHECK(dispdata->
402 layer->SetCooperativeLevel(dispdata->layer,
403 DLSCL_SHARED));
404 }
405
406 SDL_DFB_RELEASE(dispdata->layer);
407 SDL_DFB_RELEASE(dispdata->vidlayer);
408
409 }
410 }
411
412 #endif /* SDL_VIDEO_DRIVER_DIRECTFB */
413
414 /* vi: set ts=4 sw=4 expandtab: */
415