From d5af1dce8fc23dc3763773e3c0b7e0be128d2aa0 Mon Sep 17 00:00:00 2001 From: Corbin Simpson Date: Sun, 11 Apr 2010 16:13:45 -0700 Subject: [PATCH] r300/compiler: Implement texcoord repeat and mirror for NPOT. --- src/gallium/drivers/r300/r300_fs.c | 51 +++++++-------- .../drivers/dri/r300/compiler/r300_fragprog.c | 62 +++++++++++++++---- .../drivers/dri/r300/compiler/r500_fragprog.c | 57 +++++++++++++++++ .../drivers/dri/r300/compiler/radeon_code.h | 7 ++- 4 files changed, 140 insertions(+), 37 deletions(-) diff --git a/src/gallium/drivers/r300/r300_fs.c b/src/gallium/drivers/r300/r300_fs.c index c0d26e5ebde..6af6028447f 100644 --- a/src/gallium/drivers/r300/r300_fs.c +++ b/src/gallium/drivers/r300/r300_fs.c @@ -139,11 +139,14 @@ static void get_external_state( for (i = 0; i < texstate->sampler_state_count; i++) { struct r300_sampler_state* s = texstate->sampler_states[i]; + struct r300_texture *t; - if (!s) { + if (!s || !texstate->sampler_views[i]) { continue; } + t = (struct r300_texture*)texstate->sampler_views[i]->base.texture; + if (s->state.compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { /* XXX Gallium doesn't provide us with any information regarding * this mode, so we are screwed. I'm setting 0 = LUMINANCE. */ @@ -153,30 +156,28 @@ static void get_external_state( state->unit[i].texture_compare_func = s->state.compare_func; } - /* Should we ask the shader to handle wrapping modes for us? */ - if (!s->state.normalized_coords) { - state->unit[i].non_normalized_coords = 1; - - /* XXX this should probably take into account STR, not just S. */ - switch (s->state.wrap_s) { - case PIPE_TEX_WRAP_REPEAT: - state->unit[i].wrap_mode = RC_WRAP_REPEAT; - break; - case PIPE_TEX_WRAP_CLAMP: - case PIPE_TEX_WRAP_CLAMP_TO_EDGE: - case PIPE_TEX_WRAP_CLAMP_TO_BORDER: - state->unit[i].wrap_mode = RC_WRAP_CLAMP; - break; - case PIPE_TEX_WRAP_MIRROR_REPEAT: - case PIPE_TEX_WRAP_MIRROR_CLAMP: - case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: - case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: - state->unit[i].wrap_mode = RC_WRAP_MIRROR; - break; - default: - state->unit[i].wrap_mode = RC_WRAP_NONE; - break; - } + state->unit[i].fake_npot = t->uses_pitch; + state->unit[i].non_normalized_coords = !s->state.normalized_coords; + + /* XXX this should probably take into account STR, not just S. */ + switch (s->state.wrap_s) { + case PIPE_TEX_WRAP_REPEAT: + state->unit[i].wrap_mode = RC_WRAP_REPEAT; + break; + case PIPE_TEX_WRAP_CLAMP: + case PIPE_TEX_WRAP_CLAMP_TO_EDGE: + case PIPE_TEX_WRAP_CLAMP_TO_BORDER: + state->unit[i].wrap_mode = RC_WRAP_CLAMP; + break; + case PIPE_TEX_WRAP_MIRROR_REPEAT: + case PIPE_TEX_WRAP_MIRROR_CLAMP: + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: + state->unit[i].wrap_mode = RC_WRAP_MIRROR; + break; + default: + state->unit[i].wrap_mode = RC_WRAP_NONE; + break; } } } diff --git a/src/mesa/drivers/dri/r300/compiler/r300_fragprog.c b/src/mesa/drivers/dri/r300/compiler/r300_fragprog.c index 928c15e1e40..4a60d05cd76 100644 --- a/src/mesa/drivers/dri/r300/compiler/r300_fragprog.c +++ b/src/mesa/drivers/dri/r300/compiler/r300_fragprog.c @@ -143,19 +143,59 @@ int r300_transform_TEX( * instead of [0..Width]x[0..Height]. * Add a scaling instruction. */ - if (inst->U.I.Opcode != RC_OPCODE_KIL && inst->U.I.TexSrcTarget == RC_TEXTURE_RECT) { - struct rc_instruction * inst_mul = rc_insert_new_instruction(c, inst->Prev); + if (inst->U.I.Opcode != RC_OPCODE_KIL && + (inst->U.I.TexSrcTarget == RC_TEXTURE_RECT || + compiler->state.unit[inst->U.I.TexSrcUnit].fake_npot || + compiler->state.unit[inst->U.I.TexSrcUnit].non_normalized_coords)) { + rc_wrap_mode wrapmode = compiler->state.unit[inst->U.I.TexSrcUnit].wrap_mode; + struct rc_instruction *inst_rect = NULL; + unsigned temp = rc_find_free_temporary(c); + + if (inst->U.I.TexSrcTarget == RC_TEXTURE_RECT || + compiler->state.unit[inst->U.I.TexSrcUnit].non_normalized_coords) { + inst_rect = rc_insert_new_instruction(c, inst->Prev); + + inst_rect->U.I.Opcode = RC_OPCODE_MUL; + inst_rect->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_rect->U.I.DstReg.Index = temp; + inst_rect->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + inst_rect->U.I.SrcReg[1].File = RC_FILE_CONSTANT; + inst_rect->U.I.SrcReg[1].Index = + rc_constants_add_state(&c->Program.Constants, + RC_STATE_R300_TEXRECT_FACTOR, inst->U.I.TexSrcUnit); + + reset_srcreg(&inst->U.I.SrcReg[0]); + inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[0].Index = inst_rect->U.I.DstReg.Index; + + inst->U.I.TexSrcTarget = RC_TEXTURE_2D; + } - inst_mul->U.I.Opcode = RC_OPCODE_MUL; - inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY; - inst_mul->U.I.DstReg.Index = rc_find_free_temporary(c); - inst_mul->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; - inst_mul->U.I.SrcReg[1].File = RC_FILE_CONSTANT; - inst_mul->U.I.SrcReg[1].Index = rc_constants_add_state(&c->Program.Constants, RC_STATE_R300_TEXRECT_FACTOR, inst->U.I.TexSrcUnit); + if (compiler->state.unit[inst->U.I.TexSrcUnit].fake_npot && + wrapmode != RC_WRAP_NONE && wrapmode != RC_WRAP_CLAMP) { + /* Repeat, with optional mirror */ + inst_rect = rc_insert_new_instruction(c, inst->Prev); + + inst_rect->U.I.Opcode = RC_OPCODE_FRC; + inst_rect->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_rect->U.I.DstReg.Index = temp; + inst_rect->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + + if (wrapmode == RC_WRAP_MIRROR) { + inst_rect = rc_insert_new_instruction(c, inst->Prev); + + inst_rect->U.I.Opcode = RC_OPCODE_SUB; + inst_rect->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_rect->U.I.DstReg.Index = temp; + inst_rect->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_1111; + inst_rect->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; + inst_rect->U.I.SrcReg[1].Index = temp; + } - reset_srcreg(&inst->U.I.SrcReg[0]); - inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; - inst->U.I.SrcReg[0].Index = inst_mul->U.I.DstReg.Index; + reset_srcreg(&inst->U.I.SrcReg[0]); + inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[0].Index = inst_rect->U.I.DstReg.Index; + } } /* Cannot write texture to output registers or with masks */ diff --git a/src/mesa/drivers/dri/r300/compiler/r500_fragprog.c b/src/mesa/drivers/dri/r300/compiler/r500_fragprog.c index b78d7d57157..c20ee90fcd6 100644 --- a/src/mesa/drivers/dri/r300/compiler/r500_fragprog.c +++ b/src/mesa/drivers/dri/r300/compiler/r500_fragprog.c @@ -138,6 +138,63 @@ int r500_transform_TEX( } } + /* Texture wrap modes don't work on NPOT textures or texrects. */ + if (inst->U.I.Opcode != RC_OPCODE_KIL && + (inst->U.I.TexSrcTarget == RC_TEXTURE_RECT || + compiler->state.unit[inst->U.I.TexSrcUnit].fake_npot || + compiler->state.unit[inst->U.I.TexSrcUnit].non_normalized_coords)) { + rc_wrap_mode wrapmode = compiler->state.unit[inst->U.I.TexSrcUnit].wrap_mode; + struct rc_instruction *inst_rect = NULL; + unsigned temp = rc_find_free_temporary(c); + + if (compiler->state.unit[inst->U.I.TexSrcUnit].fake_npot && + wrapmode != RC_WRAP_NONE && wrapmode != RC_WRAP_CLAMP) { + + if ((inst->U.I.TexSrcTarget == RC_TEXTURE_RECT || + compiler->state.unit[inst->U.I.TexSrcUnit].non_normalized_coords)) { + inst_rect = rc_insert_new_instruction(c, inst->Prev); + + inst_rect->U.I.Opcode = RC_OPCODE_MUL; + inst_rect->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_rect->U.I.DstReg.Index = temp; + inst_rect->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + inst_rect->U.I.SrcReg[1].File = RC_FILE_CONSTANT; + inst_rect->U.I.SrcReg[1].Index = + rc_constants_add_state(&c->Program.Constants, + RC_STATE_R300_TEXRECT_FACTOR, inst->U.I.TexSrcUnit); + + reset_srcreg(&inst->U.I.SrcReg[0]); + inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[0].Index = inst_rect->U.I.DstReg.Index; + + inst->U.I.TexSrcTarget = RC_TEXTURE_2D; + } + + /* Repeat, with optional mirror */ + inst_rect = rc_insert_new_instruction(c, inst->Prev); + + inst_rect->U.I.Opcode = RC_OPCODE_FRC; + inst_rect->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_rect->U.I.DstReg.Index = temp; + inst_rect->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + + if (wrapmode == RC_WRAP_MIRROR) { + inst_rect = rc_insert_new_instruction(c, inst->Prev); + + inst_rect->U.I.Opcode = RC_OPCODE_SUB; + inst_rect->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_rect->U.I.DstReg.Index = temp; + inst_rect->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_1111; + inst_rect->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; + inst_rect->U.I.SrcReg[1].Index = temp; + } + + reset_srcreg(&inst->U.I.SrcReg[0]); + inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[0].Index = inst_rect->U.I.DstReg.Index; + } + } + /* Cannot write texture to output registers */ if (inst->U.I.Opcode != RC_OPCODE_KIL && inst->U.I.DstReg.File != RC_FILE_TEMPORARY) { struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst); diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_code.h b/src/mesa/drivers/dri/r300/compiler/radeon_code.h index 45cc7df1e31..0a20dfe2d1a 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_code.h +++ b/src/mesa/drivers/dri/r300/compiler/radeon_code.h @@ -144,7 +144,12 @@ struct r300_fragment_program_external_state { unsigned texture_compare_func : 3; /** - * If the sampler will be accessed with non-normalized coords, + * If the sampler needs to fake NPOT, this field is set. + */ + unsigned fake_npot : 1; + + /** + * If the sampler will recieve non-normalized coords, * this field is set. */ unsigned non_normalized_coords : 1; -- 2.30.2