Bug 362

Summary: calculated dimensions for MipMaps smaller than 16x16
Product: [JogAmp] Jogl Reporter: Sven Gothel <sgothel>
Component: utilAssignee: Sven Gothel <sgothel>
Status: RESOLVED FIXED    
Severity: normal CC: michael.esemplare
Priority: P3    
Version: 1   
Hardware: All   
OS: all   
Type: DEFECT SCM Refs:
82d7bae212ad5a540a29003aaec8c7e026615f68 82927b0e75a2a93f3728d158295a6ae25dddeecf
Workaround: ---

Description Sven Gothel 2010-03-24 07:51:34 CET


---- Reported by dahie 2008-09-06 10:10:55 ----

Hello everybody!

I've been working on some DirectDraw-Surface tools. For now, mostly simple 
stuff like texture loading, preview and MipMap generating, resaving. I used the 
DDSImage-class from JOGL as base for the File-Handling and using JSquish for 
DXT-(De)Compression. 

When I implemented automatic generated MipMaps I stumbled upon a possible bug 
in the DDSImage class. I hope this is the right place to address this, the 
bugtracker seemed kinda dead.

Here is my scenario: 
I generate an array of ByteBuffers, which contain the pixel data. Each 
ByteBuffer is then compressed using a DXTn-method. This data-array is then 
given to the DDSImage class to create a new DDSImage-Object, which then can be 
written to disc.

Code:
DDSImage.createFromData(pixelformat, width, height, mipmapBufferArray);

This gave me an IllegalArgumentException in the initFromData()-method saying, 
that the remaining data size for the lowest mipmaps exceeded the expected size. 
In fact the compressed buffer could never be smaller than 16kbyte (8kbyte DXT1).

I did some research and found, that DXT-compressors always use the usual 8x8 
pixel block for compression, even if the actual texture is smaller. So the 
resulting compressed block is always of this size.
This is even hinted at the official DDS-Specification at MSDN

So now what is the problem. The current implementation of the expected mipmap 
data size:


Code:
// Now check the mipmaps against this size
int curSize = topmostMipmapSize;
int totalSize = 0;
for (int i = 0; i < mipmapData.length; i++) {
  if (mipmapData[i].remaining() != curSize) {
    throw new IllegalArgumentException("Mipmap level " + i +
                                       " didn't match expected data size 
(expected " + curSize + ", got " +
                                       mipmapData[i].remaining() + ")");
  }
  curSize /= 4;
  totalSize += mipmapData[i].remaining();
}

This always expects the datasize is 1/4 the size of the mipmap before. Works as 
far as MipMaps are bigger or equal 8x8 pixels. In that case it throughs my 
mentioned exception, as it expects the size to be smaller than it actually is.

I did some patch job to fix this.

Code:
// Now check the mipmaps against this size
int curSize = topmostMipmapSize;
int mipmapWidth = width;
int mipmapHeight = height;
int totalSize = 0;
for (int i = 0; i < mipmapData.length; i++) {
  if (mipmapData[i].remaining() != curSize) {
    throw new IllegalArgumentException("Mipmap level " + i +
                                       " didn't match expected data size 
(expected " + curSize + ", got " +
                                       mipmapData[i].remaining() + ")");
  }
  /* Change
   * I got the problem, that MipMaps below the dimension of 8x8 blocks with 
DXTn 
   * where assume smaller than they are created. 
   * Assumed: smaller than 16byte where 16byte where used by the compression. */
  if(isCompressed) {
	  // size calculation for compressed mipmaps 
	  if(mipmapWidth > 1) mipmapWidth /= 2;
    	  if(mipmapHeight > 1) mipmapHeight /= 2;
	  curSize = computeCompressedBlockSize(mipmapWidth, mipmapHeight, 1, 
d3dFormat);
  } else {
	  curSize /= 4;
  }
  /* changes end */
  totalSize += mipmapData[i].remaining();
}



This patchjob is tested for saving DXT1-5 compressed files.
I bet it could be done a bit nicer, but it does the job.

I don't know if this can be classified as a bug, but I certainly think, the 
original behavour was not desired and could be fixed in future versions.

So much from my part, hope this is patched in future releases.

best regards,
Dahie



--- Bug imported by sgothel@jausoft.com 2010-03-24 07:51 EDT  ---

This bug was previously known as _bug_ 362 at https://jogl.dev.java.net/bugs/show_bug.cgi?id=362
Comment 1 Michael 2013-12-11 23:09:41 CET
Besides compression, the size calculation is incorrect for other mipmap sequences. The current calculation uses a divisor of 4, which is true for the difference between all mipmap levels except the smallest on occasion. The following sequence for example:

64x32 RGB Uncompressed DDS Image with generated mipmaps.
64x32 -> 6144 bytes
32x16 -> 1536 bytes
16x8 -> 384 bytes
8x4 -> 96 bytes
4x2 -> 24 bytes
2x1 -> 6 bytes
1x1 -> 3 bytes

6/4 != 3 
Mipmap level 6 didn't match expected data size (expected 1, got 3))

Created patch and unit test. Ready for pull.
Comment 2 Sven Gothel 2013-12-15 17:20:19 CET
82d7bae212ad5a540a29003aaec8c7e026615f68
      Fix Bug 362: calculated dimensions for MipMaps smaller than 16x16
    Added method to calculate mipmap blocksize for uncompressed and DXTn
    images