1 /**********************************************************
2 * Copyright 2009-2011 VMware, Inc. All rights reserved.
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:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
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
24 *********************************************************
26 * Zack Rusin <zackr-at-vmware-dot-com>
27 * Thomas Hellstrom <thellstrom-at-vmware-dot-com>
30 #include "xa_composite.h"
31 #include "xa_context.h"
33 #include "cso_cache/cso_context.h"
34 #include "util/u_sampler.h"
35 #include "util/u_inlines.h"
38 /*XXX also in Xrender.h but the including it here breaks compilition */
39 #define XFixedToDouble(f) (((double) (f)) / 65536.)
41 struct xa_composite_blend
{
42 enum xa_composite_op op
: 8;
44 unsigned alpha_dst
: 4;
45 unsigned alpha_src
: 4;
47 unsigned rgb_src
: 8; /**< PIPE_BLENDFACTOR_x */
48 unsigned rgb_dst
: 8; /**< PIPE_BLENDFACTOR_x */
51 #define XA_BLEND_OP_OVER 3
52 static const struct xa_composite_blend xa_blends
[] = {
54 0, 0, PIPE_BLENDFACTOR_ZERO
, PIPE_BLENDFACTOR_ZERO
},
56 0, 0, PIPE_BLENDFACTOR_ONE
, PIPE_BLENDFACTOR_ZERO
},
58 0, 0, PIPE_BLENDFACTOR_ZERO
, PIPE_BLENDFACTOR_ONE
},
60 0, 1, PIPE_BLENDFACTOR_ONE
, PIPE_BLENDFACTOR_INV_SRC_ALPHA
},
62 1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA
, PIPE_BLENDFACTOR_ONE
},
64 1, 0, PIPE_BLENDFACTOR_DST_ALPHA
, PIPE_BLENDFACTOR_ZERO
},
66 0, 1, PIPE_BLENDFACTOR_ZERO
, PIPE_BLENDFACTOR_SRC_ALPHA
},
68 1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA
, PIPE_BLENDFACTOR_ZERO
},
70 0, 1, PIPE_BLENDFACTOR_ZERO
, PIPE_BLENDFACTOR_INV_SRC_ALPHA
},
72 1, 1, PIPE_BLENDFACTOR_DST_ALPHA
, PIPE_BLENDFACTOR_INV_SRC_ALPHA
},
74 1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA
, PIPE_BLENDFACTOR_SRC_ALPHA
},
76 1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA
, PIPE_BLENDFACTOR_INV_SRC_ALPHA
},
78 0, 0, PIPE_BLENDFACTOR_ONE
, PIPE_BLENDFACTOR_ONE
},
83 blend_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
)
89 const int num_blends
=
90 sizeof(xa_blends
)/sizeof(struct xa_composite_blend
);
92 boolean supported
= FALSE
;
95 * our default in case something goes wrong
98 *blend
= xa_blends
[XA_BLEND_OP_OVER
];
100 for (i
= 0; i
< num_blends
; ++i
) {
101 if (xa_blends
[i
].op
== op
) {
102 *blend
= xa_blends
[i
];
109 * If there's no dst alpha channel, adjust the blend op so that we'll treat
114 xa_format_a(xa_surface_format(dst_pic
->srf
)) == 0 &&
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
;
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.
127 if (mask_pic
&& mask_pic
->component_alpha
&&
128 xa_format_rgb(xa_surface_format(mask_pic
->srf
)) &&
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
;
142 xa_repeat_to_gallium(int mode
)
145 case xa_wrap_clamp_to_border
:
146 return PIPE_TEX_WRAP_CLAMP_TO_BORDER
;
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
;
156 return PIPE_TEX_WRAP_REPEAT
;
159 static INLINE boolean
160 xa_filter_to_gallium(int xrender_filter
, int *out_filter
)
163 switch (xrender_filter
) {
164 case xa_filter_nearest
:
165 *out_filter
= PIPE_TEX_FILTER_NEAREST
;
167 case xa_filter_linear
:
168 *out_filter
= PIPE_TEX_FILTER_LINEAR
;
171 *out_filter
= PIPE_TEX_FILTER_NEAREST
;
178 xa_is_filter_accelerated(struct xa_picture
*pic
)
181 if (pic
&& !xa_filter_to_gallium(pic
->filter
, &filter
))
187 xa_composite_is_accelerated(const struct xa_composite
*comp
)
189 struct xa_composite_blend blend
;
190 struct xa_picture
*src_pic
= comp
->src
;
192 if (!xa_is_filter_accelerated(src_pic
) ||
193 !xa_is_filter_accelerated(comp
->mask
)) {
198 if (src_pic
->src_pict
) {
199 if (src_pic
->src_pict
->type
!= xa_src_pict_solid_fill
)
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(xa_surface_format(mask
->srf
))) {
207 if (blend
.alpha_src
&& blend
.rgb_src
!= PIPE_BLENDFACTOR_ZERO
) {
218 bind_composite_blend_state(struct xa_context
*ctx
,
219 const struct xa_composite
*comp
)
221 struct xa_composite_blend blend_opt
;
222 struct pipe_blend_state blend
;
224 blend_for_op(&blend_opt
, comp
->op
, comp
->src
, comp
->mask
, comp
->dst
);
226 memset(&blend
, 0, sizeof(struct pipe_blend_state
));
227 blend
.rt
[0].blend_enable
= 1;
228 blend
.rt
[0].colormask
= PIPE_MASK_RGBA
;
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
;
235 cso_set_blend(ctx
->cso
, &blend
);
239 picture_format_fixups(struct xa_picture
*src_pic
,
240 struct xa_picture
*dst_pic
,
243 boolean set_alpha
= FALSE
;
244 boolean swizzle
= FALSE
;
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
;
250 src_hw_format
= xa_surface_format(src
);
251 src_pic_format
= src_pic
->pict_format
;
253 if (src_hw_format
== src_pic_format
) {
254 if (src_pic
->pict_format
== xa_format_a8
) {
256 return FS_MASK_LUMINANCE
;
257 else if (dst_pic
->pict_format
!= xa_format_a8
) {
260 * if both dst and src are luminance then
261 * we don't want to swizzle the alpha (X) of the
262 * source into W component of the dst because
263 * it will break our destination
265 return FS_SRC_LUMINANCE
;
271 src_hw_type
= xa_format_type(src_hw_format
);
272 src_pic_type
= xa_format_type(src_pic_format
);
274 swizzle
= ((src_hw_type
== xa_type_argb
&&
275 src_pic_type
== xa_type_abgr
) ||
276 ((src_hw_type
== xa_type_abgr
&&
277 src_pic_type
== xa_type_argb
)));
279 if (!swizzle
&& (src_hw_type
!= src_pic_type
))
282 set_alpha
= (xa_format_type_is_color(src_hw_type
) &&
283 xa_format_a(src_hw_type
) == 0);
286 ret
|= mask
? FS_MASK_SET_ALPHA
: FS_SRC_SET_ALPHA
;
288 ret
|= mask
? FS_MASK_SWIZZLE_RGB
: FS_SRC_SWIZZLE_RGB
;
294 bind_shaders(struct xa_context
*ctx
, const struct xa_composite
*comp
)
296 unsigned vs_traits
= 0, fs_traits
= 0;
297 struct xa_shader shader
;
298 struct xa_picture
*src_pic
= comp
->src
;
299 struct xa_picture
*mask_pic
= comp
->mask
;
300 struct xa_picture
*dst_pic
= comp
->dst
;
302 ctx
->has_solid_color
= FALSE
;
305 if (src_pic
->wrap
== xa_wrap_clamp_to_border
&& src_pic
->has_transform
)
306 fs_traits
|= FS_SRC_REPEAT_NONE
;
308 if (src_pic
->src_pict
) {
309 if (src_pic
->src_pict
->type
== xa_src_pict_solid_fill
) {
310 fs_traits
|= FS_SOLID_FILL
;
311 vs_traits
|= VS_SOLID_FILL
;
312 xa_pixel_to_float4(src_pic
->src_pict
->solid_fill
.color
,
314 ctx
->has_solid_color
= TRUE
;
317 fs_traits
|= FS_COMPOSITE
;
318 vs_traits
|= VS_COMPOSITE
;
321 fs_traits
|= picture_format_fixups(src_pic
, dst_pic
, 0);
325 vs_traits
|= VS_MASK
;
326 fs_traits
|= FS_MASK
;
327 if (mask_pic
->wrap
== xa_wrap_clamp_to_border
&&
328 mask_pic
->has_transform
)
329 fs_traits
|= FS_MASK_REPEAT_NONE
;
331 if (mask_pic
->component_alpha
) {
332 struct xa_composite_blend blend
;
333 blend_for_op(&blend
, comp
->op
, src_pic
, mask_pic
, NULL
);
334 if (blend
.alpha_src
) {
335 fs_traits
|= FS_CA_SRCALPHA
;
337 fs_traits
|= FS_CA_FULL
;
340 fs_traits
|= picture_format_fixups(mask_pic
, dst_pic
, 1);
343 shader
= xa_shaders_get(ctx
->shaders
, vs_traits
, fs_traits
);
344 cso_set_vertex_shader_handle(ctx
->cso
, shader
.vs
);
345 cso_set_fragment_shader_handle(ctx
->cso
, shader
.fs
);
349 bind_samplers(struct xa_context
*ctx
,
350 const struct xa_composite
*comp
)
352 struct pipe_sampler_state
*samplers
[PIPE_MAX_SAMPLERS
];
353 struct pipe_sampler_state src_sampler
, mask_sampler
;
354 struct pipe_sampler_view view_templ
;
355 struct pipe_sampler_view
*src_view
;
356 struct pipe_context
*pipe
= ctx
->pipe
;
357 struct xa_picture
*src_pic
= comp
->src
;
358 struct xa_picture
*mask_pic
= comp
->mask
;
360 ctx
->num_bound_samplers
= 0;
362 memset(&src_sampler
, 0, sizeof(struct pipe_sampler_state
));
363 memset(&mask_sampler
, 0, sizeof(struct pipe_sampler_state
));
366 if (ctx
->has_solid_color
) {
368 pipe_sampler_view_reference(&ctx
->bound_sampler_views
[0], NULL
);
370 unsigned src_wrap
= xa_repeat_to_gallium(src_pic
->wrap
);
373 (void) xa_filter_to_gallium(src_pic
->filter
, &filter
);
375 src_sampler
.wrap_s
= src_wrap
;
376 src_sampler
.wrap_t
= src_wrap
;
377 src_sampler
.min_img_filter
= filter
;
378 src_sampler
.mag_img_filter
= filter
;
379 src_sampler
.min_mip_filter
= PIPE_TEX_MIPFILTER_NEAREST
;
380 src_sampler
.normalized_coords
= 1;
381 samplers
[0] = &src_sampler
;
382 ctx
->num_bound_samplers
= 1;
383 u_sampler_view_default_template(&view_templ
,
385 src_pic
->srf
->tex
->format
);
386 src_view
= pipe
->create_sampler_view(pipe
, src_pic
->srf
->tex
,
388 pipe_sampler_view_reference(&ctx
->bound_sampler_views
[0], NULL
);
389 ctx
->bound_sampler_views
[0] = src_view
;
394 unsigned mask_wrap
= xa_repeat_to_gallium(mask_pic
->wrap
);
397 (void) xa_filter_to_gallium(mask_pic
->filter
, &filter
);
399 mask_sampler
.wrap_s
= mask_wrap
;
400 mask_sampler
.wrap_t
= mask_wrap
;
401 mask_sampler
.min_img_filter
= filter
;
402 mask_sampler
.mag_img_filter
= filter
;
403 src_sampler
.min_mip_filter
= PIPE_TEX_MIPFILTER_NEAREST
;
404 mask_sampler
.normalized_coords
= 1;
405 samplers
[1] = &mask_sampler
;
406 ctx
->num_bound_samplers
= 2;
407 u_sampler_view_default_template(&view_templ
,
409 mask_pic
->srf
->tex
->format
);
410 src_view
= pipe
->create_sampler_view(pipe
, mask_pic
->srf
->tex
,
412 pipe_sampler_view_reference(&ctx
->bound_sampler_views
[1], NULL
);
413 ctx
->bound_sampler_views
[1] = src_view
;
416 cso_set_samplers(ctx
->cso
, ctx
->num_bound_samplers
,
417 (const struct pipe_sampler_state
**)samplers
);
418 cso_set_fragment_sampler_views(ctx
->cso
, ctx
->num_bound_samplers
,
419 ctx
->bound_sampler_views
);
423 xa_composite_prepare(struct xa_context
*ctx
,
424 const struct xa_composite
*comp
)
426 struct xa_surface
*dst_srf
= comp
->dst
->srf
;
429 ret
= xa_surface_psurf_create(ctx
, dst_srf
);
430 if (ret
!= XA_ERR_NONE
)
433 renderer_bind_destination(ctx
, dst_srf
->srf
,
435 dst_srf
->srf
->height
);
437 bind_composite_blend_state(ctx
, comp
);
438 bind_shaders(ctx
, comp
);
439 bind_samplers(ctx
, comp
);
441 if (ctx
->num_bound_samplers
== 0 ) { /* solid fill */
442 renderer_begin_solid(ctx
);
444 renderer_begin_textures(ctx
);
447 xa_surface_psurf_destroy(dst_srf
);
451 void xa_composite_rect(struct xa_context
*ctx
,
452 int srcX
, int srcY
, int maskX
, int maskY
,
453 int dstX
, int dstY
, int width
, int height
)
455 if (ctx
->num_bound_samplers
== 0 ) { /* solid fill */
456 renderer_solid(ctx
, dstX
, dstY
, dstX
+ width
, dstY
+ height
,
459 const struct xa_composite
*comp
= ctx
->comp
;
460 int pos
[6] = {srcX
, srcY
, maskX
, maskY
, dstX
, dstY
};
461 const float *src_matrix
= NULL
;
462 const float *mask_matrix
= NULL
;
464 if (comp
->src
->has_transform
)
465 src_matrix
= comp
->src
->transform
;
466 if (comp
->mask
->has_transform
)
467 mask_matrix
= comp
->mask
->transform
;
469 renderer_texture(ctx
, pos
, width
, height
,
470 src_matrix
, mask_matrix
);
475 xa_composite_done(struct xa_context
*ctx
)
477 renderer_draw_flush(ctx
);
478 ctx
->pipe
->flush(ctx
->pipe
, &ctx
->last_fence
);
481 ctx
->has_solid_color
= FALSE
;
482 ctx
->num_bound_samplers
= 0;
485 static const struct xa_composite_allocation a
= {
486 .xa_composite_size
= sizeof(struct xa_composite
),
487 .xa_picture_size
= sizeof(struct xa_picture
),
488 .xa_source_pict_size
= sizeof(union xa_source_pict
),
491 const struct xa_composite_allocation
*
492 xa_composite_allocation(void)