mesa/drivers: use _mesa_get_format_bytes()
[mesa.git] / src / mesa / drivers / dri / radeon / radeon_mipmap_tree.c
index 955d4b71ed515fee333e8cd4b22faf3058308978..11c21037c4494ea7db70705da972004946bc5f45 100644 (file)
@@ -34,8 +34,6 @@
 #include "main/texcompress.h"
 #include "main/texformat.h"
 
-#include "radeon_buffer.h"
-
 static GLuint radeon_compressed_texture_size(GLcontext *ctx,
                GLsizei width, GLsizei height, GLsizei depth,
                GLuint mesaFormat)
@@ -58,6 +56,29 @@ static GLuint radeon_compressed_texture_size(GLcontext *ctx,
        return size;
 }
 
+
+static int radeon_compressed_num_bytes(GLuint mesaFormat)
+{
+   int bytes = 0;
+   switch(mesaFormat) {
+     
+   case MESA_FORMAT_RGB_FXT1:
+   case MESA_FORMAT_RGBA_FXT1:
+   case MESA_FORMAT_RGB_DXT1:
+   case MESA_FORMAT_RGBA_DXT1:
+     bytes = 2;
+     break;
+     
+   case MESA_FORMAT_RGBA_DXT3:
+   case MESA_FORMAT_RGBA_DXT5:
+     bytes = 4;
+   default:
+     break;
+   }
+   
+   return bytes;
+}
+
 /**
  * Compute sizes and fill in offset and blit information for the given
  * image (determined by \p face and \p level).
@@ -65,34 +86,32 @@ static GLuint radeon_compressed_texture_size(GLcontext *ctx,
  * \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(radeon_mipmap_tree *mt,
+static void compute_tex_image_offset(radeonContextPtr rmesa, radeon_mipmap_tree *mt,
        GLuint face, GLuint level, GLuint* curOffset)
 {
        radeon_mipmap_level *lvl = &mt->levels[level];
+       uint32_t row_align;
 
        /* Find image size in bytes */
        if (mt->compressed) {
                /* TODO: Is this correct? Need test cases for compressed textures! */
-               GLuint align;
-
-               if (mt->target == GL_TEXTURE_RECTANGLE_NV)
-                       align = 64 / mt->bpp;
-               else
-                       align = 32 / mt->bpp;
-               lvl->rowstride = (lvl->width + align - 1) & ~(align - 1);
+               row_align = rmesa->texture_compressed_row_align - 1;
+               lvl->rowstride = (lvl->width * mt->bpp + row_align) & ~row_align;
                lvl->size = radeon_compressed_texture_size(mt->radeon->glCtx,
-                       lvl->width, lvl->height, lvl->depth, mt->compressed);
+                                                          lvl->width, lvl->height, lvl->depth, mt->compressed);
        } else if (mt->target == GL_TEXTURE_RECTANGLE_NV) {
-               lvl->rowstride = (lvl->width * mt->bpp + 63) & ~63;
+               row_align = rmesa->texture_rect_row_align - 1;
+               lvl->rowstride = (lvl->width * mt->bpp + row_align) & ~row_align;
                lvl->size = lvl->rowstride * lvl->height;
        } else if (mt->tilebits & RADEON_TXO_MICRO_TILE) {
-         /* tile pattern is 16 bytes x2. mipmaps stay 32 byte aligned,
+               /* 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 */
                lvl->rowstride = (lvl->width * mt->bpp * 2 + 31) & ~31;
                lvl->size = lvl->rowstride * ((lvl->height + 1) / 2) * lvl->depth;
        } else {
-               lvl->rowstride = (lvl->width * mt->bpp + 31) & ~31;
+               row_align = rmesa->texture_row_align - 1;
+               lvl->rowstride = (lvl->width * mt->bpp + row_align) & ~row_align;
                lvl->size = lvl->rowstride * lvl->height * lvl->depth;
        }
        assert(lvl->size > 0);
@@ -101,6 +120,11 @@ static void compute_tex_image_offset(radeon_mipmap_tree *mt,
        *curOffset = (*curOffset + 0x1f) & ~0x1f;
        lvl->faces[face].offset = *curOffset;
        *curOffset += lvl->size;
+
+       if (RADEON_DEBUG & RADEON_TEXTURE)
+         fprintf(stderr,
+                 "level %d, face %d: rs:%d %dx%d at %d\n",
+                 level, face, lvl->rowstride, lvl->width, lvl->height, lvl->faces[face].offset);
 }
 
 static GLuint minify(GLuint size, GLuint levels)
@@ -111,14 +135,40 @@ static GLuint minify(GLuint size, GLuint levels)
        return size;
 }
 
