xorg_composite.c revision d6b58a97c2f94ca54852414103c4ac2832279f2f
1#include "xorg_composite.h" 2 3#include "xorg_exa_tgsi.h" 4 5#include "cso_cache/cso_context.h" 6#include "util/u_draw_quad.h" 7 8#include "pipe/p_inlines.h" 9 10struct xorg_composite_blend { 11 int op:8; 12 13 unsigned rgb_src_factor:5; /**< PIPE_BLENDFACTOR_x */ 14 unsigned rgb_dst_factor:5; /**< PIPE_BLENDFACTOR_x */ 15 16 unsigned alpha_src_factor:5; /**< PIPE_BLENDFACTOR_x */ 17 unsigned alpha_dst_factor:5; /**< PIPE_BLENDFACTOR_x */ 18}; 19 20#define BLEND_OP_OVER 3 21static const struct xorg_composite_blend xorg_blends[] = { 22 { PictOpClear, 23 PIPE_BLENDFACTOR_CONST_COLOR, PIPE_BLENDFACTOR_CONST_ALPHA, 24 PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO }, 25 26 { PictOpSrc, 27 PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE, 28 PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO }, 29 30 { PictOpDst, 31 PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO, 32 PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE }, 33 34 { PictOpOver, 35 PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE, 36 PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA }, 37 38 { PictOpOverReverse, 39 PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE, 40 PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA }, 41}; 42 43static INLINE void 44pixel_to_float4(PictFormatPtr format, 45 CARD32 pixel, float *color) 46{ 47 CARD32 r, g, b, a; 48 49 debug_assert(format->type == PictTypeDirect); 50 51 r = (pixel >> format->direct.red) & format->direct.redMask; 52 g = (pixel >> format->direct.green) & format->direct.greenMask; 53 b = (pixel >> format->direct.blue) & format->direct.blueMask; 54 a = (pixel >> format->direct.alpha) & format->direct.alphaMask; 55 color[0] = ((float)r) / ((float)format->direct.redMask); 56 color[1] = ((float)g) / ((float)format->direct.greenMask); 57 color[2] = ((float)b) / ((float)format->direct.blueMask); 58 color[3] = ((float)a) / ((float)format->direct.alphaMask); 59} 60 61struct acceleration_info { 62 int op : 16; 63 int with_mask : 1; 64 int component_alpha : 1; 65}; 66static const struct acceleration_info accelerated_ops[] = { 67 {PictOpClear, 1, 0}, 68 {PictOpSrc, 1, 0}, 69 {PictOpDst, 1, 0}, 70 {PictOpOver, 1, 0}, 71 {PictOpOverReverse, 1, 0}, 72 {PictOpIn, 1, 0}, 73 {PictOpInReverse, 1, 0}, 74 {PictOpOut, 1, 0}, 75 {PictOpOutReverse, 1, 0}, 76 {PictOpAtop, 1, 0}, 77 {PictOpAtopReverse, 1, 0}, 78 {PictOpXor, 1, 0}, 79 {PictOpAdd, 1, 0}, 80 {PictOpSaturate, 1, 0}, 81}; 82 83static struct xorg_composite_blend 84blend_for_op(int op) 85{ 86 const int num_blends = 87 sizeof(xorg_blends)/sizeof(struct xorg_composite_blend); 88 int i; 89 90 for (i = 0; i < num_blends; ++i) { 91 if (xorg_blends[i].op == op) 92 return xorg_blends[i]; 93 } 94 return xorg_blends[BLEND_OP_OVER]; 95} 96 97static INLINE int 98render_repeat_to_gallium(int mode) 99{ 100 switch(mode) { 101 case RepeatNone: 102 return PIPE_TEX_WRAP_CLAMP; 103 case RepeatNormal: 104 return PIPE_TEX_WRAP_REPEAT; 105 case RepeatReflect: 106 return PIPE_TEX_WRAP_MIRROR_REPEAT; 107 case RepeatPad: 108 return PIPE_TEX_WRAP_CLAMP_TO_EDGE; 109 default: 110 debug_printf("Unsupported repeat mode\n"); 111 } 112 return PIPE_TEX_WRAP_REPEAT; 113} 114 115 116static INLINE void 117setup_vertex0(float vertex[2][4], float x, float y, 118 float color[4]) 119{ 120 vertex[0][0] = x; 121 vertex[0][1] = y; 122 vertex[0][2] = 0.f; /*z*/ 123 vertex[0][3] = 1.f; /*w*/ 124 125 vertex[1][0] = color[0]; /*r*/ 126 vertex[1][1] = color[1]; /*g*/ 127 vertex[1][2] = color[2]; /*b*/ 128 vertex[1][3] = color[3]; /*a*/ 129} 130 131static struct pipe_buffer * 132setup_vertex_data0(struct exa_context *ctx, 133 int srcX, int srcY, int maskX, int maskY, 134 int dstX, int dstY, int width, int height) 135{ 136 float vertices[4][2][4]; 137 138 /* 1st vertex */ 139 setup_vertex0(vertices[0], dstX, dstY, 140 ctx->solid_color); 141 /* 2nd vertex */ 142 setup_vertex0(vertices[1], dstX + width, dstY, 143 ctx->solid_color); 144 /* 3rd vertex */ 145 setup_vertex0(vertices[2], dstX + width, dstY + height, 146 ctx->solid_color); 147 /* 4th vertex */ 148 setup_vertex0(vertices[3], dstX, dstY + height, 149 ctx->solid_color); 150 151 return pipe_user_buffer_create(ctx->ctx->screen, 152 vertices, 153 sizeof(vertices)); 154} 155 156static INLINE void 157setup_vertex1(float vertex[2][4], float x, float y, float s, float t) 158{ 159 vertex[0][0] = x; 160 vertex[0][1] = y; 161 vertex[0][2] = 0.f; /*z*/ 162 vertex[0][3] = 1.f; /*w*/ 163 164 vertex[1][0] = s; /*s*/ 165 vertex[1][1] = t; /*t*/ 166 vertex[1][2] = 0.f; /*r*/ 167 vertex[1][3] = 1.f; /*q*/ 168} 169 170static struct pipe_buffer * 171setup_vertex_data1(struct exa_context *ctx, 172 int srcX, int srcY, int maskX, int maskY, 173 int dstX, int dstY, int width, int height) 174{ 175 float vertices[4][2][4]; 176 float s0, t0, s1, t1; 177 struct pipe_texture *src = ctx->bound_textures[0]; 178 179 s0 = srcX / src->width[0]; 180 s1 = srcX + width / src->width[0]; 181 t0 = srcY / src->height[0]; 182 t1 = srcY + height / src->height[0]; 183 184 /* 1st vertex */ 185 setup_vertex1(vertices[0], dstX, dstY, 186 s0, t0); 187 /* 2nd vertex */ 188 setup_vertex1(vertices[1], dstX + width, dstY, 189 s1, t0); 190 /* 3rd vertex */ 191 setup_vertex1(vertices[2], dstX + width, dstY + height, 192 s1, t1); 193 /* 4th vertex */ 194 setup_vertex1(vertices[3], dstX, dstY + height, 195 s0, t1); 196 197 return pipe_user_buffer_create(ctx->ctx->screen, 198 vertices, 199 sizeof(vertices)); 200} 201 202 203static INLINE void 204setup_vertex2(float vertex[3][4], float x, float y, 205 float s0, float t0, float s1, float t1) 206{ 207 vertex[0][0] = x; 208 vertex[0][1] = y; 209 vertex[0][2] = 0.f; /*z*/ 210 vertex[0][3] = 1.f; /*w*/ 211 212 vertex[1][0] = s0; /*s*/ 213 vertex[1][1] = t0; /*t*/ 214 vertex[1][2] = 0.f; /*r*/ 215 vertex[1][3] = 1.f; /*q*/ 216 217 vertex[2][0] = s1; /*s*/ 218 vertex[2][1] = t1; /*t*/ 219 vertex[2][2] = 0.f; /*r*/ 220 vertex[2][3] = 1.f; /*q*/ 221} 222 223static struct pipe_buffer * 224setup_vertex_data2(struct exa_context *ctx, 225 int srcX, int srcY, int maskX, int maskY, 226 int dstX, int dstY, int width, int height) 227{ 228 float vertices[4][3][4]; 229 float st0[4], st1[4]; 230 struct pipe_texture *src = ctx->bound_textures[0]; 231 struct pipe_texture *mask = ctx->bound_textures[0]; 232 233 st0[0] = srcX / src->width[0]; 234 st0[1] = srcY / src->height[0]; 235 st0[2] = srcX + width / src->width[0]; 236 st0[3] = srcY + height / src->height[0]; 237 238 st1[0] = maskX / mask->width[0]; 239 st1[1] = maskY / mask->height[0]; 240 st1[2] = maskX + width / mask->width[0]; 241 st1[3] = maskY + height / mask->height[0]; 242 243 /* 1st vertex */ 244 setup_vertex2(vertices[0], dstX, dstY, 245 st0[0], st0[1], st1[0], st1[1]); 246 /* 2nd vertex */ 247 setup_vertex2(vertices[1], dstX + width, dstY, 248 st0[2], st0[1], st1[2], st1[1]); 249 /* 3rd vertex */ 250 setup_vertex2(vertices[2], dstX + width, dstY + height, 251 st0[2], st0[3], st1[2], st1[3]); 252 /* 4th vertex */ 253 setup_vertex2(vertices[3], dstX, dstY + height, 254 st0[0], st0[3], st1[0], st1[3]); 255 256 return pipe_user_buffer_create(ctx->ctx->screen, 257 vertices, 258 sizeof(vertices)); 259} 260 261boolean xorg_composite_accelerated(int op, 262 PicturePtr pSrcPicture, 263 PicturePtr pMaskPicture, 264 PicturePtr pDstPicture) 265{ 266 unsigned i; 267 unsigned accel_ops_count = 268 sizeof(accelerated_ops)/sizeof(struct acceleration_info); 269 270 271 /*FIXME: currently accel is disabled */ 272 return FALSE; 273 274 if (pSrcPicture) { 275 /* component alpha not supported */ 276 if (pSrcPicture->componentAlpha) 277 return FALSE; 278 /* fills not supported */ 279 if (pSrcPicture->pSourcePict) 280 return FALSE; 281 } 282 283 for (i = 0; i < accel_ops_count; ++i) { 284 if (op == accelerated_ops[i].op) { 285 if (pMaskPicture && !accelerated_ops[i].with_mask) 286 return FALSE; 287 return TRUE; 288 } 289 } 290 return FALSE; 291} 292 293static void 294bind_framebuffer_state(struct exa_context *exa, PicturePtr pDstPicture, 295 struct exa_pixmap_priv *pDst) 296{ 297 unsigned i; 298 struct pipe_framebuffer_state state; 299 struct pipe_surface *surface = exa_gpu_surface(exa, pDst); 300 memset(&state, 0, sizeof(struct pipe_framebuffer_state)); 301 302 state.width = pDstPicture->pDrawable->width; 303 state.height = pDstPicture->pDrawable->height; 304 305 state.nr_cbufs = 1; 306 state.cbufs[0] = surface; 307 for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i) 308 state.cbufs[i] = 0; 309 310 /* currently we don't use depth/stencil */ 311 state.zsbuf = 0; 312 313 cso_set_framebuffer(exa->cso, &state); 314} 315 316enum AxisOrientation { 317 Y0_BOTTOM, 318 Y0_TOP 319}; 320 321static void 322set_viewport(struct exa_context *exa, int width, int height, 323 enum AxisOrientation orientation) 324{ 325 struct pipe_viewport_state viewport; 326 float y_scale = (orientation == Y0_BOTTOM) ? -2.f : 2.f; 327 328 viewport.scale[0] = width / 2.f; 329 viewport.scale[1] = height / y_scale; 330 viewport.scale[2] = 1.0; 331 viewport.scale[3] = 1.0; 332 viewport.translate[0] = width / 2.f; 333 viewport.translate[1] = height / 2.f; 334 viewport.translate[2] = 0.0; 335 viewport.translate[3] = 0.0; 336 337 cso_set_viewport(exa->cso, &viewport); 338} 339 340static void 341bind_viewport_state(struct exa_context *exa, PicturePtr pDstPicture) 342{ 343 int width = pDstPicture->pDrawable->width; 344 int height = pDstPicture->pDrawable->height; 345 346 set_viewport(exa, width, height, Y0_TOP); 347} 348 349static void 350bind_blend_state(struct exa_context *exa, int op, 351 PicturePtr pSrcPicture, PicturePtr pMaskPicture) 352{ 353 boolean component_alpha = pSrcPicture->componentAlpha; 354 struct xorg_composite_blend blend_opt; 355 struct pipe_blend_state blend; 356 357 if (component_alpha) { 358 op = PictOpOver; 359 } 360 blend_opt = blend_for_op(op); 361 362 memset(&blend, 0, sizeof(struct pipe_blend_state)); 363 blend.blend_enable = 1; 364 blend.colormask |= PIPE_MASK_R; 365 blend.colormask |= PIPE_MASK_G; 366 blend.colormask |= PIPE_MASK_B; 367 blend.colormask |= PIPE_MASK_A; 368 369 blend.rgb_src_factor = blend_opt.rgb_src_factor; 370 blend.alpha_src_factor = blend_opt.alpha_src_factor; 371 blend.rgb_dst_factor = blend_opt.rgb_dst_factor; 372 blend.alpha_dst_factor = blend_opt.alpha_dst_factor; 373 374 cso_set_blend(exa->cso, &blend); 375} 376 377static void 378bind_rasterizer_state(struct exa_context *exa) 379{ 380 struct pipe_rasterizer_state raster; 381 memset(&raster, 0, sizeof(struct pipe_rasterizer_state)); 382 raster.gl_rasterization_rules = 1; 383 cso_set_rasterizer(exa->cso, &raster); 384} 385 386static void 387bind_shaders(struct exa_context *exa, int op, 388 PicturePtr pSrcPicture, PicturePtr pMaskPicture) 389{ 390 unsigned vs_traits = 0, fs_traits = 0; 391 struct xorg_shader shader; 392 393 if (pSrcPicture) { 394 if (pSrcPicture->pSourcePict) { 395 if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) { 396 fs_traits |= FS_FILL; 397 vs_traits |= VS_FILL; 398 pixel_to_float4(pSrcPicture->pFormat, 399 pSrcPicture->pSourcePict->solidFill.color, 400 exa->solid_color); 401 } else { 402 debug_assert("!gradients not supported"); 403 } 404 } else { 405 fs_traits |= FS_COMPOSITE; 406 vs_traits |= VS_COMPOSITE; 407 } 408 } 409 410 if (pMaskPicture) { 411 vs_traits |= VS_MASK; 412 fs_traits |= FS_MASK; 413 } 414 415 shader = xorg_shaders_get(exa->shaders, vs_traits, fs_traits); 416 cso_set_vertex_shader_handle(exa->cso, shader.vs); 417 cso_set_fragment_shader_handle(exa->cso, shader.fs); 418} 419 420 421static void 422bind_samplers(struct exa_context *exa, int op, 423 PicturePtr pSrcPicture, PicturePtr pMaskPicture, 424 PicturePtr pDstPicture, 425 struct exa_pixmap_priv *pSrc, 426 struct exa_pixmap_priv *pMask, 427 struct exa_pixmap_priv *pDst) 428{ 429 struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; 430 struct pipe_sampler_state src_sampler, mask_sampler; 431 432 exa->num_bound_samplers = 0; 433 434 memset(&src_sampler, 0, sizeof(struct pipe_sampler_state)); 435 memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state)); 436 437 if (pSrcPicture && pSrc) { 438 unsigned src_wrap = render_repeat_to_gallium( 439 pSrcPicture->repeatType); 440 src_sampler.wrap_s = src_wrap; 441 src_sampler.wrap_t = src_wrap; 442 src_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST; 443 src_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST; 444 src_sampler.normalized_coords = 1; 445 samplers[0] = &src_sampler; 446 exa->bound_textures[0] = pSrc->tex; 447 ++exa->num_bound_samplers; 448 } 449 450 if (pMaskPicture && pMask) { 451 unsigned mask_wrap = render_repeat_to_gallium( 452 pMaskPicture->repeatType); 453 mask_sampler.wrap_s = mask_wrap; 454 mask_sampler.wrap_t = mask_wrap; 455 mask_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST; 456 mask_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST; 457 mask_sampler.normalized_coords = 1; 458 samplers[1] = &mask_sampler; 459 exa->bound_textures[1] = pMask->tex; 460 ++exa->num_bound_samplers; 461 } 462 463 cso_set_samplers(exa->cso, exa->num_bound_samplers, 464 (const struct pipe_sampler_state **)samplers); 465 cso_set_sampler_textures(exa->cso, exa->num_bound_samplers, 466 exa->bound_textures); 467} 468 469static void 470setup_vs_constant_buffer(struct exa_context *exa, 471 int width, int height) 472{ 473 const int param_bytes = 8 * sizeof(float); 474 float vs_consts[8] = { 475 2.f/width, 2.f/height, 1, 1, 476 -1, -1, 0, 0 477 }; 478 struct pipe_constant_buffer *cbuf = &exa->vs_const_buffer; 479 480 pipe_buffer_reference(&cbuf->buffer, NULL); 481 cbuf->buffer = pipe_buffer_create(exa->ctx->screen, 16, 482 PIPE_BUFFER_USAGE_CONSTANT, 483 param_bytes); 484 485 if (cbuf->buffer) { 486 pipe_buffer_write(exa->ctx->screen, cbuf->buffer, 487 0, param_bytes, vs_consts); 488 } 489 exa->ctx->set_constant_buffer(exa->ctx, PIPE_SHADER_VERTEX, 0, cbuf); 490} 491 492 493static void 494setup_fs_constant_buffer(struct exa_context *exa) 495{ 496 const int param_bytes = 4 * sizeof(float); 497 float fs_consts[8] = { 498 0, 0, 0, 1, 499 }; 500 struct pipe_constant_buffer *cbuf = &exa->fs_const_buffer; 501 502 pipe_buffer_reference(&cbuf->buffer, NULL); 503 cbuf->buffer = pipe_buffer_create(exa->ctx->screen, 16, 504 PIPE_BUFFER_USAGE_CONSTANT, 505 param_bytes); 506 507 if (cbuf->buffer) { 508 pipe_buffer_write(exa->ctx->screen, cbuf->buffer, 509 0, param_bytes, fs_consts); 510 } 511 exa->ctx->set_constant_buffer(exa->ctx, PIPE_SHADER_FRAGMENT, 0, cbuf); 512} 513 514static void 515setup_constant_buffers(struct exa_context *exa, PicturePtr pDstPicture) 516{ 517 int width = pDstPicture->pDrawable->width; 518 int height = pDstPicture->pDrawable->height; 519 520 setup_vs_constant_buffer(exa, width, height); 521 setup_fs_constant_buffer(exa); 522} 523 524boolean xorg_composite_bind_state(struct exa_context *exa, 525 int op, 526 PicturePtr pSrcPicture, 527 PicturePtr pMaskPicture, 528 PicturePtr pDstPicture, 529 struct exa_pixmap_priv *pSrc, 530 struct exa_pixmap_priv *pMask, 531 struct exa_pixmap_priv *pDst) 532{ 533 bind_framebuffer_state(exa, pDstPicture, pDst); 534 bind_viewport_state(exa, pDstPicture); 535 bind_blend_state(exa, op, pSrcPicture, pMaskPicture); 536 bind_rasterizer_state(exa); 537 bind_shaders(exa, op, pSrcPicture, pMaskPicture); 538 bind_samplers(exa, op, pSrcPicture, pMaskPicture, 539 pDstPicture, pSrc, pMask, pDst); 540 541 setup_constant_buffers(exa, pDstPicture); 542 543 return FALSE; 544} 545 546void xorg_composite(struct exa_context *exa, 547 struct exa_pixmap_priv *dst, 548 int srcX, int srcY, int maskX, int maskY, 549 int dstX, int dstY, int width, int height) 550{ 551 struct pipe_context *pipe = exa->ctx; 552 struct pipe_buffer *buf = 0; 553 554 if (exa->num_bound_samplers == 0 ) { /* solid fill */ 555 buf = setup_vertex_data0(exa, 556 srcX, srcY, maskX, maskY, 557 dstX, dstY, width, height); 558 } else if (exa->num_bound_samplers == 1 ) /* src */ 559 buf = setup_vertex_data1(exa, 560 srcX, srcY, maskX, maskY, 561 dstX, dstY, width, height); 562 else if (exa->num_bound_samplers == 2) /* src + mask */ 563 buf = setup_vertex_data2(exa, 564 srcX, srcY, maskX, maskY, 565 dstX, dstY, width, height); 566 else if (exa->num_bound_samplers == 3) { /* src + mask + dst */ 567 debug_assert(!"src/mask/dst not handled right now"); 568#if 0 569 buf = setup_vertex_data2(exa, 570 srcX, srcY, maskX, maskY, 571 dstX, dstY, width, height); 572#endif 573 } 574 575 if (buf) { 576 util_draw_vertex_buffer(pipe, buf, 0, 577 PIPE_PRIM_TRIANGLE_FAN, 578 4, /* verts */ 579 1 + exa->num_bound_samplers); /* attribs/vert */ 580 581 pipe_buffer_reference(&buf, NULL); 582 } 583} 584 585