xa_composite.c revision 568d99cc6c8eea75ce50fe29e1ea8a94fe7ff7a7
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 41struct xa_composite_blend { 42 enum xa_composite_op 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 52static 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 */ 86static unsigned 87xa_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 101static boolean 102blend_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 * our default in case something goes wrong 115 */ 116 117 *blend = xa_blends[XA_BLEND_OP_OVER]; 118 119 for (i = 0; i < num_blends; ++i) { 120 if (xa_blends[i].op == op) { 121 *blend = xa_blends[i]; 122 supported = TRUE; 123 } 124 } 125 126 if (!dst_pic->srf) 127 return supported; 128 129 if (dst_pic->srf->tex->format == PIPE_FORMAT_L8_UNORM) { 130 blend->rgb_src = xa_convert_blend_for_luminance(blend->rgb_src); 131 blend->rgb_dst = xa_convert_blend_for_luminance(blend->rgb_dst); 132 } 133 134 /* 135 * If there's no dst alpha channel, adjust the blend op so that we'll treat 136 * it as always 1. 137 */ 138 139 if (xa_format_a(dst_pic->pict_format) == 0 && blend->alpha_dst) { 140 if (blend->rgb_src == PIPE_BLENDFACTOR_DST_ALPHA) 141 blend->rgb_src = PIPE_BLENDFACTOR_ONE; 142 else if (blend->rgb_src == PIPE_BLENDFACTOR_INV_DST_ALPHA) 143 blend->rgb_src = PIPE_BLENDFACTOR_ZERO; 144 } 145 146 /* 147 * If the source alpha is being used, then we should only be in a case where 148 * the source blend factor is 0, and the source blend value is the mask 149 * channels multiplied by the source picture's alpha. 150 */ 151 if (mask_pic && mask_pic->component_alpha && 152 xa_format_rgb(mask_pic->pict_format) && 153 blend->alpha_src) { 154 if (blend->rgb_dst == PIPE_BLENDFACTOR_SRC_ALPHA) { 155 blend->rgb_dst = PIPE_BLENDFACTOR_SRC_COLOR; 156 } else if (blend->rgb_dst == PIPE_BLENDFACTOR_INV_SRC_ALPHA) { 157 blend->rgb_dst = PIPE_BLENDFACTOR_INV_SRC_COLOR; 158 } 159 } 160 161 return supported; 162} 163 164 165static INLINE int 166xa_repeat_to_gallium(int mode) 167{ 168 switch(mode) { 169 case xa_wrap_clamp_to_border: 170 return PIPE_TEX_WRAP_CLAMP_TO_BORDER; 171 case xa_wrap_repeat: 172 return PIPE_TEX_WRAP_REPEAT; 173 case xa_wrap_mirror_repeat: 174 return PIPE_TEX_WRAP_MIRROR_REPEAT; 175 case xa_wrap_clamp_to_edge: 176 return PIPE_TEX_WRAP_CLAMP_TO_EDGE; 177 default: 178 break; 179 } 180 return PIPE_TEX_WRAP_REPEAT; 181} 182 183static INLINE boolean 184xa_filter_to_gallium(int xrender_filter, int *out_filter) 185{ 186 187 switch (xrender_filter) { 188 case xa_filter_nearest: 189 *out_filter = PIPE_TEX_FILTER_NEAREST; 190 break; 191 case xa_filter_linear: 192 *out_filter = PIPE_TEX_FILTER_LINEAR; 193 break; 194 default: 195 *out_filter = PIPE_TEX_FILTER_NEAREST; 196 return FALSE; 197 } 198 return TRUE; 199} 200 201static int 202xa_is_filter_accelerated(struct xa_picture *pic) 203{ 204 int filter; 205 if (pic && !xa_filter_to_gallium(pic->filter, &filter)) 206 return 0; 207 return 1; 208} 209 210int 211xa_composite_check_accelerated(const struct xa_composite *comp) 212{ 213 struct xa_composite_blend blend; 214 struct xa_picture *src_pic = comp->src; 215 216 if (!xa_is_filter_accelerated(src_pic) || 217 !xa_is_filter_accelerated(comp->mask)) { 218 return XA_ERR_INVAL; 219 } 220 221 222 if (src_pic->src_pict) { 223 if (src_pic->src_pict->type != xa_src_pict_solid_fill) 224 return XA_ERR_INVAL; 225 } 226 227 if (blend_for_op(&blend, comp->op, comp->src, comp->mask, comp->dst)) { 228 struct xa_picture *mask = comp->mask; 229 if (mask && mask->component_alpha && 230 xa_format_rgb(mask->pict_format)) { 231 if (blend.alpha_src && blend.rgb_src != PIPE_BLENDFACTOR_ZERO) { 232 return XA_ERR_INVAL; 233 } 234 } 235 236 return XA_ERR_NONE; 237 } 238 return XA_ERR_INVAL; 239} 240 241static void 242bind_composite_blend_state(struct xa_context *ctx, 243 const struct xa_composite *comp) 244{ 245 struct xa_composite_blend blend_opt; 246 struct pipe_blend_state blend; 247 248 blend_for_op(&blend_opt, comp->op, comp->src, comp->mask, comp->dst); 249 250 memset(&blend, 0, sizeof(struct pipe_blend_state)); 251 blend.rt[0].blend_enable = 1; 252 blend.rt[0].colormask = PIPE_MASK_RGBA; 253 254 blend.rt[0].rgb_src_factor = blend_opt.rgb_src; 255 blend.rt[0].alpha_src_factor = blend_opt.rgb_src; 256 blend.rt[0].rgb_dst_factor = blend_opt.rgb_dst; 257 blend.rt[0].alpha_dst_factor = blend_opt.rgb_dst; 258 259 cso_set_blend(ctx->cso, &blend); 260} 261 262static unsigned int 263picture_format_fixups(struct xa_picture *src_pic, 264 int mask) 265{ 266 boolean set_alpha = FALSE; 267 boolean swizzle = FALSE; 268 unsigned ret = 0; 269 struct xa_surface *src = src_pic->srf; 270 enum xa_formats src_hw_format, src_pic_format; 271 enum xa_surface_type src_hw_type, src_pic_type; 272 273 if (!src) 274 return 0; 275 276 src_hw_format = xa_surface_format(src); 277 src_pic_format = src_pic->pict_format; 278 279 set_alpha = (xa_format_type_is_color(src_pic_format) && 280 xa_format_a(src_pic_format) == 0); 281 282 if (set_alpha) 283 ret |= mask ? FS_MASK_SET_ALPHA : FS_SRC_SET_ALPHA; 284 285 if (src_hw_format == src_pic_format) { 286 if (src->tex->format == PIPE_FORMAT_L8_UNORM) 287 return ((mask) ? FS_MASK_LUMINANCE : FS_SRC_LUMINANCE); 288 289 return ret; 290 } 291 292 src_hw_type = xa_format_type(src_hw_format); 293 src_pic_type = xa_format_type(src_pic_format); 294 295 swizzle = ((src_hw_type == xa_type_argb && 296 src_pic_type == xa_type_abgr) || 297 ((src_hw_type == xa_type_abgr && 298 src_pic_type == xa_type_argb))); 299 300 if (!swizzle && (src_hw_type != src_pic_type)) 301 return ret; 302 303 if (swizzle) 304 ret |= mask ? FS_MASK_SWIZZLE_RGB : FS_SRC_SWIZZLE_RGB; 305 306 return ret; 307} 308 309static void 310bind_shaders(struct xa_context *ctx, const struct xa_composite *comp) 311{ 312 unsigned vs_traits = 0, fs_traits = 0; 313 struct xa_shader shader; 314 struct xa_picture *src_pic = comp->src; 315 struct xa_picture *mask_pic = comp->mask; 316 317 ctx->has_solid_color = FALSE; 318 319 if (src_pic) { 320 if (src_pic->wrap == xa_wrap_clamp_to_border && src_pic->has_transform) 321 fs_traits |= FS_SRC_REPEAT_NONE; 322 323 if (src_pic->src_pict) { 324 if (src_pic->src_pict->type == xa_src_pict_solid_fill) { 325 fs_traits |= FS_SOLID_FILL; 326 vs_traits |= VS_SOLID_FILL; 327 xa_pixel_to_float4(src_pic->src_pict->solid_fill.color, 328 ctx->solid_color); 329 ctx->has_solid_color = TRUE; 330 } 331 } else { 332 fs_traits |= FS_COMPOSITE; 333 vs_traits |= VS_COMPOSITE; 334 } 335 336 fs_traits |= picture_format_fixups(src_pic, 0); 337 } 338 339 if (mask_pic) { 340 vs_traits |= VS_MASK; 341 fs_traits |= FS_MASK; 342 if (mask_pic->wrap == xa_wrap_clamp_to_border && 343 mask_pic->has_transform) 344 fs_traits |= FS_MASK_REPEAT_NONE; 345 346 if (mask_pic->component_alpha) { 347 struct xa_composite_blend blend; 348 blend_for_op(&blend, comp->op, src_pic, mask_pic, NULL); 349 if (blend.alpha_src) { 350 fs_traits |= FS_CA_SRCALPHA; 351 } else 352 fs_traits |= FS_CA_FULL; 353 } 354 355 fs_traits |= picture_format_fixups(mask_pic, 1); 356 } 357 358 if (ctx->dst->srf->format == PIPE_FORMAT_L8_UNORM) 359 fs_traits |= FS_DST_LUMINANCE; 360 361 shader = xa_shaders_get(ctx->shaders, vs_traits, fs_traits); 362 cso_set_vertex_shader_handle(ctx->cso, shader.vs); 363 cso_set_fragment_shader_handle(ctx->cso, shader.fs); 364} 365 366static void 367bind_samplers(struct xa_context *ctx, 368 const struct xa_composite *comp) 369{ 370 struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; 371 struct pipe_sampler_state src_sampler, mask_sampler; 372 struct pipe_sampler_view view_templ; 373 struct pipe_sampler_view *src_view; 374 struct pipe_context *pipe = ctx->pipe; 375 struct xa_picture *src_pic = comp->src; 376 struct xa_picture *mask_pic = comp->mask; 377 378 ctx->num_bound_samplers = 0; 379 380 memset(&src_sampler, 0, sizeof(struct pipe_sampler_state)); 381 memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state)); 382 383 if (src_pic) { 384 if (ctx->has_solid_color) { 385 samplers[0] = NULL; 386 pipe_sampler_view_reference(&ctx->bound_sampler_views[0], NULL); 387 } else { 388 unsigned src_wrap = xa_repeat_to_gallium(src_pic->wrap); 389 int filter; 390 391 (void) xa_filter_to_gallium(src_pic->filter, &filter); 392 393 src_sampler.wrap_s = src_wrap; 394 src_sampler.wrap_t = src_wrap; 395 src_sampler.min_img_filter = filter; 396 src_sampler.mag_img_filter = filter; 397 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; 398 src_sampler.normalized_coords = 1; 399 samplers[0] = &src_sampler; 400 ctx->num_bound_samplers = 1; 401 u_sampler_view_default_template(&view_templ, 402 src_pic->srf->tex, 403 src_pic->srf->tex->format); 404 src_view = pipe->create_sampler_view(pipe, src_pic->srf->tex, 405 &view_templ); 406 pipe_sampler_view_reference(&ctx->bound_sampler_views[0], NULL); 407 ctx->bound_sampler_views[0] = src_view; 408 } 409 } 410 411 if (mask_pic) { 412 unsigned mask_wrap = xa_repeat_to_gallium(mask_pic->wrap); 413 int filter; 414 415 (void) xa_filter_to_gallium(mask_pic->filter, &filter); 416 417 mask_sampler.wrap_s = mask_wrap; 418 mask_sampler.wrap_t = mask_wrap; 419 mask_sampler.min_img_filter = filter; 420 mask_sampler.mag_img_filter = filter; 421 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; 422 mask_sampler.normalized_coords = 1; 423 samplers[1] = &mask_sampler; 424 ctx->num_bound_samplers = 2; 425 u_sampler_view_default_template(&view_templ, 426 mask_pic->srf->tex, 427 mask_pic->srf->tex->format); 428 src_view = pipe->create_sampler_view(pipe, mask_pic->srf->tex, 429 &view_templ); 430 pipe_sampler_view_reference(&ctx->bound_sampler_views[1], NULL); 431 ctx->bound_sampler_views[1] = src_view; 432 } 433 434 cso_set_samplers(ctx->cso, ctx->num_bound_samplers, 435 (const struct pipe_sampler_state **)samplers); 436 cso_set_fragment_sampler_views(ctx->cso, ctx->num_bound_samplers, 437 ctx->bound_sampler_views); 438} 439 440int 441xa_composite_prepare(struct xa_context *ctx, 442 const struct xa_composite *comp) 443{ 444 struct xa_surface *dst_srf = comp->dst->srf; 445 int ret; 446 447 ret = xa_surface_psurf_create(ctx, dst_srf); 448 if (ret != XA_ERR_NONE) 449 return ret; 450 451 ctx->dst = dst_srf; 452 renderer_bind_destination(ctx, dst_srf->srf, 453 dst_srf->srf->width, 454 dst_srf->srf->height); 455 456 bind_composite_blend_state(ctx, comp); 457 bind_shaders(ctx, comp); 458 bind_samplers(ctx, comp); 459 460 if (ctx->num_bound_samplers == 0 ) { /* solid fill */ 461 renderer_begin_solid(ctx); 462 } else { 463 renderer_begin_textures(ctx); 464 ctx->comp = comp; 465 } 466 467 xa_surface_psurf_destroy(dst_srf); 468 return XA_ERR_NONE; 469} 470 471void xa_composite_rect(struct xa_context *ctx, 472 int srcX, int srcY, int maskX, int maskY, 473 int dstX, int dstY, int width, int height) 474{ 475 if (ctx->num_bound_samplers == 0 ) { /* solid fill */ 476 renderer_solid(ctx, dstX, dstY, dstX + width, dstY + height, 477 ctx->solid_color); 478 } else { 479 const struct xa_composite *comp = ctx->comp; 480 int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY}; 481 const float *src_matrix = NULL; 482 const float *mask_matrix = NULL; 483 484 if (comp->src->has_transform) 485 src_matrix = comp->src->transform; 486 if (comp->mask && comp->mask->has_transform) 487 mask_matrix = comp->mask->transform; 488 489 renderer_texture(ctx, pos, width, height, 490 src_matrix, mask_matrix); 491 } 492} 493 494void 495xa_composite_done(struct xa_context *ctx) 496{ 497 renderer_draw_flush(ctx); 498 ctx->pipe->flush(ctx->pipe, &ctx->last_fence); 499 500 ctx->comp = NULL; 501 ctx->has_solid_color = FALSE; 502 ctx->num_bound_samplers = 0; 503} 504 505static const struct xa_composite_allocation a = { 506 .xa_composite_size = sizeof(struct xa_composite), 507 .xa_picture_size = sizeof(struct xa_picture), 508 .xa_source_pict_size = sizeof(union xa_source_pict), 509}; 510 511const struct xa_composite_allocation * 512xa_composite_allocation(void) 513{ 514 return &a; 515} 516