Mercurial > sdl-ios-xcode
diff src/video/directfb/SDL_DirectFB_modes.c @ 2737:140a7edcf2bd
Date: Sun, 31 Aug 2008 17:53:59 +0200
From: Couriersud
Subject: Re: Updated DirectFB driver for SDL1.3
attached is a patch which brings the directfb driver in line with
current svn. In addition:
* driver now is in line with the structure of the X11 driver.
This adds a couple of files.
* driver now supports relative mouse movements
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sun, 31 Aug 2008 16:04:32 +0000 |
parents | |
children | e759ad5e6f43 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/directfb/SDL_DirectFB_modes.c Sun Aug 31 16:04:32 2008 +0000 @@ -0,0 +1,507 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2006 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "SDL_DirectFB_video.h" + +#define DFB_MAX_MODES 200 + +struct scn_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 int +DFBToSDLPixelFormat(DFBSurfacePixelFormat pixelformat, Uint32 * fmt) +{ + switch (pixelformat) { + case DSPF_ALUT44: + *fmt = SDL_PIXELFORMAT_INDEX4LSB; + break; + case DSPF_LUT8: + *fmt = SDL_PIXELFORMAT_INDEX8; + break; + case DSPF_RGB332: + *fmt = SDL_PIXELFORMAT_RGB332; + break; + case DSPF_ARGB4444: + *fmt = SDL_PIXELFORMAT_ARGB4444; + break; + case SDL_PIXELFORMAT_ARGB1555: + *fmt = SDL_PIXELFORMAT_ARGB1555; + break; + case DSPF_RGB16: + *fmt = SDL_PIXELFORMAT_RGB565; + break; + case DSPF_RGB24: + *fmt = SDL_PIXELFORMAT_RGB24; + break; + case DSPF_RGB32: + *fmt = SDL_PIXELFORMAT_RGB888; + break; + case DSPF_ARGB: + *fmt = SDL_PIXELFORMAT_ARGB8888; + break; + case DSPF_YV12: + *fmt = SDL_PIXELFORMAT_YV12; + break; /* Planar mode: Y + V + U (3 planes) */ + case DSPF_I420: + *fmt = SDL_PIXELFORMAT_IYUV; + break; /* Planar mode: Y + U + V (3 planes) */ + case DSPF_YUY2: + *fmt = SDL_PIXELFORMAT_YUY2; + break; /* Packed mode: Y0+U0+Y1+V0 (1 plane) */ + case DSPF_UYVY: + *fmt = SDL_PIXELFORMAT_UYVY; + break; /* Packed mode: U0+Y0+V0+Y1 (1 plane) */ + default: + return -1; + } + return 0; +} + +static DFBSurfacePixelFormat +SDLToDFBPixelFormat(Uint32 format) +{ + switch (format) { + case SDL_PIXELFORMAT_INDEX4LSB: + return DSPF_ALUT44; + case SDL_PIXELFORMAT_INDEX8: + return DSPF_LUT8; + case SDL_PIXELFORMAT_RGB332: + return DSPF_RGB332; + case SDL_PIXELFORMAT_RGB555: + return DSPF_ARGB1555; + case SDL_PIXELFORMAT_ARGB4444: + return DSPF_ARGB4444; + case SDL_PIXELFORMAT_ARGB1555: + return DSPF_ARGB1555; + case SDL_PIXELFORMAT_RGB565: + return DSPF_RGB16; + case SDL_PIXELFORMAT_RGB24: + return DSPF_RGB24; + case SDL_PIXELFORMAT_RGB888: + return DSPF_RGB32; + case SDL_PIXELFORMAT_ARGB8888: + return DSPF_ARGB; + case SDL_PIXELFORMAT_YV12: + return DSPF_YV12; /* Planar mode: Y + V + U (3 planes) */ + case SDL_PIXELFORMAT_IYUV: + return DSPF_I420; /* Planar mode: Y + U + V (3 planes) */ + case SDL_PIXELFORMAT_YUY2: + return DSPF_YUY2; /* Packed mode: Y0+U0+Y1+V0 (1 plane) */ + case SDL_PIXELFORMAT_UYVY: + return DSPF_UYVY; /* Packed mode: U0+Y0+V0+Y1 (1 plane) */ + case SDL_PIXELFORMAT_YVYU: + return DSPF_UNKNOWN; /* Packed mode: Y0+V0+Y1+U0 (1 plane) */ + case SDL_PIXELFORMAT_INDEX1LSB: + return DSPF_UNKNOWN; + case SDL_PIXELFORMAT_INDEX1MSB: + return DSPF_UNKNOWN; + case SDL_PIXELFORMAT_INDEX4MSB: + return DSPF_UNKNOWN; + case SDL_PIXELFORMAT_RGB444: + return DSPF_UNKNOWN; + case SDL_PIXELFORMAT_BGR24: + return DSPF_UNKNOWN; + case SDL_PIXELFORMAT_BGR888: + return DSPF_UNKNOWN; + case SDL_PIXELFORMAT_RGBA8888: + return DSPF_UNKNOWN; + case SDL_PIXELFORMAT_ABGR8888: + return DSPF_UNKNOWN; + case SDL_PIXELFORMAT_BGRA8888: + return DSPF_UNKNOWN; + case SDL_PIXELFORMAT_ARGB2101010: + return DSPF_UNKNOWN; + default: + return DSPF_UNKNOWN; + } +} + +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; + } + + SDL_DFB_DEBUG("w %d h %d bpp %d\n", width, height, bpp); + return DFENUM_OK; +} + +static DFBEnumerationResult +cbScreens(DFBScreenID screen_id, DFBScreenDescription desc, + void *callbackdata) +{ + struct scn_callback_t *devdata = (struct scn_callback_t *) callbackdata; + + devdata->screenid[devdata->numscreens++] = screen_id; + return DFENUM_OK; +} + +DFBEnumerationResult +cbLayers(DFBDisplayLayerID layer_id, DFBDisplayLayerDescription desc, + void *callbackdata) +{ + struct scn_callback_t *devdata = (struct scn_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, DFB_DisplayData * data, SDL_DisplayMode * mode) +{ + SDL_DFB_DEVICEDATA(_this); + DFBDisplayLayerConfig config; + DFBDisplayLayerConfigFlags failed; + int ret; + + SDL_DFB_CHECKERR(data->layer-> + SetCooperativeLevel(data->layer, DLSCL_ADMINISTRATIVE)); + config.width = mode->w; + config.height = mode->h; + config.pixelformat = 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(_this->current_display, mode); + else + SDL_DFB_DEBUG("Mode %d x %d not available: %x\n", mode->w, mode->h, + failed); + + return; + error: + return; +} + +void +DirectFB_InitModes(_THIS) +{ + SDL_DFB_DEVICEDATA(_this); + IDirectFBDisplayLayer *layer = NULL; + SDL_VideoDisplay display; + DFB_DisplayData *dispdata; + SDL_DisplayMode mode; +#if (DIRECTFB_MAJOR_VERSION == 0) && (DIRECTFB_MINOR_VERSION == 9) && (DIRECTFB_MICRO_VERSION < 23) + DFBCardCapabilities caps; +#else + DFBGraphicsDeviceDescription caps; +#endif + DFBDisplayLayerConfig dlc; + struct scn_callback_t *screencbdata; + + int tcw[DFB_MAX_SCREENS]; + int tch[DFB_MAX_SCREENS]; + int i; + DFBResult ret; + + SDL_DFB_CALLOC(screencbdata, 1, 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, &cbScreens, 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, &cbLayers, screencbdata)); +#if (DIRECTFB_MAJOR_VERSION >= 1) + screen->GetSize(screen, &tcw[i], &tch[i]); +#else + /* FIXME: this is only used to center windows + * Should be done otherwise, e.g. get surface from layer + */ + tcw[i] = 800; + tch[i] = 600; +#endif + screen->Release(screen); + } + + /* Query card capabilities */ + + devdata->dfb->GetDeviceDescription(devdata->dfb, &caps); + + SDL_DFB_DEBUG("SDL directfb video driver - %s %s\n", __DATE__, __TIME__); + SDL_DFB_DEBUG("Using %s (%s) driver.\n", caps.name, caps.vendor); + SDL_DFB_DEBUG("Found %d screens\n", devdata->numscreens); + + 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) { + /* try AiRGB if the previous failed */ + dlc.pixelformat = DSPF_AiRGB; + ret = layer->SetConfiguration(layer, &dlc); + } + } + + SDL_DFB_CHECKERR(layer->SetCooperativeLevel(layer, DLSCL_SHARED)); + + /* Query layer configuration to determine the current mode and pixelformat */ + layer->GetConfiguration(layer, &dlc); + + if (DFBToSDLPixelFormat(dlc.pixelformat, &mode.format) != 0) { + 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_CALLOC(dispdata, 1, 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; + + 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_DFB_DEVICEDATA(_this); + DFB_DisplayData *dispdata = + (DFB_DisplayData *) SDL_CurrentDisplay.driverdata; + SDL_DisplayMode mode; + struct modes_callback_t data; + int i; + int ret; + + 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, dispdata, &mode); + mode.format = SDL_PIXELFORMAT_RGB888; + CheckSetDisplayMode(_this, dispdata, &mode); + mode.format = SDL_PIXELFORMAT_RGB24; + CheckSetDisplayMode(_this, dispdata, &mode); + mode.format = SDL_PIXELFORMAT_RGB565; + CheckSetDisplayMode(_this, dispdata, &mode); + mode.format = SDL_PIXELFORMAT_INDEX8; + CheckSetDisplayMode(_this, dispdata, &mode); + } + SDL_DFB_FREE(data.modelist); + return; + error: + SDL_DFB_FREE(data.modelist); + return; +} + +int +DirectFB_SetDisplayMode(_THIS, SDL_DisplayMode * mode) +{ + /* + * FIXME: video mode switch is currently broken for 1.2.0 + * + */ + + SDL_DFB_DEVICEDATA(_this); + DFB_DisplayData *data = (DFB_DisplayData *) SDL_CurrentDisplay.driverdata; + DFBDisplayLayerConfig config, rconfig; + DFBDisplayLayerConfigFlags fail = 0; + DFBResult ret; + + 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 = 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; + } + + SDL_DFB_DEBUG("Trace\n"); + config.flags &= ~fail; + SDL_DFB_CHECKERR(data->layer->SetConfiguration(data->layer, &config)); + + /* 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; + SDL_CurrentDisplay.current_mode = *mode; + + return 0; + error: + return -1; +} + +void +DirectFB_QuitModes(_THIS) +{ + DFB_DeviceData *devdata = (DFB_DeviceData *) _this->driverdata; + SDL_DisplayMode tmode; + DFBResult ret; + int i; + + SDL_SelectVideoDisplay(0); + + SDL_GetDesktopDisplayMode(&tmode); + tmode.format = SDL_PIXELFORMAT_UNKNOWN; + DirectFB_SetDisplayMode(_this, &tmode); + + SDL_GetDesktopDisplayMode(&tmode); + DirectFB_SetDisplayMode(_this, &tmode); + + for (i = 0; i < SDL_GetNumVideoDisplays(); i++) { + DFB_DisplayData *dispdata = + (DFB_DisplayData *) _this->displays[i].driverdata; + + 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); + + } +} + +/* vi: set ts=4 sw=4 expandtab: */