richgel999 / bc7enc

Single source file BC1-5 and BC7 encoders and BC1-5/7 decoders with MIT or Public Domain licenses

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to calculate PSNR correctly?

JustAndreww opened this issue · comments

Sorry for the noob question.

I'm trying to compress attached image to dxt1 (bc1) and caclulate PSNR:
.\bc7enc.exe -1 -u5 -i -b -n .\Sky_1k.png Sky_1k.dds

After compression I'm getting:

Luma  Max error:  12 RMSE: 0.916742 PSNR 48.89 dB
RGB   Max error:  18 RMSE: 1.124917 PSNR 47.11 dB
RGBA  Max error:  18 RMSE: 0.974207 PSNR 48.36 dB
Red   Max error:  18 RMSE: 1.197769 PSNR 46.56 dB
Green Max error:  12 RMSE: 0.957731 PSNR 48.51 dB
Blue  Max error:  15 RMSE: 1.201839 PSNR 46.53 dB
Alpha Max error:   0 RMSE: 0.000000 PSNR 100.00 dB

If I want to use 3rd party tool like Microsoft's texdiag.exe (texdiag.zip) and calculate PSNR using it I'm getting following results (./texdiag.exe compare Sky_1k.png Sky_1k.dds):

Result: 0.000059 (0.000023 0.000014 0.000022 0.000000) PSNR 47.041554 dB

However, if I will compare unpacked png (.\texdiag.exe compare .\Sky_1k.png .\Sky_1k_unpacked.png):

Result: 0.000058 (0.000022 0.000014 0.000022 0.000000) PSNR 47.109453 dB

which is close to the RGB Max Error from bc7enc tool.

Does it mean that it's not possible to directly compare files without constant unpacking them?

Sky_1k

Also, it looks like different software decodes back to png differently. With your decoder I always get higher PSNRs.

In attachment there is two different PNGs (one from CompressonatorCLI -UseGPUDecompress, and the second is from bc7enc).

1 - decoded by bc7enc, PSNR: 47.108 RGB, 51.209 YUV:
image

2- decoded by AMD CompressonatorCLI, PSNR: 46.992 RGB, 51.221 YUV:
image

dds_compress_psnr.zip

Unfortunately the BC1 format is not sufficiently standardized. There is no one "true" way to decode it. The last I checked, AMD Compressonator's tool used rounding to compute colors 2,3, which is incorrect according to Microsoft.

There are 3 or 4 different ways to decode BC1: ideal with no rounding, ideal with rounding, AMD GPU BC1, NVidia GPU BC1, and Intel GPU BC1. Each results in different output. In "ideal" mode my encoder/decoders use these formulas from Microsoft, which don't round:

https://docs.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-block-compression#bc1

If I want to use 3rd party tool like Microsoft's texdiag.exe (texdiag.zip) and calculate PSNR using it I'm getting following results (./texdiag.exe compare Sky_1k.png Sky_1k.dds):

You're using Microsoft's tool to unpack the texture data in the .DDS file, but there are several different ways of decoding BC1. If they don't use the "standard" ideal way, which is no rounding for colors 2/3, you'll get different results vs. my code:

https://docs.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-block-compression#bc1

Does it mean that it's not possible to directly compare files without constant unpacking them?

Yes, until this mess is addressed by Microsoft. We need a 100% standard way of decoding BC1.

I will be adding another BC1 approximation mode that supports rounding. It won't follow Microsoft's own formulas, but it'll allow you to compare against other decoders.

I've added the "rgbcx::bc1_approx_mode::cBC1IdealRound4" mode to the encoder. To select this from the command line tool, use the -r command line option. I've verified that in this mode, my output matches AMD Compressonator's.

Now, does this mode result in higher quality textures when decoded on actual GPU's? I need to find out. But it won't match some popular tools' output, such as crunch's.

As a side note, BC3-5 alpha are decoded with rounding by AMD Compressonator. But my decoders (and many others) don't round. So there will be differences with BC3-5.