tgsi_ureg.c revision 8a7d1e7b7681a4f0be9cee9e62477317dcd09caf
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_dump.h"
33#include "util/u_memory.h"
34
35union tgsi_any_token {
36   struct tgsi_version version;
37   struct tgsi_header header;
38   struct tgsi_processor processor;
39   struct tgsi_token token;
40   struct tgsi_declaration decl;
41   struct tgsi_declaration_range decl_range;
42   struct tgsi_declaration_semantic decl_semantic;
43   struct tgsi_immediate imm;
44   union  tgsi_immediate_data imm_data;
45   struct tgsi_instruction insn;
46   struct tgsi_instruction_ext_nv insn_ext_nv;
47   struct tgsi_instruction_ext_label insn_ext_label;
48   struct tgsi_instruction_ext_texture insn_ext_texture;
49   struct tgsi_instruction_ext_predicate insn_ext_predicate;
50   struct tgsi_src_register src;
51   struct tgsi_src_register_ext_swz src_ext_swz;
52   struct tgsi_src_register_ext_mod src_ext_mod;
53   struct tgsi_dimension dim;
54   struct tgsi_dst_register dst;
55   struct tgsi_dst_register_ext_concode dst_ext_code;
56   struct tgsi_dst_register_ext_modulate dst_ext_mod;
57   struct tgsi_dst_register_ext_predicate dst_ext_pred;
58   unsigned value;
59};
60
61
62struct ureg_tokens {
63   union tgsi_any_token *tokens;
64   unsigned size;
65   unsigned order;
66   unsigned count;
67};
68
69#define UREG_MAX_INPUT PIPE_MAX_ATTRIBS
70#define UREG_MAX_OUTPUT PIPE_MAX_ATTRIBS
71#define UREG_MAX_IMMEDIATE 32
72
73#define DOMAIN_DECL 0
74#define DOMAIN_INSN 1
75
76struct ureg_program
77{
78   unsigned processor;
79   struct pipe_context *pipe;
80
81   struct {
82      unsigned semantic_name;
83      unsigned semantic_index;
84      unsigned interp;
85   } input[UREG_MAX_INPUT];
86   unsigned nr_inputs;
87
88   struct {
89      unsigned semantic_name;
90      unsigned semantic_index;
91   } output[UREG_MAX_OUTPUT];
92   unsigned nr_outputs;
93
94   struct {
95      float v[4];
96      unsigned nr;
97   } immediate[UREG_MAX_OUTPUT];
98   unsigned nr_immediates;
99
100
101   unsigned nr_constants;
102   unsigned nr_temps;
103   unsigned nr_samplers;
104
105   struct ureg_tokens domain[2];
106};
107
108static union tgsi_any_token error_tokens[32];
109
110static void tokens_error( struct ureg_tokens *tokens )
111{
112   tokens->tokens = error_tokens;
113   tokens->size = Elements(error_tokens);
114   tokens->count = 0;
115}
116
117
118static void tokens_expand( struct ureg_tokens *tokens,
119                           unsigned count )
120{
121   union tgsi_any_token *tmp;
122
123   if (tokens->tokens == error_tokens)
124      goto fail;
125
126   while (tokens->count + count > tokens->size) {
127      tokens->size = (1 << ++tokens->order);
128   }
129
130   tmp = MALLOC(tokens->size * sizeof(unsigned));
131   if (tmp == NULL) {
132      FREE(tokens->tokens);
133      goto fail;
134   }
135
136   if (tokens->count) {
137      memcpy(tmp, tokens->tokens, tokens->count * sizeof tokens->tokens[0] );
138      FREE(tokens->tokens);
139   }
140
141   tokens->tokens = tmp;
142   return;
143
144fail:
145   tokens_error(tokens);
146}
147
148static void set_bad( struct ureg_program *ureg )
149{
150   tokens_error(&ureg->domain[0]);
151}
152
153
154
155static union tgsi_any_token *get_tokens( struct ureg_program *ureg,
156                                         unsigned domain,
157                                         unsigned count )
158{
159   struct ureg_tokens *tokens = &ureg->domain[domain];
160   union tgsi_any_token *result;
161
162   if (tokens->count + count > tokens->size)
163      tokens_expand(tokens, count);
164
165   result = &tokens->tokens[tokens->count];
166   tokens->count += count;
167   return result;
168}
169
170
171static union tgsi_any_token *retrieve_token( struct ureg_program *ureg,
172                                            unsigned domain,
173                                            unsigned nr )
174{
175   if (ureg->domain[domain].tokens == error_tokens)
176      return &error_tokens[0];
177
178   return &ureg->domain[domain].tokens[nr];
179}
180
181
182
183static INLINE struct ureg_dst
184ureg_dst_register( unsigned file,
185                   unsigned index )
186{
187   struct ureg_dst dst;
188
189   dst.File      = file;
190   dst.WriteMask = TGSI_WRITEMASK_XYZW;
191   dst.Indirect  = 0;
192   dst.Saturate  = 0;
193   dst.Index     = index;
194   dst.Pad1      = 0;
195   dst.Pad2      = 0;
196
197   return dst;
198}
199
200static INLINE struct ureg_src
201ureg_src_register( unsigned file,
202                   unsigned index )
203{
204   struct ureg_src src;
205
206   src.File     = file;
207   src.SwizzleX = TGSI_SWIZZLE_X;
208   src.SwizzleY = TGSI_SWIZZLE_Y;
209   src.SwizzleZ = TGSI_SWIZZLE_Z;
210   src.SwizzleW = TGSI_SWIZZLE_W;
211   src.Pad      = 0;
212   src.Indirect = 0;
213   src.Absolute = 0;
214   src.Index    = index;
215   src.Negate   = 0;
216
217   return src;
218}
219
220
221
222
223static struct ureg_src
224ureg_DECL_input( struct ureg_program *ureg,
225                 unsigned name,
226                 unsigned index,
227                 unsigned interp_mode )
228{
229   unsigned i;
230
231   for (i = 0; i < ureg->nr_inputs; i++) {
232      if (ureg->input[i].semantic_name == name &&
233          ureg->input[i].semantic_index == index)
234         goto out;
235   }
236
237   if (ureg->nr_inputs < UREG_MAX_INPUT) {
238      ureg->input[i].semantic_name = name;
239      ureg->input[i].semantic_index = index;
240      ureg->input[i].interp = interp_mode;
241      ureg->nr_inputs++;
242   }
243   else {
244      set_bad( ureg );
245   }
246
247out:
248   return ureg_src_register( TGSI_FILE_INPUT, i );
249}
250
251
252
253struct ureg_src
254ureg_DECL_fs_input( struct ureg_program *ureg,
255                    unsigned name,
256                    unsigned index,
257                    unsigned interp )
258{
259   return ureg_DECL_input( ureg, name, index, interp );
260}
261
262
263struct ureg_src
264ureg_DECL_vs_input( struct ureg_program *ureg,
265                    unsigned name,
266                    unsigned index )
267{
268   return ureg_DECL_input( ureg, name, index, TGSI_INTERPOLATE_CONSTANT );
269}
270
271
272struct ureg_dst
273ureg_DECL_output( struct ureg_program *ureg,
274                  unsigned name,
275                  unsigned index )
276{
277   unsigned i;
278
279   for (i = 0; i < ureg->nr_outputs; i++) {
280      if (ureg->output[i].semantic_name == name &&
281          ureg->output[i].semantic_index == index)
282         goto out;
283   }
284
285   if (ureg->nr_outputs < UREG_MAX_OUTPUT) {
286      ureg->output[i].semantic_name = name;
287      ureg->output[i].semantic_index = index;
288      ureg->nr_outputs++;
289   }
290   else {
291      set_bad( ureg );
292   }
293
294out:
295   return ureg_dst_register( TGSI_FILE_OUTPUT, i );
296}
297
298
299/* Returns a new constant register.  Keep track of which have been
300 * referred to so that we can emit decls later.
301 *
302 * There is nothing in this code to bind this constant to any tracked
303 * value or manage any constant_buffer contents -- that's the
304 * resposibility of the calling code.
305 */
306struct ureg_src ureg_DECL_constant(struct ureg_program *ureg )
307{
308   return ureg_src_register( TGSI_FILE_TEMPORARY, ureg->nr_constants++ );
309}
310
311
312/* Allocate a new temporary.  No way to release temporaries in this code.
313 */
314struct ureg_dst ureg_DECL_temporary( struct ureg_program *ureg )
315{
316   return ureg_dst_register( TGSI_FILE_TEMPORARY, ureg->nr_temps++ );
317}
318
319
320/* Allocate a new sampler.
321 */
322struct ureg_src ureg_DECL_sampler( struct ureg_program *ureg )
323{
324   return ureg_src_register( TGSI_FILE_SAMPLER, ureg->nr_samplers++ );
325}
326
327
328
329
330static int match_or_expand_immediate( const float *v,
331                                      unsigned nr,
332                                      float *v2,
333                                      unsigned *nr2,
334                                      unsigned *swizzle )
335{
336   unsigned i, j;
337
338   for (i = 0; i < nr; i++) {
339      boolean found = FALSE;
340
341      for (j = 0; j < *nr2 && !found; j++) {
342         if (v[i] == v2[j]) {
343            *swizzle |= j << (i * 2);
344            found = TRUE;
345         }
346      }
347
348      if (!found) {
349         if (*nr2 >= 4)
350            return FALSE;
351
352         v2[*nr2] = v[i];
353         *swizzle |= *nr2 << (i * 2);
354         (*nr2)++;
355      }
356   }
357
358   return TRUE;
359}
360
361
362
363
364struct ureg_src ureg_DECL_immediate( struct ureg_program *ureg,
365                                     const float *v,
366                                     unsigned nr )
367{
368   unsigned i;
369   unsigned swizzle;
370
371   /* Could do a first pass where we examine all existing immediates
372    * without expanding.
373    */
374
375   for (i = 0; i < ureg->nr_immediates; i++) {
376      if (match_or_expand_immediate( v,
377                                     nr,
378                                     ureg->immediate[i].v,
379                                     &ureg->immediate[i].nr,
380                                     &swizzle ))
381         goto out;
382   }
383
384   if (ureg->nr_immediates < UREG_MAX_IMMEDIATE) {
385      i = ureg->nr_immediates++;
386      if (match_or_expand_immediate( v,
387                                     nr,
388                                     ureg->immediate[i].v,
389                                     &ureg->immediate[i].nr,
390                                     &swizzle ))
391         goto out;
392   }
393
394   set_bad( ureg );
395
396out:
397   return ureg_swizzle( ureg_src_register( TGSI_FILE_IMMEDIATE, i ),
398                        (swizzle >> 0) & 0x3,
399                        (swizzle >> 2) & 0x3,
400                        (swizzle >> 4) & 0x3,
401                        (swizzle >> 6) & 0x3);
402}
403
404
405void
406ureg_emit_src( struct ureg_program *ureg,
407               struct ureg_src src )
408{
409   unsigned size = (1 +
410                    (src.Absolute ? 1 : 0) +
411                    (src.Indirect ? 1 : 0));
412
413   union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size );
414   unsigned n = 0;
415
416   out[n].value = 0;
417   out[n].src.File = src.File;
418   out[n].src.SwizzleX = src.SwizzleX;
419   out[n].src.SwizzleY = src.SwizzleY;
420   out[n].src.SwizzleZ = src.SwizzleZ;
421   out[n].src.SwizzleW = src.SwizzleW;
422   out[n].src.Indirect = src.Indirect;
423   out[n].src.Index = src.Index;
424   n++;
425
426   if (src.Absolute) {
427      out[n].value = 0;
428      out[n].src_ext_mod.Absolute = 1;
429      n++;
430   }
431
432   if (src.Indirect) {
433      out[n].value = 0;
434      out[n].src.File = TGSI_FILE_ADDRESS;
435      out[n].src.SwizzleX = TGSI_SWIZZLE_X;
436      out[n].src.SwizzleY = TGSI_SWIZZLE_X;
437      out[n].src.SwizzleZ = TGSI_SWIZZLE_X;
438      out[n].src.SwizzleW = TGSI_SWIZZLE_X;
439      out[n].src.Indirect = 0;
440      out[n].src.Index = 0;
441      n++;
442   }
443
444   assert(n == size);
445}
446
447
448void
449ureg_emit_dst( struct ureg_program *ureg,
450               struct ureg_dst dst )
451{
452   unsigned size = (1 +
453                    (dst.Indirect ? 1 : 0));
454
455   union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size );
456   unsigned n = 0;
457
458   out[n].value = 0;
459   out[n].dst.File = dst.File;
460   out[n].dst.WriteMask = dst.WriteMask;
461   out[n].dst.Indirect = dst.Indirect;
462   out[n].dst.Index = dst.Index;
463   n++;
464
465   if (dst.Indirect) {
466      out[n].value = 0;
467      out[n].src.File = TGSI_FILE_ADDRESS;
468      out[n].src.SwizzleX = TGSI_SWIZZLE_X;
469      out[n].src.SwizzleY = TGSI_SWIZZLE_X;
470      out[n].src.SwizzleZ = TGSI_SWIZZLE_X;
471      out[n].src.SwizzleW = TGSI_SWIZZLE_X;
472      out[n].src.Indirect = 0;
473      out[n].src.Index = 0;
474      n++;
475   }
476
477   assert(n == size);
478}
479
480
481
482unsigned
483ureg_emit_insn(struct ureg_program *ureg,
484               unsigned opcode,
485               boolean saturate,
486               unsigned num_dst,
487               unsigned num_src )
488{
489   union tgsi_any_token *out;
490
491   out = get_tokens( ureg, DOMAIN_INSN, 1 );
492   out[0].value = 0;
493   out[0].insn.Type = TGSI_TOKEN_TYPE_INSTRUCTION;
494   out[0].insn.NrTokens = 0;
495   out[0].insn.Opcode = opcode;
496   out[0].insn.Saturate = saturate;
497   out[0].insn.NrTokens = 0;
498   out[0].insn.NumDstRegs = num_dst;
499   out[0].insn.NumSrcRegs = num_src;
500   out[0].insn.Padding = 0;
501   out[0].insn.Extended = 0;
502
503   return ureg->domain[DOMAIN_INSN].count - 1;
504}
505
506
507void
508ureg_emit_label(struct ureg_program *ureg,
509                unsigned insn_token,
510                unsigned *label_token )
511{
512   union tgsi_any_token *out, *insn;
513
514   out = get_tokens( ureg, DOMAIN_INSN, 1 );
515   insn = retrieve_token( ureg, DOMAIN_INSN, insn_token );
516
517   insn->insn.Extended = 1;
518
519   out[0].value = 0;
520   out[0].insn_ext_label.Type = TGSI_INSTRUCTION_EXT_TYPE_LABEL;
521}
522
523
524void
525ureg_emit_texture(struct ureg_program *ureg,
526                  unsigned insn_token,
527                  unsigned target )
528{
529   union tgsi_any_token *out, *insn;
530
531   out = get_tokens( ureg, DOMAIN_INSN, 1 );
532   insn = retrieve_token( ureg, DOMAIN_INSN, insn_token );
533
534   insn->insn.Extended = 1;
535
536   out[0].value = 0;
537   out[0].insn_ext_texture.Type = TGSI_INSTRUCTION_EXT_TYPE_TEXTURE;
538   out[0].insn_ext_texture.Texture = target;
539}
540
541
542void
543ureg_fixup_insn_size(struct ureg_program *ureg,
544                     unsigned insn )
545{
546   union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, insn );
547
548   out->insn.NrTokens = ureg->domain[DOMAIN_INSN].count - insn - 1;
549}
550
551
552
553
554
555static void emit_decl( struct ureg_program *ureg,
556                       unsigned file,
557                       unsigned index,
558                       unsigned semantic_name,
559                       unsigned semantic_index,
560                       unsigned interp )
561{
562   union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 );
563
564   out[0].value = 0;
565   out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION;
566   out[0].decl.NrTokens = 3;
567   out[0].decl.File = file;
568   out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; /* FIXME! */
569   out[0].decl.Interpolate = interp;
570   out[0].decl.Semantic = 1;
571
572   out[1].value = 0;
573   out[1].decl_range.First =
574      out[1].decl_range.Last = index;
575
576   out[2].value = 0;
577   out[2].decl_semantic.SemanticName = semantic_name;
578   out[2].decl_semantic.SemanticIndex = semantic_index;
579
580}
581
582
583static void emit_decl_range( struct ureg_program *ureg,
584                             unsigned file,
585                             unsigned first,
586                             unsigned count )
587{
588   union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 );
589
590   out[0].value = 0;
591   out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION;
592   out[0].decl.NrTokens = 2;
593   out[0].decl.File = file;
594   out[0].decl.UsageMask = 0xf;
595   out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT;
596   out[0].decl.Semantic = 0;
597
598   out[1].value = 0;
599   out[1].decl_range.First = first;
600   out[1].decl_range.Last = first + count - 1;
601}
602
603static void emit_immediate( struct ureg_program *ureg,
604                            const float *v )
605{
606   union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 5 );
607
608   out[0].value = 0;
609   out[0].imm.Type = TGSI_TOKEN_TYPE_IMMEDIATE;
610   out[0].imm.NrTokens = 5;
611   out[0].imm.DataType = TGSI_IMM_FLOAT32;
612   out[0].imm.Padding = 0;
613   out[0].imm.Extended = 0;
614
615   out[1].imm_data.Float = v[0];
616   out[2].imm_data.Float = v[1];
617   out[3].imm_data.Float = v[2];
618   out[4].imm_data.Float = v[3];
619}
620
621
622
623
624static void emit_decls( struct ureg_program *ureg )
625{
626   unsigned i;
627
628   for (i = 0; i < ureg->nr_inputs; i++) {
629      emit_decl( ureg,
630                 TGSI_FILE_INPUT,
631                 i,
632                 ureg->input[i].semantic_name,
633                 ureg->input[i].semantic_index,
634                 ureg->input[i].interp );
635   }
636
637   for (i = 0; i < ureg->nr_outputs; i++) {
638      emit_decl( ureg,
639                 TGSI_FILE_OUTPUT,
640                 i,
641                 ureg->output[i].semantic_name,
642                 ureg->output[i].semantic_index,
643                 TGSI_INTERPOLATE_CONSTANT );
644   }
645
646   if (ureg->nr_samplers) {
647      emit_decl_range( ureg,
648                       TGSI_FILE_SAMPLER,
649                       0, ureg->nr_samplers );
650   }
651
652   if (ureg->nr_constants) {
653      emit_decl_range( ureg,
654                       TGSI_FILE_CONSTANT,
655                       0, ureg->nr_constants );
656   }
657
658   if (ureg->nr_temps) {
659      emit_decl_range( ureg,
660                       TGSI_FILE_TEMPORARY,
661                       0, ureg->nr_temps );
662   }
663
664   for (i = 0; i < ureg->nr_immediates; i++) {
665      emit_immediate( ureg,
666                      ureg->immediate[i].v );
667   }
668}
669
670/* Append the instruction tokens onto the declarations to build a
671 * contiguous stream suitable to send to the driver.
672 */
673static void copy_instructions( struct ureg_program *ureg )
674{
675   unsigned nr_tokens = ureg->domain[DOMAIN_INSN].count;
676   union tgsi_any_token *out = get_tokens( ureg,
677                                           DOMAIN_DECL,
678                                           nr_tokens );
679
680   memcpy(out,
681          ureg->domain[DOMAIN_INSN].tokens,
682          nr_tokens * sizeof out[0] );
683}
684
685
686static void
687fixup_header_size(struct ureg_program *ureg,
688                     unsigned insn )
689{
690   union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_DECL, 1 );
691
692   out->header.BodySize = ureg->domain[DOMAIN_DECL].count - 3;
693}
694
695
696static void
697emit_header( struct ureg_program *ureg )
698{
699   union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 );
700
701   out[0].version.MajorVersion = 1;
702   out[0].version.MinorVersion = 1;
703   out[0].version.Padding = 0;
704
705   out[1].header.HeaderSize = 2;
706   out[1].header.BodySize = 0;
707
708   out[2].processor.Processor = ureg->processor;
709   out[2].processor.Padding = 0;
710}
711
712
713void *ureg_create_shader( struct ureg_program *ureg )
714{
715   struct pipe_shader_state state;
716   unsigned insn;
717
718   emit_header( ureg );
719   emit_decls( ureg );
720   copy_instructions( ureg );
721   fixup_header_size( ureg, insn );
722
723   if (ureg->domain[0].tokens == error_tokens ||
724       ureg->domain[1].tokens == error_tokens) {
725      debug_printf("%s: error in generated shader\n", __FUNCTION__);
726      assert(0);
727      return NULL;
728   }
729
730   state.tokens = (const struct tgsi_token *)ureg->domain[DOMAIN_DECL].tokens;
731
732   if (1) {
733      debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__,
734                   ureg->domain[DOMAIN_DECL].count);
735      tgsi_dump( state.tokens, 0 );
736   }
737
738   if (ureg->processor == TGSI_PROCESSOR_VERTEX)
739      return ureg->pipe->create_vs_state( ureg->pipe, &state );
740   else
741      return ureg->pipe->create_fs_state( ureg->pipe, &state );
742}
743
744
745
746
747struct ureg_program *ureg_create( struct pipe_context *pipe,
748                                  unsigned processor )
749{
750   struct ureg_program *ureg = CALLOC_STRUCT( ureg_program );
751   if (ureg == NULL)
752      return NULL;
753
754   ureg->pipe = pipe;
755   ureg->processor = processor;
756   return ureg;
757}
758
759
760void ureg_destroy( struct ureg_program *ureg )
761{
762   unsigned i;
763
764   for (i = 0; i < Elements(ureg->domain); i++) {
765      if (ureg->domain[i].tokens &&
766          ureg->domain[i].tokens != error_tokens)
767         FREE(ureg->domain[i].tokens);
768   }
769
770   FREE(ureg);
771}
772