sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_DirectFB_render.c (36348B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      4 
      5   This software is provided 'as-is', without any express or implied
      6   warranty.  In no event will the authors be held liable for any damages
      7   arising from the use of this software.
      8 
      9   Permission is granted to anyone to use this software for any purpose,
     10   including commercial applications, and to alter it and redistribute it
     11   freely, subject to the following restrictions:
     12 
     13   1. The origin of this software must not be misrepresented; you must not
     14      claim that you wrote the original software. If you use this software
     15      in a product, an acknowledgment in the product documentation would be
     16      appreciated but is not required.
     17   2. Altered source versions must be plainly marked as such, and must not be
     18      misrepresented as being the original software.
     19   3. This notice may not be removed or altered from any source distribution.
     20 */
     21 #include "../../SDL_internal.h"
     22 
     23 #if SDL_VIDEO_DRIVER_DIRECTFB
     24 #include "SDL_DirectFB_window.h"
     25 #include "SDL_DirectFB_modes.h"
     26 
     27 #include "SDL_syswm.h"
     28 #include "SDL_DirectFB_shape.h"
     29 
     30 #include "../SDL_sysvideo.h"
     31 #include "../../render/SDL_sysrender.h"
     32 
     33 #ifndef DFB_VERSION_ATLEAST
     34 
     35 #define DFB_VERSIONNUM(X, Y, Z)                     \
     36     ((X)*1000 + (Y)*100 + (Z))
     37 
     38 #define DFB_COMPILEDVERSION \
     39     DFB_VERSIONNUM(DIRECTFB_MAJOR_VERSION, DIRECTFB_MINOR_VERSION, DIRECTFB_MICRO_VERSION)
     40 
     41 #define DFB_VERSION_ATLEAST(X, Y, Z) \
     42     (DFB_COMPILEDVERSION >= DFB_VERSIONNUM(X, Y, Z))
     43 
     44 #define SDL_DFB_CHECK(x)    x
     45 
     46 #endif
     47 
     48 /* the following is not yet tested ... */
     49 #define USE_DISPLAY_PALETTE         (0)
     50 
     51 
     52 #define SDL_DFB_RENDERERDATA(rend) DirectFB_RenderData *renddata = ((rend) ? (DirectFB_RenderData *) (rend)->driverdata : NULL)
     53 #define SDL_DFB_WINDOWSURFACE(win)  IDirectFBSurface *destsurf = ((DFB_WindowData *) ((win)->driverdata))->surface;
     54 
     55 typedef struct
     56 {
     57     SDL_Window *window;
     58     DFBSurfaceFlipFlags flipflags;
     59     int size_changed;
     60     int lastBlendMode;
     61     DFBSurfaceBlittingFlags blitFlags;
     62     DFBSurfaceDrawingFlags drawFlags;
     63     IDirectFBSurface* target;
     64 } DirectFB_RenderData;
     65 
     66 typedef struct
     67 {
     68     IDirectFBSurface *surface;
     69     Uint32 format;
     70     void *pixels;
     71     int pitch;
     72     IDirectFBPalette *palette;
     73     int isDirty;
     74 
     75     SDL_VideoDisplay *display;      /* only for yuv textures */
     76 
     77 #if (DFB_VERSION_ATLEAST(1,2,0))
     78     DFBSurfaceRenderOptions render_options;
     79 #endif
     80 } DirectFB_TextureData;
     81 
     82 static SDL_INLINE void
     83 SDLtoDFBRect(const SDL_Rect * sr, DFBRectangle * dr)
     84 {
     85     dr->x = sr->x;
     86     dr->y = sr->y;
     87     dr->h = sr->h;
     88     dr->w = sr->w;
     89 }
     90 static SDL_INLINE void
     91 SDLtoDFBRect_Float(const SDL_FRect * sr, DFBRectangle * dr)
     92 {
     93     dr->x = sr->x;
     94     dr->y = sr->y;
     95     dr->h = sr->h;
     96     dr->w = sr->w;
     97 }
     98 
     99 
    100 static int
    101 TextureHasAlpha(DirectFB_TextureData * data)
    102 {
    103     /* Drawing primitive ? */
    104     if (!data)
    105         return 0;
    106 
    107     return (DFB_PIXELFORMAT_HAS_ALPHA(DirectFB_SDLToDFBPixelFormat(data->format)) ? 1 : 0);
    108 #if 0
    109     switch (data->format) {
    110     case SDL_PIXELFORMAT_INDEX4LSB:
    111     case SDL_PIXELFORMAT_INDEX4MSB:
    112     case SDL_PIXELFORMAT_ARGB4444:
    113     case SDL_PIXELFORMAT_ARGB1555:
    114     case SDL_PIXELFORMAT_ARGB8888:
    115     case SDL_PIXELFORMAT_RGBA8888:
    116     case SDL_PIXELFORMAT_ABGR8888:
    117     case SDL_PIXELFORMAT_BGRA8888:
    118     case SDL_PIXELFORMAT_ARGB2101010:
    119        return 1;
    120     default:
    121         return 0;
    122     }
    123 #endif
    124 }
    125 
    126 static SDL_INLINE IDirectFBSurface *get_dfb_surface(SDL_Window *window)
    127 {
    128     SDL_SysWMinfo wm_info;
    129     SDL_memset(&wm_info, 0, sizeof(SDL_SysWMinfo));
    130 
    131     SDL_VERSION(&wm_info.version);
    132     if (!SDL_GetWindowWMInfo(window, &wm_info)) {
    133         return NULL;
    134     }
    135 
    136     return wm_info.info.dfb.surface;
    137 }
    138 
    139 static SDL_INLINE IDirectFBWindow *get_dfb_window(SDL_Window *window)
    140 {
    141     SDL_SysWMinfo wm_info;
    142     SDL_memset(&wm_info, 0, sizeof(SDL_SysWMinfo));
    143 
    144     SDL_VERSION(&wm_info.version);
    145     if (!SDL_GetWindowWMInfo(window, &wm_info)) {
    146         return NULL;
    147     }
    148 
    149     return wm_info.info.dfb.window;
    150 }
    151 
    152 static void
    153 SetBlendMode(DirectFB_RenderData * data, int blendMode,
    154              DirectFB_TextureData * source)
    155 {
    156     IDirectFBSurface *destsurf = data->target;
    157 
    158     /* FIXME: check for format change */
    159     if (1 || data->lastBlendMode != blendMode) {
    160         switch (blendMode) {
    161         case SDL_BLENDMODE_NONE:
    162                                            /**< No blending */
    163             data->blitFlags = DSBLIT_NOFX;
    164             data->drawFlags = DSDRAW_NOFX;
    165             SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_ONE));
    166             SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_ZERO));
    167             break;
    168 #if 0
    169         case SDL_BLENDMODE_MASK:
    170             data->blitFlags =  DSBLIT_BLEND_ALPHACHANNEL;
    171             data->drawFlags = DSDRAW_BLEND;
    172             SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_SRCALPHA));
    173             SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_INVSRCALPHA));
    174             break;
    175 #endif
    176         case SDL_BLENDMODE_BLEND:
    177             data->blitFlags = DSBLIT_BLEND_ALPHACHANNEL;
    178             data->drawFlags = DSDRAW_BLEND;
    179             SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_SRCALPHA));
    180             SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_INVSRCALPHA));
    181             break;
    182         case SDL_BLENDMODE_ADD:
    183             data->blitFlags = DSBLIT_BLEND_ALPHACHANNEL;
    184             data->drawFlags = DSDRAW_BLEND;
    185             /* FIXME: SRCALPHA kills performance on radeon ...
    186              * It will be cheaper to copy the surface to a temporary surface and premultiply
    187              */
    188             if (source && TextureHasAlpha(source))
    189                 SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_SRCALPHA));
    190             else
    191                 SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_ONE));
    192             SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_ONE));
    193             break;
    194         case SDL_BLENDMODE_MOD:
    195             data->blitFlags = DSBLIT_BLEND_ALPHACHANNEL;
    196             data->drawFlags = DSDRAW_BLEND;
    197             SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_ZERO));
    198             SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_SRCCOLOR));
    199 
    200             break;
    201         case SDL_BLENDMODE_MUL:
    202             data->blitFlags = DSBLIT_BLEND_ALPHACHANNEL;
    203             data->drawFlags = DSDRAW_BLEND;
    204             SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_DESTCOLOR));
    205             SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_INVSRCALPHA));
    206 
    207             break;
    208         }
    209         data->lastBlendMode = blendMode;
    210     }
    211 }
    212 
    213 static int
    214 PrepareDraw(SDL_Renderer * renderer, const SDL_RenderCommand *cmd)
    215 {
    216     DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    217     IDirectFBSurface *destsurf = data->target;
    218     Uint8 r = cmd->data.draw.r;
    219     Uint8 g = cmd->data.draw.g;
    220     Uint8 b = cmd->data.draw.b;
    221     Uint8 a = cmd->data.draw.a;
    222 
    223     SetBlendMode(data, cmd->data.draw.blend, NULL);
    224     SDL_DFB_CHECKERR(destsurf->SetDrawingFlags(destsurf, data->drawFlags));
    225 
    226     switch (renderer->blendMode) {
    227     case SDL_BLENDMODE_NONE:
    228     /* case SDL_BLENDMODE_MASK: */
    229     case SDL_BLENDMODE_BLEND:
    230         break;
    231     case SDL_BLENDMODE_ADD:
    232     case SDL_BLENDMODE_MOD:
    233     case SDL_BLENDMODE_MUL:
    234         r = ((int) r * (int) a) / 255;
    235         g = ((int) g * (int) a) / 255;
    236         b = ((int) b * (int) a) / 255;
    237         a = 255;
    238         break;
    239     case SDL_BLENDMODE_INVALID: break;
    240     }
    241 
    242     SDL_DFB_CHECKERR(destsurf->SetColor(destsurf, r, g, b, a));
    243     return 0;
    244   error:
    245     return -1;
    246 }
    247 
    248 static void
    249 DirectFB_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
    250 {
    251     SDL_DFB_RENDERERDATA(renderer);
    252 
    253     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
    254         /* Rebind the context to the window area and update matrices */
    255         /* SDL_CurrentContext = NULL; */
    256         /* data->updateSize = SDL_TRUE; */
    257         renddata->size_changed = SDL_TRUE;
    258    }
    259 }
    260 
    261 static void
    262 DirectFB_ActivateRenderer(SDL_Renderer * renderer)
    263 {
    264     SDL_DFB_RENDERERDATA(renderer);
    265 
    266     if (renddata->size_changed /* || windata->wm_needs_redraw */) {
    267         renddata->size_changed = SDL_FALSE;
    268     }
    269 }
    270 
    271 static int
    272 DirectFB_AcquireVidLayer(SDL_Renderer * renderer, SDL_Texture * texture)
    273 {
    274     SDL_Window *window = renderer->window;
    275     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
    276     SDL_DFB_DEVICEDATA(display->device);
    277     DFB_DisplayData *dispdata = (DFB_DisplayData *) display->driverdata;
    278     DirectFB_TextureData *data = texture->driverdata;
    279     DFBDisplayLayerConfig layconf;
    280     DFBResult ret;
    281 
    282     if (devdata->use_yuv_direct && (dispdata->vidID >= 0)
    283         && (!dispdata->vidIDinuse)
    284         && SDL_ISPIXELFORMAT_FOURCC(data->format)) {
    285         layconf.flags =
    286             DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT |
    287             DLCONF_SURFACE_CAPS;
    288         layconf.width = texture->w;
    289         layconf.height = texture->h;
    290         layconf.pixelformat = DirectFB_SDLToDFBPixelFormat(data->format);
    291         layconf.surface_caps = DSCAPS_VIDEOONLY | DSCAPS_DOUBLE;
    292 
    293         SDL_DFB_CHECKERR(devdata->dfb->GetDisplayLayer(devdata->dfb,
    294                                                        dispdata->vidID,
    295                                                        &dispdata->vidlayer));
    296         SDL_DFB_CHECKERR(dispdata->
    297                          vidlayer->SetCooperativeLevel(dispdata->vidlayer,
    298                                                        DLSCL_EXCLUSIVE));
    299 
    300         if (devdata->use_yuv_underlays) {
    301             ret = dispdata->vidlayer->SetLevel(dispdata->vidlayer, -1);
    302             if (ret != DFB_OK)
    303                 SDL_DFB_DEBUG("Underlay Setlevel not supported\n");
    304         }
    305         SDL_DFB_CHECKERR(dispdata->
    306                          vidlayer->SetConfiguration(dispdata->vidlayer,
    307                                                     &layconf));
    308         SDL_DFB_CHECKERR(dispdata->
    309                          vidlayer->GetSurface(dispdata->vidlayer,
    310                                               &data->surface));
    311         dispdata->vidIDinuse = 1;
    312         data->display = display;
    313         return 0;
    314     }
    315     return 1;
    316   error:
    317     if (dispdata->vidlayer) {
    318         SDL_DFB_RELEASE(data->surface);
    319         SDL_DFB_CHECKERR(dispdata->
    320                          vidlayer->SetCooperativeLevel(dispdata->vidlayer,
    321                                                        DLSCL_ADMINISTRATIVE));
    322         SDL_DFB_RELEASE(dispdata->vidlayer);
    323     }
    324     return 1;
    325 }
    326 
    327 static int
    328 DirectFB_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
    329 {
    330     SDL_Window *window = renderer->window;
    331     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
    332     SDL_DFB_DEVICEDATA(display->device);
    333     DirectFB_TextureData *data;
    334     DFBSurfaceDescription dsc;
    335     DFBSurfacePixelFormat pixelformat;
    336 
    337     DirectFB_ActivateRenderer(renderer);
    338 
    339     SDL_DFB_ALLOC_CLEAR(data, sizeof(*data));
    340     texture->driverdata = data;
    341 
    342     /* find the right pixelformat */
    343     pixelformat = DirectFB_SDLToDFBPixelFormat(texture->format);
    344     if (pixelformat == DSPF_UNKNOWN) {
    345         SDL_SetError("Unknown pixel format %d", data->format);
    346         goto error;
    347     }
    348 
    349     data->format = texture->format;
    350     data->pitch = texture->w * DFB_BYTES_PER_PIXEL(pixelformat);
    351 
    352     if (DirectFB_AcquireVidLayer(renderer, texture) != 0) {
    353         /* fill surface description */
    354         dsc.flags =
    355             DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT | DSDESC_CAPS;
    356         dsc.width = texture->w;
    357         dsc.height = texture->h;
    358         if(texture->format == SDL_PIXELFORMAT_YV12 ||
    359            texture->format == SDL_PIXELFORMAT_IYUV) {
    360            /* dfb has problems with odd sizes -make them even internally */
    361            dsc.width += (dsc.width % 2);
    362            dsc.height += (dsc.height % 2);
    363         }
    364         /* <1.2 Never use DSCAPS_VIDEOONLY here. It kills performance
    365          * No DSCAPS_SYSTEMONLY either - let dfb decide
    366          * 1.2: DSCAPS_SYSTEMONLY boosts performance by factor ~8
    367          * Depends on other settings as well. Let dfb decide.
    368          */
    369         dsc.caps = DSCAPS_PREMULTIPLIED;
    370 #if 0
    371         if (texture->access == SDL_TEXTUREACCESS_STREAMING)
    372             dsc.caps |= DSCAPS_SYSTEMONLY;
    373         else
    374             dsc.caps |= DSCAPS_VIDEOONLY;
    375 #endif
    376 
    377         dsc.pixelformat = pixelformat;
    378         data->pixels = NULL;
    379 
    380         /* Create the surface */
    381         SDL_DFB_CHECKERR(devdata->dfb->CreateSurface(devdata->dfb, &dsc,
    382                                                      &data->surface));
    383         if (SDL_ISPIXELFORMAT_INDEXED(data->format)
    384             && !SDL_ISPIXELFORMAT_FOURCC(data->format)) {
    385 #if 1
    386             SDL_DFB_CHECKERR(data->surface->GetPalette(data->surface, &data->palette));
    387 #else
    388             /* DFB has issues with blitting LUT8 surfaces.
    389              * Creating a new palette does not help.
    390              */
    391             DFBPaletteDescription pal_desc;
    392             pal_desc.flags = DPDESC_SIZE; /* | DPDESC_ENTRIES */
    393             pal_desc.size = 256;
    394             SDL_DFB_CHECKERR(devdata->dfb->CreatePalette(devdata->dfb, &pal_desc,&data->palette));
    395             SDL_DFB_CHECKERR(data->surface->SetPalette(data->surface, data->palette));
    396 #endif
    397         }
    398 
    399     }
    400 #if (DFB_VERSION_ATLEAST(1,2,0))
    401     data->render_options = DSRO_NONE;
    402 #endif
    403     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
    404         /* 3 plane YUVs return 1 bpp, but we need more space for other planes */
    405         if(texture->format == SDL_PIXELFORMAT_YV12 ||
    406            texture->format == SDL_PIXELFORMAT_IYUV) {
    407             SDL_DFB_ALLOC_CLEAR(data->pixels, (texture->h * data->pitch  + ((texture->h + texture->h % 2) * (data->pitch + data->pitch % 2) * 2) / 4));
    408         } else {
    409             SDL_DFB_ALLOC_CLEAR(data->pixels, texture->h * data->pitch);
    410         }
    411     }
    412 
    413     return 0;
    414 
    415   error:
    416     SDL_DFB_RELEASE(data->palette);
    417     SDL_DFB_RELEASE(data->surface);
    418     SDL_DFB_FREE(texture->driverdata);
    419     return -1;
    420 }
    421 
    422 #if 0
    423 static int
    424 DirectFB_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
    425 {
    426 #if (DFB_VERSION_ATLEAST(1,2,0))
    427 
    428     DirectFB_TextureData *data = (DirectFB_TextureData *) texture->driverdata;
    429 
    430     switch (texture->scaleMode) {
    431     case SDL_SCALEMODE_NONE:
    432     case SDL_SCALEMODE_FAST:
    433         data->render_options = DSRO_NONE;
    434         break;
    435     case SDL_SCALEMODE_SLOW:
    436         data->render_options = DSRO_SMOOTH_UPSCALE | DSRO_SMOOTH_DOWNSCALE;
    437         break;
    438     case SDL_SCALEMODE_BEST:
    439         data->render_options =
    440             DSRO_SMOOTH_UPSCALE | DSRO_SMOOTH_DOWNSCALE | DSRO_ANTIALIAS;
    441         break;
    442     default:
    443         data->render_options = DSRO_NONE;
    444         texture->scaleMode = SDL_SCALEMODE_NONE;
    445         return SDL_Unsupported();
    446     }
    447 #endif
    448     return 0;
    449 }
    450 #endif
    451 
    452 static int
    453 DirectFB_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    454                        const SDL_Rect * rect, const void *pixels, int pitch)
    455 {
    456     DirectFB_TextureData *data = (DirectFB_TextureData *) texture->driverdata;
    457     Uint8 *dpixels;
    458     int dpitch;
    459     Uint8 *src, *dst;
    460     int row;
    461     size_t length;
    462     int bpp = DFB_BYTES_PER_PIXEL(DirectFB_SDLToDFBPixelFormat(texture->format));
    463     /* FIXME: SDL_BYTESPERPIXEL(texture->format) broken for yuv yv12 3 planes */
    464 
    465     DirectFB_ActivateRenderer(renderer);
    466 
    467     if ((texture->format == SDL_PIXELFORMAT_YV12) ||
    468         (texture->format == SDL_PIXELFORMAT_IYUV)) {
    469         bpp = 1;
    470     }
    471 
    472     SDL_DFB_CHECKERR(data->surface->Lock(data->surface,
    473                                          DSLF_WRITE | DSLF_READ,
    474                                          ((void **) &dpixels), &dpitch));
    475     src = (Uint8 *) pixels;
    476     dst = (Uint8 *) dpixels + rect->y * dpitch + rect->x * bpp;
    477     length = rect->w * bpp;
    478     for (row = 0; row < rect->h; ++row) {
    479         SDL_memcpy(dst, src, length);
    480         src += pitch;
    481         dst += dpitch;
    482     }
    483     /* copy other planes for 3 plane formats */
    484     if ((texture->format == SDL_PIXELFORMAT_YV12) ||
    485         (texture->format == SDL_PIXELFORMAT_IYUV)) {
    486         src = (Uint8 *) pixels + texture->h * pitch;
    487         dst = (Uint8 *) dpixels + texture->h * dpitch + rect->y * dpitch / 4 + rect->x * bpp / 2;
    488         for (row = 0; row < rect->h / 2 + (rect->h & 1); ++row) {
    489             SDL_memcpy(dst, src, length / 2);
    490             src += pitch / 2;
    491             dst += dpitch / 2;
    492         }
    493         src = (Uint8 *) pixels + texture->h * pitch + texture->h * pitch / 4;
    494         dst = (Uint8 *) dpixels + texture->h * dpitch + texture->h * dpitch / 4 + rect->y * dpitch / 4 + rect->x * bpp / 2;
    495         for (row = 0; row < rect->h / 2 + (rect->h & 1); ++row) {
    496             SDL_memcpy(dst, src, length / 2);
    497             src += pitch / 2;
    498             dst += dpitch / 2;
    499         }
    500     }
    501     SDL_DFB_CHECKERR(data->surface->Unlock(data->surface));
    502     data->isDirty = 0;
    503     return 0;
    504   error:
    505     return 1;
    506 
    507 }
    508 
    509 static int
    510 DirectFB_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    511                      const SDL_Rect * rect, void **pixels, int *pitch)
    512 {
    513     DirectFB_TextureData *texturedata =
    514         (DirectFB_TextureData *) texture->driverdata;
    515 
    516     DirectFB_ActivateRenderer(renderer);
    517 
    518 #if 0
    519     if (markDirty) {
    520         SDL_AddDirtyRect(&texturedata->dirty, rect);
    521     }
    522 #endif
    523 
    524     if (texturedata->display) {
    525         void *fdata;
    526         int fpitch;
    527 
    528         SDL_DFB_CHECKERR(texturedata->surface->Lock(texturedata->surface,
    529                                                     DSLF_WRITE | DSLF_READ,
    530                                                     &fdata, &fpitch));
    531         *pitch = fpitch;
    532         *pixels = fdata;
    533     } else {
    534         *pixels =
    535             (void *) ((Uint8 *) texturedata->pixels +
    536                       rect->y * texturedata->pitch +
    537                       rect->x * DFB_BYTES_PER_PIXEL(DirectFB_SDLToDFBPixelFormat(texture->format)));
    538         *pitch = texturedata->pitch;
    539         texturedata->isDirty = 1;
    540     }
    541     return 0;
    542 
    543   error:
    544     return -1;
    545 }
    546 
    547 static void
    548 DirectFB_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
    549 {
    550     DirectFB_TextureData *texturedata =
    551         (DirectFB_TextureData *) texture->driverdata;
    552 
    553     DirectFB_ActivateRenderer(renderer);
    554 
    555     if (texturedata->display) {
    556         SDL_DFB_CHECK(texturedata->surface->Unlock(texturedata->surface));
    557         texturedata->pixels = NULL;
    558     }
    559 }
    560 
    561 static void
    562 DirectFB_SetTextureScaleMode()
    563 {
    564 }
    565 
    566 #if 0
    567 static void
    568 DirectFB_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    569                       int numrects, const SDL_Rect * rects)
    570 {
    571     DirectFB_TextureData *data = (DirectFB_TextureData *) texture->driverdata;
    572     int i;
    573 
    574     for (i = 0; i < numrects; ++i) {
    575         SDL_AddDirtyRect(&data->dirty, &rects[i]);
    576     }
    577 }
    578 #endif
    579 
    580 static int DirectFB_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
    581 {
    582     DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    583     DirectFB_TextureData *tex_data = NULL;
    584 
    585     DirectFB_ActivateRenderer(renderer);
    586     if (texture) {
    587         tex_data = (DirectFB_TextureData *) texture->driverdata;
    588         data->target = tex_data->surface;
    589     } else {
    590         data->target = get_dfb_surface(data->window);
    591     }
    592     data->lastBlendMode = 0;
    593     return 0;
    594 }
    595 
    596 
    597 static int
    598 DirectFB_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
    599 {
    600     return 0;  /* nothing to do in this backend. */
    601 }
    602 
    603 static int
    604 DirectFB_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
    605 {
    606     const size_t len = count * sizeof (SDL_FPoint);
    607     SDL_FPoint *verts = (SDL_FPoint *) SDL_AllocateRenderVertices(renderer, len, 0, &cmd->data.draw.first);
    608 
    609     if (!verts) {
    610         return -1;
    611     }
    612 
    613     cmd->data.draw.count = count;
    614     SDL_memcpy(verts, points, len);
    615     return 0;
    616 }
    617 
    618 static int
    619 DirectFB_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
    620 {
    621     const size_t len = count * sizeof (SDL_FRect);
    622     SDL_FRect *verts = (SDL_FRect *) SDL_AllocateRenderVertices(renderer, len, 0, &cmd->data.draw.first);
    623 
    624     if (!verts) {
    625         return -1;
    626     }
    627 
    628     cmd->data.draw.count = count;
    629     SDL_memcpy(verts, rects, len);
    630     return 0;
    631 }
    632 
    633 static int
    634 DirectFB_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
    635              const SDL_Rect * srcrect, const SDL_FRect * dstrect)
    636 {
    637     DFBRectangle *verts = (DFBRectangle *) SDL_AllocateRenderVertices(renderer, 2 * sizeof (DFBRectangle), 0, &cmd->data.draw.first);
    638 
    639     if (!verts) {
    640         return -1;
    641     }
    642 
    643     cmd->data.draw.count = 1;
    644 
    645     SDLtoDFBRect(srcrect, verts++);
    646     SDLtoDFBRect_Float(dstrect, verts);
    647 
    648     return 0;
    649 }
    650 
    651 static int
    652 DirectFB_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
    653                const SDL_Rect * srcrect, const SDL_FRect * dstrect,
    654                const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
    655 {
    656     return SDL_Unsupported();
    657 }
    658 
    659 
    660 static int
    661 DirectFB_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
    662 {
    663     /* !!! FIXME: there are probably some good optimization wins in here if someone wants to look it over. */
    664     DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    665     IDirectFBSurface *destsurf = data->target;
    666     DFBRegion clip_region;
    667     size_t i;
    668 
    669     DirectFB_ActivateRenderer(renderer);
    670 
    671     SDL_zero(clip_region);  /* in theory, this always gets set before use. */
    672 
    673     while (cmd) {
    674         switch (cmd->command) {
    675             case SDL_RENDERCMD_SETDRAWCOLOR:
    676                 break;  /* not used here */
    677 
    678             case SDL_RENDERCMD_SETVIEWPORT: {
    679                 const SDL_Rect *viewport = &cmd->data.viewport.rect;
    680                 clip_region.x1 = viewport->x;
    681                 clip_region.y1 = viewport->y;
    682                 clip_region.x2 = clip_region.x1 + viewport->w - 1;
    683                 clip_region.y2 = clip_region.y1 + viewport->h - 1;
    684                 destsurf->SetClip(destsurf, &clip_region);
    685                 break;
    686             }
    687 
    688             case SDL_RENDERCMD_SETCLIPRECT: {
    689                 /* !!! FIXME: how does this SetClip interact with the one in SETVIEWPORT? */
    690                 if (cmd->data.cliprect.enabled) {
    691                     const SDL_Rect *rect = &cmd->data.cliprect.rect;
    692                     clip_region.x1 = rect->x;
    693                     clip_region.x2 = rect->x + rect->w;
    694                     clip_region.y1 = rect->y;
    695                     clip_region.y2 = rect->y + rect->h;
    696                     destsurf->SetClip(destsurf, &clip_region);
    697                 }
    698                 break;
    699             }
    700 
    701             case SDL_RENDERCMD_CLEAR: {
    702                 const Uint8 r = cmd->data.color.r;
    703                 const Uint8 g = cmd->data.color.g;
    704                 const Uint8 b = cmd->data.color.b;
    705                 const Uint8 a = cmd->data.color.a;
    706                 destsurf->Clear(destsurf, r, g, b, a);
    707                 break;
    708             }
    709 
    710             case SDL_RENDERCMD_DRAW_POINTS: {
    711                 const size_t count = cmd->data.draw.count;
    712                 const SDL_FPoint *points = (SDL_FPoint *) (((Uint8 *) vertices) + cmd->data.draw.first);
    713                 PrepareDraw(renderer, cmd);
    714                 for (i = 0; i < count; i++) {
    715                     const int x = points[i].x + clip_region.x1;
    716                     const int y = points[i].y + clip_region.y1;
    717                     destsurf->DrawLine(destsurf, x, y, x, y);
    718                 }
    719                 break;
    720             }
    721 
    722             case SDL_RENDERCMD_DRAW_LINES: {
    723                 const SDL_FPoint *points = (SDL_FPoint *) (((Uint8 *) vertices) + cmd->data.draw.first);
    724                 const size_t count = cmd->data.draw.count;
    725 
    726                 PrepareDraw(renderer, cmd);
    727 
    728                 #if (DFB_VERSION_ATLEAST(1,2,0))  /* !!! FIXME: should this be set once, somewhere else? */
    729                 destsurf->SetRenderOptions(destsurf, DSRO_ANTIALIAS);
    730                 #endif
    731 
    732                 for (i = 0; i < count - 1; i++) {
    733                     const int x1 = points[i].x + clip_region.x1;
    734                     const int y1 = points[i].y + clip_region.y1;
    735                     const int x2 = points[i + 1].x + clip_region.x1;
    736                     const int y2 = points[i + 1].y + clip_region.y1;
    737                     destsurf->DrawLine(destsurf, x1, y1, x2, y2);
    738                 }
    739                 break;
    740             }
    741 
    742             case SDL_RENDERCMD_FILL_RECTS: {
    743                 const SDL_FRect *rects = (SDL_FRect *) (((Uint8 *) vertices) + cmd->data.draw.first);
    744                 const size_t count = cmd->data.draw.count;
    745 
    746                 PrepareDraw(renderer, cmd);
    747 
    748                 for (i = 0; i < count; i++, rects++) {
    749                     destsurf->FillRectangle(destsurf, rects->x + clip_region.x1, rects->y + clip_region.y1, rects->w, rects->h);
    750                 }
    751                 break;
    752             }
    753 
    754             case SDL_RENDERCMD_COPY: {
    755                 SDL_Texture *texture = cmd->data.draw.texture;
    756                 const Uint8 r = cmd->data.draw.r;
    757                 const Uint8 g = cmd->data.draw.g;
    758                 const Uint8 b = cmd->data.draw.b;
    759                 const Uint8 a = cmd->data.draw.a;
    760                 DFBRectangle *verts = (DFBRectangle *) (((Uint8 *) vertices) + cmd->data.draw.first);
    761                 DirectFB_TextureData *texturedata = (DirectFB_TextureData *) texture->driverdata;
    762                 DFBRectangle *sr = verts++;
    763                 DFBRectangle *dr = verts;
    764 
    765                 dr->x += clip_region.x1;
    766                 dr->y += clip_region.y1;
    767 
    768                 if (texturedata->display) {
    769                     int px, py;
    770                     SDL_Window *window = renderer->window;
    771                     IDirectFBWindow *dfbwin = get_dfb_window(window);
    772                     SDL_DFB_WINDOWDATA(window);
    773                     SDL_VideoDisplay *display = texturedata->display;
    774                     DFB_DisplayData *dispdata = (DFB_DisplayData *) display->driverdata;
    775 
    776                     dispdata->vidlayer->SetSourceRectangle(dispdata->vidlayer, sr->x, sr->y, sr->w, sr->h);
    777                     dfbwin->GetPosition(dfbwin, &px, &py);
    778                     px += windata->client.x;
    779                     py += windata->client.y;
    780                     dispdata->vidlayer->SetScreenRectangle(dispdata->vidlayer, px + dr->x, py + dr->y, dr->w, dr->h);
    781                 } else {
    782                     DFBSurfaceBlittingFlags flags = 0;
    783                     if (texturedata->isDirty) {
    784                         const SDL_Rect rect = { 0, 0, texture->w, texture->h };
    785                         DirectFB_UpdateTexture(renderer, texture, &rect, texturedata->pixels, texturedata->pitch);
    786                     }
    787 
    788                     if (a != 0xFF) {
    789                         flags |= DSBLIT_BLEND_COLORALPHA;
    790                     }
    791 
    792                     if ((r & g & b) != 0xFF) {
    793                         flags |= DSBLIT_COLORIZE;
    794                     }
    795 
    796                     destsurf->SetColor(destsurf, r, g, b, a);
    797 
    798                     /* ???? flags |= DSBLIT_SRC_PREMULTCOLOR; */
    799 
    800                     SetBlendMode(data, texture->blendMode, texturedata);
    801 
    802                     destsurf->SetBlittingFlags(destsurf, data->blitFlags | flags);
    803 
    804 #if (DFB_VERSION_ATLEAST(1,2,0))
    805                     destsurf->SetRenderOptions(destsurf, texturedata->render_options);
    806 #endif
    807 
    808                     if (sr->w == dr->w && sr->h == dr->h) {
    809                         destsurf->Blit(destsurf, texturedata->surface, sr, dr->x, dr->y);
    810                     } else {
    811                         destsurf->StretchBlit(destsurf, texturedata->surface, sr, dr);
    812                     }
    813                 }
    814                 break;
    815             }
    816 
    817             case SDL_RENDERCMD_COPY_EX:
    818                 break;  /* unsupported */
    819 
    820             case SDL_RENDERCMD_NO_OP:
    821                 break;
    822         }
    823 
    824         cmd = cmd->next;
    825     }
    826 
    827     return 0;
    828 }
    829 
    830 
    831 static void
    832 DirectFB_RenderPresent(SDL_Renderer * renderer)
    833 {
    834     DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    835     SDL_Window *window = renderer->window;
    836     SDL_DFB_WINDOWDATA(window);
    837     SDL_ShapeData *shape_data = (window->shaper ? window->shaper->driverdata : NULL);
    838 
    839     DirectFB_ActivateRenderer(renderer);
    840 
    841     if (shape_data && shape_data->surface) {
    842         /* saturate the window surface alpha channel */
    843         SDL_DFB_CHECK(windata->window_surface->SetSrcBlendFunction(windata->window_surface, DSBF_ONE));
    844         SDL_DFB_CHECK(windata->window_surface->SetDstBlendFunction(windata->window_surface, DSBF_ONE));
    845         SDL_DFB_CHECK(windata->window_surface->SetDrawingFlags(windata->window_surface, DSDRAW_BLEND));
    846         SDL_DFB_CHECK(windata->window_surface->SetColor(windata->window_surface, 0, 0, 0, 0xff));
    847         SDL_DFB_CHECK(windata->window_surface->FillRectangle(windata->window_surface, 0,0, windata->size.w, windata->size.h));
    848 
    849         /* blit the mask */
    850         SDL_DFB_CHECK(windata->surface->SetSrcBlendFunction(windata->surface, DSBF_DESTCOLOR));
    851         SDL_DFB_CHECK(windata->surface->SetDstBlendFunction(windata->surface, DSBF_ZERO));
    852         SDL_DFB_CHECK(windata->surface->SetBlittingFlags(windata->surface, DSBLIT_BLEND_ALPHACHANNEL));
    853 #if (DFB_VERSION_ATLEAST(1,2,0))
    854         SDL_DFB_CHECK(windata->surface->SetRenderOptions(windata->surface, DSRO_NONE));
    855 #endif
    856         SDL_DFB_CHECK(windata->surface->Blit(windata->surface, shape_data->surface, NULL, 0, 0));
    857     }
    858 
    859     /* Send the data to the display */
    860     SDL_DFB_CHECK(windata->window_surface->Flip(windata->window_surface, NULL,
    861                                                 data->flipflags));
    862 }
    863 
    864 static void
    865 DirectFB_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
    866 {
    867     DirectFB_TextureData *data = (DirectFB_TextureData *) texture->driverdata;
    868 
    869     DirectFB_ActivateRenderer(renderer);
    870 
    871     if (!data) {
    872         return;
    873     }
    874     SDL_DFB_RELEASE(data->palette);
    875     SDL_DFB_RELEASE(data->surface);
    876     if (data->display) {
    877         DFB_DisplayData *dispdata =
    878             (DFB_DisplayData *) data->display->driverdata;
    879         dispdata->vidIDinuse = 0;
    880         /* FIXME: Shouldn't we reset the cooperative level */
    881         SDL_DFB_CHECK(dispdata->vidlayer->SetCooperativeLevel(dispdata->vidlayer,
    882                                                 DLSCL_ADMINISTRATIVE));
    883         SDL_DFB_RELEASE(dispdata->vidlayer);
    884     }
    885     SDL_DFB_FREE(data->pixels);
    886     SDL_free(data);
    887     texture->driverdata = NULL;
    888 }
    889 
    890 static void
    891 DirectFB_DestroyRenderer(SDL_Renderer * renderer)
    892 {
    893     DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    894 #if 0
    895     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(data->window);
    896     if (display->palette) {
    897         SDL_DelPaletteWatch(display->palette, DisplayPaletteChanged, data);
    898     }
    899 #endif
    900 
    901     SDL_free(data);
    902     SDL_free(renderer);
    903 }
    904 
    905 static int
    906 DirectFB_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    907                      Uint32 format, void * pixels, int pitch)
    908 {
    909     Uint32 sdl_format;
    910     unsigned char* laypixels;
    911     int laypitch;
    912     DFBSurfacePixelFormat dfb_format;
    913     DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    914     IDirectFBSurface *winsurf = data->target;
    915 
    916     DirectFB_ActivateRenderer(renderer);
    917 
    918     winsurf->GetPixelFormat(winsurf, &dfb_format);
    919     sdl_format = DirectFB_DFBToSDLPixelFormat(dfb_format);
    920     winsurf->Lock(winsurf, DSLF_READ, (void **) &laypixels, &laypitch);
    921 
    922     laypixels += (rect->y * laypitch + rect->x * SDL_BYTESPERPIXEL(sdl_format) );
    923     SDL_ConvertPixels(rect->w, rect->h,
    924                       sdl_format, laypixels, laypitch,
    925                       format, pixels, pitch);
    926 
    927     winsurf->Unlock(winsurf);
    928 
    929     return 0;
    930 }
    931 
    932 #if 0
    933 static int
    934 DirectFB_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    935                       Uint32 format, const void * pixels, int pitch)
    936 {
    937     SDL_Window *window = renderer->window;
    938     SDL_DFB_WINDOWDATA(window);
    939     Uint32 sdl_format;
    940     unsigned char* laypixels;
    941     int laypitch;
    942     DFBSurfacePixelFormat dfb_format;
    943 
    944     SDL_DFB_CHECK(windata->surface->GetPixelFormat(windata->surface, &dfb_format));
    945     sdl_format = DirectFB_DFBToSDLPixelFormat(dfb_format);
    946 
    947     SDL_DFB_CHECK(windata->surface->Lock(windata->surface, DSLF_WRITE, (void **) &laypixels, &laypitch));
    948 
    949     laypixels += (rect->y * laypitch + rect->x * SDL_BYTESPERPIXEL(sdl_format) );
    950     SDL_ConvertPixels(rect->w, rect->h,
    951                       format, pixels, pitch,
    952                       sdl_format, laypixels, laypitch);
    953 
    954     SDL_DFB_CHECK(windata->surface->Unlock(windata->surface));
    955 
    956     return 0;
    957 }
    958 #endif
    959 
    960 
    961 SDL_Renderer *
    962 DirectFB_CreateRenderer(SDL_Window * window, Uint32 flags)
    963 {
    964     IDirectFBSurface *winsurf = get_dfb_surface(window);
    965     /*SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);*/
    966     SDL_Renderer *renderer = NULL;
    967     DirectFB_RenderData *data = NULL;
    968     DFBSurfaceCapabilities scaps;
    969 
    970     if (!winsurf) {
    971         return NULL;
    972     }
    973 
    974     SDL_DFB_ALLOC_CLEAR(renderer, sizeof(*renderer));
    975     SDL_DFB_ALLOC_CLEAR(data, sizeof(*data));
    976 
    977     renderer->WindowEvent = DirectFB_WindowEvent;
    978     renderer->CreateTexture = DirectFB_CreateTexture;
    979     renderer->UpdateTexture = DirectFB_UpdateTexture;
    980     renderer->LockTexture = DirectFB_LockTexture;
    981     renderer->UnlockTexture = DirectFB_UnlockTexture;
    982     renderer->SetTextureScaleMode = DirectFB_SetTextureScaleMode;
    983     renderer->QueueSetViewport = DirectFB_QueueSetViewport;
    984     renderer->QueueSetDrawColor = DirectFB_QueueSetViewport;  /* SetViewport and SetDrawColor are (currently) no-ops. */
    985     renderer->QueueDrawPoints = DirectFB_QueueDrawPoints;
    986     renderer->QueueDrawLines = DirectFB_QueueDrawPoints;  /* lines and points queue vertices the same way. */
    987     renderer->QueueFillRects = DirectFB_QueueFillRects;
    988     renderer->QueueCopy = DirectFB_QueueCopy;
    989     renderer->QueueCopyEx = DirectFB_QueueCopyEx;
    990     renderer->RunCommandQueue = DirectFB_RunCommandQueue;
    991     renderer->RenderPresent = DirectFB_RenderPresent;
    992 
    993     /* FIXME: Yet to be tested */
    994     renderer->RenderReadPixels = DirectFB_RenderReadPixels;
    995     /* renderer->RenderWritePixels = DirectFB_RenderWritePixels; */
    996 
    997     renderer->DestroyTexture = DirectFB_DestroyTexture;
    998     renderer->DestroyRenderer = DirectFB_DestroyRenderer;
    999     renderer->SetRenderTarget = DirectFB_SetRenderTarget;
   1000 
   1001     renderer->info = DirectFB_RenderDriver.info;
   1002     renderer->window = window;      /* SDL window */
   1003     renderer->driverdata = data;
   1004 
   1005     renderer->info.flags =
   1006         SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
   1007 
   1008     data->window = window;
   1009     data->target = winsurf;
   1010 
   1011     data->flipflags = DSFLIP_PIPELINE | DSFLIP_BLIT;
   1012 
   1013     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   1014         data->flipflags |= DSFLIP_WAITFORSYNC | DSFLIP_ONSYNC;
   1015         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   1016     } else
   1017         data->flipflags |= DSFLIP_ONSYNC;
   1018 
   1019     SDL_DFB_CHECKERR(winsurf->GetCapabilities(winsurf, &scaps));
   1020 
   1021 #if 0
   1022     if (scaps & DSCAPS_DOUBLE)
   1023         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2;
   1024     else if (scaps & DSCAPS_TRIPLE)
   1025         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3;
   1026     else
   1027         renderer->info.flags |= SDL_RENDERER_SINGLEBUFFER;
   1028 #endif
   1029 
   1030     DirectFB_SetSupportedPixelFormats(&renderer->info);
   1031 
   1032 #if 0
   1033     /* Set up a palette watch on the display palette */
   1034     if (display-> palette) {
   1035         SDL_AddPaletteWatch(display->palette, DisplayPaletteChanged, data);
   1036     }
   1037 #endif
   1038 
   1039     return renderer;
   1040 
   1041   error:
   1042     SDL_DFB_FREE(renderer);
   1043     SDL_DFB_FREE(data);
   1044     return NULL;
   1045 }
   1046 
   1047 
   1048 SDL_RenderDriver DirectFB_RenderDriver = {
   1049     DirectFB_CreateRenderer,
   1050     {
   1051      "directfb",
   1052      (SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED),
   1053      /* (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR |
   1054       SDL_TEXTUREMODULATE_ALPHA),
   1055       (SDL_BLENDMODE_NONE | SDL_BLENDMODE_MASK | SDL_BLENDMODE_BLEND |
   1056       SDL_BLENDMODE_ADD | SDL_BLENDMODE_MOD),
   1057      (SDL_SCALEMODE_NONE | SDL_SCALEMODE_FAST |
   1058       SDL_SCALEMODE_SLOW | SDL_SCALEMODE_BEST), */
   1059      0,
   1060      {
   1061              /* formats filled in later */
   1062      },
   1063      0,
   1064      0}
   1065 };
   1066 
   1067 #endif /* SDL_VIDEO_DRIVER_DIRECTFB */
   1068 
   1069 /* vi: set ts=4 sw=4 expandtab: */