src/video/directfb/SDL_DirectFB_render.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 31 Jan 2011 22:44:43 -0800
changeset 5138 da10636e5eca
parent 4929 aa8888658021
child 5140 e743b9c3f6d6
permissions -rw-r--r--
Making the API simpler, scaling is always defined as linear interpolation and should be supported as much as possible on all renderers.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 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     SDL1.3 implementation by couriersud@arcor.de
    23     
    24 */
    25 #include "SDL_config.h"
    26 
    27 #include "SDL_DirectFB_video.h"
    28 #include "SDL_DirectFB_render.h"
    29 #include "../SDL_rect_c.h"
    30 #include "../SDL_yuv_sw_c.h"
    31 
    32 /* the following is not yet tested ... */
    33 #define USE_DISPLAY_PALETTE			(0)
    34 
    35 /* GDI renderer implementation */
    36 
    37 static SDL_Renderer *DirectFB_CreateRenderer(SDL_Window * window,
    38                                              Uint32 flags);
    39 static int DirectFB_DisplayModeChanged(SDL_Renderer * renderer);
    40 static int DirectFB_ActivateRenderer(SDL_Renderer * renderer);
    41 static int DirectFB_CreateTexture(SDL_Renderer * renderer,
    42                                   SDL_Texture * texture);
    43 static int DirectFB_QueryTexturePixels(SDL_Renderer * renderer,
    44                                        SDL_Texture * texture,
    45                                        void **pixels, int *pitch);
    46 static int DirectFB_SetTexturePalette(SDL_Renderer * renderer,
    47                                       SDL_Texture * texture,
    48                                       const SDL_Color * colors,
    49                                       int firstcolor, int ncolors);
    50 static int DirectFB_GetTexturePalette(SDL_Renderer * renderer,
    51                                       SDL_Texture * texture,
    52                                       SDL_Color * colors,
    53                                       int firstcolor, int ncolors);
    54 static int DirectFB_SetTextureAlphaMod(SDL_Renderer * renderer,
    55                                        SDL_Texture * texture);
    56 static int DirectFB_SetTextureColorMod(SDL_Renderer * renderer,
    57                                        SDL_Texture * texture);
    58 static int DirectFB_SetTextureBlendMode(SDL_Renderer * renderer,
    59                                         SDL_Texture * texture);
    60 static int DirectFB_UpdateTexture(SDL_Renderer * renderer,
    61                                   SDL_Texture * texture,
    62                                   const SDL_Rect * rect,
    63                                   const void *pixels, int pitch);
    64 static int DirectFB_LockTexture(SDL_Renderer * renderer,
    65                                 SDL_Texture * texture,
    66                                 const SDL_Rect * rect, int markDirty,
    67                                 void **pixels, int *pitch);
    68 static void DirectFB_UnlockTexture(SDL_Renderer * renderer,
    69                                    SDL_Texture * texture);
    70 static void DirectFB_DirtyTexture(SDL_Renderer * renderer,
    71                                   SDL_Texture * texture, int numrects,
    72                                   const SDL_Rect * rects);
    73 static int DirectFB_SetDrawBlendMode(SDL_Renderer * renderer);
    74 static int DirectFB_RenderDrawPoints(SDL_Renderer * renderer,
    75                                 const SDL_Point * points, int count);
    76 static int DirectFB_RenderDrawLines(SDL_Renderer * renderer,
    77                                const SDL_Point * points, int count);
    78 static int DirectFB_RenderDrawRects(SDL_Renderer * renderer,
    79 		const SDL_Rect ** rects, int count);
    80 static int DirectFB_RenderFillRects(SDL_Renderer * renderer,
    81 		const SDL_Rect ** rects, int count);
    82 static int DirectFB_RenderCopy(SDL_Renderer * renderer,
    83                                SDL_Texture * texture,
    84                                const SDL_Rect * srcrect,
    85                                const SDL_Rect * dstrect);
    86 static void DirectFB_RenderPresent(SDL_Renderer * renderer);
    87 static void DirectFB_DestroyTexture(SDL_Renderer * renderer,
    88                                     SDL_Texture * texture);
    89 static void DirectFB_DestroyRenderer(SDL_Renderer * renderer);
    90 
    91 #define SDL_DFB_WINDOWSURFACE(win)  IDirectFBSurface *destsurf = ((DFB_WindowData *) ((win)->driverdata))->surface;
    92 
    93 SDL_RenderDriver DirectFB_RenderDriver = {
    94     DirectFB_CreateRenderer,
    95     {
    96      "directfb",
    97      (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY |
    98       SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTFLIP3 |
    99       SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_PRESENTDISCARD |
   100       SDL_RENDERER_ACCELERATED),
   101      (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR |
   102       SDL_TEXTUREMODULATE_ALPHA),
   103      (SDL_BLENDMODE_NONE | SDL_BLENDMODE_MASK | SDL_BLENDMODE_BLEND |
   104       SDL_BLENDMODE_ADD | SDL_BLENDMODE_MOD),
   105      14,
   106      {
   107       SDL_PIXELFORMAT_INDEX4LSB,
   108       SDL_PIXELFORMAT_INDEX8,
   109       SDL_PIXELFORMAT_RGB332,
   110       SDL_PIXELFORMAT_RGB555,
   111       SDL_PIXELFORMAT_RGB565,
   112       SDL_PIXELFORMAT_RGB888,
   113       SDL_PIXELFORMAT_ARGB8888,
   114       SDL_PIXELFORMAT_ARGB4444,
   115       SDL_PIXELFORMAT_ARGB1555,
   116       SDL_PIXELFORMAT_RGB24,
   117       SDL_PIXELFORMAT_YV12,
   118       SDL_PIXELFORMAT_IYUV,
   119       SDL_PIXELFORMAT_YUY2,
   120       SDL_PIXELFORMAT_UYVY},
   121      0,
   122      0}
   123 };
   124 
   125 typedef struct
   126 {
   127     SDL_Window *window;
   128     DFBSurfaceFlipFlags flipflags;
   129     int isyuvdirect;
   130     int size_changed;
   131     int lastBlendMode;
   132     DFBSurfaceBlittingFlags blitFlags;
   133     DFBSurfaceDrawingFlags drawFlags;
   134 } DirectFB_RenderData;
   135 
   136 typedef struct
   137 {
   138     IDirectFBSurface *surface;
   139     Uint32 format;
   140     void *pixels;
   141     int pitch;
   142     IDirectFBPalette *palette;
   143     SDL_VideoDisplay *display;
   144     SDL_DirtyRectList dirty;
   145 #if (DFB_VERSION_ATLEAST(1,2,0))
   146     DFBSurfaceRenderOptions render_options;
   147 #endif
   148 } DirectFB_TextureData;
   149 
   150 static __inline__ void
   151 SDLtoDFBRect(const SDL_Rect * sr, DFBRectangle * dr)
   152 {
   153     dr->x = sr->x;
   154     dr->y = sr->y;
   155     dr->h = sr->h;
   156     dr->w = sr->w;
   157 }
   158 
   159 
   160 static int
   161 TextureHasAlpha(DirectFB_TextureData * data)
   162 {
   163     /* Drawing primitive ? */
   164     if (!data)
   165         return 0;
   166     switch (data->format) {
   167     case SDL_PIXELFORMAT_INDEX4LSB:
   168     case SDL_PIXELFORMAT_ARGB4444:
   169     case SDL_PIXELFORMAT_ARGB1555:
   170     case SDL_PIXELFORMAT_ARGB8888:
   171     case SDL_PIXELFORMAT_RGBA8888:
   172     case SDL_PIXELFORMAT_ABGR8888:
   173     case SDL_PIXELFORMAT_BGRA8888:
   174     case SDL_PIXELFORMAT_ARGB2101010:
   175         return 1;
   176     default:
   177         return 0;
   178     }
   179 }
   180 
   181 static void
   182 SetBlendMode(DirectFB_RenderData * data, int blendMode,
   183              DirectFB_TextureData * source)
   184 {
   185     SDL_DFB_WINDOWSURFACE(data->window);
   186 
   187     //FIXME: check for format change
   188     if (1 || data->lastBlendMode != blendMode) {
   189         switch (blendMode) {
   190         case SDL_BLENDMODE_NONE:
   191                                            /**< No blending */
   192             data->blitFlags = DSBLIT_NOFX;
   193             data->drawFlags = DSDRAW_NOFX;
   194             SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_ONE));
   195             SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_ZERO));
   196             break;
   197         case SDL_BLENDMODE_MASK:
   198             data->blitFlags = DSBLIT_BLEND_ALPHACHANNEL;
   199             data->drawFlags = DSDRAW_BLEND;
   200             SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_SRCALPHA));
   201             SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_INVSRCALPHA));
   202             break;
   203         case SDL_BLENDMODE_BLEND:
   204             data->blitFlags = DSBLIT_BLEND_ALPHACHANNEL;
   205             data->drawFlags = DSDRAW_BLEND;
   206             SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_SRCALPHA));
   207             SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_INVSRCALPHA));
   208             break;
   209         case SDL_BLENDMODE_ADD:
   210             data->blitFlags = DSBLIT_BLEND_ALPHACHANNEL;
   211             data->drawFlags = DSDRAW_BLEND;
   212             // FIXME: SRCALPHA kills performance on radeon ...
   213             // It will be cheaper to copy the surface to
   214             // a temporay surface and premultiply 
   215             if (source && TextureHasAlpha(source))
   216                 SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_SRCALPHA));
   217             else
   218                 SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_ONE));
   219             SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_ONE));
   220             break;
   221         case SDL_BLENDMODE_MOD:
   222             data->blitFlags = DSBLIT_BLEND_ALPHACHANNEL;
   223             data->drawFlags = DSDRAW_BLEND;
   224             SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_DESTCOLOR));
   225             SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_ZERO));
   226             break;
   227         }
   228         data->lastBlendMode = blendMode;
   229     }
   230 }
   231 
   232 void
   233 DirectFB_AddRenderDriver(_THIS)
   234 {
   235     int i;
   236 
   237     for (i = 0; i < _this->num_displays; ++i) {
   238         SDL_AddRenderDriver(&_this->displays[i], &DirectFB_RenderDriver);
   239     }
   240 }
   241 
   242 static int
   243 DisplayPaletteChanged(void *userdata, SDL_Palette * palette)
   244 {
   245 #if USE_DISPLAY_PALETTE
   246     DirectFB_RenderData *data = (DirectFB_RenderData *) userdata;
   247     SDL_DFB_WINDOWSURFACE(data->window);
   248     IDirectFBPalette *surfpal;
   249 
   250     int i;
   251     int ncolors;
   252     DFBColor entries[256];
   253 
   254     SDL_DFB_CHECKERR(destsurf->GetPalette(destsurf, &surfpal));
   255 
   256     /* FIXME: number of colors */
   257     ncolors = (palette->ncolors < 256 ? palette->ncolors : 256);
   258 
   259     for (i = 0; i < ncolors; ++i) {
   260         entries[i].r = palette->colors[i].r;
   261         entries[i].g = palette->colors[i].g;
   262         entries[i].b = palette->colors[i].b;
   263         entries[i].a = palette->colors[i].unused;
   264     }
   265     SDL_DFB_CHECKERR(surfpal->SetEntries(surfpal, entries, ncolors, 0));
   266     return 0;
   267   error:
   268 #else
   269     SDL_Unsupported();
   270 #endif
   271     return -1;
   272 }
   273 
   274 
   275 SDL_Renderer *
   276 DirectFB_CreateRenderer(SDL_Window * window, Uint32 flags)
   277 {
   278     SDL_DFB_WINDOWDATA(window);
   279     SDL_VideoDisplay *display = window->display;
   280     SDL_Renderer *renderer = NULL;
   281     DirectFB_RenderData *data = NULL;
   282     DFBSurfaceCapabilities scaps;
   283     char *p;
   284 
   285     SDL_DFB_CALLOC(renderer, 1, sizeof(*renderer));
   286     SDL_DFB_CALLOC(data, 1, sizeof(*data));
   287 
   288     renderer->DisplayModeChanged = DirectFB_DisplayModeChanged;
   289     renderer->ActivateRenderer = DirectFB_ActivateRenderer;
   290     renderer->CreateTexture = DirectFB_CreateTexture;
   291     renderer->QueryTexturePixels = DirectFB_QueryTexturePixels;
   292     renderer->SetTexturePalette = DirectFB_SetTexturePalette;
   293     renderer->GetTexturePalette = DirectFB_GetTexturePalette;
   294     renderer->SetTextureAlphaMod = DirectFB_SetTextureAlphaMod;
   295     renderer->SetTextureColorMod = DirectFB_SetTextureColorMod;
   296     renderer->SetTextureBlendMode = DirectFB_SetTextureBlendMode;
   297     renderer->UpdateTexture = DirectFB_UpdateTexture;
   298     renderer->LockTexture = DirectFB_LockTexture;
   299     renderer->UnlockTexture = DirectFB_UnlockTexture;
   300     renderer->DirtyTexture = DirectFB_DirtyTexture;
   301     renderer->RenderDrawPoints = DirectFB_RenderDrawPoints;
   302     renderer->RenderDrawLines = DirectFB_RenderDrawLines;
   303     /* SetDrawColor - no needed */
   304     renderer->SetDrawBlendMode = DirectFB_SetDrawBlendMode;
   305     renderer->RenderFillRects = DirectFB_RenderFillRects;
   306     renderer->RenderDrawRects = DirectFB_RenderDrawRects;
   307     /* RenderDrawEllipse - no reference implementation yet */
   308     /* RenderFillEllipse - no reference implementation yet */
   309     renderer->RenderCopy = DirectFB_RenderCopy;
   310     renderer->RenderPresent = DirectFB_RenderPresent;
   311     /* RenderReadPixels is difficult to implement */
   312     /* RenderWritePixels is difficult to implement */
   313     renderer->DestroyTexture = DirectFB_DestroyTexture;
   314     renderer->DestroyRenderer = DirectFB_DestroyRenderer;
   315     renderer->info = DirectFB_RenderDriver.info;
   316     renderer->window = window;      /* SDL window */
   317     renderer->driverdata = data;
   318 
   319     renderer->info.flags =
   320         SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTDISCARD;
   321 
   322     data->window = window;
   323 
   324     data->flipflags = DSFLIP_PIPELINE | DSFLIP_BLIT;
   325 
   326     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   327         data->flipflags |= DSFLIP_WAITFORSYNC | DSFLIP_ONSYNC;
   328         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   329     } else
   330         data->flipflags |= DSFLIP_ONSYNC;
   331 
   332     SDL_DFB_CHECKERR(windata->surface->
   333                      GetCapabilities(windata->surface, &scaps));
   334     if (scaps & DSCAPS_DOUBLE)
   335         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2;
   336     else if (scaps & DSCAPS_TRIPLE)
   337         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3;
   338     else
   339         renderer->info.flags |= SDL_RENDERER_SINGLEBUFFER;
   340 
   341     data->isyuvdirect = 0;      /* default is off! */
   342     p = SDL_getenv(DFBENV_USE_YUV_DIRECT);
   343     if (p)
   344         data->isyuvdirect = atoi(p);
   345 
   346     /* Set up a palette watch on the display palette */
   347     if (display->palette) {
   348         SDL_AddPaletteWatch(display->palette, DisplayPaletteChanged, data);
   349     }
   350 
   351     return renderer;
   352 
   353   error:
   354     SDL_DFB_FREE(renderer);
   355     SDL_DFB_FREE(data);
   356     return NULL;
   357 }
   358 
   359 static DFBSurfacePixelFormat
   360 SDLToDFBPixelFormat(Uint32 format)
   361 {
   362     switch (format) {
   363     case SDL_PIXELFORMAT_INDEX4LSB:
   364         return DSPF_ALUT44;
   365     case SDL_PIXELFORMAT_INDEX8:
   366         return DSPF_LUT8;
   367     case SDL_PIXELFORMAT_RGB332:
   368         return DSPF_RGB332;
   369     case SDL_PIXELFORMAT_RGB555:
   370         return DSPF_ARGB1555;
   371     case SDL_PIXELFORMAT_ARGB4444:
   372         return DSPF_ARGB4444;
   373     case SDL_PIXELFORMAT_ARGB1555:
   374         return DSPF_ARGB1555;
   375     case SDL_PIXELFORMAT_RGB565:
   376         return DSPF_RGB16;
   377     case SDL_PIXELFORMAT_RGB24:
   378         return DSPF_RGB24;
   379     case SDL_PIXELFORMAT_RGB888:
   380         return DSPF_RGB32;
   381     case SDL_PIXELFORMAT_ARGB8888:
   382         return DSPF_ARGB;
   383     case SDL_PIXELFORMAT_YV12:
   384         return DSPF_YV12;       /* Planar mode: Y + V + U  (3 planes) */
   385     case SDL_PIXELFORMAT_IYUV:
   386         return DSPF_I420;       /* Planar mode: Y + U + V  (3 planes) */
   387     case SDL_PIXELFORMAT_YUY2:
   388         return DSPF_YUY2;       /* Packed mode: Y0+U0+Y1+V0 (1 plane) */
   389     case SDL_PIXELFORMAT_UYVY:
   390         return DSPF_UYVY;       /* Packed mode: U0+Y0+V0+Y1 (1 plane) */
   391     case SDL_PIXELFORMAT_YVYU:
   392         return DSPF_UNKNOWN;    /* Packed mode: Y0+V0+Y1+U0 (1 plane) */
   393     case SDL_PIXELFORMAT_INDEX1LSB:
   394         return DSPF_UNKNOWN;
   395     case SDL_PIXELFORMAT_INDEX1MSB:
   396         return DSPF_UNKNOWN;
   397     case SDL_PIXELFORMAT_INDEX4MSB:
   398         return DSPF_UNKNOWN;
   399 #if (DFB_VERSION_ATLEAST(1,2,0))
   400     case SDL_PIXELFORMAT_RGB444:
   401         return DSPF_RGB444;
   402 #endif
   403     case SDL_PIXELFORMAT_BGR24:
   404         return DSPF_UNKNOWN;
   405     case SDL_PIXELFORMAT_BGR888:
   406         return DSPF_UNKNOWN;
   407     case SDL_PIXELFORMAT_RGBA8888:
   408         return DSPF_UNKNOWN;
   409     case SDL_PIXELFORMAT_ABGR8888:
   410         return DSPF_UNKNOWN;
   411     case SDL_PIXELFORMAT_BGRA8888:
   412         return DSPF_UNKNOWN;
   413     case SDL_PIXELFORMAT_ARGB2101010:
   414         return DSPF_UNKNOWN;
   415     default:
   416         return DSPF_UNKNOWN;
   417     }
   418 }
   419 
   420 static int
   421 DirectFB_ActivateRenderer(SDL_Renderer * renderer)
   422 {
   423     SDL_DFB_RENDERERDATA(renderer);
   424     SDL_Window *window = renderer->window;
   425     SDL_DFB_WINDOWDATA(window);
   426 
   427     if (renddata->size_changed || windata->wm_needs_redraw) {
   428 //        DirectFB_AdjustWindowSurface(window);
   429     }
   430     return 0;
   431 }
   432 
   433 static int
   434 DirectFB_DisplayModeChanged(SDL_Renderer * renderer)
   435 {
   436     SDL_DFB_RENDERERDATA(renderer);
   437 
   438     renddata->size_changed = SDL_TRUE;
   439     return 0;
   440 }
   441 
   442 static int
   443 DirectFB_AcquireVidLayer(SDL_Renderer * renderer, SDL_Texture * texture)
   444 {
   445     SDL_DFB_RENDERERDATA(renderer);
   446     SDL_Window *window = renderer->window;
   447     SDL_VideoDisplay *display = window->display;
   448     SDL_DFB_DEVICEDATA(display->device);
   449     DFB_DisplayData *dispdata = (DFB_DisplayData *) display->driverdata;
   450     DirectFB_TextureData *data = texture->driverdata;
   451     DFBDisplayLayerConfig layconf;
   452     DFBResult ret;
   453 
   454     if (renddata->isyuvdirect && (dispdata->vidID >= 0)
   455         && (!dispdata->vidIDinuse)
   456         && SDL_ISPIXELFORMAT_FOURCC(data->format)) {
   457         layconf.flags =
   458             DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT |
   459             DLCONF_SURFACE_CAPS;
   460         layconf.width = texture->w;
   461         layconf.height = texture->h;
   462         layconf.pixelformat = SDLToDFBPixelFormat(data->format);
   463         layconf.surface_caps = DSCAPS_VIDEOONLY | DSCAPS_DOUBLE;
   464 
   465         SDL_DFB_CHECKERR(devdata->dfb->GetDisplayLayer(devdata->dfb,
   466                                                        dispdata->vidID,
   467                                                        &dispdata->vidlayer));
   468         SDL_DFB_CHECKERR(dispdata->
   469                          vidlayer->SetCooperativeLevel(dispdata->vidlayer,
   470                                                        DLSCL_EXCLUSIVE));
   471 
   472         if (devdata->use_yuv_underlays) {
   473             ret = SDL_DFB_CHECK(dispdata->vidlayer->SetLevel(dispdata->vidlayer, -1));
   474             if (ret != DFB_OK)
   475                 SDL_DFB_DEBUG("Underlay Setlevel not supported\n");
   476         }
   477         SDL_DFB_CHECKERR(dispdata->
   478                          vidlayer->SetConfiguration(dispdata->vidlayer,
   479                                                     &layconf));
   480         SDL_DFB_CHECKERR(dispdata->
   481                          vidlayer->GetSurface(dispdata->vidlayer,
   482                                               &data->surface));
   483         dispdata->vidIDinuse = 1;
   484         data->display = display;
   485         return 0;
   486     }
   487     return 1;
   488   error:
   489     if (dispdata->vidlayer) {
   490         SDL_DFB_RELEASE(data->surface);
   491         SDL_DFB_CHECKERR(dispdata->
   492                          vidlayer->SetCooperativeLevel(dispdata->vidlayer,
   493                                                        DLSCL_ADMINISTRATIVE));
   494         SDL_DFB_RELEASE(dispdata->vidlayer);
   495     }
   496     return 1;
   497 }
   498 
   499 static int
   500 DirectFB_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   501 {
   502     SDL_Window *window = renderer->window;
   503     SDL_VideoDisplay *display = window->display;
   504     SDL_DFB_DEVICEDATA(display->device);
   505     DirectFB_TextureData *data;
   506     DFBSurfaceDescription dsc;
   507     DFBSurfacePixelFormat pixelformat;
   508 
   509     SDL_DFB_CALLOC(data, 1, sizeof(*data));
   510     texture->driverdata = data;
   511 
   512     /* find the right pixelformat */
   513     pixelformat = SDLToDFBPixelFormat(texture->format);
   514     if (pixelformat == DSPF_UNKNOWN) {
   515         SDL_SetError("Unknown pixel format %d\n", data->format);
   516         goto error;
   517     }
   518 
   519     data->format = texture->format;
   520     data->pitch = texture->w * DFB_BYTES_PER_PIXEL(pixelformat);
   521 
   522     if (DirectFB_AcquireVidLayer(renderer, texture) != 0) {
   523         /* fill surface description */
   524         dsc.flags =
   525             DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT | DSDESC_CAPS;
   526         dsc.width = texture->w;
   527         dsc.height = texture->h;
   528         /* <1.2 Never use DSCAPS_VIDEOONLY here. It kills performance
   529          * No DSCAPS_SYSTEMONLY either - let dfb decide
   530          * 1.2: DSCAPS_SYSTEMONLY boosts performance by factor ~8
   531          * Depends on other settings as well. Let dfb decide.
   532          */
   533         dsc.caps = DSCAPS_PREMULTIPLIED;
   534 #if 0
   535         if (texture->access == SDL_TEXTUREACCESS_STREAMING)
   536             dsc.caps |= DSCAPS_SYSTEMONLY;
   537         else
   538             dsc.caps |= DSCAPS_VIDEOONLY;
   539 #endif
   540 
   541         dsc.pixelformat = pixelformat;
   542         data->pixels = NULL;
   543 
   544         /* Create the surface */
   545         SDL_DFB_CHECKERR(devdata->dfb->CreateSurface(devdata->dfb, &dsc,
   546                                                      &data->surface));
   547         if (SDL_ISPIXELFORMAT_INDEXED(data->format)
   548             && !SDL_ISPIXELFORMAT_FOURCC(data->format)) {
   549             SDL_DFB_CHECKERR(data->surface->GetPalette(data->surface,
   550                                                        &data->palette));
   551         }
   552 
   553     }
   554 #if (DFB_VERSION_ATLEAST(1,2,0))
   555     data->render_options = DSRO_NONE;
   556 #endif
   557 
   558     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   559         /* 3 plane YUVs return 1 bpp, but we need more space for other planes */
   560         if(texture->format == SDL_PIXELFORMAT_YV12 ||
   561            texture->format == SDL_PIXELFORMAT_IYUV) {
   562             SDL_DFB_CALLOC(data->pixels, 1, (texture->h * data->pitch * 3 + texture->h * data->pitch * 3 % 2) / 2);
   563         } else {
   564             SDL_DFB_CALLOC(data->pixels, 1, texture->h * data->pitch);
   565         }
   566     }
   567 
   568     return 0;
   569 
   570   error:
   571     SDL_DFB_RELEASE(data->palette);
   572     SDL_DFB_RELEASE(data->surface);
   573     SDL_DFB_FREE(texture->driverdata);
   574     return -1;
   575 }
   576 
   577 static int
   578 DirectFB_QueryTexturePixels(SDL_Renderer * renderer,
   579                             SDL_Texture * texture, void **pixels, int *pitch)
   580 {
   581     DirectFB_TextureData *texturedata =
   582         (DirectFB_TextureData *) texture->driverdata;
   583 
   584     if (texturedata->display) {
   585         return -1;
   586     } else {
   587         *pixels = texturedata->pixels;
   588         *pitch = texturedata->pitch;
   589     }
   590     return 0;
   591 }
   592 
   593 static int
   594 DirectFB_SetTexturePalette(SDL_Renderer * renderer,
   595                            SDL_Texture * texture,
   596                            const SDL_Color * colors, int firstcolor,
   597                            int ncolors)
   598 {
   599     DirectFB_TextureData *data = (DirectFB_TextureData *) texture->driverdata;
   600  
   601     if (SDL_ISPIXELFORMAT_INDEXED(data->format)
   602         && !SDL_ISPIXELFORMAT_FOURCC(data->format)) {
   603         DFBColor entries[256];
   604         int i;
   605 
   606         for (i = 0; i < ncolors; ++i) {
   607             entries[i].r = colors[i].r;
   608             entries[i].g = colors[i].g;
   609             entries[i].b = colors[i].b;
   610             entries[i].a = 0xFF;
   611         }
   612         SDL_DFB_CHECKERR(data->
   613                          palette->SetEntries(data->palette, entries, ncolors,
   614                                              firstcolor));
   615         return 0;
   616     } else {
   617         SDL_SetError("YUV textures don't have a palette");
   618         return -1;
   619     }
   620   error:
   621     return -1;
   622 }
   623 
   624 static int
   625 DirectFB_GetTexturePalette(SDL_Renderer * renderer,
   626                            SDL_Texture * texture, SDL_Color * colors,
   627                            int firstcolor, int ncolors)
   628 {
   629     DirectFB_TextureData *data = (DirectFB_TextureData *) texture->driverdata;
   630 
   631     if (SDL_ISPIXELFORMAT_INDEXED(data->format)
   632         && !SDL_ISPIXELFORMAT_FOURCC(data->format)) {
   633         DFBColor entries[256];
   634         int i;
   635 
   636         SDL_DFB_CHECKERR(data->
   637                          palette->GetEntries(data->palette, entries, ncolors,
   638                                              firstcolor));
   639 
   640         for (i = 0; i < ncolors; ++i) {
   641             colors[i].r = entries[i].r;
   642             colors[i].g = entries[i].g;
   643             colors[i].b = entries[i].b;
   644             colors->unused = SDL_ALPHA_OPAQUE;
   645         }
   646         return 0;
   647     } else {
   648         SDL_SetError("YUV textures don't have a palette");
   649         return -1;
   650     }
   651   error:
   652     return -1;
   653 }
   654 
   655 static int
   656 DirectFB_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   657 {
   658     return 0;
   659 }
   660 
   661 static int
   662 DirectFB_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   663 {
   664     return 0;
   665 }
   666 
   667 static int
   668 DirectFB_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   669 {
   670     switch (texture->blendMode) {
   671     case SDL_BLENDMODE_NONE:
   672     case SDL_BLENDMODE_MASK:
   673     case SDL_BLENDMODE_BLEND:
   674     case SDL_BLENDMODE_ADD:
   675     case SDL_BLENDMODE_MOD:
   676         return 0;
   677     default:
   678         SDL_Unsupported();
   679         texture->blendMode = SDL_BLENDMODE_NONE;
   680         return -1;
   681     }
   682 }
   683 
   684 static int
   685 DirectFB_SetDrawBlendMode(SDL_Renderer * renderer)
   686 {
   687     switch (renderer->blendMode) {
   688     case SDL_BLENDMODE_NONE:
   689     case SDL_BLENDMODE_MASK:
   690     case SDL_BLENDMODE_BLEND:
   691     case SDL_BLENDMODE_ADD:
   692     case SDL_BLENDMODE_MOD:
   693         return 0;
   694     default:
   695         SDL_Unsupported();
   696         renderer->blendMode = SDL_BLENDMODE_NONE;
   697         return -1;
   698     }
   699 }
   700 
   701 static int
   702 DirectFB_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
   703 {
   704 #if (DFB_VERSION_ATLEAST(1,2,0))
   705 
   706     DirectFB_TextureData *data = (DirectFB_TextureData *) texture->driverdata;
   707 
   708     switch (texture->scaleMode) {
   709     case SDL_SCALEMODE_NONE:
   710     case SDL_SCALEMODE_FAST:
   711         data->render_options = DSRO_NONE;
   712         break;
   713     case SDL_SCALEMODE_SLOW:
   714         data->render_options = DSRO_SMOOTH_UPSCALE | DSRO_SMOOTH_DOWNSCALE;
   715         break;
   716     case SDL_SCALEMODE_BEST:
   717         data->render_options =
   718             DSRO_SMOOTH_UPSCALE | DSRO_SMOOTH_DOWNSCALE | DSRO_ANTIALIAS;
   719         break;
   720     default:
   721         SDL_Unsupported();
   722         data->render_options = DSRO_NONE;
   723         texture->scaleMode = SDL_SCALEMODE_NONE;
   724         return -1;
   725     }
   726 #endif
   727     return 0;
   728 }
   729 
   730 static int
   731 DirectFB_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   732                        const SDL_Rect * rect, const void *pixels, int pitch)
   733 {
   734     DirectFB_TextureData *data = (DirectFB_TextureData *) texture->driverdata;
   735     Uint8 *dpixels;
   736     int dpitch;
   737     Uint8 *src, *dst;
   738     int row;
   739     size_t length;
   740     int bpp = DFB_BYTES_PER_PIXEL(SDLToDFBPixelFormat(texture->format));
   741     // FIXME: SDL_BYTESPERPIXEL(texture->format) broken for yuv yv12 3 planes
   742 
   743     SDL_DFB_CHECKERR(data->surface->Lock(data->surface,
   744                                          DSLF_WRITE | DSLF_READ,
   745                                          ((void **) &dpixels), &dpitch));
   746     src = (Uint8 *) pixels;
   747     dst = (Uint8 *) dpixels + rect->y * dpitch + rect->x * bpp;
   748     length = rect->w * bpp;
   749     for (row = 0; row < rect->h; ++row) {
   750         SDL_memcpy(dst, src, length);
   751         src += pitch;
   752         dst += dpitch;
   753     }
   754     /* copy other planes for 3 plane formats */
   755     if (texture->format == SDL_PIXELFORMAT_YV12 ||
   756         texture->format == SDL_PIXELFORMAT_IYUV) {
   757         src = (Uint8 *) pixels + texture->h * pitch;
   758         dst = (Uint8 *) dpixels + texture->h * dpitch + rect->y * dpitch / 4 + rect->x * bpp / 2;
   759         for (row = 0; row < rect->h / 2; ++row) {
   760             SDL_memcpy(dst, src, length / 2);
   761             src += pitch / 2;
   762             dst += dpitch / 2;
   763         }
   764         src = (Uint8 *) pixels + texture->h * pitch + texture->h * pitch / 4;
   765         dst = (Uint8 *) dpixels + texture->h * dpitch + texture->h * dpitch / 4 + rect->y * dpitch / 4 + rect->x * bpp / 2;
   766         for (row = 0; row < rect->h / 2; ++row) {
   767             SDL_memcpy(dst, src, length / 2);
   768             src += pitch / 2;
   769             dst += dpitch / 2;
   770         }
   771     }
   772     SDL_DFB_CHECKERR(data->surface->Unlock(data->surface));
   773     return 0;
   774   error:
   775     return 1;
   776 
   777 }
   778 
   779 static int
   780 DirectFB_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   781                      const SDL_Rect * rect, int markDirty,
   782                      void **pixels, int *pitch)
   783 {
   784     DirectFB_TextureData *texturedata =
   785         (DirectFB_TextureData *) texture->driverdata;
   786 
   787     if (markDirty) {
   788         SDL_AddDirtyRect(&texturedata->dirty, rect);
   789     }
   790 
   791     if (texturedata->display) {
   792         void *fdata;
   793         int fpitch;
   794 
   795         SDL_DFB_CHECKERR(texturedata->surface->Lock(texturedata->surface,
   796                                                     DSLF_WRITE | DSLF_READ,
   797                                                     &fdata, &fpitch));
   798         *pitch = fpitch;
   799         *pixels = fdata;
   800     } else {
   801         *pixels =
   802             (void *) ((Uint8 *) texturedata->pixels +
   803                       rect->y * texturedata->pitch +
   804                       rect->x * DFB_BYTES_PER_PIXEL(SDLToDFBPixelFormat(texture->format)));
   805         *pitch = texturedata->pitch;
   806     }
   807     return 0;
   808 
   809   error:
   810     return -1;
   811 }
   812 
   813 static void
   814 DirectFB_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   815 {
   816     DirectFB_TextureData *texturedata =
   817         (DirectFB_TextureData *) texture->driverdata;
   818 
   819     if (texturedata->display) {
   820         SDL_DFB_CHECK(texturedata->surface->Unlock(texturedata->surface));
   821         texturedata->pixels = NULL;
   822     }
   823 }
   824 
   825 static void
   826 DirectFB_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   827                       int numrects, const SDL_Rect * rects)
   828 {
   829     DirectFB_TextureData *data = (DirectFB_TextureData *) texture->driverdata;
   830     int i;
   831 
   832     for (i = 0; i < numrects; ++i) {
   833         SDL_AddDirtyRect(&data->dirty, &rects[i]);
   834     }
   835 }
   836 
   837 static int
   838 PrepareDraw(SDL_Renderer * renderer)
   839 {
   840     DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
   841     SDL_DFB_WINDOWSURFACE(data->window);
   842 
   843     Uint8 r, g, b, a;
   844 
   845     r = renderer->r;
   846     g = renderer->g;
   847     b = renderer->b;
   848     a = renderer->a;
   849 
   850     SetBlendMode(data, renderer->blendMode, NULL);
   851     SDL_DFB_CHECKERR(destsurf->SetDrawingFlags(destsurf, data->drawFlags));
   852 
   853     switch (renderer->blendMode) {
   854     case SDL_BLENDMODE_NONE:
   855     case SDL_BLENDMODE_MASK:
   856     case SDL_BLENDMODE_BLEND:
   857         break;
   858     case SDL_BLENDMODE_ADD:
   859     case SDL_BLENDMODE_MOD:
   860         r = ((int) r * (int) a) / 255;
   861         g = ((int) g * (int) a) / 255;
   862         b = ((int) b * (int) a) / 255;
   863         a = 255;
   864         break;
   865     }
   866 
   867     SDL_DFB_CHECKERR(destsurf->SetColor(destsurf, r, g, b, a));
   868     return 0;
   869   error:
   870     return -1;
   871 }
   872 
   873 static int DirectFB_RenderDrawPoints(SDL_Renderer * renderer,
   874                                 const SDL_Point * points, int count)
   875 {
   876     DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
   877     SDL_DFB_WINDOWSURFACE(data->window);
   878     int i;
   879 
   880     PrepareDraw(renderer);
   881     for (i=0; i < count; i++)
   882     	SDL_DFB_CHECKERR(destsurf->DrawLine(destsurf, points[i].x, points[i].y, points[i].x, points[i].y));
   883     return 0;
   884   error:
   885     return -1;
   886 }
   887 
   888 static int DirectFB_RenderDrawLines(SDL_Renderer * renderer,
   889                                const SDL_Point * points, int count)
   890 {
   891     DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
   892     SDL_DFB_WINDOWSURFACE(data->window);
   893     int i;
   894 
   895     PrepareDraw(renderer);
   896     /* Use antialiasing when available */
   897 #if (DFB_VERSION_ATLEAST(1,2,0))
   898     SDL_DFB_CHECKERR(destsurf->SetRenderOptions(destsurf, DSRO_ANTIALIAS));
   899 #endif
   900 
   901     for (i=0; i < count - 1; i++)
   902     	SDL_DFB_CHECKERR(destsurf->DrawLine(destsurf, points[i].x, points[i].y, points[i+1].x, points[i+1].y));
   903 
   904     return 0;
   905   error:
   906     return -1;
   907 }
   908 
   909 static int
   910 DirectFB_RenderDrawRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count)
   911 {
   912     DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
   913     SDL_DFB_WINDOWSURFACE(data->window);
   914     int i;
   915 
   916     PrepareDraw(renderer);
   917 
   918     for (i=0; i<count; i++)
   919     	SDL_DFB_CHECKERR(destsurf->DrawRectangle(destsurf, rects[i]->x, rects[i]->y,
   920     			rects[i]->w, rects[i]->h));
   921 
   922     return 0;
   923   error:
   924     return -1;
   925 }
   926 
   927 static int
   928 DirectFB_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count)
   929 {
   930     DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
   931     SDL_DFB_WINDOWSURFACE(data->window);
   932     int i;
   933 
   934     PrepareDraw(renderer);
   935 
   936     for (i=0; i<count; i++)
   937     	SDL_DFB_CHECKERR(destsurf->FillRectangle(destsurf, rects[i]->x, rects[i]->y,
   938     			rects[i]->w, rects[i]->h));
   939 
   940     return 0;
   941   error:
   942     return -1;
   943 }
   944 
   945 static int
   946 DirectFB_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   947                     const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   948 {
   949     DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
   950     SDL_DFB_WINDOWSURFACE(data->window);
   951     DirectFB_TextureData *texturedata =
   952         (DirectFB_TextureData *) texture->driverdata;
   953     Uint8 alpha = 0xFF;
   954 
   955     if (texturedata->display) {
   956         int px, py;
   957         SDL_Window *window = renderer->window;
   958         SDL_DFB_WINDOWDATA(window);
   959         SDL_VideoDisplay *display = texturedata->display;
   960         DFB_DisplayData *dispdata = (DFB_DisplayData *) display->driverdata;
   961 
   962         SDL_DFB_CHECKERR(dispdata->
   963                          vidlayer->SetSourceRectangle(dispdata->vidlayer,
   964                                                       srcrect->x, srcrect->y,
   965                                                       srcrect->w,
   966                                                       srcrect->h));
   967         SDL_DFB_CHECK(windata->window->GetPosition(windata->window, &px, &py));
   968         px += windata->client.x;
   969         py += windata->client.y;
   970         SDL_DFB_CHECKERR(dispdata->
   971                          vidlayer->SetScreenRectangle(dispdata->vidlayer,
   972                                                       px + dstrect->x,
   973                                                       py + dstrect->y,
   974                                                       dstrect->w,
   975                                                       dstrect->h));
   976     } else {
   977         DFBRectangle sr, dr;
   978         DFBSurfaceBlittingFlags flags = 0;
   979 
   980         if (texturedata->dirty.list) {
   981             SDL_DirtyRect *dirty;
   982             void *pixels;
   983             int bpp = DFB_BYTES_PER_PIXEL(SDLToDFBPixelFormat(texture->format));
   984             int pitch = texturedata->pitch;
   985 
   986             for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) {
   987                 SDL_Rect *rect = &dirty->rect;
   988                 pixels =
   989                     (void *) ((Uint8 *) texturedata->pixels +
   990                               rect->y * pitch + rect->x * bpp);
   991                 DirectFB_UpdateTexture(renderer, texture, rect,
   992                                        texturedata->pixels,
   993                                        texturedata->pitch);
   994             }
   995             SDL_ClearDirtyRects(&texturedata->dirty);
   996         }
   997 
   998         SDLtoDFBRect(srcrect, &sr);
   999         SDLtoDFBRect(dstrect, &dr);
  1000 
  1001         SDL_DFB_CHECKERR(destsurf->
  1002                          SetColor(destsurf, 0xFF, 0xFF, 0xFF, 0xFF));
  1003         if (texture->
  1004             modMode & (SDL_TEXTUREMODULATE_COLOR | SDL_TEXTUREMODULATE_ALPHA))
  1005         {
  1006             if (texture->modMode & SDL_TEXTUREMODULATE_ALPHA) {
  1007                 alpha = texture->a;
  1008                 SDL_DFB_CHECKERR(destsurf->SetColor(destsurf, 0xFF, 0xFF,
  1009                                                     0xFF, alpha));
  1010             }
  1011             if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) {
  1012 
  1013                 SDL_DFB_CHECKERR(destsurf->SetColor(destsurf,
  1014                                                     texture->r,
  1015                                                     texture->g,
  1016                                                     texture->b, alpha));
  1017                 flags |= DSBLIT_COLORIZE;
  1018             }
  1019             if (alpha < 0xFF)
  1020                 flags |= DSBLIT_SRC_PREMULTCOLOR;
  1021         } else
  1022             SDL_DFB_CHECKERR(destsurf->SetColor(destsurf, 0xFF, 0xFF,
  1023                                                 0xFF, 0xFF));
  1024 
  1025         SetBlendMode(data, texture->blendMode, texturedata);
  1026 
  1027         SDL_DFB_CHECKERR(destsurf->SetBlittingFlags(destsurf,
  1028                                                     data->blitFlags | flags));
  1029 
  1030 #if (DFB_VERSION_ATLEAST(1,2,0))
  1031         SDL_DFB_CHECKERR(destsurf->SetRenderOptions(destsurf,
  1032                                                     texturedata->
  1033                                                     render_options));
  1034 #endif
  1035 
  1036         if (srcrect->w == dstrect->w && srcrect->h == dstrect->h) {
  1037             SDL_DFB_CHECKERR(destsurf->Blit(destsurf,
  1038                                             texturedata->surface,
  1039                                             &sr, dr.x, dr.y));
  1040         } else {
  1041             SDL_DFB_CHECKERR(destsurf->StretchBlit(destsurf,
  1042                                                    texturedata->surface,
  1043                                                    &sr, &dr));
  1044         }
  1045     }
  1046     return 0;
  1047   error:
  1048     return -1;
  1049 }
  1050 
  1051 static void
  1052 DirectFB_RenderPresent(SDL_Renderer * renderer)
  1053 {
  1054     DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
  1055     SDL_Window *window = renderer->window;
  1056     SDL_DFB_WINDOWDATA(window);
  1057 
  1058     DFBRectangle sr;
  1059 
  1060     sr.x = 0;
  1061     sr.y = 0;
  1062     sr.w = window->w;
  1063     sr.h = window->h;
  1064 
  1065     /* Send the data to the display */
  1066     SDL_DFB_CHECK(windata->window_surface->Flip(windata->window_surface, NULL,
  1067                                                 data->flipflags));
  1068 }
  1069 
  1070 static void
  1071 DirectFB_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1072 {
  1073     DirectFB_TextureData *data = (DirectFB_TextureData *) texture->driverdata;
  1074 
  1075     if (!data) {
  1076         return;
  1077     }
  1078     SDL_DFB_RELEASE(data->palette);
  1079     SDL_DFB_RELEASE(data->surface);
  1080     if (data->display) {
  1081         DFB_DisplayData *dispdata =
  1082             (DFB_DisplayData *) data->display->driverdata;
  1083         dispdata->vidIDinuse = 0;
  1084         /* FIXME: Shouldn't we reset the cooperative level */
  1085         SDL_DFB_CHECK(dispdata->vidlayer->SetCooperativeLevel(dispdata->vidlayer,
  1086                                                 DLSCL_ADMINISTRATIVE));
  1087         SDL_DFB_RELEASE(dispdata->vidlayer);
  1088     }
  1089     SDL_FreeDirtyRects(&data->dirty);
  1090     SDL_DFB_FREE(data->pixels);
  1091     SDL_free(data);
  1092     texture->driverdata = NULL;
  1093 }
  1094 
  1095 static void
  1096 DirectFB_DestroyRenderer(SDL_Renderer * renderer)
  1097 {
  1098     DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
  1099 
  1100     if (data) {
  1101         SDL_free(data);
  1102     }
  1103     SDL_free(renderer);
  1104 }
  1105 
  1106 /* vi: set ts=4 sw=4 expandtab: */