lp_bld_tgsi_info.c revision d8452a0be810d7176b0cbfe6632fc0f8016b5733
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 "lp_bld_debug.h"
35#include "lp_bld_tgsi.h"
36
37
38/**
39 * Analysis context.
40 *
41 * This is where we keep store the value of each channel of the IMM/TEMP/OUT
42 * register values, as we walk the shader.
43 */
44struct analysis_context
45{
46   struct lp_tgsi_info *info;
47
48   unsigned num_imms;
49   float imm[32][4];
50
51   struct lp_tgsi_channel_info temp[32][4];
52};
53
54
55/**
56 * Describe the specified channel of the src register.
57 */
58static void
59analyse_src(struct analysis_context *ctx,
60            struct lp_tgsi_channel_info *chan_info,
61            const struct tgsi_src_register *src,
62            unsigned chan)
63{
64   chan_info->file = TGSI_FILE_NULL;
65   if (!src->Indirect && !src->Absolute && !src->Negate) {
66      unsigned swizzle = tgsi_util_get_src_register_swizzle(src, chan);
67      if (src->File == TGSI_FILE_TEMPORARY) {
68         if (src->Index < Elements(ctx->temp)) {
69            *chan_info = ctx->temp[src->Index][swizzle];
70         }
71      } else {
72         chan_info->file = src->File;
73         if (src->File == TGSI_FILE_IMMEDIATE) {
74            assert(src->Index < Elements(ctx->imm));
75            if (src->Index < Elements(ctx->imm)) {
76               chan_info->u.value = ctx->imm[src->Index][swizzle];
77            }
78         } else {
79            chan_info->u.index = src->Index;
80            chan_info->swizzle = swizzle;
81         }
82      }
83   }
84}
85
86
87/**
88 * Whether this register channel refers to a specific immediate value.
89 */
90static boolean
91is_immediate(const struct lp_tgsi_channel_info *chan_info, float value)
92{
93   return chan_info->file == TGSI_FILE_IMMEDIATE &&
94          chan_info->u.value == value;
95}
96
97
98static void
99analyse_tex(struct analysis_context *ctx,
100            const struct tgsi_full_instruction *inst,
101            enum lp_build_tex_modifier modifier)
102{
103   struct lp_tgsi_info *info = ctx->info;
104   unsigned chan;
105
106   if (info->num_texs < Elements(info->tex)) {
107      struct lp_tgsi_texture_info *tex_info = &info->tex[info->num_texs];
108      boolean indirect = FALSE;
109      unsigned readmask = 0;
110
111      tex_info->target = inst->Texture.Texture;
112      switch (inst->Texture.Texture) {
113      case TGSI_TEXTURE_1D:
114         readmask = TGSI_WRITEMASK_X;
115         break;
116      case TGSI_TEXTURE_1D_ARRAY:
117      case TGSI_TEXTURE_2D:
118      case TGSI_TEXTURE_RECT:
119         readmask = TGSI_WRITEMASK_XY;
120         break;
121      case TGSI_TEXTURE_SHADOW1D:
122      case TGSI_TEXTURE_SHADOW1D_ARRAY:
123      case TGSI_TEXTURE_SHADOW2D:
124      case TGSI_TEXTURE_SHADOWRECT:
125      case TGSI_TEXTURE_2D_ARRAY:
126      case TGSI_TEXTURE_3D:
127      case TGSI_TEXTURE_CUBE:
128         readmask = TGSI_WRITEMASK_XYZ;
129         break;
130      case TGSI_TEXTURE_SHADOW2D_ARRAY:
131         readmask = TGSI_WRITEMASK_XYZW;
132         break;
133      default:
134         assert(0);
135         return;
136      }
137
138      if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) {
139         /* We don't track explicit derivatives, although we could */
140         indirect = TRUE;
141         tex_info->unit = inst->Src[3].Register.Index;
142      }  else {
143         if (modifier == LP_BLD_TEX_MODIFIER_PROJECTED ||
144             modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS ||
145             modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD) {
146            readmask |= TGSI_WRITEMASK_W;
147         }
148         tex_info->unit = inst->Src[1].Register.Index;
149      }
150
151      for (chan = 0; chan < 4; ++chan) {
152         struct lp_tgsi_channel_info *chan_info = &tex_info->coord[chan];
153         if (readmask & (1 << chan)) {
154            analyse_src(ctx, chan_info, &inst->Src[0].Register, chan);
155            if (chan_info->file != TGSI_FILE_INPUT) {
156               indirect = TRUE;
157            }
158         } else {
159            memset(chan_info, 0, sizeof *chan_info);
160         }
161      }
162
163      if (indirect) {
164         info->indirect_textures = TRUE;
165      }
166
167      ++info->num_texs;
168   } else {
169      info->indirect_textures = TRUE;
170   }
171}
172
173
174/**
175 * Process an instruction, and update the register values accordingly.
176 */
177static void
178analyse_instruction(struct analysis_context *ctx,
179                    struct tgsi_full_instruction *inst)
180{
181   struct lp_tgsi_info *info = ctx->info;
182   struct lp_tgsi_channel_info (*regs)[4];
183   unsigned max_regs;
184   unsigned i;
185   unsigned index;
186   unsigned chan;
187
188   for (i = 0; i < inst->Instruction.NumDstRegs; ++i) {
189      const struct tgsi_dst_register *dst = &inst->Dst[i].Register;
190
191      /*
192       * Get the lp_tgsi_channel_info array corresponding to the destination
193       * register file.
194       */
195
196      if (dst->File == TGSI_FILE_TEMPORARY) {
197         regs = ctx->temp;
198         max_regs = Elements(ctx->temp);
199      } else if (dst->File == TGSI_FILE_OUTPUT) {
200         regs = info->output;
201         max_regs = Elements(info->output);
202      } else if (dst->File == TGSI_FILE_ADDRESS ||
203                 dst->File == TGSI_FILE_PREDICATE) {
204         continue;
205      } else {
206         assert(0);
207         continue;
208      }
209
210      /*
211       * Detect direct TEX instructions
212       */
213
214      switch (inst->Instruction.Opcode) {
215      case TGSI_OPCODE_TEX:
216         analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE);
217         break;
218      case TGSI_OPCODE_TXD:
219         analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV);
220         break;
221      case TGSI_OPCODE_TXB:
222         analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS);
223         break;
224      case TGSI_OPCODE_TXL:
225         analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD);
226         break;
227      case TGSI_OPCODE_TXP:
228         analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_PROJECTED);
229         break;
230      default:
231         break;
232      }
233
234      /*
235       * Keep track of assignments and writes
236       */
237
238      if (dst->Indirect) {
239         /*
240          * It could be any register index so clear all register indices.
241          */
242
243         for (chan = 0; chan < 4; ++chan) {
244            if (dst->WriteMask & (1 << chan)) {
245               for (index = 0; index < max_regs; ++index) {
246                  regs[index][chan].file = TGSI_FILE_NULL;
247               }
248            }
249         }
250      } else if (dst->Index < max_regs) {
251         /*
252          * Update this destination register value.
253          */
254
255         struct lp_tgsi_channel_info res[4];
256
257         memset(res, 0, sizeof res);
258
259         if (!inst->Instruction.Predicate &&
260             !inst->Instruction.Saturate) {
261            for (chan = 0; chan < 4; ++chan) {
262               if (dst->WriteMask & (1 << chan)) {
263                  if (inst->Instruction.Opcode == TGSI_OPCODE_MOV) {
264                     analyse_src(ctx, &res[chan],
265                                 &inst->Src[0].Register, chan);
266                  } else if (inst->Instruction.Opcode == TGSI_OPCODE_MUL) {
267                     /*
268                      * Propagate values across 1.0 and 0.0 multiplications.
269                      */
270
271                     struct lp_tgsi_channel_info src0;
272                     struct lp_tgsi_channel_info src1;
273
274                     analyse_src(ctx, &src0, &inst->Src[0].Register, chan);
275                     analyse_src(ctx, &src1, &inst->Src[1].Register, chan);
276
277                     if (is_immediate(&src0, 0.0f)) {
278                        res[chan] = src0;
279                     } else if (is_immediate(&src1, 0.0f)) {
280                        res[chan] = src1;
281                     } else if (is_immediate(&src0, 1.0f)) {
282                        res[chan] = src1;
283                     } else if (is_immediate(&src1, 1.0f)) {
284                        res[chan] = src0;
285                     }
286                  }
287               }
288            }
289         }
290
291         for (chan = 0; chan < 4; ++chan) {
292            if (dst->WriteMask & (1 << chan)) {
293               regs[dst->Index][chan] = res[chan];
294            }
295         }
296      }
297   }
298
299   /*
300    * Clear all temporaries information in presence of a control flow opcode.
301    */
302
303   switch (inst->Instruction.Opcode) {
304   case TGSI_OPCODE_IF:
305   case TGSI_OPCODE_IFC:
306   case TGSI_OPCODE_ELSE:
307   case TGSI_OPCODE_ENDIF:
308   case TGSI_OPCODE_BGNLOOP:
309   case TGSI_OPCODE_BRK:
310   case TGSI_OPCODE_BREAKC:
311   case TGSI_OPCODE_CONT:
312   case TGSI_OPCODE_ENDLOOP:
313   case TGSI_OPCODE_CALLNZ:
314   case TGSI_OPCODE_CAL:
315   case TGSI_OPCODE_BGNSUB:
316   case TGSI_OPCODE_ENDSUB:
317   case TGSI_OPCODE_SWITCH:
318   case TGSI_OPCODE_CASE:
319   case TGSI_OPCODE_DEFAULT:
320   case TGSI_OPCODE_ENDSWITCH:
321   case TGSI_OPCODE_RET:
322   case TGSI_OPCODE_END:
323      /* XXX: Are there more cases? */
324      memset(&ctx->temp, 0, sizeof ctx->temp);
325      memset(&info->output, 0, sizeof info->output);
326   default:
327      break;
328   }
329}
330
331
332static INLINE void
333dump_info(const struct tgsi_token *tokens,
334          struct lp_tgsi_info *info)
335{
336   unsigned index;
337   unsigned chan;
338
339   tgsi_dump(tokens, 0);
340
341   for (index = 0; index < info->num_texs; ++index) {
342      const struct lp_tgsi_texture_info *tex_info = &info->tex[index];
343      debug_printf("TEX[%u] =", index);
344      for (chan = 0; chan < 4; ++chan) {
345         const struct lp_tgsi_channel_info *chan_info =
346               &tex_info->coord[chan];
347         if (chan_info->file != TGSI_FILE_NULL) {
348            debug_printf(" %s[%u].%c",
349                         tgsi_file_names[chan_info->file],
350                         chan_info->u.index,
351                         "xyzw01"[chan_info->swizzle]);
352         } else {
353            debug_printf(" _");
354         }
355      }
356      debug_printf(", SAMP[%u], %s\n",
357                   tex_info->unit,
358                   tgsi_texture_names[tex_info->target]);
359   }
360
361   for (index = 0; index < PIPE_MAX_SHADER_OUTPUTS; ++index) {
362      for (chan = 0; chan < 4; ++chan) {
363         const struct lp_tgsi_channel_info *chan_info =
364               &info->output[index][chan];
365         if (chan_info->file != TGSI_FILE_NULL) {
366            debug_printf("OUT[%u].%c = ", index, "xyzw"[chan]);
367            if (chan_info->file == TGSI_FILE_IMMEDIATE) {
368               debug_printf("%f", chan_info->u.value);
369            } else {
370               const char *file_name;
371               switch (chan_info->file) {
372               case TGSI_FILE_CONSTANT:
373                  file_name = "CONST";
374                  break;
375               case TGSI_FILE_INPUT:
376                  file_name = "IN";
377                  break;
378               default:
379                  file_name = "???";
380                  break;
381               }
382               debug_printf("%s[%u].%c",
383                            file_name,
384                            chan_info->u.index,
385                            "xyzw01"[chan_info->swizzle]);
386            }
387            debug_printf("\n");
388         }
389      }
390   }
391}
392
393
394/**
395 * Detect any direct relationship between the output color
396 */
397void
398lp_build_tgsi_info(const struct tgsi_token *tokens,
399                   struct lp_tgsi_info *info)
400{
401   struct tgsi_parse_context parse;
402   struct analysis_context ctx;
403   unsigned index;
404   unsigned chan;
405
406   memset(info, 0, sizeof *info);
407
408   tgsi_scan_shader(tokens, &info->base);
409
410   memset(&ctx, 0, sizeof ctx);
411   ctx.info = info;
412
413   tgsi_parse_init(&parse, tokens);
414
415   while (!tgsi_parse_end_of_tokens(&parse)) {
416      tgsi_parse_token(&parse);
417
418      switch (parse.FullToken.Token.Type) {
419      case TGSI_TOKEN_TYPE_DECLARATION:
420         break;
421
422      case TGSI_TOKEN_TYPE_INSTRUCTION:
423         {
424            struct tgsi_full_instruction *inst =
425                  &parse.FullToken.FullInstruction;
426
427            if (inst->Instruction.Opcode == TGSI_OPCODE_END ||
428                inst->Instruction.Opcode == TGSI_OPCODE_BGNSUB) {
429               /* We reached the end of main function body. */
430               goto finished;
431            }
432
433            analyse_instruction(&ctx, inst);
434         }
435         break;
436
437      case TGSI_TOKEN_TYPE_IMMEDIATE:
438         {
439            const unsigned size =
440                  parse.FullToken.FullImmediate.Immediate.NrTokens - 1;
441            assert(size <= 4);
442            if (ctx.num_imms < Elements(ctx.imm)) {
443               for (chan = 0; chan < size; ++chan) {
444                  ctx.imm[ctx.num_imms][chan] =
445                        parse.FullToken.FullImmediate.u[chan].Float;
446               }
447               ++ctx.num_imms;
448            }
449         }
450         break;
451
452      case TGSI_TOKEN_TYPE_PROPERTY:
453         break;
454
455      default:
456         assert(0);
457      }
458   }
459finished:
460
461   tgsi_parse_free(&parse);
462
463
464   /*
465    * Link the output color values.
466    */
467
468   for (index = 0; index < PIPE_MAX_COLOR_BUFS; ++index) {
469      const struct lp_tgsi_channel_info null_output[4];
470      info->cbuf[index] = null_output;
471   }
472
473   for (index = 0; index < info->base.num_outputs; ++index) {
474      unsigned semantic_name = info->base.output_semantic_name[index];
475      unsigned semantic_index = info->base.output_semantic_index[index];
476      if (semantic_name == TGSI_SEMANTIC_COLOR &&
477          semantic_index < PIPE_MAX_COLOR_BUFS) {
478         info->cbuf[semantic_index] = info->output[index];
479      }
480   }
481
482   if (gallivm_debug & GALLIVM_DEBUG_TGSI) {
483      dump_info(tokens, info);
484   }
485}
486