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