radeon: update miptree code a little
authorMaciej Cencora <m.cencora@gmail.com>
Sun, 29 Nov 2009 14:40:13 +0000 (15:40 +0100)
committerMaciej Cencora <m.cencora@gmail.com>
Sun, 29 Nov 2009 16:27:48 +0000 (17:27 +0100)
Simplify gl image level <-> miptree level mapping (are equal now).
Don't allocate miptree for images that won't fit in it (fixes #25230).

src/mesa/drivers/dri/radeon/radeon_mipmap_tree.c
src/mesa/drivers/dri/radeon/radeon_mipmap_tree.h
src/mesa/drivers/dri/radeon/radeon_texture.c

index 39b6d50094e7fa26960107ef355fb891a9f8e6a3..a9d601a0b5f14812b73b634ca528d6fb5e7b372b 100644 (file)
@@ -124,20 +124,19 @@ static GLuint minify(GLuint size, GLuint levels)
 
 static void calculate_miptree_layout_r100(radeonContextPtr rmesa, radeon_mipmap_tree *mt)
 {
-       GLuint curOffset;
-       GLuint i;
-       GLuint face;
+       GLuint curOffset, i, face, level;
 
        assert(mt->numLevels <= rmesa->glCtx->Const.MaxTextureLevels);
 
        curOffset = 0;
        for(face = 0; face < mt->faces; face++) {
 
-               for(i = 0; i < mt->numLevels; i++) {
-                       mt->levels[i].width = minify(mt->width0, i);
-                       mt->levels[i].height = minify(mt->height0, i);
-                       mt->levels[i].depth = minify(mt->depth0, i);
-                       compute_tex_image_offset(rmesa, mt, face, i, &curOffset);
+               for(i = 0, level = mt->baseLevel; i < mt->numLevels; i++, level++) {
+                       mt->levels[level].valid = 1;
+                       mt->levels[level].width = minify(mt->width0, i);
+                       mt->levels[level].height = minify(mt->height0, i);
+                       mt->levels[level].depth = minify(mt->depth0, i);
+                       compute_tex_image_offset(rmesa, mt, face, level, &curOffset);
                }
        }
 
@@ -147,21 +146,21 @@ static void calculate_miptree_layout_r100(radeonContextPtr rmesa, radeon_mipmap_
 
 static void calculate_miptree_layout_r300(radeonContextPtr rmesa, radeon_mipmap_tree *mt)
 {
-       GLuint curOffset;
-       GLuint i;
+       GLuint curOffset, i, level;
 
        assert(mt->numLevels <= rmesa->glCtx->Const.MaxTextureLevels);
 
        curOffset = 0;
-       for(i = 0; i < mt->numLevels; i++) {
+       for(i = 0, level = mt->baseLevel; i < mt->numLevels; i++, level++) {
                GLuint face;
 
-               mt->levels[i].width = minify(mt->width0, i);
-               mt->levels[i].height = minify(mt->height0, i);
-               mt->levels[i].depth = minify(mt->depth0, i);
+               mt->levels[level].valid = 1;
+               mt->levels[level].width = minify(mt->width0, i);
+               mt->levels[level].height = minify(mt->height0, i);
+               mt->levels[level].depth = minify(mt->depth0, i);
 
                for(face = 0; face < mt->faces; face++)
-                       compute_tex_image_offset(rmesa, mt, face, i, &curOffset);
+                       compute_tex_image_offset(rmesa, mt, face, level, &curOffset);
        }
 
        /* Note the required size in memory */
@@ -277,18 +276,19 @@ static void calculate_min_max_lod(struct gl_texture_object *tObj,
  * given face and level.
  */
 GLboolean radeon_miptree_matches_image(radeon_mipmap_tree *mt,
-               struct gl_texture_image *texImage, GLuint face, GLuint mtLevel)
+               struct gl_texture_image *texImage, GLuint face, GLuint level)
 {
        radeon_mipmap_level *lvl;
 
-       if (face >= mt->faces || mtLevel > mt->numLevels)
+       if (face >= mt->faces)
                return GL_FALSE;
 
        if (texImage->TexFormat != mt->mesaFormat)
                return GL_FALSE;
 
-       lvl = &mt->levels[mtLevel];
-       if (lvl->width != texImage->Width ||
+       lvl = &mt->levels[level];
+       if (!lvl->valid ||
+           lvl->width != texImage->Width ||
            lvl->height != texImage->Height ||
            lvl->depth != texImage->Depth)
                return GL_FALSE;
@@ -393,39 +393,18 @@ radeon_miptree_image_offset(radeon_mipmap_tree *mt,
                return mt->levels[level].faces[0].offset;
 }
 
-/**
- * Convert radeon miptree texture level to GL texture level
- * @param[in] tObj texture object whom level is to be converted
- * @param[in] level radeon miptree texture level
- * @return GL texture level
- */
-unsigned radeon_miptree_level_to_gl_level(struct gl_texture_object *tObj, unsigned level)
-{
-       return level + tObj->BaseLevel;
-}
-
-/**
- * Convert GL texture level to radeon miptree texture level
- * @param[in] tObj texture object whom level is to be converted
- * @param[in] level GL texture level
- * @return radeon miptree texture level
- */
-unsigned radeon_gl_level_to_miptree_level(struct gl_texture_object *tObj, unsigned level)
-{
-       return level - tObj->BaseLevel;
-}
-
 /**
  * Ensure that the given image is stored in the given miptree from now on.
  */
 static void migrate_image_to_miptree(radeon_mipmap_tree *mt,
                                                                         radeon_texture_image *image,
-                                                                        int face, int mtLevel)
+                                                                        int face, int level)
 {
-       radeon_mipmap_level *dstlvl = &mt->levels[mtLevel];
+       radeon_mipmap_level *dstlvl = &mt->levels[level];
        unsigned char *dest;
 
        assert(image->mt != mt);
+       assert(dstlvl->valid);
        assert(dstlvl->width == image->base.Width);
        assert(dstlvl->height == image->base.Height);
        assert(dstlvl->depth == image->base.Depth);
@@ -442,6 +421,7 @@ static void migrate_image_to_miptree(radeon_mipmap_tree *mt,
 
                radeon_mipmap_level *srclvl = &image->mt->levels[image->mtlevel];
 
+               assert(image->mtlevel == level);
                assert(srclvl->size == dstlvl->size);
                assert(srclvl->rowstride == dstlvl->rowstride);
 
@@ -479,7 +459,7 @@ static void migrate_image_to_miptree(radeon_mipmap_tree *mt,
 
        radeon_miptree_reference(mt, &image->mt);
        image->mtface = face;
-       image->mtlevel = mtLevel;
+       image->mtlevel = level;
 }
 
 /**
@@ -603,7 +583,7 @@ int radeon_validate_texture_miptree(GLcontext * ctx, struct gl_texture_object *t
                                if (src_bo && radeon_bo_is_referenced_by_cs(src_bo, rmesa->cmdbuf.cs)) {
                                        radeon_firevertices(rmesa);
                                }
-                               migrate_image_to_miptree(dst_miptree, img, face, radeon_gl_level_to_miptree_level(texObj, level));
+                               migrate_image_to_miptree(dst_miptree, img, face, level);
                        } else if (RADEON_DEBUG & RADEON_TEXTURE) {
                                fprintf(stderr, "OK\n");
                        }
index 28b848509547107d8f0975554f142da5ebe731c0..a10649b5aeac8ee961d48b04c39f84bb62a44417 100644 (file)
@@ -44,6 +44,7 @@ struct _radeon_mipmap_level {
        GLuint depth;
        GLuint size; /** Size of each image, in bytes */
        GLuint rowstride; /** in bytes */
+       GLuint valid;
        radeon_mipmap_image faces[6];
 };
 
@@ -70,9 +71,9 @@ struct _radeon_mipmap_tree {
        GLuint baseLevel; /** gl_texture_object->baseLevel it was created for */
        GLuint numLevels; /** Number of mip levels stored in this mipmap tree */
 
-       GLuint width0; /** Width of firstLevel image */
-       GLuint height0; /** Height of firstLevel image */
-       GLuint depth0; /** Depth of firstLevel image */
+       GLuint width0; /** Width of baseLevel image */
+       GLuint height0; /** Height of baseLevel image */
+       GLuint depth0; /** Depth of baseLevel image */
 
        GLuint tilebits; /** RADEON_TXO_xxx_TILE */
 
@@ -89,8 +90,5 @@ GLuint radeon_miptree_image_offset(radeon_mipmap_tree *mt,
                                   GLuint face, GLuint level);
 void radeon_miptree_depth_offsets(radeon_mipmap_tree *mt, GLuint level, GLuint *offsets);
 
-unsigned radeon_miptree_level_to_gl_level(struct gl_texture_object *tObj, unsigned level);
-unsigned radeon_gl_level_to_miptree_level(struct gl_texture_object *tObj, unsigned level);
-
 uint32_t get_base_teximage_offset(radeonTexObj *texObj);
 #endif /* __RADEON_MIPMAP_TREE_H_ */
index c715650d55f6e4cad1cd352100d6968b31a5d23e..0390d376ba231b2cc22229da846510b3219d7e32 100644 (file)
@@ -509,6 +509,27 @@ gl_format radeonChooseTextureFormat(GLcontext * ctx,
        return MESA_FORMAT_NONE;                /* never get here */
 }
 
+/** Check if given image is valid within current texture object.
+ */
+static int image_matches_texture_obj(struct gl_texture_object *texObj,
+       struct gl_texture_image *texImage,
+       unsigned level)
+{
+       const struct gl_texture_image *baseImage = texObj->Image[0][level];
+
+       if (level < texObj->BaseLevel || level > texObj->MaxLevel)
+               return 0;
+
+       const unsigned levelDiff = level - texObj->BaseLevel;
+       const unsigned refWidth = baseImage->Width >> levelDiff;
+       const unsigned refHeight = baseImage->Height >> levelDiff;
+       const unsigned refDepth = baseImage->Depth >> levelDiff;
+
+       return (texImage->Width == refWidth &&
+                       texImage->Height == refHeight &&
+                       texImage->Depth == refDepth);
+}
+
 static void teximage_assign_miptree(radeonContextPtr rmesa,
        struct gl_texture_object *texObj,
        struct gl_texture_image *texImage,
@@ -518,9 +539,14 @@ static void teximage_assign_miptree(radeonContextPtr rmesa,
        radeonTexObj *t = radeon_tex_obj(texObj);
        radeon_texture_image* image = get_radeon_texture_image(texImage);
 
+       /* Since miptree holds only images for levels <BaseLevel..MaxLevel>
+        * don't allocate the miptree if the teximage won't fit.
+        */
+       if (!image_matches_texture_obj(texObj, texImage, level))
+               return;
+
        /* Try using current miptree, or create new if there isn't any */
-       if (!t->mt || !radeon_miptree_matches_image(t->mt, texImage, face,
-                                       radeon_gl_level_to_miptree_level(texObj, level))) {
+       if (!t->mt || !radeon_miptree_matches_image(t->mt, texImage, face, level)) {
                radeon_miptree_unreference(&t->mt);
                radeon_try_alloc_miptree(rmesa, t);
                if (RADEON_DEBUG & RADEON_TEXTURE) {
@@ -534,7 +560,7 @@ static void teximage_assign_miptree(radeonContextPtr rmesa,
         * when there was no image for baselevel specified */
        if (t->mt) {
                image->mtface = face;
-               image->mtlevel = radeon_gl_level_to_miptree_level(texObj, level);
+               image->mtlevel = level;
                radeon_miptree_reference(t->mt, &image->mt);
        }
 }
@@ -590,6 +616,8 @@ static void radeon_store_teximage(GLcontext* ctx, int dims,
                dstRowStride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
        }
 
+       assert(dstRowStride);
+
        if (dims == 3) {
                unsigned alignedWidth = dstRowStride/_mesa_get_format_bytes(texImage->TexFormat);
                dstImageOffsets = allocate_image_offsets(ctx, alignedWidth, texImage->Height, texImage->Depth);
@@ -704,7 +732,7 @@ static void radeon_teximage(
 
        if (!t->bo) {
                teximage_assign_miptree(rmesa, texObj, texImage, face, level);
-               if (!t->mt) {
+               if (!image->mt) {
                        int size = _mesa_format_image_size(texImage->TexFormat,
                                                                texImage->Width,
                                                                texImage->Height,