In this series of blog posts, I'm going to cover various parts of the research and development behind Bink 2 HDR.
So first thing is deciding on an encoding. Of which there are a very many to choose from. There is...
Just to name a few. Additionally with video games, we have additional constraints such as texture filtering and performance considerations, etc... For example, bilinear filtering is a linear operation, and the luma representation would have to operate correctly under linear transforms (or at least be fast enough to decode so that it wouldn't matter to first decode then interpolate). Additional x 2 for a video format like Bink, we need to consider various compression artifacts and what those would look like. With so many different formats to choose from, you have to take a step back and instead look at the actual encoding used by the output itself  as that really determines what is best (or used directly). Which leads me to the next topic of SMPTE 2084. SMPTE2084 ... aka High Dynamic Range ElectroOptical Transfer Function of Mastering Reference Displays (try saying that 5 times fast!) SMPTE2084 is the format to which Dolby Vision and HDR10 displays use  so its basically the narrow part of the pipeline. Everything you want to display has to go through this nonlinear encoding at some point before being displayed on the TV (decoded back to linear in the process as well). The SMPTE2084 format is locked behind a pay wall (yay)  which I have purchased and will boil it down for you to what I believe is the most important parts. The format defines luma in absolute values between 0 to 10,000 cd/m^2 (candelas per square meter). However, with the caveat that in real implementations of the spec, 10k luma won't actually be representable in anything but pure white color. Additionally, actual displays vary from the absolute curve due to output limitations and effects of nonideal viewing environments. While the format supports 10, 12, 14, and 16bit Luma representations, as currently deployed Dolby Vision is 12bit and HDR10 is 10bit. 14 and 16bit is not widely deployed  if deployed at all anywhere other than the reference monitor. Additionally, these are positive numbers only. No negative values. The code to encode/decode a SMPTE2084 is as follows. #define SMPTE_2084_M1 (2610.f/4096*0.25f) #define SMPTE_2084_M2 (2523.f/4096*128) #define SMPTE_2084_C1 (3424.f/4096) #define SMPTE_2084_C2 (2413.f/4096*32) #define SMPTE_2084_C3 (2392.f/4096*32) // Gives a value of 0 .. 10,000 in linear absolute brightness float smpte2084_decode(unsigned v, int bits) { float fv, num, denom; fv = v / ((1 << bits)1.f); fv = fv > 1.f ? 1.f : fv; // Clamp 0 .. 1 fv = powf(fv, 1.f/SMPTE_2084_M2); num = fv  SMPTE_2084_C1; num = num < 0.f ? 0.f : num; denom = SMPTE_2084_C2  SMPTE_2084_C3 * fv; return powf(num / denom, 1.f/SMPTE_2084_M1) * 10000.f; } // Gives a value between 0 and 2^bits1 (nonlinear) unsigned smpte2084_encode(float v, int bits) { float n, tmp; v /= 10000.f; v = v > 1.f ? 1.f : v < 0.f ? 0.f : v; // Clamp 0 .. 1 tmp = powf(v, SMPTE_2084_M1); n = powf((SMPTE_2084_C1 + SMPTE_2084_C2 * tmp) / (1 + SMPTE_2084_C3 * tmp), SMPTE_2084_M2); return (int)floorf(((1 << bits)1) * n + 0.5f); } The pretty nice thing about the limited range here (10 to 12 bits) is that you can pregenerate a table to decode into floats and store it in a texture or constant buffer or whatever. This makes decoding rather inexpensive! There are still some open questions here regarding its suitability as a video encoding format that I have. Namely...
To be continued....
0 Comments

Archives
November 2021
Categories 