xorg_composite.c revision 59d6f3eb4a4052ef764a9ba0589e64a5252feceb
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 memset(&src_sampler, 0, sizeof(struct pipe_sampler_state)); 363 memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state)); 364 365 if (pSrcPicture && pSrc) { 366 if (exa->has_solid_color) { 367 debug_assert(!"solid color with textures"); 368 samplers[0] = NULL; 369 exa->bound_textures[0] = NULL; 370 } else { 371 unsigned src_wrap = render_repeat_to_gallium( 372 pSrcPicture->repeatType); 373 int filter; 374 375 render_filter_to_gallium(pSrcPicture->filter, &filter); 376 377 src_sampler.wrap_s = src_wrap; 378 src_sampler.wrap_t = src_wrap; 379 src_sampler.min_img_filter = filter; 380 src_sampler.mag_img_filter = filter; 381 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; 382 src_sampler.normalized_coords = 1; 383 samplers[0] = &src_sampler; 384 exa->bound_textures[0] = pSrc->tex; 385 exa->num_bound_samplers = 1; 386 } 387 } 388 389 if (pMaskPicture && pMask) { 390 unsigned mask_wrap = render_repeat_to_gallium( 391 pMaskPicture->repeatType); 392 int filter; 393 394 render_filter_to_gallium(pMaskPicture->filter, &filter); 395 396 mask_sampler.wrap_s = mask_wrap; 397 mask_sampler.wrap_t = mask_wrap; 398 mask_sampler.min_img_filter = filter; 399 mask_sampler.mag_img_filter = filter; 400 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; 401 mask_sampler.normalized_coords = 1; 402 samplers[1] = &mask_sampler; 403 exa->bound_textures[1] = pMask->tex; 404 exa->num_bound_samplers = 2; 405 } 406 407 cso_set_samplers(exa->renderer->cso, exa->num_bound_samplers, 408 (const struct pipe_sampler_state **)samplers); 409 cso_set_sampler_textures(exa->renderer->cso, exa->num_bound_samplers, 410 exa->bound_textures); 411} 412 413 414 415static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix) 416{ 417 if (!trans) 418 return FALSE; 419 420 matrix[0] = XFixedToDouble(trans->matrix[0][0]); 421 matrix[3] = XFixedToDouble(trans->matrix[0][1]); 422 matrix[6] = XFixedToDouble(trans->matrix[0][2]); 423 424 matrix[1] = XFixedToDouble(trans->matrix[1][0]); 425 matrix[4] = XFixedToDouble(trans->matrix[1][1]); 426 matrix[7] = XFixedToDouble(trans->matrix[1][2]); 427 428 matrix[2] = XFixedToDouble(trans->matrix[2][0]); 429 matrix[5] = XFixedToDouble(trans->matrix[2][1]); 430 matrix[8] = XFixedToDouble(trans->matrix[2][2]); 431 432 return TRUE; 433} 434 435static void 436setup_transforms(struct exa_context *exa, 437 PicturePtr pSrcPicture, PicturePtr pMaskPicture) 438{ 439 PictTransform *src_t = NULL; 440 PictTransform *mask_t = NULL; 441 442 if (pSrcPicture) 443 src_t = pSrcPicture->transform; 444 if (pMaskPicture) 445 mask_t = pMaskPicture->transform; 446 447 exa->transform.has_src = 448 matrix_from_pict_transform(src_t, exa->transform.src); 449 exa->transform.has_mask = 450 matrix_from_pict_transform(mask_t, exa->transform.mask); 451} 452 453boolean xorg_composite_bind_state(struct exa_context *exa, 454 int op, 455 PicturePtr pSrcPicture, 456 PicturePtr pMaskPicture, 457 PicturePtr pDstPicture, 458 struct exa_pixmap_priv *pSrc, 459 struct exa_pixmap_priv *pMask, 460 struct exa_pixmap_priv *pDst) 461{ 462 struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pDst); 463 464 renderer_bind_destination(exa->renderer, dst_surf, 465 pDst->width, 466 pDst->height); 467 468 bind_blend_state(exa, op, pSrcPicture, pMaskPicture, pDstPicture); 469 bind_shaders(exa, op, pSrcPicture, pMaskPicture, pDstPicture, pSrc, pMask); 470 bind_samplers(exa, op, pSrcPicture, pMaskPicture, 471 pDstPicture, pSrc, pMask, pDst); 472 473 setup_transforms(exa, pSrcPicture, pMaskPicture); 474 475 if (exa->num_bound_samplers == 0 ) { /* solid fill */ 476 renderer_begin_solid(exa->renderer); 477 } else { 478 renderer_begin_textures(exa->renderer, 479 exa->bound_textures, 480 exa->num_bound_samplers); 481 } 482 483 484 pipe_surface_reference(&dst_surf, NULL); 485 return TRUE; 486} 487 488void xorg_composite(struct exa_context *exa, 489 struct exa_pixmap_priv *dst, 490 int srcX, int srcY, int maskX, int maskY, 491 int dstX, int dstY, int width, int height) 492{ 493 if (exa->num_bound_samplers == 0 ) { /* solid fill */ 494 renderer_solid(exa->renderer, 495 dstX, dstY, dstX + width, dstY + height, 496 exa->solid_color); 497 } else { 498 int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY}; 499 float *src_matrix = NULL; 500 float *mask_matrix = NULL; 501 502 if (exa->transform.has_src) 503 src_matrix = exa->transform.src; 504 if (exa->transform.has_mask) 505 mask_matrix = exa->transform.mask; 506 507 renderer_texture(exa->renderer, 508 pos, width, height, 509 exa->bound_textures, 510 exa->num_bound_samplers, 511 src_matrix, mask_matrix); 512 } 513} 514 515boolean xorg_solid_bind_state(struct exa_context *exa, 516 struct exa_pixmap_priv *pixmap, 517 Pixel fg) 518{ 519 struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pixmap); 520 unsigned vs_traits, fs_traits; 521 struct xorg_shader shader; 522 523 pixel_to_float4(fg, exa->solid_color); 524 exa->has_solid_color = TRUE; 525 526#if 0 527 debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n", 528 (fg >> 24) & 0xff, (fg >> 16) & 0xff, 529 (fg >> 8) & 0xff, (fg >> 0) & 0xff, 530 exa->solid_color[0], exa->solid_color[1], 531 exa->solid_color[2], exa->solid_color[3]); 532#endif 533 534 vs_traits = VS_SOLID_FILL; 535 fs_traits = FS_SOLID_FILL; 536 537 renderer_bind_destination(exa->renderer, dst_surf, 538 pixmap->width, pixmap->height); 539 bind_blend_state(exa, PictOpSrc, NULL, NULL, NULL); 540 cso_set_samplers(exa->renderer->cso, 0, NULL); 541 cso_set_sampler_textures(exa->renderer->cso, 0, NULL); 542 543 shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits); 544 cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs); 545 cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs); 546 547 renderer_begin_solid(exa->renderer); 548 549 pipe_surface_reference(&dst_surf, NULL); 550 return TRUE; 551} 552 553void xorg_solid(struct exa_context *exa, 554 struct exa_pixmap_priv *pixmap, 555 int x0, int y0, int x1, int y1) 556{ 557 renderer_solid(exa->renderer, 558 x0, y0, x1, y1, exa->solid_color); 559} 560 561void 562xorg_composite_done(struct exa_context *exa) 563{ 564 renderer_draw_flush(exa->renderer); 565 566 exa->transform.has_src = FALSE; 567 exa->transform.has_mask = FALSE; 568 exa->has_solid_color = FALSE; 569 exa->num_bound_samplers = 0; 570} 571