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