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