| /* |
| Simple DirectMedia Layer |
| Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> |
| |
| This software is provided 'as-is', without any express or implied |
| warranty. In no event will the authors be held liable for any damages |
| arising from the use of this software. |
| |
| Permission is granted to anyone to use this software for any purpose, |
| including commercial applications, and to alter it and redistribute it |
| freely, subject to the following restrictions: |
| |
| 1. The origin of this software must not be misrepresented; you must not |
| claim that you wrote the original software. If you use this software |
| in a product, an acknowledgment in the product documentation would be |
| appreciated but is not required. |
| 2. Altered source versions must be plainly marked as such, and must not be |
| misrepresented as being the original software. |
| 3. This notice may not be removed or altered from any source distribution. |
| */ |
| #include "../../SDL_internal.h" |
| |
| #if SDL_VIDEO_DRIVER_DIRECTFB |
| #include "SDL_DirectFB_window.h" |
| #include "SDL_DirectFB_modes.h" |
| |
| #include "SDL_syswm.h" |
| #include "SDL_DirectFB_shape.h" |
| |
| #include "../SDL_sysvideo.h" |
| #include "../../render/SDL_sysrender.h" |
| |
| #ifndef DFB_VERSION_ATLEAST |
| |
| #define DFB_VERSIONNUM(X, Y, Z) \ |
| ((X)*1000 + (Y)*100 + (Z)) |
| |
| #define DFB_COMPILEDVERSION \ |
| DFB_VERSIONNUM(DIRECTFB_MAJOR_VERSION, DIRECTFB_MINOR_VERSION, DIRECTFB_MICRO_VERSION) |
| |
| #define DFB_VERSION_ATLEAST(X, Y, Z) \ |
| (DFB_COMPILEDVERSION >= DFB_VERSIONNUM(X, Y, Z)) |
| |
| #define SDL_DFB_CHECK(x) x |
| |
| #endif |
| |
| /* the following is not yet tested ... */ |
| #define USE_DISPLAY_PALETTE (0) |
| |
| |
| #define SDL_DFB_RENDERERDATA(rend) DirectFB_RenderData *renddata = ((rend) ? (DirectFB_RenderData *) (rend)->driverdata : NULL) |
| #define SDL_DFB_WINDOWSURFACE(win) IDirectFBSurface *destsurf = ((DFB_WindowData *) ((win)->driverdata))->surface; |
| |
| typedef struct |
| { |
| SDL_Window *window; |
| DFBSurfaceFlipFlags flipflags; |
| int size_changed; |
| int lastBlendMode; |
| DFBSurfaceBlittingFlags blitFlags; |
| DFBSurfaceDrawingFlags drawFlags; |
| IDirectFBSurface* target; |
| } DirectFB_RenderData; |
| |
| typedef struct |
| { |
| IDirectFBSurface *surface; |
| Uint32 format; |
| void *pixels; |
| int pitch; |
| IDirectFBPalette *palette; |
| int isDirty; |
| |
| SDL_VideoDisplay *display; /* only for yuv textures */ |
| |
| #if (DFB_VERSION_ATLEAST(1,2,0)) |
| DFBSurfaceRenderOptions render_options; |
| #endif |
| } DirectFB_TextureData; |
| |
| static SDL_INLINE void |
| SDLtoDFBRect(const SDL_Rect * sr, DFBRectangle * dr) |
| { |
| dr->x = sr->x; |
| dr->y = sr->y; |
| dr->h = sr->h; |
| dr->w = sr->w; |
| } |
| static SDL_INLINE void |
| SDLtoDFBRect_Float(const SDL_FRect * sr, DFBRectangle * dr) |
| { |
| dr->x = sr->x; |
| dr->y = sr->y; |
| dr->h = sr->h; |
| dr->w = sr->w; |
| } |
| |
| |
| static int |
| TextureHasAlpha(DirectFB_TextureData * data) |
| { |
| /* Drawing primitive ? */ |
| if (!data) |
| return 0; |
| |
| return (DFB_PIXELFORMAT_HAS_ALPHA(DirectFB_SDLToDFBPixelFormat(data->format)) ? 1 : 0); |
| #if 0 |
| switch (data->format) { |
| case SDL_PIXELFORMAT_INDEX4LSB: |
| case SDL_PIXELFORMAT_INDEX4MSB: |
| case SDL_PIXELFORMAT_ARGB4444: |
| case SDL_PIXELFORMAT_ARGB1555: |
| case SDL_PIXELFORMAT_ARGB8888: |
| case SDL_PIXELFORMAT_RGBA8888: |
| case SDL_PIXELFORMAT_ABGR8888: |
| case SDL_PIXELFORMAT_BGRA8888: |
| case SDL_PIXELFORMAT_ARGB2101010: |
| return 1; |
| default: |
| return 0; |
| } |
| #endif |
| } |
| |
| static SDL_INLINE IDirectFBSurface *get_dfb_surface(SDL_Window *window) |
| { |
| SDL_SysWMinfo wm_info; |
| SDL_memset(&wm_info, 0, sizeof(SDL_SysWMinfo)); |
| |
| SDL_VERSION(&wm_info.version); |
| if (!SDL_GetWindowWMInfo(window, &wm_info)) { |
| return NULL; |
| } |
| |
| return wm_info.info.dfb.surface; |
| } |
| |
| static SDL_INLINE IDirectFBWindow *get_dfb_window(SDL_Window *window) |
| { |
| SDL_SysWMinfo wm_info; |
| SDL_memset(&wm_info, 0, sizeof(SDL_SysWMinfo)); |
| |
| SDL_VERSION(&wm_info.version); |
| if (!SDL_GetWindowWMInfo(window, &wm_info)) { |
| return NULL; |
| } |
| |
| return wm_info.info.dfb.window; |
| } |
| |
| static void |
| SetBlendMode(DirectFB_RenderData * data, int blendMode, |
| DirectFB_TextureData * source) |
| { |
| IDirectFBSurface *destsurf = data->target; |
| |
| /* FIXME: check for format change */ |
| if (1 || data->lastBlendMode != blendMode) { |
| switch (blendMode) { |
| case SDL_BLENDMODE_NONE: |
| /**< No blending */ |
| data->blitFlags = DSBLIT_NOFX; |
| data->drawFlags = DSDRAW_NOFX; |
| SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_ONE)); |
| SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_ZERO)); |
| break; |
| #if 0 |
| case SDL_BLENDMODE_MASK: |
| data->blitFlags = DSBLIT_BLEND_ALPHACHANNEL; |
| data->drawFlags = DSDRAW_BLEND; |
| SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_SRCALPHA)); |
| SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_INVSRCALPHA)); |
| break; |
| #endif |
| case SDL_BLENDMODE_BLEND: |
| data->blitFlags = DSBLIT_BLEND_ALPHACHANNEL; |
| data->drawFlags = DSDRAW_BLEND; |
| SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_SRCALPHA)); |
| SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_INVSRCALPHA)); |
| break; |
| case SDL_BLENDMODE_ADD: |
| data->blitFlags = DSBLIT_BLEND_ALPHACHANNEL; |
| data->drawFlags = DSDRAW_BLEND; |
| /* FIXME: SRCALPHA kills performance on radeon ... |
| * It will be cheaper to copy the surface to a temporary surface and premultiply |
| */ |
| if (source && TextureHasAlpha(source)) |
| SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_SRCALPHA)); |
| else |
| SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_ONE)); |
| SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_ONE)); |
| break; |
| case SDL_BLENDMODE_MOD: |
| data->blitFlags = DSBLIT_BLEND_ALPHACHANNEL; |
| data->drawFlags = DSDRAW_BLEND; |
| SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_ZERO)); |
| SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_SRCCOLOR)); |
| |
| break; |
| case SDL_BLENDMODE_MUL: |
| data->blitFlags = DSBLIT_BLEND_ALPHACHANNEL; |
| data->drawFlags = DSDRAW_BLEND; |
| SDL_DFB_CHECK(destsurf->SetSrcBlendFunction(destsurf, DSBF_DESTCOLOR)); |
| SDL_DFB_CHECK(destsurf->SetDstBlendFunction(destsurf, DSBF_INVSRCALPHA)); |
| |
| break; |
| } |
| data->lastBlendMode = blendMode; |
| } |
| } |
| |
| static int |
| PrepareDraw(SDL_Renderer * renderer, const SDL_RenderCommand *cmd) |
| { |
| DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata; |
| IDirectFBSurface *destsurf = data->target; |
| Uint8 r = cmd->data.draw.r; |
| Uint8 g = cmd->data.draw.g; |
| Uint8 b = cmd->data.draw.b; |
| Uint8 a = cmd->data.draw.a; |
| |
| SetBlendMode(data, cmd->data.draw.blend, NULL); |
| SDL_DFB_CHECKERR(destsurf->SetDrawingFlags(destsurf, data->drawFlags)); |
| |
| switch (renderer->blendMode) { |
| case SDL_BLENDMODE_NONE: |
| /* case SDL_BLENDMODE_MASK: */ |
| case SDL_BLENDMODE_BLEND: |
| break; |
| case SDL_BLENDMODE_ADD: |
| case SDL_BLENDMODE_MOD: |
| case SDL_BLENDMODE_MUL: |
| r = ((int) r * (int) a) / 255; |
| g = ((int) g * (int) a) / 255; |
| b = ((int) b * (int) a) / 255; |
| a = 255; |
| break; |
| case SDL_BLENDMODE_INVALID: break; |
| } |
| |
| SDL_DFB_CHECKERR(destsurf->SetColor(destsurf, r, g, b, a)); |
| return 0; |
| error: |
| return -1; |
| } |
| |
| static void |
| DirectFB_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) |
| { |
| SDL_DFB_RENDERERDATA(renderer); |
| |
| if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) { |
| /* Rebind the context to the window area and update matrices */ |
| /* SDL_CurrentContext = NULL; */ |
| /* data->updateSize = SDL_TRUE; */ |
| renddata->size_changed = SDL_TRUE; |
| } |
| } |
| |
| static void |
| DirectFB_ActivateRenderer(SDL_Renderer * renderer) |
| { |
| SDL_DFB_RENDERERDATA(renderer); |
| |
| if (renddata->size_changed /* || windata->wm_needs_redraw */) { |
| renddata->size_changed = SDL_FALSE; |
| } |
| } |
| |
| static int |
| DirectFB_AcquireVidLayer(SDL_Renderer * renderer, SDL_Texture * texture) |
| { |
| SDL_Window *window = renderer->window; |
| SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); |
| SDL_DFB_DEVICEDATA(display->device); |
| DFB_DisplayData *dispdata = (DFB_DisplayData *) display->driverdata; |
| DirectFB_TextureData *data = texture->driverdata; |
| DFBDisplayLayerConfig layconf; |
| DFBResult ret; |
| |
| if (devdata->use_yuv_direct && (dispdata->vidID >= 0) |
| && (!dispdata->vidIDinuse) |
| && SDL_ISPIXELFORMAT_FOURCC(data->format)) { |
| layconf.flags = |
| DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT | |
| DLCONF_SURFACE_CAPS; |
| layconf.width = texture->w; |
| layconf.height = texture->h; |
| layconf.pixelformat = DirectFB_SDLToDFBPixelFormat(data->format); |
| layconf.surface_caps = DSCAPS_VIDEOONLY | DSCAPS_DOUBLE; |
| |
| SDL_DFB_CHECKERR(devdata->dfb->GetDisplayLayer(devdata->dfb, |
| dispdata->vidID, |
| &dispdata->vidlayer)); |
| SDL_DFB_CHECKERR(dispdata-> |
| vidlayer->SetCooperativeLevel(dispdata->vidlayer, |
| DLSCL_EXCLUSIVE)); |
| |
| if (devdata->use_yuv_underlays) { |
| ret = dispdata->vidlayer->SetLevel(dispdata->vidlayer, -1); |
| if (ret != DFB_OK) |
| SDL_DFB_DEBUG("Underlay Setlevel not supported\n"); |
| } |
| SDL_DFB_CHECKERR(dispdata-> |
| vidlayer->SetConfiguration(dispdata->vidlayer, |
| &layconf)); |
| SDL_DFB_CHECKERR(dispdata-> |
| vidlayer->GetSurface(dispdata->vidlayer, |
| &data->surface)); |
| dispdata->vidIDinuse = 1; |
| data->display = display; |
| return 0; |
| } |
| return 1; |
| error: |
| if (dispdata->vidlayer) { |
| SDL_DFB_RELEASE(data->surface); |
| SDL_DFB_CHECKERR(dispdata-> |
| vidlayer->SetCooperativeLevel(dispdata->vidlayer, |
| DLSCL_ADMINISTRATIVE)); |
| SDL_DFB_RELEASE(dispdata->vidlayer); |
| } |
| 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", 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; |
| } |
| |
| #if 0 |
| static int |
| DirectFB_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture) |
| { |
| #if (DFB_VERSION_ATLEAST(1,2,0)) |
| |
| DirectFB_TextureData *data = (DirectFB_TextureData *) texture->driverdata; |
| |
| switch (texture->scaleMode) { |
| case SDL_SCALEMODE_NONE: |
| case SDL_SCALEMODE_FAST: |
| data->render_options = DSRO_NONE; |
| break; |
| case SDL_SCALEMODE_SLOW: |
| data->render_options = DSRO_SMOOTH_UPSCALE | DSRO_SMOOTH_DOWNSCALE; |
| break; |
| case SDL_SCALEMODE_BEST: |
| data->render_options = |
| DSRO_SMOOTH_UPSCALE | DSRO_SMOOTH_DOWNSCALE | DSRO_ANTIALIAS; |
| break; |
| default: |
| data->render_options = DSRO_NONE; |
| texture->scaleMode = SDL_SCALEMODE_NONE; |
| return SDL_Unsupported(); |
| } |
| #endif |
| return 0; |
| } |
| #endif |
| |
| 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 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 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 void |
| DirectFB_SetTextureScaleMode() |
| { |
| } |
| |
| #if 0 |
| static void |
| DirectFB_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, |
| int numrects, const SDL_Rect * rects) |
| { |
| DirectFB_TextureData *data = (DirectFB_TextureData *) texture->driverdata; |
| int i; |
| |
| for (i = 0; i < numrects; ++i) { |
| SDL_AddDirtyRect(&data->dirty, &rects[i]); |
| } |
| } |
| #endif |
| |
| 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; |
| } |
| |
| |
| static int |
| DirectFB_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd) |
| { |
| return 0; /* nothing to do in this backend. */ |
| } |
| |
| static int |
| DirectFB_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) |
| { |
| const size_t len = count * sizeof (SDL_FPoint); |
| SDL_FPoint *verts = (SDL_FPoint *) SDL_AllocateRenderVertices(renderer, len, 0, &cmd->data.draw.first); |
| |
| if (!verts) { |
| return -1; |
| } |
| |
| cmd->data.draw.count = count; |
| SDL_memcpy(verts, points, len); |
| return 0; |
| } |
| |
| static int |
| DirectFB_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count) |
| { |
| const size_t len = count * sizeof (SDL_FRect); |
| SDL_FRect *verts = (SDL_FRect *) SDL_AllocateRenderVertices(renderer, len, 0, &cmd->data.draw.first); |
| |
| if (!verts) { |
| return -1; |
| } |
| |
| cmd->data.draw.count = count; |
| SDL_memcpy(verts, rects, len); |
| return 0; |
| } |
| |
| static int |
| DirectFB_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, |
| const SDL_Rect * srcrect, const SDL_FRect * dstrect) |
| { |
| DFBRectangle *verts = (DFBRectangle *) SDL_AllocateRenderVertices(renderer, 2 * sizeof (DFBRectangle), 0, &cmd->data.draw.first); |
| |
| if (!verts) { |
| return -1; |
| } |
| |
| cmd->data.draw.count = 1; |
| |
| SDLtoDFBRect(srcrect, verts++); |
| SDLtoDFBRect_Float(dstrect, verts); |
| |
| return 0; |
| } |
| |
| static int |
| DirectFB_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, |
| const SDL_Rect * srcrect, const SDL_FRect * dstrect, |
| const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip) |
| { |
| return SDL_Unsupported(); |
| } |
| |
| |
| static int |
| DirectFB_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) |
| { |
| /* !!! FIXME: there are probably some good optimization wins in here if someone wants to look it over. */ |
| DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata; |
| IDirectFBSurface *destsurf = data->target; |
| DFBRegion clip_region; |
| size_t i; |
| |
| DirectFB_ActivateRenderer(renderer); |
| |
| SDL_zero(clip_region); /* in theory, this always gets set before use. */ |
| |
| while (cmd) { |
| switch (cmd->command) { |
| case SDL_RENDERCMD_SETDRAWCOLOR: |
| break; /* not used here */ |
| |
| case SDL_RENDERCMD_SETVIEWPORT: { |
| const SDL_Rect *viewport = &cmd->data.viewport.rect; |
| clip_region.x1 = viewport->x; |
| clip_region.y1 = viewport->y; |
| clip_region.x2 = clip_region.x1 + viewport->w - 1; |
| clip_region.y2 = clip_region.y1 + viewport->h - 1; |
| destsurf->SetClip(destsurf, &clip_region); |
| break; |
| } |
| |
| case SDL_RENDERCMD_SETCLIPRECT: { |
| /* !!! FIXME: how does this SetClip interact with the one in SETVIEWPORT? */ |
| if (cmd->data.cliprect.enabled) { |
| const SDL_Rect *rect = &cmd->data.cliprect.rect; |
| clip_region.x1 = rect->x; |
| clip_region.x2 = rect->x + rect->w; |
| clip_region.y1 = rect->y; |
| clip_region.y2 = rect->y + rect->h; |
| destsurf->SetClip(destsurf, &clip_region); |
| } |
| break; |
| } |
| |
| case SDL_RENDERCMD_CLEAR: { |
| const Uint8 r = cmd->data.color.r; |
| const Uint8 g = cmd->data.color.g; |
| const Uint8 b = cmd->data.color.b; |
| const Uint8 a = cmd->data.color.a; |
| destsurf->Clear(destsurf, r, g, b, a); |
| break; |
| } |
| |
| case SDL_RENDERCMD_DRAW_POINTS: { |
| const size_t count = cmd->data.draw.count; |
| const SDL_FPoint *points = (SDL_FPoint *) (((Uint8 *) vertices) + cmd->data.draw.first); |
| PrepareDraw(renderer, cmd); |
| for (i = 0; i < count; i++) { |
| const int x = points[i].x + clip_region.x1; |
| const int y = points[i].y + clip_region.y1; |
| destsurf->DrawLine(destsurf, x, y, x, y); |
| } |
| break; |
| } |
| |
| case SDL_RENDERCMD_DRAW_LINES: { |
| const SDL_FPoint *points = (SDL_FPoint *) (((Uint8 *) vertices) + cmd->data.draw.first); |
| const size_t count = cmd->data.draw.count; |
| |
| PrepareDraw(renderer, cmd); |
| |
| #if (DFB_VERSION_ATLEAST(1,2,0)) /* !!! FIXME: should this be set once, somewhere else? */ |
| destsurf->SetRenderOptions(destsurf, DSRO_ANTIALIAS); |
| #endif |
| |
| for (i = 0; i < count - 1; i++) { |
| const int x1 = points[i].x + clip_region.x1; |
| const int y1 = points[i].y + clip_region.y1; |
| const int x2 = points[i + 1].x + clip_region.x1; |
| const int y2 = points[i + 1].y + clip_region.y1; |
| destsurf->DrawLine(destsurf, x1, y1, x2, y2); |
| } |
| break; |
| } |
| |
| case SDL_RENDERCMD_FILL_RECTS: { |
| const SDL_FRect *rects = (SDL_FRect *) (((Uint8 *) vertices) + cmd->data.draw.first); |
| const size_t count = cmd->data.draw.count; |
| |
| PrepareDraw(renderer, cmd); |
| |
| for (i = 0; i < count; i++, rects++) { |
| destsurf->FillRectangle(destsurf, rects->x + clip_region.x1, rects->y + clip_region.y1, rects->w, rects->h); |
| } |
| break; |
| } |
| |
| case SDL_RENDERCMD_COPY: { |
| SDL_Texture *texture = cmd->data.draw.texture; |
| const Uint8 r = cmd->data.draw.r; |
| const Uint8 g = cmd->data.draw.g; |
| const Uint8 b = cmd->data.draw.b; |
| const Uint8 a = cmd->data.draw.a; |
| DFBRectangle *verts = (DFBRectangle *) (((Uint8 *) vertices) + cmd->data.draw.first); |
| DirectFB_TextureData *texturedata = (DirectFB_TextureData *) texture->driverdata; |
| DFBRectangle *sr = verts++; |
| DFBRectangle *dr = verts; |
| |
| 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; |
| |
| 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; |
| dispdata->vidlayer->SetScreenRectangle(dispdata->vidlayer, px + dr->x, py + dr->y, dr->w, dr->h); |
| } else { |
| DFBSurfaceBlittingFlags flags = 0; |
| if (texturedata->isDirty) { |
| const SDL_Rect rect = { 0, 0, texture->w, texture->h }; |
| DirectFB_UpdateTexture(renderer, texture, &rect, texturedata->pixels, texturedata->pitch); |
| } |
| |
| if (a != 0xFF) { |
| flags |= DSBLIT_BLEND_COLORALPHA; |
| } |
| |
| if ((r & g & b) != 0xFF) { |
| flags |= DSBLIT_COLORIZE; |
| } |
| |
| destsurf->SetColor(destsurf, r, g, b, a); |
| |
| /* ???? flags |= DSBLIT_SRC_PREMULTCOLOR; */ |
| |
| SetBlendMode(data, texture->blendMode, texturedata); |
| |
| destsurf->SetBlittingFlags(destsurf, data->blitFlags | flags); |
| |
| #if (DFB_VERSION_ATLEAST(1,2,0)) |
| destsurf->SetRenderOptions(destsurf, texturedata->render_options); |
| #endif |
| |
| if (sr->w == dr->w && sr->h == dr->h) { |
| destsurf->Blit(destsurf, texturedata->surface, sr, dr->x, dr->y); |
| } else { |
| destsurf->StretchBlit(destsurf, texturedata->surface, sr, dr); |
| } |
| } |
| break; |
| } |
| |
| case SDL_RENDERCMD_COPY_EX: |
| break; /* unsupported */ |
| |
| case SDL_RENDERCMD_NO_OP: |
| break; |
| } |
| |
| cmd = cmd->next; |
| } |
| |
| 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 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 void |
| DirectFB_DestroyRenderer(SDL_Renderer * renderer) |
| { |
| DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata; |
| #if 0 |
| SDL_VideoDisplay *display = SDL_GetDisplayForWindow(data->window); |
| if (display->palette) { |
| SDL_DelPaletteWatch(display->palette, DisplayPaletteChanged, data); |
| } |
| #endif |
| |
| SDL_free(data); |
| SDL_free(renderer); |
| } |
| |
| 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; |
| } |
| |
| #if 0 |
| static int |
| DirectFB_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect, |
| Uint32 format, const void * pixels, int pitch) |
| { |
| SDL_Window *window = renderer->window; |
| SDL_DFB_WINDOWDATA(window); |
| Uint32 sdl_format; |
| unsigned char* laypixels; |
| int laypitch; |
| DFBSurfacePixelFormat dfb_format; |
| |
| SDL_DFB_CHECK(windata->surface->GetPixelFormat(windata->surface, &dfb_format)); |
| sdl_format = DirectFB_DFBToSDLPixelFormat(dfb_format); |
| |
| SDL_DFB_CHECK(windata->surface->Lock(windata->surface, DSLF_WRITE, (void **) &laypixels, &laypitch)); |
| |
| laypixels += (rect->y * laypitch + rect->x * SDL_BYTESPERPIXEL(sdl_format) ); |
| SDL_ConvertPixels(rect->w, rect->h, |
| format, pixels, pitch, |
| sdl_format, laypixels, laypitch); |
| |
| SDL_DFB_CHECK(windata->surface->Unlock(windata->surface)); |
| |
| return 0; |
| } |
| #endif |
| |
| |
| SDL_Renderer * |
| DirectFB_CreateRenderer(SDL_Window * window, Uint32 flags) |
| { |
| IDirectFBSurface *winsurf = get_dfb_surface(window); |
| /*SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);*/ |
| SDL_Renderer *renderer = NULL; |
| DirectFB_RenderData *data = NULL; |
| DFBSurfaceCapabilities scaps; |
| |
| if (!winsurf) { |
| return NULL; |
| } |
| |
| SDL_DFB_ALLOC_CLEAR(renderer, sizeof(*renderer)); |
| SDL_DFB_ALLOC_CLEAR(data, sizeof(*data)); |
| |
| renderer->WindowEvent = DirectFB_WindowEvent; |
| renderer->CreateTexture = DirectFB_CreateTexture; |
| renderer->UpdateTexture = DirectFB_UpdateTexture; |
| renderer->LockTexture = DirectFB_LockTexture; |
| renderer->UnlockTexture = DirectFB_UnlockTexture; |
| renderer->SetTextureScaleMode = DirectFB_SetTextureScaleMode; |
| renderer->QueueSetViewport = DirectFB_QueueSetViewport; |
| renderer->QueueSetDrawColor = DirectFB_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */ |
| renderer->QueueDrawPoints = DirectFB_QueueDrawPoints; |
| renderer->QueueDrawLines = DirectFB_QueueDrawPoints; /* lines and points queue vertices the same way. */ |
| renderer->QueueFillRects = DirectFB_QueueFillRects; |
| renderer->QueueCopy = DirectFB_QueueCopy; |
| renderer->QueueCopyEx = DirectFB_QueueCopyEx; |
| renderer->RunCommandQueue = DirectFB_RunCommandQueue; |
| renderer->RenderPresent = DirectFB_RenderPresent; |
| |
| /* FIXME: Yet to be tested */ |
| renderer->RenderReadPixels = DirectFB_RenderReadPixels; |
| /* renderer->RenderWritePixels = DirectFB_RenderWritePixels; */ |
| |
| renderer->DestroyTexture = DirectFB_DestroyTexture; |
| renderer->DestroyRenderer = DirectFB_DestroyRenderer; |
| renderer->SetRenderTarget = DirectFB_SetRenderTarget; |
| |
| renderer->info = DirectFB_RenderDriver.info; |
| renderer->window = window; /* SDL window */ |
| renderer->driverdata = data; |
| |
| renderer->info.flags = |
| SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE; |
| |
| data->window = window; |
| data->target = winsurf; |
| |
| data->flipflags = DSFLIP_PIPELINE | DSFLIP_BLIT; |
| |
| if (flags & SDL_RENDERER_PRESENTVSYNC) { |
| data->flipflags |= DSFLIP_WAITFORSYNC | DSFLIP_ONSYNC; |
| renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; |
| } else |
| data->flipflags |= DSFLIP_ONSYNC; |
| |
| SDL_DFB_CHECKERR(winsurf->GetCapabilities(winsurf, &scaps)); |
| |
| #if 0 |
| if (scaps & DSCAPS_DOUBLE) |
| renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2; |
| else if (scaps & DSCAPS_TRIPLE) |
| renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3; |
| else |
| renderer->info.flags |= SDL_RENDERER_SINGLEBUFFER; |
| #endif |
| |
| DirectFB_SetSupportedPixelFormats(&renderer->info); |
| |
| #if 0 |
| /* Set up a palette watch on the display palette */ |
| if (display-> palette) { |
| SDL_AddPaletteWatch(display->palette, DisplayPaletteChanged, data); |
| } |
| #endif |
| |
| return renderer; |
| |
| error: |
| SDL_DFB_FREE(renderer); |
| SDL_DFB_FREE(data); |
| return NULL; |
| } |
| |
| |
| SDL_RenderDriver DirectFB_RenderDriver = { |
| DirectFB_CreateRenderer, |
| { |
| "directfb", |
| (SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED), |
| /* (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR | |
| SDL_TEXTUREMODULATE_ALPHA), |
| (SDL_BLENDMODE_NONE | SDL_BLENDMODE_MASK | SDL_BLENDMODE_BLEND | |
| SDL_BLENDMODE_ADD | SDL_BLENDMODE_MOD), |
| (SDL_SCALEMODE_NONE | SDL_SCALEMODE_FAST | |
| SDL_SCALEMODE_SLOW | SDL_SCALEMODE_BEST), */ |
| 0, |
| { |
| /* formats filled in later */ |
| }, |
| 0, |
| 0} |
| }; |
| |
| #endif /* SDL_VIDEO_DRIVER_DIRECTFB */ |
| |
| /* vi: set ts=4 sw=4 expandtab: */ |