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 */
287ec681f3Smrg#include "xa_priv.h"
297ec681f3Smrg
307ec681f3Smrg#include "pipe/p_format.h"
317ec681f3Smrg#include "pipe/p_context.h"
327ec681f3Smrg#include "pipe/p_state.h"
337ec681f3Smrg#include "pipe/p_shader_tokens.h"
347ec681f3Smrg
357ec681f3Smrg#include "util/u_memory.h"
367ec681f3Smrg
377ec681f3Smrg#include "tgsi/tgsi_ureg.h"
387ec681f3Smrg
397ec681f3Smrg#include "cso_cache/cso_context.h"
407ec681f3Smrg#include "cso_cache/cso_hash.h"
417ec681f3Smrg
427ec681f3Smrg/* Vertex shader:
437ec681f3Smrg * IN[0]    = vertex pos
447ec681f3Smrg * IN[1]    = src tex coord | solid fill color
457ec681f3Smrg * IN[2]    = mask tex coord
467ec681f3Smrg * IN[3]    = dst tex coord
477ec681f3Smrg * CONST[0] = (2/dst_width, 2/dst_height, 1, 1)
487ec681f3Smrg * CONST[1] = (-1, -1, 0, 0)
497ec681f3Smrg *
507ec681f3Smrg * OUT[0]   = vertex pos
517ec681f3Smrg * OUT[1]   = src tex coord
527ec681f3Smrg * OUT[2]   = mask tex coord
537ec681f3Smrg * OUT[3]   = dst tex coord
547ec681f3Smrg */
557ec681f3Smrg
567ec681f3Smrg/* Fragment shader. Samplers are allocated when needed.
577ec681f3Smrg * SAMP[0]  = sampler for first texture (src or mask if src is solid)
587ec681f3Smrg * SAMP[1]  = sampler for second texture (mask or none)
597ec681f3Smrg * IN[0]    = first texture coordinates if present
607ec681f3Smrg * IN[1]    = second texture coordinates if present
617ec681f3Smrg * CONST[0] = Solid color (src if src solid or mask if mask solid
627ec681f3Smrg *            or src in mask if both solid).
637ec681f3Smrg *
647ec681f3Smrg * OUT[0] = color
657ec681f3Smrg */
667ec681f3Smrg
677ec681f3Smrgstatic void
687ec681f3Smrgprint_fs_traits(int fs_traits)
697ec681f3Smrg{
707ec681f3Smrg    const char *strings[] = {
717ec681f3Smrg	"FS_COMPOSITE",		/* = 1 << 0, */
727ec681f3Smrg	"FS_MASK",		/* = 1 << 1, */
737ec681f3Smrg	"FS_SRC_SRC",	        /* = 1 << 2, */
747ec681f3Smrg	"FS_MASK_SRC",	        /* = 1 << 3, */
757ec681f3Smrg	"FS_YUV",	        /* = 1 << 4, */
767ec681f3Smrg	"FS_SRC_REPEAT_NONE",	/* = 1 << 5, */
777ec681f3Smrg	"FS_MASK_REPEAT_NONE",	/* = 1 << 6, */
787ec681f3Smrg	"FS_SRC_SWIZZLE_RGB",	/* = 1 << 7, */
797ec681f3Smrg	"FS_MASK_SWIZZLE_RGB",	/* = 1 << 8, */
807ec681f3Smrg	"FS_SRC_SET_ALPHA",	/* = 1 << 9, */
817ec681f3Smrg	"FS_MASK_SET_ALPHA",	/* = 1 << 10, */
827ec681f3Smrg	"FS_SRC_LUMINANCE",	/* = 1 << 11, */
837ec681f3Smrg	"FS_MASK_LUMINANCE",	/* = 1 << 12, */
847ec681f3Smrg	"FS_DST_LUMINANCE",     /* = 1 << 13, */
857ec681f3Smrg        "FS_CA",                /* = 1 << 14, */
867ec681f3Smrg    };
877ec681f3Smrg    int i, k;
887ec681f3Smrg
897ec681f3Smrg    debug_printf("%s: ", __func__);
907ec681f3Smrg
917ec681f3Smrg    for (i = 0, k = 1; k < (1 << 16); i++, k <<= 1) {
927ec681f3Smrg	if (fs_traits & k)
937ec681f3Smrg	    debug_printf("%s, ", strings[i]);
947ec681f3Smrg    }
957ec681f3Smrg
967ec681f3Smrg    debug_printf("\n");
977ec681f3Smrg}
987ec681f3Smrg
997ec681f3Smrgstruct xa_shaders {
1007ec681f3Smrg    struct xa_context *r;
1017ec681f3Smrg
1027ec681f3Smrg    struct cso_hash vs_hash;
1037ec681f3Smrg    struct cso_hash fs_hash;
1047ec681f3Smrg};
1057ec681f3Smrg
1067ec681f3Smrgstatic inline void
1077ec681f3Smrgsrc_in_mask(struct ureg_program *ureg,
1087ec681f3Smrg	    struct ureg_dst dst,
1097ec681f3Smrg	    struct ureg_src src,
1107ec681f3Smrg	    struct ureg_src mask,
1117ec681f3Smrg	    unsigned mask_luminance, boolean component_alpha)
1127ec681f3Smrg{
1137ec681f3Smrg    if (mask_luminance)
1147ec681f3Smrg        if (component_alpha) {
1157ec681f3Smrg            ureg_MOV(ureg, dst, src);
1167ec681f3Smrg            ureg_MUL(ureg, ureg_writemask(dst, TGSI_WRITEMASK_W),
1177ec681f3Smrg                     src, ureg_scalar(mask, TGSI_SWIZZLE_X));
1187ec681f3Smrg        } else {
1197ec681f3Smrg            ureg_MUL(ureg, dst, src, ureg_scalar(mask, TGSI_SWIZZLE_X));
1207ec681f3Smrg        }
1217ec681f3Smrg    else if (!component_alpha)
1227ec681f3Smrg        ureg_MUL(ureg, dst, src, ureg_scalar(mask, TGSI_SWIZZLE_W));
1237ec681f3Smrg    else
1247ec681f3Smrg        ureg_MUL(ureg, dst, src, mask);
1257ec681f3Smrg}
1267ec681f3Smrg
1277ec681f3Smrgstatic struct ureg_src
1287ec681f3Smrgvs_normalize_coords(struct ureg_program *ureg,
1297ec681f3Smrg		    struct ureg_src coords,
1307ec681f3Smrg		    struct ureg_src const0, struct ureg_src const1)
1317ec681f3Smrg{
1327ec681f3Smrg    struct ureg_dst tmp = ureg_DECL_temporary(ureg);
1337ec681f3Smrg    struct ureg_src ret;
1347ec681f3Smrg
1357ec681f3Smrg    ureg_MAD(ureg, tmp, coords, const0, const1);
1367ec681f3Smrg    ret = ureg_src(tmp);
1377ec681f3Smrg    ureg_release_temporary(ureg, tmp);
1387ec681f3Smrg    return ret;
1397ec681f3Smrg}
1407ec681f3Smrg
1417ec681f3Smrgstatic void *
1427ec681f3Smrgcreate_vs(struct pipe_context *pipe, unsigned vs_traits)
1437ec681f3Smrg{
1447ec681f3Smrg    struct ureg_program *ureg;
1457ec681f3Smrg    struct ureg_src src;
1467ec681f3Smrg    struct ureg_dst dst;
1477ec681f3Smrg    struct ureg_src const0, const1;
1487ec681f3Smrg    boolean is_composite = (vs_traits & VS_COMPOSITE) != 0;
1497ec681f3Smrg    boolean has_mask = (vs_traits & VS_MASK) != 0;
1507ec681f3Smrg    boolean is_yuv = (vs_traits & VS_YUV) != 0;
1517ec681f3Smrg    boolean is_src_src = (vs_traits & VS_SRC_SRC) != 0;
1527ec681f3Smrg    boolean is_mask_src = (vs_traits & VS_MASK_SRC) != 0;
1537ec681f3Smrg    unsigned input_slot = 0;
1547ec681f3Smrg
1557ec681f3Smrg    ureg = ureg_create(PIPE_SHADER_VERTEX);
1567ec681f3Smrg    if (ureg == NULL)
1577ec681f3Smrg	return 0;
1587ec681f3Smrg
1597ec681f3Smrg    const0 = ureg_DECL_constant(ureg, 0);
1607ec681f3Smrg    const1 = ureg_DECL_constant(ureg, 1);
1617ec681f3Smrg
1627ec681f3Smrg    /* it has to be either a fill or a composite op */
1637ec681f3Smrg    src = ureg_DECL_vs_input(ureg, input_slot++);
1647ec681f3Smrg    dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
1657ec681f3Smrg    src = vs_normalize_coords(ureg, src, const0, const1);
1667ec681f3Smrg    ureg_MOV(ureg, dst, src);
1677ec681f3Smrg
1687ec681f3Smrg    if (is_yuv) {
1697ec681f3Smrg	src = ureg_DECL_vs_input(ureg, input_slot++);
1707ec681f3Smrg	dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 0);
1717ec681f3Smrg	ureg_MOV(ureg, dst, src);
1727ec681f3Smrg    }
1737ec681f3Smrg
1747ec681f3Smrg    if (is_composite) {
1757ec681f3Smrg        if (!is_src_src || (has_mask && !is_mask_src)) {
1767ec681f3Smrg            src = ureg_DECL_vs_input(ureg, input_slot++);
1777ec681f3Smrg            dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 0);
1787ec681f3Smrg            ureg_MOV(ureg, dst, src);
1797ec681f3Smrg        }
1807ec681f3Smrg
1817ec681f3Smrg        if (!is_src_src && (has_mask && !is_mask_src)) {
1827ec681f3Smrg            src = ureg_DECL_vs_input(ureg, input_slot++);
1837ec681f3Smrg            dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 1);
1847ec681f3Smrg            ureg_MOV(ureg, dst, src);
1857ec681f3Smrg        }
1867ec681f3Smrg    }
1877ec681f3Smrg
1887ec681f3Smrg    ureg_END(ureg);
1897ec681f3Smrg
1907ec681f3Smrg    return ureg_create_shader_and_destroy(ureg, pipe);
1917ec681f3Smrg}
1927ec681f3Smrg
1937ec681f3Smrgstatic void *
1947ec681f3Smrgcreate_yuv_shader(struct pipe_context *pipe, struct ureg_program *ureg)
1957ec681f3Smrg{
1967ec681f3Smrg    struct ureg_src y_sampler, u_sampler, v_sampler;
1977ec681f3Smrg    struct ureg_src pos;
1987ec681f3Smrg    struct ureg_src matrow0, matrow1, matrow2, matrow3;
1997ec681f3Smrg    struct ureg_dst y, u, v, rgb;
2007ec681f3Smrg    struct ureg_dst out = ureg_DECL_output(ureg,
2017ec681f3Smrg					   TGSI_SEMANTIC_COLOR,
2027ec681f3Smrg					   0);
2037ec681f3Smrg
2047ec681f3Smrg    pos = ureg_DECL_fs_input(ureg,
2057ec681f3Smrg			     TGSI_SEMANTIC_GENERIC, 0,
2067ec681f3Smrg			     TGSI_INTERPOLATE_PERSPECTIVE);
2077ec681f3Smrg
2087ec681f3Smrg    rgb = ureg_DECL_temporary(ureg);
2097ec681f3Smrg    y = ureg_DECL_temporary(ureg);
2107ec681f3Smrg    u = ureg_DECL_temporary(ureg);
2117ec681f3Smrg    v = ureg_DECL_temporary(ureg);
2127ec681f3Smrg
2137ec681f3Smrg    y_sampler = ureg_DECL_sampler(ureg, 0);
2147ec681f3Smrg    u_sampler = ureg_DECL_sampler(ureg, 1);
2157ec681f3Smrg    v_sampler = ureg_DECL_sampler(ureg, 2);
2167ec681f3Smrg
2177ec681f3Smrg    ureg_DECL_sampler_view(ureg, 0, TGSI_TEXTURE_2D,
2187ec681f3Smrg                           TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT,
2197ec681f3Smrg                           TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT);
2207ec681f3Smrg    ureg_DECL_sampler_view(ureg, 1, TGSI_TEXTURE_2D,
2217ec681f3Smrg                           TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT,
2227ec681f3Smrg                           TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT);
2237ec681f3Smrg    ureg_DECL_sampler_view(ureg, 2, TGSI_TEXTURE_2D,
2247ec681f3Smrg                           TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT,
2257ec681f3Smrg                           TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT);
2267ec681f3Smrg
2277ec681f3Smrg    matrow0 = ureg_DECL_constant(ureg, 0);
2287ec681f3Smrg    matrow1 = ureg_DECL_constant(ureg, 1);
2297ec681f3Smrg    matrow2 = ureg_DECL_constant(ureg, 2);
2307ec681f3Smrg    matrow3 = ureg_DECL_constant(ureg, 3);
2317ec681f3Smrg
2327ec681f3Smrg    ureg_TEX(ureg, y, TGSI_TEXTURE_2D, pos, y_sampler);
2337ec681f3Smrg    ureg_TEX(ureg, u, TGSI_TEXTURE_2D, pos, u_sampler);
2347ec681f3Smrg    ureg_TEX(ureg, v, TGSI_TEXTURE_2D, pos, v_sampler);
2357ec681f3Smrg
2367ec681f3Smrg    ureg_MOV(ureg, rgb, matrow3);
2377ec681f3Smrg    ureg_MAD(ureg, rgb,
2387ec681f3Smrg	     ureg_scalar(ureg_src(y), TGSI_SWIZZLE_X), matrow0, ureg_src(rgb));
2397ec681f3Smrg    ureg_MAD(ureg, rgb,
2407ec681f3Smrg	     ureg_scalar(ureg_src(u), TGSI_SWIZZLE_X), matrow1, ureg_src(rgb));
2417ec681f3Smrg    ureg_MAD(ureg, rgb,
2427ec681f3Smrg	     ureg_scalar(ureg_src(v), TGSI_SWIZZLE_X), matrow2, ureg_src(rgb));
2437ec681f3Smrg
2447ec681f3Smrg    ureg_MOV(ureg, out, ureg_src(rgb));
2457ec681f3Smrg
2467ec681f3Smrg    ureg_release_temporary(ureg, rgb);
2477ec681f3Smrg    ureg_release_temporary(ureg, y);
2487ec681f3Smrg    ureg_release_temporary(ureg, u);
2497ec681f3Smrg    ureg_release_temporary(ureg, v);
2507ec681f3Smrg
2517ec681f3Smrg    ureg_END(ureg);
2527ec681f3Smrg
2537ec681f3Smrg    return ureg_create_shader_and_destroy(ureg, pipe);
2547ec681f3Smrg}
2557ec681f3Smrg
2567ec681f3Smrgstatic inline void
2577ec681f3Smrgxrender_tex(struct ureg_program *ureg,
2587ec681f3Smrg	    struct ureg_dst dst,
2597ec681f3Smrg	    struct ureg_src coords,
2607ec681f3Smrg	    struct ureg_src sampler,
2617ec681f3Smrg	    const struct ureg_src *imm0,
2627ec681f3Smrg	    boolean repeat_none, boolean swizzle, boolean set_alpha)
2637ec681f3Smrg{
2647ec681f3Smrg    if (repeat_none) {
2657ec681f3Smrg	struct ureg_dst tmp0 = ureg_DECL_temporary(ureg);
2667ec681f3Smrg	struct ureg_dst tmp1 = ureg_DECL_temporary(ureg);
2677ec681f3Smrg
2687ec681f3Smrg	ureg_SGT(ureg, tmp1, ureg_swizzle(coords,
2697ec681f3Smrg					  TGSI_SWIZZLE_X,
2707ec681f3Smrg					  TGSI_SWIZZLE_Y,
2717ec681f3Smrg					  TGSI_SWIZZLE_X,
2727ec681f3Smrg					  TGSI_SWIZZLE_Y), ureg_scalar(*imm0,
2737ec681f3Smrg								       TGSI_SWIZZLE_X));
2747ec681f3Smrg	ureg_SLT(ureg, tmp0,
2757ec681f3Smrg		 ureg_swizzle(coords, TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y,
2767ec681f3Smrg			      TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y), ureg_scalar(*imm0,
2777ec681f3Smrg									   TGSI_SWIZZLE_W));
2787ec681f3Smrg	ureg_MIN(ureg, tmp0, ureg_src(tmp0), ureg_src(tmp1));
2797ec681f3Smrg	ureg_MIN(ureg, tmp0, ureg_scalar(ureg_src(tmp0), TGSI_SWIZZLE_X),
2807ec681f3Smrg		 ureg_scalar(ureg_src(tmp0), TGSI_SWIZZLE_Y));
2817ec681f3Smrg	ureg_TEX(ureg, tmp1, TGSI_TEXTURE_2D, coords, sampler);
2827ec681f3Smrg	if (swizzle)
2837ec681f3Smrg	    ureg_MOV(ureg, tmp1, ureg_swizzle(ureg_src(tmp1),
2847ec681f3Smrg					      TGSI_SWIZZLE_Z,
2857ec681f3Smrg					      TGSI_SWIZZLE_Y, TGSI_SWIZZLE_X,
2867ec681f3Smrg					      TGSI_SWIZZLE_W));
2877ec681f3Smrg	if (set_alpha)
2887ec681f3Smrg	    ureg_MOV(ureg,
2897ec681f3Smrg		     ureg_writemask(tmp1, TGSI_WRITEMASK_W),
2907ec681f3Smrg		     ureg_scalar(*imm0, TGSI_SWIZZLE_W));
2917ec681f3Smrg	ureg_MUL(ureg, dst, ureg_src(tmp1), ureg_src(tmp0));
2927ec681f3Smrg	ureg_release_temporary(ureg, tmp0);
2937ec681f3Smrg	ureg_release_temporary(ureg, tmp1);
2947ec681f3Smrg    } else {
2957ec681f3Smrg	if (swizzle) {
2967ec681f3Smrg	    struct ureg_dst tmp = ureg_DECL_temporary(ureg);
2977ec681f3Smrg
2987ec681f3Smrg	    ureg_TEX(ureg, tmp, TGSI_TEXTURE_2D, coords, sampler);
2997ec681f3Smrg	    ureg_MOV(ureg, dst, ureg_swizzle(ureg_src(tmp),
3007ec681f3Smrg					     TGSI_SWIZZLE_Z,
3017ec681f3Smrg					     TGSI_SWIZZLE_Y, TGSI_SWIZZLE_X,
3027ec681f3Smrg					     TGSI_SWIZZLE_W));
3037ec681f3Smrg	    ureg_release_temporary(ureg, tmp);
3047ec681f3Smrg	} else {
3057ec681f3Smrg	    ureg_TEX(ureg, dst, TGSI_TEXTURE_2D, coords, sampler);
3067ec681f3Smrg	}
3077ec681f3Smrg	if (set_alpha)
3087ec681f3Smrg	    ureg_MOV(ureg,
3097ec681f3Smrg		     ureg_writemask(dst, TGSI_WRITEMASK_W),
3107ec681f3Smrg		     ureg_scalar(*imm0, TGSI_SWIZZLE_W));
3117ec681f3Smrg    }
3127ec681f3Smrg}
3137ec681f3Smrg
3147ec681f3Smrgstatic void
3157ec681f3Smrgread_input(struct ureg_program *ureg,
3167ec681f3Smrg           struct ureg_dst dst,
3177ec681f3Smrg           const struct ureg_src *imm0,
3187ec681f3Smrg           boolean repeat_none, boolean swizzle, boolean set_alpha,
3197ec681f3Smrg           boolean is_src, unsigned *cur_constant, unsigned *cur_sampler)
3207ec681f3Smrg{
3217ec681f3Smrg    struct ureg_src input, sampler;
3227ec681f3Smrg
3237ec681f3Smrg    if (is_src) {
3247ec681f3Smrg        input = ureg_DECL_constant(ureg, (*cur_constant)++);
3257ec681f3Smrg        ureg_MOV(ureg, dst, input);
3267ec681f3Smrg    } else {
3277ec681f3Smrg        sampler = ureg_DECL_sampler(ureg, *cur_sampler);
3287ec681f3Smrg        ureg_DECL_sampler_view(ureg, *cur_sampler, TGSI_TEXTURE_2D,
3297ec681f3Smrg                               TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT,
3307ec681f3Smrg                               TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT);
3317ec681f3Smrg        input = ureg_DECL_fs_input(ureg,
3327ec681f3Smrg                                   TGSI_SEMANTIC_GENERIC, (*cur_sampler)++,
3337ec681f3Smrg                                   TGSI_INTERPOLATE_PERSPECTIVE);
3347ec681f3Smrg        xrender_tex(ureg, dst, input, sampler, imm0,
3357ec681f3Smrg                    repeat_none, swizzle, set_alpha);
3367ec681f3Smrg    }
3377ec681f3Smrg}
3387ec681f3Smrg
3397ec681f3Smrgstatic void *
3407ec681f3Smrgcreate_fs(struct pipe_context *pipe, unsigned fs_traits)
3417ec681f3Smrg{
3427ec681f3Smrg    struct ureg_program *ureg;
3437ec681f3Smrg    struct ureg_dst src, mask;
3447ec681f3Smrg    struct ureg_dst out;
3457ec681f3Smrg    struct ureg_src imm0 = { 0 };
3467ec681f3Smrg    unsigned has_mask = (fs_traits & FS_MASK) != 0;
3477ec681f3Smrg    unsigned is_yuv = (fs_traits & FS_YUV) != 0;
3487ec681f3Smrg    unsigned src_repeat_none = (fs_traits & FS_SRC_REPEAT_NONE) != 0;
3497ec681f3Smrg    unsigned mask_repeat_none = (fs_traits & FS_MASK_REPEAT_NONE) != 0;
3507ec681f3Smrg    unsigned src_swizzle = (fs_traits & FS_SRC_SWIZZLE_RGB) != 0;
3517ec681f3Smrg    unsigned mask_swizzle = (fs_traits & FS_MASK_SWIZZLE_RGB) != 0;
3527ec681f3Smrg    unsigned src_set_alpha = (fs_traits & FS_SRC_SET_ALPHA) != 0;
3537ec681f3Smrg    unsigned mask_set_alpha = (fs_traits & FS_MASK_SET_ALPHA) != 0;
3547ec681f3Smrg    unsigned src_luminance = (fs_traits & FS_SRC_LUMINANCE) != 0;
3557ec681f3Smrg    unsigned mask_luminance = (fs_traits & FS_MASK_LUMINANCE) != 0;
3567ec681f3Smrg    unsigned dst_luminance = (fs_traits & FS_DST_LUMINANCE) != 0;
3577ec681f3Smrg    unsigned is_src_src = (fs_traits & FS_SRC_SRC) != 0;
3587ec681f3Smrg    unsigned is_mask_src = (fs_traits & FS_MASK_SRC) != 0;
3597ec681f3Smrg    boolean component_alpha = (fs_traits & FS_CA) != 0;
3607ec681f3Smrg    unsigned cur_sampler = 0;
3617ec681f3Smrg    unsigned cur_constant = 0;
3627ec681f3Smrg
3637ec681f3Smrg#if 0
3647ec681f3Smrg    print_fs_traits(fs_traits);
3657ec681f3Smrg#else
3667ec681f3Smrg    (void)print_fs_traits;
3677ec681f3Smrg#endif
3687ec681f3Smrg
3697ec681f3Smrg    ureg = ureg_create(PIPE_SHADER_FRAGMENT);
3707ec681f3Smrg    if (ureg == NULL)
3717ec681f3Smrg	return 0;
3727ec681f3Smrg
3737ec681f3Smrg    if (is_yuv)
3747ec681f3Smrg       return create_yuv_shader(pipe, ureg);
3757ec681f3Smrg
3767ec681f3Smrg    out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
3777ec681f3Smrg
3787ec681f3Smrg    if (src_repeat_none || mask_repeat_none ||
3797ec681f3Smrg	src_set_alpha || mask_set_alpha || src_luminance) {
3807ec681f3Smrg	imm0 = ureg_imm4f(ureg, 0, 0, 0, 1);
3817ec681f3Smrg    }
3827ec681f3Smrg
3837ec681f3Smrg    src = (has_mask || src_luminance || dst_luminance) ?
3847ec681f3Smrg        ureg_DECL_temporary(ureg) : out;
3857ec681f3Smrg
3867ec681f3Smrg    read_input(ureg, src, &imm0, src_repeat_none, src_swizzle,
3877ec681f3Smrg               src_set_alpha, is_src_src, &cur_constant, &cur_sampler);
3887ec681f3Smrg
3897ec681f3Smrg    if (src_luminance) {
3907ec681f3Smrg	ureg_MOV(ureg, src, ureg_scalar(ureg_src(src), TGSI_SWIZZLE_X));
3917ec681f3Smrg	ureg_MOV(ureg, ureg_writemask(src, TGSI_WRITEMASK_XYZ),
3927ec681f3Smrg		 ureg_scalar(imm0, TGSI_SWIZZLE_X));
3937ec681f3Smrg	if (!has_mask && !dst_luminance)
3947ec681f3Smrg	    ureg_MOV(ureg, out, ureg_src(src));
3957ec681f3Smrg    }
3967ec681f3Smrg
3977ec681f3Smrg    if (has_mask) {
3987ec681f3Smrg	mask = ureg_DECL_temporary(ureg);
3997ec681f3Smrg        read_input(ureg, mask, &imm0, mask_repeat_none,
4007ec681f3Smrg                   mask_swizzle, mask_set_alpha, is_mask_src, &cur_constant,
4017ec681f3Smrg                   &cur_sampler);
4027ec681f3Smrg
4037ec681f3Smrg	src_in_mask(ureg, (dst_luminance) ? src : out, ureg_src(src),
4047ec681f3Smrg		    ureg_src(mask), mask_luminance, component_alpha);
4057ec681f3Smrg
4067ec681f3Smrg	ureg_release_temporary(ureg, mask);
4077ec681f3Smrg    }
4087ec681f3Smrg
4097ec681f3Smrg    if (dst_luminance) {
4107ec681f3Smrg	/*
4117ec681f3Smrg	 * Make sure the alpha channel goes into the output L8 surface.
4127ec681f3Smrg	 */
4137ec681f3Smrg	ureg_MOV(ureg, out, ureg_scalar(ureg_src(src), TGSI_SWIZZLE_W));
4147ec681f3Smrg    }
4157ec681f3Smrg
4167ec681f3Smrg    ureg_END(ureg);
4177ec681f3Smrg
4187ec681f3Smrg    return ureg_create_shader_and_destroy(ureg, pipe);
4197ec681f3Smrg}
4207ec681f3Smrg
4217ec681f3Smrgstruct xa_shaders *
4227ec681f3Smrgxa_shaders_create(struct xa_context *r)
4237ec681f3Smrg{
4247ec681f3Smrg    struct xa_shaders *sc = CALLOC_STRUCT(xa_shaders);
4257ec681f3Smrg
4267ec681f3Smrg    sc->r = r;
4277ec681f3Smrg    cso_hash_init(&sc->vs_hash);
4287ec681f3Smrg    cso_hash_init(&sc->fs_hash);
4297ec681f3Smrg
4307ec681f3Smrg    return sc;
4317ec681f3Smrg}
4327ec681f3Smrg
4337ec681f3Smrgstatic void
4347ec681f3Smrgcache_destroy(struct pipe_context *pipe,
4357ec681f3Smrg	      struct cso_hash *hash, unsigned processor)
4367ec681f3Smrg{
4377ec681f3Smrg    struct cso_hash_iter iter = cso_hash_first_node(hash);
4387ec681f3Smrg
4397ec681f3Smrg    while (!cso_hash_iter_is_null(iter)) {
4407ec681f3Smrg	void *shader = (void *)cso_hash_iter_data(iter);
4417ec681f3Smrg
4427ec681f3Smrg	if (processor == PIPE_SHADER_FRAGMENT) {
4437ec681f3Smrg	    pipe->delete_fs_state(pipe, shader);
4447ec681f3Smrg	} else if (processor == PIPE_SHADER_VERTEX) {
4457ec681f3Smrg	    pipe->delete_vs_state(pipe, shader);
4467ec681f3Smrg	}
4477ec681f3Smrg	iter = cso_hash_erase(hash, iter);
4487ec681f3Smrg    }
4497ec681f3Smrg    cso_hash_deinit(hash);
4507ec681f3Smrg}
4517ec681f3Smrg
4527ec681f3Smrgvoid
4537ec681f3Smrgxa_shaders_destroy(struct xa_shaders *sc)
4547ec681f3Smrg{
4557ec681f3Smrg    cache_destroy(sc->r->pipe, &sc->vs_hash, PIPE_SHADER_VERTEX);
4567ec681f3Smrg    cache_destroy(sc->r->pipe, &sc->fs_hash, PIPE_SHADER_FRAGMENT);
4577ec681f3Smrg
4587ec681f3Smrg    FREE(sc);
4597ec681f3Smrg}
4607ec681f3Smrg
4617ec681f3Smrgstatic inline void *
4627ec681f3Smrgshader_from_cache(struct pipe_context *pipe,
4637ec681f3Smrg		  unsigned type, struct cso_hash *hash, unsigned key)
4647ec681f3Smrg{
4657ec681f3Smrg    void *shader = 0;
4667ec681f3Smrg
4677ec681f3Smrg    struct cso_hash_iter iter = cso_hash_find(hash, key);
4687ec681f3Smrg
4697ec681f3Smrg    if (cso_hash_iter_is_null(iter)) {
4707ec681f3Smrg	if (type == PIPE_SHADER_VERTEX)
4717ec681f3Smrg	    shader = create_vs(pipe, key);
4727ec681f3Smrg	else
4737ec681f3Smrg	    shader = create_fs(pipe, key);
4747ec681f3Smrg	cso_hash_insert(hash, key, shader);
4757ec681f3Smrg    } else
4767ec681f3Smrg	shader = (void *)cso_hash_iter_data(iter);
4777ec681f3Smrg
4787ec681f3Smrg    return shader;
4797ec681f3Smrg}
4807ec681f3Smrg
4817ec681f3Smrgstruct xa_shader
4827ec681f3Smrgxa_shaders_get(struct xa_shaders *sc, unsigned vs_traits, unsigned fs_traits)
4837ec681f3Smrg{
4847ec681f3Smrg    struct xa_shader shader = { NULL, NULL };
4857ec681f3Smrg    void *vs, *fs;
4867ec681f3Smrg
4877ec681f3Smrg    vs = shader_from_cache(sc->r->pipe, PIPE_SHADER_VERTEX,
4887ec681f3Smrg			   &sc->vs_hash, vs_traits);
4897ec681f3Smrg    fs = shader_from_cache(sc->r->pipe, PIPE_SHADER_FRAGMENT,
4907ec681f3Smrg			   &sc->fs_hash, fs_traits);
4917ec681f3Smrg
4927ec681f3Smrg    debug_assert(vs && fs);
4937ec681f3Smrg    if (!vs || !fs)
4947ec681f3Smrg	return shader;
4957ec681f3Smrg
4967ec681f3Smrg    shader.vs = vs;
4977ec681f3Smrg    shader.fs = fs;
4987ec681f3Smrg
4997ec681f3Smrg    return shader;
5007ec681f3Smrg}
501