src/video/directfb/SDL_DirectFB_video.c
author Ryan C. Gordon
Mon, 04 Jun 2007 11:17:46 +0000
changeset 2113 6264c973814a
parent 1895 c121d94672cb
child 2226 0e70b4b8cf84
permissions -rw-r--r--
Merged r3044:3045 from branches/SDL-1.2: directfb reported screen size fix.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 
    22 	MGA CRTC2 support by Thomas Jarosch - tomj@simonv.com
    23 	CRTC2 support is inspired by mplayer's dfbmga driver
    24 	written by Ville Syrj��<syrjala@sci.fi>
    25 */
    26 #include "SDL_config.h"
    27 
    28 /* DirectFB video driver implementation.
    29 */
    30 
    31 #include <fcntl.h>
    32 #include <unistd.h>
    33 #include <sys/mman.h>
    34 
    35 #include <directfb.h>
    36 #include <directfb_version.h>
    37 
    38 #include "SDL_video.h"
    39 #include "SDL_mouse.h"
    40 #include "../SDL_sysvideo.h"
    41 #include "../SDL_pixels_c.h"
    42 #include "../../events/SDL_events_c.h"
    43 #include "SDL_DirectFB_video.h"
    44 #include "SDL_DirectFB_events.h"
    45 #include "SDL_DirectFB_yuv.h"
    46 
    47 /* The implementation dependent data for the window manager cursor */
    48 struct WMcursor
    49 {
    50     int unused;
    51 };
    52 
    53 
    54 /* Initialization/Query functions */
    55 static int DirectFB_VideoInit(_THIS, SDL_PixelFormat * vformat);
    56 static SDL_Rect **DirectFB_ListModes(_THIS, SDL_PixelFormat * format,
    57                                      Uint32 flags);
    58 static SDL_Surface *DirectFB_SetVideoMode(_THIS, SDL_Surface * current,
    59                                           int width, int height, int bpp,
    60                                           Uint32 flags);
    61 static int DirectFB_SetColors(_THIS, int firstcolor, int ncolors,
    62                               SDL_Color * colors);
    63 static void DirectFB_VideoQuit(_THIS);
    64 
    65 /* Hardware surface functions */
    66 static int DirectFB_AllocHWSurface(_THIS, SDL_Surface * surface);
    67 static int DirectFB_FillHWRect(_THIS, SDL_Surface * dst, SDL_Rect * dstrect,
    68                                Uint32 color);
    69 static int DirectFB_LockHWSurface(_THIS, SDL_Surface * surface);
    70 static void DirectFB_UnlockHWSurface(_THIS, SDL_Surface * surface);
    71 static void DirectFB_FreeHWSurface(_THIS, SDL_Surface * surface);
    72 static int DirectFB_CheckHWBlit(_THIS, SDL_Surface * src, SDL_Surface * dst);
    73 static int DirectFB_HWAccelBlit(SDL_Surface * src, SDL_Rect * srcrect,
    74                                 SDL_Surface * dst, SDL_Rect * dstrect);
    75 static int DirectFB_SetHWColorKey(_THIS, SDL_Surface * surface, Uint32 key);
    76 static int DirectFB_SetHWAlpha(_THIS, SDL_Surface * surface, Uint8 alpha);
    77 static int DirectFB_FlipHWSurface(_THIS, SDL_Surface * surface);
    78 static int DirectFB_ShowWMCursor(_THIS, WMcursor * cursor);
    79 
    80 /* Various screen update functions available */
    81 static void DirectFB_DirectUpdate(_THIS, int numrects, SDL_Rect * rects);
    82 static void DirectFB_WindowedUpdate(_THIS, int numrects, SDL_Rect * rects);
    83 
    84 /* This is the rect EnumModes2 uses */
    85 struct DirectFBEnumRect
    86 {
    87     SDL_Rect r;
    88     struct DirectFBEnumRect *next;
    89 };
    90 
    91 static struct DirectFBEnumRect *enumlist = NULL;
    92 
    93 
    94 /* DirectFB driver bootstrap functions */
    95 
    96 static int
    97 DirectFB_Available(void)
    98 {
    99     return 1;
   100 }
   101 
   102 static void
   103 DirectFB_DeleteDevice(SDL_VideoDevice * device)
   104 {
   105     SDL_free(device->hidden);
   106     SDL_free(device);
   107 }
   108 
   109 static SDL_VideoDevice *
   110 DirectFB_CreateDevice(int devindex)
   111 {
   112     SDL_VideoDevice *device;
   113 
   114     /* Initialize all variables that we clean on shutdown */
   115     device = (SDL_VideoDevice *) SDL_malloc(sizeof(SDL_VideoDevice));
   116     if (device) {
   117         SDL_memset(device, 0, (sizeof *device));
   118         device->hidden = (struct SDL_PrivateVideoData *)
   119             malloc(sizeof(*device->hidden));
   120     }
   121     if (device == NULL || device->hidden == NULL) {
   122         SDL_OutOfMemory();
   123         if (device) {
   124             free(device);
   125         }
   126         return (0);
   127     }
   128     SDL_memset(device->hidden, 0, sizeof(*device->hidden));
   129 
   130     /* Set the function pointers */
   131     device->VideoInit = DirectFB_VideoInit;
   132     device->ListModes = DirectFB_ListModes;
   133     device->SetVideoMode = DirectFB_SetVideoMode;
   134     device->SetColors = DirectFB_SetColors;
   135     device->UpdateRects = NULL;
   136     device->CreateYUVOverlay = DirectFB_CreateYUVOverlay;
   137     device->VideoQuit = DirectFB_VideoQuit;
   138     device->AllocHWSurface = DirectFB_AllocHWSurface;
   139     device->CheckHWBlit = DirectFB_CheckHWBlit;
   140     device->FillHWRect = DirectFB_FillHWRect;
   141     device->SetHWColorKey = DirectFB_SetHWColorKey;
   142     device->SetHWAlpha = DirectFB_SetHWAlpha;
   143     device->LockHWSurface = DirectFB_LockHWSurface;
   144     device->UnlockHWSurface = DirectFB_UnlockHWSurface;
   145     device->FlipHWSurface = DirectFB_FlipHWSurface;
   146     device->FreeHWSurface = DirectFB_FreeHWSurface;
   147     device->ShowWMCursor = DirectFB_ShowWMCursor;
   148     device->SetCaption = NULL;
   149     device->SetIcon = NULL;
   150     device->IconifyWindow = NULL;
   151     device->GrabInput = NULL;
   152     device->GetWMInfo = NULL;
   153     device->InitOSKeymap = DirectFB_InitOSKeymap;
   154     device->PumpEvents = DirectFB_PumpEvents;
   155 
   156     device->free = DirectFB_DeleteDevice;
   157 
   158     return device;
   159 }
   160 
   161 VideoBootStrap DirectFB_bootstrap = {
   162     "directfb", "DirectFB",
   163     DirectFB_Available, DirectFB_CreateDevice
   164 };
   165 
   166 static DFBSurfacePixelFormat
   167 GetFormatForBpp(int bpp, IDirectFBDisplayLayer * layer)
   168 {
   169     DFBDisplayLayerConfig dlc;
   170     int bytes = (bpp + 7) / 8;
   171 
   172     layer->GetConfiguration(layer, &dlc);
   173 
   174     if (bytes == DFB_BYTES_PER_PIXEL(dlc.pixelformat) && bytes > 1)
   175         return dlc.pixelformat;
   176 
   177     switch (bytes) {
   178     case 1:
   179         return DSPF_LUT8;
   180     case 2:
   181         return DSPF_RGB16;
   182     case 3:
   183         return DSPF_RGB24;
   184     case 4:
   185         return DSPF_RGB32;
   186     }
   187 
   188     return DSPF_UNKNOWN;
   189 }
   190 
   191 static DFBEnumerationResult
   192 EnumModesCallback(int width, int height, int bpp, void *data)
   193 {
   194     SDL_VideoDevice *this = (SDL_VideoDevice *) data;
   195     struct DirectFBEnumRect *enumrect;
   196 
   197     HIDDEN->nummodes++;
   198 
   199     if (enumlist && enumlist->r.w == width && enumlist->r.h == height)
   200         return DFENUM_OK;
   201 
   202     enumrect = SDL_calloc(1, sizeof(struct DirectFBEnumRect));
   203     if (!enumrect) {
   204         SDL_OutOfMemory();
   205         return DFENUM_CANCEL;
   206     }
   207 
   208     enumrect->r.w = (Uint16) width;
   209     enumrect->r.h = (Uint16) height;
   210     enumrect->next = enumlist;
   211 
   212     enumlist = enumrect;
   213 
   214     return DFENUM_OK;
   215 }
   216 
   217 struct private_hwdata
   218 {
   219     IDirectFBSurface *surface;
   220     IDirectFBPalette *palette;
   221 };
   222 
   223 void
   224 SetDirectFBerror(const char *function, DFBResult code)
   225 {
   226     const char *error = DirectFBErrorString(code);
   227 
   228     if (error)
   229         SDL_SetError("%s: %s", function, error);
   230     else
   231         SDL_SetError("Unknown error code from %s", function);
   232 }
   233 
   234 static DFBSurfacePixelFormat
   235 SDLToDFBPixelFormat(SDL_PixelFormat * format)
   236 {
   237     if (format->Rmask && format->Gmask && format->Bmask) {
   238         switch (format->BitsPerPixel) {
   239         case 8:
   240             return DSPF_LUT8;
   241 
   242         case 16:
   243             if (format->Rmask == 0xF800 &&
   244                 format->Gmask == 0x07E0 && format->Bmask == 0x001F)
   245                 return DSPF_RGB16;
   246             /* fall through */
   247 
   248         case 15:
   249             if (format->Rmask == 0x7C00 &&
   250                 format->Gmask == 0x03E0 && format->Bmask == 0x001F)
   251                 return DSPF_ARGB1555;
   252             break;
   253 
   254         case 24:
   255             if (format->Rmask == 0xFF0000 &&
   256                 format->Gmask == 0x00FF00 && format->Bmask == 0x0000FF)
   257                 return DSPF_RGB24;
   258             break;
   259 
   260         case 32:
   261             if (format->Rmask == 0xFF0000 &&
   262                 format->Gmask == 0x00FF00 && format->Bmask == 0x0000FF) {
   263                 if (format->Amask == 0xFF000000)
   264                     return DSPF_ARGB;
   265                 else
   266                     return DSPF_RGB32;
   267             }
   268             break;
   269         }
   270     } else {
   271         switch (format->BitsPerPixel) {
   272         case 8:
   273             return DSPF_LUT8;
   274         case 15:
   275             return DSPF_ARGB1555;
   276         case 16:
   277             return DSPF_RGB16;
   278         case 24:
   279             return DSPF_RGB24;
   280         case 32:
   281             return DSPF_RGB32;
   282         }
   283     }
   284 
   285     return DSPF_UNKNOWN;
   286 }
   287 
   288 static SDL_Palette *
   289 AllocatePalette(int size)
   290 {
   291     SDL_Palette *palette;
   292     SDL_Color *colors;
   293 
   294     palette = SDL_calloc(1, sizeof(SDL_Palette));
   295     if (!palette) {
   296         SDL_OutOfMemory();
   297         return NULL;
   298     }
   299 
   300     colors = SDL_calloc(size, sizeof(SDL_Color));
   301     if (!colors) {
   302         SDL_OutOfMemory();
   303         return NULL;
   304     }
   305 
   306     palette->ncolors = size;
   307     palette->colors = colors;
   308 
   309     return palette;
   310 }
   311 
   312 static int
   313 DFBToSDLPixelFormat(DFBSurfacePixelFormat pixelformat,
   314                     SDL_PixelFormat * format)
   315 {
   316     format->Amask = format->Rmask = format->Gmask = format->Bmask = 0;
   317     format->BitsPerPixel = format->BytesPerPixel = 0;
   318 
   319     switch (pixelformat) {
   320     case DSPF_A8:
   321         format->Amask = 0x000000FF;
   322         break;
   323 
   324     case DSPF_ARGB1555:
   325         format->Rmask = 0x00007C00;
   326         format->Gmask = 0x000003E0;
   327         format->Bmask = 0x0000001F;
   328         break;
   329 
   330     case DSPF_RGB16:
   331         format->Rmask = 0x0000F800;
   332         format->Gmask = 0x000007E0;
   333         format->Bmask = 0x0000001F;
   334         break;
   335 
   336     case DSPF_ARGB:
   337         format->Amask = 0;      /* apps don't seem to like that:  0xFF000000; */
   338         /* fall through */
   339     case DSPF_RGB24:
   340     case DSPF_RGB32:
   341         format->Rmask = 0x00FF0000;
   342         format->Gmask = 0x0000FF00;
   343         format->Bmask = 0x000000FF;
   344         break;
   345 
   346     case DSPF_LUT8:
   347         format->Rmask = 0x000000FF;
   348         format->Gmask = 0x000000FF;
   349         format->Bmask = 0x000000FF;
   350 
   351         if (!format->palette)
   352             format->palette = AllocatePalette(256);
   353         break;
   354 
   355     default:
   356         fprintf(stderr,
   357                 "SDL_DirectFB: Unsupported pixelformat (0x%08x)!\n",
   358                 pixelformat);
   359         return -1;
   360     }
   361 
   362     format->BitsPerPixel = DFB_BYTES_PER_PIXEL(pixelformat) * 8;
   363     format->BytesPerPixel = DFB_BYTES_PER_PIXEL(pixelformat);
   364 
   365     return 0;
   366 }
   367 
   368 
   369 int
   370 DirectFB_VideoInit(_THIS, SDL_PixelFormat * vformat)
   371 {
   372     int i;
   373     DFBResult ret;
   374 #if (DIRECTFB_MAJOR_VERSION == 0) && (DIRECTFB_MINOR_VERSION == 9) && (DIRECTFB_MICRO_VERSION < 23)
   375     DFBCardCapabilities caps;
   376 #else
   377     DFBGraphicsDeviceDescription caps;
   378 #endif
   379     DFBDisplayLayerConfig dlc;
   380     struct DirectFBEnumRect *rect;
   381     IDirectFB *dfb = NULL;
   382     IDirectFBDisplayLayer *layer = NULL;
   383     IDirectFBEventBuffer *events = NULL;
   384 
   385     HIDDEN->c2layer = NULL, HIDDEN->c2frame = NULL;
   386     HIDDEN->enable_mga_crtc2 = 0;
   387     HIDDEN->mga_crtc2_stretch_overscan = 1;
   388 
   389     ret = DirectFBInit(NULL, NULL);
   390     if (ret) {
   391         SetDirectFBerror("DirectFBInit", ret);
   392         goto error;
   393     }
   394 
   395     ret = DirectFBCreate(&dfb);
   396     if (ret) {
   397         SetDirectFBerror("DirectFBCreate", ret);
   398         goto error;
   399     }
   400 
   401     ret = dfb->GetDisplayLayer(dfb, DLID_PRIMARY, &layer);
   402     if (ret) {
   403         SetDirectFBerror("dfb->GetDisplayLayer", ret);
   404         goto error;
   405     }
   406 
   407     ret = dfb->CreateInputEventBuffer(dfb, DICAPS_ALL, DFB_FALSE, &events);
   408     if (ret) {
   409         SetDirectFBerror("dfb->CreateEventBuffer", ret);
   410         goto error;
   411     }
   412 
   413     layer->EnableCursor(layer, 1);
   414 
   415     /* Query layer configuration to determine the current mode and pixelformat */
   416     layer->GetConfiguration(layer, &dlc);
   417 
   418     /* If current format is not supported use LUT8 as the default */
   419     if (DFBToSDLPixelFormat(dlc.pixelformat, vformat))
   420         DFBToSDLPixelFormat(DSPF_LUT8, vformat);
   421 
   422     /* Enumerate the available fullscreen modes */
   423     ret = dfb->EnumVideoModes(dfb, EnumModesCallback, this);
   424     if (ret) {
   425         SetDirectFBerror("dfb->EnumVideoModes", ret);
   426         goto error;
   427     }
   428 
   429     HIDDEN->modelist = SDL_calloc(HIDDEN->nummodes + 1, sizeof(SDL_Rect *));
   430     if (!HIDDEN->modelist) {
   431         SDL_OutOfMemory();
   432         goto error;
   433     }
   434 
   435     for (i = 0, rect = enumlist; rect; ++i, rect = rect->next) {
   436         HIDDEN->modelist[i] = &rect->r;
   437     }
   438 
   439     HIDDEN->modelist[i] = NULL;
   440 
   441 
   442     /* Query card capabilities to get the video memory size */
   443 #if (DIRECTFB_MAJOR_VERSION == 0) && (DIRECTFB_MINOR_VERSION == 9) && (DIRECTFB_MICRO_VERSION < 23)
   444     dfb->GetCardCapabilities(dfb, &caps);
   445 #else
   446     dfb->GetDeviceDescription(dfb, &caps);
   447 #endif
   448 
   449     this->info.wm_available = 1;
   450     this->info.hw_available = 1;
   451     this->info.blit_hw = 1;
   452     this->info.blit_hw_CC = 1;
   453     this->info.blit_hw_A = 1;
   454     this->info.blit_fill = 1;
   455     this->info.video_mem = caps.video_memory / 1024;
   456     this->info.current_w = dlc.width;
   457     this->info.current_h = dlc.height;
   458 
   459     HIDDEN->initialized = 1;
   460     HIDDEN->dfb = dfb;
   461     HIDDEN->layer = layer;
   462     HIDDEN->eventbuffer = events;
   463 
   464     if (SDL_getenv("SDL_DIRECTFB_MGA_CRTC2") != NULL)
   465         HIDDEN->enable_mga_crtc2 = 1;
   466 
   467     if (HIDDEN->enable_mga_crtc2) {
   468         DFBDisplayLayerConfig dlc;
   469         DFBDisplayLayerConfigFlags failed;
   470 
   471         ret = dfb->GetDisplayLayer(dfb, 2, &HIDDEN->c2layer);
   472         if (ret) {
   473             SetDirectFBerror("dfb->GetDisplayLayer(CRTC2)", ret);
   474             goto error;
   475         }
   476 
   477         ret =
   478             HIDDEN->layer->SetCooperativeLevel(HIDDEN->layer,
   479                                                DLSCL_EXCLUSIVE);
   480         if (ret) {
   481             SetDirectFBerror
   482                 ("layer->SetCooperativeLevel(CRTC2, EXCLUSIVE)", ret);
   483             goto error;
   484         }
   485 
   486         ret =
   487             HIDDEN->c2layer->SetCooperativeLevel(HIDDEN->c2layer,
   488                                                  DLSCL_EXCLUSIVE);
   489         if (ret) {
   490             SetDirectFBerror
   491                 ("c2layer->SetCooperativeLevel(CRTC2, EXCLUSIVE)", ret);
   492             goto error;
   493         }
   494 
   495         HIDDEN->c2layer->SetOpacity(HIDDEN->c2layer, 0x0);
   496 
   497         /* Init the surface here as it got a fixed size */
   498         dlc.flags = DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE;
   499         dlc.buffermode = DLBM_BACKVIDEO;
   500         dlc.pixelformat = DSPF_RGB32;
   501 
   502         ret =
   503             HIDDEN->c2layer->TestConfiguration(HIDDEN->c2layer, &dlc,
   504                                                &failed);
   505         if (ret) {
   506             SetDirectFBerror("c2layer->TestConfiguration", ret);
   507             goto error;
   508         }
   509 
   510         ret = HIDDEN->c2layer->SetConfiguration(HIDDEN->c2layer, &dlc);
   511         if (ret) {
   512             SetDirectFBerror("c2layer->SetConfiguration", ret);
   513             goto error;
   514         }
   515 
   516         ret = HIDDEN->c2layer->GetSurface(HIDDEN->c2layer, &HIDDEN->c2frame);
   517         if (ret) {
   518             SetDirectFBerror("c2layer->GetSurface", ret);
   519             goto error;
   520         }
   521 
   522         HIDDEN->c2framesize.x = 0;
   523         HIDDEN->c2framesize.y = 0;
   524         HIDDEN->c2frame->GetSize(HIDDEN->c2frame, &HIDDEN->c2framesize.w,
   525                                  &HIDDEN->c2framesize.h);
   526 
   527         HIDDEN->c2frame->SetBlittingFlags(HIDDEN->c2frame, DSBLIT_NOFX);
   528         HIDDEN->c2frame->SetColor(HIDDEN->c2frame, 0, 0, 0, 0xff);
   529 
   530         /* Clear CRTC2 */
   531         HIDDEN->c2frame->Clear(HIDDEN->c2frame, 0, 0, 0, 0xff);
   532         HIDDEN->c2frame->Flip(HIDDEN->c2frame, NULL, 0);
   533         HIDDEN->c2frame->Clear(HIDDEN->c2frame, 0, 0, 0, 0xff);
   534         HIDDEN->c2frame->Flip(HIDDEN->c2frame, NULL, 0);
   535         HIDDEN->c2frame->Clear(HIDDEN->c2frame, 0, 0, 0, 0xff);
   536 
   537         HIDDEN->c2layer->SetOpacity(HIDDEN->c2layer, 0xFF);
   538 
   539         /* Check if overscan is possibly set */
   540         if (SDL_getenv("SDL_DIRECTFB_MGA_OVERSCAN") != NULL) {
   541             float overscan = 0;
   542             if (SDL_sscanf
   543                 (SDL_getenv("SDL_DIRECTFB_MGA_OVERSCAN"), "%f",
   544                  &overscan) == 1)
   545                 if (overscan > 0 && overscan < 2)
   546                     HIDDEN->mga_crtc2_stretch_overscan = overscan;
   547         }
   548 #ifdef DIRECTFB_CRTC2_DEBUG
   549         printf("CRTC2 overscan: %f\n", HIDDEN->mga_crtc2_stretch_overscan);
   550 #endif
   551     }
   552 
   553     return 0;
   554 
   555   error:
   556     if (events)
   557         events->Release(events);
   558 
   559     if (HIDDEN->c2frame)
   560         HIDDEN->c2frame->Release(HIDDEN->c2frame);
   561 
   562     if (HIDDEN->c2layer)
   563         HIDDEN->c2layer->Release(HIDDEN->c2layer);
   564 
   565     if (layer)
   566         layer->Release(layer);
   567 
   568     if (dfb)
   569         dfb->Release(dfb);
   570 
   571     return -1;
   572 }
   573 
   574 static SDL_Rect **
   575 DirectFB_ListModes(_THIS, SDL_PixelFormat * format, Uint32 flags)
   576 {
   577     if (flags & SDL_FULLSCREEN)
   578         return HIDDEN->modelist;
   579     else if (SDLToDFBPixelFormat(format) != DSPF_UNKNOWN)
   580         return (SDL_Rect **) - 1;
   581 
   582     return NULL;
   583 }
   584 
   585 static SDL_Surface *
   586 DirectFB_SetVideoMode(_THIS, SDL_Surface * current, int width, int height,
   587                       int bpp, Uint32 flags)
   588 {
   589     DFBResult ret;
   590     DFBSurfaceDescription dsc;
   591     DFBSurfacePixelFormat pixelformat;
   592     IDirectFBSurface *surface;
   593 
   594     fprintf(stderr, "SDL DirectFB_SetVideoMode: %dx%d@%d, flags: 0x%08x\n",
   595             width, height, bpp, flags);
   596 
   597     flags |= SDL_FULLSCREEN;
   598 
   599     /* Release previous primary surface */
   600     if (current->hwdata && current->hwdata->surface) {
   601         current->hwdata->surface->Release(current->hwdata->surface);
   602         current->hwdata->surface = NULL;
   603 
   604         /* And its palette if present */
   605         if (current->hwdata->palette) {
   606             current->hwdata->palette->Release(current->hwdata->palette);
   607             current->hwdata->palette = NULL;
   608         }
   609     } else if (!current->hwdata) {
   610         /* Allocate the hardware acceleration data */
   611         current->hwdata =
   612             (struct private_hwdata *) SDL_calloc(1, sizeof(*current->hwdata));
   613         if (!current->hwdata) {
   614             SDL_OutOfMemory();
   615             return NULL;
   616         }
   617     }
   618 
   619     /* Set cooperative level depending on flag SDL_FULLSCREEN */
   620     if (flags & SDL_FULLSCREEN) {
   621         ret = HIDDEN->dfb->SetCooperativeLevel(HIDDEN->dfb, DFSCL_FULLSCREEN);
   622         if (ret && !HIDDEN->enable_mga_crtc2) {
   623             DirectFBError("dfb->SetCooperativeLevel", ret);
   624             flags &= ~SDL_FULLSCREEN;
   625         }
   626     } else
   627         HIDDEN->dfb->SetCooperativeLevel(HIDDEN->dfb, DFSCL_NORMAL);
   628 
   629     /* Set video mode */
   630     ret = HIDDEN->dfb->SetVideoMode(HIDDEN->dfb, width, height, bpp);
   631     if (ret) {
   632         if (flags & SDL_FULLSCREEN) {
   633             flags &= ~SDL_FULLSCREEN;
   634             HIDDEN->dfb->SetCooperativeLevel(HIDDEN->dfb, DFSCL_NORMAL);
   635             ret = HIDDEN->dfb->SetVideoMode(HIDDEN->dfb, width, height, bpp);
   636         }
   637 
   638         if (ret) {
   639             SetDirectFBerror("dfb->SetVideoMode", ret);
   640             return NULL;
   641         }
   642     }
   643 
   644     /* Create primary surface */
   645     dsc.flags = DSDESC_CAPS | DSDESC_PIXELFORMAT;
   646     dsc.caps =
   647         DSCAPS_PRIMARY | ((flags & SDL_DOUBLEBUF) ? DSCAPS_FLIPPING : 0);
   648     dsc.pixelformat = GetFormatForBpp(bpp, HIDDEN->layer);
   649 
   650     ret = HIDDEN->dfb->CreateSurface(HIDDEN->dfb, &dsc, &surface);
   651     if (ret && (flags & SDL_DOUBLEBUF)) {
   652         /* Try without double buffering */
   653         dsc.caps &= ~DSCAPS_FLIPPING;
   654         ret = HIDDEN->dfb->CreateSurface(HIDDEN->dfb, &dsc, &surface);
   655     }
   656     if (ret) {
   657         SetDirectFBerror("dfb->CreateSurface", ret);
   658         return NULL;
   659     }
   660 
   661     current->w = width;
   662     current->h = height;
   663     current->flags = SDL_HWSURFACE | SDL_PREALLOC;
   664 
   665     if (flags & SDL_FULLSCREEN) {
   666         current->flags |= SDL_FULLSCREEN;
   667         this->UpdateRects = DirectFB_DirectUpdate;
   668     } else
   669         this->UpdateRects = DirectFB_WindowedUpdate;
   670 
   671     if (dsc.caps & DSCAPS_FLIPPING)
   672         current->flags |= SDL_DOUBLEBUF;
   673 
   674     surface->GetPixelFormat(surface, &pixelformat);
   675 
   676     DFBToSDLPixelFormat(pixelformat, current->format);
   677 
   678     /* Get the surface palette (if supported) */
   679     if (DFB_PIXELFORMAT_IS_INDEXED(pixelformat)) {
   680         surface->GetPalette(surface, &current->hwdata->palette);
   681 
   682         current->flags |= SDL_HWPALETTE;
   683     }
   684 
   685     current->hwdata->surface = surface;
   686 
   687     /* MGA CRTC2 stuff */
   688     if (HIDDEN->enable_mga_crtc2) {
   689         /* no stretching if c2ssize == c2framesize */
   690         HIDDEN->c2ssize.x = 0, HIDDEN->c2ssize.y = 0;
   691         HIDDEN->c2ssize.w = width;
   692         HIDDEN->c2ssize.h = height;
   693 
   694         HIDDEN->c2dsize.x = 0, HIDDEN->c2dsize.y = 0;
   695         HIDDEN->c2dsize.w = width;
   696         HIDDEN->c2dsize.h = height;
   697 
   698         HIDDEN->mga_crtc2_stretch = 0;
   699 
   700         if (SDL_getenv("SDL_DIRECTFB_MGA_STRETCH") != NULL) {
   701             /* Normally assume a picture aspect ratio of 4:3 */
   702             int zoom_aspect_x = 4, zoom_aspect_y = 3, i, j;
   703 
   704             for (i = 1; i < 20; i++) {
   705                 for (j = 1; j < 10; j++) {
   706                     if ((float) width / (float) i * (float) j == height) {
   707                         zoom_aspect_x = i;
   708                         zoom_aspect_y = j;
   709 
   710                         /* break the loop */
   711                         i = 21;
   712                         break;
   713                     }
   714                 }
   715             }
   716 
   717 #ifdef DIRECTFB_CRTC2_DEBUG
   718             printf
   719                 ("Source resolution: X: %d, Y: %d, Aspect ratio: %d:%d\n",
   720                  width, height, zoom_aspect_x, zoom_aspect_y);
   721             printf("CRTC2 resolution: X: %d, Y: %d\n",
   722                    HIDDEN->c2framesize.w, HIDDEN->c2framesize.h);
   723 #endif
   724 
   725             /* don't stretch only slightly smaller/larger images */
   726             if ((float) width < (float) HIDDEN->c2framesize.w * 0.95
   727                 || (float) height < (float) HIDDEN->c2framesize.h * 0.95) {
   728                 while ((float) HIDDEN->c2dsize.w <
   729                        (float) HIDDEN->c2framesize.w *
   730                        HIDDEN->mga_crtc2_stretch_overscan
   731                        && (float) HIDDEN->c2dsize.h <
   732                        (float) HIDDEN->c2framesize.h *
   733                        HIDDEN->mga_crtc2_stretch_overscan) {
   734                     HIDDEN->c2dsize.w += zoom_aspect_x;
   735                     HIDDEN->c2dsize.h += zoom_aspect_y;
   736                 }
   737 
   738                 /* one step down */
   739                 HIDDEN->c2dsize.w -= zoom_aspect_x;
   740                 HIDDEN->c2dsize.h -= zoom_aspect_y;
   741 
   742 #ifdef DIRECTFB_CRTC2_DEBUG
   743                 printf("Stretched resolution: X: %d, Y: %d\n",
   744                        HIDDEN->c2dsize.w, HIDDEN->c2dsize.h);
   745 #endif
   746 
   747                 HIDDEN->mga_crtc2_stretch = 1;
   748             } else if ((float) width > (float) HIDDEN->c2framesize.w * 0.95
   749                        || (float) height >
   750                        (float) HIDDEN->c2framesize.h * 0.95) {
   751                 while ((float) HIDDEN->c2dsize.w >
   752                        (float) HIDDEN->c2framesize.w *
   753                        HIDDEN->mga_crtc2_stretch_overscan
   754                        || (float) HIDDEN->c2dsize.h >
   755                        (float) HIDDEN->c2framesize.h *
   756                        HIDDEN->mga_crtc2_stretch_overscan) {
   757                     HIDDEN->c2dsize.w -= zoom_aspect_x;
   758                     HIDDEN->c2dsize.h -= zoom_aspect_y;
   759                 }
   760 
   761 #ifdef DIRECTFB_CRTC2_DEBUG
   762                 printf("Down-Stretched resolution: X: %d, Y: %d\n",
   763                        HIDDEN->c2dsize.w, HIDDEN->c2dsize.h);
   764 #endif
   765 
   766                 HIDDEN->mga_crtc2_stretch = 1;
   767             } else {
   768 #ifdef DIRECTFB_CRTC2_DEBUG
   769                 printf("Not stretching image\n");
   770 #endif
   771             }
   772 
   773             /* Panning */
   774             if (HIDDEN->c2framesize.w > HIDDEN->c2dsize.w)
   775                 HIDDEN->c2dsize.x =
   776                     (HIDDEN->c2framesize.w - HIDDEN->c2dsize.w) / 2;
   777             else
   778                 HIDDEN->c2dsize.x =
   779                     (HIDDEN->c2dsize.w - HIDDEN->c2framesize.w) / 2;
   780 
   781             if (HIDDEN->c2framesize.h > HIDDEN->c2dsize.h)
   782                 HIDDEN->c2dsize.y =
   783                     (HIDDEN->c2framesize.h - HIDDEN->c2dsize.h) / 2;
   784             else
   785                 HIDDEN->c2dsize.y =
   786                     (HIDDEN->c2dsize.h - HIDDEN->c2framesize.h) / 2;
   787 
   788 #ifdef DIRECTFB_CRTC2_DEBUG
   789             printf("CRTC2 position X: %d, Y: %d\n", HIDDEN->c2dsize.x,
   790                    HIDDEN->c2dsize.y);
   791 #endif
   792         }
   793     }
   794 
   795     return current;
   796 }
   797 
   798 static int
   799 DirectFB_AllocHWSurface(_THIS, SDL_Surface * surface)
   800 {
   801     DFBResult ret;
   802     DFBSurfaceDescription dsc;
   803 
   804     /*  fprintf(stderr, "SDL: DirectFB_AllocHWSurface (%dx%d@%d, flags: 0x%08x)\n",
   805        surface->w, surface->h, surface->format->BitsPerPixel, surface->flags); */
   806 
   807     if (surface->w < 8 || surface->h < 8)
   808         return -1;
   809 
   810     /* fill surface description */
   811     dsc.flags =
   812         DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT | DSDESC_CAPS;
   813     dsc.width = surface->w;
   814     dsc.height = surface->h;
   815     dsc.caps = (surface->flags & SDL_DOUBLEBUF) ? DSCAPS_FLIPPING : 0;
   816 
   817     /* find the right pixelformat */
   818     dsc.pixelformat = SDLToDFBPixelFormat(surface->format);
   819     if (dsc.pixelformat == DSPF_UNKNOWN)
   820         return -1;
   821 
   822     /* Allocate the hardware acceleration data */
   823     surface->hwdata =
   824         (struct private_hwdata *) SDL_calloc(1, sizeof(*surface->hwdata));
   825     if (surface->hwdata == NULL) {
   826         SDL_OutOfMemory();
   827         return -1;
   828     }
   829 
   830     /* Create the surface */
   831     ret =
   832         HIDDEN->dfb->CreateSurface(HIDDEN->dfb, &dsc,
   833                                    &surface->hwdata->surface);
   834     if (ret) {
   835         SetDirectFBerror("dfb->CreateSurface", ret);
   836         free(surface->hwdata);
   837         surface->hwdata = NULL;
   838         return -1;
   839     }
   840 
   841     surface->flags |= SDL_HWSURFACE | SDL_PREALLOC;
   842 
   843     return 0;
   844 }
   845 
   846 static void
   847 DirectFB_FreeHWSurface(_THIS, SDL_Surface * surface)
   848 {
   849     if (surface->hwdata && HIDDEN->initialized) {
   850         surface->hwdata->surface->Release(surface->hwdata->surface);
   851         free(surface->hwdata);
   852         surface->hwdata = NULL;
   853     }
   854 }
   855 
   856 static int
   857 DirectFB_CheckHWBlit(_THIS, SDL_Surface * src, SDL_Surface * dst)
   858 {
   859     /*  fprintf(stderr, "SDL: DirectFB_CheckHWBlit (src->hwdata: %p, dst->hwdata: %p)\n",
   860        src->hwdata, dst->hwdata); */
   861 
   862     if (!src->hwdata || !dst->hwdata)
   863         return 0;
   864 
   865     src->flags |= SDL_HWACCEL;
   866     src->map->hw_blit = DirectFB_HWAccelBlit;
   867 
   868     return 1;
   869 }
   870 
   871 static int
   872 DirectFB_HWAccelBlit(SDL_Surface * src, SDL_Rect * srcrect,
   873                      SDL_Surface * dst, SDL_Rect * dstrect)
   874 {
   875     DFBSurfaceBlittingFlags flags = DSBLIT_NOFX;
   876 
   877     DFBRectangle sr = { srcrect->x, srcrect->y, srcrect->w, srcrect->h };
   878     DFBRectangle dr = { dstrect->x, dstrect->y, dstrect->w, dstrect->h };
   879 
   880     IDirectFBSurface *surface = dst->hwdata->surface;
   881 
   882     if (src->flags & SDL_SRCCOLORKEY) {
   883         flags |= DSBLIT_SRC_COLORKEY;
   884         DirectFB_SetHWColorKey(NULL, src, src->format->colorkey);
   885     }
   886 
   887     if (src->flags & SDL_SRCALPHA) {
   888         flags |= DSBLIT_BLEND_COLORALPHA;
   889         surface->SetColor(surface, 0xff, 0xff, 0xff, src->format->alpha);
   890     }
   891 
   892     surface->SetBlittingFlags(surface, flags);
   893 
   894     if (sr.w == dr.w && sr.h == dr.h)
   895         surface->Blit(surface, src->hwdata->surface, &sr, dr.x, dr.y);
   896     else
   897         surface->StretchBlit(surface, src->hwdata->surface, &sr, &dr);
   898 
   899     return 0;
   900 }
   901 
   902 static int
   903 DirectFB_FillHWRect(_THIS, SDL_Surface * dst, SDL_Rect * dstrect,
   904                     Uint32 color)
   905 {
   906     SDL_PixelFormat *fmt = dst->format;
   907     IDirectFBSurface *surface = dst->hwdata->surface;
   908 
   909     /* ugly */
   910     surface->SetColor(surface,
   911                       (color & fmt->Rmask) >> (fmt->Rshift - fmt->Rloss),
   912                       (color & fmt->Gmask) >> (fmt->Gshift - fmt->Gloss),
   913                       (color & fmt->Bmask) << (fmt->Bloss - fmt->Bshift),
   914                       0xFF);
   915     surface->FillRectangle(surface, dstrect->x, dstrect->y, dstrect->w,
   916                            dstrect->h);
   917 
   918     return 0;
   919 }
   920 
   921 static int
   922 DirectFB_SetHWColorKey(_THIS, SDL_Surface * src, Uint32 key)
   923 {
   924     SDL_PixelFormat *fmt = src->format;
   925     IDirectFBSurface *surface = src->hwdata->surface;
   926 
   927     if (fmt->BitsPerPixel == 8)
   928         surface->SetSrcColorKeyIndex(surface, key);
   929     else
   930         /* ugly */
   931         surface->SetSrcColorKey(surface,
   932                                 (key & fmt->Rmask) >> (fmt->Rshift -
   933                                                        fmt->Rloss),
   934                                 (key & fmt->Gmask) >> (fmt->Gshift -
   935                                                        fmt->Gloss),
   936                                 (key & fmt->Bmask) << (fmt->Bloss -
   937                                                        fmt->Bshift));
   938 
   939     return 0;
   940 }
   941 
   942 static int
   943 DirectFB_SetHWAlpha(_THIS, SDL_Surface * surface, Uint8 alpha)
   944 {
   945     return 0;
   946 }
   947 
   948 static int
   949 DirectFB_FlipHWSurface(_THIS, SDL_Surface * surface)
   950 {
   951     if (HIDDEN->enable_mga_crtc2) {
   952         int rtn =
   953             surface->hwdata->surface->Flip(surface->hwdata->surface, NULL,
   954                                            0);
   955         if (HIDDEN->mga_crtc2_stretch)
   956             HIDDEN->c2frame->StretchBlit(HIDDEN->c2frame,
   957                                          surface->hwdata->surface,
   958                                          &HIDDEN->c2ssize, &HIDDEN->c2dsize);
   959         else
   960             HIDDEN->c2frame->Blit(HIDDEN->c2frame,
   961                                   surface->hwdata->surface, NULL,
   962                                   HIDDEN->c2dsize.x, HIDDEN->c2dsize.y);
   963 
   964         HIDDEN->c2frame->Flip(HIDDEN->c2frame, NULL, DSFLIP_WAITFORSYNC);
   965         return rtn;
   966     } else
   967         return surface->hwdata->surface->Flip(surface->hwdata->surface, NULL,
   968                                               DSFLIP_WAITFORSYNC);
   969 }
   970 
   971 static int
   972 DirectFB_LockHWSurface(_THIS, SDL_Surface * surface)
   973 {
   974     DFBResult ret;
   975     void *data;
   976     int pitch;
   977 
   978     ret = surface->hwdata->surface->Lock(surface->hwdata->surface,
   979                                          DSLF_WRITE, &data, &pitch);
   980     if (ret) {
   981         SetDirectFBerror("surface->Lock", ret);
   982         return -1;
   983     }
   984 
   985     surface->pixels = data;
   986     surface->pitch = pitch;
   987 
   988     return 0;
   989 }
   990 
   991 static void
   992 DirectFB_UnlockHWSurface(_THIS, SDL_Surface * surface)
   993 {
   994     surface->hwdata->surface->Unlock(surface->hwdata->surface);
   995     surface->pixels = NULL;
   996 }
   997 
   998 static void
   999 DirectFB_DirectUpdate(_THIS, int numrects, SDL_Rect * rects)
  1000 {
  1001     if (HIDDEN->enable_mga_crtc2) {
  1002         if (HIDDEN->mga_crtc2_stretch)
  1003             HIDDEN->c2frame->StretchBlit(HIDDEN->c2frame,
  1004                                          this->screen->hwdata->surface,
  1005                                          &HIDDEN->c2ssize, &HIDDEN->c2dsize);
  1006         else
  1007             HIDDEN->c2frame->Blit(HIDDEN->c2frame,
  1008                                   this->screen->hwdata->surface, NULL,
  1009                                   HIDDEN->c2dsize.x, HIDDEN->c2dsize.y);
  1010 
  1011         HIDDEN->c2frame->Flip(HIDDEN->c2frame, NULL, DSFLIP_WAITFORSYNC);
  1012     }
  1013 }
  1014 
  1015 static void
  1016 DirectFB_WindowedUpdate(_THIS, int numrects, SDL_Rect * rects)
  1017 {
  1018     DFBRegion region;
  1019     int i;
  1020     int region_valid = 0;
  1021     IDirectFBSurface *surface = this->screen->hwdata->surface;
  1022 
  1023     for (i = 0; i < numrects; ++i) {
  1024         int x2, y2;
  1025 
  1026         if (!rects[i].w)        /* Clipped? */
  1027             continue;
  1028 
  1029         x2 = rects[i].x + rects[i].w - 1;
  1030         y2 = rects[i].y + rects[i].h - 1;
  1031 
  1032         if (region_valid) {
  1033             if (rects[i].x < region.x1)
  1034                 region.x1 = rects[i].x;
  1035 
  1036             if (rects[i].y < region.y1)
  1037                 region.y1 = rects[i].y;
  1038 
  1039             if (x2 > region.x2)
  1040                 region.x2 = x2;
  1041 
  1042             if (y2 > region.y2)
  1043                 region.y2 = y2;
  1044         } else {
  1045             region.x1 = rects[i].x;
  1046             region.y1 = rects[i].y;
  1047             region.x2 = x2;
  1048             region.y2 = y2;
  1049 
  1050             region_valid = 1;
  1051         }
  1052     }
  1053 
  1054     if (region_valid) {
  1055         if (HIDDEN->enable_mga_crtc2) {
  1056             if (HIDDEN->mga_crtc2_stretch)
  1057                 HIDDEN->c2frame->StretchBlit(HIDDEN->c2frame, surface,
  1058                                              &HIDDEN->c2ssize,
  1059                                              &HIDDEN->c2dsize);
  1060             else
  1061                 HIDDEN->c2frame->Blit(HIDDEN->c2frame, surface, NULL,
  1062                                       HIDDEN->c2dsize.x, HIDDEN->c2dsize.y);
  1063 
  1064             HIDDEN->c2frame->Flip(HIDDEN->c2frame, NULL, DSFLIP_WAITFORSYNC);
  1065         } else
  1066             surface->Flip(surface, &region, DSFLIP_WAITFORSYNC);
  1067     }
  1068 }
  1069 
  1070 int
  1071 DirectFB_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color * colors)
  1072 {
  1073     IDirectFBPalette *palette = this->screen->hwdata->palette;
  1074 
  1075     if (!palette)
  1076         return 0;
  1077 
  1078     if (firstcolor > 255)
  1079         return 0;
  1080 
  1081     if (firstcolor + ncolors > 256)
  1082         ncolors = 256 - firstcolor;
  1083 
  1084     if (ncolors > 0) {
  1085         int i;
  1086         DFBColor entries[ncolors];
  1087 
  1088         for (i = 0; i < ncolors; i++) {
  1089             entries[i].a = 0xff;
  1090             entries[i].r = colors[i].r;
  1091             entries[i].g = colors[i].g;
  1092             entries[i].b = colors[i].b;
  1093         }
  1094 
  1095         palette->SetEntries(palette, entries, ncolors, firstcolor);
  1096     }
  1097 
  1098     return 1;
  1099 }
  1100 
  1101 void
  1102 DirectFB_VideoQuit(_THIS)
  1103 {
  1104     struct DirectFBEnumRect *rect = enumlist;
  1105 
  1106     if (this->screen && this->screen->hwdata) {
  1107         IDirectFBSurface *surface = this->screen->hwdata->surface;
  1108         IDirectFBPalette *palette = this->screen->hwdata->palette;
  1109 
  1110         if (palette)
  1111             palette->Release(palette);
  1112 
  1113         if (surface)
  1114             surface->Release(surface);
  1115 
  1116         this->screen->hwdata->surface = NULL;
  1117         this->screen->hwdata->palette = NULL;
  1118     }
  1119 
  1120     if (HIDDEN->c2frame) {
  1121         HIDDEN->c2frame->Release(HIDDEN->c2frame);
  1122         HIDDEN->c2frame = NULL;
  1123     }
  1124 
  1125     if (HIDDEN->eventbuffer) {
  1126         HIDDEN->eventbuffer->Release(HIDDEN->eventbuffer);
  1127         HIDDEN->eventbuffer = NULL;
  1128     }
  1129 
  1130     if (HIDDEN->c2layer) {
  1131         HIDDEN->c2layer->Release(HIDDEN->c2layer);
  1132         HIDDEN->c2layer = NULL;
  1133     }
  1134 
  1135     if (HIDDEN->layer) {
  1136         HIDDEN->layer->Release(HIDDEN->layer);
  1137         HIDDEN->layer = NULL;
  1138     }
  1139 
  1140     if (HIDDEN->dfb) {
  1141         HIDDEN->dfb->Release(HIDDEN->dfb);
  1142         HIDDEN->dfb = NULL;
  1143     }
  1144 
  1145     /* Free video mode list */
  1146     if (HIDDEN->modelist) {
  1147         free(HIDDEN->modelist);
  1148         HIDDEN->modelist = NULL;
  1149     }
  1150 
  1151     /* Free mode enumeration list */
  1152     while (rect) {
  1153         struct DirectFBEnumRect *next = rect->next;
  1154         free(rect);
  1155         rect = next;
  1156     }
  1157     enumlist = NULL;
  1158 
  1159     HIDDEN->initialized = 0;
  1160 }
  1161 
  1162 
  1163 int
  1164 DirectFB_ShowWMCursor(_THIS, WMcursor * cursor)
  1165 {
  1166     /* We can only hide or show the default cursor */
  1167     if (cursor == NULL) {
  1168         HIDDEN->layer->SetCursorOpacity(HIDDEN->layer, 0x00);
  1169     } else {
  1170         HIDDEN->layer->SetCursorOpacity(HIDDEN->layer, 0xFF);
  1171     }
  1172     return 1;
  1173 }
  1174 
  1175 void
  1176 DirectFB_FinalQuit(void)
  1177 {
  1178 }
  1179 
  1180 /* vi: set ts=4 sw=4 expandtab: */