SDL_DirectFB_modes.c (13336B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 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 30struct 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 39struct modes_callback_t 40{ 41 int nummodes; 42 SDL_DisplayMode *modelist; 43}; 44 45static DFBEnumerationResult 46EnumModesCallback(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 64static DFBEnumerationResult 65EnumScreensCallback(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 74static DFBEnumerationResult 75EnumLayersCallback(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 92static void 93CheckSetDisplayMode(_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 128void 129DirectFB_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 147void 148DirectFB_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 272void 273DirectFB_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); 303error: 304 return; 305} 306 307int 308DirectFB_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 378void 379DirectFB_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: */