1 /********************************************************** 2 * Copyright 2009-2011 VMware, Inc. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 ********************************************************* 25 * Authors: 26 * Zack Rusin <zackr-at-vmware-dot-com> 27 * Thomas Hellstrom <thellstrom-at-vmware-dot-com> 28 */ 29 30 #include "xa_composite.h" 31 #include "xa_context.h" 32 #include "xa_priv.h" 33 #include "cso_cache/cso_context.h" 34 #include "util/u_sampler.h" 35 #include "util/u_inlines.h" 36 37 38 /*XXX also in Xrender.h but the including it here breaks compilition */ 39 #define XFixedToDouble(f) (((double) (f)) / 65536.) 40 41 struct xa_composite_blend { 42 unsigned op : 8; 43 44 unsigned alpha_dst : 4; 45 unsigned alpha_src : 4; 46 47 unsigned rgb_src : 8; /**< PIPE_BLENDFACTOR_x */ 48 unsigned rgb_dst : 8; /**< PIPE_BLENDFACTOR_x */ 49 }; 50 51 #define XA_BLEND_OP_OVER 3 52 static const struct xa_composite_blend xa_blends[] = { 53 { xa_op_clear, 54 0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO}, 55 { xa_op_src, 56 0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ZERO}, 57 { xa_op_dst, 58 0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ONE}, 59 { xa_op_over, 60 0, 1, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, 61 { xa_op_over_reverse, 62 1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE}, 63 { xa_op_in, 64 1, 0, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_ZERO}, 65 { xa_op_in_reverse, 66 0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_SRC_ALPHA}, 67 { xa_op_out, 68 1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ZERO}, 69 { xa_op_out_reverse, 70 0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, 71 { xa_op_atop, 72 1, 1, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, 73 { xa_op_atop_reverse, 74 1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_SRC_ALPHA}, 75 { xa_op_xor, 76 1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, 77 { xa_op_add, 78 0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE}, 79 }; 80 81 82 /* 83 * The alpha value stored in a luminance texture is read by the 84 * hardware as color. 85 */ 86 static unsigned 87 xa_convert_blend_for_luminance(unsigned factor) 88 { 89 switch(factor) { 90 case PIPE_BLENDFACTOR_DST_ALPHA: 91 return PIPE_BLENDFACTOR_DST_COLOR; 92 case PIPE_BLENDFACTOR_INV_DST_ALPHA: 93 return PIPE_BLENDFACTOR_INV_DST_COLOR; 94 default: 95 break; 96 } 97 return factor; 98 } 99 100 101 static boolean 102 blend_for_op(struct xa_composite_blend *blend, 103 enum xa_composite_op op, 104 struct xa_picture *src_pic, 105 struct xa_picture *mask_pic, 106 struct xa_picture *dst_pic) 107 { 108 const int num_blends = 109 sizeof(xa_blends)/sizeof(struct xa_composite_blend); 110 int i; 111 boolean supported = FALSE; 112 113 /* 114 * Temporarily disable component alpha since it appears buggy. 115 */ 116 if (mask_pic && mask_pic->component_alpha) 117 return FALSE; 118 119 /* 120 * our default in case something goes wrong 121 */ 122 *blend = xa_blends[XA_BLEND_OP_OVER]; 123 124 for (i = 0; i < num_blends; ++i) { 125 if (xa_blends[i].op == op) { 126 *blend = xa_blends[i]; 127 supported = TRUE; 128 } 129 } 130 131 if (!dst_pic->srf) 132 return supported; 133 134 if (dst_pic->srf->tex->format == PIPE_FORMAT_L8_UNORM) { 135 blend->rgb_src = xa_convert_blend_for_luminance(blend->rgb_src); 136 blend->rgb_dst = xa_convert_blend_for_luminance(blend->rgb_dst); 137 } 138 139 /* 140 * If there's no dst alpha channel, adjust the blend op so that we'll treat 141 * it as always 1. 142 */ 143 144 if (xa_format_a(dst_pic->pict_format) == 0 && blend->alpha_dst) { 145 if (blend->rgb_src == PIPE_BLENDFACTOR_DST_ALPHA) 146 blend->rgb_src = PIPE_BLENDFACTOR_ONE; 147 else if (blend->rgb_src == PIPE_BLENDFACTOR_INV_DST_ALPHA) 148 blend->rgb_src = PIPE_BLENDFACTOR_ZERO; 149 } 150 151 /* 152 * If the source alpha is being used, then we should only be in a case where 153 * the source blend factor is 0, and the source blend value is the mask 154 * channels multiplied by the source picture's alpha. 155 */ 156 if (mask_pic && mask_pic->component_alpha && 157 xa_format_rgb(mask_pic->pict_format) && 158 blend->alpha_src) { 159 if (blend->rgb_dst == PIPE_BLENDFACTOR_SRC_ALPHA) { 160 blend->rgb_dst = PIPE_BLENDFACTOR_SRC_COLOR; 161 } else if (blend->rgb_dst == PIPE_BLENDFACTOR_INV_SRC_ALPHA) { 162 blend->rgb_dst = PIPE_BLENDFACTOR_INV_SRC_COLOR; 163 } 164 } 165 166 return supported; 167 } 168 169 170 static INLINE int 171 xa_repeat_to_gallium(int mode) 172 { 173 switch(mode) { 174 case xa_wrap_clamp_to_border: 175 return PIPE_TEX_WRAP_CLAMP_TO_BORDER; 176 case xa_wrap_repeat: 177 return PIPE_TEX_WRAP_REPEAT; 178 case xa_wrap_mirror_repeat: 179 return PIPE_TEX_WRAP_MIRROR_REPEAT; 180 case xa_wrap_clamp_to_edge: 181 return PIPE_TEX_WRAP_CLAMP_TO_EDGE; 182 default: 183 break; 184 } 185 return PIPE_TEX_WRAP_REPEAT; 186 } 187 188 static INLINE boolean 189 xa_filter_to_gallium(int xrender_filter, int *out_filter) 190 { 191 192 switch (xrender_filter) { 193 case xa_filter_nearest: 194 *out_filter = PIPE_TEX_FILTER_NEAREST; 195 break; 196 case xa_filter_linear: 197 *out_filter = PIPE_TEX_FILTER_LINEAR; 198 break; 199 default: 200 *out_filter = PIPE_TEX_FILTER_NEAREST; 201 return FALSE; 202 } 203 return TRUE; 204 } 205 206 static int 207 xa_is_filter_accelerated(struct xa_picture *pic) 208 { 209 int filter; 210 if (pic && !xa_filter_to_gallium(pic->filter, &filter)) 211 return 0; 212 return 1; 213 } 214 215 XA_EXPORT int 216 xa_composite_check_accelerated(const struct xa_composite *comp) 217 { 218 struct xa_composite_blend blend; 219 struct xa_picture *src_pic = comp->src; 220 221 if (!xa_is_filter_accelerated(src_pic) || 222 !xa_is_filter_accelerated(comp->mask)) { 223 return -XA_ERR_INVAL; 224 } 225 226 227 if (src_pic->src_pict) { 228 if (src_pic->src_pict->type != xa_src_pict_solid_fill) 229 return -XA_ERR_INVAL; 230 231 /* 232 * Currently we don't support solid fill with a mask. 233 * We can easily do that, but that would require shader, 234 * sampler view setup and vertex setup modification. 235 */ 236 if (comp->mask) 237 return -XA_ERR_INVAL; 238 } 239 240 if (blend_for_op(&blend, comp->op, comp->src, comp->mask, comp->dst)) { 241 struct xa_picture *mask = comp->mask; 242 if (mask && mask->component_alpha && 243 xa_format_rgb(mask->pict_format)) { 244 if (blend.alpha_src && blend.rgb_src != PIPE_BLENDFACTOR_ZERO) { 245 return -XA_ERR_INVAL; 246 } 247 } 248 249 return XA_ERR_NONE; 250 } 251 return -XA_ERR_INVAL; 252 } 253 254 static int 255 bind_composite_blend_state(struct xa_context *ctx, 256 const struct xa_composite *comp) 257 { 258 struct xa_composite_blend blend_opt; 259 struct pipe_blend_state blend; 260 261 if (!blend_for_op(&blend_opt, comp->op, comp->src, comp->mask, comp->dst)) 262 return -XA_ERR_INVAL; 263 264 memset(&blend, 0, sizeof(struct pipe_blend_state)); 265 blend.rt[0].blend_enable = 1; 266 blend.rt[0].colormask = PIPE_MASK_RGBA; 267 268 blend.rt[0].rgb_src_factor = blend_opt.rgb_src; 269 blend.rt[0].alpha_src_factor = blend_opt.rgb_src; 270 blend.rt[0].rgb_dst_factor = blend_opt.rgb_dst; 271 blend.rt[0].alpha_dst_factor = blend_opt.rgb_dst; 272 273 cso_set_blend(ctx->cso, &blend); 274 return XA_ERR_NONE; 275 } 276 277 static unsigned int 278 picture_format_fixups(struct xa_picture *src_pic, 279 int mask) 280 { 281 boolean set_alpha = FALSE; 282 boolean swizzle = FALSE; 283 unsigned ret = 0; 284 struct xa_surface *src = src_pic->srf; 285 enum xa_formats src_hw_format, src_pic_format; 286 enum xa_surface_type src_hw_type, src_pic_type; 287 288 if (!src) 289 return 0; 290 291 src_hw_format = xa_surface_format(src); 292 src_pic_format = src_pic->pict_format; 293 294 set_alpha = (xa_format_type_is_color(src_pic_format) && 295 xa_format_a(src_pic_format) == 0); 296 297 if (set_alpha) 298 ret |= mask ? FS_MASK_SET_ALPHA : FS_SRC_SET_ALPHA; 299 300 if (src_hw_format == src_pic_format) { 301 if (src->tex->format == PIPE_FORMAT_L8_UNORM) 302 return ((mask) ? FS_MASK_LUMINANCE : FS_SRC_LUMINANCE); 303 304 return ret; 305 } 306 307 src_hw_type = xa_format_type(src_hw_format); 308 src_pic_type = xa_format_type(src_pic_format); 309 310 swizzle = ((src_hw_type == xa_type_argb && 311 src_pic_type == xa_type_abgr) || 312 ((src_hw_type == xa_type_abgr && 313 src_pic_type == xa_type_argb))); 314 315 if (!swizzle && (src_hw_type != src_pic_type)) 316 return ret; 317 318 if (swizzle) 319 ret |= mask ? FS_MASK_SWIZZLE_RGB : FS_SRC_SWIZZLE_RGB; 320 321 return ret; 322 } 323 324 static int 325 bind_shaders(struct xa_context *ctx, const struct xa_composite *comp) 326 { 327 unsigned vs_traits = 0, fs_traits = 0; 328 struct xa_shader shader; 329 struct xa_picture *src_pic = comp->src; 330 struct xa_picture *mask_pic = comp->mask; 331 332 ctx->has_solid_color = FALSE; 333 334 if (src_pic) { 335 if (src_pic->wrap == xa_wrap_clamp_to_border && src_pic->has_transform) 336 fs_traits |= FS_SRC_REPEAT_NONE; 337 338 if (src_pic->src_pict) { 339 if (src_pic->src_pict->type == xa_src_pict_solid_fill) { 340 fs_traits |= FS_SOLID_FILL | FS_FILL; 341 vs_traits |= VS_SOLID_FILL; 342 xa_pixel_to_float4(src_pic->src_pict->solid_fill.color, 343 ctx->solid_color); 344 ctx->has_solid_color = TRUE; 345 } 346 } else { 347 fs_traits |= FS_COMPOSITE; 348 vs_traits |= VS_COMPOSITE; 349 } 350 351 fs_traits |= picture_format_fixups(src_pic, 0); 352 } 353 354 if (mask_pic) { 355 vs_traits |= VS_MASK; 356 fs_traits |= FS_MASK; 357 if (mask_pic->wrap == xa_wrap_clamp_to_border && 358 mask_pic->has_transform) 359 fs_traits |= FS_MASK_REPEAT_NONE; 360 361 if (mask_pic->component_alpha) { 362 struct xa_composite_blend blend; 363 if (!blend_for_op(&blend, comp->op, src_pic, mask_pic, NULL)) 364 return -XA_ERR_INVAL; 365 366 if (blend.alpha_src) { 367 fs_traits |= FS_CA_SRCALPHA; 368 } else 369 fs_traits |= FS_CA_FULL; 370 } 371 372 fs_traits |= picture_format_fixups(mask_pic, 1); 373 } 374 375 if (ctx->srf->format == PIPE_FORMAT_L8_UNORM) 376 fs_traits |= FS_DST_LUMINANCE; 377 378 shader = xa_shaders_get(ctx->shaders, vs_traits, fs_traits); 379 cso_set_vertex_shader_handle(ctx->cso, shader.vs); 380 cso_set_fragment_shader_handle(ctx->cso, shader.fs); 381 return XA_ERR_NONE; 382 } 383 384 static void 385 bind_samplers(struct xa_context *ctx, 386 const struct xa_composite *comp) 387 { 388 struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; 389 struct pipe_sampler_state src_sampler, mask_sampler; 390 struct pipe_sampler_view view_templ; 391 struct pipe_sampler_view *src_view; 392 struct pipe_context *pipe = ctx->pipe; 393 struct xa_picture *src_pic = comp->src; 394 struct xa_picture *mask_pic = comp->mask; 395 396 ctx->num_bound_samplers = 0; 397 398 memset(&src_sampler, 0, sizeof(struct pipe_sampler_state)); 399 memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state)); 400 401 if (src_pic) { 402 if (ctx->has_solid_color) { 403 samplers[0] = NULL; 404 pipe_sampler_view_reference(&ctx->bound_sampler_views[0], NULL); 405 } else { 406 unsigned src_wrap = xa_repeat_to_gallium(src_pic->wrap); 407 int filter; 408 409 (void) xa_filter_to_gallium(src_pic->filter, &filter); 410 411 src_sampler.wrap_s = src_wrap; 412 src_sampler.wrap_t = src_wrap; 413 src_sampler.min_img_filter = filter; 414 src_sampler.mag_img_filter = filter; 415 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; 416 src_sampler.normalized_coords = 1; 417 samplers[0] = &src_sampler; 418 ctx->num_bound_samplers = 1; 419 u_sampler_view_default_template(&view_templ, 420 src_pic->srf->tex, 421 src_pic->srf->tex->format); 422 src_view = pipe->create_sampler_view(pipe, src_pic->srf->tex, 423 &view_templ); 424 pipe_sampler_view_reference(&ctx->bound_sampler_views[0], NULL); 425 ctx->bound_sampler_views[0] = src_view; 426 } 427 } 428 429 if (mask_pic) { 430 unsigned mask_wrap = xa_repeat_to_gallium(mask_pic->wrap); 431 int filter; 432 433 (void) xa_filter_to_gallium(mask_pic->filter, &filter); 434 435 mask_sampler.wrap_s = mask_wrap; 436 mask_sampler.wrap_t = mask_wrap; 437 mask_sampler.min_img_filter = filter; 438 mask_sampler.mag_img_filter = filter; 439 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; 440 mask_sampler.normalized_coords = 1; 441 samplers[1] = &mask_sampler; 442 ctx->num_bound_samplers = 2; 443 u_sampler_view_default_template(&view_templ, 444 mask_pic->srf->tex, 445 mask_pic->srf->tex->format); 446 src_view = pipe->create_sampler_view(pipe, mask_pic->srf->tex, 447 &view_templ); 448 pipe_sampler_view_reference(&ctx->bound_sampler_views[1], NULL); 449 ctx->bound_sampler_views[1] = src_view; 450 451 452 /* 453 * If src is a solid color, we have no src view, so set up a 454 * dummy one that will not be used anyway. 455 */ 456 if (ctx->bound_sampler_views[0] == NULL) 457 pipe_sampler_view_reference(&ctx->bound_sampler_views[0], 458 src_view); 459 460 } 461 462 cso_set_samplers(ctx->cso, PIPE_SHADER_FRAGMENT, ctx->num_bound_samplers, 463 (const struct pipe_sampler_state **)samplers); 464 cso_set_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT, ctx->num_bound_samplers, 465 ctx->bound_sampler_views); 466 } 467 468 XA_EXPORT int 469 xa_composite_prepare(struct xa_context *ctx, 470 const struct xa_composite *comp) 471 { 472 struct xa_surface *dst_srf = comp->dst->srf; 473 int ret; 474 475 ret = xa_ctx_srf_create(ctx, dst_srf); 476 if (ret != XA_ERR_NONE) 477 return ret; 478 479 ctx->dst = dst_srf; 480 renderer_bind_destination(ctx, ctx->srf, ctx->srf->width, 481 ctx->srf->height); 482 483 ret = bind_composite_blend_state(ctx, comp); 484 if (ret != XA_ERR_NONE) 485 return ret; 486 ret = bind_shaders(ctx, comp); 487 if (ret != XA_ERR_NONE) 488 return ret; 489 bind_samplers(ctx, comp); 490 491 if (ctx->num_bound_samplers == 0 ) { /* solid fill */ 492 renderer_begin_solid(ctx); 493 } else { 494 renderer_begin_textures(ctx); 495 ctx->comp = comp; 496 } 497 498 xa_ctx_srf_destroy(ctx); 499 return XA_ERR_NONE; 500 } 501 502 XA_EXPORT void 503 xa_composite_rect(struct xa_context *ctx, 504 int srcX, int srcY, int maskX, int maskY, 505 int dstX, int dstY, int width, int height) 506 { 507 if (ctx->num_bound_samplers == 0 ) { /* solid fill */ 508 renderer_solid(ctx, dstX, dstY, dstX + width, dstY + height, 509 ctx->solid_color); 510 } else { 511 const struct xa_composite *comp = ctx->comp; 512 int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY}; 513 const float *src_matrix = NULL; 514 const float *mask_matrix = NULL; 515 516 if (comp->src->has_transform) 517 src_matrix = comp->src->transform; 518 if (comp->mask && comp->mask->has_transform) 519 mask_matrix = comp->mask->transform; 520 521 renderer_texture(ctx, pos, width, height, 522 src_matrix, mask_matrix); 523 } 524 } 525 526 XA_EXPORT void 527 xa_composite_done(struct xa_context *ctx) 528 { 529 renderer_draw_flush(ctx); 530 ctx->pipe->flush(ctx->pipe, &ctx->last_fence); 531 532 ctx->comp = NULL; 533 ctx->has_solid_color = FALSE; 534 xa_ctx_sampler_views_destroy(ctx); 535 } 536 537 static const struct xa_composite_allocation a = { 538 .xa_composite_size = sizeof(struct xa_composite), 539 .xa_picture_size = sizeof(struct xa_picture), 540 .xa_source_pict_size = sizeof(union xa_source_pict), 541 }; 542 543 XA_EXPORT const struct xa_composite_allocation * 544 xa_composite_allocation(void) 545 { 546 return &a; 547 } 548