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