r300: Improve texture layout calculations
authorNicolai Haehnle <nhaehnle@gmail.com>
Fri, 6 Jun 2008 21:47:46 +0000 (23:47 +0200)
committerNicolai Haehnle <nhaehnle@gmail.com>
Fri, 6 Jun 2008 21:47:46 +0000 (23:47 +0200)
The texture layout calculations for mipmapped cubemaps used to be completely
wrong, since the GPU expects images to be grouped by miplevel instead of by
face number.

This has been fixed now, though the memory layout is still slightly incorrect
for the smaller miplevels. Unfortunately, the docs are lacking in that area.

src/mesa/drivers/dri/r300/r300_texmem.c
src/mesa/drivers/dri/r300/r300_texstate.c

index e0fda86ac8b70089625215a010a6128eb7b8a9ce..69847a4022d02097de0045cec3120cd60b871716 100644 (file)
@@ -349,7 +349,7 @@ static void r300UploadSubImage(r300ContextPtr rmesa, r300TexObjPtr t,
        imageWidth = texImage->Width;
        imageHeight = texImage->Height;
 
-       offset = t->bufAddr + t->base.totalSize / 6 * face;
+       offset = t->bufAddr;
 
        if (RADEON_DEBUG & (DEBUG_TEXTURE | DEBUG_IOCTL)) {
                GLint imageX = 0;
index 131d9580050cb8645441729f95ba368275f5026a..2589ec572ec95d6490985929b29ec11816e7397f 100644 (file)
@@ -189,6 +189,112 @@ 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).
@@ -206,7 +312,7 @@ static void r300SetTexImages(r300ContextPtr rmesa,
        r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData;
        const struct gl_texture_image *baseImage =
            tObj->Image[0][tObj->BaseLevel];
-       GLint curOffset, blitWidth;
+       GLint curOffset;
        GLint i, texelBytes;
        GLint numLevels;
        GLint log2Width, log2Height, log2Depth;
@@ -245,8 +351,6 @@ static void r300SetTexImages(r300ContextPtr rmesa,
         * The idea is that we lay out the mipmap levels within a block of
         * memory organized as a rectangle of width BLIT_WIDTH_BYTES.
         */
-       curOffset = 0;
-       blitWidth = R300_BLIT_WIDTH_BYTES;
        t->tile_bits = 0;
 
        /* figure out if this texture is suitable for tiling. */
@@ -276,94 +380,20 @@ static void r300SetTexImages(r300ContextPtr rmesa,
        }
 #endif
 
-       for (i = 0; i < numLevels; i++) {
-               const struct gl_texture_image *texImage;
-               GLuint size;
-
-               texImage = tObj->Image[0][i + t->base.firstLevel];
-               if (!texImage)
-                       break;
-
-               /* 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);
-
-               /* Align to 32-byte offset.  It is faster to do this unconditionally
-                * (no branch penalty).
-                */
+       curOffset = 0;
 
-               curOffset = (curOffset + 0x1f) & ~0x1f;
+       if (tObj->Target == GL_TEXTURE_CUBE_MAP) {
+               ASSERT(log2Width == log2Height);
+               t->format |= R300_TX_FORMAT_CUBIC_MAP;
 
-               if (texelBytes) {
-                       /* fix x and y coords up later together with offset */
-                       t->image[0][i].x = curOffset;
-                       t->image[0][i].y = 0;
-                       t->image[0][i].width =
-                           MIN2(size / texelBytes, blitWidth);
-                       t->image[0][i].height =
-                           (size / texelBytes) / t->image[0][i].width;
-               } else {
-                       t->image[0][i].x = curOffset % R300_BLIT_WIDTH_BYTES;
-                       t->image[0][i].y = curOffset / R300_BLIT_WIDTH_BYTES;
-                       t->image[0][i].width =
-                           MIN2(size, R300_BLIT_WIDTH_BYTES);
-                       t->image[0][i].height = size / t->image[0][i].width;
+               for(i = 0; i < numLevels; i++) {
+                       GLuint face;
+                       for(face = 0; face < 6; face++)
+                               compute_tex_image_offset(tObj, face, i, &curOffset);
                }
-
-               if (RADEON_DEBUG & DEBUG_TEXTURE)
-                       fprintf(stderr,
-                               "level %d: %dx%d x=%d y=%d w=%d h=%d size=%d at %d\n",
-                               i, texImage->Width, texImage->Height,
-                               t->image[0][i].x, t->image[0][i].y,
-                               t->image[0][i].width, t->image[0][i].height,
-                               size, curOffset);
-
-               curOffset += size;
+       } else {
+               for (i = 0; i < numLevels; i++)
+                       compute_tex_image_offset(tObj, 0, i, &curOffset);
        }
 
        /* Align the total size of texture memory block.
@@ -371,26 +401,6 @@ static void r300SetTexImages(r300ContextPtr rmesa,
        t->base.totalSize =
            (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK;
 
-       /* Setup remaining cube face blits, if needed */
-       if (tObj->Target == GL_TEXTURE_CUBE_MAP) {
-               GLuint face;
-               for (face = 1; face < 6; face++) {
-                       for (i = 0; i < numLevels; i++) {
-                               t->image[face][i].x = t->image[0][i].x;
-                               t->image[face][i].y = t->image[0][i].y;
-                               t->image[face][i].width = t->image[0][i].width;
-                               t->image[face][i].height =
-                                   t->image[0][i].height;
-                       }
-               }
-               t->base.totalSize *= 6; /* total texmem needed */
-       }
-
-       if (tObj->Target == GL_TEXTURE_CUBE_MAP) {
-               ASSERT(log2Width == log2Height);
-               t->format |= R300_TX_FORMAT_CUBIC_MAP;
-       }
-
        t->size =
            (((tObj->Image[0][t->base.firstLevel]->Width -
               1) << R300_TX_WIDTHMASK_SHIFT)
@@ -408,7 +418,7 @@ static void r300SetTexImages(r300ContextPtr rmesa,
                t->pitch |=
                    (tObj->Image[0][t->base.firstLevel]->Width + 63) & ~(63);
        } else if (tObj->Target == GL_TEXTURE_RECTANGLE_NV) {
-               unsigned int align = blitWidth - 1;
+               unsigned int align = (64 / texelBytes) - 1;
                t->pitch |= ((tObj->Image[0][t->base.firstLevel]->Width *
                             texelBytes) + 63) & ~(63);
                t->size |= R300_TX_SIZE_TXPITCH_EN;