tgsi_ureg.c revision ff56a12051a91c5c69db9afb85e4a3ebdb17ef96
1/**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE, INC AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28
29#include "pipe/p_context.h"
30#include "pipe/p_state.h"
31#include "tgsi/tgsi_ureg.h"
32#include "tgsi/tgsi_build.h"
33#include "tgsi/tgsi_info.h"
34#include "tgsi/tgsi_dump.h"
35#include "tgsi/tgsi_sanity.h"
36#include "util/u_memory.h"
37#include "util/u_math.h"
38
39union tgsi_any_token {
40   struct tgsi_header header;
41   struct tgsi_processor processor;
42   struct tgsi_token token;
43   struct tgsi_declaration decl;
44   struct tgsi_declaration_range decl_range;
45   struct tgsi_declaration_semantic decl_semantic;
46   struct tgsi_immediate imm;
47   union  tgsi_immediate_data imm_data;
48   struct tgsi_instruction insn;
49   struct tgsi_instruction_predicate insn_predicate;
50   struct tgsi_instruction_label insn_label;
51   struct tgsi_instruction_texture insn_texture;
52   struct tgsi_src_register src;
53   struct tgsi_dimension dim;
54   struct tgsi_dst_register dst;
55   unsigned value;
56};
57
58
59struct ureg_tokens {
60   union tgsi_any_token *tokens;
61   unsigned size;
62   unsigned order;
63   unsigned count;
64};
65
66#define UREG_MAX_INPUT PIPE_MAX_ATTRIBS
67#define UREG_MAX_OUTPUT PIPE_MAX_ATTRIBS
68#define UREG_MAX_CONSTANT_RANGE 32
69#define UREG_MAX_IMMEDIATE 32
70#define UREG_MAX_TEMP 256
71#define UREG_MAX_ADDR 2
72#define UREG_MAX_LOOP 1
73#define UREG_MAX_PRED 1
74
75#define DOMAIN_DECL 0
76#define DOMAIN_INSN 1
77
78struct ureg_program
79{
80   unsigned processor;
81   struct pipe_context *pipe;
82
83   struct {
84      unsigned semantic_name;
85      unsigned semantic_index;
86      unsigned interp;
87   } fs_input[UREG_MAX_INPUT];
88   unsigned nr_fs_inputs;
89
90   unsigned vs_inputs[UREG_MAX_INPUT/32];
91
92   struct {
93      unsigned index;
94   } gs_input[UREG_MAX_INPUT];
95   unsigned nr_gs_inputs;
96
97   struct {
98      unsigned semantic_name;
99      unsigned semantic_index;
100   } output[UREG_MAX_OUTPUT];
101   unsigned nr_outputs;
102
103   struct {
104      union {
105         float f[4];
106         unsigned u[4];
107         int i[4];
108      } value;
109      unsigned nr;
110      unsigned type;
111   } immediate[UREG_MAX_IMMEDIATE];
112   unsigned nr_immediates;
113
114   struct ureg_src sampler[PIPE_MAX_SAMPLERS];
115   unsigned nr_samplers;
116
117   unsigned temps_active[UREG_MAX_TEMP / 32];
118   unsigned nr_temps;
119
120   struct {
121      unsigned first;
122      unsigned last;
123   } constant_range[UREG_MAX_CONSTANT_RANGE];
124   unsigned nr_constant_ranges;
125
126   unsigned nr_addrs;
127   unsigned nr_preds;
128   unsigned nr_loops;
129   unsigned nr_instructions;
130
131   struct ureg_tokens domain[2];
132};
133
134static union tgsi_any_token error_tokens[32];
135
136static void tokens_error( struct ureg_tokens *tokens )
137{
138   if (tokens->tokens && tokens->tokens != error_tokens)
139      FREE(tokens->tokens);
140
141   tokens->tokens = error_tokens;
142   tokens->size = Elements(error_tokens);
143   tokens->count = 0;
144}
145
146
147static void tokens_expand( struct ureg_tokens *tokens,
148                           unsigned count )
149{
150   unsigned old_size = tokens->size * sizeof(unsigned);
151
152   if (tokens->tokens == error_tokens) {
153      return;
154   }
155
156   while (tokens->count + count > tokens->size) {
157      tokens->size = (1 << ++tokens->order);
158   }
159
160   tokens->tokens = REALLOC(tokens->tokens,
161                            old_size,
162                            tokens->size * sizeof(unsigned));
163   if (tokens->tokens == NULL) {
164      tokens_error(tokens);
165   }
166}
167
168static void set_bad( struct ureg_program *ureg )
169{
170   tokens_error(&ureg->domain[0]);
171}
172
173
174
175static union tgsi_any_token *get_tokens( struct ureg_program *ureg,
176                                         unsigned domain,
177                                         unsigned count )
178{
179   struct ureg_tokens *tokens = &ureg->domain[domain];
180   union tgsi_any_token *result;
181
182   if (tokens->count + count > tokens->size)
183      tokens_expand(tokens, count);
184
185   result = &tokens->tokens[tokens->count];
186   tokens->count += count;
187   return result;
188}
189
190
191static union tgsi_any_token *retrieve_token( struct ureg_program *ureg,
192                                            unsigned domain,
193                                            unsigned nr )
194{
195   if (ureg->domain[domain].tokens == error_tokens)
196      return &error_tokens[0];
197
198   return &ureg->domain[domain].tokens[nr];
199}
200
201
202
203static INLINE struct ureg_dst
204ureg_dst_register( unsigned file,
205                   unsigned index )
206{
207   struct ureg_dst dst;
208
209   dst.File      = file;
210   dst.WriteMask = TGSI_WRITEMASK_XYZW;
211   dst.Indirect  = 0;
212   dst.IndirectIndex = 0;
213   dst.IndirectSwizzle = 0;
214   dst.Saturate  = 0;
215   dst.Predicate = 0;
216   dst.PredNegate = 0;
217   dst.PredSwizzleX = TGSI_SWIZZLE_X;
218   dst.PredSwizzleY = TGSI_SWIZZLE_Y;
219   dst.PredSwizzleZ = TGSI_SWIZZLE_Z;
220   dst.PredSwizzleW = TGSI_SWIZZLE_W;
221   dst.Index     = index;
222
223   return dst;
224}
225
226static INLINE struct ureg_src
227ureg_src_register( unsigned file,
228                   unsigned index )
229{
230   struct ureg_src src;
231
232   src.File     = file;
233   src.SwizzleX = TGSI_SWIZZLE_X;
234   src.SwizzleY = TGSI_SWIZZLE_Y;
235   src.SwizzleZ = TGSI_SWIZZLE_Z;
236   src.SwizzleW = TGSI_SWIZZLE_W;
237   src.Pad      = 0;
238   src.Indirect = 0;
239   src.IndirectIndex = 0;
240   src.IndirectSwizzle = 0;
241   src.Absolute = 0;
242   src.Index    = index;
243   src.Negate   = 0;
244
245   return src;
246}
247
248
249
250
251struct ureg_src
252ureg_DECL_fs_input( struct ureg_program *ureg,
253                    unsigned name,
254                    unsigned index,
255                    unsigned interp_mode )
256{
257   unsigned i;
258
259   for (i = 0; i < ureg->nr_fs_inputs; i++) {
260      if (ureg->fs_input[i].semantic_name == name &&
261          ureg->fs_input[i].semantic_index == index)
262         goto out;
263   }
264
265   if (ureg->nr_fs_inputs < UREG_MAX_INPUT) {
266      ureg->fs_input[i].semantic_name = name;
267      ureg->fs_input[i].semantic_index = index;
268      ureg->fs_input[i].interp = interp_mode;
269      ureg->nr_fs_inputs++;
270   }
271   else {
272      set_bad( ureg );
273   }
274
275out:
276   return ureg_src_register( TGSI_FILE_INPUT, i );
277}
278
279
280struct ureg_src
281ureg_DECL_vs_input( struct ureg_program *ureg,
282                    unsigned index )
283{
284   assert(ureg->processor == TGSI_PROCESSOR_VERTEX);
285
286   ureg->vs_inputs[index/32] |= 1 << (index % 32);
287   return ureg_src_register( TGSI_FILE_INPUT, index );
288}
289
290
291struct ureg_src
292ureg_DECL_gs_input(struct ureg_program *ureg,
293                   unsigned index)
294{
295   if (ureg->nr_gs_inputs < UREG_MAX_INPUT) {
296      ureg->gs_input[ureg->nr_gs_inputs].index = index;
297      ureg->nr_gs_inputs++;
298   } else {
299      set_bad(ureg);
300   }
301
302   /* XXX: Add suport for true 2D input registers. */
303   return ureg_src_register(TGSI_FILE_INPUT, index);
304}
305
306
307struct ureg_dst
308ureg_DECL_output( struct ureg_program *ureg,
309                  unsigned name,
310                  unsigned index )
311{
312   unsigned i;
313
314   for (i = 0; i < ureg->nr_outputs; i++) {
315      if (ureg->output[i].semantic_name == name &&
316          ureg->output[i].semantic_index == index)
317         goto out;
318   }
319
320   if (ureg->nr_outputs < UREG_MAX_OUTPUT) {
321      ureg->output[i].semantic_name = name;
322      ureg->output[i].semantic_index = index;
323      ureg->nr_outputs++;
324   }
325   else {
326      set_bad( ureg );
327   }
328
329out:
330   return ureg_dst_register( TGSI_FILE_OUTPUT, i );
331}
332
333
334/* Returns a new constant register.  Keep track of which have been
335 * referred to so that we can emit decls later.
336 *
337 * There is nothing in this code to bind this constant to any tracked
338 * value or manage any constant_buffer contents -- that's the
339 * resposibility of the calling code.
340 */
341struct ureg_src ureg_DECL_constant(struct ureg_program *ureg,
342                                   unsigned index )
343{
344   unsigned minconst = index, maxconst = index;
345   unsigned i;
346
347   /* Inside existing range?
348    */
349   for (i = 0; i < ureg->nr_constant_ranges; i++) {
350      if (ureg->constant_range[i].first <= index &&
351          ureg->constant_range[i].last >= index)
352         goto out;
353   }
354
355   /* Extend existing range?
356    */
357   for (i = 0; i < ureg->nr_constant_ranges; i++) {
358      if (ureg->constant_range[i].last == index - 1) {
359         ureg->constant_range[i].last = index;
360         goto out;
361      }
362
363      if (ureg->constant_range[i].first == index + 1) {
364         ureg->constant_range[i].first = index;
365         goto out;
366      }
367
368      minconst = MIN2(minconst, ureg->constant_range[i].first);
369      maxconst = MAX2(maxconst, ureg->constant_range[i].last);
370   }
371
372   /* Create new range?
373    */
374   if (ureg->nr_constant_ranges < UREG_MAX_CONSTANT_RANGE) {
375      i = ureg->nr_constant_ranges++;
376      ureg->constant_range[i].first = index;
377      ureg->constant_range[i].last = index;
378      goto out;
379   }
380
381   /* Collapse all ranges down to one:
382    */
383   i = 0;
384   ureg->constant_range[0].first = minconst;
385   ureg->constant_range[0].last = maxconst;
386   ureg->nr_constant_ranges = 1;
387
388out:
389   assert(i < ureg->nr_constant_ranges);
390   assert(ureg->constant_range[i].first <= index);
391   assert(ureg->constant_range[i].last >= index);
392   return ureg_src_register( TGSI_FILE_CONSTANT, index );
393}
394
395
396/* Allocate a new temporary.  Temporaries greater than UREG_MAX_TEMP
397 * are legal, but will not be released.
398 */
399struct ureg_dst ureg_DECL_temporary( struct ureg_program *ureg )
400{
401   unsigned i;
402
403   for (i = 0; i < UREG_MAX_TEMP; i += 32) {
404      int bit = ffs(~ureg->temps_active[i/32]);
405      if (bit != 0) {
406         i += bit - 1;
407         goto out;
408      }
409   }
410
411   /* No reusable temps, so allocate a new one:
412    */
413   i = ureg->nr_temps++;
414
415out:
416   if (i < UREG_MAX_TEMP)
417      ureg->temps_active[i/32] |= 1 << (i % 32);
418
419   if (i >= ureg->nr_temps)
420      ureg->nr_temps = i + 1;
421
422   return ureg_dst_register( TGSI_FILE_TEMPORARY, i );
423}
424
425
426void ureg_release_temporary( struct ureg_program *ureg,
427                             struct ureg_dst tmp )
428{
429   if(tmp.File == TGSI_FILE_TEMPORARY)
430      if (tmp.Index < UREG_MAX_TEMP)
431         ureg->temps_active[tmp.Index/32] &= ~(1 << (tmp.Index % 32));
432}
433
434
435/* Allocate a new address register.
436 */
437struct ureg_dst ureg_DECL_address( struct ureg_program *ureg )
438{
439   if (ureg->nr_addrs < UREG_MAX_ADDR)
440      return ureg_dst_register( TGSI_FILE_ADDRESS, ureg->nr_addrs++ );
441
442   assert( 0 );
443   return ureg_dst_register( TGSI_FILE_ADDRESS, 0 );
444}
445
446/* Allocate a new loop register.
447 */
448struct ureg_dst
449ureg_DECL_loop(struct ureg_program *ureg)
450{
451   if (ureg->nr_loops < UREG_MAX_LOOP) {
452      return ureg_dst_register(TGSI_FILE_LOOP, ureg->nr_loops++);
453   }
454
455   assert(0);
456   return ureg_dst_register(TGSI_FILE_LOOP, 0);
457}
458
459/* Allocate a new predicate register.
460 */
461struct ureg_dst
462ureg_DECL_predicate(struct ureg_program *ureg)
463{
464   if (ureg->nr_preds < UREG_MAX_PRED) {
465      return ureg_dst_register(TGSI_FILE_PREDICATE, ureg->nr_preds++);
466   }
467
468   assert(0);
469   return ureg_dst_register(TGSI_FILE_PREDICATE, 0);
470}
471
472/* Allocate a new sampler.
473 */
474struct ureg_src ureg_DECL_sampler( struct ureg_program *ureg,
475                                   unsigned nr )
476{
477   unsigned i;
478
479   for (i = 0; i < ureg->nr_samplers; i++)
480      if (ureg->sampler[i].Index == nr)
481         return ureg->sampler[i];
482
483   if (i < PIPE_MAX_SAMPLERS) {
484      ureg->sampler[i] = ureg_src_register( TGSI_FILE_SAMPLER, nr );
485      ureg->nr_samplers++;
486      return ureg->sampler[i];
487   }
488
489   assert( 0 );
490   return ureg->sampler[0];
491}
492
493
494static int
495match_or_expand_immediate( const unsigned *v,
496                           unsigned nr,
497                           unsigned *v2,
498                           unsigned *nr2,
499                           unsigned *swizzle )
500{
501   unsigned i, j;
502
503   *swizzle = 0;
504
505   for (i = 0; i < nr; i++) {
506      boolean found = FALSE;
507
508      for (j = 0; j < *nr2 && !found; j++) {
509         if (v[i] == v2[j]) {
510            *swizzle |= j << (i * 2);
511            found = TRUE;
512         }
513      }
514
515      if (!found) {
516         if (*nr2 >= 4) {
517            return FALSE;
518         }
519
520         v2[*nr2] = v[i];
521         *swizzle |= *nr2 << (i * 2);
522         (*nr2)++;
523      }
524   }
525
526   return TRUE;
527}
528
529
530static struct ureg_src
531decl_immediate( struct ureg_program *ureg,
532                const unsigned *v,
533                unsigned nr,
534                unsigned type )
535{
536   unsigned i, j;
537   unsigned swizzle;
538
539   /* Could do a first pass where we examine all existing immediates
540    * without expanding.
541    */
542
543   for (i = 0; i < ureg->nr_immediates; i++) {
544      if (ureg->immediate[i].type != type) {
545         continue;
546      }
547      if (match_or_expand_immediate(v,
548                                    nr,
549                                    ureg->immediate[i].value.u,
550                                    &ureg->immediate[i].nr,
551                                    &swizzle)) {
552         goto out;
553      }
554   }
555
556   if (ureg->nr_immediates < UREG_MAX_IMMEDIATE) {
557      i = ureg->nr_immediates++;
558      ureg->immediate[i].type = type;
559      if (match_or_expand_immediate(v,
560                                    nr,
561                                    ureg->immediate[i].value.u,
562                                    &ureg->immediate[i].nr,
563                                    &swizzle)) {
564         goto out;
565      }
566   }
567
568   set_bad(ureg);
569
570out:
571   /* Make sure that all referenced elements are from this immediate.
572    * Has the effect of making size-one immediates into scalars.
573    */
574   for (j = nr; j < 4; j++) {
575      swizzle |= (swizzle & 0x3) << (j * 2);
576   }
577
578   return ureg_swizzle(ureg_src_register(TGSI_FILE_IMMEDIATE, i),
579                       (swizzle >> 0) & 0x3,
580                       (swizzle >> 2) & 0x3,
581                       (swizzle >> 4) & 0x3,
582                       (swizzle >> 6) & 0x3);
583}
584
585
586struct ureg_src
587ureg_DECL_immediate( struct ureg_program *ureg,
588                     const float *v,
589                     unsigned nr )
590{
591   union {
592      float f[4];
593      unsigned u[4];
594   } fu;
595   unsigned int i;
596
597   for (i = 0; i < nr; i++) {
598      fu.f[i] = v[i];
599   }
600
601   return decl_immediate(ureg, fu.u, nr, TGSI_IMM_FLOAT32);
602}
603
604
605struct ureg_src
606ureg_DECL_immediate_uint( struct ureg_program *ureg,
607                          const unsigned *v,
608                          unsigned nr )
609{
610   return decl_immediate(ureg, v, nr, TGSI_IMM_UINT32);
611}
612
613
614struct ureg_src
615ureg_DECL_immediate_int( struct ureg_program *ureg,
616                         const int *v,
617                         unsigned nr )
618{
619   return decl_immediate(ureg, (const unsigned *)v, nr, TGSI_IMM_INT32);
620}
621
622
623void
624ureg_emit_src( struct ureg_program *ureg,
625               struct ureg_src src )
626{
627   unsigned size = 1 + (src.Indirect ? 1 : 0);
628
629   union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size );
630   unsigned n = 0;
631
632   assert(src.File != TGSI_FILE_NULL);
633   assert(src.File != TGSI_FILE_OUTPUT);
634   assert(src.File < TGSI_FILE_COUNT);
635
636   out[n].value = 0;
637   out[n].src.File = src.File;
638   out[n].src.SwizzleX = src.SwizzleX;
639   out[n].src.SwizzleY = src.SwizzleY;
640   out[n].src.SwizzleZ = src.SwizzleZ;
641   out[n].src.SwizzleW = src.SwizzleW;
642   out[n].src.Index = src.Index;
643   out[n].src.Negate = src.Negate;
644   out[0].src.Absolute = src.Absolute;
645   n++;
646
647   if (src.Indirect) {
648      out[0].src.Indirect = 1;
649      out[n].value = 0;
650      out[n].src.File = TGSI_FILE_ADDRESS;
651      out[n].src.SwizzleX = src.IndirectSwizzle;
652      out[n].src.SwizzleY = src.IndirectSwizzle;
653      out[n].src.SwizzleZ = src.IndirectSwizzle;
654      out[n].src.SwizzleW = src.IndirectSwizzle;
655      out[n].src.Index = src.IndirectIndex;
656      n++;
657   }
658
659   assert(n == size);
660}
661
662
663void
664ureg_emit_dst( struct ureg_program *ureg,
665               struct ureg_dst dst )
666{
667   unsigned size = (1 +
668                    (dst.Indirect ? 1 : 0));
669
670   union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size );
671   unsigned n = 0;
672
673   assert(dst.File != TGSI_FILE_NULL);
674   assert(dst.File != TGSI_FILE_CONSTANT);
675   assert(dst.File != TGSI_FILE_INPUT);
676   assert(dst.File != TGSI_FILE_SAMPLER);
677   assert(dst.File != TGSI_FILE_IMMEDIATE);
678   assert(dst.File < TGSI_FILE_COUNT);
679
680   out[n].value = 0;
681   out[n].dst.File = dst.File;
682   out[n].dst.WriteMask = dst.WriteMask;
683   out[n].dst.Indirect = dst.Indirect;
684   out[n].dst.Index = dst.Index;
685   n++;
686
687   if (dst.Indirect) {
688      out[n].value = 0;
689      out[n].src.File = TGSI_FILE_ADDRESS;
690      out[n].src.SwizzleX = dst.IndirectSwizzle;
691      out[n].src.SwizzleY = dst.IndirectSwizzle;
692      out[n].src.SwizzleZ = dst.IndirectSwizzle;
693      out[n].src.SwizzleW = dst.IndirectSwizzle;
694      out[n].src.Index = dst.IndirectIndex;
695      n++;
696   }
697
698   assert(n == size);
699}
700
701
702static void validate( unsigned opcode,
703                      unsigned nr_dst,
704                      unsigned nr_src )
705{
706#ifdef DEBUG
707   const struct tgsi_opcode_info *info = tgsi_get_opcode_info( opcode );
708   assert(info);
709   if(info) {
710      assert(nr_dst == info->num_dst);
711      assert(nr_src == info->num_src);
712   }
713#endif
714}
715
716struct ureg_emit_insn_result
717ureg_emit_insn(struct ureg_program *ureg,
718               unsigned opcode,
719               boolean saturate,
720               boolean predicate,
721               boolean pred_negate,
722               unsigned pred_swizzle_x,
723               unsigned pred_swizzle_y,
724               unsigned pred_swizzle_z,
725               unsigned pred_swizzle_w,
726               unsigned num_dst,
727               unsigned num_src )
728{
729   union tgsi_any_token *out;
730   uint count = predicate ? 2 : 1;
731   struct ureg_emit_insn_result result;
732
733   validate( opcode, num_dst, num_src );
734
735   out = get_tokens( ureg, DOMAIN_INSN, count );
736   out[0].insn = tgsi_default_instruction();
737   out[0].insn.Opcode = opcode;
738   out[0].insn.Saturate = saturate;
739   out[0].insn.NumDstRegs = num_dst;
740   out[0].insn.NumSrcRegs = num_src;
741
742   result.insn_token = ureg->domain[DOMAIN_INSN].count - count;
743   result.extended_token = result.insn_token;
744
745   if (predicate) {
746      out[0].insn.Predicate = 1;
747      out[1].insn_predicate = tgsi_default_instruction_predicate();
748      out[1].insn_predicate.Negate = pred_negate;
749      out[1].insn_predicate.SwizzleX = pred_swizzle_x;
750      out[1].insn_predicate.SwizzleY = pred_swizzle_y;
751      out[1].insn_predicate.SwizzleZ = pred_swizzle_z;
752      out[1].insn_predicate.SwizzleW = pred_swizzle_w;
753   }
754
755   ureg->nr_instructions++;
756
757   return result;
758}
759
760
761void
762ureg_emit_label(struct ureg_program *ureg,
763                unsigned extended_token,
764                unsigned *label_token )
765{
766   union tgsi_any_token *out, *insn;
767
768   if(!label_token)
769      return;
770
771   out = get_tokens( ureg, DOMAIN_INSN, 1 );
772   out[0].value = 0;
773
774   insn = retrieve_token( ureg, DOMAIN_INSN, extended_token );
775   insn->insn.Label = 1;
776
777   *label_token = ureg->domain[DOMAIN_INSN].count - 1;
778}
779
780/* Will return a number which can be used in a label to point to the
781 * next instruction to be emitted.
782 */
783unsigned
784ureg_get_instruction_number( struct ureg_program *ureg )
785{
786   return ureg->nr_instructions;
787}
788
789/* Patch a given label (expressed as a token number) to point to a
790 * given instruction (expressed as an instruction number).
791 */
792void
793ureg_fixup_label(struct ureg_program *ureg,
794                 unsigned label_token,
795                 unsigned instruction_number )
796{
797   union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, label_token );
798
799   out->insn_label.Label = instruction_number;
800}
801
802
803void
804ureg_emit_texture(struct ureg_program *ureg,
805                  unsigned extended_token,
806                  unsigned target )
807{
808   union tgsi_any_token *out, *insn;
809
810   out = get_tokens( ureg, DOMAIN_INSN, 1 );
811   insn = retrieve_token( ureg, DOMAIN_INSN, extended_token );
812
813   insn->insn.Texture = 1;
814
815   out[0].value = 0;
816   out[0].insn_texture.Texture = target;
817}
818
819
820void
821ureg_fixup_insn_size(struct ureg_program *ureg,
822                     unsigned insn )
823{
824   union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, insn );
825
826   assert(out->insn.Type == TGSI_TOKEN_TYPE_INSTRUCTION);
827   out->insn.NrTokens = ureg->domain[DOMAIN_INSN].count - insn - 1;
828}
829
830
831void
832ureg_insn(struct ureg_program *ureg,
833          unsigned opcode,
834          const struct ureg_dst *dst,
835          unsigned nr_dst,
836          const struct ureg_src *src,
837          unsigned nr_src )
838{
839   struct ureg_emit_insn_result insn;
840   unsigned i;
841   boolean saturate;
842   boolean predicate;
843   boolean negate = FALSE;
844   unsigned swizzle[4] = { 0 };
845
846   saturate = nr_dst ? dst[0].Saturate : FALSE;
847   predicate = nr_dst ? dst[0].Predicate : FALSE;
848   if (predicate) {
849      negate = dst[0].PredNegate;
850      swizzle[0] = dst[0].PredSwizzleX;
851      swizzle[1] = dst[0].PredSwizzleY;
852      swizzle[2] = dst[0].PredSwizzleZ;
853      swizzle[3] = dst[0].PredSwizzleW;
854   }
855
856   insn = ureg_emit_insn(ureg,
857                         opcode,
858                         saturate,
859                         predicate,
860                         negate,
861                         swizzle[0],
862                         swizzle[1],
863                         swizzle[2],
864                         swizzle[3],
865                         nr_dst,
866                         nr_src);
867
868   for (i = 0; i < nr_dst; i++)
869      ureg_emit_dst( ureg, dst[i] );
870
871   for (i = 0; i < nr_src; i++)
872      ureg_emit_src( ureg, src[i] );
873
874   ureg_fixup_insn_size( ureg, insn.insn_token );
875}
876
877void
878ureg_tex_insn(struct ureg_program *ureg,
879              unsigned opcode,
880              const struct ureg_dst *dst,
881              unsigned nr_dst,
882              unsigned target,
883              const struct ureg_src *src,
884              unsigned nr_src )
885{
886   struct ureg_emit_insn_result insn;
887   unsigned i;
888   boolean saturate;
889   boolean predicate;
890   boolean negate = FALSE;
891   unsigned swizzle[4] = { 0 };
892
893   saturate = nr_dst ? dst[0].Saturate : FALSE;
894   predicate = nr_dst ? dst[0].Predicate : FALSE;
895   if (predicate) {
896      negate = dst[0].PredNegate;
897      swizzle[0] = dst[0].PredSwizzleX;
898      swizzle[1] = dst[0].PredSwizzleY;
899      swizzle[2] = dst[0].PredSwizzleZ;
900      swizzle[3] = dst[0].PredSwizzleW;
901   }
902
903   insn = ureg_emit_insn(ureg,
904                         opcode,
905                         saturate,
906                         predicate,
907                         negate,
908                         swizzle[0],
909                         swizzle[1],
910                         swizzle[2],
911                         swizzle[3],
912                         nr_dst,
913                         nr_src);
914
915   ureg_emit_texture( ureg, insn.extended_token, target );
916
917   for (i = 0; i < nr_dst; i++)
918      ureg_emit_dst( ureg, dst[i] );
919
920   for (i = 0; i < nr_src; i++)
921      ureg_emit_src( ureg, src[i] );
922
923   ureg_fixup_insn_size( ureg, insn.insn_token );
924}
925
926
927void
928ureg_label_insn(struct ureg_program *ureg,
929                unsigned opcode,
930                const struct ureg_src *src,
931                unsigned nr_src,
932                unsigned *label_token )
933{
934   struct ureg_emit_insn_result insn;
935   unsigned i;
936
937   insn = ureg_emit_insn(ureg,
938                         opcode,
939                         FALSE,
940                         FALSE,
941                         FALSE,
942                         TGSI_SWIZZLE_X,
943                         TGSI_SWIZZLE_Y,
944                         TGSI_SWIZZLE_Z,
945                         TGSI_SWIZZLE_W,
946                         0,
947                         nr_src);
948
949   ureg_emit_label( ureg, insn.extended_token, label_token );
950
951   for (i = 0; i < nr_src; i++)
952      ureg_emit_src( ureg, src[i] );
953
954   ureg_fixup_insn_size( ureg, insn.insn_token );
955}
956
957
958
959static void emit_decl( struct ureg_program *ureg,
960                       unsigned file,
961                       unsigned index,
962                       unsigned semantic_name,
963                       unsigned semantic_index,
964                       unsigned interp )
965{
966   union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 );
967
968   out[0].value = 0;
969   out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION;
970   out[0].decl.NrTokens = 3;
971   out[0].decl.File = file;
972   out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; /* FIXME! */
973   out[0].decl.Interpolate = interp;
974   out[0].decl.Semantic = 1;
975
976   out[1].value = 0;
977   out[1].decl_range.First =
978      out[1].decl_range.Last = index;
979
980   out[2].value = 0;
981   out[2].decl_semantic.Name = semantic_name;
982   out[2].decl_semantic.Index = semantic_index;
983
984}
985
986
987static void emit_decl_range( struct ureg_program *ureg,
988                             unsigned file,
989                             unsigned first,
990                             unsigned count )
991{
992   union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 );
993
994   out[0].value = 0;
995   out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION;
996   out[0].decl.NrTokens = 2;
997   out[0].decl.File = file;
998   out[0].decl.UsageMask = 0xf;
999   out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT;
1000   out[0].decl.Semantic = 0;
1001
1002   out[1].value = 0;
1003   out[1].decl_range.First = first;
1004   out[1].decl_range.Last = first + count - 1;
1005}
1006
1007static void
1008emit_immediate( struct ureg_program *ureg,
1009                const unsigned *v,
1010                unsigned type )
1011{
1012   union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 5 );
1013
1014   out[0].value = 0;
1015   out[0].imm.Type = TGSI_TOKEN_TYPE_IMMEDIATE;
1016   out[0].imm.NrTokens = 5;
1017   out[0].imm.DataType = type;
1018   out[0].imm.Padding = 0;
1019
1020   out[1].imm_data.Uint = v[0];
1021   out[2].imm_data.Uint = v[1];
1022   out[3].imm_data.Uint = v[2];
1023   out[4].imm_data.Uint = v[3];
1024}
1025
1026
1027
1028
1029static void emit_decls( struct ureg_program *ureg )
1030{
1031   unsigned i;
1032
1033   if (ureg->processor == TGSI_PROCESSOR_VERTEX) {
1034      for (i = 0; i < UREG_MAX_INPUT; i++) {
1035         if (ureg->vs_inputs[i/32] & (1 << (i%32))) {
1036            emit_decl_range( ureg, TGSI_FILE_INPUT, i, 1 );
1037         }
1038      }
1039   } else if (ureg->processor == TGSI_PROCESSOR_FRAGMENT) {
1040      for (i = 0; i < ureg->nr_fs_inputs; i++) {
1041         emit_decl( ureg,
1042                    TGSI_FILE_INPUT,
1043                    i,
1044                    ureg->fs_input[i].semantic_name,
1045                    ureg->fs_input[i].semantic_index,
1046                    ureg->fs_input[i].interp );
1047      }
1048   } else {
1049      for (i = 0; i < ureg->nr_gs_inputs; i++) {
1050         emit_decl_range(ureg,
1051                         TGSI_FILE_INPUT,
1052                         ureg->gs_input[i].index,
1053                         1);
1054      }
1055   }
1056
1057   for (i = 0; i < ureg->nr_outputs; i++) {
1058      emit_decl( ureg,
1059                 TGSI_FILE_OUTPUT,
1060                 i,
1061                 ureg->output[i].semantic_name,
1062                 ureg->output[i].semantic_index,
1063                 TGSI_INTERPOLATE_CONSTANT );
1064   }
1065
1066   for (i = 0; i < ureg->nr_samplers; i++) {
1067      emit_decl_range( ureg,
1068                       TGSI_FILE_SAMPLER,
1069                       ureg->sampler[i].Index, 1 );
1070   }
1071
1072   if (ureg->nr_constant_ranges) {
1073      for (i = 0; i < ureg->nr_constant_ranges; i++)
1074         emit_decl_range( ureg,
1075                          TGSI_FILE_CONSTANT,
1076                          ureg->constant_range[i].first,
1077                          (ureg->constant_range[i].last + 1 -
1078                           ureg->constant_range[i].first) );
1079   }
1080
1081   if (ureg->nr_temps) {
1082      emit_decl_range( ureg,
1083                       TGSI_FILE_TEMPORARY,
1084                       0, ureg->nr_temps );
1085   }
1086
1087   if (ureg->nr_addrs) {
1088      emit_decl_range( ureg,
1089                       TGSI_FILE_ADDRESS,
1090                       0, ureg->nr_addrs );
1091   }
1092
1093   if (ureg->nr_loops) {
1094      emit_decl_range(ureg,
1095                      TGSI_FILE_LOOP,
1096                      0,
1097                      ureg->nr_loops);
1098   }
1099
1100   if (ureg->nr_preds) {
1101      emit_decl_range(ureg,
1102                      TGSI_FILE_PREDICATE,
1103                      0,
1104                      ureg->nr_preds);
1105   }
1106
1107   for (i = 0; i < ureg->nr_immediates; i++) {
1108      emit_immediate( ureg,
1109                      ureg->immediate[i].value.u,
1110                      ureg->immediate[i].type );
1111   }
1112}
1113
1114/* Append the instruction tokens onto the declarations to build a
1115 * contiguous stream suitable to send to the driver.
1116 */
1117static void copy_instructions( struct ureg_program *ureg )
1118{
1119   unsigned nr_tokens = ureg->domain[DOMAIN_INSN].count;
1120   union tgsi_any_token *out = get_tokens( ureg,
1121                                           DOMAIN_DECL,
1122                                           nr_tokens );
1123
1124   memcpy(out,
1125          ureg->domain[DOMAIN_INSN].tokens,
1126          nr_tokens * sizeof out[0] );
1127}
1128
1129
1130static void
1131fixup_header_size(struct ureg_program *ureg)
1132{
1133   union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_DECL, 0 );
1134
1135   out->header.BodySize = ureg->domain[DOMAIN_DECL].count - 2;
1136}
1137
1138
1139static void
1140emit_header( struct ureg_program *ureg )
1141{
1142   union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 );
1143
1144   out[0].header.HeaderSize = 2;
1145   out[0].header.BodySize = 0;
1146
1147   out[1].processor.Processor = ureg->processor;
1148   out[1].processor.Padding = 0;
1149}
1150
1151
1152const struct tgsi_token *ureg_finalize( struct ureg_program *ureg )
1153{
1154   const struct tgsi_token *tokens;
1155
1156   emit_header( ureg );
1157   emit_decls( ureg );
1158   copy_instructions( ureg );
1159   fixup_header_size( ureg );
1160
1161   if (ureg->domain[0].tokens == error_tokens ||
1162       ureg->domain[1].tokens == error_tokens) {
1163      debug_printf("%s: error in generated shader\n", __FUNCTION__);
1164      assert(0);
1165      return NULL;
1166   }
1167
1168   tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token;
1169
1170   if (0) {
1171      debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__,
1172                   ureg->domain[DOMAIN_DECL].count);
1173      tgsi_dump( tokens, 0 );
1174   }
1175
1176#if DEBUG
1177   if (tokens && !tgsi_sanity_check(tokens)) {
1178      debug_printf("tgsi_ureg.c, sanity check failed on generated tokens:\n");
1179      tgsi_dump(tokens, 0);
1180      assert(0);
1181   }
1182#endif
1183
1184
1185   return tokens;
1186}
1187
1188
1189void *ureg_create_shader( struct ureg_program *ureg,
1190                          struct pipe_context *pipe )
1191{
1192   struct pipe_shader_state state;
1193
1194   state.tokens = ureg_finalize(ureg);
1195   if(!state.tokens)
1196      return NULL;
1197
1198   if (ureg->processor == TGSI_PROCESSOR_VERTEX)
1199      return pipe->create_vs_state( pipe, &state );
1200   else
1201      return pipe->create_fs_state( pipe, &state );
1202}
1203
1204
1205const struct tgsi_token *ureg_get_tokens( struct ureg_program *ureg,
1206                                          unsigned *nr_tokens )
1207{
1208   const struct tgsi_token *tokens;
1209
1210   ureg_finalize(ureg);
1211
1212   tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token;
1213
1214   if (nr_tokens)
1215      *nr_tokens = ureg->domain[DOMAIN_DECL].size;
1216
1217   ureg->domain[DOMAIN_DECL].tokens = 0;
1218   ureg->domain[DOMAIN_DECL].size = 0;
1219   ureg->domain[DOMAIN_DECL].order = 0;
1220   ureg->domain[DOMAIN_DECL].count = 0;
1221
1222   return tokens;
1223}
1224
1225
1226struct ureg_program *ureg_create( unsigned processor )
1227{
1228   struct ureg_program *ureg = CALLOC_STRUCT( ureg_program );
1229   if (ureg == NULL)
1230      return NULL;
1231
1232   ureg->processor = processor;
1233   return ureg;
1234}
1235
1236
1237void ureg_destroy( struct ureg_program *ureg )
1238{
1239   unsigned i;
1240
1241   for (i = 0; i < Elements(ureg->domain); i++) {
1242      if (ureg->domain[i].tokens &&
1243          ureg->domain[i].tokens != error_tokens)
1244         FREE(ureg->domain[i].tokens);
1245   }
1246
1247   FREE(ureg);
1248}
1249