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