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 unsigned sample_target[PIPE_MAX_SHADER_SAMPLER_VIEWS];
52
53 struct lp_tgsi_channel_info temp[32][4];
54 };
55
56
57 /**
58 * Describe the specified channel of the src register.
59 */
60 static void
analyse_src(struct analysis_context * ctx,struct lp_tgsi_channel_info * chan_info,const struct tgsi_src_register * src,unsigned chan)61 analyse_src(struct analysis_context *ctx,
62 struct lp_tgsi_channel_info *chan_info,
63 const struct tgsi_src_register *src,
64 unsigned chan)
65 {
66 chan_info->file = TGSI_FILE_NULL;
67 if (!src->Indirect && !src->Absolute && !src->Negate) {
68 unsigned swizzle = tgsi_util_get_src_register_swizzle(src, chan);
69 if (src->File == TGSI_FILE_TEMPORARY) {
70 if (src->Index < ARRAY_SIZE(ctx->temp)) {
71 *chan_info = ctx->temp[src->Index][swizzle];
72 }
73 } else {
74 chan_info->file = src->File;
75 if (src->File == TGSI_FILE_IMMEDIATE) {
76 assert(src->Index < ARRAY_SIZE(ctx->imm));
77 if (src->Index < ARRAY_SIZE(ctx->imm)) {
78 chan_info->u.value = ctx->imm[src->Index][swizzle];
79 }
80 } else {
81 chan_info->u.index = src->Index;
82 chan_info->swizzle = swizzle;
83 }
84 }
85 }
86 }
87
88
89 /**
90 * Whether this register channel refers to a specific immediate value.
91 */
92 static boolean
is_immediate(const struct lp_tgsi_channel_info * chan_info,float value)93 is_immediate(const struct lp_tgsi_channel_info *chan_info, float value)
94 {
95 return chan_info->file == TGSI_FILE_IMMEDIATE &&
96 chan_info->u.value == value;
97 }
98
99
100 /**
101 * Analyse properties of tex instructions, in particular used
102 * to figure out if a texture is considered indirect.
103 * Not actually used by much except the tgsi dumping code.
104 */
105 static void
analyse_tex(struct analysis_context * ctx,const struct tgsi_full_instruction * inst,enum lp_build_tex_modifier modifier)106 analyse_tex(struct analysis_context *ctx,
107 const struct tgsi_full_instruction *inst,
108 enum lp_build_tex_modifier modifier)
109 {
110 struct lp_tgsi_info *info = ctx->info;
111 unsigned chan;
112
113 if (info->num_texs < ARRAY_SIZE(info->tex)) {
114 struct lp_tgsi_texture_info *tex_info = &info->tex[info->num_texs];
115 boolean indirect = FALSE;
116 unsigned readmask = 0;
117
118 tex_info->target = inst->Texture.Texture;
119 switch (inst->Texture.Texture) {
120 case TGSI_TEXTURE_1D:
121 readmask = TGSI_WRITEMASK_X;
122 break;
123 case TGSI_TEXTURE_1D_ARRAY:
124 case TGSI_TEXTURE_2D:
125 case TGSI_TEXTURE_RECT:
126 readmask = TGSI_WRITEMASK_XY;
127 break;
128 case TGSI_TEXTURE_SHADOW1D:
129 case TGSI_TEXTURE_SHADOW1D_ARRAY:
130 case TGSI_TEXTURE_SHADOW2D:
131 case TGSI_TEXTURE_SHADOWRECT:
132 case TGSI_TEXTURE_2D_ARRAY:
133 case TGSI_TEXTURE_2D_MSAA:
134 case TGSI_TEXTURE_3D:
135 case TGSI_TEXTURE_CUBE:
136 readmask = TGSI_WRITEMASK_XYZ;
137 break;
138 case TGSI_TEXTURE_SHADOW2D_ARRAY:
139 case TGSI_TEXTURE_SHADOWCUBE:
140 case TGSI_TEXTURE_2D_ARRAY_MSAA:
141 case TGSI_TEXTURE_CUBE_ARRAY:
142 readmask = TGSI_WRITEMASK_XYZW;
143 /* modifier would be in another not analyzed reg so just say indirect */
144 if (modifier != LP_BLD_TEX_MODIFIER_NONE) {
145 indirect = TRUE;
146 }
147 break;
148 case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
149 readmask = TGSI_WRITEMASK_XYZW;
150 indirect = TRUE;
151 break;
152 default:
153 assert(0);
154 return;
155 }
156
157 if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) {
158 /* We don't track explicit derivatives, although we could */
159 indirect = TRUE;
160 tex_info->sampler_unit = inst->Src[3].Register.Index;
161 tex_info->texture_unit = inst->Src[3].Register.Index;
162 } else {
163 if (modifier == LP_BLD_TEX_MODIFIER_PROJECTED ||
164 modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS ||
165 modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD) {
166 readmask |= TGSI_WRITEMASK_W;
167 }
168 tex_info->sampler_unit = inst->Src[1].Register.Index;
169 tex_info->texture_unit = inst->Src[1].Register.Index;
170 }
171
172 for (chan = 0; chan < 4; ++chan) {
173 struct lp_tgsi_channel_info *chan_info = &tex_info->coord[chan];
174 if (readmask & (1 << chan)) {
175 analyse_src(ctx, chan_info, &inst->Src[0].Register, chan);
176 if (chan_info->file != TGSI_FILE_INPUT) {
177 indirect = TRUE;
178 }
179 } else {
180 memset(chan_info, 0, sizeof *chan_info);
181 }
182 }
183
184 if (indirect) {
185 info->indirect_textures = TRUE;
186 }
187
188 ++info->num_texs;
189 } else {
190 info->indirect_textures = TRUE;
191 }
192 }
193
194
195 /**
196 * Analyse properties of sample instructions, in particular used
197 * to figure out if a texture is considered indirect.
198 * Not actually used by much except the tgsi dumping code.
199 */
200 static void
analyse_sample(struct analysis_context * ctx,const struct tgsi_full_instruction * inst,enum lp_build_tex_modifier modifier,boolean shadow)201 analyse_sample(struct analysis_context *ctx,
202 const struct tgsi_full_instruction *inst,
203 enum lp_build_tex_modifier modifier,
204 boolean shadow)
205 {
206 struct lp_tgsi_info *info = ctx->info;
207 unsigned chan;
208
209 if (info->num_texs < ARRAY_SIZE(info->tex)) {
210 struct lp_tgsi_texture_info *tex_info = &info->tex[info->num_texs];
211 unsigned target = ctx->sample_target[inst->Src[1].Register.Index];
212 boolean indirect = FALSE;
213 boolean shadow = FALSE;
214 unsigned readmask;
215
216 switch (target) {
217 /* note no shadow targets here */
218 case TGSI_TEXTURE_BUFFER:
219 case TGSI_TEXTURE_1D:
220 readmask = TGSI_WRITEMASK_X;
221 break;
222 case TGSI_TEXTURE_1D_ARRAY:
223 case TGSI_TEXTURE_2D:
224 case TGSI_TEXTURE_RECT:
225 readmask = TGSI_WRITEMASK_XY;
226 break;
227 case TGSI_TEXTURE_2D_ARRAY:
228 case TGSI_TEXTURE_2D_MSAA:
229 case TGSI_TEXTURE_3D:
230 case TGSI_TEXTURE_CUBE:
231 readmask = TGSI_WRITEMASK_XYZ;
232 break;
233 case TGSI_TEXTURE_CUBE_ARRAY:
234 case TGSI_TEXTURE_2D_ARRAY_MSAA:
235 readmask = TGSI_WRITEMASK_XYZW;
236 break;
237 default:
238 assert(0);
239 return;
240 }
241
242 tex_info->target = target;
243 tex_info->texture_unit = inst->Src[1].Register.Index;
244 tex_info->sampler_unit = inst->Src[2].Register.Index;
245
246 if (tex_info->texture_unit != tex_info->sampler_unit) {
247 info->sampler_texture_units_different = TRUE;
248 }
249
250 if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV ||
251 modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD ||
252 modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS || shadow) {
253 /* We don't track insts with additional regs, although we could */
254 indirect = TRUE;
255 }
256
257 for (chan = 0; chan < 4; ++chan) {
258 struct lp_tgsi_channel_info *chan_info = &tex_info->coord[chan];
259 if (readmask & (1 << chan)) {
260 analyse_src(ctx, chan_info, &inst->Src[0].Register, chan);
261 if (chan_info->file != TGSI_FILE_INPUT) {
262 indirect = TRUE;
263 }
264 } else {
265 memset(chan_info, 0, sizeof *chan_info);
266 }
267 }
268
269 if (indirect) {
270 info->indirect_textures = TRUE;
271 }
272
273 ++info->num_texs;
274 } else {
275 info->indirect_textures = TRUE;
276 }
277 }
278
279
280 /**
281 * Process an instruction, and update the register values accordingly.
282 */
283 static void
analyse_instruction(struct analysis_context * ctx,struct tgsi_full_instruction * inst)284 analyse_instruction(struct analysis_context *ctx,
285 struct tgsi_full_instruction *inst)
286 {
287 struct lp_tgsi_info *info = ctx->info;
288 struct lp_tgsi_channel_info (*regs)[4];
289 unsigned max_regs;
290 unsigned i;
291 unsigned index;
292 unsigned chan;
293
294 for (i = 0; i < inst->Instruction.NumDstRegs; ++i) {
295 const struct tgsi_dst_register *dst = &inst->Dst[i].Register;
296
297 /*
298 * Get the lp_tgsi_channel_info array corresponding to the destination
299 * register file.
300 */
301
302 if (dst->File == TGSI_FILE_TEMPORARY) {
303 regs = ctx->temp;
304 max_regs = ARRAY_SIZE(ctx->temp);
305 } else if (dst->File == TGSI_FILE_OUTPUT) {
306 regs = info->output;
307 max_regs = ARRAY_SIZE(info->output);
308 } else if (dst->File == TGSI_FILE_ADDRESS) {
309 continue;
310 } else if (dst->File == TGSI_FILE_BUFFER) {
311 continue;
312 } else if (dst->File == TGSI_FILE_IMAGE) {
313 continue;
314 } else if (dst->File == TGSI_FILE_MEMORY) {
315 continue;
316 } else {
317 assert(0);
318 continue;
319 }
320
321 /*
322 * Detect direct TEX instructions
323 */
324
325 switch (inst->Instruction.Opcode) {
326 case TGSI_OPCODE_TEX:
327 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE);
328 break;
329 case TGSI_OPCODE_TXD:
330 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV);
331 break;
332 case TGSI_OPCODE_TXB:
333 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS);
334 break;
335 case TGSI_OPCODE_TXL:
336 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD);
337 break;
338 case TGSI_OPCODE_TXP:
339 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_PROJECTED);
340 break;
341 case TGSI_OPCODE_TEX2:
342 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE);
343 break;
344 case TGSI_OPCODE_TXB2:
345 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS);
346 break;
347 case TGSI_OPCODE_TXL2:
348 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD);
349 break;
350 case TGSI_OPCODE_SAMPLE:
351 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_NONE, FALSE);
352 break;
353 case TGSI_OPCODE_SAMPLE_C:
354 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_NONE, TRUE);
355 break;
356 case TGSI_OPCODE_SAMPLE_C_LZ:
357 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_ZERO, TRUE);
358 break;
359 case TGSI_OPCODE_SAMPLE_D:
360 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV, FALSE);
361 break;
362 case TGSI_OPCODE_SAMPLE_B:
363 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS, FALSE);
364 break;
365 case TGSI_OPCODE_SAMPLE_L:
366 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD, FALSE);
367 break;
368 default:
369 break;
370 }
371
372 /*
373 * Keep track of assignments and writes
374 */
375
376 if (dst->Indirect) {
377 /*
378 * It could be any register index so clear all register indices.
379 */
380
381 for (chan = 0; chan < 4; ++chan) {
382 if (dst->WriteMask & (1 << chan)) {
383 for (index = 0; index < max_regs; ++index) {
384 regs[index][chan].file = TGSI_FILE_NULL;
385 }
386 }
387 }
388 } else if (dst->Index < max_regs) {
389 /*
390 * Update this destination register value.
391 */
392
393 struct lp_tgsi_channel_info res[4];
394
395 memset(res, 0, sizeof res);
396
397 if (!inst->Instruction.Saturate) {
398 for (chan = 0; chan < 4; ++chan) {
399 if (dst->WriteMask & (1 << chan)) {
400 if (inst->Instruction.Opcode == TGSI_OPCODE_MOV) {
401 analyse_src(ctx, &res[chan],
402 &inst->Src[0].Register, chan);
403 } else if (inst->Instruction.Opcode == TGSI_OPCODE_MUL) {
404 /*
405 * Propagate values across 1.0 and 0.0 multiplications.
406 */
407
408 struct lp_tgsi_channel_info src0;
409 struct lp_tgsi_channel_info src1;
410
411 analyse_src(ctx, &src0, &inst->Src[0].Register, chan);
412 analyse_src(ctx, &src1, &inst->Src[1].Register, chan);
413
414 if (is_immediate(&src0, 0.0f)) {
415 res[chan] = src0;
416 } else if (is_immediate(&src1, 0.0f)) {
417 res[chan] = src1;
418 } else if (is_immediate(&src0, 1.0f)) {
419 res[chan] = src1;
420 } else if (is_immediate(&src1, 1.0f)) {
421 res[chan] = src0;
422 }
423 }
424 }
425 }
426 }
427
428 for (chan = 0; chan < 4; ++chan) {
429 if (dst->WriteMask & (1 << chan)) {
430 regs[dst->Index][chan] = res[chan];
431 }
432 }
433 }
434 }
435
436 /*
437 * Clear all temporaries information in presence of a control flow opcode.
438 */
439
440 switch (inst->Instruction.Opcode) {
441 case TGSI_OPCODE_IF:
442 case TGSI_OPCODE_UIF:
443 case TGSI_OPCODE_ELSE:
444 case TGSI_OPCODE_ENDIF:
445 case TGSI_OPCODE_BGNLOOP:
446 case TGSI_OPCODE_BRK:
447 case TGSI_OPCODE_CONT:
448 case TGSI_OPCODE_ENDLOOP:
449 case TGSI_OPCODE_CAL:
450 case TGSI_OPCODE_BGNSUB:
451 case TGSI_OPCODE_ENDSUB:
452 case TGSI_OPCODE_SWITCH:
453 case TGSI_OPCODE_CASE:
454 case TGSI_OPCODE_DEFAULT:
455 case TGSI_OPCODE_ENDSWITCH:
456 case TGSI_OPCODE_RET:
457 case TGSI_OPCODE_END:
458 /* XXX: Are there more cases? */
459 memset(&ctx->temp, 0, sizeof ctx->temp);
460 memset(&info->output, 0, sizeof info->output);
461 default:
462 break;
463 }
464 }
465
466
467 static inline void
dump_info(const struct tgsi_token * tokens,struct lp_tgsi_info * info)468 dump_info(const struct tgsi_token *tokens,
469 struct lp_tgsi_info *info)
470 {
471 unsigned index;
472 unsigned chan;
473
474 tgsi_dump(tokens, 0);
475
476 for (index = 0; index < info->num_texs; ++index) {
477 const struct lp_tgsi_texture_info *tex_info = &info->tex[index];
478 debug_printf("TEX[%u] =", index);
479 for (chan = 0; chan < 4; ++chan) {
480 const struct lp_tgsi_channel_info *chan_info =
481 &tex_info->coord[chan];
482 if (chan_info->file != TGSI_FILE_NULL) {
483 debug_printf(" %s[%u].%c",
484 tgsi_file_name(chan_info->file),
485 chan_info->u.index,
486 "xyzw01"[chan_info->swizzle]);
487 } else {
488 debug_printf(" _");
489 }
490 }
491 debug_printf(", RES[%u], SAMP[%u], %s\n",
492 tex_info->texture_unit,
493 tex_info->sampler_unit,
494 tgsi_texture_names[tex_info->target]);
495 }
496
497 for (index = 0; index < PIPE_MAX_SHADER_OUTPUTS; ++index) {
498 for (chan = 0; chan < 4; ++chan) {
499 const struct lp_tgsi_channel_info *chan_info =
500 &info->output[index][chan];
501 if (chan_info->file != TGSI_FILE_NULL) {
502 debug_printf("OUT[%u].%c = ", index, "xyzw"[chan]);
503 if (chan_info->file == TGSI_FILE_IMMEDIATE) {
504 debug_printf("%f", chan_info->u.value);
505 } else {
506 const char *file_name;
507 switch (chan_info->file) {
508 case TGSI_FILE_CONSTANT:
509 file_name = "CONST";
510 break;
511 case TGSI_FILE_INPUT:
512 file_name = "IN";
513 break;
514 default:
515 file_name = "???";
516 break;
517 }
518 debug_printf("%s[%u].%c",
519 file_name,
520 chan_info->u.index,
521 "xyzw01"[chan_info->swizzle]);
522 }
523 debug_printf("\n");
524 }
525 }
526 }
527 }
528
529
530 /**
531 * Detect any direct relationship between the output color
532 */
533 void
lp_build_tgsi_info(const struct tgsi_token * tokens,struct lp_tgsi_info * info)534 lp_build_tgsi_info(const struct tgsi_token *tokens,
535 struct lp_tgsi_info *info)
536 {
537 struct tgsi_parse_context parse;
538 struct analysis_context *ctx;
539 unsigned index;
540 unsigned chan;
541
542 memset(info, 0, sizeof *info);
543
544 tgsi_scan_shader(tokens, &info->base);
545
546 ctx = CALLOC(1, sizeof(struct analysis_context));
547 ctx->info = info;
548
549 tgsi_parse_init(&parse, tokens);
550
551 while (!tgsi_parse_end_of_tokens(&parse)) {
552 tgsi_parse_token(&parse);
553
554 switch (parse.FullToken.Token.Type) {
555 case TGSI_TOKEN_TYPE_DECLARATION: {
556 struct tgsi_full_declaration *decl = &parse.FullToken.FullDeclaration;
557 if (decl->Declaration.File == TGSI_FILE_SAMPLER_VIEW) {
558 for (index = decl->Range.First; index <= decl->Range.Last; index++) {
559 ctx->sample_target[index] = decl->SamplerView.Resource;
560 }
561 }
562 }
563 break;
564
565 case TGSI_TOKEN_TYPE_INSTRUCTION:
566 {
567 struct tgsi_full_instruction *inst =
568 &parse.FullToken.FullInstruction;
569
570 if (inst->Instruction.Opcode == TGSI_OPCODE_END ||
571 inst->Instruction.Opcode == TGSI_OPCODE_BGNSUB) {
572 /* We reached the end of main function body. */
573 goto finished;
574 }
575
576 analyse_instruction(ctx, inst);
577 }
578 break;
579
580 case TGSI_TOKEN_TYPE_IMMEDIATE:
581 {
582 const unsigned size =
583 parse.FullToken.FullImmediate.Immediate.NrTokens - 1;
584 assert(size <= 4);
585 if (ctx->num_imms < ARRAY_SIZE(ctx->imm)) {
586 for (chan = 0; chan < size; ++chan) {
587 float value = parse.FullToken.FullImmediate.u[chan].Float;
588 ctx->imm[ctx->num_imms][chan] = value;
589
590 if (value < 0.0f || value > 1.0f) {
591 info->unclamped_immediates = TRUE;
592 }
593 }
594 ++ctx->num_imms;
595 }
596 }
597 break;
598
599 case TGSI_TOKEN_TYPE_PROPERTY:
600 break;
601
602 default:
603 assert(0);
604 }
605 }
606 finished:
607
608 tgsi_parse_free(&parse);
609 FREE(ctx);
610
611
612 /*
613 * Link the output color values.
614 */
615
616 for (index = 0; index < PIPE_MAX_COLOR_BUFS; ++index) {
617 static const struct lp_tgsi_channel_info null_output[4];
618 info->cbuf[index] = null_output;
619 }
620
621 for (index = 0; index < info->base.num_outputs; ++index) {
622 unsigned semantic_name = info->base.output_semantic_name[index];
623 unsigned semantic_index = info->base.output_semantic_index[index];
624 if (semantic_name == TGSI_SEMANTIC_COLOR &&
625 semantic_index < PIPE_MAX_COLOR_BUFS) {
626 info->cbuf[semantic_index] = info->output[index];
627 }
628 }
629
630 if (gallivm_debug & GALLIVM_DEBUG_TGSI) {
631 dump_info(tokens, info);
632 }
633 }
634