-static void calculate_miptree_layout(radeon_mipmap_tree *mt)
+
+static void calculate_miptree_layout_r100(radeonContextPtr rmesa, radeon_mipmap_tree *mt)
+{
+       GLuint curOffset;
+       GLuint numLevels;
+       GLuint i;
+       GLuint face;
+
+       numLevels = mt->lastLevel - mt->firstLevel + 1;
+       assert(numLevels <= rmesa->glCtx->Const.MaxTextureLevels);
+
+       curOffset = 0;
+       for(face = 0; face < mt->faces; face++) {
+
+               for(i = 0; i < 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);
+               }
+       }
+
+       /* Note the required size in memory */
+       mt->totalsize = (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK;
+}
+
+static void calculate_miptree_layout_r300(radeonContextPtr rmesa, radeon_mipmap_tree *mt)
 {
        GLuint curOffset;
        GLuint numLevels;
        GLuint i;
 
        numLevels = mt->lastLevel - mt->firstLevel + 1;
-       assert(numLevels <= RADEON_MAX_TEXTURE_LEVELS);
+       assert(numLevels <= rmesa->glCtx->Const.MaxTextureLevels);
 
        curOffset = 0;
        for(i = 0; i < numLevels; i++) {
@@ -129,25 +179,25 @@ static void calculate_miptree_layout(radeon_mipmap_tree *mt)
                mt->levels[i].depth = minify(mt->depth0, i);
 
                for(face = 0; face < mt->faces; face++)
-                       compute_tex_image_offset(mt, face, i, &curOffset);
+                       compute_tex_image_offset(rmesa, mt, face, i, &curOffset);
        }
 
        /* Note the required size in memory */
        mt->totalsize = (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK;
 }
 
-
 /**
  * Create a new mipmap tree, calculate its layout and allocate memory.
  */
 radeon_mipmap_tree* radeon_miptree_create(radeonContextPtr rmesa, radeonTexObj *t,
-               GLenum target, GLuint firstLevel, GLuint lastLevel,
+               GLenum target, GLenum internal_format, GLuint firstLevel, GLuint lastLevel,
                GLuint width0, GLuint height0, GLuint depth0,
                GLuint bpp, GLuint tilebits, GLuint compressed)
 {
        radeon_mipmap_tree *mt = CALLOC_STRUCT(_radeon_mipmap_tree);
 
        mt->radeon = rmesa;
+       mt->internal_format = internal_format;
        mt->refcount = 1;
        mt->t = t;
        mt->target = target;
@@ -157,11 +207,14 @@ radeon_mipmap_tree* radeon_miptree_create(radeonContextPtr rmesa, radeonTexObj *
        mt->width0 = width0;
        mt->height0 = height0;
        mt->depth0 = depth0;
-       mt->bpp = bpp;
+       mt->bpp = compressed ? radeon_compressed_num_bytes(compressed) : bpp;
        mt->tilebits = tilebits;
        mt->compressed = compressed;
 
-       calculate_miptree_layout(mt);
+       if (rmesa->radeonScreen->chip_family >= CHIP_FAMILY_R300)
+               calculate_miptree_layout_r300(rmesa, mt);
+       else
+               calculate_miptree_layout_r100(rmesa, mt);
 
        mt->bo = radeon_bo_open(rmesa->radeonScreen->bom,
                             0, mt->totalsize, 1024,
@@ -191,12 +244,26 @@ void radeon_miptree_unreference(radeon_mipmap_tree *mt)
 }
 
 
+/**
+ * Calculate first and last mip levels for the given texture object,
+ * where the dimensions are taken from the given texture image at
+ * the given level.
+ *
+ * Note: level is the OpenGL level number, which is not necessarily the same
+ * as the first level that is actually present.
+ *
+ * The base level image of the given texture face must be non-null,
+ * or this will fail.
+ */
 static void calculate_first_last_level(struct gl_texture_object *tObj,
-                                      GLuint *pfirstLevel, GLuint *plastLevel)
+                                      GLuint *pfirstLevel, GLuint *plastLevel,
+                                      GLuint face, GLuint level)
 {
        const struct gl_texture_image * const baseImage =
-               tObj->Image[0][tObj->BaseLevel];
+               tObj->Image[face][level];
 
+       assert(baseImage);
+       
        /* These must be signed values.  MinLod and MaxLod can be negative numbers,
        * and having firstLevel and lastLevel as signed prevents the need for
        * extra sign checks.
@@ -218,10 +285,10 @@ static void calculate_first_last_level(struct gl_texture_object *tObj,
                } else {
                        firstLevel = tObj->BaseLevel + (GLint)(tObj->MinLod + 0.5);
                        firstLevel = MAX2(firstLevel, tObj->BaseLevel);
-                       firstLevel = MIN2(firstLevel, tObj->BaseLevel + baseImage->MaxLog2);
+                       firstLevel = MIN2(firstLevel, level + baseImage->MaxLog2);
                        lastLevel = tObj->BaseLevel + (GLint)(tObj->MaxLod + 0.5);
                        lastLevel = MAX2(lastLevel, tObj->BaseLevel);
-                       lastLevel = MIN2(lastLevel, tObj->BaseLevel + baseImage->MaxLog2);
+                       lastLevel = MIN2(lastLevel, level + baseImage->MaxLog2);
                        lastLevel = MIN2(lastLevel, tObj->MaxLevel);
                        lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */
                }
@@ -252,7 +319,13 @@ GLboolean radeon_miptree_matches_image(radeon_mipmap_tree *mt,
        if (face >= mt->faces || level < mt->firstLevel || level > mt->lastLevel)
                return GL_FALSE;
 
-       if (texImage->TexFormat->TexelBytes != mt->bpp)
+       if (texImage->InternalFormat != mt->internal_format ||
+           texImage->IsCompressed != mt->compressed)
+               return GL_FALSE;
+
+       if (!texImage->IsCompressed &&
+           !mt->compressed &&
+           _mesa_get_format_bytes(texImage->TexFormat->MesaFormat) != mt->bpp)
                return GL_FALSE;
 
        lvl = &mt->levels[level - mt->firstLevel];
@@ -275,7 +348,7 @@ GLboolean radeon_miptree_matches_texture(radeon_mipmap_tree *mt, struct gl_textu
        GLuint numfaces = 1;
        GLuint firstLevel, lastLevel;
 
-       calculate_first_last_level(texObj, &firstLevel, &lastLevel);
+       calculate_first_last_level(texObj, &firstLevel, &lastLevel, 0, texObj->BaseLevel);
        if (texObj->Target == GL_TEXTURE_CUBE_MAP)
                numfaces = 6;
 
@@ -287,8 +360,8 @@ GLboolean radeon_miptree_matches_texture(radeon_mipmap_tree *mt, struct gl_textu
                mt->width0 == firstImage->Width &&
                mt->height0 == firstImage->Height &&
                mt->depth0 == firstImage->Depth &&
-               mt->bpp == firstImage->TexFormat->TexelBytes &&
-               mt->compressed == compressed);
+               mt->compressed == compressed &&
+               (!mt->compressed ? (mt->bpp == firstImage->TexFormat->TexelBytes) : 1));
 }
 
 
@@ -297,15 +370,15 @@ GLboolean radeon_miptree_matches_texture(radeon_mipmap_tree *mt, struct gl_textu
  * given image in the given position.
  */
 void radeon_try_alloc_miptree(radeonContextPtr rmesa, radeonTexObj *t,
-               struct gl_texture_image *texImage, GLuint face, GLuint level)
+               radeon_texture_image *image, GLuint face, GLuint level)
 {
-       GLuint compressed = texImage->IsCompressed ? texImage->TexFormat->MesaFormat : 0;
+       GLuint compressed = image->base.IsCompressed ? image->base.TexFormat->MesaFormat : 0;
        GLuint numfaces = 1;
        GLuint firstLevel, lastLevel;
 
        assert(!t->mt);
 
-       calculate_first_last_level(&t->base, &firstLevel, &lastLevel);
+       calculate_first_last_level(&t->base, &firstLevel, &lastLevel, face, level);
        if (t->base.Target == GL_TEXTURE_CUBE_MAP)
                numfaces = 6;
 
@@ -313,7 +386,36 @@ void radeon_try_alloc_miptree(radeonContextPtr rmesa, radeonTexObj *t,
                return;
 
        t->mt = radeon_miptree_create(rmesa, t, t->base.Target,
+               image->base.InternalFormat,
                firstLevel, lastLevel,
-               texImage->Width, texImage->Height, texImage->Depth,
-               texImage->TexFormat->TexelBytes, t->tile_bits, compressed);
+               image->base.Width, image->base.Height, image->base.Depth,
+               image->base.TexFormat->TexelBytes, t->tile_bits, compressed);
+}
+
+/* Although we use the image_offset[] array to store relative offsets
+ * to cube faces, Mesa doesn't know anything about this and expects
+ * each cube face to be treated as a separate image.
+ *
+ * These functions present that view to mesa:
+ */
+void
+radeon_miptree_depth_offsets(radeon_mipmap_tree *mt, GLuint level, GLuint *offsets)
+{
+     if (mt->target != GL_TEXTURE_3D || mt->faces == 1)
+        offsets[0] = 0;
+     else {
+       int i;
+       for (i = 0; i < 6; i++)
+               offsets[i] = mt->levels[level].faces[i].offset;
+     }
+}
+
+GLuint
+radeon_miptree_image_offset(radeon_mipmap_tree *mt,
+                           GLuint face, GLuint level)
+{
+   if (mt->target == GL_TEXTURE_CUBE_MAP_ARB)
+      return (mt->levels[level].faces[face].offset);
+   else
+      return mt->levels[level].faces[0].offset;
 }