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