#include "tgsi/tgsi_parse.h"
#include "tgsi/tgsi_util.h"
#include "tgsi/tgsi_dump.h"
+#include "tgsi/tgsi_strings.h"
#include "lp_bld_debug.h"
#include "lp_bld_tgsi.h"
struct lp_tgsi_info *info;
unsigned num_imms;
- float imm[32][4];
+ float imm[LP_MAX_TGSI_IMMEDIATES][4];
+ unsigned sample_target[PIPE_MAX_SHADER_SAMPLER_VIEWS];
struct lp_tgsi_channel_info temp[32][4];
};
}
+/**
+ * Analyse properties of tex instructions, in particular used
+ * to figure out if a texture is considered indirect.
+ * Not actually used by much except the tgsi dumping code.
+ */
static void
analyse_tex(struct analysis_context *ctx,
const struct tgsi_full_instruction *inst,
if (info->num_texs < Elements(info->tex)) {
struct lp_tgsi_texture_info *tex_info = &info->tex[info->num_texs];
- bool indirect = FALSE;
+ boolean indirect = FALSE;
unsigned readmask = 0;
tex_info->target = inst->Texture.Texture;
case TGSI_TEXTURE_1D:
readmask = TGSI_WRITEMASK_X;
break;
+ case TGSI_TEXTURE_1D_ARRAY:
case TGSI_TEXTURE_2D:
case TGSI_TEXTURE_RECT:
readmask = TGSI_WRITEMASK_XY;
break;
case TGSI_TEXTURE_SHADOW1D:
+ case TGSI_TEXTURE_SHADOW1D_ARRAY:
case TGSI_TEXTURE_SHADOW2D:
case TGSI_TEXTURE_SHADOWRECT:
+ case TGSI_TEXTURE_2D_ARRAY:
+ case TGSI_TEXTURE_2D_MSAA:
case TGSI_TEXTURE_3D:
case TGSI_TEXTURE_CUBE:
readmask = TGSI_WRITEMASK_XYZ;
break;
+ case TGSI_TEXTURE_SHADOW2D_ARRAY:
+ case TGSI_TEXTURE_SHADOWCUBE:
+ case TGSI_TEXTURE_2D_ARRAY_MSAA:
+ case TGSI_TEXTURE_CUBE_ARRAY:
+ readmask = TGSI_WRITEMASK_XYZW;
+ /* modifier would be in another not analyzed reg so just say indirect */
+ if (modifier != LP_BLD_TEX_MODIFIER_NONE) {
+ indirect = TRUE;
+ }
+ break;
+ case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
+ readmask = TGSI_WRITEMASK_XYZW;
+ indirect = TRUE;
+ break;
default:
assert(0);
return;
if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) {
/* We don't track explicit derivatives, although we could */
indirect = TRUE;
- tex_info->unit = inst->Src[3].Register.Index;
+ tex_info->sampler_unit = inst->Src[3].Register.Index;
+ tex_info->texture_unit = inst->Src[3].Register.Index;
} else {
if (modifier == LP_BLD_TEX_MODIFIER_PROJECTED ||
modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS ||
modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD) {
readmask |= TGSI_WRITEMASK_W;
}
- tex_info->unit = inst->Src[1].Register.Index;
+ tex_info->sampler_unit = inst->Src[1].Register.Index;
+ tex_info->texture_unit = inst->Src[1].Register.Index;
+ }
+
+ for (chan = 0; chan < 4; ++chan) {
+ struct lp_tgsi_channel_info *chan_info = &tex_info->coord[chan];
+ if (readmask & (1 << chan)) {
+ analyse_src(ctx, chan_info, &inst->Src[0].Register, chan);
+ if (chan_info->file != TGSI_FILE_INPUT) {
+ indirect = TRUE;
+ }
+ } else {
+ memset(chan_info, 0, sizeof *chan_info);
+ }
+ }
+
+ if (indirect) {
+ info->indirect_textures = TRUE;
+ }
+
+ ++info->num_texs;
+ } else {
+ info->indirect_textures = TRUE;
+ }
+}
+
+
+/**
+ * Analyse properties of sample instructions, in particular used
+ * to figure out if a texture is considered indirect.
+ * Not actually used by much except the tgsi dumping code.
+ */
+static void
+analyse_sample(struct analysis_context *ctx,
+ const struct tgsi_full_instruction *inst,
+ enum lp_build_tex_modifier modifier,
+ boolean shadow)
+{
+ struct lp_tgsi_info *info = ctx->info;
+ unsigned chan;
+
+ if (info->num_texs < Elements(info->tex)) {
+ struct lp_tgsi_texture_info *tex_info = &info->tex[info->num_texs];
+ unsigned target = ctx->sample_target[inst->Src[1].Register.Index];
+ boolean indirect = FALSE;
+ boolean shadow = FALSE;
+ unsigned readmask;
+
+ switch (target) {
+ /* note no shadow targets here */
+ case TGSI_TEXTURE_BUFFER:
+ case TGSI_TEXTURE_1D:
+ readmask = TGSI_WRITEMASK_X;
+ break;
+ case TGSI_TEXTURE_1D_ARRAY:
+ case TGSI_TEXTURE_2D:
+ case TGSI_TEXTURE_RECT:
+ readmask = TGSI_WRITEMASK_XY;
+ break;
+ case TGSI_TEXTURE_2D_ARRAY:
+ case TGSI_TEXTURE_2D_MSAA:
+ case TGSI_TEXTURE_3D:
+ case TGSI_TEXTURE_CUBE:
+ readmask = TGSI_WRITEMASK_XYZ;
+ break;
+ case TGSI_TEXTURE_CUBE_ARRAY:
+ case TGSI_TEXTURE_2D_ARRAY_MSAA:
+ readmask = TGSI_WRITEMASK_XYZW;
+ break;
+ default:
+ assert(0);
+ return;
+ }
+
+ tex_info->target = target;
+ tex_info->texture_unit = inst->Src[1].Register.Index;
+ tex_info->sampler_unit = inst->Src[2].Register.Index;
+
+ if (tex_info->texture_unit != tex_info->sampler_unit) {
+ info->sampler_texture_units_different = TRUE;
+ }
+
+ if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV ||
+ modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD ||
+ modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS || shadow) {
+ /* We don't track insts with additional regs, although we could */
+ indirect = TRUE;
}
for (chan = 0; chan < 4; ++chan) {
case TGSI_OPCODE_TXP:
analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_PROJECTED);
break;
+ case TGSI_OPCODE_TEX2:
+ analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE);
+ break;
+ case TGSI_OPCODE_TXB2:
+ analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS);
+ break;
+ case TGSI_OPCODE_TXL2:
+ analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD);
+ break;
+ case TGSI_OPCODE_SAMPLE:
+ analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_NONE, FALSE);
+ break;
+ case TGSI_OPCODE_SAMPLE_C:
+ analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_NONE, TRUE);
+ break;
+ case TGSI_OPCODE_SAMPLE_C_LZ:
+ analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_ZERO, TRUE);
+ break;
+ case TGSI_OPCODE_SAMPLE_D:
+ analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV, FALSE);
+ break;
+ case TGSI_OPCODE_SAMPLE_B:
+ analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS, FALSE);
+ break;
+ case TGSI_OPCODE_SAMPLE_L:
+ analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD, FALSE);
+ break;
default:
break;
}
switch (inst->Instruction.Opcode) {
case TGSI_OPCODE_IF:
- case TGSI_OPCODE_IFC:
+ case TGSI_OPCODE_UIF:
case TGSI_OPCODE_ELSE:
case TGSI_OPCODE_ENDIF:
case TGSI_OPCODE_BGNLOOP:
&tex_info->coord[chan];
if (chan_info->file != TGSI_FILE_NULL) {
debug_printf(" %s[%u].%c",
- tgsi_file_names[chan_info->file],
+ tgsi_file_name(chan_info->file),
chan_info->u.index,
"xyzw01"[chan_info->swizzle]);
} else {
debug_printf(" _");
}
}
- debug_printf(", SAMP[%u], %s\n",
- tex_info->unit,
+ debug_printf(", RES[%u], SAMP[%u], %s\n",
+ tex_info->texture_unit,
+ tex_info->sampler_unit,
tgsi_texture_names[tex_info->target]);
}
struct lp_tgsi_info *info)
{
struct tgsi_parse_context parse;
- struct analysis_context ctx;
+ struct analysis_context *ctx;
unsigned index;
unsigned chan;
tgsi_scan_shader(tokens, &info->base);
- memset(&ctx, 0, sizeof ctx);
- ctx.info = info;
+ ctx = CALLOC(1, sizeof(struct analysis_context));
+ ctx->info = info;
tgsi_parse_init(&parse, tokens);
tgsi_parse_token(&parse);
switch (parse.FullToken.Token.Type) {
- case TGSI_TOKEN_TYPE_DECLARATION:
+ case TGSI_TOKEN_TYPE_DECLARATION: {
+ struct tgsi_full_declaration *decl = &parse.FullToken.FullDeclaration;
+ if (decl->Declaration.File == TGSI_FILE_SAMPLER_VIEW) {
+ for (index = decl->Range.First; index <= decl->Range.Last; index++) {
+ ctx->sample_target[index] = decl->SamplerView.Resource;
+ }
+ }
+ }
break;
case TGSI_TOKEN_TYPE_INSTRUCTION:
goto finished;
}
- analyse_instruction(&ctx, inst);
+ analyse_instruction(ctx, inst);
}
break;
const unsigned size =
parse.FullToken.FullImmediate.Immediate.NrTokens - 1;
assert(size <= 4);
- if (ctx.num_imms < Elements(ctx.imm)) {
+ if (ctx->num_imms < Elements(ctx->imm)) {
for (chan = 0; chan < size; ++chan) {
- ctx.imm[ctx.num_imms][chan] =
- parse.FullToken.FullImmediate.u[chan].Float;
+ float value = parse.FullToken.FullImmediate.u[chan].Float;
+ ctx->imm[ctx->num_imms][chan] = value;
+
+ if (value < 0.0f || value > 1.0f) {
+ info->unclamped_immediates = TRUE;
+ }
}
- ++ctx.num_imms;
+ ++ctx->num_imms;
}
}
break;
finished:
tgsi_parse_free(&parse);
+ FREE(ctx);
/*