st/xorg: don't use flow control
[mesa.git] / src / gallium / state_trackers / xorg / xorg_exa_tgsi.c
1 #include "xorg_exa_tgsi.h"
2
3 /*### stupidity defined in X11/extensions/XI.h */
4 #undef Absolute
5
6 #include "pipe/p_format.h"
7 #include "pipe/p_context.h"
8 #include "pipe/p_state.h"
9 #include "pipe/p_inlines.h"
10 #include "pipe/p_shader_tokens.h"
11
12 #include "util/u_memory.h"
13 #include "util/u_simple_shaders.h"
14
15 #include "tgsi/tgsi_ureg.h"
16
17 #include "cso_cache/cso_context.h"
18 #include "cso_cache/cso_hash.h"
19
20 /* Vertex shader:
21 * IN[0] = vertex pos
22 * IN[1] = src tex coord | solid fill color
23 * IN[2] = mask tex coord
24 * IN[3] = dst tex coord
25 * CONST[0] = (2/dst_width, 2/dst_height, 1, 1)
26 * CONST[1] = (-1, -1, 0, 0)
27 *
28 * OUT[0] = vertex pos
29 * OUT[1] = src tex coord | solid fill color
30 * OUT[2] = mask tex coord
31 * OUT[3] = dst tex coord
32 */
33
34 /* Fragment shader:
35 * SAMP[0] = src
36 * SAMP[1] = mask
37 * SAMP[2] = dst
38 * IN[0] = pos src | solid fill color
39 * IN[1] = pos mask
40 * IN[2] = pos dst
41 * CONST[0] = (0, 0, 0, 1)
42 *
43 * OUT[0] = color
44 */
45
46 struct xorg_shaders {
47 struct xorg_renderer *r;
48
49 struct cso_hash *vs_hash;
50 struct cso_hash *fs_hash;
51 };
52
53 static INLINE void
54 src_in_mask(struct ureg_program *ureg,
55 struct ureg_dst dst,
56 struct ureg_src src,
57 struct ureg_src mask,
58 int component_alpha)
59 {
60 if (component_alpha == FS_CA_FULL) {
61 ureg_MUL(ureg, dst, src, mask);
62 } else if (component_alpha == FS_CA_SRCALPHA) {
63 ureg_MUL(ureg, dst,
64 ureg_scalar(src, TGSI_SWIZZLE_W), mask);
65 }
66 else {
67 ureg_MUL(ureg, dst, src,
68 ureg_scalar(mask, TGSI_SWIZZLE_X));
69 }
70 }
71
72 static struct ureg_src
73 vs_normalize_coords(struct ureg_program *ureg, struct ureg_src coords,
74 struct ureg_src const0, struct ureg_src const1)
75 {
76 struct ureg_dst tmp = ureg_DECL_temporary(ureg);
77 struct ureg_src ret;
78 ureg_MAD(ureg, tmp, coords, const0, const1);
79 ret = ureg_src(tmp);
80 ureg_release_temporary(ureg, tmp);
81 return ret;
82 }
83
84 static void
85 linear_gradient(struct ureg_program *ureg,
86 struct ureg_dst out,
87 struct ureg_src pos,
88 struct ureg_src sampler,
89 struct ureg_src coords,
90 struct ureg_src const0124,
91 struct ureg_src matrow0,
92 struct ureg_src matrow1,
93 struct ureg_src matrow2)
94 {
95 struct ureg_dst temp0 = ureg_DECL_temporary(ureg);
96 struct ureg_dst temp1 = ureg_DECL_temporary(ureg);
97 struct ureg_dst temp2 = ureg_DECL_temporary(ureg);
98 struct ureg_dst temp3 = ureg_DECL_temporary(ureg);
99 struct ureg_dst temp4 = ureg_DECL_temporary(ureg);
100 struct ureg_dst temp5 = ureg_DECL_temporary(ureg);
101
102 ureg_MOV(ureg,
103 ureg_writemask(temp0, TGSI_WRITEMASK_XY), pos);
104 ureg_MOV(ureg,
105 ureg_writemask(temp0, TGSI_WRITEMASK_Z),
106 ureg_scalar(const0124, TGSI_SWIZZLE_Y));
107
108 ureg_DP3(ureg, temp1, matrow0, ureg_src(temp0));
109 ureg_DP3(ureg, temp2, matrow1, ureg_src(temp0));
110 ureg_DP3(ureg, temp3, matrow2, ureg_src(temp0));
111 ureg_RCP(ureg, temp3, ureg_src(temp3));
112 ureg_MUL(ureg, temp1, ureg_src(temp1), ureg_src(temp3));
113 ureg_MUL(ureg, temp2, ureg_src(temp2), ureg_src(temp3));
114
115 ureg_MOV(ureg, ureg_writemask(temp4, TGSI_WRITEMASK_X),
116 ureg_src(temp1));
117 ureg_MOV(ureg, ureg_writemask(temp4, TGSI_WRITEMASK_Y),
118 ureg_src(temp2));
119
120 ureg_MUL(ureg, temp0,
121 ureg_scalar(coords, TGSI_SWIZZLE_Y),
122 ureg_scalar(ureg_src(temp4), TGSI_SWIZZLE_Y));
123 ureg_MAD(ureg, temp1,
124 ureg_scalar(coords, TGSI_SWIZZLE_X),
125 ureg_scalar(ureg_src(temp4), TGSI_SWIZZLE_X),
126 ureg_src(temp0));
127
128 ureg_MUL(ureg, temp2,
129 ureg_src(temp1),
130 ureg_scalar(coords, TGSI_SWIZZLE_Z));
131
132 ureg_TEX(ureg, out,
133 TGSI_TEXTURE_1D, ureg_src(temp2), sampler);
134
135 ureg_release_temporary(ureg, temp0);
136 ureg_release_temporary(ureg, temp1);
137 ureg_release_temporary(ureg, temp2);
138 ureg_release_temporary(ureg, temp3);
139 ureg_release_temporary(ureg, temp4);
140 ureg_release_temporary(ureg, temp5);
141 }
142
143
144 static void
145 radial_gradient(struct ureg_program *ureg,
146 struct ureg_dst out,
147 struct ureg_src pos,
148 struct ureg_src sampler,
149 struct ureg_src coords,
150 struct ureg_src const0124,
151 struct ureg_src matrow0,
152 struct ureg_src matrow1,
153 struct ureg_src matrow2)
154 {
155 struct ureg_dst temp0 = ureg_DECL_temporary(ureg);
156 struct ureg_dst temp1 = ureg_DECL_temporary(ureg);
157 struct ureg_dst temp2 = ureg_DECL_temporary(ureg);
158 struct ureg_dst temp3 = ureg_DECL_temporary(ureg);
159 struct ureg_dst temp4 = ureg_DECL_temporary(ureg);
160 struct ureg_dst temp5 = ureg_DECL_temporary(ureg);
161
162 ureg_MOV(ureg,
163 ureg_writemask(temp0, TGSI_WRITEMASK_XY),
164 pos);
165 ureg_MOV(ureg,
166 ureg_writemask(temp0, TGSI_WRITEMASK_Z),
167 ureg_scalar(const0124, TGSI_SWIZZLE_Y));
168
169 ureg_DP3(ureg, temp1, matrow0, ureg_src(temp0));
170 ureg_DP3(ureg, temp2, matrow1, ureg_src(temp0));
171 ureg_DP3(ureg, temp3, matrow2, ureg_src(temp0));
172 ureg_RCP(ureg, temp3, ureg_src(temp3));
173 ureg_MUL(ureg, temp1, ureg_src(temp1), ureg_src(temp3));
174 ureg_MUL(ureg, temp2, ureg_src(temp2), ureg_src(temp3));
175
176 ureg_MOV(ureg, ureg_writemask(temp5, TGSI_WRITEMASK_X),
177 ureg_src(temp1));
178 ureg_MOV(ureg, ureg_writemask(temp5, TGSI_WRITEMASK_Y),
179 ureg_src(temp2));
180
181 ureg_MUL(ureg, temp0, ureg_scalar(coords, TGSI_SWIZZLE_Y),
182 ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y));
183 ureg_MAD(ureg, temp1,
184 ureg_scalar(coords, TGSI_SWIZZLE_X),
185 ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X),
186 ureg_src(temp0));
187 ureg_ADD(ureg, temp1,
188 ureg_src(temp1), ureg_src(temp1));
189 ureg_MUL(ureg, temp3,
190 ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y),
191 ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y));
192 ureg_MAD(ureg, temp4,
193 ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X),
194 ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X),
195 ureg_src(temp3));
196 ureg_MOV(ureg, temp4, ureg_negate(ureg_src(temp4)));
197 ureg_MUL(ureg, temp2,
198 ureg_scalar(coords, TGSI_SWIZZLE_Z),
199 ureg_src(temp4));
200 ureg_MUL(ureg, temp0,
201 ureg_scalar(const0124, TGSI_SWIZZLE_W),
202 ureg_src(temp2));
203 ureg_MUL(ureg, temp3,
204 ureg_src(temp1), ureg_src(temp1));
205 ureg_SUB(ureg, temp2,
206 ureg_src(temp3), ureg_src(temp0));
207 ureg_RSQ(ureg, temp2, ureg_abs(ureg_src(temp2)));
208 ureg_RCP(ureg, temp2, ureg_src(temp2));
209 ureg_SUB(ureg, temp1,
210 ureg_src(temp2), ureg_src(temp1));
211 ureg_ADD(ureg, temp0,
212 ureg_scalar(coords, TGSI_SWIZZLE_Z),
213 ureg_scalar(coords, TGSI_SWIZZLE_Z));
214 ureg_RCP(ureg, temp0, ureg_src(temp0));
215 ureg_MUL(ureg, temp2,
216 ureg_src(temp1), ureg_src(temp0));
217 ureg_TEX(ureg, out, TGSI_TEXTURE_1D,
218 ureg_src(temp2), sampler);
219
220 ureg_release_temporary(ureg, temp0);
221 ureg_release_temporary(ureg, temp1);
222 ureg_release_temporary(ureg, temp2);
223 ureg_release_temporary(ureg, temp3);
224 ureg_release_temporary(ureg, temp4);
225 ureg_release_temporary(ureg, temp5);
226 }
227
228 static void *
229 create_vs(struct pipe_context *pipe,
230 unsigned vs_traits)
231 {
232 struct ureg_program *ureg;
233 struct ureg_src src;
234 struct ureg_dst dst;
235 struct ureg_src const0, const1;
236 boolean is_fill = (vs_traits & VS_FILL) != 0;
237 boolean is_composite = (vs_traits & VS_COMPOSITE) != 0;
238 boolean has_mask = (vs_traits & VS_MASK) != 0;
239 boolean is_yuv = (vs_traits & VS_YUV) != 0;
240 unsigned input_slot = 0;
241
242 ureg = ureg_create(TGSI_PROCESSOR_VERTEX);
243 if (ureg == NULL)
244 return 0;
245
246 const0 = ureg_DECL_constant(ureg, 0);
247 const1 = ureg_DECL_constant(ureg, 1);
248
249 /* it has to be either a fill or a composite op */
250 debug_assert((is_fill ^ is_composite) ^ is_yuv);
251
252 src = ureg_DECL_vs_input(ureg, input_slot++);
253 dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
254 src = vs_normalize_coords(ureg, src,
255 const0, const1);
256 ureg_MOV(ureg, dst, src);
257
258 if (is_yuv) {
259 src = ureg_DECL_vs_input(ureg, input_slot++);
260 dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 0);
261 ureg_MOV(ureg, dst, src);
262 }
263
264 if (is_composite) {
265 src = ureg_DECL_vs_input(ureg, input_slot++);
266 dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 0);
267 ureg_MOV(ureg, dst, src);
268 }
269
270 if (is_fill) {
271 src = ureg_DECL_vs_input(ureg, input_slot++);
272 dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
273 ureg_MOV(ureg, dst, src);
274 }
275
276 if (has_mask) {
277 src = ureg_DECL_vs_input(ureg, input_slot++);
278 dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 1);
279 ureg_MOV(ureg, dst, src);
280 }
281
282 ureg_END(ureg);
283
284 return ureg_create_shader_and_destroy(ureg, pipe);
285 }
286
287 static void *
288 create_yuv_shader(struct pipe_context *pipe, struct ureg_program *ureg)
289 {
290 struct ureg_src y_sampler, u_sampler, v_sampler;
291 struct ureg_src pos;
292 struct ureg_src matrow0, matrow1, matrow2;
293 struct ureg_dst y, u, v, rgb;
294 struct ureg_dst out = ureg_DECL_output(ureg,
295 TGSI_SEMANTIC_COLOR,
296 0);
297
298 pos = ureg_DECL_fs_input(ureg,
299 TGSI_SEMANTIC_GENERIC,
300 0,
301 TGSI_INTERPOLATE_PERSPECTIVE);
302
303 rgb = ureg_DECL_temporary(ureg);
304 y = ureg_DECL_temporary(ureg);
305 u = ureg_DECL_temporary(ureg);
306 v = ureg_DECL_temporary(ureg);
307
308 y_sampler = ureg_DECL_sampler(ureg, 0);
309 u_sampler = ureg_DECL_sampler(ureg, 1);
310 v_sampler = ureg_DECL_sampler(ureg, 2);
311
312 matrow0 = ureg_DECL_constant(ureg, 0);
313 matrow1 = ureg_DECL_constant(ureg, 1);
314 matrow2 = ureg_DECL_constant(ureg, 2);
315
316 ureg_TEX(ureg, y,
317 TGSI_TEXTURE_2D, pos, y_sampler);
318 ureg_TEX(ureg, u,
319 TGSI_TEXTURE_2D, pos, u_sampler);
320 ureg_TEX(ureg, v,
321 TGSI_TEXTURE_2D, pos, v_sampler);
322
323 ureg_SUB(ureg, u, ureg_src(u),
324 ureg_scalar(matrow0, TGSI_SWIZZLE_W));
325 ureg_SUB(ureg, v, ureg_src(v),
326 ureg_scalar(matrow0, TGSI_SWIZZLE_W));
327
328 ureg_MUL(ureg, rgb,
329 ureg_scalar(ureg_src(y), TGSI_SWIZZLE_X),
330 matrow0);
331 ureg_MAD(ureg, rgb,
332 ureg_scalar(ureg_src(u), TGSI_SWIZZLE_X),
333 matrow1,
334 ureg_src(rgb));
335 ureg_MAD(ureg, rgb,
336 ureg_scalar(ureg_src(v), TGSI_SWIZZLE_X),
337 matrow2,
338 ureg_src(rgb));
339
340 /* rgb.a = 1; */
341 ureg_MOV(ureg, ureg_writemask(rgb, TGSI_WRITEMASK_W),
342 ureg_scalar(matrow0, TGSI_SWIZZLE_X));
343
344 ureg_MOV(ureg, out, ureg_src(rgb));
345
346 ureg_release_temporary(ureg, rgb);
347 ureg_release_temporary(ureg, y);
348 ureg_release_temporary(ureg, u);
349 ureg_release_temporary(ureg, v);
350
351 ureg_END(ureg);
352
353 return ureg_create_shader_and_destroy(ureg, pipe);
354 }
355
356
357 static INLINE void
358 xrender_tex(struct ureg_program *ureg,
359 struct ureg_dst dst,
360 struct ureg_src coords,
361 struct ureg_src sampler,
362 boolean repeat_none)
363 {
364 if (repeat_none) {
365 struct ureg_dst tmp0 = ureg_DECL_temporary(ureg);
366 struct ureg_dst tmp1 = ureg_DECL_temporary(ureg);
367 struct ureg_src const0 = ureg_DECL_constant(ureg, 0);
368 ureg_SGT(ureg, tmp1, ureg_swizzle(coords,
369 TGSI_SWIZZLE_X,
370 TGSI_SWIZZLE_Y,
371 TGSI_SWIZZLE_X,
372 TGSI_SWIZZLE_Y),
373 ureg_scalar(const0, TGSI_SWIZZLE_X));
374 ureg_SLT(ureg, tmp0, ureg_swizzle(coords,
375 TGSI_SWIZZLE_X,
376 TGSI_SWIZZLE_Y,
377 TGSI_SWIZZLE_X,
378 TGSI_SWIZZLE_Y),
379 ureg_scalar(const0, TGSI_SWIZZLE_W));
380 ureg_MIN(ureg, tmp0, ureg_src(tmp0), ureg_src(tmp1));
381 ureg_MIN(ureg, tmp0, ureg_scalar(ureg_src(tmp0), TGSI_SWIZZLE_X),
382 ureg_scalar(ureg_src(tmp0), TGSI_SWIZZLE_Y));
383 ureg_TEX(ureg, tmp1, TGSI_TEXTURE_2D, coords, sampler);
384 ureg_MUL(ureg, dst, ureg_src(tmp1), ureg_src(tmp0));
385 ureg_release_temporary(ureg, tmp0);
386 ureg_release_temporary(ureg, tmp1);
387 } else
388 ureg_TEX(ureg, dst, TGSI_TEXTURE_2D, coords, sampler);
389 }
390
391 static void *
392 create_fs(struct pipe_context *pipe,
393 unsigned fs_traits)
394 {
395 struct ureg_program *ureg;
396 struct ureg_src /*dst_sampler,*/ src_sampler, mask_sampler;
397 struct ureg_src /*dst_pos,*/ src_input, mask_pos;
398 struct ureg_dst src, mask;
399 struct ureg_dst out;
400 unsigned has_mask = (fs_traits & FS_MASK) != 0;
401 unsigned is_fill = (fs_traits & FS_FILL) != 0;
402 unsigned is_composite = (fs_traits & FS_COMPOSITE) != 0;
403 unsigned is_solid = (fs_traits & FS_SOLID_FILL) != 0;
404 unsigned is_lingrad = (fs_traits & FS_LINGRAD_FILL) != 0;
405 unsigned is_radgrad = (fs_traits & FS_RADGRAD_FILL) != 0;
406 unsigned comp_alpha = (fs_traits & FS_COMPONENT_ALPHA) != 0;
407 unsigned is_yuv = (fs_traits & FS_YUV) != 0;
408 unsigned src_repeat_none = (fs_traits & FS_SRC_REPEAT_NONE) != 0;
409 unsigned mask_repeat_none = (fs_traits & FS_MASK_REPEAT_NONE) != 0;
410
411 ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
412 if (ureg == NULL)
413 return 0;
414
415 /* it has to be either a fill, a composite op or a yuv conversion */
416 debug_assert((is_fill ^ is_composite) ^ is_yuv);
417
418 out = ureg_DECL_output(ureg,
419 TGSI_SEMANTIC_COLOR,
420 0);
421
422 if (is_composite) {
423 src_sampler = ureg_DECL_sampler(ureg, 0);
424 src_input = ureg_DECL_fs_input(ureg,
425 TGSI_SEMANTIC_GENERIC,
426 0,
427 TGSI_INTERPOLATE_PERSPECTIVE);
428 } else if (is_fill) {
429 if (is_solid)
430 src_input = ureg_DECL_fs_input(ureg,
431 TGSI_SEMANTIC_COLOR,
432 0,
433 TGSI_INTERPOLATE_PERSPECTIVE);
434 else
435 src_input = ureg_DECL_fs_input(ureg,
436 TGSI_SEMANTIC_POSITION,
437 0,
438 TGSI_INTERPOLATE_PERSPECTIVE);
439 } else {
440 debug_assert(is_yuv);
441 return create_yuv_shader(pipe, ureg);
442 }
443
444 if (has_mask) {
445 mask_sampler = ureg_DECL_sampler(ureg, 1);
446 mask_pos = ureg_DECL_fs_input(ureg,
447 TGSI_SEMANTIC_GENERIC,
448 1,
449 TGSI_INTERPOLATE_PERSPECTIVE);
450 }
451
452 #if 0 /* unused right now */
453 dst_sampler = ureg_DECL_sampler(ureg, 2);
454 dst_pos = ureg_DECL_fs_input(ureg,
455 TGSI_SEMANTIC_POSITION,
456 2,
457 TGSI_INTERPOLATE_PERSPECTIVE);
458 #endif
459
460 if (is_composite) {
461 if (has_mask)
462 src = ureg_DECL_temporary(ureg);
463 else
464 src = out;
465 xrender_tex(ureg, src, src_input, src_sampler,
466 src_repeat_none);
467 } else if (is_fill) {
468 if (is_solid) {
469 if (has_mask)
470 src = ureg_dst(src_input);
471 else
472 ureg_MOV(ureg, out, src_input);
473 } else if (is_lingrad || is_radgrad) {
474 struct ureg_src coords, const0124,
475 matrow0, matrow1, matrow2;
476
477 if (has_mask)
478 src = ureg_DECL_temporary(ureg);
479 else
480 src = out;
481
482 coords = ureg_DECL_constant(ureg, 0);
483 const0124 = ureg_DECL_constant(ureg, 1);
484 matrow0 = ureg_DECL_constant(ureg, 2);
485 matrow1 = ureg_DECL_constant(ureg, 3);
486 matrow2 = ureg_DECL_constant(ureg, 4);
487
488 if (is_lingrad) {
489 linear_gradient(ureg, src,
490 src_input, src_sampler,
491 coords, const0124,
492 matrow0, matrow1, matrow2);
493 } else if (is_radgrad) {
494 radial_gradient(ureg, src,
495 src_input, src_sampler,
496 coords, const0124,
497 matrow0, matrow1, matrow2);
498 }
499 } else
500 debug_assert(!"Unknown fill type!");
501 }
502
503 if (has_mask) {
504 mask = ureg_DECL_temporary(ureg);
505 xrender_tex(ureg, mask, mask_pos, mask_sampler,
506 mask_repeat_none);
507 /* src IN mask */
508 src_in_mask(ureg, out, ureg_src(src), ureg_src(mask), comp_alpha);
509 ureg_release_temporary(ureg, mask);
510 }
511
512 ureg_END(ureg);
513
514 return ureg_create_shader_and_destroy(ureg, pipe);
515 }
516
517 struct xorg_shaders * xorg_shaders_create(struct xorg_renderer *r)
518 {
519 struct xorg_shaders *sc = CALLOC_STRUCT(xorg_shaders);
520
521 sc->r = r;
522 sc->vs_hash = cso_hash_create();
523 sc->fs_hash = cso_hash_create();
524
525 return sc;
526 }
527
528 static void
529 cache_destroy(struct cso_context *cso,
530 struct cso_hash *hash,
531 unsigned processor)
532 {
533 struct cso_hash_iter iter = cso_hash_first_node(hash);
534 while (!cso_hash_iter_is_null(iter)) {
535 void *shader = (void *)cso_hash_iter_data(iter);
536 if (processor == PIPE_SHADER_FRAGMENT) {
537 cso_delete_fragment_shader(cso, shader);
538 } else if (processor == PIPE_SHADER_VERTEX) {
539 cso_delete_vertex_shader(cso, shader);
540 }
541 iter = cso_hash_erase(hash, iter);
542 }
543 cso_hash_delete(hash);
544 }
545
546 void xorg_shaders_destroy(struct xorg_shaders *sc)
547 {
548 cache_destroy(sc->r->cso, sc->vs_hash,
549 PIPE_SHADER_VERTEX);
550 cache_destroy(sc->r->cso, sc->fs_hash,
551 PIPE_SHADER_FRAGMENT);
552
553 free(sc);
554 }
555
556 static INLINE void *
557 shader_from_cache(struct pipe_context *pipe,
558 unsigned type,
559 struct cso_hash *hash,
560 unsigned key)
561 {
562 void *shader = 0;
563
564 struct cso_hash_iter iter = cso_hash_find(hash, key);
565
566 if (cso_hash_iter_is_null(iter)) {
567 if (type == PIPE_SHADER_VERTEX)
568 shader = create_vs(pipe, key);
569 else
570 shader = create_fs(pipe, key);
571 cso_hash_insert(hash, key, shader);
572 } else
573 shader = (void *)cso_hash_iter_data(iter);
574
575 return shader;
576 }
577
578 struct xorg_shader xorg_shaders_get(struct xorg_shaders *sc,
579 unsigned vs_traits,
580 unsigned fs_traits)
581 {
582 struct xorg_shader shader = { NULL, NULL };
583 void *vs, *fs;
584
585 vs = shader_from_cache(sc->r->pipe, PIPE_SHADER_VERTEX,
586 sc->vs_hash, vs_traits);
587 fs = shader_from_cache(sc->r->pipe, PIPE_SHADER_FRAGMENT,
588 sc->fs_hash, fs_traits);
589
590 debug_assert(vs && fs);
591 if (!vs || !fs)
592 return shader;
593
594 shader.vs = vs;
595 shader.fs = fs;
596
597 return shader;
598 }