xorg_composite.c revision a6d527d7b82579feae9db20657d47a3f86115bb4
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; 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 return TRUE; 203 } 204 XORG_FALLBACK("Unsupported composition operation = %d", op); 205} 206 207static void 208bind_blend_state(struct exa_context *exa, int op, 209 PicturePtr pSrcPicture, 210 PicturePtr pMaskPicture, 211 PicturePtr pDstPicture) 212{ 213 struct xorg_composite_blend blend_opt; 214 struct pipe_blend_state blend; 215 216 blend_for_op(&blend_opt, op, pSrcPicture, pMaskPicture, pDstPicture); 217 218 memset(&blend, 0, sizeof(struct pipe_blend_state)); 219 blend.blend_enable = 1; 220 blend.colormask |= PIPE_MASK_RGBA; 221 222 blend.rgb_src_factor = blend_opt.rgb_src; 223 blend.alpha_src_factor = blend_opt.rgb_src; 224 blend.rgb_dst_factor = blend_opt.rgb_dst; 225 blend.alpha_dst_factor = blend_opt.rgb_dst; 226 227 cso_set_blend(exa->renderer->cso, &blend); 228} 229 230 231static void 232bind_shaders(struct exa_context *exa, int op, 233 PicturePtr pSrcPicture, PicturePtr pMaskPicture) 234{ 235 unsigned vs_traits = 0, fs_traits = 0; 236 struct xorg_shader shader; 237 238 exa->has_solid_color = FALSE; 239 240 if (pSrcPicture) { 241 if (pSrcPicture->pSourcePict) { 242 if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) { 243 fs_traits |= FS_SOLID_FILL; 244 vs_traits |= VS_SOLID_FILL; 245 debug_assert(pSrcPicture->format == PICT_a8r8g8b8); 246 pixel_to_float4(pSrcPicture->pSourcePict->solidFill.color, 247 exa->solid_color); 248 exa->has_solid_color = TRUE; 249 } else { 250 debug_assert("!gradients not supported"); 251 } 252 } else { 253 fs_traits |= FS_COMPOSITE; 254 vs_traits |= VS_COMPOSITE; 255 } 256 } 257 258 if (pMaskPicture) { 259 vs_traits |= VS_MASK; 260 fs_traits |= FS_MASK; 261 if (pMaskPicture->componentAlpha) { 262 struct xorg_composite_blend blend; 263 blend_for_op(&blend, op, 264 pSrcPicture, pMaskPicture, NULL); 265 if (blend.alpha_src) { 266 fs_traits |= FS_CA_SRCALPHA; 267 } else 268 fs_traits |= FS_CA_FULL; 269 } 270 } 271 272 shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits); 273 cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs); 274 cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs); 275} 276 277static void 278bind_samplers(struct exa_context *exa, int op, 279 PicturePtr pSrcPicture, PicturePtr pMaskPicture, 280 PicturePtr pDstPicture, 281 struct exa_pixmap_priv *pSrc, 282 struct exa_pixmap_priv *pMask, 283 struct exa_pixmap_priv *pDst) 284{ 285 struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; 286 struct pipe_sampler_state src_sampler, mask_sampler; 287 288 exa->num_bound_samplers = 0; 289 290#if 0 291 if ((pSrc && (exa->pipe->is_texture_referenced(exa->pipe, pSrc->tex, 0, 0) & 292 PIPE_REFERENCED_FOR_WRITE)) || 293 (pMask && (exa->pipe->is_texture_referenced(exa->pipe, pMask->tex, 0, 0) & 294 PIPE_REFERENCED_FOR_WRITE))) 295 xorg_exa_flush(exa, PIPE_FLUSH_RENDER_CACHE, NULL); 296#endif 297 298 memset(&src_sampler, 0, sizeof(struct pipe_sampler_state)); 299 memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state)); 300 301 if (pSrcPicture && pSrc) { 302 if (exa->has_solid_color) { 303 debug_assert(!"solid color with textures"); 304 samplers[0] = NULL; 305 exa->bound_textures[0] = NULL; 306 } else { 307 unsigned src_wrap = render_repeat_to_gallium( 308 pSrcPicture->repeatType); 309 int filter; 310 311 render_filter_to_gallium(pSrcPicture->filter, &filter); 312 313 src_sampler.wrap_s = src_wrap; 314 src_sampler.wrap_t = src_wrap; 315 src_sampler.min_img_filter = filter; 316 src_sampler.mag_img_filter = filter; 317 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; 318 src_sampler.normalized_coords = 1; 319 samplers[0] = &src_sampler; 320 exa->bound_textures[0] = pSrc->tex; 321 exa->num_bound_samplers = 1; 322 } 323 } 324 325 if (pMaskPicture && pMask) { 326 unsigned mask_wrap = render_repeat_to_gallium( 327 pMaskPicture->repeatType); 328 int filter; 329 330 render_filter_to_gallium(pMaskPicture->filter, &filter); 331 332 mask_sampler.wrap_s = mask_wrap; 333 mask_sampler.wrap_t = mask_wrap; 334 mask_sampler.min_img_filter = filter; 335 mask_sampler.mag_img_filter = filter; 336 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; 337 mask_sampler.normalized_coords = 1; 338 samplers[1] = &mask_sampler; 339 exa->bound_textures[1] = pMask->tex; 340 exa->num_bound_samplers = 2; 341 } 342 343 cso_set_samplers(exa->renderer->cso, exa->num_bound_samplers, 344 (const struct pipe_sampler_state **)samplers); 345 cso_set_sampler_textures(exa->renderer->cso, exa->num_bound_samplers, 346 exa->bound_textures); 347} 348 349static void 350setup_vs_constant_buffer(struct exa_context *exa, 351 int width, int height) 352{ 353 const int param_bytes = 8 * sizeof(float); 354 float vs_consts[8] = { 355 2.f/width, 2.f/height, 1, 1, 356 -1, -1, 0, 0 357 }; 358 renderer_set_constants(exa->renderer, PIPE_SHADER_VERTEX, 359 vs_consts, param_bytes); 360} 361 362 363static void 364setup_fs_constant_buffer(struct exa_context *exa) 365{ 366 const int param_bytes = 4 * sizeof(float); 367 const float fs_consts[8] = { 368 0, 0, 0, 1, 369 }; 370 renderer_set_constants(exa->renderer, PIPE_SHADER_FRAGMENT, 371 fs_consts, param_bytes); 372} 373 374static void 375setup_constant_buffers(struct exa_context *exa, struct exa_pixmap_priv *pDst) 376{ 377 int width = pDst->tex->width[0]; 378 int height = pDst->tex->height[0]; 379 380 setup_vs_constant_buffer(exa, width, height); 381 setup_fs_constant_buffer(exa); 382} 383 384static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix) 385{ 386 if (!trans) 387 return FALSE; 388 389 matrix[0] = XFixedToDouble(trans->matrix[0][0]); 390 matrix[3] = XFixedToDouble(trans->matrix[0][1]); 391 matrix[6] = XFixedToDouble(trans->matrix[0][2]); 392 393 matrix[1] = XFixedToDouble(trans->matrix[1][0]); 394 matrix[4] = XFixedToDouble(trans->matrix[1][1]); 395 matrix[7] = XFixedToDouble(trans->matrix[1][2]); 396 397 matrix[2] = XFixedToDouble(trans->matrix[2][0]); 398 matrix[5] = XFixedToDouble(trans->matrix[2][1]); 399 matrix[8] = XFixedToDouble(trans->matrix[2][2]); 400 401 return TRUE; 402} 403 404static void 405setup_transforms(struct exa_context *exa, 406 PicturePtr pSrcPicture, PicturePtr pMaskPicture) 407{ 408 PictTransform *src_t = NULL; 409 PictTransform *mask_t = NULL; 410 411 if (pSrcPicture) 412 src_t = pSrcPicture->transform; 413 if (pMaskPicture) 414 mask_t = pMaskPicture->transform; 415 416 exa->transform.has_src = 417 matrix_from_pict_transform(src_t, exa->transform.src); 418 exa->transform.has_mask = 419 matrix_from_pict_transform(mask_t, exa->transform.mask); 420} 421 422boolean xorg_composite_bind_state(struct exa_context *exa, 423 int op, 424 PicturePtr pSrcPicture, 425 PicturePtr pMaskPicture, 426 PicturePtr pDstPicture, 427 struct exa_pixmap_priv *pSrc, 428 struct exa_pixmap_priv *pMask, 429 struct exa_pixmap_priv *pDst) 430{ 431 renderer_bind_framebuffer(exa->renderer, pDst); 432 renderer_bind_viewport(exa->renderer, pDst); 433 bind_blend_state(exa, op, pSrcPicture, pMaskPicture, pDstPicture); 434 renderer_bind_rasterizer(exa->renderer); 435 bind_shaders(exa, op, pSrcPicture, pMaskPicture); 436 bind_samplers(exa, op, pSrcPicture, pMaskPicture, 437 pDstPicture, pSrc, pMask, pDst); 438 setup_constant_buffers(exa, pDst); 439 440 setup_transforms(exa, pSrcPicture, pMaskPicture); 441 442 if (exa->num_bound_samplers == 0 ) { /* solid fill */ 443 renderer_begin_solid(exa->renderer); 444 } else { 445 renderer_begin_textures(exa->renderer, 446 exa->bound_textures, 447 exa->num_bound_samplers); 448 } 449 450 return TRUE; 451} 452 453void xorg_composite(struct exa_context *exa, 454 struct exa_pixmap_priv *dst, 455 int srcX, int srcY, int maskX, int maskY, 456 int dstX, int dstY, int width, int height) 457{ 458 if (exa->num_bound_samplers == 0 ) { /* solid fill */ 459 renderer_solid(exa->renderer, 460 dstX, dstY, dstX + width, dstY + height, 461 exa->solid_color); 462 } else { 463 int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY}; 464 float *src_matrix = NULL; 465 float *mask_matrix = NULL; 466 467 if (exa->transform.has_src) 468 src_matrix = exa->transform.src; 469 if (exa->transform.has_mask) 470 mask_matrix = exa->transform.mask; 471 472#if 0 473 renderer_draw_textures(exa->renderer, 474 pos, width, height, 475 exa->bound_textures, 476 exa->num_bound_samplers, 477 src_matrix, mask_matrix); 478#else 479 renderer_texture(exa->renderer, 480 pos, width, height, 481 exa->bound_textures, 482 exa->num_bound_samplers, 483 src_matrix, mask_matrix); 484#endif 485 } 486} 487 488boolean xorg_solid_bind_state(struct exa_context *exa, 489 struct exa_pixmap_priv *pixmap, 490 Pixel fg) 491{ 492 unsigned vs_traits, fs_traits; 493 struct xorg_shader shader; 494 495 pixel_to_float4(fg, exa->solid_color); 496 exa->has_solid_color = TRUE; 497 498#if 0 499 debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n", 500 (fg >> 24) & 0xff, (fg >> 16) & 0xff, 501 (fg >> 8) & 0xff, (fg >> 0) & 0xff, 502 exa->solid_color[0], exa->solid_color[1], 503 exa->solid_color[2], exa->solid_color[3]); 504#endif 505 506 vs_traits = VS_SOLID_FILL; 507 fs_traits = FS_SOLID_FILL; 508 509 renderer_bind_framebuffer(exa->renderer, pixmap); 510 renderer_bind_viewport(exa->renderer, pixmap); 511 renderer_bind_rasterizer(exa->renderer); 512 bind_blend_state(exa, PictOpSrc, NULL, NULL, NULL); 513 setup_constant_buffers(exa, pixmap); 514 515 shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits); 516 cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs); 517 cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs); 518 519 renderer_begin_solid(exa->renderer); 520 521 return TRUE; 522} 523 524void xorg_solid(struct exa_context *exa, 525 struct exa_pixmap_priv *pixmap, 526 int x0, int y0, int x1, int y1) 527{ 528 renderer_solid(exa->renderer, 529 x0, y0, x1, y1, exa->solid_color); 530} 531 532