mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-29 08:00:12 +01:00
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:
parent
a6746d1124
commit
3541705816
2 changed files with 173 additions and 5 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue