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