mirror of
https://github.com/Ryujinx/SDL.git
synced 2025-01-21 11:01:04 +00:00
415 lines
13 KiB
C
415 lines
13 KiB
C
/*
|
|
Simple DirectMedia Layer
|
|
Copyright (C) 1997-2017 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: */
|