draw: hack around weird primitive id input in gs
[mesa.git] / src / gallium / auxiliary / gallivm / lp_bld_tgsi_info.c
1 /**************************************************************************
2 *
3 * Copyright 2010 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 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 **************************************************************************/
27
28
29 #include "util/u_memory.h"
30 #include "util/u_math.h"
31 #include "tgsi/tgsi_parse.h"
32 #include "tgsi/tgsi_util.h"
33 #include "tgsi/tgsi_dump.h"
34 #include "tgsi/tgsi_strings.h"
35 #include "lp_bld_debug.h"
36 #include "lp_bld_tgsi.h"
37
38
39 /**
40 * Analysis context.
41 *
42 * This is where we keep store the value of each channel of the IMM/TEMP/OUT
43 * register values, as we walk the shader.
44 */
45 struct analysis_context
46 {
47 struct lp_tgsi_info *info;
48
49 unsigned num_imms;
50 float imm[LP_MAX_TGSI_IMMEDIATES][4];
51
52 struct lp_tgsi_channel_info temp[32][4];
53 };
54
55
56 /**
57 * Describe the specified channel of the src register.
58 */
59 static void
60 analyse_src(struct analysis_context *ctx,
61 struct lp_tgsi_channel_info *chan_info,
62 const struct tgsi_src_register *src,
63 unsigned chan)
64 {
65 chan_info->file = TGSI_FILE_NULL;
66 if (!src->Indirect && !src->Absolute && !src->Negate) {
67 unsigned swizzle = tgsi_util_get_src_register_swizzle(src, chan);
68 if (src->File == TGSI_FILE_TEMPORARY) {
69 if (src->Index < Elements(ctx->temp)) {
70 *chan_info = ctx->temp[src->Index][swizzle];
71 }
72 } else {
73 chan_info->file = src->File;
74 if (src->File == TGSI_FILE_IMMEDIATE) {
75 assert(src->Index < Elements(ctx->imm));
76 if (src->Index < Elements(ctx->imm)) {
77 chan_info->u.value = ctx->imm[src->Index][swizzle];
78 }
79 } else {
80 chan_info->u.index = src->Index;
81 chan_info->swizzle = swizzle;
82 }
83 }
84 }
85 }
86
87
88 /**
89 * Whether this register channel refers to a specific immediate value.
90 */
91 static boolean
92 is_immediate(const struct lp_tgsi_channel_info *chan_info, float value)
93 {
94 return chan_info->file == TGSI_FILE_IMMEDIATE &&
95 chan_info->u.value == value;
96 }
97
98
99 /**
100 * Analyse properties of tex instructions, in particular used
101 * to figure out if a texture is considered indirect.
102 * Not actually used by much except the tgsi dumping code.
103 */
104 static void
105 analyse_tex(struct analysis_context *ctx,
106 const struct tgsi_full_instruction *inst,
107 enum lp_build_tex_modifier modifier)
108 {
109 struct lp_tgsi_info *info = ctx->info;
110 unsigned chan;
111
112 if (info->num_texs < Elements(info->tex)) {
113 struct lp_tgsi_texture_info *tex_info = &info->tex[info->num_texs];
114 boolean indirect = FALSE;
115 unsigned readmask = 0;
116
117 tex_info->target = inst->Texture.Texture;
118 switch (inst->Texture.Texture) {
119 case TGSI_TEXTURE_1D:
120 readmask = TGSI_WRITEMASK_X;
121 break;
122 case TGSI_TEXTURE_1D_ARRAY:
123 case TGSI_TEXTURE_2D:
124 case TGSI_TEXTURE_RECT:
125 readmask = TGSI_WRITEMASK_XY;
126 break;
127 case TGSI_TEXTURE_SHADOW1D:
128 case TGSI_TEXTURE_SHADOW1D_ARRAY:
129 case TGSI_TEXTURE_SHADOW2D:
130 case TGSI_TEXTURE_SHADOWRECT:
131 case TGSI_TEXTURE_2D_ARRAY:
132 case TGSI_TEXTURE_3D:
133 case TGSI_TEXTURE_CUBE:
134 readmask = TGSI_WRITEMASK_XYZ;
135 break;
136 case TGSI_TEXTURE_SHADOW2D_ARRAY:
137 case TGSI_TEXTURE_SHADOWCUBE:
138 readmask = TGSI_WRITEMASK_XYZW;
139 break;
140 case TGSI_TEXTURE_CUBE_ARRAY:
141 readmask = TGSI_WRITEMASK_XYZW;
142 break;
143 case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
144 readmask = TGSI_WRITEMASK_XYZW;
145 break;
146 default:
147 assert(0);
148 return;
149 }
150 /* XXX
151 * For cube map arrays, this will not analyze lod or shadow argument.
152 * For shadow cube, this will not analyze lod bias argument.
153 * "Indirect" really has no meaning for such textures anyway though.
154 */
155
156 if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) {
157 /* We don't track explicit derivatives, although we could */
158 indirect = TRUE;
159 tex_info->sampler_unit = inst->Src[3].Register.Index;
160 tex_info->texture_unit = inst->Src[3].Register.Index;
161 } else {
162 if (modifier == LP_BLD_TEX_MODIFIER_PROJECTED ||
163 modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS ||
164 modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD) {
165 readmask |= TGSI_WRITEMASK_W;
166 }
167 tex_info->sampler_unit = inst->Src[1].Register.Index;
168 tex_info->texture_unit = inst->Src[1].Register.Index;
169 }
170
171 for (chan = 0; chan < 4; ++chan) {
172 struct lp_tgsi_channel_info *chan_info = &tex_info->coord[chan];
173 if (readmask & (1 << chan)) {
174 analyse_src(ctx, chan_info, &inst->Src[0].Register, chan);
175 if (chan_info->file != TGSI_FILE_INPUT) {
176 indirect = TRUE;
177 }
178 } else {
179 memset(chan_info, 0, sizeof *chan_info);
180 }
181 }
182
183 if (indirect) {
184 info->indirect_textures = TRUE;
185 }
186
187 ++info->num_texs;
188 } else {
189 info->indirect_textures = TRUE;
190 }
191 }
192
193
194 /**
195 * Analyse properties of sample instructions, in particular used
196 * to figure out if a texture is considered indirect.
197 * Not actually used by much except the tgsi dumping code.
198 */
199 static void
200 analyse_sample(struct analysis_context *ctx,
201 const struct tgsi_full_instruction *inst,
202 enum lp_build_tex_modifier modifier,
203 boolean shadow)
204 {
205 struct lp_tgsi_info *info = ctx->info;
206 unsigned chan;
207
208 if (info->num_texs < Elements(info->tex)) {
209 struct lp_tgsi_texture_info *tex_info = &info->tex[info->num_texs];
210 boolean indirect = FALSE;
211 boolean shadow = FALSE;
212 unsigned readmask;
213
214 /*
215 * We don't really get much information here, in particular not
216 * the target info, hence no useful writemask neither. Maybe should just
217 * forget the whole function.
218 */
219 readmask = TGSI_WRITEMASK_XYZW;
220
221 tex_info->texture_unit = inst->Src[1].Register.Index;
222 tex_info->sampler_unit = inst->Src[2].Register.Index;
223
224 if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV ||
225 modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD ||
226 modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS || shadow) {
227 /* We don't track insts with additional regs, although we could */
228 indirect = TRUE;
229 }
230
231 for (chan = 0; chan < 4; ++chan) {
232 struct lp_tgsi_channel_info *chan_info = &tex_info->coord[chan];
233 if (readmask & (1 << chan)) {
234 analyse_src(ctx, chan_info, &inst->Src[0].Register, chan);
235 if (chan_info->file != TGSI_FILE_INPUT) {
236 indirect = TRUE;
237 }
238 } else {
239 memset(chan_info, 0, sizeof *chan_info);
240 }
241 }
242
243 if (indirect) {
244 info->indirect_textures = TRUE;
245 }
246
247 ++info->num_texs;
248 } else {
249 info->indirect_textures = TRUE;
250 }
251 }
252
253
254 /**
255 * Process an instruction, and update the register values accordingly.
256 */
257 static void
258 analyse_instruction(struct analysis_context *ctx,
259 struct tgsi_full_instruction *inst)
260 {
261 struct lp_tgsi_info *info = ctx->info;
262 struct lp_tgsi_channel_info (*regs)[4];
263 unsigned max_regs;
264 unsigned i;
265 unsigned index;
266 unsigned chan;
267
268 for (i = 0; i < inst->Instruction.NumDstRegs; ++i) {
269 const struct tgsi_dst_register *dst = &inst->Dst[i].Register;
270
271 /*
272 * Get the lp_tgsi_channel_info array corresponding to the destination
273 * register file.
274 */
275
276 if (dst->File == TGSI_FILE_TEMPORARY) {
277 regs = ctx->temp;
278 max_regs = Elements(ctx->temp);
279 } else if (dst->File == TGSI_FILE_OUTPUT) {
280 regs = info->output;
281 max_regs = Elements(info->output);
282 } else if (dst->File == TGSI_FILE_ADDRESS ||
283 dst->File == TGSI_FILE_PREDICATE) {
284 continue;
285 } else {
286 assert(0);
287 continue;
288 }
289
290 /*
291 * Detect direct TEX instructions
292 */
293
294 switch (inst->Instruction.Opcode) {
295 case TGSI_OPCODE_TEX:
296 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE);
297 break;
298 case TGSI_OPCODE_TXD:
299 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV);
300 break;
301 case TGSI_OPCODE_TXB:
302 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS);
303 break;
304 case TGSI_OPCODE_TXL:
305 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD);
306 break;
307 case TGSI_OPCODE_TXP:
308 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_PROJECTED);
309 break;
310 case TGSI_OPCODE_TEX2:
311 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE);
312 break;
313 case TGSI_OPCODE_TXB2:
314 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS);
315 break;
316 case TGSI_OPCODE_TXL2:
317 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD);
318 break;
319 case TGSI_OPCODE_SAMPLE:
320 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_NONE, FALSE);
321 break;
322 case TGSI_OPCODE_SAMPLE_C:
323 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_NONE, TRUE);
324 break;
325 case TGSI_OPCODE_SAMPLE_C_LZ:
326 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_ZERO, TRUE);
327 break;
328 case TGSI_OPCODE_SAMPLE_D:
329 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV, FALSE);
330 break;
331 case TGSI_OPCODE_SAMPLE_B:
332 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS, FALSE);
333 break;
334 case TGSI_OPCODE_SAMPLE_L:
335 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD, FALSE);
336 break;
337 default:
338 break;
339 }
340
341 /*
342 * Keep track of assignments and writes
343 */
344
345 if (dst->Indirect) {
346 /*
347 * It could be any register index so clear all register indices.
348 */
349
350 for (chan = 0; chan < 4; ++chan) {
351 if (dst->WriteMask & (1 << chan)) {
352 for (index = 0; index < max_regs; ++index) {
353 regs[index][chan].file = TGSI_FILE_NULL;
354 }
355 }
356 }
357 } else if (dst->Index < max_regs) {
358 /*
359 * Update this destination register value.
360 */
361
362 struct lp_tgsi_channel_info res[4];
363
364 memset(res, 0, sizeof res);
365
366 if (!inst->Instruction.Predicate &&
367 !inst->Instruction.Saturate) {
368 for (chan = 0; chan < 4; ++chan) {
369 if (dst->WriteMask & (1 << chan)) {
370 if (inst->Instruction.Opcode == TGSI_OPCODE_MOV) {
371 analyse_src(ctx, &res[chan],
372 &inst->Src[0].Register, chan);
373 } else if (inst->Instruction.Opcode == TGSI_OPCODE_MUL) {
374 /*
375 * Propagate values across 1.0 and 0.0 multiplications.
376 */
377
378 struct lp_tgsi_channel_info src0;
379 struct lp_tgsi_channel_info src1;
380
381 analyse_src(ctx, &src0, &inst->Src[0].Register, chan);
382 analyse_src(ctx, &src1, &inst->Src[1].Register, chan);
383
384 if (is_immediate(&src0, 0.0f)) {
385 res[chan] = src0;
386 } else if (is_immediate(&src1, 0.0f)) {
387 res[chan] = src1;
388 } else if (is_immediate(&src0, 1.0f)) {
389 res[chan] = src1;
390 } else if (is_immediate(&src1, 1.0f)) {
391 res[chan] = src0;
392 }
393 }
394 }
395 }
396 }
397
398 for (chan = 0; chan < 4; ++chan) {
399 if (dst->WriteMask & (1 << chan)) {
400 regs[dst->Index][chan] = res[chan];
401 }
402 }
403 }
404 }
405
406 /*
407 * Clear all temporaries information in presence of a control flow opcode.
408 */
409
410 switch (inst->Instruction.Opcode) {
411 case TGSI_OPCODE_IF:
412 case TGSI_OPCODE_UIF:
413 case TGSI_OPCODE_ELSE:
414 case TGSI_OPCODE_ENDIF:
415 case TGSI_OPCODE_BGNLOOP:
416 case TGSI_OPCODE_BRK:
417 case TGSI_OPCODE_BREAKC:
418 case TGSI_OPCODE_CONT:
419 case TGSI_OPCODE_ENDLOOP:
420 case TGSI_OPCODE_CALLNZ:
421 case TGSI_OPCODE_CAL:
422 case TGSI_OPCODE_BGNSUB:
423 case TGSI_OPCODE_ENDSUB:
424 case TGSI_OPCODE_SWITCH:
425 case TGSI_OPCODE_CASE:
426 case TGSI_OPCODE_DEFAULT:
427 case TGSI_OPCODE_ENDSWITCH:
428 case TGSI_OPCODE_RET:
429 case TGSI_OPCODE_END:
430 /* XXX: Are there more cases? */
431 memset(&ctx->temp, 0, sizeof ctx->temp);
432 memset(&info->output, 0, sizeof info->output);
433 default:
434 break;
435 }
436 }
437
438
439 static INLINE void
440 dump_info(const struct tgsi_token *tokens,
441 struct lp_tgsi_info *info)
442 {
443 unsigned index;
444 unsigned chan;
445
446 tgsi_dump(tokens, 0);
447
448 for (index = 0; index < info->num_texs; ++index) {
449 const struct lp_tgsi_texture_info *tex_info = &info->tex[index];
450 debug_printf("TEX[%u] =", index);
451 for (chan = 0; chan < 4; ++chan) {
452 const struct lp_tgsi_channel_info *chan_info =
453 &tex_info->coord[chan];
454 if (chan_info->file != TGSI_FILE_NULL) {
455 debug_printf(" %s[%u].%c",
456 tgsi_file_name(chan_info->file),
457 chan_info->u.index,
458 "xyzw01"[chan_info->swizzle]);
459 } else {
460 debug_printf(" _");
461 }
462 }
463 debug_printf(", RES[%u], SAMP[%u], %s\n",
464 tex_info->texture_unit,
465 tex_info->sampler_unit,
466 tgsi_texture_names[tex_info->target]);
467 }
468
469 for (index = 0; index < PIPE_MAX_SHADER_OUTPUTS; ++index) {
470 for (chan = 0; chan < 4; ++chan) {
471 const struct lp_tgsi_channel_info *chan_info =
472 &info->output[index][chan];
473 if (chan_info->file != TGSI_FILE_NULL) {
474 debug_printf("OUT[%u].%c = ", index, "xyzw"[chan]);
475 if (chan_info->file == TGSI_FILE_IMMEDIATE) {
476 debug_printf("%f", chan_info->u.value);
477 } else {
478 const char *file_name;
479 switch (chan_info->file) {
480 case TGSI_FILE_CONSTANT:
481 file_name = "CONST";
482 break;
483 case TGSI_FILE_INPUT:
484 file_name = "IN";
485 break;
486 default:
487 file_name = "???";
488 break;
489 }
490 debug_printf("%s[%u].%c",
491 file_name,
492 chan_info->u.index,
493 "xyzw01"[chan_info->swizzle]);
494 }
495 debug_printf("\n");
496 }
497 }
498 }
499 }
500
501
502 /**
503 * Detect any direct relationship between the output color
504 */
505 void
506 lp_build_tgsi_info(const struct tgsi_token *tokens,
507 struct lp_tgsi_info *info)
508 {
509 struct tgsi_parse_context parse;
510 struct analysis_context *ctx;
511 unsigned index;
512 unsigned chan;
513
514 memset(info, 0, sizeof *info);
515
516 tgsi_scan_shader(tokens, &info->base);
517
518 ctx = CALLOC(1, sizeof(struct analysis_context));
519 ctx->info = info;
520
521 tgsi_parse_init(&parse, tokens);
522
523 while (!tgsi_parse_end_of_tokens(&parse)) {
524 tgsi_parse_token(&parse);
525
526 switch (parse.FullToken.Token.Type) {
527 case TGSI_TOKEN_TYPE_DECLARATION:
528 break;
529
530 case TGSI_TOKEN_TYPE_INSTRUCTION:
531 {
532 struct tgsi_full_instruction *inst =
533 &parse.FullToken.FullInstruction;
534
535 if (inst->Instruction.Opcode == TGSI_OPCODE_END ||
536 inst->Instruction.Opcode == TGSI_OPCODE_BGNSUB) {
537 /* We reached the end of main function body. */
538 goto finished;
539 }
540
541 analyse_instruction(ctx, inst);
542 }
543 break;
544
545 case TGSI_TOKEN_TYPE_IMMEDIATE:
546 {
547 const unsigned size =
548 parse.FullToken.FullImmediate.Immediate.NrTokens - 1;
549 assert(size <= 4);
550 if (ctx->num_imms < Elements(ctx->imm)) {
551 for (chan = 0; chan < size; ++chan) {
552 float value = parse.FullToken.FullImmediate.u[chan].Float;
553 ctx->imm[ctx->num_imms][chan] = value;
554
555 if (value < 0.0f || value > 1.0f) {
556 info->unclamped_immediates = TRUE;
557 }
558 }
559 ++ctx->num_imms;
560 }
561 }
562 break;
563
564 case TGSI_TOKEN_TYPE_PROPERTY:
565 break;
566
567 default:
568 assert(0);
569 }
570 }
571 finished:
572
573 tgsi_parse_free(&parse);
574 FREE(ctx);
575
576
577 /*
578 * Link the output color values.
579 */
580
581 for (index = 0; index < PIPE_MAX_COLOR_BUFS; ++index) {
582 const struct lp_tgsi_channel_info null_output[4];
583 info->cbuf[index] = null_output;
584 }
585
586 for (index = 0; index < info->base.num_outputs; ++index) {
587 unsigned semantic_name = info->base.output_semantic_name[index];
588 unsigned semantic_index = info->base.output_semantic_index[index];
589 if (semantic_name == TGSI_SEMANTIC_COLOR &&
590 semantic_index < PIPE_MAX_COLOR_BUFS) {
591 info->cbuf[semantic_index] = info->output[index];
592 }
593 }
594
595 if (gallivm_debug & GALLIVM_DEBUG_TGSI) {
596 dump_info(tokens, info);
597 }
598 }