Unsure how VQ compression works

If you have any questions on programming, this is the place to ask them, whether you're a newbie or an experienced programmer. Discussion on programming in general is also welcome. We will help you with programming homework, but we will not do your work for you! Any porting requests must be made in Developmental Ideas.
Post Reply
User avatar
Protofall
DCEmu Crazy Poster
DCEmu Crazy Poster
Posts: 26
Joined: Sun Jan 14, 2018 8:03 pm
Location: Emu land
Contact:

Unsure how VQ compression works

Post by Protofall » Thu Feb 14, 2019 6:10 am

Lately I've been working on a program that converts from Tvspelsfreak's "Texconv" Dtex files to either a RGBA8888 binary or a PNG. For those who don't know a Dtex file is basically the raw texture a Dreamcast requires when rendering plus a header with height, width, texture information, etc. (Its 16-bytes long) I've got support for most of what it offers (Including Twiddle support) and now I want to have a go at de-compression support.

I've been reading an old Sega doc (Not sure if I'm allowed to link that here or not, but it would help so I can show my understanding), the description for Texconv as well as some some forum posts. I think I get how VQ-compressed textures work for the most part. Basically the texture has two parts; the "Code-Block" overhead which has 256 entries of 64-bit words (2KB in size) and for 16BPP, every 64-bit word contains 4 lots of 16bpp colours that correspond to a "2 * 2" set of texels (And for PAL8BPP its 8 texels entries ("4 * 2") and PAL4BPP its 16 ("4 * 4") entries). The "Index" section has `height * width` bytes of entries ("/2" for PAL8BPP and "/4" for PAL4BPP) where each byte contains a value that corresponds to one of the 256 code-block entries which correspondes to a "2 by 2" of texels.

The first question: I know compression can only be used on twiddled (No stride) textures, I see in the docs its says the 2 by 2 texel block is laided out in a backwards N shape (In other words, its twiddled) I can't tell if this means the "already twiddled 2 by 2 block" is Re-arranged again or if this is just a reminder that the texture *is* twiddled.

The second question: I came up with a "Compressed size" formula thats `2048 + (height * width / 2 / 2 (And further divisions for palettes as mentioned before))`Bytes. When ignoring the 16-byte Dtex header mostly every dtex file I compressed obeyed this formula, but I noticed an exception when I tried to compress small textures (Less than 32 by 32) that I don't understand. Before you say, I know unless you're doing the "Small-VQ" hack/trick its generally not a good idea to compress a texture thats smaller than 64 by 64 because the 2KB code-block overhead + indexes take up more space than the uncompressed texture, but because I'm making a converter and want to support any dtex file I need to account for this. Anyways, these were my results from my tests
For the 8 by 8 image (16 by 16 has the same compressed sizes)

4BPP insta
Uncompressed:	48		B	= 16-byte header + (8 * 8 * 0.5)Byte body
Compressed:		2096	B	= 16-byte header + 2048-byte code book + (8 * 8 / 4 / 4)Byte texture-index	= 2060	!= 2096

8BPP insta
Uncompressed:	80		B	= 16-byte header + (8 * 8 * 1)Byte body
Compressed:		2096	B	= 16-byte header + 2048-byte code book + (8 * 8 / 4 / 2)Byte texture-index	= 2072	!= 2096

RGB565 insta
Uncompressed:	144		B	= 16-byte header + (8 * 8 * 2)Byte body
Compressed:		2096	B	= 16-byte header + 2048-byte code book + (8 * 8 / 2 / 2)Byte texture-index = 2080	!= 2096


For a 32 by 32 image

4BPP insta
Uncompressed:	528		B	= 16-byte header + (8 * 8 * 0.5)Byte body
Compressed:		2128	B	= 16-byte header + 2048-byte code book + (32 * 32 / 4 / 4 = 64)Byte texture-index = 2128

8BPP insta
Uncompressed:	1040	B	= 16-byte header + (8 * 8 * 1)Byte body
Compressed:		2192	B	= 16-byte header + 2048-byte code book + (32 * 32 / 4 / 2 = 128)Byte texture-index = 2192
As you can see, my pre-established "Compressed size" formula doesn't hold for images less than 32 by 32. It seems for some reason if a compressed texture would normally be under 2096 Bytes, its rounded up to that number, but I have no idea why this would be the case. I found one line in the Sega doc that might be referring to this (Or more likely the "Small VQ" hack), but I have no idea what its trying to say:

"Normally, when dealing with textures that are 32 × 32 or smaller, it is necessary to group several into a size of at least 64 × 64 before compressing them."

I've included a zip file containing my source PNGs and all the dtex files I used in this test

The third question: The Sega docs kept saying you can't make rectangular compressed textures because they won't work. However Tvspelsfreak de-confirmed this when he added support for this and it works on hardware. I've already got uncompressed twiddled rectangle support, would there be any other tricks I need to look out for with rectangular textures? I'm fairly sure a 8 by 64 would still trigger the thing from the second question, but other than that I'd imagine everything else would be fine

The last question: With compressed PAL8BPP textures, I said before each index represents a "4 by 2" texel section. Which one is width and which is height?
Attachments
WeirdCompression.zip
(6.06 KiB) Downloaded 18 times
Working on a recreation of Minesweeper for the Dreamcast <viewtopic.php?f=34&t=104820>

Twitter <https://twitter.com/ProfessorToffal>
YouTube (Not much there, but there are a few things) <https://www.youtube.com/user/TrueMenfa>
User avatar
Protofall
DCEmu Crazy Poster
DCEmu Crazy Poster
Posts: 26
Joined: Sun Jan 14, 2018 8:03 pm
Location: Emu land
Contact:

Re: Unsure how VQ compression works

Post by Protofall » Sat Feb 23, 2019 4:34 am

I managed to figure out the answers to my questions. For those who wonder, here were the solutions.

1. Each code-book entry is twiddled (Order is 0, 2, 1, 3 for 16BPP). On top of that the image data block is also twiddled for the correct size (Imagine each index is a "texel-collection" and we twiddle the texel-collections, not each texel individually)

2. It seems texconv has some mistake/oversight that means the file size has a lower bound cap. Using my formula above I was able to extract all information

3. No extra tricks, it just worked when I tested them.

4. The answer is weird. I had to read two entries at a time and hence 16 texels which I then treated very similarly to PAL4BPP. But yes, it was a 4-by-2 texel-collection
Working on a recreation of Minesweeper for the Dreamcast <viewtopic.php?f=34&t=104820>

Twitter <https://twitter.com/ProfessorToffal>
YouTube (Not much there, but there are a few things) <https://www.youtube.com/user/TrueMenfa>
Post Reply