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