xorg_composite.c revision ecfe1352ccce802c9299c76d600c4d2f33352701
1#include "xorg_composite.h" 2 3#include "xorg_renderer.h" 4#include "xorg_exa_tgsi.h" 5 6#include "cso_cache/cso_context.h" 7#include "util/u_draw_quad.h" 8#include "util/u_math.h" 9 10#include "pipe/p_inlines.h" 11 12/*XXX also in Xrender.h but the including it here breaks compilition */ 13#define XFixedToDouble(f) (((double) (f)) / 65536.) 14 15struct xorg_composite_blend { 16 int op : 8; 17 18 unsigned alpha_dst : 4; 19 unsigned alpha_src : 4; 20 21 unsigned rgb_src : 8; /**< PIPE_BLENDFACTOR_x */ 22 unsigned rgb_dst : 8; /**< PIPE_BLENDFACTOR_x */ 23}; 24 25#define BLEND_OP_OVER 3 26static const struct xorg_composite_blend xorg_blends[] = { 27 { PictOpClear, 28 0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO}, 29 { PictOpSrc, 30 0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ZERO}, 31 { PictOpDst, 32 0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ONE}, 33 { PictOpOver, 34 0, 1, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, 35 { PictOpOverReverse, 36 1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE}, 37 { PictOpIn, 38 1, 0, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_ZERO}, 39 { PictOpInReverse, 40 0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_SRC_ALPHA}, 41 { PictOpOut, 42 1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ZERO}, 43 { PictOpOutReverse, 44 0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, 45 { PictOpAtop, 46 1, 1, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, 47 { PictOpAtopReverse, 48 1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_SRC_ALPHA}, 49 { PictOpXor, 50 1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, 51 { PictOpAdd, 52 0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE}, 53}; 54 55 56static INLINE void 57pixel_to_float4(Pixel pixel, float *color) 58{ 59 CARD32 r, g, b, a; 60 61 a = (pixel >> 24) & 0xff; 62 r = (pixel >> 16) & 0xff; 63 g = (pixel >> 8) & 0xff; 64 b = (pixel >> 0) & 0xff; 65 color[0] = ((float)r) / 255.; 66 color[1] = ((float)g) / 255.; 67 color[2] = ((float)b) / 255.; 68 color[3] = ((float)a) / 255.; 69} 70 71static boolean 72blend_for_op(struct xorg_composite_blend *blend, 73 int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, 74 PicturePtr pDstPicture) 75{ 76 const int num_blends = 77 sizeof(xorg_blends)/sizeof(struct xorg_composite_blend); 78 int i; 79 boolean supported = FALSE; 80 81 /* our default in case something goes wrong */ 82 *blend = xorg_blends[BLEND_OP_OVER]; 83 84 for (i = 0; i < num_blends; ++i) { 85 if (xorg_blends[i].op == op) { 86 *blend = xorg_blends[i]; 87 supported = TRUE; 88 } 89 } 90 91 /* If there's no dst alpha channel, adjust the blend op so that we'll treat 92 * it as always 1. */ 93 if (pDstPicture && 94 PICT_FORMAT_A(pDstPicture->format) == 0 && blend->alpha_dst) { 95 if (blend->rgb_src == PIPE_BLENDFACTOR_DST_ALPHA) 96 blend->rgb_src = PIPE_BLENDFACTOR_ONE; 97 else if (blend->rgb_src == PIPE_BLENDFACTOR_INV_DST_ALPHA) 98 blend->rgb_src = PIPE_BLENDFACTOR_ZERO; 99 } 100 101 /* If the source alpha is being used, then we should only be in a case where 102 * the source blend factor is 0, and the source blend value is the mask 103 * channels multiplied by the source picture's alpha. */ 104 if (pMaskPicture && pMaskPicture->componentAlpha && 105 PICT_FORMAT_RGB(pMaskPicture->format) && blend->alpha_src) { 106 if (blend->rgb_dst == PIPE_BLENDFACTOR_SRC_ALPHA) { 107 blend->rgb_dst = PIPE_BLENDFACTOR_SRC_COLOR; 108 } else if (blend->rgb_dst == PIPE_BLENDFACTOR_INV_SRC_ALPHA) { 109 blend->rgb_dst = PIPE_BLENDFACTOR_INV_SRC_COLOR; 110 } 111 } 112 113 return supported; 114} 115 116static INLINE int 117render_repeat_to_gallium(int mode) 118{ 119 switch(mode) { 120 case RepeatNone: 121 return PIPE_TEX_WRAP_CLAMP_TO_BORDER; 122 case RepeatNormal: 123 return PIPE_TEX_WRAP_REPEAT; 124 case RepeatReflect: 125 return PIPE_TEX_WRAP_MIRROR_REPEAT; 126 case RepeatPad: 127 return PIPE_TEX_WRAP_CLAMP_TO_EDGE; 128 default: 129 debug_printf("Unsupported repeat mode\n"); 130 } 131 return PIPE_TEX_WRAP_REPEAT; 132} 133 134static INLINE boolean 135render_filter_to_gallium(int xrender_filter, int *out_filter) 136{ 137 138 switch (xrender_filter) { 139 case PictFilterNearest: 140 *out_filter = PIPE_TEX_FILTER_NEAREST; 141 break; 142 case PictFilterBilinear: 143 *out_filter = PIPE_TEX_FILTER_LINEAR; 144 break; 145 case PictFilterFast: 146 *out_filter = PIPE_TEX_FILTER_NEAREST; 147 break; 148 case PictFilterGood: 149 *out_filter = PIPE_TEX_FILTER_LINEAR; 150 break; 151 case PictFilterBest: 152 *out_filter = PIPE_TEX_FILTER_LINEAR; 153 break; 154 case PictFilterConvolution: 155 *out_filter = PIPE_TEX_FILTER_NEAREST; 156 return FALSE; 157 default: 158 debug_printf("Unknown xrender filter\n"); 159 *out_filter = PIPE_TEX_FILTER_NEAREST; 160 return FALSE; 161 } 162 163 return TRUE; 164} 165 166static boolean is_filter_accelerated(PicturePtr pic) 167{ 168 int filter; 169 if (pic && !render_filter_to_gallium(pic->filter, &filter)) 170 return FALSE; 171 return TRUE; 172} 173 174boolean xorg_composite_accelerated(int op, 175 PicturePtr pSrcPicture, 176 PicturePtr pMaskPicture, 177 PicturePtr pDstPicture) 178{ 179 ScreenPtr pScreen = pDstPicture->pDrawable->pScreen; 180 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 181 modesettingPtr ms = modesettingPTR(pScrn); 182 struct xorg_composite_blend blend; 183 184 if (!is_filter_accelerated(pSrcPicture) || 185 !is_filter_accelerated(pMaskPicture)) { 186 XORG_FALLBACK("Unsupported Xrender filter"); 187 } 188 189 if (pSrcPicture->pSourcePict) { 190 if (pSrcPicture->pSourcePict->type != SourcePictTypeSolidFill) 191 XORG_FALLBACK("Gradients not enabled (haven't been well tested)"); 192 } 193 194 if (blend_for_op(&blend, op, 195 pSrcPicture, pMaskPicture, pDstPicture)) { 196 /* Check for component alpha */ 197 if (pMaskPicture && pMaskPicture->componentAlpha && 198 PICT_FORMAT_RGB(pMaskPicture->format)) { 199 if (blend.alpha_src && blend.rgb_src != PIPE_BLENDFACTOR_ZERO) { 200 XORG_FALLBACK("Component alpha not supported with source " 201 "alpha and source value blending. (op=%d)", 202 op); 203 } 204 } 205 206 return TRUE; 207 } 208 XORG_FALLBACK("Unsupported composition operation = %d", op); 209} 210 211static void 212bind_blend_state(struct exa_context *exa, int op, 213 PicturePtr pSrcPicture, 214 PicturePtr pMaskPicture, 215 PicturePtr pDstPicture) 216{ 217 struct xorg_composite_blend blend_opt; 218 struct pipe_blend_state blend; 219 220 blend_for_op(&blend_opt, op, pSrcPicture, pMaskPicture, pDstPicture); 221 222 memset(&blend, 0, sizeof(struct pipe_blend_state)); 223 blend.blend_enable = 1; 224 blend.colormask |= PIPE_MASK_RGBA; 225 226 blend.rgb_src_factor = blend_opt.rgb_src; 227 blend.alpha_src_factor = blend_opt.rgb_src; 228 blend.rgb_dst_factor = blend_opt.rgb_dst; 229 blend.alpha_dst_factor = blend_opt.rgb_dst; 230 231 cso_set_blend(exa->renderer->cso, &blend); 232} 233 234static unsigned 235picture_format_fixups(struct exa_pixmap_priv *pSrc, PicturePtr pSrcPicture, boolean mask, 236 PicturePtr pDstPicture) 237{ 238 boolean set_alpha = FALSE; 239 boolean swizzle = FALSE; 240 unsigned ret = 0; 241 242 if (pSrc->picture_format == pSrcPicture->format) { 243 if (pSrc->picture_format == PICT_a8) { 244 if (mask) 245 return FS_MASK_LUMINANCE; 246 else if (pDstPicture->format != PICT_a8) { 247 /* if both dst and src are luminance then 248 * we don't want to swizzle the alpha (X) of the 249 * source into W component of the dst because 250 * it will break our destination */ 251 return FS_SRC_LUMINANCE; 252 } 253 } 254 return 0; 255 } 256 257 if (pSrc->picture_format != PICT_a8r8g8b8) { 258 assert(!"can not handle formats"); 259 return 0; 260 } 261 262 /* pSrc->picture_format == PICT_a8r8g8b8 */ 263 switch (pSrcPicture->format) { 264 case PICT_x8b8g8r8: 265 case PICT_b8g8r8: 266 set_alpha = TRUE; /* fall trough */ 267 case PICT_a8b8g8r8: 268 swizzle = TRUE; 269 break; 270 case PICT_x8r8g8b8: 271 case PICT_r8g8b8: 272 set_alpha = TRUE; /* fall through */ 273 case PICT_a8r8g8b8: 274 break; 275#ifdef PICT_TYPE_BGRA 276 case PICT_b8g8r8a8: 277 case PICT_b8g8r8x8: 278 case PICT_a2r10g10b10: 279 case PICT_x2r10g10b10: 280 case PICT_a2b10g10r10: 281 case PICT_x2b10g10r10: 282#endif 283 default: 284 assert(!"can not handle formats"); 285 return 0; 286 } 287 288 if (set_alpha) 289 ret |= mask ? FS_MASK_SET_ALPHA : FS_SRC_SET_ALPHA; 290 if (swizzle) 291 ret |= mask ? FS_MASK_SWIZZLE_RGB : FS_SRC_SWIZZLE_RGB; 292 293 return ret; 294} 295 296static void 297bind_shaders(struct exa_context *exa, int op, 298 PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture, 299 struct exa_pixmap_priv *pSrc, struct exa_pixmap_priv *pMask) 300{ 301 unsigned vs_traits = 0, fs_traits = 0; 302 struct xorg_shader shader; 303 304 exa->has_solid_color = FALSE; 305 306 if (pSrcPicture) { 307 if (pSrcPicture->repeatType == RepeatNone && pSrcPicture->transform) 308 fs_traits |= FS_SRC_REPEAT_NONE; 309 310 if (pSrcPicture->pSourcePict) { 311 if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) { 312 fs_traits |= FS_SOLID_FILL; 313 vs_traits |= VS_SOLID_FILL; 314 debug_assert(pSrcPicture->format == PICT_a8r8g8b8); 315 pixel_to_float4(pSrcPicture->pSourcePict->solidFill.color, 316 exa->solid_color); 317 exa->has_solid_color = TRUE; 318 } else { 319 debug_assert("!gradients not supported"); 320 } 321 } else { 322 fs_traits |= FS_COMPOSITE; 323 vs_traits |= VS_COMPOSITE; 324 } 325 326 fs_traits |= picture_format_fixups(pSrc, pSrcPicture, FALSE, pDstPicture); 327 } 328 329 if (pMaskPicture) { 330 vs_traits |= VS_MASK; 331 fs_traits |= FS_MASK; 332 if (pMaskPicture->repeatType == RepeatNone && pMaskPicture->transform) 333 fs_traits |= FS_MASK_REPEAT_NONE; 334 if (pMaskPicture->componentAlpha) { 335 struct xorg_composite_blend blend; 336 blend_for_op(&blend, op, 337 pSrcPicture, pMaskPicture, NULL); 338 if (blend.alpha_src) { 339 fs_traits |= FS_CA_SRCALPHA; 340 } else 341 fs_traits |= FS_CA_FULL; 342 } 343 344 fs_traits |= picture_format_fixups(pMask, pMaskPicture, TRUE, pDstPicture); 345 } 346 347 shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits); 348 cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs); 349 cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs); 350} 351 352static void 353bind_samplers(struct exa_context *exa, int op, 354 PicturePtr pSrcPicture, PicturePtr pMaskPicture, 355 PicturePtr pDstPicture, 356 struct exa_pixmap_priv *pSrc, 357 struct exa_pixmap_priv *pMask, 358 struct exa_pixmap_priv *pDst) 359{ 360 struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; 361 struct pipe_sampler_state src_sampler, mask_sampler; 362 363 exa->num_bound_samplers = 0; 364 365#if 0 366 if ((pSrc && (exa->pipe->is_texture_referenced(exa->pipe, pSrc->tex, 0, 0) & 367 PIPE_REFERENCED_FOR_WRITE)) || 368 (pMask && (exa->pipe->is_texture_referenced(exa->pipe, pMask->tex, 0, 0) & 369 PIPE_REFERENCED_FOR_WRITE))) 370 xorg_exa_flush(exa, PIPE_FLUSH_RENDER_CACHE, NULL); 371#endif 372 373 memset(&src_sampler, 0, sizeof(struct pipe_sampler_state)); 374 memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state)); 375 376 if (pSrcPicture && pSrc) { 377 if (exa->has_solid_color) { 378 debug_assert(!"solid color with textures"); 379 samplers[0] = NULL; 380 exa->bound_textures[0] = NULL; 381 } else { 382 unsigned src_wrap = render_repeat_to_gallium( 383 pSrcPicture->repeatType); 384 int filter; 385 386 render_filter_to_gallium(pSrcPicture->filter, &filter); 387 388 src_sampler.wrap_s = src_wrap; 389 src_sampler.wrap_t = src_wrap; 390 src_sampler.min_img_filter = filter; 391 src_sampler.mag_img_filter = filter; 392 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; 393 src_sampler.normalized_coords = 1; 394 samplers[0] = &src_sampler; 395 exa->bound_textures[0] = pSrc->tex; 396 exa->num_bound_samplers = 1; 397 } 398 } 399 400 if (pMaskPicture && pMask) { 401 unsigned mask_wrap = render_repeat_to_gallium( 402 pMaskPicture->repeatType); 403 int filter; 404 405 render_filter_to_gallium(pMaskPicture->filter, &filter); 406 407 mask_sampler.wrap_s = mask_wrap; 408 mask_sampler.wrap_t = mask_wrap; 409 mask_sampler.min_img_filter = filter; 410 mask_sampler.mag_img_filter = filter; 411 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; 412 mask_sampler.normalized_coords = 1; 413 samplers[1] = &mask_sampler; 414 exa->bound_textures[1] = pMask->tex; 415 exa->num_bound_samplers = 2; 416 } 417 418 cso_set_samplers(exa->renderer->cso, exa->num_bound_samplers, 419 (const struct pipe_sampler_state **)samplers); 420 cso_set_sampler_textures(exa->renderer->cso, exa->num_bound_samplers, 421 exa->bound_textures); 422} 423 424 425 426 427 428static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix) 429{ 430 if (!trans) 431 return FALSE; 432 433 matrix[0] = XFixedToDouble(trans->matrix[0][0]); 434 matrix[3] = XFixedToDouble(trans->matrix[0][1]); 435 matrix[6] = XFixedToDouble(trans->matrix[0][2]); 436 437 matrix[1] = XFixedToDouble(trans->matrix[1][0]); 438 matrix[4] = XFixedToDouble(trans->matrix[1][1]); 439 matrix[7] = XFixedToDouble(trans->matrix[1][2]); 440 441 matrix[2] = XFixedToDouble(trans->matrix[2][0]); 442 matrix[5] = XFixedToDouble(trans->matrix[2][1]); 443 matrix[8] = XFixedToDouble(trans->matrix[2][2]); 444 445 return TRUE; 446} 447 448static void 449setup_transforms(struct exa_context *exa, 450 PicturePtr pSrcPicture, PicturePtr pMaskPicture) 451{ 452 PictTransform *src_t = NULL; 453 PictTransform *mask_t = NULL; 454 455 if (pSrcPicture) 456 src_t = pSrcPicture->transform; 457 if (pMaskPicture) 458 mask_t = pMaskPicture->transform; 459 460 exa->transform.has_src = 461 matrix_from_pict_transform(src_t, exa->transform.src); 462 exa->transform.has_mask = 463 matrix_from_pict_transform(mask_t, exa->transform.mask); 464} 465 466boolean xorg_composite_bind_state(struct exa_context *exa, 467 int op, 468 PicturePtr pSrcPicture, 469 PicturePtr pMaskPicture, 470 PicturePtr pDstPicture, 471 struct exa_pixmap_priv *pSrc, 472 struct exa_pixmap_priv *pMask, 473 struct exa_pixmap_priv *pDst) 474{ 475 struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pDst); 476 477 renderer_bind_destination(exa->renderer, dst_surf); 478 479 bind_blend_state(exa, op, pSrcPicture, pMaskPicture, pDstPicture); 480 bind_shaders(exa, op, pSrcPicture, pMaskPicture, pDstPicture, pSrc, pMask); 481 bind_samplers(exa, op, pSrcPicture, pMaskPicture, 482 pDstPicture, pSrc, pMask, pDst); 483 484 setup_transforms(exa, pSrcPicture, pMaskPicture); 485 486 if (exa->num_bound_samplers == 0 ) { /* solid fill */ 487 renderer_begin_solid(exa->renderer); 488 } else { 489 renderer_begin_textures(exa->renderer, 490 exa->bound_textures, 491 exa->num_bound_samplers); 492 } 493 494 495 pipe_surface_reference(&dst_surf, NULL); 496 return TRUE; 497} 498 499void xorg_composite(struct exa_context *exa, 500 struct exa_pixmap_priv *dst, 501 int srcX, int srcY, int maskX, int maskY, 502 int dstX, int dstY, int width, int height) 503{ 504 if (exa->num_bound_samplers == 0 ) { /* solid fill */ 505 renderer_solid(exa->renderer, 506 dstX, dstY, dstX + width, dstY + height, 507 exa->solid_color); 508 } else { 509 int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY}; 510 float *src_matrix = NULL; 511 float *mask_matrix = NULL; 512 513 if (exa->transform.has_src) 514 src_matrix = exa->transform.src; 515 if (exa->transform.has_mask) 516 mask_matrix = exa->transform.mask; 517 518 renderer_texture(exa->renderer, 519 pos, width, height, 520 exa->bound_textures, 521 exa->num_bound_samplers, 522 src_matrix, mask_matrix); 523 } 524} 525 526boolean xorg_solid_bind_state(struct exa_context *exa, 527 struct exa_pixmap_priv *pixmap, 528 Pixel fg) 529{ 530 struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pixmap); 531 unsigned vs_traits, fs_traits; 532 struct xorg_shader shader; 533 534 pixel_to_float4(fg, exa->solid_color); 535 exa->has_solid_color = TRUE; 536 537#if 0 538 debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n", 539 (fg >> 24) & 0xff, (fg >> 16) & 0xff, 540 (fg >> 8) & 0xff, (fg >> 0) & 0xff, 541 exa->solid_color[0], exa->solid_color[1], 542 exa->solid_color[2], exa->solid_color[3]); 543#endif 544 545 vs_traits = VS_SOLID_FILL; 546 fs_traits = FS_SOLID_FILL; 547 548 renderer_bind_destination(exa->renderer, dst_surf); 549 bind_blend_state(exa, PictOpSrc, NULL, NULL, NULL); 550 cso_set_samplers(exa->renderer->cso, 0, NULL); 551 cso_set_sampler_textures(exa->renderer->cso, 0, NULL); 552 553 shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits); 554 cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs); 555 cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs); 556 557 renderer_begin_solid(exa->renderer); 558 559 pipe_surface_reference(&dst_surf, NULL); 560 return TRUE; 561} 562 563void xorg_solid(struct exa_context *exa, 564 struct exa_pixmap_priv *pixmap, 565 int x0, int y0, int x1, int y1) 566{ 567 renderer_solid(exa->renderer, 568 x0, y0, x1, y1, exa->solid_color); 569} 570 571void 572xorg_composite_done(struct exa_context *exa) 573{ 574 renderer_draw_flush(exa->renderer); 575 576 exa->transform.has_src = FALSE; 577 exa->transform.has_mask = FALSE; 578 exa->has_solid_color = FALSE; 579 exa->num_bound_samplers = 0; 580} 581