xorg_exa_tgsi.c revision f1ce6b09cdb21d9217d6ad6057f7fb97375df8be
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
46struct xorg_shaders {
47   struct exa_context *exa;
48
49   struct cso_hash *vs_hash;
50   struct cso_hash *fs_hash;
51};
52
53static const char over_op[] =
54   "SUB TEMP[3], CONST[0].wwww, TEMP[1].wwww\n"
55   "MAD TEMP[3], TEMP[0], TEMP[3], TEMP[0]\n";
56
57
58static INLINE void
59create_preamble(struct ureg_program *ureg)
60{
61}
62
63
64static INLINE void
65src_in_mask(struct ureg_program *ureg,
66            struct ureg_dst dst,
67            struct ureg_src src,
68            struct ureg_src mask)
69{
70   /* MUL dst, src, mask.wwww */
71   ureg_MUL(ureg, dst, src,
72            ureg_scalar(mask, TGSI_SWIZZLE_W));
73}
74
75static struct ureg_src
76vs_normalize_coords(struct ureg_program *ureg, struct ureg_src coords,
77                    struct ureg_src const0, struct ureg_src const1)
78{
79   struct ureg_dst tmp = ureg_DECL_temporary(ureg);
80   struct ureg_src ret;
81   ureg_MAD(ureg, tmp, coords, const0, const1);
82   ret = ureg_src(tmp);
83   ureg_release_temporary(ureg, tmp);
84   return ret;
85}
86
87static void
88linear_gradient(struct ureg_program *ureg,
89                struct ureg_dst out,
90                struct ureg_src pos,
91                struct ureg_src sampler,
92                struct ureg_src coords,
93                struct ureg_src const0124,
94                struct ureg_src matrow0,
95                struct ureg_src matrow1,
96                struct ureg_src matrow2)
97{
98   struct ureg_dst temp0 = ureg_DECL_temporary(ureg);
99   struct ureg_dst temp1 = ureg_DECL_temporary(ureg);
100   struct ureg_dst temp2 = ureg_DECL_temporary(ureg);
101   struct ureg_dst temp3 = ureg_DECL_temporary(ureg);
102   struct ureg_dst temp4 = ureg_DECL_temporary(ureg);
103   struct ureg_dst temp5 = ureg_DECL_temporary(ureg);
104
105   ureg_MOV(ureg,
106            ureg_writemask(temp0, TGSI_WRITEMASK_XY), pos);
107   ureg_MOV(ureg,
108            ureg_writemask(temp0, TGSI_WRITEMASK_Z),
109            ureg_scalar(const0124, TGSI_SWIZZLE_Y));
110
111   ureg_DP3(ureg, temp1, matrow0, ureg_src(temp0));
112   ureg_DP3(ureg, temp2, matrow1, ureg_src(temp0));
113   ureg_DP3(ureg, temp3, matrow2, ureg_src(temp0));
114   ureg_RCP(ureg, temp3, ureg_src(temp3));
115   ureg_MUL(ureg, temp1, ureg_src(temp1), ureg_src(temp3));
116   ureg_MUL(ureg, temp2, ureg_src(temp2), ureg_src(temp3));
117
118   ureg_MOV(ureg, ureg_writemask(temp4, TGSI_WRITEMASK_X),
119            ureg_src(temp1));
120   ureg_MOV(ureg, ureg_writemask(temp4, TGSI_WRITEMASK_Y),
121            ureg_src(temp2));
122
123   ureg_MUL(ureg, temp0,
124            ureg_scalar(coords, TGSI_SWIZZLE_Y),
125            ureg_scalar(ureg_src(temp4), TGSI_SWIZZLE_Y));
126   ureg_MAD(ureg, temp1,
127            ureg_scalar(coords, TGSI_SWIZZLE_X),
128            ureg_scalar(ureg_src(temp4), TGSI_SWIZZLE_X),
129            ureg_src(temp0));
130
131   ureg_MUL(ureg, temp2,
132            ureg_src(temp1),
133            ureg_scalar(coords, TGSI_SWIZZLE_Z));
134
135   ureg_TEX(ureg, out,
136            TGSI_TEXTURE_1D, ureg_src(temp2), sampler);
137
138   ureg_release_temporary(ureg, temp0);
139   ureg_release_temporary(ureg, temp1);
140   ureg_release_temporary(ureg, temp2);
141   ureg_release_temporary(ureg, temp3);
142   ureg_release_temporary(ureg, temp4);
143   ureg_release_temporary(ureg, temp5);
144}
145
146
147static void
148radial_gradient(struct ureg_program *ureg,
149                struct ureg_dst out,
150                struct ureg_src pos,
151                struct ureg_src sampler,
152                struct ureg_src coords,
153                struct ureg_src const0124,
154                struct ureg_src matrow0,
155                struct ureg_src matrow1,
156                struct ureg_src matrow2)
157{
158   struct ureg_dst temp0 = ureg_DECL_temporary(ureg);
159   struct ureg_dst temp1 = ureg_DECL_temporary(ureg);
160   struct ureg_dst temp2 = ureg_DECL_temporary(ureg);
161   struct ureg_dst temp3 = ureg_DECL_temporary(ureg);
162   struct ureg_dst temp4 = ureg_DECL_temporary(ureg);
163   struct ureg_dst temp5 = ureg_DECL_temporary(ureg);
164
165   ureg_MOV(ureg,
166            ureg_writemask(temp0, TGSI_WRITEMASK_XY),
167            pos);
168   ureg_MOV(ureg,
169            ureg_writemask(temp0, TGSI_WRITEMASK_Z),
170            ureg_scalar(const0124, TGSI_SWIZZLE_Y));
171
172   ureg_DP3(ureg, temp1, matrow0, ureg_src(temp0));
173   ureg_DP3(ureg, temp2, matrow1, ureg_src(temp0));
174   ureg_DP3(ureg, temp3, matrow2, ureg_src(temp0));
175   ureg_RCP(ureg, temp3, ureg_src(temp3));
176   ureg_MUL(ureg, temp1, ureg_src(temp1), ureg_src(temp3));
177   ureg_MUL(ureg, temp2, ureg_src(temp2), ureg_src(temp3));
178
179   ureg_MOV(ureg, ureg_writemask(temp5, TGSI_WRITEMASK_X),
180            ureg_src(temp1));
181   ureg_MOV(ureg, ureg_writemask(temp5, TGSI_WRITEMASK_Y),
182            ureg_src(temp2));
183
184   ureg_MUL(ureg, temp0, ureg_scalar(coords, TGSI_SWIZZLE_Y),
185            ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y));
186   ureg_MAD(ureg, temp1,
187            ureg_scalar(coords, TGSI_SWIZZLE_X),
188            ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X),
189            ureg_src(temp0));
190   ureg_ADD(ureg, temp1,
191            ureg_src(temp1), ureg_src(temp1));
192   ureg_MUL(ureg, temp3,
193            ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y),
194            ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y));
195   ureg_MAD(ureg, temp4,
196            ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X),
197            ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X),
198            ureg_src(temp3));
199   ureg_MOV(ureg, temp4, ureg_negate(ureg_src(temp4)));
200   ureg_MUL(ureg, temp2,
201            ureg_scalar(coords, TGSI_SWIZZLE_Z),
202            ureg_src(temp4));
203   ureg_MUL(ureg, temp0,
204            ureg_scalar(const0124, TGSI_SWIZZLE_W),
205            ureg_src(temp2));
206   ureg_MUL(ureg, temp3,
207            ureg_src(temp1), ureg_src(temp1));
208   ureg_SUB(ureg, temp2,
209            ureg_src(temp3), ureg_src(temp0));
210   ureg_RSQ(ureg, temp2, ureg_abs(ureg_src(temp2)));
211   ureg_RCP(ureg, temp2, ureg_src(temp2));
212   ureg_SUB(ureg, temp1,
213            ureg_src(temp2), ureg_src(temp1));
214   ureg_ADD(ureg, temp0,
215            ureg_scalar(coords, TGSI_SWIZZLE_Z),
216            ureg_scalar(coords, TGSI_SWIZZLE_Z));
217   ureg_RCP(ureg, temp0, ureg_src(temp0));
218   ureg_MUL(ureg, temp2,
219            ureg_src(temp1), ureg_src(temp0));
220   ureg_TEX(ureg, out, TGSI_TEXTURE_1D,
221            ureg_src(temp2), sampler);
222
223   ureg_release_temporary(ureg, temp0);
224   ureg_release_temporary(ureg, temp1);
225   ureg_release_temporary(ureg, temp2);
226   ureg_release_temporary(ureg, temp3);
227   ureg_release_temporary(ureg, temp4);
228   ureg_release_temporary(ureg, temp5);
229}
230
231static void *
232create_vs(struct pipe_context *pipe,
233          unsigned vs_traits)
234{
235   struct ureg_program *ureg;
236   struct ureg_src src;
237   struct ureg_dst dst;
238   struct ureg_src const0, const1;
239   boolean is_fill = vs_traits & VS_FILL;
240   boolean is_composite = vs_traits & VS_COMPOSITE;
241   boolean has_mask = vs_traits & VS_MASK;
242   unsigned input_slot = 0;
243
244   ureg = ureg_create(TGSI_PROCESSOR_VERTEX);
245   if (ureg == NULL)
246      return 0;
247
248   const0 = ureg_DECL_constant(ureg, 0);
249   const1 = ureg_DECL_constant(ureg, 1);
250
251   /* it has to be either a fill or a composite op */
252   debug_assert(is_fill ^ is_composite);
253
254   src = ureg_DECL_vs_input(ureg, input_slot++);
255   dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
256   src = vs_normalize_coords(ureg, src,
257                             const0, const1);
258   ureg_MOV(ureg, dst, src);
259
260   if (is_composite) {
261      src = ureg_DECL_vs_input(ureg, input_slot++);
262      dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 1);
263      ureg_MOV(ureg, dst, src);
264   }
265
266   if (is_fill) {
267      src = ureg_DECL_vs_input(ureg, input_slot++);
268      dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
269      ureg_MOV(ureg, dst, src);
270   }
271
272   if (has_mask) {
273      src = ureg_DECL_vs_input(ureg, input_slot++);
274      dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 2);
275      ureg_MOV(ureg, dst, src);
276   }
277
278   ureg_END(ureg);
279
280   return ureg_create_shader_and_destroy(ureg, pipe);
281}
282
283static void *
284create_fs(struct pipe_context *pipe,
285          unsigned fs_traits)
286{
287   struct ureg_program *ureg;
288   struct ureg_src /*dst_sampler,*/ src_sampler, mask_sampler;
289   struct ureg_src /*dst_pos,*/ src_input, mask_pos;
290   struct ureg_dst src, mask;
291   struct ureg_dst out;
292   boolean has_mask = fs_traits & FS_MASK;
293   boolean is_fill = fs_traits & FS_FILL;
294   boolean is_composite = fs_traits & FS_COMPOSITE;
295   boolean is_solid   = fs_traits & FS_SOLID_FILL;
296   boolean is_lingrad = fs_traits & FS_LINGRAD_FILL;
297   boolean is_radgrad = fs_traits & FS_RADGRAD_FILL;
298
299   ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
300   if (ureg == NULL)
301      return 0;
302
303   /* it has to be either a fill or a composite op */
304   debug_assert(is_fill ^ is_composite);
305
306   out = ureg_DECL_output(ureg,
307                          TGSI_SEMANTIC_COLOR,
308                          0);
309
310   if (is_composite) {
311      src_sampler = ureg_DECL_sampler(ureg, 0);
312      src_input = ureg_DECL_fs_input(ureg,
313                                     TGSI_SEMANTIC_POSITION,
314                                     0,
315                                     TGSI_INTERPOLATE_PERSPECTIVE);
316   } else {
317      debug_assert(is_fill);
318      if (is_solid)
319         src_input = ureg_DECL_fs_input(ureg,
320                                        TGSI_SEMANTIC_COLOR,
321                                        0,
322                                        TGSI_INTERPOLATE_PERSPECTIVE);
323      else
324         src_input = ureg_DECL_fs_input(ureg,
325                                        TGSI_SEMANTIC_POSITION,
326                                        0,
327                                        TGSI_INTERPOLATE_PERSPECTIVE);
328   }
329
330   if (has_mask) {
331      mask_sampler = ureg_DECL_sampler(ureg, 1);
332      mask_pos = ureg_DECL_fs_input(ureg,
333                                    TGSI_SEMANTIC_POSITION,
334                                    1,
335                                    TGSI_INTERPOLATE_PERSPECTIVE);
336   }
337
338#if 0  /* unused right now */
339   dst_sampler = ureg_DECL_sampler(ureg, 2);
340   dst_pos = ureg_DECL_fs_input(ureg,
341                                TGSI_SEMANTIC_POSITION,
342                                2,
343                                TGSI_INTERPOLATE_PERSPECTIVE);
344#endif
345
346   if (is_composite) {
347      if (has_mask)
348         src = ureg_DECL_temporary(ureg);
349      else
350         src = out;
351      ureg_TEX(ureg, src,
352               TGSI_TEXTURE_2D, src_input, src_sampler);
353   } else if (is_fill) {
354      if (is_solid) {
355         if (has_mask)
356            src = ureg_dst(src_input);
357         else
358            ureg_MOV(ureg, out, src_input);
359      } else if (is_lingrad || is_radgrad) {
360         struct ureg_src coords, const0124,
361            matrow0, matrow1, matrow2;
362
363         if (has_mask)
364            src = ureg_DECL_temporary(ureg);
365         else
366            src = out;
367
368         coords = ureg_DECL_constant(ureg, 0);
369         const0124 = ureg_DECL_constant(ureg, 1);
370         matrow0 = ureg_DECL_constant(ureg, 2);
371         matrow1 = ureg_DECL_constant(ureg, 3);
372         matrow2 = ureg_DECL_constant(ureg, 4);
373
374         if (is_lingrad) {
375            linear_gradient(ureg, src,
376                            src_input, src_sampler,
377                            coords, const0124,
378                            matrow0, matrow1, matrow2);
379         } else if (is_radgrad) {
380            radial_gradient(ureg, src,
381                            src_input, src_sampler,
382                            coords, const0124,
383                            matrow0, matrow1, matrow2);
384         }
385      } else
386         debug_assert(!"Unknown fill type!");
387   }
388
389   if (has_mask) {
390      mask = ureg_DECL_temporary(ureg);
391      ureg_TEX(ureg, mask,
392               TGSI_TEXTURE_2D, mask_pos, mask_sampler);
393      /* src IN mask */
394      src_in_mask(ureg, out, ureg_src(src), ureg_src(mask));
395      ureg_release_temporary(ureg, mask);
396   }
397
398   ureg_END(ureg);
399
400   return ureg_create_shader_and_destroy(ureg, pipe);
401}
402
403struct xorg_shaders * xorg_shaders_create(struct exa_context *exa)
404{
405   struct xorg_shaders *sc = CALLOC_STRUCT(xorg_shaders);
406
407   sc->exa = exa;
408   sc->vs_hash = cso_hash_create();
409   sc->fs_hash = cso_hash_create();
410
411   return sc;
412}
413
414static void
415cache_destroy(struct cso_context *cso,
416              struct cso_hash *hash,
417              unsigned processor)
418{
419   struct cso_hash_iter iter = cso_hash_first_node(hash);
420   while (!cso_hash_iter_is_null(iter)) {
421      void *shader = (void *)cso_hash_iter_data(iter);
422      if (processor == PIPE_SHADER_FRAGMENT) {
423         cso_delete_fragment_shader(cso, shader);
424      } else if (processor == PIPE_SHADER_VERTEX) {
425         cso_delete_vertex_shader(cso, shader);
426      }
427      iter = cso_hash_erase(hash, iter);
428   }
429   cso_hash_delete(hash);
430}
431
432void xorg_shaders_destroy(struct xorg_shaders *sc)
433{
434   cache_destroy(sc->exa->cso, sc->vs_hash,
435                 PIPE_SHADER_VERTEX);
436   cache_destroy(sc->exa->cso, sc->fs_hash,
437                 PIPE_SHADER_FRAGMENT);
438
439   free(sc);
440}
441
442static INLINE void *
443shader_from_cache(struct pipe_context *pipe,
444                  unsigned type,
445                  struct cso_hash *hash,
446                  unsigned key)
447{
448   void *shader = 0;
449
450   struct cso_hash_iter iter = cso_hash_find(hash, key);
451
452   if (cso_hash_iter_is_null(iter)) {
453      if (type == PIPE_SHADER_VERTEX)
454         shader = create_vs(pipe, key);
455      else
456         shader = create_fs(pipe, key);
457      cso_hash_insert(hash, key, shader);
458   } else
459      shader = (void *)cso_hash_iter_data(iter);
460
461   return shader;
462}
463
464struct xorg_shader xorg_shaders_get(struct xorg_shaders *sc,
465                                    unsigned vs_traits,
466                                    unsigned fs_traits)
467{
468   struct xorg_shader shader = {0};
469   void *vs, *fs;
470
471   vs = shader_from_cache(sc->exa->pipe, PIPE_SHADER_VERTEX,
472                          sc->vs_hash, vs_traits);
473   fs = shader_from_cache(sc->exa->pipe, PIPE_SHADER_FRAGMENT,
474                          sc->fs_hash, fs_traits);
475
476   debug_assert(vs && fs);
477   if (!vs || !fs)
478      return shader;
479
480   shader.vs = vs;
481   shader.fs = fs;
482
483   return shader;
484}
485