xorg_composite.c revision cb060f3b987c9fa07ebe06cf2e7e54d1eaded1e1
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 default: 155 debug_printf("Unkown xrender filter"); 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.blend_enable = 1; 221 blend.colormask |= PIPE_MASK_RGBA; 222 223 blend.rgb_src_factor = blend_opt.rgb_src; 224 blend.alpha_src_factor = blend_opt.rgb_src; 225 blend.rgb_dst_factor = blend_opt.rgb_dst; 226 blend.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{ 234 boolean set_alpha = FALSE; 235 boolean swizzle = FALSE; 236 unsigned ret = 0; 237 238 if (pSrc->picture_format == pSrcPicture->format) { 239 if (pSrc->picture_format == PICT_a8) 240 return mask ? FS_MASK_LUMINANCE : FS_MASK_LUMINANCE; 241 return 0; 242 } 243 244 if (pSrc->picture_format != PICT_a8r8g8b8) { 245 assert(!"can not handle formats"); 246 return 0; 247 } 248 249 /* pSrc->picture_format == PICT_a8r8g8b8 */ 250 switch (pSrcPicture->format) { 251 case PICT_x8b8g8r8: 252 case PICT_b8g8r8: 253 set_alpha = TRUE; /* fall trough */ 254 case PICT_a8b8g8r8: 255 swizzle = TRUE; 256 break; 257 case PICT_x8r8g8b8: 258 case PICT_r8g8b8: 259 set_alpha = TRUE; /* fall through */ 260 case PICT_a8r8g8b8: 261 break; 262#ifdef PICT_TYPE_BGRA 263 case PICT_b8g8r8a8: 264 case PICT_b8g8r8x8: 265 case PICT_a2r10g10b10: 266 case PICT_x2r10g10b10: 267 case PICT_a2b10g10r10: 268 case PICT_x2b10g10r10: 269#endif 270 default: 271 assert(!"can not handle formats"); 272 return 0; 273 } 274 275 if (set_alpha) 276 ret |= mask ? FS_MASK_SET_ALPHA : FS_SRC_SET_ALPHA; 277 if (swizzle) 278 ret |= mask ? FS_MASK_SWIZZLE_RGB : FS_SRC_SWIZZLE_RGB; 279 280 return ret; 281} 282 283static void 284bind_shaders(struct exa_context *exa, int op, 285 PicturePtr pSrcPicture, PicturePtr pMaskPicture, 286 struct exa_pixmap_priv *pSrc, struct exa_pixmap_priv *pMask) 287{ 288 unsigned vs_traits = 0, fs_traits = 0; 289 struct xorg_shader shader; 290 291 exa->has_solid_color = FALSE; 292 293 if (pSrcPicture) { 294 if (pSrcPicture->repeatType == RepeatNone && pSrcPicture->transform) 295 fs_traits |= FS_SRC_REPEAT_NONE; 296 297 if (pSrcPicture->pSourcePict) { 298 if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) { 299 fs_traits |= FS_SOLID_FILL; 300 vs_traits |= VS_SOLID_FILL; 301 debug_assert(pSrcPicture->format == PICT_a8r8g8b8); 302 pixel_to_float4(pSrcPicture->pSourcePict->solidFill.color, 303 exa->solid_color); 304 exa->has_solid_color = TRUE; 305 } else { 306 debug_assert("!gradients not supported"); 307 } 308 } else { 309 fs_traits |= FS_COMPOSITE; 310 vs_traits |= VS_COMPOSITE; 311 } 312 313 fs_traits |= picture_format_fixups(pSrc, pSrcPicture, FALSE); 314 } 315 316 if (pMaskPicture) { 317 vs_traits |= VS_MASK; 318 fs_traits |= FS_MASK; 319 if (pMaskPicture->repeatType == RepeatNone && pMaskPicture->transform) 320 fs_traits |= FS_MASK_REPEAT_NONE; 321 if (pMaskPicture->componentAlpha) { 322 struct xorg_composite_blend blend; 323 blend_for_op(&blend, op, 324 pSrcPicture, pMaskPicture, NULL); 325 if (blend.alpha_src) { 326 fs_traits |= FS_CA_SRCALPHA; 327 } else 328 fs_traits |= FS_CA_FULL; 329 } 330 331 fs_traits |= picture_format_fixups(pMask, pMaskPicture, TRUE); 332 } 333 334 shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits); 335 cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs); 336 cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs); 337} 338 339static void 340bind_samplers(struct exa_context *exa, int op, 341 PicturePtr pSrcPicture, PicturePtr pMaskPicture, 342 PicturePtr pDstPicture, 343 struct exa_pixmap_priv *pSrc, 344 struct exa_pixmap_priv *pMask, 345 struct exa_pixmap_priv *pDst) 346{ 347 struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; 348 struct pipe_sampler_state src_sampler, mask_sampler; 349 350 exa->num_bound_samplers = 0; 351 352#if 0 353 if ((pSrc && (exa->pipe->is_texture_referenced(exa->pipe, pSrc->tex, 0, 0) & 354 PIPE_REFERENCED_FOR_WRITE)) || 355 (pMask && (exa->pipe->is_texture_referenced(exa->pipe, pMask->tex, 0, 0) & 356 PIPE_REFERENCED_FOR_WRITE))) 357 xorg_exa_flush(exa, PIPE_FLUSH_RENDER_CACHE, NULL); 358#endif 359 360 memset(&src_sampler, 0, sizeof(struct pipe_sampler_state)); 361 memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state)); 362 363 if (pSrcPicture && pSrc) { 364 if (exa->has_solid_color) { 365 debug_assert(!"solid color with textures"); 366 samplers[0] = NULL; 367 exa->bound_textures[0] = NULL; 368 } else { 369 unsigned src_wrap = render_repeat_to_gallium( 370 pSrcPicture->repeatType); 371 int filter; 372 373 render_filter_to_gallium(pSrcPicture->filter, &filter); 374 375 src_sampler.wrap_s = src_wrap; 376 src_sampler.wrap_t = src_wrap; 377 src_sampler.min_img_filter = filter; 378 src_sampler.mag_img_filter = filter; 379 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; 380 src_sampler.normalized_coords = 1; 381 samplers[0] = &src_sampler; 382 exa->bound_textures[0] = pSrc->tex; 383 exa->num_bound_samplers = 1; 384 } 385 } 386 387 if (pMaskPicture && pMask) { 388 unsigned mask_wrap = render_repeat_to_gallium( 389 pMaskPicture->repeatType); 390 int filter; 391 392 render_filter_to_gallium(pMaskPicture->filter, &filter); 393 394 mask_sampler.wrap_s = mask_wrap; 395 mask_sampler.wrap_t = mask_wrap; 396 mask_sampler.min_img_filter = filter; 397 mask_sampler.mag_img_filter = filter; 398 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; 399 mask_sampler.normalized_coords = 1; 400 samplers[1] = &mask_sampler; 401 exa->bound_textures[1] = pMask->tex; 402 exa->num_bound_samplers = 2; 403 } 404 405 cso_set_samplers(exa->renderer->cso, exa->num_bound_samplers, 406 (const struct pipe_sampler_state **)samplers); 407 cso_set_sampler_textures(exa->renderer->cso, exa->num_bound_samplers, 408 exa->bound_textures); 409} 410 411static void 412setup_vs_constant_buffer(struct exa_context *exa, 413 int width, int height) 414{ 415 const int param_bytes = 8 * sizeof(float); 416 float vs_consts[8] = { 417 2.f/width, 2.f/height, 1, 1, 418 -1, -1, 0, 0 419 }; 420 renderer_set_constants(exa->renderer, PIPE_SHADER_VERTEX, 421 vs_consts, param_bytes); 422} 423 424 425static void 426setup_fs_constant_buffer(struct exa_context *exa) 427{ 428 const int param_bytes = 4 * sizeof(float); 429 const float fs_consts[8] = { 430 0, 0, 0, 1, 431 }; 432 renderer_set_constants(exa->renderer, PIPE_SHADER_FRAGMENT, 433 fs_consts, param_bytes); 434} 435 436static void 437setup_constant_buffers(struct exa_context *exa, struct exa_pixmap_priv *pDst) 438{ 439 int width = pDst->tex->width[0]; 440 int height = pDst->tex->height[0]; 441 442 setup_vs_constant_buffer(exa, width, height); 443 setup_fs_constant_buffer(exa); 444} 445 446static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix) 447{ 448 if (!trans) 449 return FALSE; 450 451 matrix[0] = XFixedToDouble(trans->matrix[0][0]); 452 matrix[3] = XFixedToDouble(trans->matrix[0][1]); 453 matrix[6] = XFixedToDouble(trans->matrix[0][2]); 454 455 matrix[1] = XFixedToDouble(trans->matrix[1][0]); 456 matrix[4] = XFixedToDouble(trans->matrix[1][1]); 457 matrix[7] = XFixedToDouble(trans->matrix[1][2]); 458 459 matrix[2] = XFixedToDouble(trans->matrix[2][0]); 460 matrix[5] = XFixedToDouble(trans->matrix[2][1]); 461 matrix[8] = XFixedToDouble(trans->matrix[2][2]); 462 463 return TRUE; 464} 465 466static void 467setup_transforms(struct exa_context *exa, 468 PicturePtr pSrcPicture, PicturePtr pMaskPicture) 469{ 470 PictTransform *src_t = NULL; 471 PictTransform *mask_t = NULL; 472 473 if (pSrcPicture) 474 src_t = pSrcPicture->transform; 475 if (pMaskPicture) 476 mask_t = pMaskPicture->transform; 477 478 exa->transform.has_src = 479 matrix_from_pict_transform(src_t, exa->transform.src); 480 exa->transform.has_mask = 481 matrix_from_pict_transform(mask_t, exa->transform.mask); 482} 483 484boolean xorg_composite_bind_state(struct exa_context *exa, 485 int op, 486 PicturePtr pSrcPicture, 487 PicturePtr pMaskPicture, 488 PicturePtr pDstPicture, 489 struct exa_pixmap_priv *pSrc, 490 struct exa_pixmap_priv *pMask, 491 struct exa_pixmap_priv *pDst) 492{ 493 renderer_bind_framebuffer(exa->renderer, pDst); 494 renderer_bind_viewport(exa->renderer, pDst); 495 bind_blend_state(exa, op, pSrcPicture, pMaskPicture, pDstPicture); 496 renderer_bind_rasterizer(exa->renderer); 497 bind_shaders(exa, op, pSrcPicture, pMaskPicture, pSrc, pMask); 498 bind_samplers(exa, op, pSrcPicture, pMaskPicture, 499 pDstPicture, pSrc, pMask, pDst); 500 setup_constant_buffers(exa, pDst); 501 502 setup_transforms(exa, pSrcPicture, pMaskPicture); 503 504 if (exa->num_bound_samplers == 0 ) { /* solid fill */ 505 renderer_begin_solid(exa->renderer); 506 } else { 507 renderer_begin_textures(exa->renderer, 508 exa->bound_textures, 509 exa->num_bound_samplers); 510 } 511 512 return TRUE; 513} 514 515void xorg_composite(struct exa_context *exa, 516 struct exa_pixmap_priv *dst, 517 int srcX, int srcY, int maskX, int maskY, 518 int dstX, int dstY, int width, int height) 519{ 520 if (exa->num_bound_samplers == 0 ) { /* solid fill */ 521 renderer_solid(exa->renderer, 522 dstX, dstY, dstX + width, dstY + height, 523 exa->solid_color); 524 } else { 525 int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY}; 526 float *src_matrix = NULL; 527 float *mask_matrix = NULL; 528 529 if (exa->transform.has_src) 530 src_matrix = exa->transform.src; 531 if (exa->transform.has_mask) 532 mask_matrix = exa->transform.mask; 533 534 renderer_texture(exa->renderer, 535 pos, width, height, 536 exa->bound_textures, 537 exa->num_bound_samplers, 538 src_matrix, mask_matrix); 539 } 540} 541 542boolean xorg_solid_bind_state(struct exa_context *exa, 543 struct exa_pixmap_priv *pixmap, 544 Pixel fg) 545{ 546 unsigned vs_traits, fs_traits; 547 struct xorg_shader shader; 548 549 pixel_to_float4(fg, exa->solid_color); 550 exa->has_solid_color = TRUE; 551 552#if 0 553 debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n", 554 (fg >> 24) & 0xff, (fg >> 16) & 0xff, 555 (fg >> 8) & 0xff, (fg >> 0) & 0xff, 556 exa->solid_color[0], exa->solid_color[1], 557 exa->solid_color[2], exa->solid_color[3]); 558#endif 559 560 vs_traits = VS_SOLID_FILL; 561 fs_traits = FS_SOLID_FILL; 562 563 renderer_bind_framebuffer(exa->renderer, pixmap); 564 renderer_bind_viewport(exa->renderer, pixmap); 565 renderer_bind_rasterizer(exa->renderer); 566 bind_blend_state(exa, PictOpSrc, NULL, NULL, NULL); 567 setup_constant_buffers(exa, pixmap); 568 569 shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits); 570 cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs); 571 cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs); 572 573 renderer_begin_solid(exa->renderer); 574 575 return TRUE; 576} 577 578void xorg_solid(struct exa_context *exa, 579 struct exa_pixmap_priv *pixmap, 580 int x0, int y0, int x1, int y1) 581{ 582 renderer_solid(exa->renderer, 583 x0, y0, x1, y1, exa->solid_color); 584} 585 586