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
SDLtoDFBRect(const SDL_Rect * sr,DFBRectangle * dr)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
SDLtoDFBRect_Float(const SDL_FRect * sr,DFBRectangle * dr)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
TextureHasAlpha(DirectFB_TextureData * data)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 
get_dfb_surface(SDL_Window * window)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 
get_dfb_window(SDL_Window * window)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
SetBlendMode(DirectFB_RenderData * data,int blendMode,DirectFB_TextureData * source)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
PrepareDraw(SDL_Renderer * renderer,const SDL_RenderCommand * cmd)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
DirectFB_WindowEvent(SDL_Renderer * renderer,const SDL_WindowEvent * event)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
DirectFB_ActivateRenderer(SDL_Renderer * renderer)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
DirectFB_AcquireVidLayer(SDL_Renderer * renderer,SDL_Texture * texture)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
DirectFB_CreateTexture(SDL_Renderer * renderer,SDL_Texture * texture)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
DirectFB_UpdateTexture(SDL_Renderer * renderer,SDL_Texture * texture,const SDL_Rect * rect,const void * pixels,int pitch)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
DirectFB_LockTexture(SDL_Renderer * renderer,SDL_Texture * texture,const SDL_Rect * rect,void ** pixels,int * pitch)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
DirectFB_UnlockTexture(SDL_Renderer * renderer,SDL_Texture * texture)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
DirectFB_SetTextureScaleMode()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 
DirectFB_SetRenderTarget(SDL_Renderer * renderer,SDL_Texture * texture)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
DirectFB_QueueSetViewport(SDL_Renderer * renderer,SDL_RenderCommand * cmd)598 DirectFB_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
599 {
600     return 0;  /* nothing to do in this backend. */
601 }
602 
603 static int
DirectFB_QueueDrawPoints(SDL_Renderer * renderer,SDL_RenderCommand * cmd,const SDL_FPoint * points,int count)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
DirectFB_QueueFillRects(SDL_Renderer * renderer,SDL_RenderCommand * cmd,const SDL_FRect * rects,int count)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
DirectFB_QueueCopy(SDL_Renderer * renderer,SDL_RenderCommand * cmd,SDL_Texture * texture,const SDL_Rect * srcrect,const SDL_FRect * dstrect)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
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)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
DirectFB_RunCommandQueue(SDL_Renderer * renderer,SDL_RenderCommand * cmd,void * vertices,size_t vertsize)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
DirectFB_RenderPresent(SDL_Renderer * renderer)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
DirectFB_DestroyTexture(SDL_Renderer * renderer,SDL_Texture * texture)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
DirectFB_DestroyRenderer(SDL_Renderer * renderer)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
DirectFB_RenderReadPixels(SDL_Renderer * renderer,const SDL_Rect * rect,Uint32 format,void * pixels,int pitch)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 *
DirectFB_CreateRenderer(SDL_Window * window,Uint32 flags)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: */
1070