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