static int
DirectFB_RenderDrawRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count)
{
    DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    IDirectFBSurface *destsurf = data->target;
    DFBRegion clip_region;
    int i;

    DirectFB_ActivateRenderer(renderer);

    PrepareDraw(renderer);

    destsurf->GetClip(destsurf, &clip_region);
    for (i=0; i<count; i++) {
        SDL_Rect dst = {rects[i]->x, rects[i]->y, rects[i]->w, rects[i]->h};
        dst.x += clip_region.x1;
        dst.y += clip_region.y1;
        SDL_DFB_CHECKERR(destsurf->DrawRectangle(destsurf, dst.x, dst.y,
                dst.w, dst.h));
    }

    return 0;
  error:
    return -1;
}
static void
DirectFB_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
{
    DirectFB_TextureData *data = (DirectFB_TextureData *) texture->driverdata;

    DirectFB_ActivateRenderer(renderer);

    if (!data) {
        return;
    }
    SDL_DFB_RELEASE(data->palette);
    SDL_DFB_RELEASE(data->surface);
    if (data->display) {
        DFB_DisplayData *dispdata =
            (DFB_DisplayData *) data->display->driverdata;
        dispdata->vidIDinuse = 0;
        /* FIXME: Shouldn't we reset the cooperative level */
        SDL_DFB_CHECK(dispdata->vidlayer->SetCooperativeLevel(dispdata->vidlayer,
                                                DLSCL_ADMINISTRATIVE));
        SDL_DFB_RELEASE(dispdata->vidlayer);
    }
    SDL_DFB_FREE(data->pixels);
    SDL_free(data);
    texture->driverdata = NULL;
}
static int DirectFB_RenderDrawLines(SDL_Renderer * renderer,
                               const SDL_FPoint * points, int count)
{
    DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    IDirectFBSurface *destsurf = data->target;
    DFBRegion clip_region;
    int i;

    DirectFB_ActivateRenderer(renderer);

    PrepareDraw(renderer);
    /* Use antialiasing when available */
#if (DFB_VERSION_ATLEAST(1,2,0))
    SDL_DFB_CHECKERR(destsurf->SetRenderOptions(destsurf, DSRO_ANTIALIAS));
#endif

    destsurf->GetClip(destsurf, &clip_region);
    for (i=0; i < count - 1; i++) {
        int x1 = points[i].x + clip_region.x1;
        int y1 = points[i].y + clip_region.y1;
        int x2 = points[i + 1].x + clip_region.x1;
        int y2 = points[i + 1].y + clip_region.y1;
        SDL_DFB_CHECKERR(destsurf->DrawLine(destsurf, x1, y1, x2, y2));
    }

    return 0;
  error:
    return -1;
}
static int
DirectFB_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
                     Uint32 format, void * pixels, int pitch)
{
    Uint32 sdl_format;
    unsigned char* laypixels;
    int laypitch;
    DFBSurfacePixelFormat dfb_format;
    DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    IDirectFBSurface *winsurf = data->target;

    DirectFB_ActivateRenderer(renderer);

    winsurf->GetPixelFormat(winsurf, &dfb_format);
    sdl_format = DirectFB_DFBToSDLPixelFormat(dfb_format);
    winsurf->Lock(winsurf, DSLF_READ, (void **) &laypixels, &laypitch);

    laypixels += (rect->y * laypitch + rect->x * SDL_BYTESPERPIXEL(sdl_format) );
    SDL_ConvertPixels(rect->w, rect->h,
                      sdl_format, laypixels, laypitch,
                      format, pixels, pitch);

    winsurf->Unlock(winsurf);

    return 0;
}
static void
DirectFB_RenderPresent(SDL_Renderer * renderer)
{
    DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    SDL_Window *window = renderer->window;
    SDL_DFB_WINDOWDATA(window);
    SDL_ShapeData *shape_data = (window->shaper ? window->shaper->driverdata : NULL);

    DirectFB_ActivateRenderer(renderer);

    if (shape_data && shape_data->surface) {
        /* saturate the window surface alpha channel */
        SDL_DFB_CHECK(windata->window_surface->SetSrcBlendFunction(windata->window_surface, DSBF_ONE));
        SDL_DFB_CHECK(windata->window_surface->SetDstBlendFunction(windata->window_surface, DSBF_ONE));
        SDL_DFB_CHECK(windata->window_surface->SetDrawingFlags(windata->window_surface, DSDRAW_BLEND));
        SDL_DFB_CHECK(windata->window_surface->SetColor(windata->window_surface, 0, 0, 0, 0xff));
        SDL_DFB_CHECK(windata->window_surface->FillRectangle(windata->window_surface, 0,0, windata->size.w, windata->size.h));

        /* blit the mask */
        SDL_DFB_CHECK(windata->surface->SetSrcBlendFunction(windata->surface, DSBF_DESTCOLOR));
        SDL_DFB_CHECK(windata->surface->SetDstBlendFunction(windata->surface, DSBF_ZERO));
        SDL_DFB_CHECK(windata->surface->SetBlittingFlags(windata->surface, DSBLIT_BLEND_ALPHACHANNEL));
#if (DFB_VERSION_ATLEAST(1,2,0))
        SDL_DFB_CHECK(windata->surface->SetRenderOptions(windata->surface, DSRO_NONE));
#endif
        SDL_DFB_CHECK(windata->surface->Blit(windata->surface, shape_data->surface, NULL, 0, 0));
    }

    /* Send the data to the display */
    SDL_DFB_CHECK(windata->window_surface->Flip(windata->window_surface, NULL,
                                                data->flipflags));
}
static int
DirectFB_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
                       const SDL_Rect * rect, const void *pixels, int pitch)
{
    DirectFB_TextureData *data = (DirectFB_TextureData *) texture->driverdata;
    Uint8 *dpixels;
    int dpitch;
    Uint8 *src, *dst;
    int row;
    size_t length;
    int bpp = DFB_BYTES_PER_PIXEL(DirectFB_SDLToDFBPixelFormat(texture->format));
    /* FIXME: SDL_BYTESPERPIXEL(texture->format) broken for yuv yv12 3 planes */

    DirectFB_ActivateRenderer(renderer);

    if ((texture->format == SDL_PIXELFORMAT_YV12) ||
        (texture->format == SDL_PIXELFORMAT_IYUV)) {
        bpp = 1;
    }

    SDL_DFB_CHECKERR(data->surface->Lock(data->surface,
                                         DSLF_WRITE | DSLF_READ,
                                         ((void **) &dpixels), &dpitch));
    src = (Uint8 *) pixels;
    dst = (Uint8 *) dpixels + rect->y * dpitch + rect->x * bpp;
    length = rect->w * bpp;
    for (row = 0; row < rect->h; ++row) {
        SDL_memcpy(dst, src, length);
        src += pitch;
        dst += dpitch;
    }
    /* copy other planes for 3 plane formats */
    if ((texture->format == SDL_PIXELFORMAT_YV12) ||
        (texture->format == SDL_PIXELFORMAT_IYUV)) {
        src = (Uint8 *) pixels + texture->h * pitch;
        dst = (Uint8 *) dpixels + texture->h * dpitch + rect->y * dpitch / 4 + rect->x * bpp / 2;
        for (row = 0; row < rect->h / 2 + (rect->h & 1); ++row) {
            SDL_memcpy(dst, src, length / 2);
            src += pitch / 2;
            dst += dpitch / 2;
        }
        src = (Uint8 *) pixels + texture->h * pitch + texture->h * pitch / 4;
        dst = (Uint8 *) dpixels + texture->h * dpitch + texture->h * dpitch / 4 + rect->y * dpitch / 4 + rect->x * bpp / 2;
        for (row = 0; row < rect->h / 2 + (rect->h & 1); ++row) {
            SDL_memcpy(dst, src, length / 2);
            src += pitch / 2;
            dst += dpitch / 2;
        }
    }
    SDL_DFB_CHECKERR(data->surface->Unlock(data->surface));
    data->isDirty = 0;
    return 0;
  error:
    return 1;

}
static void
DirectFB_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
{
    DirectFB_TextureData *texturedata =
        (DirectFB_TextureData *) texture->driverdata;

    DirectFB_ActivateRenderer(renderer);

    if (texturedata->display) {
        SDL_DFB_CHECK(texturedata->surface->Unlock(texturedata->surface));
        texturedata->pixels = NULL;
    }
}
static int DirectFB_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
{
    DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    DirectFB_TextureData *tex_data = NULL;

    DirectFB_ActivateRenderer(renderer);
    if (texture) {
        tex_data = (DirectFB_TextureData *) texture->driverdata;
        data->target = tex_data->surface;
    } else {
        data->target = get_dfb_surface(data->window);
    }
    data->lastBlendMode = 0;
    return 0;
}
int
DirectFB_RenderClear(SDL_Renderer * renderer)
{
    DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    IDirectFBSurface *destsurf = data->target;

    DirectFB_ActivateRenderer(renderer);

    PrepareDraw(renderer);

    destsurf->Clear(destsurf, renderer->r, renderer->g, renderer->b, renderer->a);


    return 0;
}
static int DirectFB_RenderDrawPoints(SDL_Renderer * renderer,
                                const SDL_Point * points, int count)
{
    DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
	IDirectFBSurface *destsurf = get_dfb_surface(data->window);
    int i;

    DirectFB_ActivateRenderer(renderer);

    PrepareDraw(renderer);
    for (i=0; i < count; i++)
    	SDL_DFB_CHECKERR(destsurf->DrawLine(destsurf, points[i].x, points[i].y, points[i].x, points[i].y));
    return 0;
  error:
    return -1;
}
static int
DirectFB_RenderDrawRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count)
{
    DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
	IDirectFBSurface *destsurf = get_dfb_surface(data->window);
    int i;

    DirectFB_ActivateRenderer(renderer);

    PrepareDraw(renderer);

    for (i=0; i<count; i++)
    	SDL_DFB_CHECKERR(destsurf->DrawRectangle(destsurf, rects[i]->x, rects[i]->y,
    			rects[i]->w, rects[i]->h));

    return 0;
  error:
    return -1;
}
static int DirectFB_RenderDrawPoints(SDL_Renderer * renderer,
                                const SDL_FPoint * points, int count)
{
    DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    IDirectFBSurface *destsurf = data->target;
    DFBRegion clip_region;
    int i;

    DirectFB_ActivateRenderer(renderer);

    PrepareDraw(renderer);
    destsurf->GetClip(destsurf, &clip_region);
    for (i=0; i < count; i++) {
        int x = points[i].x + clip_region.x1;
        int y = points[i].y + clip_region.y1;
        SDL_DFB_CHECKERR(destsurf->DrawLine(destsurf, x, y, x, y));
    }
    return 0;
  error:
    return -1;
}
static int DirectFB_RenderDrawLines(SDL_Renderer * renderer,
                               const SDL_Point * points, int count)
{
    DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
	IDirectFBSurface *destsurf = get_dfb_surface(data->window);
    int i;

    DirectFB_ActivateRenderer(renderer);

    PrepareDraw(renderer);
    /* Use antialiasing when available */
#if (DFB_VERSION_ATLEAST(1,2,0))
    SDL_DFB_CHECKERR(destsurf->SetRenderOptions(destsurf, DSRO_ANTIALIAS));
#endif

    for (i=0; i < count - 1; i++)
    	SDL_DFB_CHECKERR(destsurf->DrawLine(destsurf, points[i].x, points[i].y, points[i+1].x, points[i+1].y));

    return 0;
  error:
    return -1;
}
static int
DirectFB_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
                     const SDL_Rect * rect, void **pixels, int *pitch)
{
    DirectFB_TextureData *texturedata =
        (DirectFB_TextureData *) texture->driverdata;

    DirectFB_ActivateRenderer(renderer);

#if 0
    if (markDirty) {
        SDL_AddDirtyRect(&texturedata->dirty, rect);
    }
#endif

    if (texturedata->display) {
        void *fdata;
        int fpitch;

        SDL_DFB_CHECKERR(texturedata->surface->Lock(texturedata->surface,
                                                    DSLF_WRITE | DSLF_READ,
                                                    &fdata, &fpitch));
        *pitch = fpitch;
        *pixels = fdata;
    } else {
        *pixels =
            (void *) ((Uint8 *) texturedata->pixels +
                      rect->y * texturedata->pitch +
                      rect->x * DFB_BYTES_PER_PIXEL(DirectFB_SDLToDFBPixelFormat(texture->format)));
        *pitch = texturedata->pitch;
        texturedata->isDirty = 1;
    }
    return 0;

  error:
    return -1;
}
static int
DirectFB_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
{
    SDL_Window *window = renderer->window;
    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
    SDL_DFB_DEVICEDATA(display->device);
    DirectFB_TextureData *data;
    DFBSurfaceDescription dsc;
    DFBSurfacePixelFormat pixelformat;

    DirectFB_ActivateRenderer(renderer);

    SDL_DFB_ALLOC_CLEAR(data, sizeof(*data));
    texture->driverdata = data;

    /* find the right pixelformat */
    pixelformat = DirectFB_SDLToDFBPixelFormat(texture->format);
    if (pixelformat == DSPF_UNKNOWN) {
        SDL_SetError("Unknown pixel format %d\n", data->format);
        goto error;
    }

    data->format = texture->format;
    data->pitch = texture->w * DFB_BYTES_PER_PIXEL(pixelformat);

    if (DirectFB_AcquireVidLayer(renderer, texture) != 0) {
        /* fill surface description */
        dsc.flags =
            DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT | DSDESC_CAPS;
        dsc.width = texture->w;
        dsc.height = texture->h;
        if(texture->format == SDL_PIXELFORMAT_YV12 ||
           texture->format == SDL_PIXELFORMAT_IYUV) {
           /* dfb has problems with odd sizes -make them even internally */
           dsc.width += (dsc.width % 2);
           dsc.height += (dsc.height % 2);
        }
        /* <1.2 Never use DSCAPS_VIDEOONLY here. It kills performance
         * No DSCAPS_SYSTEMONLY either - let dfb decide
         * 1.2: DSCAPS_SYSTEMONLY boosts performance by factor ~8
         * Depends on other settings as well. Let dfb decide.
         */
        dsc.caps = DSCAPS_PREMULTIPLIED;
#if 0
        if (texture->access == SDL_TEXTUREACCESS_STREAMING)
            dsc.caps |= DSCAPS_SYSTEMONLY;
        else
            dsc.caps |= DSCAPS_VIDEOONLY;
#endif

        dsc.pixelformat = pixelformat;
        data->pixels = NULL;

        /* Create the surface */
        SDL_DFB_CHECKERR(devdata->dfb->CreateSurface(devdata->dfb, &dsc,
                                                     &data->surface));
        if (SDL_ISPIXELFORMAT_INDEXED(data->format)
            && !SDL_ISPIXELFORMAT_FOURCC(data->format)) {
#if 1
            SDL_DFB_CHECKERR(data->surface->GetPalette(data->surface, &data->palette));
#else
            /* DFB has issues with blitting LUT8 surfaces.
             * Creating a new palette does not help.
             */
            DFBPaletteDescription pal_desc;
            pal_desc.flags = DPDESC_SIZE; /* | DPDESC_ENTRIES */
            pal_desc.size = 256;
            SDL_DFB_CHECKERR(devdata->dfb->CreatePalette(devdata->dfb, &pal_desc,&data->palette));
            SDL_DFB_CHECKERR(data->surface->SetPalette(data->surface, data->palette));
#endif
        }

    }
#if (DFB_VERSION_ATLEAST(1,2,0))
    data->render_options = DSRO_NONE;
#endif
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
        /* 3 plane YUVs return 1 bpp, but we need more space for other planes */
        if(texture->format == SDL_PIXELFORMAT_YV12 ||
           texture->format == SDL_PIXELFORMAT_IYUV) {
            SDL_DFB_ALLOC_CLEAR(data->pixels, (texture->h * data->pitch  + ((texture->h + texture->h % 2) * (data->pitch + data->pitch % 2) * 2) / 4));
        } else {
            SDL_DFB_ALLOC_CLEAR(data->pixels, texture->h * data->pitch);
        }
    }

    return 0;

  error:
    SDL_DFB_RELEASE(data->palette);
    SDL_DFB_RELEASE(data->surface);
    SDL_DFB_FREE(texture->driverdata);
    return -1;
}
static int
DirectFB_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
                    const SDL_Rect * srcrect, const SDL_FRect * dstrect)
{
    DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    IDirectFBSurface *destsurf = data->target;
    DirectFB_TextureData *texturedata =
        (DirectFB_TextureData *) texture->driverdata;
    Uint8 alpha, r, g, b;
    DFBRegion clip_region;
    DFBRectangle sr, dr;

    DirectFB_ActivateRenderer(renderer);

    SDLtoDFBRect(srcrect, &sr);
    SDLtoDFBRect_Float(dstrect, &dr);

    destsurf->GetClip(destsurf, &clip_region);
    dr.x += clip_region.x1;
    dr.y += clip_region.y1;

    if (texturedata->display) {
        int px, py;
        SDL_Window *window = renderer->window;
        IDirectFBWindow *dfbwin = get_dfb_window(window);
        SDL_DFB_WINDOWDATA(window);
        SDL_VideoDisplay *display = texturedata->display;
        DFB_DisplayData *dispdata = (DFB_DisplayData *) display->driverdata;

        SDL_DFB_CHECKERR(dispdata->
                         vidlayer->SetSourceRectangle(dispdata->vidlayer,
                                                      sr.x, sr.y, sr.w, sr.h));
        dfbwin->GetPosition(dfbwin, &px, &py);
        px += windata->client.x;
        py += windata->client.y;
        SDL_DFB_CHECKERR(dispdata->
                         vidlayer->SetScreenRectangle(dispdata->vidlayer,
                                                      px + dr.x,
                                                      py + dr.y,
                                                      dr.w,
                                                      dr.h));
    } else {
        DFBSurfaceBlittingFlags flags = 0;

#if 0
        if (texturedata->dirty.list) {
            SDL_DirtyRect *dirty;
            void *pixels;
            int bpp = DFB_BYTES_PER_PIXEL(DirectFB_SDLToDFBPixelFormat(texture->format));
            int pitch = texturedata->pitch;

            for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) {
                SDL_Rect *rect = &dirty->rect;
                pixels =
                    (void *) ((Uint8 *) texturedata->pixels +
                              rect->y * pitch + rect->x * bpp);
                DirectFB_UpdateTexture(renderer, texture, rect,
                                       pixels,
                                       texturedata->pitch);
            }
            SDL_ClearDirtyRects(&texturedata->dirty);
        }
#endif
        if (texturedata->isDirty)
        {
            SDL_Rect rect;

            rect.x = 0;
            rect.y = 0;
            rect.w = texture->w;
            rect.h = texture->h;

            DirectFB_UpdateTexture(renderer, texture, &rect, texturedata->pixels, texturedata->pitch);
        }

        alpha = r = g = b = 0xff;
        if (texture->modMode & SDL_TEXTUREMODULATE_ALPHA){
            alpha = texture->a;
            flags |= DSBLIT_BLEND_COLORALPHA;
        }

        if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) {
            r = texture->r;
            g = texture->g;
            b = texture->b;
            flags |= DSBLIT_COLORIZE;
        }
        SDL_DFB_CHECKERR(destsurf->
                         SetColor(destsurf, r, g, b, alpha));

        /* ???? flags |= DSBLIT_SRC_PREMULTCOLOR; */

        SetBlendMode(data, texture->blendMode, texturedata);

        SDL_DFB_CHECKERR(destsurf->SetBlittingFlags(destsurf,
                                                    data->blitFlags | flags));

#if (DFB_VERSION_ATLEAST(1,2,0))
        SDL_DFB_CHECKERR(destsurf->SetRenderOptions(destsurf,
                                                    texturedata->
                                                    render_options));
#endif

        if (srcrect->w == dstrect->w && srcrect->h == dstrect->h) {
            SDL_DFB_CHECKERR(destsurf->Blit(destsurf,
                                            texturedata->surface,
                                            &sr, dr.x, dr.y));
        } else {
            SDL_DFB_CHECKERR(destsurf->StretchBlit(destsurf,
                                                   texturedata->surface,
                                                   &sr, &dr));
        }
    }
    return 0;
  error:
    return -1;
}