diff options
Diffstat (limited to 'source/3rd-party/SDL2/src/video/directfb/SDL_DirectFB_modes.c')
-rw-r--r-- | source/3rd-party/SDL2/src/video/directfb/SDL_DirectFB_modes.c | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/source/3rd-party/SDL2/src/video/directfb/SDL_DirectFB_modes.c b/source/3rd-party/SDL2/src/video/directfb/SDL_DirectFB_modes.c new file mode 100644 index 0000000..a3b8b45 --- /dev/null +++ b/source/3rd-party/SDL2/src/video/directfb/SDL_DirectFB_modes.c @@ -0,0 +1,414 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_DIRECTFB + +#include "SDL_DirectFB_video.h" +#include "SDL_DirectFB_modes.h" + +#define DFB_MAX_MODES 200 + +struct screen_callback_t +{ + int numscreens; + DFBScreenID screenid[DFB_MAX_SCREENS]; + DFBDisplayLayerID gralayer[DFB_MAX_SCREENS]; + DFBDisplayLayerID vidlayer[DFB_MAX_SCREENS]; + int aux; /* auxiliary integer for callbacks */ +}; + +struct modes_callback_t +{ + int nummodes; + SDL_DisplayMode *modelist; +}; + +static DFBEnumerationResult +EnumModesCallback(int width, int height, int bpp, void *data) +{ + struct modes_callback_t *modedata = (struct modes_callback_t *) data; + SDL_DisplayMode mode; + + mode.w = width; + mode.h = height; + mode.refresh_rate = 0; + mode.driverdata = NULL; + mode.format = SDL_PIXELFORMAT_UNKNOWN; + + if (modedata->nummodes < DFB_MAX_MODES) { + modedata->modelist[modedata->nummodes++] = mode; + } + + return DFENUM_OK; +} + +static DFBEnumerationResult +EnumScreensCallback(DFBScreenID screen_id, DFBScreenDescription desc, + void *callbackdata) +{ + struct screen_callback_t *devdata = (struct screen_callback_t *) callbackdata; + + devdata->screenid[devdata->numscreens++] = screen_id; + return DFENUM_OK; +} + +static DFBEnumerationResult +EnumLayersCallback(DFBDisplayLayerID layer_id, DFBDisplayLayerDescription desc, + void *callbackdata) +{ + struct screen_callback_t *devdata = (struct screen_callback_t *) callbackdata; + + if (desc.caps & DLCAPS_SURFACE) { + if ((desc.type & DLTF_GRAPHICS) && (desc.type & DLTF_VIDEO)) { + if (devdata->vidlayer[devdata->aux] == -1) + devdata->vidlayer[devdata->aux] = layer_id; + } else if (desc.type & DLTF_GRAPHICS) { + if (devdata->gralayer[devdata->aux] == -1) + devdata->gralayer[devdata->aux] = layer_id; + } + } + return DFENUM_OK; +} + +static void +CheckSetDisplayMode(_THIS, SDL_VideoDisplay * display, DFB_DisplayData * data, SDL_DisplayMode * mode) +{ + SDL_DFB_DEVICEDATA(_this); + DFBDisplayLayerConfig config; + DFBDisplayLayerConfigFlags failed; + + SDL_DFB_CHECKERR(data->layer->SetCooperativeLevel(data->layer, + DLSCL_ADMINISTRATIVE)); + config.width = mode->w; + config.height = mode->h; + config.pixelformat = DirectFB_SDLToDFBPixelFormat(mode->format); + config.flags = DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT; + if (devdata->use_yuv_underlays) { + config.flags |= DLCONF_OPTIONS; + config.options = DLOP_ALPHACHANNEL; + } + failed = 0; + data->layer->TestConfiguration(data->layer, &config, &failed); + SDL_DFB_CHECKERR(data->layer->SetCooperativeLevel(data->layer, + DLSCL_SHARED)); + if (failed == 0) + { + SDL_AddDisplayMode(display, mode); + SDL_DFB_LOG("Mode %d x %d Added\n", mode->w, mode->h); + } + else + SDL_DFB_ERR("Mode %d x %d not available: %x\n", mode->w, + mode->h, failed); + + return; + error: + return; +} + + +void +DirectFB_SetContext(_THIS, SDL_Window *window) +{ +#if (DFB_VERSION_ATLEAST(1,0,0)) + /* FIXME: does not work on 1.0/1.2 with radeon driver + * the approach did work with the matrox driver + * This has simply no effect. + */ + + SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); + DFB_DisplayData *dispdata = (DFB_DisplayData *) display->driverdata; + + /* FIXME: should we handle the error */ + if (dispdata->vidIDinuse) + SDL_DFB_CHECK(dispdata->vidlayer->SwitchContext(dispdata->vidlayer, + DFB_TRUE)); +#endif +} + +void +DirectFB_InitModes(_THIS) +{ + SDL_DFB_DEVICEDATA(_this); + IDirectFBDisplayLayer *layer = NULL; + SDL_VideoDisplay display; + DFB_DisplayData *dispdata = NULL; + SDL_DisplayMode mode; + DFBGraphicsDeviceDescription caps; + DFBDisplayLayerConfig dlc; + struct screen_callback_t *screencbdata; + + int tcw[DFB_MAX_SCREENS]; + int tch[DFB_MAX_SCREENS]; + int i; + DFBResult ret; + + SDL_DFB_ALLOC_CLEAR(screencbdata, sizeof(*screencbdata)); + + screencbdata->numscreens = 0; + + for (i = 0; i < DFB_MAX_SCREENS; i++) { + screencbdata->gralayer[i] = -1; + screencbdata->vidlayer[i] = -1; + } + + SDL_DFB_CHECKERR(devdata->dfb->EnumScreens(devdata->dfb, &EnumScreensCallback, + screencbdata)); + + for (i = 0; i < screencbdata->numscreens; i++) { + IDirectFBScreen *screen; + + SDL_DFB_CHECKERR(devdata->dfb->GetScreen(devdata->dfb, + screencbdata->screenid + [i], &screen)); + + screencbdata->aux = i; + SDL_DFB_CHECKERR(screen->EnumDisplayLayers(screen, &EnumLayersCallback, + screencbdata)); + screen->GetSize(screen, &tcw[i], &tch[i]); + + screen->Release(screen); + } + + /* Query card capabilities */ + + devdata->dfb->GetDeviceDescription(devdata->dfb, &caps); + + for (i = 0; i < screencbdata->numscreens; i++) { + SDL_DFB_CHECKERR(devdata->dfb->GetDisplayLayer(devdata->dfb, + screencbdata->gralayer + [i], &layer)); + + SDL_DFB_CHECKERR(layer->SetCooperativeLevel(layer, + DLSCL_ADMINISTRATIVE)); + layer->EnableCursor(layer, 1); + SDL_DFB_CHECKERR(layer->SetCursorOpacity(layer, 0xC0)); + + if (devdata->use_yuv_underlays) { + dlc.flags = DLCONF_PIXELFORMAT | DLCONF_OPTIONS; + dlc.pixelformat = DSPF_ARGB; + dlc.options = DLOP_ALPHACHANNEL; + + ret = layer->SetConfiguration(layer, &dlc); + if (ret != DFB_OK) { + /* try AiRGB if the previous failed */ + dlc.pixelformat = DSPF_AiRGB; + SDL_DFB_CHECKERR(layer->SetConfiguration(layer, &dlc)); + } + } + + /* Query layer configuration to determine the current mode and pixelformat */ + dlc.flags = DLCONF_ALL; + SDL_DFB_CHECKERR(layer->GetConfiguration(layer, &dlc)); + + mode.format = DirectFB_DFBToSDLPixelFormat(dlc.pixelformat); + + if (mode.format == SDL_PIXELFORMAT_UNKNOWN) { + SDL_DFB_ERR("Unknown dfb pixelformat %x !\n", dlc.pixelformat); + goto error; + } + + mode.w = dlc.width; + mode.h = dlc.height; + mode.refresh_rate = 0; + mode.driverdata = NULL; + + SDL_DFB_ALLOC_CLEAR(dispdata, sizeof(*dispdata)); + + dispdata->layer = layer; + dispdata->pixelformat = dlc.pixelformat; + dispdata->cw = tcw[i]; + dispdata->ch = tch[i]; + + /* YUV - Video layer */ + + dispdata->vidID = screencbdata->vidlayer[i]; + dispdata->vidIDinuse = 0; + + SDL_zero(display); + + display.desktop_mode = mode; + display.current_mode = mode; + display.driverdata = dispdata; + +#if (DFB_VERSION_ATLEAST(1,2,0)) + dlc.flags = + DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT | + DLCONF_OPTIONS; + ret = layer->SetConfiguration(layer, &dlc); +#endif + + SDL_DFB_CHECKERR(layer->SetCooperativeLevel(layer, DLSCL_SHARED)); + + SDL_AddVideoDisplay(&display); + } + SDL_DFB_FREE(screencbdata); + return; + error: + /* FIXME: Cleanup not complete, Free existing displays */ + SDL_DFB_FREE(dispdata); + SDL_DFB_RELEASE(layer); + return; +} + +void +DirectFB_GetDisplayModes(_THIS, SDL_VideoDisplay * display) +{ + SDL_DFB_DEVICEDATA(_this); + DFB_DisplayData *dispdata = (DFB_DisplayData *) display->driverdata; + SDL_DisplayMode mode; + struct modes_callback_t data; + int i; + + data.nummodes = 0; + /* Enumerate the available fullscreen modes */ + SDL_DFB_CALLOC(data.modelist, DFB_MAX_MODES, sizeof(SDL_DisplayMode)); + SDL_DFB_CHECKERR(devdata->dfb->EnumVideoModes(devdata->dfb, + EnumModesCallback, &data)); + + for (i = 0; i < data.nummodes; ++i) { + mode = data.modelist[i]; + + mode.format = SDL_PIXELFORMAT_ARGB8888; + CheckSetDisplayMode(_this, display, dispdata, &mode); + mode.format = SDL_PIXELFORMAT_RGB888; + CheckSetDisplayMode(_this, display, dispdata, &mode); + mode.format = SDL_PIXELFORMAT_RGB24; + CheckSetDisplayMode(_this, display, dispdata, &mode); + mode.format = SDL_PIXELFORMAT_RGB565; + CheckSetDisplayMode(_this, display, dispdata, &mode); + mode.format = SDL_PIXELFORMAT_INDEX8; + CheckSetDisplayMode(_this, display, dispdata, &mode); + } + + SDL_DFB_FREE(data.modelist); +error: + return; +} + +int +DirectFB_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) +{ + /* + * FIXME: video mode switch is currently broken for 1.2.0 + * + */ + + SDL_DFB_DEVICEDATA(_this); + DFB_DisplayData *data = (DFB_DisplayData *) display->driverdata; + DFBDisplayLayerConfig config, rconfig; + DFBDisplayLayerConfigFlags fail = 0; + + SDL_DFB_CHECKERR(data->layer->SetCooperativeLevel(data->layer, + DLSCL_ADMINISTRATIVE)); + + SDL_DFB_CHECKERR(data->layer->GetConfiguration(data->layer, &config)); + config.flags = DLCONF_WIDTH | DLCONF_HEIGHT; + if (mode->format != SDL_PIXELFORMAT_UNKNOWN) { + config.flags |= DLCONF_PIXELFORMAT; + config.pixelformat = DirectFB_SDLToDFBPixelFormat(mode->format); + data->pixelformat = config.pixelformat; + } + config.width = mode->w; + config.height = mode->h; + + if (devdata->use_yuv_underlays) { + config.flags |= DLCONF_OPTIONS; + config.options = DLOP_ALPHACHANNEL; + } + + data->layer->TestConfiguration(data->layer, &config, &fail); + + if (fail & + (DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT | + DLCONF_OPTIONS)) { + SDL_DFB_ERR("Error setting mode %dx%d-%x\n", mode->w, mode->h, + mode->format); + return -1; + } + + config.flags &= ~fail; + SDL_DFB_CHECKERR(data->layer->SetConfiguration(data->layer, &config)); +#if (DFB_VERSION_ATLEAST(1,2,0)) + /* Need to call this twice ! */ + SDL_DFB_CHECKERR(data->layer->SetConfiguration(data->layer, &config)); +#endif + + /* Double check */ + SDL_DFB_CHECKERR(data->layer->GetConfiguration(data->layer, &rconfig)); + SDL_DFB_CHECKERR(data-> + layer->SetCooperativeLevel(data->layer, DLSCL_SHARED)); + + if ((config.width != rconfig.width) || (config.height != rconfig.height) + || ((mode->format != SDL_PIXELFORMAT_UNKNOWN) + && (config.pixelformat != rconfig.pixelformat))) { + SDL_DFB_ERR("Error setting mode %dx%d-%x\n", mode->w, mode->h, + mode->format); + return -1; + } + + data->pixelformat = rconfig.pixelformat; + data->cw = config.width; + data->ch = config.height; + display->current_mode = *mode; + + return 0; + error: + return -1; +} + +void +DirectFB_QuitModes(_THIS) +{ + SDL_DisplayMode tmode; + int i; + + for (i = 0; i < _this->num_displays; ++i) { + SDL_VideoDisplay *display = &_this->displays[i]; + DFB_DisplayData *dispdata = (DFB_DisplayData *) display->driverdata; + + SDL_GetDesktopDisplayMode(i, &tmode); + tmode.format = SDL_PIXELFORMAT_UNKNOWN; + DirectFB_SetDisplayMode(_this, display, &tmode); + + SDL_GetDesktopDisplayMode(i, &tmode); + DirectFB_SetDisplayMode(_this, display, &tmode); + + if (dispdata->layer) { + SDL_DFB_CHECK(dispdata-> + layer->SetCooperativeLevel(dispdata->layer, + DLSCL_ADMINISTRATIVE)); + SDL_DFB_CHECK(dispdata-> + layer->SetCursorOpacity(dispdata->layer, 0x00)); + SDL_DFB_CHECK(dispdata-> + layer->SetCooperativeLevel(dispdata->layer, + DLSCL_SHARED)); + } + + SDL_DFB_RELEASE(dispdata->layer); + SDL_DFB_RELEASE(dispdata->vidlayer); + + } +} + +#endif /* SDL_VIDEO_DRIVER_DIRECTFB */ + +/* vi: set ts=4 sw=4 expandtab: */ |