diff options
Diffstat (limited to 'src/mesa/drivers/dri/r300/r300_texstate.c')
-rw-r--r-- | src/mesa/drivers/dri/r300/r300_texstate.c | 535 |
1 files changed, 163 insertions, 372 deletions
diff --git a/src/mesa/drivers/dri/r300/r300_texstate.c b/src/mesa/drivers/dri/r300/r300_texstate.c index e2329f04ec7..33673fa0b9c 100644 --- a/src/mesa/drivers/dri/r300/r300_texstate.c +++ b/src/mesa/drivers/dri/r300/r300_texstate.c @@ -48,6 +48,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "r300_state.h" #include "r300_ioctl.h" #include "radeon_ioctl.h" +#include "r300_mipmap_tree.h" #include "r300_tex.h" #include "r300_reg.h" @@ -148,8 +149,7 @@ void r300SetDepthTexMode(struct gl_texture_object *tObj) if (!tObj) return; - t = (r300TexObjPtr) tObj->DriverData; - + t = r300_tex_obj(tObj); switch (tObj->Image[0][tObj->BaseLevel]->TexFormat->MesaFormat) { case MESA_FORMAT_Z16: @@ -190,399 +190,228 @@ void r300SetDepthTexMode(struct gl_texture_object *tObj) /** - * Compute sizes and fill in offset and blit information for the given - * image (determined by \p face and \p level). - * - * \param curOffset points to the offset at which the image is to be stored - * and is updated by this function according to the size of the image. - */ -static void compute_tex_image_offset( - struct gl_texture_object *tObj, - GLuint face, - GLint level, - GLint* curOffset) -{ - r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData; - const struct gl_texture_image* texImage; - GLuint blitWidth = R300_BLIT_WIDTH_BYTES; - GLuint texelBytes; - GLuint size; - - texImage = tObj->Image[0][level + t->base.firstLevel]; - if (!texImage) - return; - - texelBytes = texImage->TexFormat->TexelBytes; - - /* find image size in bytes */ - if (texImage->IsCompressed) { - if ((t->format & R300_TX_FORMAT_DXT1) == - R300_TX_FORMAT_DXT1) { - // fprintf(stderr,"DXT 1 %d %08X\n", texImage->Width, t->format); - if ((texImage->Width + 3) < 8) /* width one block */ - size = texImage->CompressedSize * 4; - else if ((texImage->Width + 3) < 16) - size = texImage->CompressedSize * 2; - else - size = texImage->CompressedSize; - } else { - /* DXT3/5, 16 bytes per block */ - WARN_ONCE - ("DXT 3/5 suffers from multitexturing problems!\n"); - // fprintf(stderr,"DXT 3/5 %d\n", texImage->Width); - if ((texImage->Width + 3) < 8) - size = texImage->CompressedSize * 2; - else - size = texImage->CompressedSize; - } - } else if (tObj->Target == GL_TEXTURE_RECTANGLE_NV) { - size = - ((texImage->Width * texelBytes + - 63) & ~63) * texImage->Height; - blitWidth = 64 / texelBytes; - } else if (t->tile_bits & R300_TXO_MICRO_TILE) { - /* tile pattern is 16 bytes x2. mipmaps stay 32 byte aligned, - though the actual offset may be different (if texture is less than - 32 bytes width) to the untiled case */ - int w = (texImage->Width * texelBytes * 2 + 31) & ~31; - size = - (w * ((texImage->Height + 1) / 2)) * - texImage->Depth; - blitWidth = MAX2(texImage->Width, 64 / texelBytes); - } else { - int w = (texImage->Width * texelBytes + 31) & ~31; - size = w * texImage->Height * texImage->Depth; - blitWidth = MAX2(texImage->Width, 64 / texelBytes); - } - assert(size > 0); - - if (RADEON_DEBUG & DEBUG_TEXTURE) - fprintf(stderr, "w=%d h=%d d=%d tb=%d intFormat=%d\n", - texImage->Width, texImage->Height, - texImage->Depth, - texImage->TexFormat->TexelBytes, - texImage->InternalFormat); - - /* All images are aligned to a 32-byte offset */ - *curOffset = (*curOffset + 0x1f) & ~0x1f; - - if (texelBytes) { - /* fix x and y coords up later together with offset */ - t->image[face][level].x = *curOffset; - t->image[face][level].y = 0; - t->image[face][level].width = - MIN2(size / texelBytes, blitWidth); - t->image[face][level].height = - (size / texelBytes) / t->image[face][level].width; - } else { - t->image[face][level].x = *curOffset % R300_BLIT_WIDTH_BYTES; - t->image[face][level].y = *curOffset / R300_BLIT_WIDTH_BYTES; - t->image[face][level].width = - MIN2(size, R300_BLIT_WIDTH_BYTES); - t->image[face][level].height = size / t->image[face][level].width; - } - - if (RADEON_DEBUG & DEBUG_TEXTURE) - fprintf(stderr, - "level %d, face %d: %dx%d x=%d y=%d w=%d h=%d size=%d at %d\n", - level, face, texImage->Width, texImage->Height, - t->image[face][level].x, t->image[face][level].y, - t->image[face][level].width, t->image[face][level].height, - size, *curOffset); - - *curOffset += size; -} - - - -/** - * This function computes the number of bytes of storage needed for - * the given texture object (all mipmap levels, all cube faces). - * The \c image[face][level].x/y/width/height parameters for upload/blitting - * are computed here. \c filter, \c format, etc. will be set here - * too. + * Compute the cached hardware register values for the given texture object. * * \param rmesa Context pointer - * \param tObj GL texture object whose images are to be posted to - * hardware state. + * \param t the r300 texture object */ -static void r300SetTexImages(r300ContextPtr rmesa, - struct gl_texture_object *tObj) +static void setup_hardware_state(r300ContextPtr rmesa, r300TexObj *t) { - r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData; - const struct gl_texture_image *baseImage = - tObj->Image[0][tObj->BaseLevel]; - GLint curOffset; - GLint i, texelBytes; - GLint numLevels; - GLint log2Width, log2Height, log2Depth; - - /* Set the hardware texture format - */ + const struct gl_texture_image *firstImage = + t->base.Image[0][t->mt->firstLevel]; + if (!t->image_override - && VALID_FORMAT(baseImage->TexFormat->MesaFormat)) { - if (baseImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) { - r300SetDepthTexMode(tObj); + && VALID_FORMAT(firstImage->TexFormat->MesaFormat)) { + if (firstImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) { + r300SetDepthTexMode(&t->base); } else { - t->format = tx_table[baseImage->TexFormat->MesaFormat].format; + t->format = tx_table[firstImage->TexFormat->MesaFormat].format; } - t->filter |= tx_table[baseImage->TexFormat->MesaFormat].filter; + t->filter |= tx_table[firstImage->TexFormat->MesaFormat].filter; } else if (!t->image_override) { _mesa_problem(NULL, "unexpected texture format in %s", __FUNCTION__); return; } - texelBytes = baseImage->TexFormat->TexelBytes; - - /* Compute which mipmap levels we really want to send to the hardware. - */ - driCalculateTextureFirstLastLevel((driTextureObject *) t); - log2Width = tObj->Image[0][t->base.firstLevel]->WidthLog2; - log2Height = tObj->Image[0][t->base.firstLevel]->HeightLog2; - log2Depth = tObj->Image[0][t->base.firstLevel]->DepthLog2; - - numLevels = t->base.lastLevel - t->base.firstLevel + 1; - - assert(numLevels <= RADEON_MAX_TEXTURE_LEVELS); - - /* Calculate mipmap offsets and dimensions for blitting (uploading) - * The idea is that we lay out the mipmap levels within a block of - * memory organized as a rectangle of width BLIT_WIDTH_BYTES. - */ t->tile_bits = 0; - /* figure out if this texture is suitable for tiling. */ -#if 0 /* Disabled for now */ - if (texelBytes) { - if ((tObj->Target != GL_TEXTURE_RECTANGLE_NV) && - /* texrect might be able to use micro tiling too in theory? */ - (baseImage->Height > 1)) { - - /* allow 32 (bytes) x 1 mip (which will use two times the space - the non-tiled version would use) max if base texture is large enough */ - if ((numLevels == 1) || - (((baseImage->Width * texelBytes / - baseImage->Height) <= 32) - && (baseImage->Width * texelBytes > 64)) - || - ((baseImage->Width * texelBytes / - baseImage->Height) <= 16)) { - t->tile_bits |= R300_TXO_MICRO_TILE; - } - } - - if (tObj->Target != GL_TEXTURE_RECTANGLE_NV) { - /* we can set macro tiling even for small textures, they will be untiled anyway */ - t->tile_bits |= R300_TXO_MACRO_TILE; - } - } -#endif - - curOffset = 0; - - if (tObj->Target == GL_TEXTURE_CUBE_MAP) { - ASSERT(log2Width == log2Height); + if (t->base.Target == GL_TEXTURE_CUBE_MAP) t->format |= R300_TX_FORMAT_CUBIC_MAP; + if (t->base.Target == GL_TEXTURE_3D) + t->format |= R300_TX_FORMAT_3D; - for(i = 0; i < numLevels; i++) { - GLuint face; - for(face = 0; face < 6; face++) - compute_tex_image_offset(tObj, face, i, &curOffset); - } - } else { - if (tObj->Target == GL_TEXTURE_3D) - t->format |= R300_TX_FORMAT_3D; + t->size = (((firstImage->Width - 1) << R300_TX_WIDTHMASK_SHIFT) + | ((firstImage->Height - 1) << R300_TX_HEIGHTMASK_SHIFT)) + | ((t->mt->lastLevel - t->mt->firstLevel) << R300_TX_MAX_MIP_LEVEL_SHIFT); - for (i = 0; i < numLevels; i++) - compute_tex_image_offset(tObj, 0, i, &curOffset); - } - - /* Align the total size of texture memory block. - */ - t->base.totalSize = - (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK; - - t->size = - (((tObj->Image[0][t->base.firstLevel]->Width - - 1) << R300_TX_WIDTHMASK_SHIFT) - | ((tObj->Image[0][t->base.firstLevel]->Height - 1) << - R300_TX_HEIGHTMASK_SHIFT) - | ((tObj->Image[0][t->base.firstLevel]->DepthLog2) << - R300_TX_DEPTHMASK_SHIFT)) - | ((numLevels - 1) << R300_TX_MAX_MIP_LEVEL_SHIFT); - - t->pitch = 0; - - /* Only need to round to nearest 32 for textures, but the blitter - * requires 64-byte aligned pitches, and we may/may not need the - * blitter. NPOT only! - */ - if (baseImage->IsCompressed) { - t->pitch |= - (tObj->Image[0][t->base.firstLevel]->Width + 63) & ~(63); - } else if (tObj->Target == GL_TEXTURE_RECTANGLE_NV) { - unsigned int align = (64 / texelBytes) - 1; - t->pitch |= ((tObj->Image[0][t->base.firstLevel]->Width * - texelBytes) + 63) & ~(63); + if (t->base.Target == GL_TEXTURE_RECTANGLE_NV) { + unsigned int align = (64 / t->mt->bpp) - 1; t->size |= R300_TX_SIZE_TXPITCH_EN; if (!t->image_override) - t->pitch_reg = - (((tObj->Image[0][t->base.firstLevel]->Width) + - align) & ~align) - 1; - } else { - t->pitch |= - ((tObj->Image[0][t->base.firstLevel]->Width * - texelBytes) + 63) & ~(63); + t->pitch_reg = ((firstImage->Width + align) & ~align) - 1; } if (rmesa->radeon.radeonScreen->chip_family >= CHIP_FAMILY_RV515) { - if (tObj->Image[0][t->base.firstLevel]->Width > 2048) + if (firstImage->Width > 2048) t->pitch_reg |= R500_TXWIDTH_BIT11; - if (tObj->Image[0][t->base.firstLevel]->Height > 2048) + if (firstImage->Height > 2048) t->pitch_reg |= R500_TXHEIGHT_BIT11; } } -/* ================================================================ - * Texture unit state management - */ -static GLboolean r300EnableTexture2D(GLcontext * ctx, int unit) +static void copy_rows(void* dst, GLuint dststride, const void* src, GLuint srcstride, + GLuint numrows, GLuint rowsize) { - r300ContextPtr rmesa = R300_CONTEXT(ctx); - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - struct gl_texture_object *tObj = texUnit->_Current; - r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData; + assert(rowsize <= dststride); + assert(rowsize <= srcstride); - ASSERT(tObj->Target == GL_TEXTURE_2D || tObj->Target == GL_TEXTURE_1D); - - if (t->base.dirty_images[0]) { - R300_FIREVERTICES(rmesa); - - r300SetTexImages(rmesa, tObj); - r300UploadTexImages(rmesa, (r300TexObjPtr) tObj->DriverData, 0); - if (!t->base.memBlock && !t->image_override) - return GL_FALSE; + if (rowsize == srcstride && rowsize == dststride) { + memcpy(dst, src, numrows*rowsize); + } else { + GLuint i; + for(i = 0; i < numrows; ++i) { + memcpy(dst, src, rowsize); + dst += dststride; + src += srcstride; + } } - - return GL_TRUE; } -static GLboolean r300EnableTexture3D(GLcontext * ctx, int unit) + +/** + * Ensure that the given image is stored in the given miptree from now on. + */ +static void migrate_image_to_miptree(r300_mipmap_tree *mt, r300_texture_image *image, int face, int level) { - r300ContextPtr rmesa = R300_CONTEXT(ctx); - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - struct gl_texture_object *tObj = texUnit->_Current; - r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData; + r300_mipmap_level *dstlvl = &mt->levels[level - mt->firstLevel]; + unsigned char *dest; - ASSERT(tObj->Target == GL_TEXTURE_3D); + assert(image->mt != mt); + assert(dstlvl->width == image->base.Width); + assert(dstlvl->height == image->base.Height); + assert(dstlvl->depth == image->base.Depth); - /* r300 does not support mipmaps for 3D textures. */ - if ((tObj->MinFilter != GL_NEAREST) && (tObj->MinFilter != GL_LINEAR)) { - return GL_FALSE; - } + radeon_bo_map(mt->bo, GL_TRUE); + dest = mt->bo->ptr + dstlvl->faces[face].offset; - if (t->base.dirty_images[0]) { - R300_FIREVERTICES(rmesa); - r300SetTexImages(rmesa, tObj); - r300UploadTexImages(rmesa, (r300TexObjPtr) tObj->DriverData, 0); - if (!t->base.memBlock) - return GL_FALSE; - } + if (image->mt) { + /* Format etc. should match, so we really just need a memcpy(). + * In fact, that memcpy() could be done by the hardware in many + * cases, provided that we have a proper memory manager. + */ + r300_mipmap_level *srclvl = &image->mt->levels[image->mtlevel]; - return GL_TRUE; -} + assert(srclvl->size == dstlvl->size); + assert(srclvl->rowstride == dstlvl->rowstride); -static GLboolean r300EnableTextureCube(GLcontext * ctx, int unit) -{ - r300ContextPtr rmesa = R300_CONTEXT(ctx); - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - struct gl_texture_object *tObj = texUnit->_Current; - r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData; - GLuint face; - - ASSERT(tObj->Target == GL_TEXTURE_CUBE_MAP); - - if (t->base.dirty_images[0] || t->base.dirty_images[1] || - t->base.dirty_images[2] || t->base.dirty_images[3] || - t->base.dirty_images[4] || t->base.dirty_images[5]) { - /* flush */ - R300_FIREVERTICES(rmesa); - /* layout memory space, once for all faces */ - r300SetTexImages(rmesa, tObj); - } + radeon_bo_map(image->mt->bo, GL_FALSE); + memcpy(dest, + image->mt->bo->ptr + srclvl->faces[face].offset, + dstlvl->size); + radeon_bo_unmap(image->mt->bo); - /* upload (per face) */ - for (face = 0; face < 6; face++) { - if (t->base.dirty_images[face]) { - r300UploadTexImages(rmesa, - (r300TexObjPtr) tObj->DriverData, - face); - } - } + r300_miptree_unreference(image->mt); + } else { + uint srcrowstride = image->base.Width * image->base.TexFormat->TexelBytes; - if (!t->base.memBlock) { - /* texmem alloc failed, use s/w fallback */ - return GL_FALSE; + if (mt->tilebits) + WARN_ONCE("%s: tiling not supported yet", __FUNCTION__); + + copy_rows(dest, dstlvl->rowstride, image->base.Data, srcrowstride, + image->base.Height * image->base.Depth, srcrowstride); + + _mesa_free_texmemory(image->base.Data); + image->base.Data = 0; } - return GL_TRUE; + radeon_bo_unmap(mt->bo); + + image->mt = mt; + image->mtface = face; + image->mtlevel = level; + r300_miptree_reference(image->mt); } -static GLboolean r300EnableTextureRect(GLcontext * ctx, int unit) + +/** + * Ensure the given texture is ready for rendering. + * + * Mostly this means populating the texture object's mipmap tree. + */ +static GLboolean r300_validate_texture(GLcontext * ctx, struct gl_texture_object *texObj) { r300ContextPtr rmesa = R300_CONTEXT(ctx); - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - struct gl_texture_object *tObj = texUnit->_Current; - r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData; + r300TexObj *t = r300_tex_obj(texObj); + r300_texture_image *baseimage = get_r300_texture_image(texObj->Image[0][texObj->BaseLevel]); + int face, level; + + if (t->validated) + return GL_TRUE; - ASSERT(tObj->Target == GL_TEXTURE_RECTANGLE_NV); + if (RADEON_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "%s: Validating texture %p now\n", __FUNCTION__, texObj); - if (t->base.dirty_images[0]) { - R300_FIREVERTICES(rmesa); + if (baseimage->base.Border > 0) + return GL_FALSE; - r300SetTexImages(rmesa, tObj); - r300UploadTexImages(rmesa, (r300TexObjPtr) tObj->DriverData, 0); - if (!t->base.memBlock && !t->image_override && - !rmesa->prefer_gart_client_texturing) + /* Ensure a matching miptree exists. + * + * Differing mipmap trees can result when the app uses TexImage to + * change texture dimensions. + * + * Prefer to use base image's miptree if it + * exists, since that most likely contains more valid data (remember + * that the base level is usually significantly larger than the rest + * of the miptree, so cubemaps are the only possible exception). + */ + if (baseimage->mt && + baseimage->mt != t->mt && + r300_miptree_matches_texture(baseimage->mt, &t->base)) { + r300_miptree_unreference(t->mt); + t->mt = baseimage->mt; + r300_miptree_reference(t->mt); + } else if (t->mt && !r300_miptree_matches_texture(t->mt, &t->base)) { + r300_miptree_unreference(t->mt); + t->mt = 0; + } + + if (!t->mt) { + if (RADEON_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, " Allocate new miptree\n"); + r300_try_alloc_miptree(rmesa, t, &baseimage->base, 0, texObj->BaseLevel); + if (!t->mt) { + _mesa_problem(ctx, "r300_validate_texture failed to alloc miptree"); return GL_FALSE; + } + } + + /* Ensure all images are stored in the single main miptree */ + for(face = 0; face < t->mt->faces; ++face) { + for(level = t->mt->firstLevel; level <= t->mt->lastLevel; ++level) { + r300_texture_image *image = get_r300_texture_image(texObj->Image[face][level]); + if (RADEON_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, " face %i, level %i... ", face, level); + if (t->mt == image->mt) { + if (RADEON_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "OK\n"); + continue; + } + + if (RADEON_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "migrating\n"); + migrate_image_to_miptree(t->mt, image, face, level); + } } + /* Configure the hardware registers (more precisely, the cached version + * of the hardware registers). */ + setup_hardware_state(rmesa, t); + + t->validated = GL_TRUE; return GL_TRUE; } -static GLboolean r300UpdateTexture(GLcontext * ctx, int unit) + +/** + * Ensure all enabled and complete textures are uploaded. + */ +void r300ValidateTextures(GLcontext * ctx) { - r300ContextPtr rmesa = R300_CONTEXT(ctx); - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - struct gl_texture_object *tObj = texUnit->_Current; - r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData; + int i; - /* Fallback if there's a texture border */ - if (tObj->Image[0][tObj->BaseLevel]->Border > 0) - return GL_FALSE; + for (i = 0; i < ctx->Const.MaxTextureImageUnits; ++i) { + if (!ctx->Texture.Unit[i]._ReallyEnabled) + continue; - /* Update state if this is a different texture object to last - * time. - */ - if (rmesa->state.texture.unit[unit].texobj != t) { - if (rmesa->state.texture.unit[unit].texobj != NULL) { - /* The old texture is no longer bound to this texture unit. - * Mark it as such. - */ - - rmesa->state.texture.unit[unit].texobj->base.bound &= - ~(1 << unit); + if (!r300_validate_texture(ctx, ctx->Texture.Unit[i]._Current)) { + _mesa_warning(ctx, + "failed to validate texture for unit %d.\n", + i); } - - rmesa->state.texture.unit[unit].texobj = t; - t->base.bound |= (1 << unit); - driUpdateTextureLRU((driTextureObject *) t); /* XXX: should be locked! */ } - - return !t->border_fallback; } void r300SetTexOffset(__DRIcontext * pDRICtx, GLint texname, @@ -591,20 +420,18 @@ void r300SetTexOffset(__DRIcontext * pDRICtx, GLint texname, r300ContextPtr rmesa = pDRICtx->driverPrivate; struct gl_texture_object *tObj = _mesa_lookup_texture(rmesa->radeon.glCtx, texname); - r300TexObjPtr t; + r300TexObjPtr t = r300_tex_obj(tObj); uint32_t pitch_val; if (!tObj) return; - t = (r300TexObjPtr) tObj->DriverData; - t->image_override = GL_TRUE; if (!offset) return; - t->offset = offset; + t->override_offset = offset; t->pitch_reg &= (1 << 13) -1; pitch_val = pitch; @@ -630,39 +457,3 @@ void r300SetTexOffset(__DRIcontext * pDRICtx, GLint texname, t->pitch_reg |= pitch_val; } - -static GLboolean r300UpdateTextureUnit(GLcontext * ctx, int unit) -{ - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - - if (texUnit->_ReallyEnabled & (TEXTURE_RECT_BIT)) { - return (r300EnableTextureRect(ctx, unit) && - r300UpdateTexture(ctx, unit)); - } else if (texUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT)) { - return (r300EnableTexture2D(ctx, unit) && - r300UpdateTexture(ctx, unit)); - } else if (texUnit->_ReallyEnabled & (TEXTURE_3D_BIT)) { - return (r300EnableTexture3D(ctx, unit) && - r300UpdateTexture(ctx, unit)); - } else if (texUnit->_ReallyEnabled & (TEXTURE_CUBE_BIT)) { - return (r300EnableTextureCube(ctx, unit) && - r300UpdateTexture(ctx, unit)); - } else if (texUnit->_ReallyEnabled) { - return GL_FALSE; - } else { - return GL_TRUE; - } -} - -void r300UpdateTextureState(GLcontext * ctx) -{ - int i; - - for (i = 0; i < 8; i++) { - if (!r300UpdateTextureUnit(ctx, i)) { - _mesa_warning(ctx, - "failed to update texture state for unit %d.\n", - i); - } - } -} |