iris: Don't enable smooth points when point sprites are enabled
[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 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
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
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
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
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
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 {
311 assert(0);
312 continue;
313 }
314
315 /*
316 * Detect direct TEX instructions
317 */
318
319 switch (inst->Instruction.Opcode) {
320 case TGSI_OPCODE_TEX:
321 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE);
322 break;
323 case TGSI_OPCODE_TXD:
324 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV);
325 break;
326 case TGSI_OPCODE_TXB:
327 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS);
328 break;
329 case TGSI_OPCODE_TXL:
330 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD);
331 break;
332 case TGSI_OPCODE_TXP:
333 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_PROJECTED);
334 break;
335 case TGSI_OPCODE_TEX2:
336 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE);
337 break;
338 case TGSI_OPCODE_TXB2:
339 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS);
340 break;
341 case TGSI_OPCODE_TXL2:
342 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD);
343 break;
344 case TGSI_OPCODE_SAMPLE:
345 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_NONE, FALSE);
346 break;
347 case TGSI_OPCODE_SAMPLE_C:
348 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_NONE, TRUE);
349 break;
350 case TGSI_OPCODE_SAMPLE_C_LZ:
351 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_ZERO, TRUE);
352 break;
353 case TGSI_OPCODE_SAMPLE_D:
354 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV, FALSE);
355 break;
356 case TGSI_OPCODE_SAMPLE_B:
357 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS, FALSE);
358 break;
359 case TGSI_OPCODE_SAMPLE_L:
360 analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD, FALSE);
361 break;
362 default:
363 break;
364 }
365
366 /*
367 * Keep track of assignments and writes
368 */
369
370 if (dst->Indirect) {
371 /*
372 * It could be any register index so clear all register indices.
373 */
374
375 for (chan = 0; chan < 4; ++chan) {
376 if (dst->WriteMask & (1 << chan)) {
377 for (index = 0; index < max_regs; ++index) {
378 regs[index][chan].file = TGSI_FILE_NULL;
379 }
380 }
381 }
382 } else if (dst->Index < max_regs) {
383 /*
384 * Update this destination register value.
385 */
386
387 struct lp_tgsi_channel_info res[4];
388
389 memset(res, 0, sizeof res);
390
391 if (!inst->Instruction.Saturate) {
392 for (chan = 0; chan < 4; ++chan) {
393 if (dst->WriteMask & (1 << chan)) {
394 if (inst->Instruction.Opcode == TGSI_OPCODE_MOV) {
395 analyse_src(ctx, &res[chan],
396 &inst->Src[0].Register, chan);
397 } else if (inst->Instruction.Opcode == TGSI_OPCODE_MUL) {
398 /*
399 * Propagate values across 1.0 and 0.0 multiplications.
400 */
401
402 struct lp_tgsi_channel_info src0;
403 struct lp_tgsi_channel_info src1;
404
405 analyse_src(ctx, &src0, &inst->Src[0].Register, chan);
406 analyse_src(ctx, &src1, &inst->Src[1].Register, chan);
407
408 if (is_immediate(&src0, 0.0f)) {
409 res[chan] = src0;
410 } else if (is_immediate(&src1, 0.0f)) {
411 res[chan] = src1;
412 } else if (is_immediate(&src0, 1.0f)) {
413 res[chan] = src1;
414 } else if (is_immediate(&src1, 1.0f)) {
415 res[chan] = src0;
416 }
417 }
418 }
419 }
420 }
421
422 for (chan = 0; chan < 4; ++chan) {
423 if (dst->WriteMask & (1 << chan)) {
424 regs[dst->Index][chan] = res[chan];
425 }
426 }
427 }
428 }
429
430 /*
431 * Clear all temporaries information in presence of a control flow opcode.
432 */
433
434 switch (inst->Instruction.Opcode) {
435 case TGSI_OPCODE_IF:
436 case TGSI_OPCODE_UIF:
437 case TGSI_OPCODE_ELSE:
438 case TGSI_OPCODE_ENDIF:
439 case TGSI_OPCODE_BGNLOOP:
440 case TGSI_OPCODE_BRK:
441 case TGSI_OPCODE_CONT:
442 case TGSI_OPCODE_ENDLOOP:
443 case TGSI_OPCODE_CAL:
444 case TGSI_OPCODE_BGNSUB:
445 case TGSI_OPCODE_ENDSUB:
446 case TGSI_OPCODE_SWITCH:
447 case TGSI_OPCODE_CASE:
448 case TGSI_OPCODE_DEFAULT:
449 case TGSI_OPCODE_ENDSWITCH:
450 case TGSI_OPCODE_RET:
451 case TGSI_OPCODE_END:
452 /* XXX: Are there more cases? */
453 memset(&ctx->temp, 0, sizeof ctx->temp);
454 memset(&info->output, 0, sizeof info->output);
455 default:
456 break;
457 }
458 }
459
460
461 static inline void
462 dump_info(const struct tgsi_token *tokens,
463 struct lp_tgsi_info *info)
464 {
465 unsigned index;
466 unsigned chan;
467
468 tgsi_dump(tokens, 0);
469
470 for (index = 0; index < info->num_texs; ++index) {
471 const struct lp_tgsi_texture_info *tex_info = &info->tex[index];
472 debug_printf("TEX[%u] =", index);
473 for (chan = 0; chan < 4; ++chan) {
474 const struct lp_tgsi_channel_info *chan_info =
475 &tex_info->coord[chan];
476 if (chan_info->file != TGSI_FILE_NULL) {
477 debug_printf(" %s[%u].%c",
478 tgsi_file_name(chan_info->file),
479 chan_info->u.index,
480 "xyzw01"[chan_info->swizzle]);
481 } else {
482 debug_printf(" _");
483 }
484 }
485 debug_printf(", RES[%u], SAMP[%u], %s\n",
486 tex_info->texture_unit,
487 tex_info->sampler_unit,
488 tgsi_texture_names[tex_info->target]);
489 }
490
491 for (index = 0; index < PIPE_MAX_SHADER_OUTPUTS; ++index) {
492 for (chan = 0; chan < 4; ++chan) {
493 const struct lp_tgsi_channel_info *chan_info =
494 &info->output[index][chan];
495 if (chan_info->file != TGSI_FILE_NULL) {
496 debug_printf("OUT[%u].%c = ", index, "xyzw"[chan]);
497 if (chan_info->file == TGSI_FILE_IMMEDIATE) {
498 debug_printf("%f", chan_info->u.value);
499 } else {
500 const char *file_name;
501 switch (chan_info->file) {
502 case TGSI_FILE_CONSTANT:
503 file_name = "CONST";
504 break;
505 case TGSI_FILE_INPUT:
506 file_name = "IN";
507 break;
508 default:
509 file_name = "???";
510 break;
511 }
512 debug_printf("%s[%u].%c",
513 file_name,
514 chan_info->u.index,
515 "xyzw01"[chan_info->swizzle]);
516 }
517 debug_printf("\n");
518 }
519 }
520 }
521 }
522
523
524 /**
525 * Detect any direct relationship between the output color
526 */
527 void
528 lp_build_tgsi_info(const struct tgsi_token *tokens,
529 struct lp_tgsi_info *info)
530 {
531 struct tgsi_parse_context parse;
532 struct analysis_context *ctx;
533 unsigned index;
534 unsigned chan;
535
536 memset(info, 0, sizeof *info);
537
538 tgsi_scan_shader(tokens, &info->base);
539
540 ctx = CALLOC(1, sizeof(struct analysis_context));
541 ctx->info = info;
542
543 tgsi_parse_init(&parse, tokens);
544
545 while (!tgsi_parse_end_of_tokens(&parse)) {
546 tgsi_parse_token(&parse);
547
548 switch (parse.FullToken.Token.Type) {
549 case TGSI_TOKEN_TYPE_DECLARATION: {
550 struct tgsi_full_declaration *decl = &parse.FullToken.FullDeclaration;
551 if (decl->Declaration.File == TGSI_FILE_SAMPLER_VIEW) {
552 for (index = decl->Range.First; index <= decl->Range.Last; index++) {
553 ctx->sample_target[index] = decl->SamplerView.Resource;
554 }
555 }
556 }
557 break;
558
559 case TGSI_TOKEN_TYPE_INSTRUCTION:
560 {
561 struct tgsi_full_instruction *inst =
562 &parse.FullToken.FullInstruction;
563
564 if (inst->Instruction.Opcode == TGSI_OPCODE_END ||
565 inst->Instruction.Opcode == TGSI_OPCODE_BGNSUB) {
566 /* We reached the end of main function body. */
567 goto finished;
568 }
569
570 analyse_instruction(ctx, inst);
571 }
572 break;
573
574 case TGSI_TOKEN_TYPE_IMMEDIATE:
575 {
576 const unsigned size =
577 parse.FullToken.FullImmediate.Immediate.NrTokens - 1;
578 assert(size <= 4);
579 if (ctx->num_imms < ARRAY_SIZE(ctx->imm)) {
580 for (chan = 0; chan < size; ++chan) {
581 float value = parse.FullToken.FullImmediate.u[chan].Float;
582 ctx->imm[ctx->num_imms][chan] = value;
583
584 if (value < 0.0f || value > 1.0f) {
585 info->unclamped_immediates = TRUE;
586 }
587 }
588 ++ctx->num_imms;
589 }
590 }
591 break;
592
593 case TGSI_TOKEN_TYPE_PROPERTY:
594 break;
595
596 default:
597 assert(0);
598 }
599 }
600 finished:
601
602 tgsi_parse_free(&parse);
603 FREE(ctx);
604
605
606 /*
607 * Link the output color values.
608 */
609
610 for (index = 0; index < PIPE_MAX_COLOR_BUFS; ++index) {
611 const struct lp_tgsi_channel_info null_output[4];
612 info->cbuf[index] = null_output;
613 }
614
615 for (index = 0; index < info->base.num_outputs; ++index) {
616 unsigned semantic_name = info->base.output_semantic_name[index];
617 unsigned semantic_index = info->base.output_semantic_index[index];
618 if (semantic_name == TGSI_SEMANTIC_COLOR &&
619 semantic_index < PIPE_MAX_COLOR_BUFS) {
620 info->cbuf[semantic_index] = info->output[index];
621 }
622 }
623
624 if (gallivm_debug & GALLIVM_DEBUG_TGSI) {
625 dump_info(tokens, info);
626 }
627 }