freedreno: add texcoord clamp support to lowering

This is for hw that needs to emulate some texture wrap modes (like
CLAMP) with some help from the shader.

Signed-off-by: Rob Clark <robclark@freedesktop.org>
This commit is contained in:
Rob Clark 2014-09-29 09:59:27 -04:00
parent a6746d1124
commit 3541705816
2 changed files with 173 additions and 5 deletions

View file

@ -52,6 +52,7 @@ struct fd_lowering_context {
#define B 1
struct tgsi_full_src_register imm;
int emitted_decls;
unsigned saturate;
};
static inline struct fd_lowering_context *
@ -130,12 +131,14 @@ aliases(const struct tgsi_full_dst_register *dst, unsigned dst_mask,
static void
create_mov(struct tgsi_transform_context *tctx,
const struct tgsi_full_dst_register *dst,
const struct tgsi_full_src_register *src, unsigned mask)
const struct tgsi_full_src_register *src,
unsigned mask, unsigned saturate)
{
struct tgsi_full_instruction new_inst;
new_inst = tgsi_default_full_instruction();
new_inst.Instruction.Opcode = TGSI_OPCODE_MOV;
new_inst.Instruction.Saturate = saturate;
new_inst.Instruction.NumDstRegs = 1;
reg_dst(&new_inst.Dst[0], dst, mask);
new_inst.Instruction.NumSrcRegs = 1;
@ -182,12 +185,12 @@ transform_dst(struct tgsi_transform_context *tctx,
struct tgsi_full_instruction new_inst;
if (aliases(dst, TGSI_WRITEMASK_Y, src0, TGSI_WRITEMASK_Z)) {
create_mov(tctx, &ctx->tmp[A].dst, src0, TGSI_WRITEMASK_YZ);
create_mov(tctx, &ctx->tmp[A].dst, src0, TGSI_WRITEMASK_YZ, 0);
src0 = &ctx->tmp[A].src;
}
if (aliases(dst, TGSI_WRITEMASK_YZ, src1, TGSI_WRITEMASK_W)) {
create_mov(tctx, &ctx->tmp[B].dst, src1, TGSI_WRITEMASK_YW);
create_mov(tctx, &ctx->tmp[B].dst, src1, TGSI_WRITEMASK_YW, 0);
src1 = &ctx->tmp[B].src;
}
@ -332,7 +335,7 @@ transform_scs(struct tgsi_transform_context *tctx,
struct tgsi_full_instruction new_inst;
if (aliases(dst, TGSI_WRITEMASK_X, src, TGSI_WRITEMASK_X)) {
create_mov(tctx, &ctx->tmp[A].dst, src, TGSI_WRITEMASK_X);
create_mov(tctx, &ctx->tmp[A].dst, src, TGSI_WRITEMASK_X, 0);
src = &ctx->tmp[A].src;
}
@ -981,6 +984,138 @@ transform_dotp(struct tgsi_transform_context *tctx,
}
}
/* Inserts a MOV_SAT for the needed components of tex coord. Note that
* in the case of TXP, the clamping must happen *after* projection, so
* we need to lower TXP to TEX.
*
* MOV tmpA, src0
* if (opc == TXP) {
* ; do perspective division manually before clamping:
* RCP tmpB, tmpA.w
* MUL tmpB.<pmask>, tmpA, tmpB.xxxx
* opc = TEX;
* }
* MOV_SAT tmpA.<mask>, tmpA ; <mask> is the clamped s/t/r coords
* <opc> dst, tmpA, ...
*/
#define SAMP_GROW (13)
#define SAMP_TMP 2
static int
transform_samp(struct tgsi_transform_context *tctx,
struct tgsi_full_instruction *inst)
{
struct fd_lowering_context *ctx = fd_lowering_context(tctx);
struct tgsi_full_src_register *coord = &inst->Src[0];
struct tgsi_full_src_register *samp;
struct tgsi_full_instruction new_inst;
/* mask is clamped coords, pmask is all coords (for projection): */
unsigned mask = 0, pmask = 0, smask;
unsigned opcode = inst->Instruction.Opcode;
if (opcode == TGSI_OPCODE_TXB2) {
samp = &inst->Src[2];
} else {
samp = &inst->Src[1];
}
/* convert sampler # to bitmask to test: */
smask = 1 << samp->Register.Index;
/* check if we actually need to lower this one: */
if (!(ctx->saturate & smask))
return -1;
/* figure out which coordinates need saturating:
* - RECT textures should not get saturated
* - array index coords should not get saturated
*/
switch (inst->Texture.Texture) {
case TGSI_TEXTURE_3D:
case TGSI_TEXTURE_CUBE:
case TGSI_TEXTURE_CUBE_ARRAY:
case TGSI_TEXTURE_SHADOWCUBE:
case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
if (ctx->config->saturate_r & smask)
mask |= TGSI_WRITEMASK_Z;
pmask |= TGSI_WRITEMASK_Z;
/* fallthrough */
case TGSI_TEXTURE_2D:
case TGSI_TEXTURE_2D_ARRAY:
case TGSI_TEXTURE_SHADOW2D:
case TGSI_TEXTURE_SHADOW2D_ARRAY:
case TGSI_TEXTURE_2D_MSAA:
case TGSI_TEXTURE_2D_ARRAY_MSAA:
if (ctx->config->saturate_t & smask)
mask |= TGSI_WRITEMASK_Y;
pmask |= TGSI_WRITEMASK_Y;
/* fallthrough */
case TGSI_TEXTURE_1D:
case TGSI_TEXTURE_1D_ARRAY:
case TGSI_TEXTURE_SHADOW1D:
case TGSI_TEXTURE_SHADOW1D_ARRAY:
if (ctx->config->saturate_s & smask)
mask |= TGSI_WRITEMASK_X;
pmask |= TGSI_WRITEMASK_X;
break;
/* TODO: I think we should ignore these?
case TGSI_TEXTURE_RECT:
case TGSI_TEXTURE_SHADOWRECT:
*/
}
/* sanity check.. driver could be asking to saturate a non-
* existent coordinate component:
*/
if (!mask)
return -1;
/* MOV tmpA, src0 */
create_mov(tctx, &ctx->tmp[A].dst, coord, TGSI_WRITEMASK_XYZW, 0);
/* This is a bit sad.. we need to clamp *after* the coords
* are projected, which means lowering TXP to TEX and doing
* the projection ourself. But since I haven't figured out
* how to make the lowering code deliver an electric shock
* to anyone using GL_CLAMP, we must do this instead:
*/
if (opcode == TGSI_OPCODE_TXP) {
/* RCP tmpB.x tmpA.w */
new_inst = tgsi_default_full_instruction();
new_inst.Instruction.Opcode = TGSI_OPCODE_RCP;
new_inst.Instruction.NumDstRegs = 1;
reg_dst(&new_inst.Dst[0], &ctx->tmp[B].dst, TGSI_WRITEMASK_X);
new_inst.Instruction.NumSrcRegs = 1;
reg_src(&new_inst.Src[0], &ctx->tmp[A].src, SWIZ(W,_,_,_));
tctx->emit_instruction(tctx, &new_inst);
/* MUL tmpA.mask, tmpA, tmpB.xxxx */
new_inst = tgsi_default_full_instruction();
new_inst.Instruction.Opcode = TGSI_OPCODE_MUL;
new_inst.Instruction.NumDstRegs = 1;
reg_dst(&new_inst.Dst[0], &ctx->tmp[A].dst, pmask);
new_inst.Instruction.NumSrcRegs = 2;
reg_src(&new_inst.Src[0], &ctx->tmp[A].src, SWIZ(X,Y,Z,W));
reg_src(&new_inst.Src[1], &ctx->tmp[B].src, SWIZ(X,X,X,X));
tctx->emit_instruction(tctx, &new_inst);
opcode = TGSI_OPCODE_TEX;
}
/* MOV_SAT tmpA.<mask>, tmpA */
create_mov(tctx, &ctx->tmp[A].dst, &ctx->tmp[A].src, mask,
TGSI_SAT_ZERO_ONE);
/* modify the texture samp instruction to take fixed up coord: */
new_inst = *inst;
new_inst.Instruction.Opcode = opcode;
new_inst.Src[0] = ctx->tmp[A].src;
tctx->emit_instruction(tctx, &new_inst);
return 0;
}
/* Two-sided color emulation:
* For each COLOR input, create a corresponding BCOLOR input, plus
@ -1234,6 +1369,14 @@ transform_instr(struct tgsi_transform_context *tctx,
goto skip;
transform_dotp(tctx, inst);
break;
case TGSI_OPCODE_TEX:
case TGSI_OPCODE_TXP:
case TGSI_OPCODE_TXB:
case TGSI_OPCODE_TXB2:
case TGSI_OPCODE_TXL:
if (transform_samp(tctx, inst))
goto skip;
break;
default:
skip:
tctx->emit_instruction(tctx, inst);
@ -1254,6 +1397,9 @@ fd_transform_lowering(const struct fd_lowering_config *config,
struct tgsi_token *newtoks;
int newlen, numtmp;
/* sanity check in case limit is ever increased: */
assert((sizeof(config->saturate_s) * 8) >= PIPE_MAX_SAMPLERS);
memset(&ctx, 0, sizeof(ctx));
ctx.base.transform_instruction = transform_instr;
ctx.info = info;
@ -1277,6 +1423,8 @@ fd_transform_lowering(const struct fd_lowering_config *config,
}
}
ctx.saturate = config->saturate_r | config->saturate_s | config->saturate_t;
#define OPCS(x) ((config->lower_ ## x) ? info->opcode_count[TGSI_OPCODE_ ## x] : 0)
/* if there are no instructions to lower, then we are done: */
if (!(OPCS(DST) ||
@ -1293,7 +1441,8 @@ fd_transform_lowering(const struct fd_lowering_config *config,
OPCS(DPH) ||
OPCS(DP2) ||
OPCS(DP2A) ||
ctx.two_side_colors))
ctx.two_side_colors ||
ctx.saturate))
return NULL;
#if 0 /* debug */
@ -1359,6 +1508,15 @@ fd_transform_lowering(const struct fd_lowering_config *config,
newlen += DP2A_GROW * OPCS(DP2A);
numtmp = MAX2(numtmp, DOTP_TMP);
}
if (ctx.saturate) {
int n = info->opcode_count[TGSI_OPCODE_TEX] +
info->opcode_count[TGSI_OPCODE_TXP] +
info->opcode_count[TGSI_OPCODE_TXB] +
info->opcode_count[TGSI_OPCODE_TXB2] +
info->opcode_count[TGSI_OPCODE_TXL];
newlen += SAMP_GROW * n;
numtmp = MAX2(numtmp, SAMP_TMP);
}
/* specifically don't include two_side_colors temps in the count: */
ctx.numtmp = numtmp;

View file

@ -69,6 +69,16 @@ struct fd_lowering_config {
unsigned lower_DPH : 1;
unsigned lower_DP2 : 1;
unsigned lower_DP2A : 1;
/* To emulate certain texture wrap modes, this can be used
* to saturate the specified tex coord to [0.0, 1.0]. The
* bits are according to sampler #, ie. if, for example:
*
* (conf->saturate_s & (1 << n))
*
* is true, then the s coord for sampler n is saturated.
*/
unsigned saturate_s, saturate_t, saturate_r;
};
const struct tgsi_token * fd_transform_lowering(