17ec681f3Smrg/**********************************************************
27ec681f3Smrg * Copyright 2009-2011 VMware, Inc. All rights reserved.
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person
57ec681f3Smrg * obtaining a copy of this software and associated documentation
67ec681f3Smrg * files (the "Software"), to deal in the Software without
77ec681f3Smrg * restriction, including without limitation the rights to use, copy,
87ec681f3Smrg * modify, merge, publish, distribute, sublicense, and/or sell copies
97ec681f3Smrg * of the Software, and to permit persons to whom the Software is
107ec681f3Smrg * furnished to do so, subject to the following conditions:
117ec681f3Smrg *
127ec681f3Smrg * The above copyright notice and this permission notice shall be
137ec681f3Smrg * included in all copies or substantial portions of the Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
167ec681f3Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
177ec681f3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
187ec681f3Smrg * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
197ec681f3Smrg * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
207ec681f3Smrg * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
217ec681f3Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
227ec681f3Smrg * SOFTWARE.
237ec681f3Smrg *
247ec681f3Smrg *********************************************************
257ec681f3Smrg * Authors:
267ec681f3Smrg * Zack Rusin <zackr-at-vmware-dot-com>
277ec681f3Smrg * Thomas Hellstrom <thellstrom-at-vmware-dot-com>
287ec681f3Smrg */
297ec681f3Smrg
307ec681f3Smrg#include "xa_composite.h"
317ec681f3Smrg#include "xa_context.h"
327ec681f3Smrg#include "xa_priv.h"
337ec681f3Smrg#include "cso_cache/cso_context.h"
347ec681f3Smrg#include "util/u_sampler.h"
357ec681f3Smrg#include "util/u_inlines.h"
367ec681f3Smrg
377ec681f3Smrg
387ec681f3Smrg/*XXX also in Xrender.h but the including it here breaks compilition */
397ec681f3Smrg#define XFixedToDouble(f)    (((double) (f)) / 65536.)
407ec681f3Smrg
417ec681f3Smrgstruct xa_composite_blend {
427ec681f3Smrg    unsigned op : 8;
437ec681f3Smrg
447ec681f3Smrg    unsigned alpha_dst : 4;
457ec681f3Smrg    unsigned alpha_src : 4;
467ec681f3Smrg
477ec681f3Smrg    unsigned rgb_src : 8;    /**< PIPE_BLENDFACTOR_x */
487ec681f3Smrg    unsigned rgb_dst : 8;    /**< PIPE_BLENDFACTOR_x */
497ec681f3Smrg};
507ec681f3Smrg
517ec681f3Smrg#define XA_BLEND_OP_OVER 3
527ec681f3Smrgstatic const struct xa_composite_blend xa_blends[] = {
537ec681f3Smrg    { xa_op_clear,
547ec681f3Smrg      0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO},
557ec681f3Smrg    { xa_op_src,
567ec681f3Smrg      0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ZERO},
577ec681f3Smrg    { xa_op_dst,
587ec681f3Smrg      0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ONE},
597ec681f3Smrg    { xa_op_over,
607ec681f3Smrg      0, 1, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
617ec681f3Smrg    { xa_op_over_reverse,
627ec681f3Smrg      1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE},
637ec681f3Smrg    { xa_op_in,
647ec681f3Smrg      1, 0, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_ZERO},
657ec681f3Smrg    { xa_op_in_reverse,
667ec681f3Smrg      0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_SRC_ALPHA},
677ec681f3Smrg    { xa_op_out,
687ec681f3Smrg      1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ZERO},
697ec681f3Smrg    { xa_op_out_reverse,
707ec681f3Smrg      0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
717ec681f3Smrg    { xa_op_atop,
727ec681f3Smrg      1, 1, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
737ec681f3Smrg    { xa_op_atop_reverse,
747ec681f3Smrg      1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_SRC_ALPHA},
757ec681f3Smrg    { xa_op_xor,
767ec681f3Smrg      1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
777ec681f3Smrg    { xa_op_add,
787ec681f3Smrg      0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE},
797ec681f3Smrg};
807ec681f3Smrg
817ec681f3Smrg/*
827ec681f3Smrg * The alpha value stored in a L8 texture is read by the
837ec681f3Smrg * hardware as color, and R8 is read as red. The source alpha value
847ec681f3Smrg * at the end of the fragment shader is stored in all color channels,
857ec681f3Smrg * so the correct approach is to blend using DST_COLOR instead of
867ec681f3Smrg * DST_ALPHA and then output any color channel (L8) or the red channel (R8).
877ec681f3Smrg */
887ec681f3Smrgstatic unsigned
897ec681f3Smrgxa_convert_blend_for_luminance(unsigned factor)
907ec681f3Smrg{
917ec681f3Smrg    switch(factor) {
927ec681f3Smrg    case PIPE_BLENDFACTOR_DST_ALPHA:
937ec681f3Smrg	return PIPE_BLENDFACTOR_DST_COLOR;
947ec681f3Smrg    case PIPE_BLENDFACTOR_INV_DST_ALPHA:
957ec681f3Smrg	return PIPE_BLENDFACTOR_INV_DST_COLOR;
967ec681f3Smrg    default:
977ec681f3Smrg	break;
987ec681f3Smrg    }
997ec681f3Smrg    return factor;
1007ec681f3Smrg}
1017ec681f3Smrg
1027ec681f3Smrgstatic boolean
1037ec681f3Smrgblend_for_op(struct xa_composite_blend *blend,
1047ec681f3Smrg	     enum xa_composite_op op,
1057ec681f3Smrg	     struct xa_picture *src_pic,
1067ec681f3Smrg	     struct xa_picture *mask_pic,
1077ec681f3Smrg	     struct xa_picture *dst_pic)
1087ec681f3Smrg{
1097ec681f3Smrg    const int num_blends =
1107ec681f3Smrg	sizeof(xa_blends)/sizeof(struct xa_composite_blend);
1117ec681f3Smrg    int i;
1127ec681f3Smrg    boolean supported = FALSE;
1137ec681f3Smrg
1147ec681f3Smrg    /*
1157ec681f3Smrg     * our default in case something goes wrong
1167ec681f3Smrg     */
1177ec681f3Smrg    *blend = xa_blends[XA_BLEND_OP_OVER];
1187ec681f3Smrg
1197ec681f3Smrg    for (i = 0; i < num_blends; ++i) {
1207ec681f3Smrg	if (xa_blends[i].op == op) {
1217ec681f3Smrg	    *blend = xa_blends[i];
1227ec681f3Smrg	    supported = TRUE;
1237ec681f3Smrg            break;
1247ec681f3Smrg	}
1257ec681f3Smrg    }
1267ec681f3Smrg
1277ec681f3Smrg    /*
1287ec681f3Smrg     * No component alpha yet.
1297ec681f3Smrg     */
1307ec681f3Smrg    if (mask_pic && mask_pic->component_alpha && blend->alpha_src)
1317ec681f3Smrg	return FALSE;
1327ec681f3Smrg
1337ec681f3Smrg    if (!dst_pic->srf)
1347ec681f3Smrg	return supported;
1357ec681f3Smrg
1367ec681f3Smrg    if ((dst_pic->srf->tex->format == PIPE_FORMAT_L8_UNORM ||
1377ec681f3Smrg         dst_pic->srf->tex->format == PIPE_FORMAT_R8_UNORM)) {
1387ec681f3Smrg        blend->rgb_src = xa_convert_blend_for_luminance(blend->rgb_src);
1397ec681f3Smrg        blend->rgb_dst = xa_convert_blend_for_luminance(blend->rgb_dst);
1407ec681f3Smrg    }
1417ec681f3Smrg
1427ec681f3Smrg    /*
1437ec681f3Smrg     * If there's no dst alpha channel, adjust the blend op so that we'll treat
1447ec681f3Smrg     * it as always 1.
1457ec681f3Smrg     */
1467ec681f3Smrg
1477ec681f3Smrg    if (xa_format_a(dst_pic->pict_format) == 0 && blend->alpha_dst) {
1487ec681f3Smrg	if (blend->rgb_src == PIPE_BLENDFACTOR_DST_ALPHA)
1497ec681f3Smrg	    blend->rgb_src = PIPE_BLENDFACTOR_ONE;
1507ec681f3Smrg	else if (blend->rgb_src == PIPE_BLENDFACTOR_INV_DST_ALPHA)
1517ec681f3Smrg	    blend->rgb_src = PIPE_BLENDFACTOR_ZERO;
1527ec681f3Smrg    }
1537ec681f3Smrg
1547ec681f3Smrg    return supported;
1557ec681f3Smrg}
1567ec681f3Smrg
1577ec681f3Smrg
1587ec681f3Smrgstatic inline int
1597ec681f3Smrgxa_repeat_to_gallium(int mode)
1607ec681f3Smrg{
1617ec681f3Smrg    switch(mode) {
1627ec681f3Smrg    case xa_wrap_clamp_to_border:
1637ec681f3Smrg	return PIPE_TEX_WRAP_CLAMP_TO_BORDER;
1647ec681f3Smrg    case xa_wrap_repeat:
1657ec681f3Smrg	return PIPE_TEX_WRAP_REPEAT;
1667ec681f3Smrg    case xa_wrap_mirror_repeat:
1677ec681f3Smrg	return PIPE_TEX_WRAP_MIRROR_REPEAT;
1687ec681f3Smrg    case xa_wrap_clamp_to_edge:
1697ec681f3Smrg	return PIPE_TEX_WRAP_CLAMP_TO_EDGE;
1707ec681f3Smrg    default:
1717ec681f3Smrg	break;
1727ec681f3Smrg    }
1737ec681f3Smrg    return PIPE_TEX_WRAP_REPEAT;
1747ec681f3Smrg}
1757ec681f3Smrg
1767ec681f3Smrgstatic inline boolean
1777ec681f3Smrgxa_filter_to_gallium(int xrender_filter, int *out_filter)
1787ec681f3Smrg{
1797ec681f3Smrg
1807ec681f3Smrg    switch (xrender_filter) {
1817ec681f3Smrg    case xa_filter_nearest:
1827ec681f3Smrg	*out_filter = PIPE_TEX_FILTER_NEAREST;
1837ec681f3Smrg	break;
1847ec681f3Smrg    case xa_filter_linear:
1857ec681f3Smrg	*out_filter = PIPE_TEX_FILTER_LINEAR;
1867ec681f3Smrg	break;
1877ec681f3Smrg    default:
1887ec681f3Smrg	*out_filter = PIPE_TEX_FILTER_NEAREST;
1897ec681f3Smrg	return FALSE;
1907ec681f3Smrg    }
1917ec681f3Smrg    return TRUE;
1927ec681f3Smrg}
1937ec681f3Smrg
1947ec681f3Smrgstatic int
1957ec681f3Smrgxa_is_filter_accelerated(struct xa_picture *pic)
1967ec681f3Smrg{
1977ec681f3Smrg    int filter;
1987ec681f3Smrg    if (pic && !xa_filter_to_gallium(pic->filter, &filter))
1997ec681f3Smrg	return 0;
2007ec681f3Smrg    return 1;
2017ec681f3Smrg}
2027ec681f3Smrg
2037ec681f3Smrg/**
2047ec681f3Smrg * xa_src_pict_is_accelerated - Check whether we support acceleration
2057ec681f3Smrg * of the given src_pict type
2067ec681f3Smrg *
2077ec681f3Smrg * \param src_pic[in]: Pointer to a union xa_source_pict to check.
2087ec681f3Smrg *
2097ec681f3Smrg * \returns TRUE if accelerated, FALSE otherwise.
2107ec681f3Smrg */
2117ec681f3Smrgstatic boolean
2127ec681f3Smrgxa_src_pict_is_accelerated(const union xa_source_pict *src_pic)
2137ec681f3Smrg{
2147ec681f3Smrg    if (!src_pic)
2157ec681f3Smrg        return TRUE;
2167ec681f3Smrg
2177ec681f3Smrg    if (src_pic->type == xa_src_pict_solid_fill ||
2187ec681f3Smrg        src_pic->type == xa_src_pict_float_solid_fill)
2197ec681f3Smrg        return TRUE;
2207ec681f3Smrg
2217ec681f3Smrg    return FALSE;
2227ec681f3Smrg}
2237ec681f3Smrg
2247ec681f3SmrgXA_EXPORT int
2257ec681f3Smrgxa_composite_check_accelerated(const struct xa_composite *comp)
2267ec681f3Smrg{
2277ec681f3Smrg    struct xa_picture *src_pic = comp->src;
2287ec681f3Smrg    struct xa_picture *mask_pic = comp->mask;
2297ec681f3Smrg    struct xa_composite_blend blend;
2307ec681f3Smrg
2317ec681f3Smrg    if (!xa_is_filter_accelerated(src_pic) ||
2327ec681f3Smrg	!xa_is_filter_accelerated(comp->mask)) {
2337ec681f3Smrg	return -XA_ERR_INVAL;
2347ec681f3Smrg    }
2357ec681f3Smrg
2367ec681f3Smrg    if (!xa_src_pict_is_accelerated(src_pic->src_pict) ||
2377ec681f3Smrg        (mask_pic && !xa_src_pict_is_accelerated(mask_pic->src_pict)))
2387ec681f3Smrg        return -XA_ERR_INVAL;
2397ec681f3Smrg
2407ec681f3Smrg    if (!blend_for_op(&blend, comp->op, comp->src, comp->mask, comp->dst))
2417ec681f3Smrg	return -XA_ERR_INVAL;
2427ec681f3Smrg
2437ec681f3Smrg    /*
2447ec681f3Smrg     * No component alpha yet.
2457ec681f3Smrg     */
2467ec681f3Smrg    if (mask_pic && mask_pic->component_alpha && blend.alpha_src)
2477ec681f3Smrg	return -XA_ERR_INVAL;
2487ec681f3Smrg
2497ec681f3Smrg    return XA_ERR_NONE;
2507ec681f3Smrg}
2517ec681f3Smrg
2527ec681f3Smrgstatic int
2537ec681f3Smrgbind_composite_blend_state(struct xa_context *ctx,
2547ec681f3Smrg			   const struct xa_composite *comp)
2557ec681f3Smrg{
2567ec681f3Smrg    struct xa_composite_blend blend_opt;
2577ec681f3Smrg    struct pipe_blend_state blend;
2587ec681f3Smrg
2597ec681f3Smrg    if (!blend_for_op(&blend_opt, comp->op, comp->src, comp->mask, comp->dst))
2607ec681f3Smrg	return -XA_ERR_INVAL;
2617ec681f3Smrg
2627ec681f3Smrg    memset(&blend, 0, sizeof(struct pipe_blend_state));
2637ec681f3Smrg    blend.rt[0].blend_enable = 1;
2647ec681f3Smrg    blend.rt[0].colormask = PIPE_MASK_RGBA;
2657ec681f3Smrg
2667ec681f3Smrg    blend.rt[0].rgb_src_factor   = blend_opt.rgb_src;
2677ec681f3Smrg    blend.rt[0].alpha_src_factor = blend_opt.rgb_src;
2687ec681f3Smrg    blend.rt[0].rgb_dst_factor   = blend_opt.rgb_dst;
2697ec681f3Smrg    blend.rt[0].alpha_dst_factor = blend_opt.rgb_dst;
2707ec681f3Smrg
2717ec681f3Smrg    cso_set_blend(ctx->cso, &blend);
2727ec681f3Smrg    return XA_ERR_NONE;
2737ec681f3Smrg}
2747ec681f3Smrg
2757ec681f3Smrgstatic unsigned int
2767ec681f3Smrgpicture_format_fixups(struct xa_picture *src_pic,
2777ec681f3Smrg		      int mask)
2787ec681f3Smrg{
2797ec681f3Smrg    boolean set_alpha = FALSE;
2807ec681f3Smrg    boolean swizzle = FALSE;
2817ec681f3Smrg    unsigned ret = 0;
2827ec681f3Smrg    struct xa_surface *src = src_pic->srf;
2837ec681f3Smrg    enum xa_formats src_hw_format, src_pic_format;
2847ec681f3Smrg    enum xa_surface_type src_hw_type, src_pic_type;
2857ec681f3Smrg
2867ec681f3Smrg    if (!src)
2877ec681f3Smrg	return 0;
2887ec681f3Smrg
2897ec681f3Smrg    src_hw_format = xa_surface_format(src);
2907ec681f3Smrg    src_pic_format = src_pic->pict_format;
2917ec681f3Smrg
2927ec681f3Smrg    set_alpha = (xa_format_type_is_color(src_hw_format) &&
2937ec681f3Smrg		 xa_format_a(src_pic_format) == 0);
2947ec681f3Smrg
2957ec681f3Smrg    if (set_alpha)
2967ec681f3Smrg	ret |= mask ? FS_MASK_SET_ALPHA : FS_SRC_SET_ALPHA;
2977ec681f3Smrg
2987ec681f3Smrg    if (src_hw_format == src_pic_format) {
2997ec681f3Smrg	if (src->tex->format == PIPE_FORMAT_L8_UNORM ||
3007ec681f3Smrg            src->tex->format == PIPE_FORMAT_R8_UNORM)
3017ec681f3Smrg	    return ((mask) ? FS_MASK_LUMINANCE : FS_SRC_LUMINANCE);
3027ec681f3Smrg
3037ec681f3Smrg	return ret;
3047ec681f3Smrg    }
3057ec681f3Smrg
3067ec681f3Smrg    src_hw_type = xa_format_type(src_hw_format);
3077ec681f3Smrg    src_pic_type = xa_format_type(src_pic_format);
3087ec681f3Smrg
3097ec681f3Smrg    swizzle = ((src_hw_type == xa_type_argb &&
3107ec681f3Smrg		src_pic_type == xa_type_abgr) ||
3117ec681f3Smrg	       ((src_hw_type == xa_type_abgr &&
3127ec681f3Smrg		 src_pic_type == xa_type_argb)));
3137ec681f3Smrg
3147ec681f3Smrg    if (!swizzle && (src_hw_type != src_pic_type))
3157ec681f3Smrg      return ret;
3167ec681f3Smrg
3177ec681f3Smrg    if (swizzle)
3187ec681f3Smrg	ret |= mask ? FS_MASK_SWIZZLE_RGB : FS_SRC_SWIZZLE_RGB;
3197ec681f3Smrg
3207ec681f3Smrg    return ret;
3217ec681f3Smrg}
3227ec681f3Smrg
3237ec681f3Smrgstatic void
3247ec681f3Smrgxa_src_in_mask(float src[4], const float mask[4])
3257ec681f3Smrg{
3267ec681f3Smrg	src[0] *= mask[3];
3277ec681f3Smrg	src[1] *= mask[3];
3287ec681f3Smrg	src[2] *= mask[3];
3297ec681f3Smrg	src[3] *= mask[3];
3307ec681f3Smrg}
3317ec681f3Smrg
3327ec681f3Smrg/**
3337ec681f3Smrg * xa_handle_src_pict - Set up xa_context state and fragment shader
3347ec681f3Smrg * input based on scr_pict type
3357ec681f3Smrg *
3367ec681f3Smrg * \param ctx[in, out]: Pointer to the xa context.
3377ec681f3Smrg * \param src_pict[in]: Pointer to the union xa_source_pict to consider.
3387ec681f3Smrg * \param is_mask[in]: Whether we're considering a mask picture.
3397ec681f3Smrg *
3407ec681f3Smrg * \returns TRUE if succesful, FALSE otherwise.
3417ec681f3Smrg *
3427ec681f3Smrg * This function computes some xa_context state used to determine whether
3437ec681f3Smrg * to upload the solid color and also the solid color itself used as an input
3447ec681f3Smrg * to the fragment shader.
3457ec681f3Smrg */
3467ec681f3Smrgstatic boolean
3477ec681f3Smrgxa_handle_src_pict(struct xa_context *ctx,
3487ec681f3Smrg                   const union xa_source_pict *src_pict,
3497ec681f3Smrg                   boolean is_mask)
3507ec681f3Smrg{
3517ec681f3Smrg    float solid_color[4];
3527ec681f3Smrg
3537ec681f3Smrg    switch(src_pict->type) {
3547ec681f3Smrg    case xa_src_pict_solid_fill:
3557ec681f3Smrg        xa_pixel_to_float4(src_pict->solid_fill.color, solid_color);
3567ec681f3Smrg        break;
3577ec681f3Smrg    case xa_src_pict_float_solid_fill:
3587ec681f3Smrg        memcpy(solid_color, src_pict->float_solid_fill.color,
3597ec681f3Smrg               sizeof(solid_color));
3607ec681f3Smrg        break;
3617ec681f3Smrg    default:
3627ec681f3Smrg        return FALSE;
3637ec681f3Smrg    }
3647ec681f3Smrg
3657ec681f3Smrg    if (is_mask && ctx->has_solid_src)
3667ec681f3Smrg        xa_src_in_mask(ctx->solid_color, solid_color);
3677ec681f3Smrg    else
3687ec681f3Smrg        memcpy(ctx->solid_color, solid_color, sizeof(solid_color));
3697ec681f3Smrg
3707ec681f3Smrg    if (is_mask)
3717ec681f3Smrg        ctx->has_solid_mask = TRUE;
3727ec681f3Smrg    else
3737ec681f3Smrg        ctx->has_solid_src = TRUE;
3747ec681f3Smrg
3757ec681f3Smrg    return TRUE;
3767ec681f3Smrg}
3777ec681f3Smrg
3787ec681f3Smrgstatic int
3797ec681f3Smrgbind_shaders(struct xa_context *ctx, const struct xa_composite *comp)
3807ec681f3Smrg{
3817ec681f3Smrg    unsigned vs_traits = 0, fs_traits = 0;
3827ec681f3Smrg    struct xa_shader shader;
3837ec681f3Smrg    struct xa_picture *src_pic = comp->src;
3847ec681f3Smrg    struct xa_picture *mask_pic = comp->mask;
3857ec681f3Smrg    struct xa_picture *dst_pic = comp->dst;
3867ec681f3Smrg
3877ec681f3Smrg    ctx->has_solid_src = FALSE;
3887ec681f3Smrg    ctx->has_solid_mask = FALSE;
3897ec681f3Smrg
3907ec681f3Smrg    if (dst_pic && xa_format_type(dst_pic->pict_format) !=
3917ec681f3Smrg        xa_format_type(xa_surface_format(dst_pic->srf)))
3927ec681f3Smrg       return -XA_ERR_INVAL;
3937ec681f3Smrg
3947ec681f3Smrg    if (src_pic) {
3957ec681f3Smrg	if (src_pic->wrap == xa_wrap_clamp_to_border && src_pic->has_transform)
3967ec681f3Smrg	    fs_traits |= FS_SRC_REPEAT_NONE;
3977ec681f3Smrg
3987ec681f3Smrg        fs_traits |= FS_COMPOSITE;
3997ec681f3Smrg        vs_traits |= VS_COMPOSITE;
4007ec681f3Smrg
4017ec681f3Smrg	if (src_pic->src_pict) {
4027ec681f3Smrg            if (!xa_handle_src_pict(ctx, src_pic->src_pict, false))
4037ec681f3Smrg                return -XA_ERR_INVAL;
4047ec681f3Smrg            fs_traits |= FS_SRC_SRC;
4057ec681f3Smrg            vs_traits |= VS_SRC_SRC;
4067ec681f3Smrg	} else
4077ec681f3Smrg           fs_traits |= picture_format_fixups(src_pic, 0);
4087ec681f3Smrg    }
4097ec681f3Smrg
4107ec681f3Smrg    if (mask_pic) {
4117ec681f3Smrg	vs_traits |= VS_MASK;
4127ec681f3Smrg	fs_traits |= FS_MASK;
4137ec681f3Smrg        if (mask_pic->component_alpha)
4147ec681f3Smrg           fs_traits |= FS_CA;
4157ec681f3Smrg        if (mask_pic->src_pict) {
4167ec681f3Smrg            if (!xa_handle_src_pict(ctx, mask_pic->src_pict, true))
4177ec681f3Smrg                return -XA_ERR_INVAL;
4187ec681f3Smrg
4197ec681f3Smrg            if (ctx->has_solid_src) {
4207ec681f3Smrg                vs_traits &= ~VS_MASK;
4217ec681f3Smrg                fs_traits &= ~FS_MASK;
4227ec681f3Smrg            } else {
4237ec681f3Smrg                vs_traits |= VS_MASK_SRC;
4247ec681f3Smrg                fs_traits |= FS_MASK_SRC;
4257ec681f3Smrg            }
4267ec681f3Smrg        } else {
4277ec681f3Smrg            if (mask_pic->wrap == xa_wrap_clamp_to_border &&
4287ec681f3Smrg                mask_pic->has_transform)
4297ec681f3Smrg                fs_traits |= FS_MASK_REPEAT_NONE;
4307ec681f3Smrg
4317ec681f3Smrg            fs_traits |= picture_format_fixups(mask_pic, 1);
4327ec681f3Smrg        }
4337ec681f3Smrg    }
4347ec681f3Smrg
4357ec681f3Smrg    if (ctx->srf->format == PIPE_FORMAT_L8_UNORM ||
4367ec681f3Smrg        ctx->srf->format == PIPE_FORMAT_R8_UNORM)
4377ec681f3Smrg	fs_traits |= FS_DST_LUMINANCE;
4387ec681f3Smrg
4397ec681f3Smrg    shader = xa_shaders_get(ctx->shaders, vs_traits, fs_traits);
4407ec681f3Smrg    cso_set_vertex_shader_handle(ctx->cso, shader.vs);
4417ec681f3Smrg    cso_set_fragment_shader_handle(ctx->cso, shader.fs);
4427ec681f3Smrg    return XA_ERR_NONE;
4437ec681f3Smrg}
4447ec681f3Smrg
4457ec681f3Smrgstatic void
4467ec681f3Smrgbind_samplers(struct xa_context *ctx,
4477ec681f3Smrg	      const struct xa_composite *comp)
4487ec681f3Smrg{
4497ec681f3Smrg    struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
4507ec681f3Smrg    struct pipe_sampler_state src_sampler, mask_sampler;
4517ec681f3Smrg    struct pipe_sampler_view view_templ;
4527ec681f3Smrg    struct pipe_sampler_view *src_view;
4537ec681f3Smrg    struct pipe_context *pipe = ctx->pipe;
4547ec681f3Smrg    struct xa_picture *src_pic = comp->src;
4557ec681f3Smrg    struct xa_picture *mask_pic = comp->mask;
4567ec681f3Smrg    int num_samplers = 0;
4577ec681f3Smrg
4587ec681f3Smrg    xa_ctx_sampler_views_destroy(ctx);
4597ec681f3Smrg    memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
4607ec681f3Smrg    memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
4617ec681f3Smrg
4627ec681f3Smrg    if (src_pic && !ctx->has_solid_src) {
4637ec681f3Smrg	unsigned src_wrap = xa_repeat_to_gallium(src_pic->wrap);
4647ec681f3Smrg	int filter;
4657ec681f3Smrg
4667ec681f3Smrg	(void) xa_filter_to_gallium(src_pic->filter, &filter);
4677ec681f3Smrg
4687ec681f3Smrg	src_sampler.wrap_s = src_wrap;
4697ec681f3Smrg	src_sampler.wrap_t = src_wrap;
4707ec681f3Smrg	src_sampler.min_img_filter = filter;
4717ec681f3Smrg	src_sampler.mag_img_filter = filter;
4727ec681f3Smrg	src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
4737ec681f3Smrg	src_sampler.normalized_coords = 1;
4747ec681f3Smrg	samplers[0] = &src_sampler;
4757ec681f3Smrg	u_sampler_view_default_template(&view_templ,
4767ec681f3Smrg					src_pic->srf->tex,+					src_pic->srf->tex->format);
4777ec681f3Smrg	src_view = pipe->create_sampler_view(pipe, src_pic->srf->tex,
4787ec681f3Smrg					     &view_templ);
4797ec681f3Smrg	ctx->bound_sampler_views[0] = src_view;
4807ec681f3Smrg	num_samplers++;
4817ec681f3Smrg    }
4827ec681f3Smrg
4837ec681f3Smrg    if (mask_pic && !ctx->has_solid_mask) {
4847ec681f3Smrg        unsigned mask_wrap = xa_repeat_to_gallium(mask_pic->wrap);
4857ec681f3Smrg	int filter;
4867ec681f3Smrg
4877ec681f3Smrg	(void) xa_filter_to_gallium(mask_pic->filter, &filter);
4887ec681f3Smrg
4897ec681f3Smrg	mask_sampler.wrap_s = mask_wrap;
4907ec681f3Smrg	mask_sampler.wrap_t = mask_wrap;
4917ec681f3Smrg	mask_sampler.min_img_filter = filter;
4927ec681f3Smrg	mask_sampler.mag_img_filter = filter;
4937ec681f3Smrg	src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
4947ec681f3Smrg	mask_sampler.normalized_coords = 1;
4957ec681f3Smrg        samplers[num_samplers] = &mask_sampler;
4967ec681f3Smrg	u_sampler_view_default_template(&view_templ,
4977ec681f3Smrg					mask_pic->srf->tex,
4987ec681f3Smrg					mask_pic->srf->tex->format);
4997ec681f3Smrg	src_view = pipe->create_sampler_view(pipe, mask_pic->srf->tex,
5007ec681f3Smrg					     &view_templ);
5017ec681f3Smrg        ctx->bound_sampler_views[num_samplers] = src_view;
5027ec681f3Smrg        num_samplers++;
5037ec681f3Smrg    }
5047ec681f3Smrg
5057ec681f3Smrg    cso_set_samplers(ctx->cso, PIPE_SHADER_FRAGMENT, num_samplers,
5067ec681f3Smrg		     (const struct pipe_sampler_state **)samplers);
5077ec681f3Smrg    pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, num_samplers, 0,
5087ec681f3Smrg                            false, ctx->bound_sampler_views);
5097ec681f3Smrg    ctx->num_bound_samplers = num_samplers;
5107ec681f3Smrg}
5117ec681f3Smrg
5127ec681f3SmrgXA_EXPORT int
5137ec681f3Smrgxa_composite_prepare(struct xa_context *ctx,
5147ec681f3Smrg		     const struct xa_composite *comp)
5157ec681f3Smrg{
5167ec681f3Smrg    struct xa_surface *dst_srf = comp->dst->srf;
5177ec681f3Smrg    int ret;
5187ec681f3Smrg
5197ec681f3Smrg    ret = xa_ctx_srf_create(ctx, dst_srf);
5207ec681f3Smrg    if (ret != XA_ERR_NONE)
5217ec681f3Smrg	return ret;
5227ec681f3Smrg
5237ec681f3Smrg    ctx->dst = dst_srf;
5247ec681f3Smrg    renderer_bind_destination(ctx, ctx->srf);
5257ec681f3Smrg
5267ec681f3Smrg    ret = bind_composite_blend_state(ctx, comp);
5277ec681f3Smrg    if (ret != XA_ERR_NONE)
5287ec681f3Smrg	return ret;
5297ec681f3Smrg    ret = bind_shaders(ctx, comp);
5307ec681f3Smrg    if (ret != XA_ERR_NONE)
5317ec681f3Smrg	return ret;
5327ec681f3Smrg    bind_samplers(ctx, comp);
5337ec681f3Smrg
5347ec681f3Smrg    if (ctx->num_bound_samplers == 0 ) { /* solid fill */
5357ec681f3Smrg	renderer_begin_solid(ctx);
5367ec681f3Smrg    } else {
5377ec681f3Smrg	renderer_begin_textures(ctx);
5387ec681f3Smrg	ctx->comp = comp;
5397ec681f3Smrg    }
5407ec681f3Smrg
5417ec681f3Smrg    xa_ctx_srf_destroy(ctx);
5427ec681f3Smrg    return XA_ERR_NONE;
5437ec681f3Smrg}
5447ec681f3Smrg
5457ec681f3SmrgXA_EXPORT void
5467ec681f3Smrgxa_composite_rect(struct xa_context *ctx,
5477ec681f3Smrg		  int srcX, int srcY, int maskX, int maskY,
5487ec681f3Smrg		  int dstX, int dstY, int width, int height)
5497ec681f3Smrg{
5507ec681f3Smrg    if (ctx->num_bound_samplers == 0 ) { /* solid fill */
5517ec681f3Smrg	xa_scissor_update(ctx, dstX, dstY, dstX + width, dstY + height);
5527ec681f3Smrg	renderer_solid(ctx, dstX, dstY, dstX + width, dstY + height);
5537ec681f3Smrg    } else {
5547ec681f3Smrg	const struct xa_composite *comp = ctx->comp;
5557ec681f3Smrg	int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY};
5567ec681f3Smrg	const float *src_matrix = NULL;
5577ec681f3Smrg	const float *mask_matrix = NULL;
5587ec681f3Smrg
5597ec681f3Smrg	xa_scissor_update(ctx, dstX, dstY, dstX + width, dstY + height);
5607ec681f3Smrg
5617ec681f3Smrg	if (comp->src->has_transform)
5627ec681f3Smrg	    src_matrix = comp->src->transform;
5637ec681f3Smrg	if (comp->mask && comp->mask->has_transform)
5647ec681f3Smrg	    mask_matrix = comp->mask->transform;
5657ec681f3Smrg
5667ec681f3Smrg	renderer_texture(ctx, pos, width, height,
5677ec681f3Smrg			 src_matrix, mask_matrix);
5687ec681f3Smrg    }
5697ec681f3Smrg}
5707ec681f3Smrg
5717ec681f3SmrgXA_EXPORT void
5727ec681f3Smrgxa_composite_done(struct xa_context *ctx)
5737ec681f3Smrg{
5747ec681f3Smrg    renderer_draw_flush(ctx);
5757ec681f3Smrg
5767ec681f3Smrg    ctx->comp = NULL;
5777ec681f3Smrg    ctx->has_solid_src = FALSE;
5787ec681f3Smrg    ctx->has_solid_mask = FALSE;
5797ec681f3Smrg    xa_ctx_sampler_views_destroy(ctx);
5807ec681f3Smrg}
5817ec681f3Smrg
5827ec681f3Smrgstatic const struct xa_composite_allocation a = {
5837ec681f3Smrg    .xa_composite_size = sizeof(struct xa_composite),
5847ec681f3Smrg    .xa_picture_size = sizeof(struct xa_picture),
5857ec681f3Smrg    .xa_source_pict_size = sizeof(union xa_source_pict),
5867ec681f3Smrg};
5877ec681f3Smrg
5887ec681f3SmrgXA_EXPORT const struct xa_composite_allocation *
5897ec681f3Smrgxa_composite_allocation(void)
5907ec681f3Smrg{
5917ec681f3Smrg    return &a;
5927ec681f3Smrg}
593