diff options
Diffstat (limited to 'src/gallium/drivers/r300/r300_texture.c')
-rw-r--r-- | src/gallium/drivers/r300/r300_texture.c | 123 |
1 files changed, 82 insertions, 41 deletions
diff --git a/src/gallium/drivers/r300/r300_texture.c b/src/gallium/drivers/r300/r300_texture.c index 3c8ff24e17d..093a21ebe24 100644 --- a/src/gallium/drivers/r300/r300_texture.c +++ b/src/gallium/drivers/r300/r300_texture.c @@ -27,19 +27,25 @@ #include "r300_context.h" #include "r300_texture.h" +#include "r300_screen.h" -static void r300_setup_texture_state(struct r300_texture* tex) +static void r300_setup_texture_state(struct r300_texture* tex, boolean is_r500) { struct r300_texture_state* state = &tex->state; struct pipe_texture *pt = &tex->tex; - state->format0 = R300_TX_WIDTH((pt->width[0] - 1) & 0x7ff) | - R300_TX_HEIGHT((pt->height[0] - 1) & 0x7ff) | - R300_TX_DEPTH(util_logbase2(pt->depth[0]) & 0xf) | - R300_TX_NUM_LEVELS(pt->last_level) | - R300_TX_PITCH_EN; + state->format0 = R300_TX_WIDTH((pt->width0 - 1) & 0x7ff) | + R300_TX_HEIGHT((pt->height0 - 1) & 0x7ff); + + if (tex->is_npot) { + /* rectangles love this */ + state->format0 |= R300_TX_PITCH_EN; + state->format2 = (tex->pitch[0] - 1) & 0x1fff; + } else { + /* power of two textures (3D, mipmaps, and no pitch) */ + state->format0 |= R300_TX_DEPTH(util_logbase2(pt->depth0) & 0xf); + } - /* XXX */ state->format1 = r300_translate_texformat(pt->format); if (pt->target == PIPE_TEXTURE_CUBE) { state->format1 |= R300_TX_FORMAT_CUBIC_MAP; @@ -48,19 +54,40 @@ static void r300_setup_texture_state(struct r300_texture* tex) state->format1 |= R300_TX_FORMAT_3D; } - state->format2 = (r300_texture_get_stride(tex, 0) / pt->block.size) - 1; - - /* Don't worry about accidentally setting this bit on non-r500; - * the kernel should catch it. */ - if (pt->width[0] > 2048) { - state->format2 |= R500_TXWIDTH_BIT11; - } - if (pt->height[0] > 2048) { - state->format2 |= R500_TXHEIGHT_BIT11; + /* large textures on r500 */ + if (is_r500) + { + if (pt->width0 > 2048) { + state->format2 |= R500_TXWIDTH_BIT11; + } + if (pt->height0 > 2048) { + state->format2 |= R500_TXHEIGHT_BIT11; + } } + assert(is_r500 || (pt->width0 <= 2048 && pt->height0 <= 2048)); debug_printf("r300: Set texture state (%dx%d, %d levels)\n", - pt->width[0], pt->height[0], pt->last_level); + pt->width0, pt->height0, pt->last_level); +} + +unsigned r300_texture_get_offset(struct r300_texture* tex, unsigned level, + unsigned zslice, unsigned face) +{ + unsigned offset = tex->offset[level]; + + switch (tex->tex.target) { + case PIPE_TEXTURE_3D: + assert(face == 0); + return offset + zslice * tex->layer_size[level]; + + case PIPE_TEXTURE_CUBE: + assert(zslice == 0); + return offset + face * tex->layer_size[level]; + + default: + assert(zslice == 0 && face == 0); + return offset; + } } /** @@ -78,38 +105,45 @@ unsigned r300_texture_get_stride(struct r300_texture* tex, unsigned level) return 0; } - return align(pf_get_stride(&tex->tex.block, tex->tex.width[level]), 32); + return align(pf_get_stride(&tex->tex.block, u_minify(tex->tex.width0, level)), 32); } static void r300_setup_miptree(struct r300_texture* tex) { struct pipe_texture* base = &tex->tex; - int stride, size; + int stride, size, layer_size; int i; for (i = 0; i <= base->last_level; i++) { - if (i > 0) { - base->width[i] = minify(base->width[i-1]); - base->height[i] = minify(base->height[i-1]); - base->depth[i] = minify(base->depth[i-1]); - } - - base->nblocksx[i] = pf_get_nblocksx(&base->block, base->width[i]); - base->nblocksy[i] = pf_get_nblocksy(&base->block, base->height[i]); + base->nblocksx[i] = pf_get_nblocksx(&base->block, u_minify(base->width0, i)); + base->nblocksy[i] = pf_get_nblocksy(&base->block, u_minify(base->height0, i)); stride = r300_texture_get_stride(tex, i); - size = stride * base->nblocksy[i] * base->depth[i]; + layer_size = stride * base->nblocksy[i]; + + if (base->target == PIPE_TEXTURE_CUBE) + size = layer_size * 6; + else + size = layer_size * u_minify(base->depth0, i); tex->offset[i] = align(tex->size, 32); tex->size = tex->offset[i] + size; + tex->layer_size[i] = layer_size; + tex->pitch[i] = stride / base->block.size; debug_printf("r300: Texture miptree: Level %d " "(%dx%dx%d px, pitch %d bytes)\n", - i, base->width[i], base->height[i], base->depth[i], - stride); + i, u_minify(base->width0, i), u_minify(base->height0, i), + u_minify(base->depth0, i), stride); } } +static void r300_setup_flags(struct r300_texture* tex) +{ + tex->is_npot = !util_is_power_of_two(tex->tex.width0) || + !util_is_power_of_two(tex->tex.height0); +} + /* Create a new texture. */ static struct pipe_texture* r300_texture_create(struct pipe_screen* screen, @@ -125,9 +159,9 @@ static struct pipe_texture* pipe_reference_init(&tex->tex.reference, 1); tex->tex.screen = screen; + r300_setup_flags(tex); r300_setup_miptree(tex); - - r300_setup_texture_state(tex); + r300_setup_texture_state(tex, r300_screen(screen)->caps->is_r500); tex->buffer = screen->buffer_create(screen, 1024, PIPE_BUFFER_USAGE_PIXEL, @@ -161,17 +195,20 @@ static struct pipe_surface* r300_get_tex_surface(struct pipe_screen* screen, struct pipe_surface* surface = CALLOC_STRUCT(pipe_surface); unsigned offset; - /* XXX this is certainly dependent on tex target */ - offset = tex->offset[level]; + offset = r300_texture_get_offset(tex, level, zslice, face); if (surface) { pipe_reference_init(&surface->reference, 1); pipe_texture_reference(&surface->texture, texture); surface->format = texture->format; - surface->width = texture->width[level]; - surface->height = texture->height[level]; + surface->width = u_minify(texture->width0, level); + surface->height = u_minify(texture->height0, level); surface->offset = offset; surface->usage = flags; + surface->zslice = zslice; + surface->texture = texture; + surface->face = face; + surface->level = level; } return surface; @@ -191,8 +228,10 @@ static struct pipe_texture* { struct r300_texture* tex; + /* Support only 2D textures without mipmaps */ if (base->target != PIPE_TEXTURE_2D || - base->depth[0] != 1) { + base->depth0 != 1 || + base->last_level != 0) { return NULL; } @@ -206,8 +245,10 @@ static struct pipe_texture* tex->tex.screen = screen; tex->stride_override = *stride; + tex->pitch[0] = *stride / base->block.size; - r300_setup_texture_state(tex); + r300_setup_flags(tex); + r300_setup_texture_state(tex, r300_screen(screen)->caps->is_r500); pipe_buffer_reference(&tex->buffer, buffer); @@ -239,9 +280,9 @@ r300_video_surface_create(struct pipe_screen *screen, template.target = PIPE_TEXTURE_2D; template.format = PIPE_FORMAT_X8R8G8B8_UNORM; template.last_level = 0; - template.width[0] = util_next_power_of_two(width); - template.height[0] = util_next_power_of_two(height); - template.depth[0] = 1; + template.width0 = util_next_power_of_two(width); + template.height0 = util_next_power_of_two(height); + template.depth0 = 1; pf_get_block(template.format, &template.block); template.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER | PIPE_TEXTURE_USAGE_RENDER_TARGET; |