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