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