1/**********************************************************
2 * Copyright 2009-2011 VMware, Inc. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 *********************************************************
25 * Authors:
26 * Zack Rusin <zackr-at-vmware-dot-com>
27 */
28#include "xa_priv.h"
29
30#include "pipe/p_format.h"
31#include "pipe/p_context.h"
32#include "pipe/p_state.h"
33#include "pipe/p_shader_tokens.h"
34
35#include "util/u_memory.h"
36
37#include "tgsi/tgsi_ureg.h"
38
39#include "cso_cache/cso_context.h"
40#include "cso_cache/cso_hash.h"
41
42/* Vertex shader:
43 * IN[0]    = vertex pos
44 * IN[1]    = src tex coord | solid fill color
45 * IN[2]    = mask tex coord
46 * IN[3]    = dst tex coord
47 * CONST[0] = (2/dst_width, 2/dst_height, 1, 1)
48 * CONST[1] = (-1, -1, 0, 0)
49 *
50 * OUT[0]   = vertex pos
51 * OUT[1]   = src tex coord | solid fill color
52 * OUT[2]   = mask tex coord
53 * OUT[3]   = dst tex coord
54 */
55
56/* Fragment shader:
57 * SAMP[0]  = src
58 * SAMP[1]  = mask
59 * SAMP[2]  = dst
60 * IN[0]    = pos src | solid fill color
61 * IN[1]    = pos mask
62 * IN[2]    = pos dst
63 * CONST[0] = (0, 0, 0, 1)
64 *
65 * OUT[0] = color
66 */
67
68static void
69print_fs_traits(int fs_traits)
70{
71    const char *strings[] = {
72	"FS_COMPOSITE",		/* = 1 << 0, */
73	"FS_MASK",		/* = 1 << 1, */
74	"FS_SOLID_FILL",	/* = 1 << 2, */
75	"FS_LINGRAD_FILL",	/* = 1 << 3, */
76	"FS_RADGRAD_FILL",	/* = 1 << 4, */
77	"FS_CA_FULL",		/* = 1 << 5, *//* src.rgba * mask.rgba */
78	"FS_CA_SRCALPHA",	/* = 1 << 6, *//* src.aaaa * mask.rgba */
79	"FS_YUV",		/* = 1 << 7, */
80	"FS_SRC_REPEAT_NONE",	/* = 1 << 8, */
81	"FS_MASK_REPEAT_NONE",	/* = 1 << 9, */
82	"FS_SRC_SWIZZLE_RGB",	/* = 1 << 10, */
83	"FS_MASK_SWIZZLE_RGB",	/* = 1 << 11, */
84	"FS_SRC_SET_ALPHA",	/* = 1 << 12, */
85	"FS_MASK_SET_ALPHA",	/* = 1 << 13, */
86	"FS_SRC_LUMINANCE",	/* = 1 << 14, */
87	"FS_MASK_LUMINANCE",	/* = 1 << 15, */
88	"FS_DST_LUMINANCE",     /* = 1 << 15, */
89    };
90    int i, k;
91
92    debug_printf("%s: ", __func__);
93
94    for (i = 0, k = 1; k < (1 << 16); i++, k <<= 1) {
95	if (fs_traits & k)
96	    debug_printf("%s, ", strings[i]);
97    }
98
99    debug_printf("\n");
100}
101
102struct xa_shaders {
103    struct xa_context *r;
104
105    struct cso_hash *vs_hash;
106    struct cso_hash *fs_hash;
107};
108
109static INLINE void
110src_in_mask(struct ureg_program *ureg,
111	    struct ureg_dst dst,
112	    struct ureg_src src,
113	    struct ureg_src mask,
114	    unsigned component_alpha, unsigned mask_luminance)
115{
116    if (component_alpha == FS_CA_FULL) {
117	ureg_MUL(ureg, dst, src, mask);
118    } else if (component_alpha == FS_CA_SRCALPHA) {
119	ureg_MUL(ureg, dst, ureg_scalar(src, TGSI_SWIZZLE_W), mask);
120    } else {
121	if (mask_luminance)
122	    ureg_MUL(ureg, dst, src, ureg_scalar(mask, TGSI_SWIZZLE_X));
123	else
124	    ureg_MUL(ureg, dst, src, ureg_scalar(mask, TGSI_SWIZZLE_W));
125    }
126}
127
128static struct ureg_src
129vs_normalize_coords(struct ureg_program *ureg,
130		    struct ureg_src coords,
131		    struct ureg_src const0, struct ureg_src const1)
132{
133    struct ureg_dst tmp = ureg_DECL_temporary(ureg);
134    struct ureg_src ret;
135
136    ureg_MAD(ureg, tmp, coords, const0, const1);
137    ret = ureg_src(tmp);
138    ureg_release_temporary(ureg, tmp);
139    return ret;
140}
141
142static void
143linear_gradient(struct ureg_program *ureg,
144		struct ureg_dst out,
145		struct ureg_src pos,
146		struct ureg_src sampler,
147		struct ureg_src coords,
148		struct ureg_src const0124,
149		struct ureg_src matrow0,
150		struct ureg_src matrow1, struct ureg_src matrow2)
151{
152    struct ureg_dst temp0 = ureg_DECL_temporary(ureg);
153    struct ureg_dst temp1 = ureg_DECL_temporary(ureg);
154    struct ureg_dst temp2 = ureg_DECL_temporary(ureg);
155    struct ureg_dst temp3 = ureg_DECL_temporary(ureg);
156    struct ureg_dst temp4 = ureg_DECL_temporary(ureg);
157    struct ureg_dst temp5 = ureg_DECL_temporary(ureg);
158
159    ureg_MOV(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_XY), pos);
160    ureg_MOV(ureg,
161	     ureg_writemask(temp0, TGSI_WRITEMASK_Z),
162	     ureg_scalar(const0124, TGSI_SWIZZLE_Y));
163
164    ureg_DP3(ureg, temp1, matrow0, ureg_src(temp0));
165    ureg_DP3(ureg, temp2, matrow1, ureg_src(temp0));
166    ureg_DP3(ureg, temp3, matrow2, ureg_src(temp0));
167    ureg_RCP(ureg, temp3, ureg_src(temp3));
168    ureg_MUL(ureg, temp1, ureg_src(temp1), ureg_src(temp3));
169    ureg_MUL(ureg, temp2, ureg_src(temp2), ureg_src(temp3));
170
171    ureg_MOV(ureg, ureg_writemask(temp4, TGSI_WRITEMASK_X), ureg_src(temp1));
172    ureg_MOV(ureg, ureg_writemask(temp4, TGSI_WRITEMASK_Y), ureg_src(temp2));
173
174    ureg_MUL(ureg, temp0,
175	     ureg_scalar(coords, TGSI_SWIZZLE_Y),
176	     ureg_scalar(ureg_src(temp4), TGSI_SWIZZLE_Y));
177    ureg_MAD(ureg, temp1,
178	     ureg_scalar(coords, TGSI_SWIZZLE_X),
179	     ureg_scalar(ureg_src(temp4), TGSI_SWIZZLE_X), ureg_src(temp0));
180
181    ureg_MUL(ureg, temp2, ureg_src(temp1), ureg_scalar(coords, TGSI_SWIZZLE_Z));
182
183    ureg_TEX(ureg, out, TGSI_TEXTURE_1D, ureg_src(temp2), sampler);
184
185    ureg_release_temporary(ureg, temp0);
186    ureg_release_temporary(ureg, temp1);
187    ureg_release_temporary(ureg, temp2);
188    ureg_release_temporary(ureg, temp3);
189    ureg_release_temporary(ureg, temp4);
190    ureg_release_temporary(ureg, temp5);
191}
192
193static void
194radial_gradient(struct ureg_program *ureg,
195		struct ureg_dst out,
196		struct ureg_src pos,
197		struct ureg_src sampler,
198		struct ureg_src coords,
199		struct ureg_src const0124,
200		struct ureg_src matrow0,
201		struct ureg_src matrow1, struct ureg_src matrow2)
202{
203    struct ureg_dst temp0 = ureg_DECL_temporary(ureg);
204    struct ureg_dst temp1 = ureg_DECL_temporary(ureg);
205    struct ureg_dst temp2 = ureg_DECL_temporary(ureg);
206    struct ureg_dst temp3 = ureg_DECL_temporary(ureg);
207    struct ureg_dst temp4 = ureg_DECL_temporary(ureg);
208    struct ureg_dst temp5 = ureg_DECL_temporary(ureg);
209
210    ureg_MOV(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_XY), pos);
211    ureg_MOV(ureg,
212	     ureg_writemask(temp0, TGSI_WRITEMASK_Z),
213	     ureg_scalar(const0124, TGSI_SWIZZLE_Y));
214
215    ureg_DP3(ureg, temp1, matrow0, ureg_src(temp0));
216    ureg_DP3(ureg, temp2, matrow1, ureg_src(temp0));
217    ureg_DP3(ureg, temp3, matrow2, ureg_src(temp0));
218    ureg_RCP(ureg, temp3, ureg_src(temp3));
219    ureg_MUL(ureg, temp1, ureg_src(temp1), ureg_src(temp3));
220    ureg_MUL(ureg, temp2, ureg_src(temp2), ureg_src(temp3));
221
222    ureg_MOV(ureg, ureg_writemask(temp5, TGSI_WRITEMASK_X), ureg_src(temp1));
223    ureg_MOV(ureg, ureg_writemask(temp5, TGSI_WRITEMASK_Y), ureg_src(temp2));
224
225    ureg_MUL(ureg, temp0, ureg_scalar(coords, TGSI_SWIZZLE_Y),
226	     ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y));
227    ureg_MAD(ureg, temp1,
228	     ureg_scalar(coords, TGSI_SWIZZLE_X),
229	     ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X), ureg_src(temp0));
230    ureg_ADD(ureg, temp1, ureg_src(temp1), ureg_src(temp1));
231    ureg_MUL(ureg, temp3,
232	     ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y),
233	     ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y));
234    ureg_MAD(ureg, temp4,
235	     ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X),
236	     ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X), ureg_src(temp3));
237    ureg_MOV(ureg, temp4, ureg_negate(ureg_src(temp4)));
238    ureg_MUL(ureg, temp2, ureg_scalar(coords, TGSI_SWIZZLE_Z), ureg_src(temp4));
239    ureg_MUL(ureg, temp0,
240	     ureg_scalar(const0124, TGSI_SWIZZLE_W), ureg_src(temp2));
241    ureg_MUL(ureg, temp3, ureg_src(temp1), ureg_src(temp1));
242    ureg_SUB(ureg, temp2, ureg_src(temp3), ureg_src(temp0));
243    ureg_RSQ(ureg, temp2, ureg_abs(ureg_src(temp2)));
244    ureg_RCP(ureg, temp2, ureg_src(temp2));
245    ureg_SUB(ureg, temp1, ureg_src(temp2), ureg_src(temp1));
246    ureg_ADD(ureg, temp0,
247	     ureg_scalar(coords, TGSI_SWIZZLE_Z),
248	     ureg_scalar(coords, TGSI_SWIZZLE_Z));
249    ureg_RCP(ureg, temp0, ureg_src(temp0));
250    ureg_MUL(ureg, temp2, ureg_src(temp1), ureg_src(temp0));
251    ureg_TEX(ureg, out, TGSI_TEXTURE_1D, ureg_src(temp2), sampler);
252
253    ureg_release_temporary(ureg, temp0);
254    ureg_release_temporary(ureg, temp1);
255    ureg_release_temporary(ureg, temp2);
256    ureg_release_temporary(ureg, temp3);
257    ureg_release_temporary(ureg, temp4);
258    ureg_release_temporary(ureg, temp5);
259}
260
261static void *
262create_vs(struct pipe_context *pipe, unsigned vs_traits)
263{
264    struct ureg_program *ureg;
265    struct ureg_src src;
266    struct ureg_dst dst;
267    struct ureg_src const0, const1;
268    boolean is_fill = (vs_traits & VS_FILL) != 0;
269    boolean is_composite = (vs_traits & VS_COMPOSITE) != 0;
270    boolean has_mask = (vs_traits & VS_MASK) != 0;
271    boolean is_yuv = (vs_traits & VS_YUV) != 0;
272    unsigned input_slot = 0;
273
274    ureg = ureg_create(TGSI_PROCESSOR_VERTEX);
275    if (ureg == NULL)
276	return 0;
277
278    const0 = ureg_DECL_constant(ureg, 0);
279    const1 = ureg_DECL_constant(ureg, 1);
280
281    /* it has to be either a fill or a composite op */
282    debug_assert((is_fill ^ is_composite) ^ is_yuv);
283
284    src = ureg_DECL_vs_input(ureg, input_slot++);
285    dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
286    src = vs_normalize_coords(ureg, src, const0, const1);
287    ureg_MOV(ureg, dst, src);
288
289    if (is_yuv) {
290	src = ureg_DECL_vs_input(ureg, input_slot++);
291	dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 0);
292	ureg_MOV(ureg, dst, src);
293    }
294
295    if (is_composite) {
296	src = ureg_DECL_vs_input(ureg, input_slot++);
297	dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 0);
298	ureg_MOV(ureg, dst, src);
299    }
300
301    if (is_fill) {
302	src = ureg_DECL_vs_input(ureg, input_slot++);
303	dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
304	ureg_MOV(ureg, dst, src);
305    }
306
307    if (has_mask) {
308	src = ureg_DECL_vs_input(ureg, input_slot++);
309	dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 1);
310	ureg_MOV(ureg, dst, src);
311    }
312
313    ureg_END(ureg);
314
315    return ureg_create_shader_and_destroy(ureg, pipe);
316}
317
318static void *
319create_yuv_shader(struct pipe_context *pipe, struct ureg_program *ureg)
320{
321    struct ureg_src y_sampler, u_sampler, v_sampler;
322    struct ureg_src pos;
323    struct ureg_src matrow0, matrow1, matrow2, matrow3;
324    struct ureg_dst y, u, v, rgb;
325    struct ureg_dst out = ureg_DECL_output(ureg,
326					   TGSI_SEMANTIC_COLOR,
327					   0);
328
329    pos = ureg_DECL_fs_input(ureg,
330			     TGSI_SEMANTIC_GENERIC, 0,
331			     TGSI_INTERPOLATE_PERSPECTIVE);
332
333    rgb = ureg_DECL_temporary(ureg);
334    y = ureg_DECL_temporary(ureg);
335    u = ureg_DECL_temporary(ureg);
336    v = ureg_DECL_temporary(ureg);
337
338    y_sampler = ureg_DECL_sampler(ureg, 0);
339    u_sampler = ureg_DECL_sampler(ureg, 1);
340    v_sampler = ureg_DECL_sampler(ureg, 2);
341
342    matrow0 = ureg_DECL_constant(ureg, 0);
343    matrow1 = ureg_DECL_constant(ureg, 1);
344    matrow2 = ureg_DECL_constant(ureg, 2);
345    matrow3 = ureg_DECL_constant(ureg, 3);
346
347    ureg_TEX(ureg, y, TGSI_TEXTURE_2D, pos, y_sampler);
348    ureg_TEX(ureg, u, TGSI_TEXTURE_2D, pos, u_sampler);
349    ureg_TEX(ureg, v, TGSI_TEXTURE_2D, pos, v_sampler);
350
351    ureg_MOV(ureg, rgb, matrow3);
352    ureg_MAD(ureg, rgb,
353	     ureg_scalar(ureg_src(y), TGSI_SWIZZLE_X), matrow0, ureg_src(rgb));
354    ureg_MAD(ureg, rgb,
355	     ureg_scalar(ureg_src(u), TGSI_SWIZZLE_X), matrow1, ureg_src(rgb));
356    ureg_MAD(ureg, rgb,
357	     ureg_scalar(ureg_src(v), TGSI_SWIZZLE_X), matrow2, ureg_src(rgb));
358
359    ureg_MOV(ureg, out, ureg_src(rgb));
360
361    ureg_release_temporary(ureg, rgb);
362    ureg_release_temporary(ureg, y);
363    ureg_release_temporary(ureg, u);
364    ureg_release_temporary(ureg, v);
365
366    ureg_END(ureg);
367
368    return ureg_create_shader_and_destroy(ureg, pipe);
369}
370
371static INLINE void
372xrender_tex(struct ureg_program *ureg,
373	    struct ureg_dst dst,
374	    struct ureg_src coords,
375	    struct ureg_src sampler,
376	    struct ureg_src imm0,
377	    boolean repeat_none, boolean swizzle, boolean set_alpha)
378{
379    if (repeat_none) {
380	struct ureg_dst tmp0 = ureg_DECL_temporary(ureg);
381	struct ureg_dst tmp1 = ureg_DECL_temporary(ureg);
382
383	ureg_SGT(ureg, tmp1, ureg_swizzle(coords,
384					  TGSI_SWIZZLE_X,
385					  TGSI_SWIZZLE_Y,
386					  TGSI_SWIZZLE_X,
387					  TGSI_SWIZZLE_Y), ureg_scalar(imm0,
388								       TGSI_SWIZZLE_X));
389	ureg_SLT(ureg, tmp0,
390		 ureg_swizzle(coords, TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y,
391			      TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y), ureg_scalar(imm0,
392									   TGSI_SWIZZLE_W));
393	ureg_MIN(ureg, tmp0, ureg_src(tmp0), ureg_src(tmp1));
394	ureg_MIN(ureg, tmp0, ureg_scalar(ureg_src(tmp0), TGSI_SWIZZLE_X),
395		 ureg_scalar(ureg_src(tmp0), TGSI_SWIZZLE_Y));
396	ureg_TEX(ureg, tmp1, TGSI_TEXTURE_2D, coords, sampler);
397	if (swizzle)
398	    ureg_MOV(ureg, tmp1, ureg_swizzle(ureg_src(tmp1),
399					      TGSI_SWIZZLE_Z,
400					      TGSI_SWIZZLE_Y, TGSI_SWIZZLE_X,
401					      TGSI_SWIZZLE_W));
402	if (set_alpha)
403	    ureg_MOV(ureg,
404		     ureg_writemask(tmp1, TGSI_WRITEMASK_W),
405		     ureg_scalar(imm0, TGSI_SWIZZLE_W));
406	ureg_MUL(ureg, dst, ureg_src(tmp1), ureg_src(tmp0));
407	ureg_release_temporary(ureg, tmp0);
408	ureg_release_temporary(ureg, tmp1);
409    } else {
410	if (swizzle) {
411	    struct ureg_dst tmp = ureg_DECL_temporary(ureg);
412
413	    ureg_TEX(ureg, tmp, TGSI_TEXTURE_2D, coords, sampler);
414	    ureg_MOV(ureg, dst, ureg_swizzle(ureg_src(tmp),
415					     TGSI_SWIZZLE_Z,
416					     TGSI_SWIZZLE_Y, TGSI_SWIZZLE_X,
417					     TGSI_SWIZZLE_W));
418	    ureg_release_temporary(ureg, tmp);
419	} else {
420	    ureg_TEX(ureg, dst, TGSI_TEXTURE_2D, coords, sampler);
421	}
422	if (set_alpha)
423	    ureg_MOV(ureg,
424		     ureg_writemask(dst, TGSI_WRITEMASK_W),
425		     ureg_scalar(imm0, TGSI_SWIZZLE_W));
426    }
427}
428
429static void *
430create_fs(struct pipe_context *pipe, unsigned fs_traits)
431{
432    struct ureg_program *ureg;
433    struct ureg_src /*dst_sampler, */ src_sampler, mask_sampler;
434    struct ureg_src /*dst_pos, */ src_input, mask_pos;
435    struct ureg_dst src, mask;
436    struct ureg_dst out;
437    struct ureg_src imm0 = { 0 };
438    unsigned has_mask = (fs_traits & FS_MASK) != 0;
439    unsigned is_fill = (fs_traits & FS_FILL) != 0;
440    unsigned is_composite = (fs_traits & FS_COMPOSITE) != 0;
441    unsigned is_solid = (fs_traits & FS_SOLID_FILL) != 0;
442    unsigned is_lingrad = (fs_traits & FS_LINGRAD_FILL) != 0;
443    unsigned is_radgrad = (fs_traits & FS_RADGRAD_FILL) != 0;
444    unsigned comp_alpha_mask = fs_traits & FS_COMPONENT_ALPHA;
445    unsigned is_yuv = (fs_traits & FS_YUV) != 0;
446    unsigned src_repeat_none = (fs_traits & FS_SRC_REPEAT_NONE) != 0;
447    unsigned mask_repeat_none = (fs_traits & FS_MASK_REPEAT_NONE) != 0;
448    unsigned src_swizzle = (fs_traits & FS_SRC_SWIZZLE_RGB) != 0;
449    unsigned mask_swizzle = (fs_traits & FS_MASK_SWIZZLE_RGB) != 0;
450    unsigned src_set_alpha = (fs_traits & FS_SRC_SET_ALPHA) != 0;
451    unsigned mask_set_alpha = (fs_traits & FS_MASK_SET_ALPHA) != 0;
452    unsigned src_luminance = (fs_traits & FS_SRC_LUMINANCE) != 0;
453    unsigned mask_luminance = (fs_traits & FS_MASK_LUMINANCE) != 0;
454    unsigned dst_luminance = (fs_traits & FS_DST_LUMINANCE) != 0;
455
456#if 0
457    print_fs_traits(fs_traits);
458#else
459    (void)print_fs_traits;
460#endif
461
462    ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
463    if (ureg == NULL)
464	return 0;
465
466    /* it has to be either a fill, a composite op or a yuv conversion */
467    debug_assert((is_fill ^ is_composite) ^ is_yuv);
468    (void)is_yuv;
469
470    out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
471
472    if (src_repeat_none || mask_repeat_none ||
473	src_set_alpha || mask_set_alpha || src_luminance) {
474	imm0 = ureg_imm4f(ureg, 0, 0, 0, 1);
475    }
476    if (is_composite) {
477	src_sampler = ureg_DECL_sampler(ureg, 0);
478	src_input = ureg_DECL_fs_input(ureg,
479				       TGSI_SEMANTIC_GENERIC, 0,
480				       TGSI_INTERPOLATE_PERSPECTIVE);
481    } else if (is_fill) {
482	if (is_solid)
483	    src_input = ureg_DECL_fs_input(ureg,
484					   TGSI_SEMANTIC_COLOR, 0,
485					   TGSI_INTERPOLATE_PERSPECTIVE);
486	else
487	    src_input = ureg_DECL_fs_input(ureg,
488					   TGSI_SEMANTIC_POSITION, 0,
489					   TGSI_INTERPOLATE_PERSPECTIVE);
490    } else {
491	debug_assert(is_yuv);
492	return create_yuv_shader(pipe, ureg);
493    }
494
495    if (has_mask) {
496	mask_sampler = ureg_DECL_sampler(ureg, 1);
497	mask_pos = ureg_DECL_fs_input(ureg,
498				      TGSI_SEMANTIC_GENERIC, 1,
499				      TGSI_INTERPOLATE_PERSPECTIVE);
500    }
501#if 0				/* unused right now */
502    dst_sampler = ureg_DECL_sampler(ureg, 2);
503    dst_pos = ureg_DECL_fs_input(ureg,
504				 TGSI_SEMANTIC_POSITION, 2,
505				 TGSI_INTERPOLATE_PERSPECTIVE);
506#endif
507
508    if (is_composite) {
509	if (has_mask || src_luminance || dst_luminance)
510	    src = ureg_DECL_temporary(ureg);
511	else
512	    src = out;
513	xrender_tex(ureg, src, src_input, src_sampler, imm0,
514		    src_repeat_none, src_swizzle, src_set_alpha);
515    } else if (is_fill) {
516	if (is_solid) {
517	    if (has_mask || src_luminance || dst_luminance)
518		src = ureg_dst(src_input);
519	    else
520		ureg_MOV(ureg, out, src_input);
521	} else if (is_lingrad || is_radgrad) {
522	    struct ureg_src coords, const0124, matrow0, matrow1, matrow2;
523
524	    if (has_mask || src_luminance || dst_luminance)
525		src = ureg_DECL_temporary(ureg);
526	    else
527		src = out;
528
529	    coords = ureg_DECL_constant(ureg, 0);
530	    const0124 = ureg_DECL_constant(ureg, 1);
531	    matrow0 = ureg_DECL_constant(ureg, 2);
532	    matrow1 = ureg_DECL_constant(ureg, 3);
533	    matrow2 = ureg_DECL_constant(ureg, 4);
534
535	    if (is_lingrad) {
536		linear_gradient(ureg, src,
537				src_input, src_sampler,
538				coords, const0124, matrow0, matrow1, matrow2);
539	    } else if (is_radgrad) {
540		radial_gradient(ureg, src,
541				src_input, src_sampler,
542				coords, const0124, matrow0, matrow1, matrow2);
543	    }
544	} else
545	    debug_assert(!"Unknown fill type!");
546    }
547    if (src_luminance) {
548	ureg_MOV(ureg, src, ureg_scalar(ureg_src(src), TGSI_SWIZZLE_X));
549	ureg_MOV(ureg, ureg_writemask(src, TGSI_WRITEMASK_XYZ),
550		 ureg_scalar(imm0, TGSI_SWIZZLE_X));
551	if (!has_mask && !dst_luminance)
552	    ureg_MOV(ureg, out, ureg_src(src));
553    }
554
555    if (has_mask) {
556	mask = ureg_DECL_temporary(ureg);
557	xrender_tex(ureg, mask, mask_pos, mask_sampler, imm0,
558		    mask_repeat_none, mask_swizzle, mask_set_alpha);
559	/* src IN mask */
560
561	src_in_mask(ureg, (dst_luminance) ? src : out, ureg_src(src),
562		    ureg_src(mask),
563		    comp_alpha_mask, mask_luminance);
564
565	ureg_release_temporary(ureg, mask);
566    }
567
568    if (dst_luminance) {
569	/*
570	 * Make sure the alpha channel goes into the output L8 surface.
571	 */
572	ureg_MOV(ureg, out, ureg_scalar(ureg_src(src), TGSI_SWIZZLE_W));
573    }
574
575    ureg_END(ureg);
576
577    return ureg_create_shader_and_destroy(ureg, pipe);
578}
579
580struct xa_shaders *
581xa_shaders_create(struct xa_context *r)
582{
583    struct xa_shaders *sc = CALLOC_STRUCT(xa_shaders);
584
585    sc->r = r;
586    sc->vs_hash = cso_hash_create();
587    sc->fs_hash = cso_hash_create();
588
589    return sc;
590}
591
592static void
593cache_destroy(struct cso_context *cso,
594	      struct cso_hash *hash, unsigned processor)
595{
596    struct cso_hash_iter iter = cso_hash_first_node(hash);
597
598    while (!cso_hash_iter_is_null(iter)) {
599	void *shader = (void *)cso_hash_iter_data(iter);
600
601	if (processor == PIPE_SHADER_FRAGMENT) {
602	    cso_delete_fragment_shader(cso, shader);
603	} else if (processor == PIPE_SHADER_VERTEX) {
604	    cso_delete_vertex_shader(cso, shader);
605	}
606	iter = cso_hash_erase(hash, iter);
607    }
608    cso_hash_delete(hash);
609}
610
611void
612xa_shaders_destroy(struct xa_shaders *sc)
613{
614    cache_destroy(sc->r->cso, sc->vs_hash, PIPE_SHADER_VERTEX);
615    cache_destroy(sc->r->cso, sc->fs_hash, PIPE_SHADER_FRAGMENT);
616
617    FREE(sc);
618}
619
620static INLINE void *
621shader_from_cache(struct pipe_context *pipe,
622		  unsigned type, struct cso_hash *hash, unsigned key)
623{
624    void *shader = 0;
625
626    struct cso_hash_iter iter = cso_hash_find(hash, key);
627
628    if (cso_hash_iter_is_null(iter)) {
629	if (type == PIPE_SHADER_VERTEX)
630	    shader = create_vs(pipe, key);
631	else
632	    shader = create_fs(pipe, key);
633	cso_hash_insert(hash, key, shader);
634    } else
635	shader = (void *)cso_hash_iter_data(iter);
636
637    return shader;
638}
639
640struct xa_shader
641xa_shaders_get(struct xa_shaders *sc, unsigned vs_traits, unsigned fs_traits)
642{
643    struct xa_shader shader = { NULL, NULL };
644    void *vs, *fs;
645
646    vs = shader_from_cache(sc->r->pipe, PIPE_SHADER_VERTEX,
647			   sc->vs_hash, vs_traits);
648    fs = shader_from_cache(sc->r->pipe, PIPE_SHADER_FRAGMENT,
649			   sc->fs_hash, fs_traits);
650
651    debug_assert(vs && fs);
652    if (!vs || !fs)
653	return shader;
654
655    shader.vs = vs;
656    shader.fs = fs;
657
658    return shader;
659}
660