From 7385c0815012a8d1e08e91e32cde9728aaad7579 Mon Sep 17 00:00:00 2001 From: "Andon M. Coleman" Date: Wed, 28 Aug 2024 04:49:59 -0400 Subject: [PATCH] Cleanup various PQ transform code --- include/utility/image.h | 49 ++++---- src/tabs/viewer.cpp | 2 +- src/utility/image.cpp | 243 +++------------------------------------- 3 files changed, 46 insertions(+), 248 deletions(-) diff --git a/include/utility/image.h b/include/utility/image.h index a877f5d..84e32a6 100644 --- a/include/utility/image.h +++ b/include/utility/image.h @@ -66,49 +66,54 @@ constexpr DirectX::XMMATRIX c_fromXYZto709 = // Transposed constexpr DirectX::XMMATRIX c_fromXYZtoLMS = // Transposed { - { 0.3592, -0.1922, 0.0070, 0.0 }, - { 0.6976, 1.1004, 0.0749, 0.0 }, - { -0.0358, 0.0755, 0.8434, 0.0 }, - { 0.0, 0.0, 0.0, 1.0 } + { 0.3592f, -0.1922f, 0.0070f, 0.0f }, + { 0.6976f, 1.1004f, 0.0749f, 0.0f }, + { -0.0358f, 0.0755f, 0.8434f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f } }; constexpr DirectX::XMMATRIX c_fromLMStoXYZ = // Transposed { - { 2.070180056695613509600, 0.364988250032657479740, -0.049595542238932107896, 0.0 }, - { -1.326456876103021025500, 0.680467362852235141020, -0.049421161186757487412, 0.0 }, - { 0.206616006847855170810, -0.045421753075853231409, 1.187995941732803439400, 0.0 }, - { 0.0, 0.0, 0.0, 1.0 } + { 2.070180056695613509600f, 0.364988250032657479740f, -0.049595542238932107896f, 0.0f }, + { -1.326456876103021025500f, 0.680467362852235141020f, -0.049421161186757487412f, 0.0f }, + { 0.206616006847855170810f, -0.045421753075853231409f, 1.187995941732803439400f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f } }; constexpr DirectX::XMMATRIX c_scRGBtoBt2100 = // Transposed { - { 2939026994.L / 585553224375.L, 76515593.L / 138420033750.L, 12225392.L / 93230009375.L, 0.0 }, - { 9255011753.L / 3513319346250.L, 6109575001.L / 830520202500.L, 1772384008.L / 2517210253125.L, 0.0 }, - { 173911579.L / 501902763750.L, 75493061.L / 830520202500.L, 18035212433.L / 2517210253125.L, 0.0 }, - { 0.0, 0.0, 0.0, 1.0 } + { 2939026994.0f / 585553224375.0f, 76515593.0f / 138420033750.0f, 12225392.0f / 93230009375.0f, 0.0f }, + { 9255011753.0f / 3513319346250.0f, 6109575001.0f / 830520202500.0f, 1772384008.0f / 2517210253125.0f, 0.0f }, + { 173911579.0f / 501902763750.0f, 75493061.0f / 830520202500.0f, 18035212433.0f / 2517210253125.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f } }; constexpr DirectX::XMMATRIX c_Bt2100toscRGB = // Transposed { - { 348196442125.L / 1677558947.L, -579752563250.L / 37238079773.L, -12183628000.L / 5369968309.L, 0.0f }, - { -123225331250.L / 1677558947.L, 5273377093000.L / 37238079773.L, -472592308000.L / 37589778163.L, 0.0f }, - { -15276242500.L / 1677558947.L, -38864558125.L / 37238079773.L, 5256599974375.L / 37589778163.L, 0.0f }, - { 0.0f, 0.0f, 0.0f, 1.0f } + { 348196442125.0f / 1677558947.0f, -579752563250.0f / 37238079773.0f, -12183628000.0f / 5369968309.0f, 0.0f }, + { -123225331250.0f / 1677558947.0f, 5273377093000.0f / 37238079773.0f, -472592308000.0f / 37589778163.0f, 0.0f }, + { -15276242500.0f / 1677558947.0f, -38864558125.0f / 37238079773.0f, 5256599974375.0f / 37589778163.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f } }; struct ParamsPQ { - DirectX::XMVECTOR N, M; + DirectX::XMVECTOR N, M; DirectX::XMVECTOR C1, C2, C3; + DirectX::XMVECTOR MaxPQ; + DirectX::XMVECTOR RcpN, RcpM; }; static const ParamsPQ PQ = { - DirectX::XMVectorReplicate (2610.0 / 4096.0 / 4.0), // N - DirectX::XMVectorReplicate (2523.0 / 4096.0 * 128.0), // M - DirectX::XMVectorReplicate (3424.0 / 4096.0), // C1 - DirectX::XMVectorReplicate (2413.0 / 4096.0 * 32.0), // C2 - DirectX::XMVectorReplicate (2392.0 / 4096.0 * 32.0), // C3 + DirectX::XMVectorReplicate (2610.0 / 4096.0 / 4.0), // N + DirectX::XMVectorReplicate (2523.0 / 4096.0 * 128.0), // M + DirectX::XMVectorReplicate (3424.0 / 4096.0), // C1 + DirectX::XMVectorReplicate (2413.0 / 4096.0 * 32.0), // C2 + DirectX::XMVectorReplicate (2392.0 / 4096.0 * 32.0), // C3 + DirectX::XMVectorReplicate (125.0f), // MaxPQ + DirectX::XMVectorReciprocal (DirectX::XMVectorReplicate (2610.0 / 4096.0 / 4.0)), + DirectX::XMVectorReciprocal (DirectX::XMVectorReplicate (2523.0 / 4096.0 * 128.0)), }; #pragma warning( pop ) diff --git a/src/tabs/viewer.cpp b/src/tabs/viewer.cpp index 2e9790c..1f808e8 100644 --- a/src/tabs/viewer.cpp +++ b/src/tabs/viewer.cpp @@ -1960,7 +1960,7 @@ LoadLibraryTexture (image_s& image) XMVECTOR v = *pixels++; v = - XMVector3Transform (v, c_from709toXYZ); + XMVectorMax (g_XMZero, XMVector3Transform (v, c_from709toXYZ)); luminance_freq [ std::clamp ( (int) diff --git a/src/utility/image.cpp b/src/utility/image.cpp index e6b6d5d..6aeb608 100644 --- a/src/utility/image.cpp +++ b/src/utility/image.cpp @@ -42,13 +42,8 @@ using namespace DirectX; XMVECTOR ret; - XMVECTOR sign = - XMVectorSet (XMVectorGetX (N) < 0.0f ? -1.0f : 1.0f, - XMVectorGetY (N) < 0.0f ? -1.0f : 1.0f, - XMVectorGetZ (N) < 0.0f ? -1.0f : 1.0f, 1.0f); - ret = - XMVectorPow (XMVectorAbs (N), XMVectorDivide (g_XMOne, PQ.M)); + XMVectorPow (XMVectorMax (N, g_XMZero), PQ.RcpM); XMVECTOR nd; @@ -59,7 +54,7 @@ using namespace DirectX; XMVectorMultiply (PQ.C3, ret))); ret = - XMVectorMultiply (XMVectorMultiply (XMVectorPow (nd, XMVectorDivide (g_XMOne, PQ.N)), maxPQValue), sign); + XMVectorMultiply (XMVectorPow (nd, PQ.RcpN), maxPQValue); return ret; }; @@ -70,13 +65,9 @@ SKIV_Image_LinearToPQ (DirectX::XMVECTOR N, DirectX::XMVECTOR maxPQValue) using namespace DirectX; XMVECTOR ret; - XMVECTOR sign = - XMVectorSet (XMVectorGetX (N) < 0.0f ? -1.0f : 1.0f, - XMVectorGetY (N) < 0.0f ? -1.0f : 1.0f, - XMVectorGetZ (N) < 0.0f ? -1.0f : 1.0f, 1.0f); ret = - XMVectorPow (XMVectorDivide (XMVectorAbs (N), maxPQValue), PQ.N); + XMVectorPow (XMVectorDivide (XMVectorMax (N, g_XMZero), maxPQValue), PQ.N); XMVECTOR nd = XMVectorDivide ( @@ -85,7 +76,7 @@ SKIV_Image_LinearToPQ (DirectX::XMVECTOR N, DirectX::XMVECTOR maxPQValue) ); return - XMVectorMultiply (XMVectorPow (nd, PQ.M), sign); + XMVectorPow (nd, PQ.M); }; float @@ -116,7 +107,7 @@ SKIV_Image_Rec709toICtCp (DirectX::XMVECTOR N) ret = XMVector3Transform (ret, c_fromXYZtoLMS); ret = - SKIV_Image_LinearToPQ (XMVectorMax (ret, g_XMZero), XMVectorReplicate (125.0f)); + SKIV_Image_LinearToPQ (XMVectorMax (ret, g_XMZero), PQ.MaxPQ); static const DirectX::XMMATRIX ConvMat = // Transposed { @@ -153,8 +144,8 @@ SKIV_Image_ICtCptoRec709 (DirectX::XMVECTOR N) ret = XMVector3Transform (ret, ConvMat); - ret = SKIV_Image_PQToLinear (ret, XMVectorReplicate (125.0f)); - ret = XMVector3Transform (ret, c_fromLMStoXYZ); + ret = SKIV_Image_PQToLinear (ret, PQ.MaxPQ); + ret = XMVector3Transform (ret, c_fromLMStoXYZ); return XMVector3Transform (ret, c_fromXYZto709); @@ -618,7 +609,7 @@ SKIV_HDR_CalculateContentLightInfo (const DirectX::Image& img) XMVECTOR v = *pixels++; v = - XMVector3Transform (v, c_from709toXYZ); + XMVectorMax (g_XMZero, XMVector3Transform (v, c_from709toXYZ)); luminance_freq [ std::clamp ( (int) @@ -1276,132 +1267,6 @@ class SKIV_ScopedThreadPriority }; #include -#include -#include - -void -scRGB_to_ICtCp (float r, float g, float b, float& I, float& Ct, float& Cp) -{ - using namespace DirectX; - - XMVECTOR scRGB = - XMVectorSet (r,g,b,1.0f); - - XMVECTOR ICtCp = - SKIV_Image_Rec709toICtCp (scRGB); - - I = XMVectorGetX (ICtCp); - Ct = XMVectorGetY (ICtCp); - Cp = XMVectorGetZ (ICtCp); -} - -void -ICtCp_to_scRGB (float I, float Ct, float Cp, float& r, float& g, float& b) -{ - using namespace DirectX; - - XMVECTOR ICtCp = - XMVectorSet (I,Ct,Cp,1.0f); - - XMVECTOR scRGB = - SKIV_Image_ICtCptoRec709 (ICtCp); - - r = XMVectorGetX (scRGB); - g = XMVectorGetY (scRGB); - b = XMVectorGetZ (scRGB); -} - -// Function to clamp values between 0 and 63 -int clamp(int value, int min, int max) { - return std::max(min, std::min(value, max)); -} - -// Example function to look up a value from the LUT -//std::array lookupLUT(const std::vector>>>& lut, -// float r, float g, float b) { -// -//} - -DirectX::XMVECTOR -SKIV_Image_LookupLUT (std::vector >>& lut, DirectX::XMVECTOR& v) -{ - using namespace DirectX; - - const int LUT_SIZE = 64; - - // Ensure input values are between 0 and 1 - float r = std::max (0.0f, std::min (1.0f, XMVectorGetX (v))); - float g = std::max (0.0f, std::min (1.0f, XMVectorGetY (v))); - float b = std::max (0.0f, std::min (1.0f, XMVectorGetZ (v))); - - // Convert normalized values to indices - int ri = static_cast(r * (LUT_SIZE - 1)); - int gi = static_cast(g * (LUT_SIZE - 1)); - int bi = static_cast(b * (LUT_SIZE - 1)); - - // Clamp indices to be within the LUT bounds - ri = clamp (ri, 0, LUT_SIZE - 1); - gi = clamp (gi, 0, LUT_SIZE - 1); - bi = clamp (bi, 0, LUT_SIZE - 1); - - // Retrieve the value from the LUT - return - XMVectorSet (lut [ri][gi][bi][0], lut [ri][gi][bi][1], lut [ri][gi][bi][2], 1.0f); -} - -void -SKIV_Image_GenerateLUT_scRGB_to_ICtCp (std::vector >>& lut) -{ - const int LUT_SIZE = 64; -//const float MAX_VAL = 1.0f; // Assuming values are normalized between 0 and 1 - - for (int r = 0; r < LUT_SIZE; ++r) - { - for (int g = 0; g < LUT_SIZE; ++g) - { - for (int b = 0; b < LUT_SIZE; ++b) - { - float sr = static_cast (r) / (LUT_SIZE - 1); - float sg = static_cast (g) / (LUT_SIZE - 1); - float sb = static_cast (b) / (LUT_SIZE - 1); - - float I, Ct, Cp; - scRGB_to_ICtCp (sr, sg, sb, I, Ct, Cp); - - lut[r][g][b][0] = I; - lut[r][g][b][1] = Ct; - lut[r][g][b][2] = Cp; - } - } - } -} - -void -SKIV_Image_GenerateLUT_ICtCp_to_scRGB (std::vector >>& lut) -{ - const int LUT_SIZE = 64; -//const float MAX_VAL = 1.0f; // Assuming values are normalized between 0 and 1 - - for (int r = 0; r < LUT_SIZE; ++r) - { - for (int g = 0; g < LUT_SIZE; ++g) - { - for (int b = 0; b < LUT_SIZE; ++b) - { - float I = static_cast (r) / (LUT_SIZE - 1); - float Ct = static_cast (g) / (LUT_SIZE - 1); - float Cp = static_cast (b) / (LUT_SIZE - 1); - - float sr, sg, sb; - ICtCp_to_scRGB (I, Ct, Cp, sr, sg, sb); - - lut[r][g][b][0] = sr; - lut[r][g][b][1] = sg; - lut[r][g][b][2] = sb; - } - } - } -} HRESULT SKIV_Image_TonemapToSDR (const DirectX::Image& image, DirectX::ScratchImage& final_sdr, float mastering_max_nits, float mastering_sdr_nits) @@ -1509,7 +1374,7 @@ SKIV_Image_TonemapToSDR (const DirectX::Image& image, DirectX::ScratchImage& fin XMVECTOR value = inPixels [j]; value = - XMVectorMultiply (value, vLumaRescale); + XMVectorMultiply (value, vLumaRescale); if (needs_tonemapping) { @@ -1575,7 +1440,7 @@ SKIV_Image_TonemapToSDR (const DirectX::Image& image, DirectX::ScratchImage& fin ); PLOG_INFO << "SKIV_Image_TonemapToSDR ( ): TransformImageEnd"; -#if 1 +#if 0 float fMaxR = XMVectorGetX (maxTonemappedRGB); float fMaxG = XMVectorGetY (maxTonemappedRGB); float fMaxB = XMVectorGetZ (maxTonemappedRGB); @@ -1654,79 +1519,7 @@ SKIV_Image_SaveToDisk_SDR (const DirectX::Image& image, const wchar_t* wszFileNa scratch_image; scratch_image.InitializeFromImage (image); - - TransformImage (image, - [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t width, size_t y) - { - UNREFERENCED_PARAMETER(y); - - for (size_t j = 0; j < width; ++j) - { - XMVECTOR value = inPixels [j]; - outPixels [j] = - image.format == DXGI_FORMAT_R16G16B16A16_FLOAT ? - XMVectorSet (XMVectorGetX (value), XMVectorGetY (value), XMVectorGetZ (value), 65504.0f) : - XMVectorSet (XMVectorGetX (value), XMVectorGetY (value), XMVectorGetZ (value), 1.0f); - } - }, scratch_image); - - auto pDevice = - SKIF_D3D11_GetDevice (); - - if (! pDevice) - return E_UNEXPECTED; - - CComPtr pFactory; - CreateDXGIFactory (IID_IDXGIFactory, (void **)&pFactory.p); - - if (! pFactory) - return E_NOTIMPL; - - CComPtr pAdapter; - UINT uiAdapter = 0; - - RECT wnd_rect = {}; - GetWindowRect (SKIF_ImGui_hWnd, &wnd_rect); - - HMONITOR hMonitor = - MonitorFromWindow (SKIF_ImGui_hWnd, MONITOR_DEFAULTTONEAREST); - - CComPtr pMonitorOutput; - DXGI_OUTPUT_DESC out_desc = {}; - DXGI_OUTPUT_DESC1 out_desc1= {}; - - while (SUCCEEDED (pFactory->EnumAdapters (uiAdapter++, &pAdapter.p))) - { - CComPtr pOutput; - UINT uiOutput = 0; - - while (SUCCEEDED (pAdapter->EnumOutputs (uiOutput++, &pOutput))) - { - pOutput->GetDesc (&out_desc); - - CComQIPtr - pOutput6 (pOutput); - if (pOutput6.p != nullptr) - { - pOutput6->GetDesc1 (&out_desc1); - } - - if (out_desc.AttachedToDesktop && out_desc.Monitor == hMonitor) - { - pMonitorOutput = pOutput; - break; - } - - pOutput = nullptr; - } - - if (pMonitorOutput != nullptr) - break; - - pAdapter = nullptr; - } - - wchar_t* wszExtension = + wchar_t* wszExtension = PathFindExtensionW (wszFileName); wchar_t wszImplicitFileName [MAX_PATH] = { }; @@ -1952,6 +1745,8 @@ SKIV_Image_SaveToDisk_SDR (const DirectX::Image& image, const wchar_t* wszFileNa } }); + minLum = XMVectorMax (g_XMZero, minLum); + auto luminance_freq = std::make_unique (65536); ZeroMemory (luminance_freq.get (), sizeof (uint32_t) * 65536); @@ -1971,7 +1766,7 @@ SKIV_Image_SaveToDisk_SDR (const DirectX::Image& image, const wchar_t* wszFileNa XMVECTOR v = *pixels++; v = - XMVector3Transform (v, c_from709toXYZ); + XMVectorMax (g_XMZero, XMVector3Transform (v, c_from709toXYZ)); luminance_freq [ std::clamp ( (int) @@ -1991,9 +1786,9 @@ SKIV_Image_SaveToDisk_SDR (const DirectX::Image& image, const wchar_t* wszFileNa percent -= 100.0 * ((double)luminance_freq [i] / img_size); - if (percent <= 99.825) + if (percent <= 99.85) { - PLOG_INFO << "99.825th percentile luminance: " << + PLOG_INFO << "99.85th percentile luminance: " << 80.0f * (XMVectorGetY (minLum) + (fLumRange * ((float)i / 65536.0f))) << " nits"; @@ -2025,7 +1820,7 @@ SKIV_Image_SaveToDisk_SDR (const DirectX::Image& image, const wchar_t* wszFileNa bool needs_tonemapping = false; - if (XMVectorGetY (maxLum) > 1.01f) + //if (SKIV_Image_LinearToPQY (XMVectorGetY (maxLum)) > SDR_YInPQ) { needs_tonemapping = true; } @@ -2318,8 +2113,6 @@ SKIV_Image_SaveToDisk_UltraHDR (const DirectX::Image& image, const wchar_t* wszF // Convert to HDR10 if (image.format == DXGI_FORMAT_R16G16B16A16_FLOAT) { - XMVECTOR c_MaxPQ = XMVectorReplicate (125.0f); - DirectX::TransformImage (image, [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t width, size_t y) { @@ -2331,7 +2124,7 @@ SKIV_Image_SaveToDisk_UltraHDR (const DirectX::Image& image, const wchar_t* wszF outPixels [j] = SKIV_Image_LinearToPQ ( - XMVectorMax (g_XMZero, XMVector3Transform (value, c_from709to2020)), c_MaxPQ + XMVectorMax (g_XMZero, XMVector3Transform (value, c_scRGBtoBt2100)) ); } },temp_image