summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gallium/drivers/r300/r300_context.h7
-rw-r--r--src/gallium/drivers/r300/r300_emit.c16
-rw-r--r--src/gallium/drivers/r300/r300_fs.c3
-rw-r--r--src/gallium/drivers/r300/r300_texture.c15
-rw-r--r--src/gallium/drivers/r300/r300_texture_desc.c35
-rw-r--r--src/mesa/drivers/dri/r300/compiler/radeon_code.h9
-rw-r--r--src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c32
7 files changed, 90 insertions, 27 deletions
diff --git a/src/gallium/drivers/r300/r300_context.h b/src/gallium/drivers/r300/r300_context.h
index 1927370325e..b59bc002610 100644
--- a/src/gallium/drivers/r300/r300_context.h
+++ b/src/gallium/drivers/r300/r300_context.h
@@ -336,6 +336,13 @@ struct r300_texture_desc {
/* Parent class. */
struct u_resource b;
+ /* Width, height, and depth.
+ * Most of the time, these are equal to pipe_texture::width0, height0,
+ * and depth0. However, NPOT 3D textures must have dimensions aligned
+ * to POT, and this is the only case when these variables differ from
+ * pipe_texture. */
+ unsigned width0, height0, depth0;
+
/* Buffer tiling.
* Macrotiling is specified per-level because small mipmaps cannot
* be macrotiled. */
diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c
index db783ff0add..3a1085d2dc5 100644
--- a/src/gallium/drivers/r300/r300_emit.c
+++ b/src/gallium/drivers/r300/r300_emit.c
@@ -89,7 +89,7 @@ static const float * get_rc_constant_state(
{
struct r300_textures_state* texstate = r300->textures_state.state;
static float vec[4] = { 0.0, 0.0, 0.0, 1.0 };
- struct pipe_resource *tex;
+ struct r300_texture *tex;
assert(constant->Type == RC_CONSTANT_STATE);
@@ -97,9 +97,17 @@ static const float * get_rc_constant_state(
/* Factor for converting rectangle coords to
* normalized coords. Should only show up on non-r500. */
case RC_STATE_R300_TEXRECT_FACTOR:
- tex = texstate->sampler_views[constant->u.State[1]]->base.texture;
- vec[0] = 1.0 / tex->width0;
- vec[1] = 1.0 / tex->height0;
+ tex = r300_texture(texstate->sampler_views[constant->u.State[1]]->base.texture);
+ vec[0] = 1.0 / tex->desc.width0;
+ vec[1] = 1.0 / tex->desc.height0;
+ break;
+
+ case RC_STATE_R300_TEXSCALE_FACTOR:
+ tex = r300_texture(texstate->sampler_views[constant->u.State[1]]->base.texture);
+ /* Add a small number to the texture size to work around rounding errors in hw. */
+ vec[0] = tex->desc.b.b.width0 / (tex->desc.width0 + 0.001f);
+ vec[1] = tex->desc.b.b.height0 / (tex->desc.height0 + 0.001f);
+ vec[2] = tex->desc.b.b.depth0 / (tex->desc.depth0 + 0.001f);
break;
case RC_STATE_R300_VIEWPORT_SCALE:
diff --git a/src/gallium/drivers/r300/r300_fs.c b/src/gallium/drivers/r300/r300_fs.c
index 3f89987897d..d9d4a9304df 100644
--- a/src/gallium/drivers/r300/r300_fs.c
+++ b/src/gallium/drivers/r300/r300_fs.c
@@ -200,6 +200,9 @@ static void get_external_state(
default:
state->unit[i].wrap_mode = RC_WRAP_NONE;
}
+
+ if (t->desc.b.b.target == PIPE_TEXTURE_3D)
+ state->unit[i].clamp_and_scale_before_fetch = TRUE;
}
}
}
diff --git a/src/gallium/drivers/r300/r300_texture.c b/src/gallium/drivers/r300/r300_texture.c
index 34105aa4bcd..a7911c6fcc4 100644
--- a/src/gallium/drivers/r300/r300_texture.c
+++ b/src/gallium/drivers/r300/r300_texture.c
@@ -556,18 +556,15 @@ void r300_texture_setup_format_state(struct r300_screen *screen,
out->tile_config = 0;
/* Set sampler state. */
- out->format0 = R300_TX_WIDTH((u_minify(pt->width0, level) - 1) & 0x7ff) |
- R300_TX_HEIGHT((u_minify(pt->height0, level) - 1) & 0x7ff);
+ out->format0 =
+ R300_TX_WIDTH((u_minify(desc->width0, level) - 1) & 0x7ff) |
+ R300_TX_HEIGHT((u_minify(desc->height0, level) - 1) & 0x7ff) |
+ R300_TX_DEPTH(util_logbase2(u_minify(desc->depth0, level)) & 0xf);
if (desc->uses_stride_addressing) {
/* rectangles love this */
out->format0 |= R300_TX_PITCH_EN;
out->format2 = (desc->stride_in_pixels[level] - 1) & 0x1fff;
- } else {
- /* Power of two textures (3D, mipmaps, and no pitch),
- * also NPOT textures with a width being POT. */
- out->format0 |=
- R300_TX_DEPTH(util_logbase2(u_minify(pt->depth0, level)) & 0xf);
}
if (pt->target == PIPE_TEXTURE_CUBE) {
@@ -580,10 +577,10 @@ void r300_texture_setup_format_state(struct r300_screen *screen,
/* large textures on r500 */
if (is_r500)
{
- if (pt->width0 > 2048) {
+ if (desc->width0 > 2048) {
out->format2 |= R500_TXWIDTH_BIT11;
}
- if (pt->height0 > 2048) {
+ if (desc->height0 > 2048) {
out->format2 |= R500_TXHEIGHT_BIT11;
}
}
diff --git a/src/gallium/drivers/r300/r300_texture_desc.c b/src/gallium/drivers/r300/r300_texture_desc.c
index 6a1030f8eee..a49029e1e92 100644
--- a/src/gallium/drivers/r300/r300_texture_desc.c
+++ b/src/gallium/drivers/r300/r300_texture_desc.c
@@ -91,9 +91,9 @@ static boolean r300_texture_macro_switch(struct r300_texture_desc *desc,
tile = r300_get_pixel_alignment(desc->b.b.format, desc->b.b.nr_samples,
desc->microtile, R300_BUFFER_TILED, dim);
if (dim == DIM_WIDTH) {
- texdim = u_minify(desc->b.b.width0, level);
+ texdim = u_minify(desc->width0, level);
} else {
- texdim = u_minify(desc->b.b.height0, level);
+ texdim = u_minify(desc->height0, level);
}
/* See TX_FILTER1_n.MACRO_SWITCH. */
@@ -124,7 +124,7 @@ static unsigned r300_texture_get_stride(struct r300_screen *screen,
return 0;
}
- width = u_minify(desc->b.b.width0, level);
+ width = u_minify(desc->width0, level);
if (util_format_is_plain(desc->b.b.format)) {
tile_width = r300_get_pixel_alignment(desc->b.b.format,
@@ -172,7 +172,7 @@ static unsigned r300_texture_get_nblocksy(struct r300_texture_desc *desc,
{
unsigned height, tile_height;
- height = u_minify(desc->b.b.height0, level);
+ height = u_minify(desc->height0, level);
if (util_format_is_plain(desc->b.b.format)) {
tile_height = r300_get_pixel_alignment(desc->b.b.format,
@@ -237,7 +237,7 @@ static void r300_texture_3d_fix_mipmapping(struct r300_screen *screen,
r300_texture_get_nblocksy(desc, i, FALSE);
}
- size *= desc->b.b.depth0;
+ size *= desc->depth0;
desc->size_in_bytes = size;
}
}
@@ -292,7 +292,7 @@ static void r300_setup_miptree(struct r300_screen *screen,
if (base->target == PIPE_TEXTURE_CUBE)
size = layer_size * 6;
else
- size = layer_size * u_minify(base->depth0, i);
+ size = layer_size * u_minify(desc->depth0, i);
desc->offset_in_bytes[i] = desc->size_in_bytes;
desc->size_in_bytes = desc->offset_in_bytes[i] + size;
@@ -303,8 +303,8 @@ static void r300_setup_miptree(struct r300_screen *screen,
SCREEN_DBG(screen, DBG_TEXALLOC, "r300: Texture miptree: Level %d "
"(%dx%dx%d px, pitch %d bytes) %d bytes total, macrotiled %s\n",
- i, u_minify(base->width0, i), u_minify(base->height0, i),
- u_minify(base->depth0, i), stride, desc->size_in_bytes,
+ i, u_minify(desc->width0, i), u_minify(desc->height0, i),
+ u_minify(desc->depth0, i), stride, desc->size_in_bytes,
desc->macrotile[i] ? "TRUE" : "FALSE");
}
}
@@ -313,14 +313,14 @@ static void r300_setup_flags(struct r300_texture_desc *desc)
{
desc->uses_stride_addressing =
!util_is_power_of_two(desc->b.b.width0) ||
- !util_is_power_of_two(desc->b.b.height0) ||
(desc->stride_in_bytes_override &&
stride_to_width(desc->b.b.format,
desc->stride_in_bytes_override) != desc->b.b.width0);
desc->is_npot =
desc->uses_stride_addressing ||
- !util_is_power_of_two(desc->b.b.height0);
+ !util_is_power_of_two(desc->b.b.height0) ||
+ !util_is_power_of_two(desc->b.b.depth0);
}
static void r300_setup_cbzb_flags(struct r300_screen *rscreen,
@@ -416,9 +416,21 @@ boolean r300_texture_desc_init(struct r300_screen *rscreen,
{
desc->b.b = *base;
desc->b.b.screen = &rscreen->screen;
-
desc->stride_in_bytes_override = stride_in_bytes_override;
+ desc->width0 = base->width0;
+ desc->height0 = base->height0;
+ desc->depth0 = base->depth0;
+
+ r300_setup_flags(desc);
+
+ /* Align a 3D NPOT texture to POT. */
+ if (base->target == PIPE_TEXTURE_3D && desc->is_npot) {
+ desc->width0 = util_next_power_of_two(desc->width0);
+ desc->height0 = util_next_power_of_two(desc->height0);
+ desc->depth0 = util_next_power_of_two(desc->depth0);
+ }
+ /* Setup tiling. */
if (microtile == R300_BUFFER_SELECT_LAYOUT ||
macrotile == R300_BUFFER_SELECT_LAYOUT) {
r300_setup_tiling(rscreen, desc);
@@ -428,7 +440,6 @@ boolean r300_texture_desc_init(struct r300_screen *rscreen,
assert(desc->b.b.last_level == 0);
}
- r300_setup_flags(desc);
r300_setup_cbzb_flags(rscreen, desc);
/* Setup the miptree description. */
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_code.h b/src/mesa/drivers/dri/r300/compiler/radeon_code.h
index 53cc1bd77e9..2dd9c5e4bd3 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_code.h
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_code.h
@@ -60,6 +60,7 @@ enum {
RC_STATE_R300_WINDOW_DIMENSION,
RC_STATE_R300_TEXRECT_FACTOR,
+ RC_STATE_R300_TEXSCALE_FACTOR,
RC_STATE_R300_VIEWPORT_SCALE,
RC_STATE_R300_VIEWPORT_OFFSET
};
@@ -158,7 +159,13 @@ struct r300_fragment_program_external_state {
* If this field is \ref RC_WRAP_NONE (aka 0), no wrapping maths
* will be performed on the coordinates.
*/
- unsigned wrap_mode : 2;
+ unsigned wrap_mode : 3;
+
+ /**
+ * The coords are scaled after applying the wrap mode emulation
+ * and right before texture fetch. The scaling factor is given by
+ * RC_STATE_R300_TEXSCALE_FACTOR. */
+ unsigned clamp_and_scale_before_fetch : 1;
} unit[16];
};
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c b/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c
index de988b7c10c..530afa5e08e 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c
@@ -252,7 +252,8 @@ int radeonTransformTEX(
/* Divide by W if needed. */
if (inst->U.I.Opcode == RC_OPCODE_TXP &&
- (wrapmode == RC_WRAP_REPEAT || wrapmode == RC_WRAP_MIRRORED_REPEAT)) {
+ (wrapmode == RC_WRAP_REPEAT || wrapmode == RC_WRAP_MIRRORED_REPEAT ||
+ compiler->state.unit[inst->U.I.TexSrcUnit].clamp_and_scale_before_fetch)) {
projective_divide(compiler, inst);
}
@@ -388,6 +389,35 @@ int radeonTransformTEX(
inst->U.I.SrcReg[0].Index = temp;
}
+ if (inst->U.I.Opcode != RC_OPCODE_KIL &&
+ compiler->state.unit[inst->U.I.TexSrcUnit].clamp_and_scale_before_fetch) {
+ struct rc_instruction *inst_mov;
+ unsigned temp = rc_find_free_temporary(c);
+
+ /* Saturate XYZ. */
+ inst_mov = rc_insert_new_instruction(c, inst->Prev);
+ inst_mov->U.I.Opcode = RC_OPCODE_MOV;
+ inst_mov->U.I.SaturateMode = RC_SATURATE_ZERO_ONE;
+ inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
+ inst_mov->U.I.DstReg.Index = temp;
+ inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZ;
+ inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
+
+ /* Copy W. */
+ inst_mov = rc_insert_new_instruction(c, inst->Prev);
+ inst_mov->U.I.Opcode = RC_OPCODE_MOV;
+ inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
+ inst_mov->U.I.DstReg.Index = temp;
+ inst_mov->U.I.DstReg.WriteMask = RC_MASK_W;
+ inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
+
+ reset_srcreg(&inst->U.I.SrcReg[0]);
+ inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
+ inst->U.I.SrcReg[0].Index = temp;
+
+ scale_texcoords(compiler, inst, RC_STATE_R300_TEXSCALE_FACTOR);
+ }
+
/* Cannot write texture to output registers (all chips) or with masks (non-r500) */
if (inst->U.I.Opcode != RC_OPCODE_KIL &&
(inst->U.I.DstReg.File != RC_FILE_TEMPORARY ||