From aaea911dc4bc386324f1bf97a8e4197b382a5dc3 Mon Sep 17 00:00:00 2001 From: Stanca Serban <sstanca@mozilla.com> Date: Wed, 15 Feb 2023 12:18:44 +0200 Subject: [PATCH] Backed out 9 changesets (bug 1799258) for causing multiple failures. CLOSED TREE Backed out changeset 40351b5987a5 (bug 1799258) Backed out changeset 87f3532bfbcd (bug 1799258) Backed out changeset 9c1d9405e8bf (bug 1799258) Backed out changeset 60a0351d9092 (bug 1799258) Backed out changeset 5f911de66ec0 (bug 1799258) Backed out changeset 294a00d1c7b7 (bug 1799258) Backed out changeset 228200dcaf93 (bug 1799258) Backed out changeset b25110652394 (bug 1799258) Backed out changeset 3c3c7366cc40 (bug 1799258) --- .../test/reftest/color_quads/reftest.list | 2 +- gfx/2d/Types.h | 5 +- gfx/gl/Colorspaces.cpp | 208 +---------- gfx/gl/Colorspaces.h | 341 +----------------- gfx/gl/gtest/TestColorspaces.cpp | 293 --------------- gfx/qcms/qcms.h | 89 ++--- gfx/qcms/src/c_bindings.rs | 121 +------ gfx/qcms/src/iccread.rs | 4 +- gfx/qcms/src/lib.rs | 3 +- gfx/qcms/src/matrix.rs | 6 +- gfx/qcms/src/transform_util.rs | 97 ++--- gfx/thebes/AllOfDcomp.h | 40 -- gfx/thebes/DeviceManagerDx.cpp | 23 +- gfx/thebes/gfxPlatform.cpp | 11 +- gfx/thebes/gfxPlatform.h | 8 +- gfx/thebes/gfxWindowsPlatform.cpp | 17 +- gfx/thebes/gfxWindowsPlatform.h | 6 - gfx/thebes/moz.build | 1 - gfx/webrender_bindings/DCLayerTree.cpp | 262 +------------- gfx/webrender_bindings/DCLayerTree.h | 36 -- mfbt/Span.h | 23 +- mfbt/tests/gtest/TestSpan.cpp | 48 +-- modules/libpref/init/StaticPrefList.yaml | 17 +- modules/libpref/init/all.js | 2 + netwerk/dns/DNSPacket.cpp | 2 +- 25 files changed, 137 insertions(+), 1528 deletions(-) delete mode 100644 gfx/thebes/AllOfDcomp.h diff --git a/dom/media/test/reftest/color_quads/reftest.list b/dom/media/test/reftest/color_quads/reftest.list index a5ad475b879b6..98df160be672c 100644 --- a/dom/media/test/reftest/color_quads/reftest.list +++ b/dom/media/test/reftest/color_quads/reftest.list @@ -17,7 +17,7 @@ defaults pref(media.av1.enabled,true) fuzzy(16-51,5234-5622) fuzzy-if(swgl,32-38,1600-91746) fuzzy-if(useDrawSnapshot,16-16,11600-11600) fuzzy-if(OSX,16-73,5212-5622) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm ../reftest_img.html?src=color_quads/720p.png fuzzy-if(winWidget&&swgl,0-20,0-5620) fuzzy-if(winWidget&&!swgl,0-1,0-78) fuzzy-if(Android,254-255,273680-273807) fuzzy-if(OSX,0-35,0-1947) fuzzy-if(OSX&&swgl,0-67,0-5451) fuzzy-if(appleSilicon,30-48,1760-187409) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.vp9.webm ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm fuzzy-if(winWidget,0-1,0-78) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.mp4 ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm -skip-if(winWidget&&isCoverageBuild) fuzzy(0-16,75-1941) fuzzy-if(Android,254-255,273680-273807) fuzzy-if(OSX,30-32,187326-187407) fuzzy-if(appleSilicon,30-48,1835-187409) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.h264.mp4 ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm +skip-if(winWidget&&isCoverageBuild) fuzzy(0-16,75-1861) fuzzy-if(Android,254-255,273680-273807) fuzzy-if(OSX,30-32,187326-187407) fuzzy-if(appleSilicon,30-48,1835-187409) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.h264.mp4 ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm fuzzy-if(winWidget&&swgl,0-20,0-5620) fuzzy-if(winWidget&&!swgl,0-1,0-78) fuzzy-if(Android,254-255,273680-273807) fuzzy-if(OSX,0-35,0-1947) fuzzy-if(OSX&&swgl,0-67,0-5451) fuzzy-if(appleSilicon,30-48,1760-187409) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.vp9.mp4 ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm skip-if(Android) fuzzy(16-48,8107-8818) fuzzy-if(winWidget&&swgl,31-38,8240-184080) fuzzy-if(appleSilicon,33-38,8819-11705) fuzzy-if(useDrawSnapshot,20-20,187200-187200) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.pc.yuv420p.av1.webm ../reftest_img.html?src=color_quads/720p.png diff --git a/gfx/2d/Types.h b/gfx/2d/Types.h index 5f027eb6d3943..fc3a910daa3c4 100644 --- a/gfx/2d/Types.h +++ b/gfx/2d/Types.h @@ -498,8 +498,7 @@ enum class YUVRangedColorSpace : uint8_t { // one. // Some times Worse Is Better. enum class ColorSpace2 : uint8_t { - Display, - UNKNOWN = Display, // We feel sufficiently bad about this TODO. + UNKNOWN, // Really "DISPLAY". Eventually we will remove this. SRGB, DISPLAY_P3, BT601_525, // aka smpte170m NTSC @@ -507,7 +506,7 @@ enum class ColorSpace2 : uint8_t { BT601_625 = BT709, // aka bt470bg PAL. Basically BT709, just Xg is 0.290 not 0.300. BT2020, - _First = Display, + _First = UNKNOWN, _Last = BT2020, }; diff --git a/gfx/gl/Colorspaces.cpp b/gfx/gl/Colorspaces.cpp index c7c40b2abaa8d..8ef15a58d77d2 100644 --- a/gfx/gl/Colorspaces.cpp +++ b/gfx/gl/Colorspaces.cpp @@ -7,9 +7,6 @@ #include "Colorspaces.h" -#include "nsDebug.h" -#include "qcms.h" - namespace mozilla::color { // tf = { k * linear | linear < b @@ -79,12 +76,6 @@ mat4 YuvFromYcbcr(const YcbcrDesc& d) { return yuvFromYcbcr; } -inline vec3 CIEXYZ_from_CIExyY(const vec2 xy, const float Y = 1) { - const auto xyz = vec3(xy, 1 - xy.x() - xy.y()); - const auto XYZ = xyz * (Y / xy.y()); - return XYZ; -} - mat3 XyzFromLinearRgb(const Chromaticities& c) { // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html @@ -124,7 +115,7 @@ mat3 XyzFromLinearRgb(const Chromaticities& c) { const auto XYZrgb = mat3({Xrgb, Yrgb, Zrgb}); const auto XYZrgb_inv = inverse(XYZrgb); - const auto XYZwhitepoint = vec3({c.wx, c.wy, 1 - c.wx - c.wy}) / c.wy; + const auto XYZwhitepoint = vec3({c.wx, c.wy, 1 - c.wx - c.wy}); const auto Srgb = XYZrgb_inv * XYZwhitepoint; const auto M = mat3({Srgb * Xrgb, Srgb * Yrgb, Srgb * Zrgb}); @@ -192,29 +183,6 @@ vec3 ColorspaceTransform::DstFromSrc(const vec3 src) const { // - -mat3 XyzAFromXyzB_BradfordLinear(const vec2 xyA, const vec2 xyB) { - // This is what ICC profiles use to do whitepoint transforms, - // because ICC also requires D50 for the Profile Connection Space. - - // From https://www.color.org/specification/ICC.1-2022-05.pdf - // E.3 "Linearized Bradford transformation": - - constexpr auto M_BFD = mat3{{ - vec3{{0.8951, 0.2664f, -0.1614f}}, - vec3{{-0.7502f, 1.7135f, 0.0367f}}, - vec3{{0.0389f, -0.0685f, 1.0296f}}, - }}; - // NB: They use rho/gamma/beta, but we'll use R/G/B here. - const auto XYZDst = CIEXYZ_from_CIExyY(xyA); // "XYZ_W", WP of PCS - const auto XYZSrc = CIEXYZ_from_CIExyY(xyB); // "XYZ_NAW", WP of src - const auto rgbSrc = M_BFD * XYZSrc; // "RGB_SRC" - const auto rgbDst = M_BFD * XYZDst; // "RGB_PCS" - const auto rgbDstOverSrc = rgbDst / rgbSrc; - const auto M_dstOverSrc = mat3::Scale(rgbDstOverSrc); - const auto M_adapt = inverse(M_BFD) * M_dstOverSrc * M_BFD; - return M_adapt; -} - std::optional<mat4> ColorspaceTransform::ToMat4() const { mat4 fromSrc = srcRgbTfFromSrc; if (srcTf) return {}; @@ -258,178 +226,4 @@ vec3 Lut3::Sample(const vec3 in01) const { return fxyz; } -// - - -ColorProfileDesc ColorProfileDesc::From(const ColorspaceDesc& cspace) { - auto ret = ColorProfileDesc{}; - - if (cspace.yuv) { - const auto yuvFromYcbcr = YuvFromYcbcr(cspace.yuv->ycbcr); - const auto yuvFromRgb = YuvFromRgb(cspace.yuv->yCoeffs); - const auto rgbFromYuv = inverse(yuvFromRgb); - ret.rgbFromYcbcr = mat4(rgbFromYuv) * yuvFromYcbcr; - } - - if (cspace.tf) { - const size_t tableSize = 256; - auto& tableR = ret.linearFromTf.r; - tableR.resize(tableSize); - for (size_t i = 0; i < tableR.size(); i++) { - const float tfVal = i / float(tableR.size() - 1); - const float linearVal = LinearFromTf(*cspace.tf, tfVal); - tableR[i] = linearVal; - } - ret.linearFromTf.g = tableR; - ret.linearFromTf.b = tableR; - } - - ret.xyzd65FromLinearRgb = XyzFromLinearRgb(cspace.chrom); - - return ret; -} - -// - - -template <class T> -constexpr inline T NewtonEstimateX(const T x1, const T y1, const T dydx, - const T y2 = 0) { - // Estimate x s.t. y=0 - // y = y0 + x*dydx; - // y0 = y - x*dydx; - // y1 - x1*dydx = y2 - x2*dydx - // x2*dydx = y2 - y1 + x1*dydx - // x2 = (y2 - y1)/dydx + x1 - return (y2 - y1) / dydx + x1; -} - -float GuessGamma(const std::vector<float>& vals, float exp_guess) { - // Approximate (signed) error = 0.0. - constexpr float d_exp = 0.001; - constexpr float error_tolerance = 0.001; - struct Samples { - float y1, y2; - }; - const auto Sample = [&](const float exp) { - int i = -1; - auto samples = Samples{}; - for (const auto& expected : vals) { - i += 1; - const auto in = i / float(vals.size() - 1); - samples.y1 += powf(in, exp) - expected; - samples.y2 += powf(in, exp + d_exp) - expected; - } - samples.y1 /= vals.size(); // Normalize by val count. - samples.y2 /= vals.size(); - return samples; - }; - constexpr int MAX_ITERS = 10; - for (int i = 1;; i++) { - const auto err = Sample(exp_guess); - const auto derr = err.y2 - err.y1; - exp_guess = NewtonEstimateX(exp_guess, err.y1, derr / d_exp); - // Check if we were close before, because then this last round of estimation - // should get us pretty much right on it. - if (std::abs(err.y1) < error_tolerance) { - return exp_guess; - } - if (i >= MAX_ITERS) { - printf_stderr("GuessGamma() -> %f after %i iterations (avg err %f)\n", - exp_guess, i, err.y1); - MOZ_ASSERT(false, "GuessGamma failed."); - return exp_guess; - } - } -} - -// - - -ColorProfileDesc ColorProfileDesc::From(const qcms_profile& qcmsProfile) { - ColorProfileDesc ret; - - qcms_profile_data data = {}; - qcms_profile_get_data(&qcmsProfile, &data); - - auto xyzd50FromLinearRgb = mat3{}; - // X contributions from [R,G,B] - xyzd50FromLinearRgb.at(0, 0) = data.red_colorant_xyzd50[0]; - xyzd50FromLinearRgb.at(1, 0) = data.green_colorant_xyzd50[0]; - xyzd50FromLinearRgb.at(2, 0) = data.blue_colorant_xyzd50[0]; - // Y contributions from [R,G,B] - xyzd50FromLinearRgb.at(0, 1) = data.red_colorant_xyzd50[1]; - xyzd50FromLinearRgb.at(1, 1) = data.green_colorant_xyzd50[1]; - xyzd50FromLinearRgb.at(2, 1) = data.blue_colorant_xyzd50[1]; - // Z contributions from [R,G,B] - xyzd50FromLinearRgb.at(0, 2) = data.red_colorant_xyzd50[2]; - xyzd50FromLinearRgb.at(1, 2) = data.green_colorant_xyzd50[2]; - xyzd50FromLinearRgb.at(2, 2) = data.blue_colorant_xyzd50[2]; - - const auto d65FromD50 = XyzAFromXyzB_BradfordLinear(D65, D50); - ret.xyzd65FromLinearRgb = d65FromD50 * xyzd50FromLinearRgb; - - // - - - const auto Fn = [&](std::vector<float>* const linearFromTf, - int32_t claimed_samples, - const qcms_color_channel channel) { - if (claimed_samples == 0) return; // No tf. - - if (claimed_samples == -1) { - claimed_samples = 4096; // Ask it to generate a bunch. - claimed_samples = 256; // Ask it to generate a bunch. - } - - linearFromTf->resize(AssertedCast<size_t>(claimed_samples)); - - const auto begin = linearFromTf->data(); - qcms_profile_get_lut(&qcmsProfile, channel, begin, - begin + linearFromTf->size()); - }; - - Fn(&ret.linearFromTf.r, data.linear_from_trc_red_samples, - qcms_color_channel::Red); - Fn(&ret.linearFromTf.b, data.linear_from_trc_blue_samples, - qcms_color_channel::Blue); - Fn(&ret.linearFromTf.g, data.linear_from_trc_green_samples, - qcms_color_channel::Green); - - // - - - return ret; -} - -// - - -ColorProfileConversionDesc ColorProfileConversionDesc::From( - const FromDesc& desc) { - const auto dstLinearRgbFromXyzd65 = inverse(desc.dst.xyzd65FromLinearRgb); - auto ret = ColorProfileConversionDesc{ - .srcRgbFromSrcYuv = desc.src.rgbFromYcbcr, - .srcLinearFromSrcTf = desc.src.linearFromTf, - .dstLinearFromSrcLinear = - dstLinearRgbFromXyzd65 * desc.src.xyzd65FromLinearRgb, - .dstTfFromDstLinear = {}, - }; - bool sameTF = true; - sameTF &= desc.src.linearFromTf.r == desc.dst.linearFromTf.r; - sameTF &= desc.src.linearFromTf.g == desc.dst.linearFromTf.g; - sameTF &= desc.src.linearFromTf.b == desc.dst.linearFromTf.b; - if (sameTF) { - ret.srcLinearFromSrcTf = {}; - ret.dstTfFromDstLinear = {}; - } else { - const auto Invert = [](const std::vector<float>& linearFromTf, - std::vector<float>* const tfFromLinear) { - const auto size = linearFromTf.size(); - MOZ_ASSERT(size != 1); // Less than two is uninvertable. - if (size < 2) return; - (*tfFromLinear).resize(size); - InvertLut(linearFromTf, &*tfFromLinear); - }; - Invert(desc.dst.linearFromTf.r, &ret.dstTfFromDstLinear.r); - Invert(desc.dst.linearFromTf.g, &ret.dstTfFromDstLinear.g); - Invert(desc.dst.linearFromTf.b, &ret.dstTfFromDstLinear.b); - } - return ret; -} - } // namespace mozilla::color diff --git a/gfx/gl/Colorspaces.h b/gfx/gl/Colorspaces.h index 8f36854d2d4f3..04fe9e678fe00 100644 --- a/gfx/gl/Colorspaces.h +++ b/gfx/gl/Colorspaces.h @@ -15,16 +15,12 @@ #include <algorithm> #include <array> #include <cmath> -#include <cstdint> #include <cstdlib> -#include <functional> #include <optional> #include <vector> #include "AutoMappable.h" -#include "mozilla/Assertions.h" #include "mozilla/Attributes.h" -#include "mozilla/Span.h" #ifdef DEBUG # define ASSERT(EXPR) \ @@ -37,9 +33,6 @@ # define ASSERT(EXPR) (void)(EXPR) #endif -struct _qcms_profile; -typedef struct _qcms_profile qcms_profile; - namespace mozilla::color { struct YuvLumaCoeffs final { @@ -81,7 +74,8 @@ struct PiecewiseGammaDesc final { 4.5, }; } - // FYI: static constexpr auto Rec2020_10bit() { return Rec709(); } + static constexpr auto Rec2020_10bit() { return Rec709(); } + static constexpr auto Rec2020_12bit() { return PiecewiseGammaDesc{ 1.0993, @@ -296,7 +290,6 @@ struct avec final { return eq; } }; -using vec2 = avec<float, 2>; using vec3 = avec<float, 3>; using vec4 = avec<float, 4>; using ivec3 = avec<int32_t, 3>; @@ -371,15 +364,10 @@ struct mat final { static constexpr auto Identity() { auto ret = mat{}; - for (int i = 0; i < std::min(x_cols, y_rows); i++) { - ret.at(i, i) = 1; - } - return ret; - } - static constexpr auto Scale(const avec<float, std::min(x_cols, y_rows)>& v) { - auto ret = mat{}; - for (int i = 0; i < v.N; i++) { - ret.at(i, i) = v[i]; + for (int x = 0; x < x_cols; x++) { + for (int y = 0; y < y_rows; y++) { + ret.at(x, y) = (x == y ? 1 : 0); + } } return ret; } @@ -439,30 +427,7 @@ struct mat final { } return c; } - - // For e.g. similarity evaluation - friend auto operator-(const mat& a, const mat& b) { - mat c; - for (int y = 0; y < y_rows; y++) { - c.rows[y] = a.rows[y] - b.rows[y]; - } - return c; - } }; - -template <class M> -inline float dotDifference(const M& a, const M& b) { - const auto c = a - b; - const auto d = c * avec<float, M::x_cols>(1); - const auto d2 = dot(d, d); - return d2; -} -template <class M> -inline bool approx(const M& a, const M& b, const float eps = 0.0001) { - const auto errSquared = dotDifference(a, b); - return errSquared <= (eps * eps); -} - using mat3 = mat<3, 3>; using mat4 = mat<4, 4>; @@ -686,300 +651,6 @@ struct ColorspaceTransform final { } }; -// - - -struct RgbTransferTables { - std::vector<float> r; - std::vector<float> g; - std::vector<float> b; -}; -float GuessGamma(const std::vector<float>& vals, float exp_guess = 1.0); - -static constexpr auto D65 = vec2{{0.3127, 0.3290}}; -static constexpr auto D50 = vec2{{0.34567, 0.35850}}; -mat3 XyzAFromXyzB_BradfordLinear(const vec2 xyA, const vec2 xyB); - -// - - -struct ColorProfileDesc { - // ICC profiles are phrased as PCS-from-encoded (PCS is CIEXYZ-D50) - // However, all of our colorspaces are D65, so let's normalize to that, - // even though it's a reversible transform. - color::mat4 rgbFromYcbcr = color::mat4::Identity(); - RgbTransferTables linearFromTf; - color::mat3 xyzd65FromLinearRgb = color::mat3::Identity(); - - static ColorProfileDesc From(const ColorspaceDesc&); - static ColorProfileDesc From(const qcms_profile&); -}; - -template <class C> -inline float SampleOutByIn(const C& outByIn, const float in) { - switch (outByIn.size()) { - case 0: - return in; - case 1: - return outByIn.at(0); - } - MOZ_ASSERT(outByIn.size() >= 2); - const auto begin = outByIn.begin(); - - const auto in0i = size_t(floorf(in * (outByIn.size() - 1))); - const auto out0_itr = begin + std::min(in0i, outByIn.size() - 2); - - const auto in0 = float(out0_itr - begin) / (outByIn.size() - 1); - const auto out0 = *out0_itr; - const auto d_in = float(1) / (outByIn.size() - 1); - const auto d_out = *(out0_itr + 1) - *out0_itr; - - const auto out = out0 + (d_out / d_in) * (in - in0); - // printf("SampleOutByIn(%f)->%f\n", in, out); - return out; -} - -template <class C> -inline float SampleInByOut(const C& outByIn, const float out) { - MOZ_ASSERT(outByIn.size() >= 2); - const auto begin = outByIn.begin(); - - const auto out0_itr = std::lower_bound(begin + 1, outByIn.end() - 1, out) - 1; - - const auto in0 = float(out0_itr - begin) / (outByIn.size() - 1); - const auto out0 = *out0_itr; - const auto d_in = float(1) / (outByIn.size() - 1); - const auto d_out = *(out0_itr + 1) - *out0_itr; - - // printf("%f + (%f / %f) * (%f - %f)\n", in0, d_in, d_out, out, out0); - const auto in = in0 + (d_in / d_out) * (out - out0); - // printf("SampleInByOut(%f)->%f\n", out, in); - return in; -} - -template <class C, class FnLessEqualT = std::less_equal<typename C::value_type>> -inline bool IsMonotonic(const C& vals, const FnLessEqualT& LessEqual = {}) { - bool ok = true; - const auto begin = vals.begin(); - for (size_t i = 1; i < vals.size(); i++) { - const auto itr = begin + i; - ok &= LessEqual(*(itr - 1), *itr); - // Assert(true, [&]() { - // return prints("[%zu]->%f <= [%zu]->%f", i-1, *(itr-1), i, *itr); - // }); - } - return ok; -} - -template <class T, class I> -inline std::optional<I> SeekNeq(const T& ref, const I first, const I last) { - const auto inc = (last - first) > 0 ? 1 : -1; - auto itr = first; - while (true) { - if (*itr != ref) return itr; - if (itr == last) return {}; - itr += inc; - } -} - -template <class T> -struct TwoPoints { - struct { - T x; - T y; - } p0; - struct { - T x; - T y; - } p1; - - T y(const T x) const { - const auto dx = p1.x - p0.x; - const auto dy = p1.y - p0.y; - return p0.y + dy / dx * (x - p0.x); - } -}; - -/// Fills `vals` with `x:[0..vals.size()-1] => line.y(x)`. -template <class T> -static void LinearFill(T& vals, const TwoPoints<float>& line) { - float x = -1; - for (auto& val : vals) { - x += 1; - val = line.y(x); - } -} - -// - - -inline void DequantizeMonotonic(const Span<float> vals) { - MOZ_ASSERT(IsMonotonic(vals)); - - const auto first = vals.begin(); - const auto end = vals.end(); - if (first == end) return; - const auto last = end - 1; - if (first == last) return; - - // Three monotonic cases: - // 1. [0,0,0,0] - // 2. [0,0,1,1] - // 3. [0,1,1,2] - - const auto body_first = SeekNeq(*first, first, last); - if (!body_first) { - // E.g. [0,0,0,0] - return; - } - - const auto body_last = SeekNeq(*last, last, *body_first); - if (!body_last) { - // E.g. [0,0,1,1] - // This isn't the most accurate, but close enough. - // print("#2: %s", to_str(vals).c_str()); - LinearFill(vals, { - {0, *first}, - {float(vals.size() - 1), *last}, - }); - // print(" -> %s\n", to_str(vals).c_str()); - return; - } - - // E.g. [0,1,1,2] - // ^^^ body - // => f(0.5)->0.5, f(2.5)->1.5 - // => f(x) = f(x0) + (x-x0) * (f(x1) - f(x0)) / (x1-x0) - // => f(x) = f(x0) + (x-x0) * dfdx - - const auto head_end = *body_first; - const auto head = vals.subspan(0, head_end - vals.begin()); - const auto tail_begin = *body_last + 1; - const auto tail = vals.subspan(tail_begin - vals.begin()); - // print("head tail: %s %s\n", - // to_str(head).c_str(), - // to_str(tail).c_str()); - - // const auto body = vals->subspan(head.size(), vals->size()-tail.size()); - auto next_part_first = head_end; - while (next_part_first != tail_begin) { - const auto part_first = next_part_first; - // print("part_first: %f\n", *part_first); - next_part_first = *SeekNeq(*part_first, part_first, tail_begin); - // print("next_part_first: %f\n", *next_part_first); - const auto part = - Span<float>{part_first, size_t(next_part_first - part_first)}; - // print("part: %s\n", to_str(part).c_str()); - const auto prev_part_last = part_first - 1; - const auto part_last = next_part_first - 1; - const auto line = TwoPoints<float>{ - {-0.5, (*prev_part_last + *part_first) / 2}, - {part.size() - 0.5f, (*part_last + *next_part_first) / 2}, - }; - LinearFill(part, line); - } - - static constexpr bool INFER_HEAD_TAIL_FROM_BODY_EDGE = false; - // Basically ignore contents of head and tail, and infer from edges of body. - // print("3: %s\n", to_str(vals).c_str()); - if (!IsMonotonic(head, std::less<float>{})) { - if (!INFER_HEAD_TAIL_FROM_BODY_EDGE) { - LinearFill(head, - { - {0, *head.begin()}, - {head.size() - 0.5f, (*(head.end() - 1) + *head_end) / 2}, - }); - } else { - LinearFill(head, { - {head.size() + 0.0f, *head_end}, - {head.size() + 1.0f, *(head_end + 1)}, - }); - } - } - if (!IsMonotonic(tail, std::less<float>{})) { - if (!INFER_HEAD_TAIL_FROM_BODY_EDGE) { - LinearFill(tail, { - {-0.5, (*(tail_begin - 1) + *tail.begin()) / 2}, - {tail.size() - 1.0f, *(tail.end() - 1)}, - }); - } else { - LinearFill(tail, { - {-2.0f, *(tail_begin - 2)}, - {-1.0f, *(tail_begin - 1)}, - }); - } - } - // print("3: %s\n", to_str(vals).c_str()); - MOZ_ASSERT(IsMonotonic(vals, std::less<float>{})); - - // Rescale, because we tend to lose range. - static constexpr bool RESCALE = false; - if (RESCALE) { - const auto firstv = *first; - const auto lastv = *last; - for (auto& val : vals) { - val = (val - firstv) / (lastv - firstv); - } - } - // print("4: %s\n", to_str(vals).c_str()); -} - -template <class In, class Out> -static void InvertLut(const In& lut, Out* const out_invertedLut) { - MOZ_ASSERT(IsMonotonic(lut)); - auto plut = &lut; - auto vec = std::vector<float>{}; - if (!IsMonotonic(lut, std::less<float>{})) { - // print("Not strictly monotonic...\n"); - vec.assign(lut.begin(), lut.end()); - DequantizeMonotonic(vec); - plut = &vec; - // print(" Now strictly monotonic: %i: %s\n", - // int(IsMonotonic(*plut, std::less<float>{})), to_str(*plut).c_str()); - MOZ_ASSERT(IsMonotonic(*plut, std::less<float>{})); - } - MOZ_ASSERT(plut->size() >= 2); - - auto& ret = *out_invertedLut; - for (size_t i_out = 0; i_out < ret.size(); i_out++) { - const auto f_out = i_out / float(ret.size() - 1); - const auto f_in = SampleInByOut(*plut, f_out); - ret[i_out] = f_in; - } - - MOZ_ASSERT(IsMonotonic(ret)); - MOZ_ASSERT(IsMonotonic(ret, std::less<float>{})); -} - -// - - -struct ColorProfileConversionDesc { - // ICC profiles are phrased as PCS-from-encoded (PCS is CIEXYZ-D50) - color::mat4 srcRgbFromSrcYuv = color::mat4::Identity(); - RgbTransferTables srcLinearFromSrcTf; - color::mat3 dstLinearFromSrcLinear = color::mat3::Identity(); - RgbTransferTables dstTfFromDstLinear; - - struct FromDesc { - ColorProfileDesc src; - ColorProfileDesc dst; - }; - static ColorProfileConversionDesc From(const FromDesc&); - - vec3 Apply(const vec3 src) const { - const auto srcRgb = vec3(srcRgbFromSrcYuv * vec4(src, 1)); - const auto srcLinear = vec3{{ - SampleOutByIn(srcLinearFromSrcTf.r, srcRgb.x()), - SampleOutByIn(srcLinearFromSrcTf.g, srcRgb.y()), - SampleOutByIn(srcLinearFromSrcTf.b, srcRgb.z()), - }}; - const auto dstLinear = dstLinearFromSrcLinear * srcLinear; - const auto dstRgb = vec3{{ - SampleOutByIn(dstTfFromDstLinear.r, dstLinear.x()), - SampleOutByIn(dstTfFromDstLinear.g, dstLinear.y()), - SampleOutByIn(dstTfFromDstLinear.b, dstLinear.z()), - }}; - return dstRgb; - } -}; - } // namespace mozilla::color #undef ASSERT diff --git a/gfx/gl/gtest/TestColorspaces.cpp b/gfx/gl/gtest/TestColorspaces.cpp index c437e204af020..af204c7fc913c 100644 --- a/gfx/gl/gtest/TestColorspaces.cpp +++ b/gfx/gl/gtest/TestColorspaces.cpp @@ -6,14 +6,12 @@ #include "gtest/gtest.h" #include "Colorspaces.h" -#include <array> #include <limits> namespace mozilla::color { mat4 YuvFromYcbcr(const YcbcrDesc&); float TfFromLinear(const PiecewiseGammaDesc&, float linear); float LinearFromTf(const PiecewiseGammaDesc&, float tf); -mat3 XyzFromLinearRgb(const Chromaticities&); } // namespace mozilla::color using namespace mozilla::color; @@ -316,24 +314,6 @@ TEST(Colorspaces, SrgbFromDisplayP3) // - -template <class Fn, class Tuple, size_t... I> -constexpr auto map_tups_seq(const Tuple& a, const Tuple& b, const Fn& fn, - std::index_sequence<I...>) { - return std::tuple{fn(std::get<I>(a), std::get<I>(b))...}; -} -template <class Fn, class Tuple> -constexpr auto map_tups(const Tuple& a, const Tuple& b, const Fn& fn) { - return map_tups_seq(a, b, fn, - std::make_index_sequence<std::tuple_size_v<Tuple>>{}); -} - -template <class Fn, class Tuple> -constexpr auto cmp_tups_all(const Tuple& a, const Tuple& b, const Fn& fn) { - bool all = true; - map_tups(a, b, [&](const auto& a, const auto& b) { return all &= fn(a, b); }); - return all; -} - struct Stats { double mean = 0; double variance = 0; @@ -349,7 +329,6 @@ struct Stats { ret.max = std::max(ret.max, cur); } ret.mean /= iterable.size(); - // Gather mean first before we can calc variance. for (const auto& cur : iterable) { ret.variance += pow(cur - ret.mean, 2); } @@ -357,61 +336,8 @@ struct Stats { return ret; } - template <class T, class U> - static Stats Diff(const T& a, const U& b) { - MOZ_ASSERT(a.size() == b.size()); - std::vector<double> diff; - diff.reserve(a.size()); - for (size_t i = 0; i < diff.capacity(); i++) { - diff.push_back(a[i] - b[i]); - } - return Stats::For(diff); - } - double standardDeviation() const { return sqrt(variance); } - - friend std::ostream& operator<<(std::ostream& s, const Stats& a) { - return s << "Stats" - << "{ mean:" << a.mean << ", stddev:" << a.standardDeviation() - << ", min:" << a.min << ", max:" << a.max << " }"; - } - - struct Error { - double absmean = std::numeric_limits<double>::infinity(); - double stddev = std::numeric_limits<double>::infinity(); - double absmax = std::numeric_limits<double>::infinity(); - - constexpr auto Fields() const { return std::tie(absmean, stddev, absmax); } - - template <class Fn> - friend constexpr bool cmp_all(const Error& a, const Error& b, - const Fn& fn) { - return cmp_tups_all(a.Fields(), b.Fields(), fn); - } - friend constexpr bool operator<(const Error& a, const Error& b) { - return cmp_all(a, b, [](const auto& a, const auto& b) { return a < b; }); - } - friend constexpr bool operator<=(const Error& a, const Error& b) { - return cmp_all(a, b, [](const auto& a, const auto& b) { return a <= b; }); - } - - friend std::ostream& operator<<(std::ostream& s, const Error& a) { - return s << "Stats::Error" - << "{ absmean:" << a.absmean << ", stddev:" << a.stddev - << ", absmax:" << a.absmax << " }"; - } - }; - - operator Error() const { - return {abs(mean), standardDeviation(), std::max(abs(min), abs(max))}; - } }; -static_assert(Stats::Error{0, 0, 0} < Stats::Error{1, 1, 1}); -static_assert(!(Stats::Error{0, 1, 0} < Stats::Error{1, 1, 1})); -static_assert(Stats::Error{0, 1, 0} <= Stats::Error{1, 1, 1}); -static_assert(!(Stats::Error{0, 2, 0} <= Stats::Error{1, 1, 1})); - -// - static Stats StatsForLutError(const ColorspaceTransform& ct, const ivec3 srcQuants, const ivec3 dstQuants) { @@ -477,222 +403,3 @@ TEST(Colorspaces, LutError_Rec709Full_Srgb) EXPECT_NEAR(stats.min, 0, 0.001); EXPECT_NEAR(stats.max, 17, 0.001); } - -// - -// https://www.reedbeta.com/blog/python-like-enumerate-in-cpp17/ - -template <typename T, typename TIter = decltype(std::begin(std::declval<T>())), - typename = decltype(std::end(std::declval<T>()))> -constexpr auto enumerate(T&& iterable) { - struct iterator { - size_t i; - TIter iter; - bool operator!=(const iterator& other) const { return iter != other.iter; } - void operator++() { - ++i; - ++iter; - } - auto operator*() const { return std::tie(i, *iter); } - }; - struct iterable_wrapper { - T iterable; - auto begin() { return iterator{0, std::begin(iterable)}; } - auto end() { return iterator{0, std::end(iterable)}; } - }; - return iterable_wrapper{std::forward<T>(iterable)}; -} - -inline auto MakeLinear(const float from, const float to, const int n) { - std::vector<float> ret; - ret.resize(n); - for (auto [i, val] : enumerate(ret)) { - const auto t = i / float(ret.size() - 1); - val = from + (to - from) * t; - } - return ret; -}; - -inline auto MakeGamma(const float exp, const int n) { - std::vector<float> ret; - ret.resize(n); - for (auto [i, val] : enumerate(ret)) { - const auto t = i / float(ret.size() - 1); - val = powf(t, exp); - } - return ret; -}; - -// - - -TEST(Colorspaces, GuessGamma) -{ - EXPECT_NEAR(GuessGamma(MakeGamma(1, 11)), 1.0, 0); - EXPECT_NEAR(GuessGamma(MakeGamma(2.2, 11)), 2.2, 4.8e-8); - EXPECT_NEAR(GuessGamma(MakeGamma(1 / 2.2, 11)), 1 / 2.2, 1.7e-7); -} - -// - - -template <class T, class U> -float StdDev(const T& test, const U& ref) { - float sum = 0; - for (size_t i = 0; i < test.size(); i++) { - const auto diff = test[i] - ref[i]; - sum += diff * diff; - } - const auto variance = sum / test.size(); - return sqrt(variance); -} - -template <class T> -inline void AutoLinearFill(T& vals) { - LinearFill(vals, { - {0, 0}, - {vals.size() - 1.0f, 1}, - }); -} - -template <class T, class... More> -auto MakeArray(const T& a0, const More&... args) { - return std::array<T, 1 + sizeof...(More)>{a0, static_cast<float>(args)...}; -} - -TEST(Colorspaces, LinearFill) -{ - EXPECT_NEAR(StdDev(MakeLinear(0, 1, 3), MakeArray<float>(0, 0.5, 1)), 0, - 0.001); - - auto vals = std::vector<float>(3); - LinearFill(vals, { - {0, 0}, - {vals.size() - 1.0f, 1}, - }); - EXPECT_NEAR(StdDev(vals, MakeArray<float>(0, 0.5, 1)), 0, 0.001); - - LinearFill(vals, { - {0, 1}, - {vals.size() - 1.0f, 0}, - }); - EXPECT_NEAR(StdDev(vals, MakeArray<float>(1, 0.5, 0)), 0, 0.001); -} - -TEST(Colorspaces, DequantizeMonotonic) -{ - auto orig = std::vector<float>{0, 0, 0, 1, 1, 2}; - auto vals = orig; - EXPECT_TRUE(IsMonotonic(vals)); - EXPECT_TRUE(!IsMonotonic(vals, std::less<float>{})); - DequantizeMonotonic(vals); - EXPECT_TRUE(IsMonotonic(vals, std::less<float>{})); - EXPECT_LT(StdDev(vals, orig), - StdDev(MakeLinear(orig.front(), orig.back(), vals.size()), orig)); -} - -TEST(Colorspaces, InvertLut) -{ - const auto linear = MakeLinear(0, 1, 256); - auto linearFromSrgb = linear; - for (auto& val : linearFromSrgb) { - val = powf(val, 2.2); - } - auto srgbFromLinearExpected = linear; - for (auto& val : srgbFromLinearExpected) { - val = powf(val, 1 / 2.2); - } - - auto srgbFromLinearViaInvert = linearFromSrgb; - InvertLut(linearFromSrgb, &srgbFromLinearViaInvert); - // I just want to appreciate that InvertLut is a non-analytical approximation, - // and yet it's extraordinarily close to the analytical inverse. - EXPECT_LE(Stats::Diff(srgbFromLinearViaInvert, srgbFromLinearExpected), - (Stats::Error{3e-6, 3e-6, 3e-5})); - - const auto srcSrgb = MakeLinear(0, 1, 256); - auto roundtripSrgb = srcSrgb; - for (auto& srgb : roundtripSrgb) { - const auto linear = SampleOutByIn(linearFromSrgb, srgb); - const auto srgb2 = SampleOutByIn(srgbFromLinearViaInvert, linear); - // printf("[%f] %f -> %f -> %f\n", srgb2-srgb, srgb, linear, srgb2); - srgb = srgb2; - } - EXPECT_LE(Stats::Diff(roundtripSrgb, srcSrgb), - (Stats::Error{0.0013, 0.0046, 0.023})); -} - -TEST(Colorspaces, XyzFromLinearRgb) -{ - const auto xyzd65FromLinearRgb = XyzFromLinearRgb(Chromaticities::Srgb()); - - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const auto XYZD65_FROM_LINEAR_RGB = mat3({ - vec3{{0.4124564, 0.3575761, 0.1804375}}, - vec3{{0.2126729, 0.7151522, 0.0721750}}, - vec3{{0.0193339, 0.1191920, 0.9503041}}, - }); - EXPECT_NEAR(sqrt(dotDifference(xyzd65FromLinearRgb, XYZD65_FROM_LINEAR_RGB)), - 0, 0.001); -} - -TEST(Colorspaces, ColorProfileConversionDesc_SrgbFromRec709) -{ - const auto srgb = ColorProfileDesc::From({ - Chromaticities::Srgb(), - PiecewiseGammaDesc::Srgb(), - }); - const auto rec709 = ColorProfileDesc::From({ - Chromaticities::Rec709(), - PiecewiseGammaDesc::Rec709(), - }); - - { - const auto conv = ColorProfileConversionDesc::From({ - .src = srgb, - .dst = srgb, - }); - auto src = vec3(16.0); - auto dst = conv.Apply(src / 255) * 255; - - const auto tfa = PiecewiseGammaDesc::Srgb(); - const auto tfb = PiecewiseGammaDesc::Srgb(); - const auto expected = - TfFromLinear(tfb, LinearFromTf(tfa, src.x() / 255)) * 255; - - printf("%f %f %f\n", src.x(), src.y(), src.z()); - printf("%f %f %f\n", dst.x(), dst.y(), dst.z()); - EXPECT_LT(Stats::Diff(dst.data, vec3(expected).data), (Stats::Error{0.42})); - } - { - const auto conv = ColorProfileConversionDesc::From({ - .src = rec709, - .dst = rec709, - }); - auto src = vec3(16.0); - auto dst = conv.Apply(src / 255) * 255; - - const auto tfa = PiecewiseGammaDesc::Rec709(); - const auto tfb = PiecewiseGammaDesc::Rec709(); - const auto expected = - TfFromLinear(tfb, LinearFromTf(tfa, src.x() / 255)) * 255; - - printf("%f %f %f\n", src.x(), src.y(), src.z()); - printf("%f %f %f\n", dst.x(), dst.y(), dst.z()); - EXPECT_LT(Stats::Diff(dst.data, vec3(expected).data), (Stats::Error{1e-6})); - } - { - const auto conv = ColorProfileConversionDesc::From({ - .src = rec709, - .dst = srgb, - }); - auto src = vec3(16.0); - auto dst = conv.Apply(src / 255) * 255; - - const auto tfa = PiecewiseGammaDesc::Rec709(); - const auto tfb = PiecewiseGammaDesc::Srgb(); - const auto expected = - TfFromLinear(tfb, LinearFromTf(tfa, src.x() / 255)) * 255; - printf("expected: %f\n", expected); - printf("%f %f %f\n", src.x(), src.y(), src.z()); - printf("%f %f %f\n", dst.x(), dst.y(), dst.z()); - EXPECT_LT(Stats::Diff(dst.data, vec3(expected).data), (Stats::Error{0.12})); - } -} diff --git a/gfx/qcms/qcms.h b/gfx/qcms/qcms.h index c23346006cd30..380d0f48026a4 100644 --- a/gfx/qcms/qcms.h +++ b/gfx/qcms/qcms.h @@ -11,35 +11,35 @@ extern "C" { #ifndef ICC_H /* icc34 defines */ -/***************************************************************** +/***************************************************************** Copyright (c) 1994-1996 SunSoft, Inc. Rights Reserved -Permission is hereby granted, free of charge, to any person +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without restrict- -ion, including without limitation the rights to use, copy, modify, -merge, publish distribute, sublicense, and/or sell copies of the -Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +files (the "Software"), to deal in the Software without restrict- +ion, including without limitation the rights to use, copy, modify, +merge, publish distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON- -INFRINGEMENT. IN NO EVENT SHALL SUNSOFT, INC. OR ITS PARENT -COMPANY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of SunSoft, Inc. -shall not be used in advertising or otherwise to promote the -sale, use or other dealings in this Software without written -authorization from SunSoft Inc. +INFRINGEMENT. IN NO EVENT SHALL SUNSOFT, INC. OR ITS PARENT +COMPANY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of SunSoft, Inc. +shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without written +authorization from SunSoft Inc. ******************************************************************/ /* @@ -48,11 +48,11 @@ authorization from SunSoft Inc. * don't use the same objects on different threads at the same time. */ -/* +/* * Color Space Signatures * Note that only icSigXYZData and icSigLabData are valid * Profile Connection Spaces (PCSs) - */ + */ typedef enum { icSigXYZData = 0x58595A20L, /* 'XYZ ' */ icSigLabData = 0x4C616220L, /* 'Lab ' */ @@ -79,13 +79,12 @@ typedef enum { icSig13colorData = 0x44434C52L, /* 'DCLR' */ icSig14colorData = 0x45434C52L, /* 'ECLR' */ icSig15colorData = 0x46434C52L, /* 'FCLR' */ - icMaxEnumData = 0xFFFFFFFFL + icMaxEnumData = 0xFFFFFFFFL } icColorSpaceSignature; #endif #include <stdio.h> #include <stdbool.h> -#include <cstdint> struct _qcms_transform; typedef struct _qcms_transform qcms_transform; @@ -197,42 +196,6 @@ void qcms_enable_iccv4(); void qcms_enable_neon(); void qcms_enable_avx(); - - -// - -/* -struct qcms_mat3r3 { - struct row { - float cols[3]; - }; - row rows[3]; -}; -*/ -struct qcms_profile_data { - uint32_t class_type; - uint32_t color_space; - uint32_t pcs; - qcms_intent rendering_intent; - float red_colorant_xyzd50[3]; - float blue_colorant_xyzd50[3]; - float green_colorant_xyzd50[3]; - int32_t linear_from_trc_red_samples; - int32_t linear_from_trc_blue_samples; - int32_t linear_from_trc_green_samples; -}; - -void qcms_profile_get_data(const qcms_profile*, qcms_profile_data* out_data); - - -enum class qcms_color_channel : uint8_t { - Red, - Green, - Blue, -}; - -void qcms_profile_get_lut(const qcms_profile*, qcms_color_channel, - float* begin, float* end); - #ifdef __cplusplus } #endif diff --git a/gfx/qcms/src/c_bindings.rs b/gfx/qcms/src/c_bindings.rs index efe6674fe5a5a..ba0431f675b05 100644 --- a/gfx/qcms/src/c_bindings.rs +++ b/gfx/qcms/src/c_bindings.rs @@ -7,11 +7,9 @@ use libc::{fclose, fopen, fread, free, malloc, memset, FILE}; use crate::{ double_to_s15Fixed16Number, iccread::*, - s15Fixed16Number_to_float, transform::get_rgb_colorants, transform::DataType, transform::{qcms_transform, transform_create}, - transform_util, Intent, }; @@ -377,124 +375,6 @@ pub unsafe extern "C" fn qcms_transform_data( length, ); } -/* -use crate::matrix; -#[repr(C)] -#[derive(Clone, Debug, Default)] -pub struct qcms_mat3r3 { - pub rows: [[f32; 3] ; 3], -} -impl qcms_mat3r3 { - fn from(m: matrix::Matrix) -> qcms_mat3r3 { - qcms_mat3r3{ - rows: [ - m.row(0), - m.row(1), - m.row(2), - ], - } - } -} -*/ -#[repr(C)] -#[derive(Clone, Debug, Default)] -#[allow(clippy::upper_case_acronyms)] -pub struct qcms_profile_data { - pub class_type: u32, - pub color_space: u32, - pub pcs: u32, - pub rendering_intent: Intent, - pub red_colorant_xyzd50: [f32; 3], - pub blue_colorant_xyzd50: [f32; 3], - pub green_colorant_xyzd50: [f32; 3], - // Number of samples in the e.g. gamma->linear LUT. - pub linear_from_trc_red_samples: i32, - pub linear_from_trc_blue_samples: i32, - pub linear_from_trc_green_samples: i32, -} - -pub use crate::iccread::Profile as qcms_profile; - -#[no_mangle] -pub extern "C" fn qcms_profile_get_data( - profile: &qcms_profile, - out_data: &mut qcms_profile_data, -) { - out_data.class_type = profile.class_type; - out_data.color_space = profile.color_space; - out_data.pcs = profile.pcs; - out_data.rendering_intent = profile.rendering_intent; - - fn colorant(c: &XYZNumber) -> [f32;3] { - [c.X, c.Y, c.Z].map(s15Fixed16Number_to_float) - } - out_data.red_colorant_xyzd50 = colorant(&profile.redColorant); - out_data.blue_colorant_xyzd50 = colorant(&profile.blueColorant); - out_data.green_colorant_xyzd50 = colorant(&profile.greenColorant); - - fn trc_to_samples(trc: &Option<Box<curveType>>) -> i32 { - if let Some(ref trc) = *trc { - match &**trc { - curveType::Curve(v) => { - let len = v.len(); - if len <= 1 { - -1 - } else { - len as i32 - } - }, - curveType::Parametric(_) => -1, - } - } else { - 0 - } - } - out_data.linear_from_trc_red_samples = trc_to_samples(&profile.redTRC); - out_data.linear_from_trc_blue_samples = trc_to_samples(&profile.blueTRC); - out_data.linear_from_trc_green_samples = trc_to_samples(&profile.greenTRC); -} - -#[repr(u8)] -pub enum qcms_color_channel { - Red, - Green, - Blue, -} - -#[no_mangle] -pub extern "C" fn qcms_profile_get_lut( - profile: &qcms_profile, - channel: qcms_color_channel, // FYI: UB if you give Rust something out of range! - out_begin: *mut f32, - out_end: *mut f32, -) { - let out_slice = unsafe { - std::slice::from_raw_parts_mut(out_begin, out_end.offset_from(out_begin) as usize) - }; - - let trc = match channel { - qcms_color_channel::Red => &profile.redTRC, - qcms_color_channel::Green => &profile.greenTRC, - qcms_color_channel::Blue => &profile.blueTRC, - }; - - let samples_u16 = if let Some(trc) = trc { - let trc = &*trc; - // Yes, sub-optimal, but easier to implement, and these aren't big or hot: - // 1. Ask for a new vec<u16> lut based on the trc. - // * (eat the extra alloc) - // 2. Convert the u16s back out to f32s in our slice. - // * (eat the copy and quantization error from f32->u16->f32 roundtrip) - transform_util::build_lut_for_linear_from_tf(trc, Some(out_slice.len())) - } else { - Vec::new() - }; - - assert_eq!(samples_u16.len(), out_slice.len()); - for (d, s) in out_slice.iter_mut().zip(samples_u16.into_iter()) { - *d = (s as f32) / (u16::MAX as f32); - } -} pub type icColorSpaceSignature = u32; pub const icSigGrayData: icColorSpaceSignature = 0x47524159; // 'GRAY' @@ -502,6 +382,7 @@ pub const icSigRgbData: icColorSpaceSignature = 0x52474220; // 'RGB ' pub const icSigCmykData: icColorSpaceSignature = 0x434d594b; // 'CMYK' pub use crate::iccread::qcms_profile_is_bogus; +pub use crate::iccread::Profile as qcms_profile; pub use crate::transform::{ qcms_enable_iccv4, qcms_profile_precache_output_transform, qcms_transform_release, }; diff --git a/gfx/qcms/src/iccread.rs b/gfx/qcms/src/iccread.rs index d86e9742d4b19..67cc1d38ffe3d 100644 --- a/gfx/qcms/src/iccread.rs +++ b/gfx/qcms/src/iccread.rs @@ -50,8 +50,6 @@ pub struct Profile { pub(crate) redColorant: XYZNumber, pub(crate) blueColorant: XYZNumber, pub(crate) greenColorant: XYZNumber, - // "TRC" is EOTF, e.g. gamma->linear transfer function. - // Because ICC profiles are phrased as decodings to the xyzd50-linear PCS. pub(crate) redTRC: Option<Box<curveType>>, pub(crate) blueTRC: Option<Box<curveType>>, pub(crate) greenTRC: Option<Box<curveType>>, @@ -95,7 +93,7 @@ pub(crate) struct lutmABType { } #[derive(Clone, Debug)] pub(crate) enum curveType { - Curve(Vec<uInt16Number>), // len=0 => Linear, len=1 => Gamma(v[0]), _ => lut + Curve(Vec<uInt16Number>), /// The ICC parametricCurveType is specified in terms of s15Fixed16Number, /// so it's possible to use this variant to specify greater precision than /// any raw ICC profile could diff --git a/gfx/qcms/src/lib.rs b/gfx/qcms/src/lib.rs index c311964ee3f49..25b18ad1bb53c 100644 --- a/gfx/qcms/src/lib.rs +++ b/gfx/qcms/src/lib.rs @@ -11,11 +11,10 @@ #![cfg_attr( feature = "neon", feature(arm_target_feature, raw_ref_op) - )] /// These values match the Rendering Intent values from the ICC spec -#[repr(C)] +#[repr(u32)] #[derive(Clone, Copy, Debug)] pub enum Intent { AbsoluteColorimetric = 3, diff --git a/gfx/qcms/src/matrix.rs b/gfx/qcms/src/matrix.rs index 8cd450241ef0c..4793f38071a92 100644 --- a/gfx/qcms/src/matrix.rs +++ b/gfx/qcms/src/matrix.rs @@ -22,7 +22,7 @@ #[derive(Copy, Clone, Debug, Default)] pub struct Matrix { - pub m: [[f32; 3]; 3], // Three rows of three elems. + pub m: [[f32; 3]; 3], } #[derive(Copy, Clone)] @@ -39,10 +39,6 @@ impl Matrix { result } - pub fn row(&self, r: usize) -> [f32; 3] { - self.m[r] - } - //probably reuse this computation in matrix_invert pub fn det(&self) -> f32 { let det: f32 = self.m[0][0] * self.m[1][1] * self.m[2][2] diff --git a/gfx/qcms/src/transform_util.rs b/gfx/qcms/src/transform_util.rs index 75fd2ca0e2c07..5c198010539e7 100644 --- a/gfx/qcms/src/transform_util.rs +++ b/gfx/qcms/src/transform_util.rs @@ -440,10 +440,10 @@ invert_lut will produce an inverse of: which has an maximum error of about 9855 (pixel difference of ~38.346) For now, we punt the decision of output size to the caller. */ -fn invert_lut(table: &[u16], out_length: usize) -> Vec<u16> { +fn invert_lut(table: &[u16], out_length: i32) -> Vec<u16> { /* for now we invert the lut by creating a lut of size out_length * and attempting to lookup a value for each entry using lut_inverse_interp16 */ - let mut output = Vec::with_capacity(out_length); + let mut output = Vec::with_capacity(out_length as usize); for i in 0..out_length { let x: f64 = i as f64 * 65535.0f64 / (out_length - 1) as f64; let input: uint16_fract_t = (x + 0.5f64).floor() as uint16_fract_t; @@ -476,7 +476,7 @@ pub(crate) fn compute_precache(trc: &curveType, output: &mut [u8; PRECACHE_OUTPU curveType::Parametric(params) => { let mut gamma_table_uint: [u16; 256] = [0; 256]; - let mut inverted_size: usize = 256; + let mut inverted_size: i32 = 256; let gamma_table = compute_curve_gamma_table_type_parametric(params); let mut i: u16 = 0u16; while (i as i32) < 256 { @@ -498,7 +498,7 @@ pub(crate) fn compute_precache(trc: &curveType, output: &mut [u8; PRECACHE_OUTPU 0 => compute_precache_linear(output), 1 => compute_precache_pow(output, 1. / u8Fixed8Number_to_float(data[0])), _ => { - let mut inverted_size = data.len(); + let mut inverted_size = data.len() as i32; //XXX: the choice of a minimum of 256 here is not backed by any theory, // measurement or data, however it is what lcms uses. // the maximum number we would need is 65535 because that's the @@ -514,8 +514,8 @@ pub(crate) fn compute_precache(trc: &curveType, output: &mut [u8; PRECACHE_OUTPU } true } -fn build_linear_table(length: usize) -> Vec<u16> { - let mut output = Vec::with_capacity(length); +fn build_linear_table(length: i32) -> Vec<u16> { + let mut output = Vec::with_capacity(length as usize); for i in 0..length { let x: f64 = i as f64 * 65535.0f64 / (length - 1) as f64; let input: uint16_fract_t = (x + 0.5f64).floor() as uint16_fract_t; @@ -523,8 +523,8 @@ fn build_linear_table(length: usize) -> Vec<u16> { } output } -fn build_pow_table(gamma: f32, length: usize) -> Vec<u16> { - let mut output = Vec::with_capacity(length); +fn build_pow_table(gamma: f32, length: i32) -> Vec<u16> { + let mut output = Vec::with_capacity(length as usize); for i in 0..length { let mut x: f64 = i as f64 / (length - 1) as f64; x = x.powf(gamma as f64); @@ -534,75 +534,36 @@ fn build_pow_table(gamma: f32, length: usize) -> Vec<u16> { output } -fn to_lut(params: &Param, len: usize) -> Vec<u16> { - let mut output = Vec::with_capacity(len); - for i in 0..len { - let X = i as f32 / (len-1) as f32; - output.push((params.eval(X) * 65535.) as u16); - } - output -} - -pub(crate) fn build_lut_for_linear_from_tf(trc: &curveType, - lut_len: Option<usize>) -> Vec<u16> { +pub(crate) fn build_output_lut(trc: &curveType) -> Option<Vec<u16>> { match trc { curveType::Parametric(params) => { - let lut_len = lut_len.unwrap_or(256); let params = Param::new(params); - to_lut(¶ms, lut_len) - }, - curveType::Curve(data) => { - let autogen_lut_len = lut_len.unwrap_or(4096); - match data.len() { - 0 => build_linear_table(autogen_lut_len), - 1 => { - let gamma = u8Fixed8Number_to_float(data[0]); - build_pow_table(gamma, autogen_lut_len) - } - _ => { - let lut_len = lut_len.unwrap_or(data.len()); - assert_eq!(lut_len, data.len()); - data.clone() // I feel bad about this. - } - } - }, - } -} + let inv_params = params.invert()?; -pub(crate) fn build_lut_for_tf_from_linear(trc: &curveType) -> Option<Vec<u16>> { - match trc { - curveType::Parametric(params) => { - let lut_len = 256; - let params = Param::new(params); - if let Some(inv_params) = params.invert() { - return Some(to_lut(&inv_params, lut_len)); + let mut output = Vec::with_capacity(256); + for i in 0..256 { + let X = i as f32 / 255.; + output.push((inv_params.eval(X) * 65535.) as u16); } - // else return None instead of fallthrough to generic lut inversion. - return None; - }, + Some(output) + } curveType::Curve(data) => { - let autogen_lut_len = 4096; match data.len() { - 0 => { - return Some(build_linear_table(autogen_lut_len)); - }, + 0 => Some(build_linear_table(4096)), 1 => { let gamma = 1. / u8Fixed8Number_to_float(data[0]); - return Some(build_pow_table(gamma, autogen_lut_len)); - }, - _ => {}, + Some(build_pow_table(gamma, 4096)) + } + _ => { + //XXX: the choice of a minimum of 256 here is not backed by any theory, + // measurement or data, however it is what lcms uses. + let mut output_gamma_lut_length = data.len(); + if output_gamma_lut_length < 256 { + output_gamma_lut_length = 256 + } + Some(invert_lut(data, output_gamma_lut_length as i32)) + } } - }, + } } - - let linear_from_tf = build_lut_for_linear_from_tf(trc, None); - - //XXX: the choice of a minimum of 256 here is not backed by any theory, - // measurement or data, however it is what lcms uses. - let inverted_lut_len = std::cmp::max(linear_from_tf.len(), 256); - Some(invert_lut(&linear_from_tf, inverted_lut_len)) -} - -pub(crate) fn build_output_lut(trc: &curveType) -> Option<Vec<u16>> { - build_lut_for_tf_from_linear(trc) } diff --git a/gfx/thebes/AllOfDcomp.h b/gfx/thebes/AllOfDcomp.h deleted file mode 100644 index bd4448b68baaf..0000000000000 --- a/gfx/thebes/AllOfDcomp.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_gfx_AllOfDcomp_h -#define mozilla_gfx_AllOfDcomp_h - -// Getting everything that we need in dcomp.h defined means messing with some -// defines. - -#if (_WIN32_WINNT < _WIN32_WINNT_WIN10) - -# define XSTR(x) STR(x) -# define STR(x) #x -// clang-format off - -# pragma message "IDCompositionFilterEffect in dcomp.h requires _WIN32_WINNT >= _WIN32_WINNT_WIN10." -// Pedantically, it actually requires _WIN32_WINNT_WINTHRESHOLD, but that's the -// same as _WIN32_WINNT_WIN10. - -# pragma message "Forcing NTDDI_VERSION " XSTR(NTDDI_VERSION) " -> " XSTR(NTDDI_WIN10) -# undef NTDDI_VERSION -# define NTDDI_VERSION NTDDI_WIN10 - -# pragma message "Forcing _WIN32_WINNT " XSTR(_WIN32_WINNT) " -> " XSTR(_WIN32_WINNT_WIN10) -# undef _WIN32_WINNT -# define _WIN32_WINNT _WIN32_WINNT_WIN10 - -// clang-format on -# undef STR -# undef XSTR - -#endif - -// - - -#include <dcomp.h> - -#endif // mozilla_gfx_AllOfDcomp_h diff --git a/gfx/thebes/DeviceManagerDx.cpp b/gfx/thebes/DeviceManagerDx.cpp index 100cd3192afc6..d8bfc0d43d1f6 100644 --- a/gfx/thebes/DeviceManagerDx.cpp +++ b/gfx/thebes/DeviceManagerDx.cpp @@ -25,10 +25,13 @@ #include "nsPrintfCString.h" #include "nsString.h" -// - +#undef _WIN32_WINNT +#define _WIN32_WINNT _WIN32_WINNT_WINBLUE +#undef NTDDI_VERSION +#define NTDDI_VERSION NTDDI_WINBLUE -#include "mozilla/gfx/AllOfDcomp.h" #include <d3d11.h> +#include <dcomp.h> #include <ddraw.h> #include <dxgi.h> @@ -47,7 +50,6 @@ decltype(D3D11CreateDevice)* sD3D11CreateDeviceFn = nullptr; // It should only be used within CreateDirectCompositionDevice. decltype(DCompositionCreateDevice2)* sDcompCreateDevice2Fn = nullptr; -decltype(DCompositionCreateDevice3)* sDcompCreateDevice3Fn = nullptr; // It should only be used within CreateDCompSurfaceHandle decltype(DCompositionCreateSurfaceHandle)* sDcompCreateSurfaceHandleFn = @@ -115,7 +117,7 @@ bool DeviceManagerDx::LoadDcomp() { MOZ_ASSERT(gfxVars::UseWebRenderDCompWin()); if (sDcompCreateDevice2Fn) { - return true; // Already loaded. + return true; } nsModuleHandle module(LoadLibrarySystem32(L"dcomp.dll")); @@ -125,8 +127,6 @@ bool DeviceManagerDx::LoadDcomp() { sDcompCreateDevice2Fn = (decltype(DCompositionCreateDevice2)*)GetProcAddress( module, "DCompositionCreateDevice2"); - sDcompCreateDevice3Fn = (decltype(DCompositionCreateDevice3)*)GetProcAddress( - module, "DCompositionCreateDevice3"); if (!sDcompCreateDevice2Fn) { return false; } @@ -135,6 +135,9 @@ bool DeviceManagerDx::LoadDcomp() { sDcompCreateSurfaceHandleFn = (decltype(DCompositionCreateSurfaceHandle)*)::GetProcAddress( module, "DCompositionCreateSurfaceHandle"); + if (!sDcompCreateDevice2Fn) { + return false; + } mDcompModule.steal(module); return true; @@ -445,16 +448,10 @@ void DeviceManagerDx::CreateDirectCompositionDeviceLocked() { HRESULT hr; RefPtr<IDCompositionDesktopDevice> desktopDevice; MOZ_SEH_TRY { - hr = sDcompCreateDevice3Fn( + hr = sDcompCreateDevice2Fn( dxgiDevice.get(), IID_PPV_ARGS( (IDCompositionDesktopDevice**)getter_AddRefs(desktopDevice))); - if (!desktopDevice) { - hr = sDcompCreateDevice2Fn( - dxgiDevice.get(), - IID_PPV_ARGS( - (IDCompositionDesktopDevice**)getter_AddRefs(desktopDevice))); - } } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { return; } diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 75c6d2b4fd72d..2d0b4f7d6d5ee 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -2034,10 +2034,15 @@ DeviceColor gfxPlatform::TransformPixel(const sRGBColor& in, return DeviceColor(in.r, in.g, in.b, in.a); } +nsTArray<uint8_t> gfxPlatform::GetPlatformCMSOutputProfileData() { + return GetPrefCMSOutputProfileData(); +} + nsTArray<uint8_t> gfxPlatform::GetPrefCMSOutputProfileData() { - const auto mirror = StaticPrefs::gfx_color_management_display_profile(); - const auto fname = *mirror; - if (fname == "") { + nsAutoCString fname; + Preferences::GetCString("gfx.color_management.display_profile", fname); + + if (fname.IsEmpty()) { return nsTArray<uint8_t>(); } diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index db9b8fd436027..b93d94603a580 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -753,9 +753,7 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener { * Returns a buffer containing the CMS output profile data. The way this * is obtained is platform-specific. */ - virtual nsTArray<uint8_t> GetPlatformCMSOutputProfileData() { - return GetPrefCMSOutputProfileData(); - } + virtual nsTArray<uint8_t> GetPlatformCMSOutputProfileData(); /** * Return information on how child processes should initialize graphics @@ -867,15 +865,13 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener { virtual void ImportContentDeviceData( const mozilla::gfx::ContentDeviceData& aData); - public: /** * Returns the contents of the file pointed to by the * gfx.color_management.display_profile pref, if set. * Returns an empty array if not set, or if an error occurs */ - static nsTArray<uint8_t> GetPrefCMSOutputProfileData(); + nsTArray<uint8_t> GetPrefCMSOutputProfileData(); - protected: /** * If inside a child process and currently being initialized by the * SetXPCOMProcessAttributes message, this can be used by subclasses to diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 6c88c524c8d77..a7194a81276a7 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -1036,21 +1036,16 @@ nsTArray<uint8_t> gfxWindowsPlatform::GetPlatformCMSOutputProfileData() { return result; } - return GetPlatformCMSOutputProfileData_Impl(); -} + if (!mCachedOutputColorProfile.IsEmpty()) { + return mCachedOutputColorProfile.Clone(); + } -nsTArray<uint8_t> gfxWindowsPlatform::GetPlatformCMSOutputProfileData_Impl() { - static nsTArray<uint8_t> sCached = [&] { - // Check override pref first: - nsTArray<uint8_t> prefProfileData = - gfxPlatform::GetPrefCMSOutputProfileData(); + mCachedOutputColorProfile = [&] { + nsTArray<uint8_t> prefProfileData = GetPrefCMSOutputProfileData(); if (!prefProfileData.IsEmpty()) { return prefProfileData; } - // - - // Otherwise, create a dummy DC and pull from that. - HDC dc = ::GetDC(nullptr); if (!dc) { return nsTArray<uint8_t>(); @@ -1083,7 +1078,7 @@ nsTArray<uint8_t> gfxWindowsPlatform::GetPlatformCMSOutputProfileData_Impl() { return result; }(); - return sCached.Clone(); + return mCachedOutputColorProfile.Clone(); } void gfxWindowsPlatform::GetDLLVersion(char16ptr_t aDLLPath, diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index 95315bcaa950b..a05b690c90eab 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -200,13 +200,7 @@ class gfxWindowsPlatform final : public gfxPlatform { protected: bool AccelerateLayersByDefault() override { return true; } - nsTArray<uint8_t> GetPlatformCMSOutputProfileData() override; - - public: - static nsTArray<uint8_t> GetPlatformCMSOutputProfileData_Impl(); - - protected: void GetPlatformDisplayInfo(mozilla::widget::InfoObject& aObj) override; void ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData) override; diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index 9a87ea6aa0b08..176cc3c7e5dba 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -67,7 +67,6 @@ EXPORTS += [ ] EXPORTS.mozilla.gfx += [ - "AllOfDcomp.h", "D3D11Checks.h", "DeviceManagerDx.h", "DisplayConfigWindows.h", diff --git a/gfx/webrender_bindings/DCLayerTree.cpp b/gfx/webrender_bindings/DCLayerTree.cpp index f6c0511202613..8d192ea091620 100644 --- a/gfx/webrender_bindings/DCLayerTree.cpp +++ b/gfx/webrender_bindings/DCLayerTree.cpp @@ -6,16 +6,6 @@ #include "DCLayerTree.h" -// - - -#include "mozilla/gfx/AllOfDcomp.h" -#include <d3d11.h> -#include <d3d11_1.h> -#include <dxgi1_2.h> - -// - - -#include "gfxWindowsPlatform.h" #include "GLContext.h" #include "GLContextEGL.h" #include "mozilla/gfx/DeviceManagerDx.h" @@ -33,15 +23,15 @@ #include "nsPrintfCString.h" #include "WinUtils.h" -// - +#undef _WIN32_WINNT +#define _WIN32_WINNT _WIN32_WINNT_WINBLUE +#undef NTDDI_VERSION +#define NTDDI_VERSION NTDDI_WINBLUE -#if defined(__MINGW32__) // 64 defines both 32 and 64 -// We need to fake some things, while we wait on updates to mingw's dcomp.h -// header. Just enough that we can successfully fail to work there. -# define MOZ_MINGW_DCOMP_H_INCOMPLETE -struct IDCompositionColorMatrixEffect : public IDCompositionFilterEffect {}; -struct IDCompositionTableTransferEffect : public IDCompositionFilterEffect {}; -#endif // defined(__MINGW32__) +#include <d3d11.h> +#include <d3d11_1.h> +#include <dcomp.h> +#include <dxgi1_2.h> namespace mozilla { namespace wr { @@ -577,16 +567,6 @@ void DCExternalSurfaceWrapper::AttachExternalImage( } } -template <class ToT> -struct QI { - template <class FromT> - [[nodiscard]] static inline RefPtr<ToT> From(FromT* const from) { - RefPtr<ToT> to; - (void)from->QueryInterface(static_cast<ToT**>(getter_AddRefs(to))); - return to; - } -}; - DCSurface* DCExternalSurfaceWrapper::EnsureSurfaceForExternalImage( wr::ExternalImageId aExternalImage) { if (mSurface) { @@ -611,117 +591,14 @@ DCSurface* DCExternalSurfaceWrapper::EnsureSurfaceForExternalImage( mSurface = nullptr; } } - if (!mSurface) { + + if (mSurface) { + // Add surface's visual which will contain video data to our root visual. + mVisual->AddVisual(mSurface->GetVisual(), TRUE, nullptr); + } else { gfxCriticalNote << "Failed to create a surface for external image: " << gfx::hexa(texture); - return nullptr; } - const auto textureSwgl = texture->AsRenderTextureHostSWGL(); - MOZ_ASSERT(textureSwgl); // Covered above. - - // Add surface's visual which will contain video data to our root visual. - const auto surfaceVisual = mSurface->GetVisual(); - mVisual->AddVisual(surfaceVisual, true, nullptr); - - // - - // Apply color management. - - [&]() { - const auto cmsMode = GfxColorManagementMode(); - if (cmsMode == CMSMode::Off) return; - - const auto dcomp = mDCLayerTree->GetCompositionDevice(); - const auto dcomp3 = QI<IDCompositionDevice3>::From(dcomp); - if (!dcomp3) { - NS_WARNING( - "No IDCompositionDevice3, cannot use dcomp for color management."); - return; - } - - // - - - const auto cspace = [&]() { - const auto rangedCspace = textureSwgl->GetYUVColorSpace(); - const auto info = FromYUVRangedColorSpace(rangedCspace); - auto ret = ToColorSpace2(info.space); - if (ret == gfx::ColorSpace2::Display && cmsMode == CMSMode::All) { - ret = gfx::ColorSpace2::SRGB; - } - return ret; - }(); - - const bool rec709GammaAsSrgb = - StaticPrefs::gfx_color_management_rec709_gamma_as_srgb(); - const bool rec2020GammaAsRec709 = - StaticPrefs::gfx_color_management_rec2020_gamma_as_rec709(); - - auto cspaceDesc = color::ColorspaceDesc{}; - switch (cspace) { - case gfx::ColorSpace2::Display: - return; // No color management needed! - case gfx::ColorSpace2::SRGB: - cspaceDesc.chrom = color::Chromaticities::Srgb(); - cspaceDesc.tf = color::PiecewiseGammaDesc::Srgb(); - break; - - case gfx::ColorSpace2::DISPLAY_P3: - cspaceDesc.chrom = color::Chromaticities::DisplayP3(); - cspaceDesc.tf = color::PiecewiseGammaDesc::DisplayP3(); - break; - - case gfx::ColorSpace2::BT601_525: - cspaceDesc.chrom = color::Chromaticities::Rec601_525_Ntsc(); - if (rec709GammaAsSrgb) { - cspaceDesc.tf = color::PiecewiseGammaDesc::Srgb(); - } else { - cspaceDesc.tf = color::PiecewiseGammaDesc::Rec709(); - } - break; - - case gfx::ColorSpace2::BT709: - cspaceDesc.chrom = color::Chromaticities::Rec709(); - if (rec709GammaAsSrgb) { - cspaceDesc.tf = color::PiecewiseGammaDesc::Srgb(); - } else { - cspaceDesc.tf = color::PiecewiseGammaDesc::Rec709(); - } - break; - - case gfx::ColorSpace2::BT2020: - cspaceDesc.chrom = color::Chromaticities::Rec2020(); - if (rec2020GammaAsRec709 && rec709GammaAsSrgb) { - cspaceDesc.tf = color::PiecewiseGammaDesc::Srgb(); - } else if (rec2020GammaAsRec709) { - cspaceDesc.tf = color::PiecewiseGammaDesc::Rec709(); - } else { - // Just Rec709 with slightly more precision. - cspaceDesc.tf = color::PiecewiseGammaDesc::Rec2020_12bit(); - } - break; - } - - const auto cprofileIn = color::ColorProfileDesc::From(cspaceDesc); - auto cprofileOut = mDCLayerTree->OutputColorProfile(); - bool pretendSrgb = StaticPrefs::gfx_color_management_native_srgb(); - if (pretendSrgb) { - cprofileOut = color::ColorProfileDesc::From({ - color::Chromaticities::Srgb(), - color::PiecewiseGammaDesc::Srgb(), - }); - } - const auto conversion = color::ColorProfileConversionDesc::From({ - .src = cprofileIn, - .dst = cprofileOut, - }); - - // - - - auto chain = ColorManagementChain::From(*dcomp3, conversion); - mCManageChain = Some(chain); - - surfaceVisual->SetEffect(mCManageChain->last.get()); - }(); - return mSurface.get(); } @@ -1714,119 +1591,6 @@ void DCLayerTree::DestroyEGLSurface() { } } -// - - -color::ColorProfileDesc DCLayerTree::QueryOutputColorProfile() { - // GPU process can't simply init gfxPlatform, (and we don't need most of it) - // but we do need gfxPlatform::GetCMSOutputProfile(). - // So we steal what we need through the window: - const auto outputProfileData = - gfxWindowsPlatform::GetPlatformCMSOutputProfileData_Impl(); - - const auto qcmsProfile = qcms_profile_from_memory( - outputProfileData.Elements(), outputProfileData.Length()); - MOZ_ASSERT(qcmsProfile); - const auto release = - MakeScopeExit([&]() { qcms_profile_release(qcmsProfile); }); - - const auto ret = color::ColorProfileDesc::From(*qcmsProfile); - bool print = gfxEnv::MOZ_GL_SPEW(); - if (print) { - const auto gammaGuess = color::GuessGamma(ret.linearFromTf.r); - printf_stderr( - "Display profile:\n" - " Approx Gamma: %f\n" - " XYZ-D65 Red : %f, %f, %f\n" - " XYZ-D65 Green: %f, %f, %f\n" - " XYZ-D65 Blue : %f, %f, %f\n", - gammaGuess, ret.xyzd65FromLinearRgb.at(0, 0), - ret.xyzd65FromLinearRgb.at(0, 1), ret.xyzd65FromLinearRgb.at(0, 2), - - ret.xyzd65FromLinearRgb.at(1, 0), ret.xyzd65FromLinearRgb.at(1, 1), - ret.xyzd65FromLinearRgb.at(1, 2), - - ret.xyzd65FromLinearRgb.at(2, 0), ret.xyzd65FromLinearRgb.at(2, 1), - ret.xyzd65FromLinearRgb.at(2, 2)); - } - - return ret; -} - -inline D2D1_MATRIX_5X4_F to_D2D1_MATRIX_5X4_F(const color::mat4& m) { - return D2D1_MATRIX_5X4_F{{{ - m.rows[0][0], - m.rows[1][0], - m.rows[2][0], - m.rows[3][0], - m.rows[0][1], - m.rows[1][1], - m.rows[2][1], - m.rows[3][1], - m.rows[0][2], - m.rows[1][2], - m.rows[2][2], - m.rows[3][2], - m.rows[0][3], - m.rows[1][3], - m.rows[2][3], - m.rows[3][3], - 0, - 0, - 0, - 0, - }}}; -} - -ColorManagementChain ColorManagementChain::From( - IDCompositionDevice3& dcomp, - const color::ColorProfileConversionDesc& conv) { - auto ret = ColorManagementChain{}; - -#if !defined(MOZ_MINGW_DCOMP_H_INCOMPLETE) - - const auto Append = [&](const RefPtr<IDCompositionFilterEffect>& afterLast) { - if (ret.last) { - afterLast->SetInput(0, ret.last, 0); - } - ret.last = afterLast; - }; - - const auto MaybeAppendColorMatrix = [&](const color::mat4& m) { - RefPtr<IDCompositionColorMatrixEffect> e; - if (approx(m, color::mat4::Identity())) return e; - dcomp.CreateColorMatrixEffect(getter_AddRefs(e)); - MOZ_ASSERT(e); - if (!e) return e; - e->SetMatrix(to_D2D1_MATRIX_5X4_F(m)); - Append(e); - return e; - }; - const auto MaybeAppendTableTransfer = [&](const color::RgbTransferTables& t) { - RefPtr<IDCompositionTableTransferEffect> e; - if (!t.r.size() && !t.g.size() && !t.b.size()) return e; - dcomp.CreateTableTransferEffect(getter_AddRefs(e)); - MOZ_ASSERT(e); - if (!e) return e; - e->SetRedTable(t.r.data(), t.r.size()); - e->SetGreenTable(t.g.data(), t.g.size()); - e->SetBlueTable(t.b.data(), t.b.size()); - Append(e); - return e; - }; - - ret.srcRgbFromSrcYuv = MaybeAppendColorMatrix(conv.srcRgbFromSrcYuv); - ret.srcLinearFromSrcTf = MaybeAppendTableTransfer(conv.srcLinearFromSrcTf); - ret.dstLinearFromSrcLinear = - MaybeAppendColorMatrix(color::mat4(conv.dstLinearFromSrcLinear)); - ret.dstTfFromDstLinear = MaybeAppendTableTransfer(conv.dstTfFromDstLinear); - -#endif // !defined(MOZ_MINGW_DCOMP_H_INCOMPLETE) - - return ret; -} - -ColorManagementChain::~ColorManagementChain() = default; - } // namespace wr } // namespace mozilla diff --git a/gfx/webrender_bindings/DCLayerTree.h b/gfx/webrender_bindings/DCLayerTree.h index 921a9389aebbf..25076444a967d 100644 --- a/gfx/webrender_bindings/DCLayerTree.h +++ b/gfx/webrender_bindings/DCLayerTree.h @@ -12,7 +12,6 @@ #include <vector> #include <windows.h> -#include "Colorspaces.h" #include "GLTypes.h" #include "mozilla/HashFunctions.h" #include "mozilla/layers/OverlayInfo.h" @@ -28,11 +27,7 @@ struct ID3D11VideoContext; struct ID3D11VideoProcessor; struct ID3D11VideoProcessorEnumerator; struct ID3D11VideoProcessorOutputView; -struct IDCompositionColorMatrixEffect; -struct IDCompositionFilterEffect; -struct IDCompositionTableTransferEffect; struct IDCompositionDevice2; -struct IDCompositionDevice3; struct IDCompositionSurface; struct IDCompositionTarget; struct IDCompositionVisual2; @@ -71,23 +66,6 @@ struct GpuOverlayInfo { UINT mRgb10a2OverlaySupportFlags = 0; }; -// - - -struct ColorManagementChain { - RefPtr<IDCompositionColorMatrixEffect> srcRgbFromSrcYuv; - RefPtr<IDCompositionTableTransferEffect> srcLinearFromSrcTf; - RefPtr<IDCompositionColorMatrixEffect> dstLinearFromSrcLinear; - RefPtr<IDCompositionTableTransferEffect> dstTfFromDstLinear; - RefPtr<IDCompositionFilterEffect> last; - - static ColorManagementChain From(IDCompositionDevice3& dcomp, - const color::ColorProfileConversionDesc&); - - ~ColorManagementChain(); -}; - -// - - /** * DCLayerTree manages direct composition layers. * It does not manage gecko's layers::Layer. @@ -232,19 +210,6 @@ class DCLayerTree { bool mPendingCommit; - static color::ColorProfileDesc QueryOutputColorProfile(); - - mutable Maybe<color::ColorProfileDesc> mOutputColorProfile; - - public: - const color::ColorProfileDesc& OutputColorProfile() const { - if (!mOutputColorProfile) { - mOutputColorProfile = Some(QueryOutputColorProfile()); - } - return *mOutputColorProfile; - } - - protected: static UniquePtr<GpuOverlayInfo> sGpuOverlayInfo; }; @@ -357,7 +322,6 @@ class DCExternalSurfaceWrapper : public DCSurface { UniquePtr<DCSurface> mSurface; const bool mIsOpaque; - Maybe<ColorManagementChain> mCManageChain; }; class DCSurfaceVideo : public DCSurface { diff --git a/mfbt/Span.h b/mfbt/Span.h index bcbd492d35edb..5d8b3255f49da 100644 --- a/mfbt/Span.h +++ b/mfbt/Span.h @@ -105,7 +105,7 @@ class span_iterator { public: using iterator_category = std::random_access_iterator_tag; using value_type = std::remove_const_t<element_type_>; - using difference_type = ptrdiff_t; + using difference_type = typename SpanT::index_type; using reference = std::conditional_t<IsConst, const element_type_, element_type_>&; @@ -366,7 +366,6 @@ class Span { public: // constants and types using element_type = ElementType; - using value_type = std::remove_cv_t<element_type>; using index_type = size_t; using pointer = element_type*; using reference = element_type&; @@ -421,16 +420,6 @@ class Span { aEnd) : storage_(aBegin == aEnd ? nullptr : &*aBegin, aEnd - aBegin) {} - /** - * Constructor for {iterator,size_t} - */ - template <typename OtherElementType, size_t OtherExtent, bool IsConst> - constexpr Span( - span_details::span_iterator<Span<OtherElementType, OtherExtent>, IsConst> - aBegin, - index_type aLength) - : storage_(!aLength ? nullptr : &*aBegin, aLength) {} - /** * Constructor for C array. */ @@ -675,16 +664,6 @@ class Span { return Subspan(0, aEnd); } - /// std::span-compatible method name - constexpr auto subspan(index_type aStart, - index_type aLength = dynamic_extent) const { - return Subspan(aStart, aLength); - } - /// std::span-compatible method name - constexpr auto from(index_type aStart) const { return From(aStart); } - /// std::span-compatible method name - constexpr auto to(index_type aEnd) const { return To(aEnd); } - /** * Subspan with run-time start index and exclusive end index. * (Rust's &foo[start..end]) diff --git a/mfbt/tests/gtest/TestSpan.cpp b/mfbt/tests/gtest/TestSpan.cpp index c5f04db0ddbd9..405a87ee2cf7d 100644 --- a/mfbt/tests/gtest/TestSpan.cpp +++ b/mfbt/tests/gtest/TestSpan.cpp @@ -1630,16 +1630,16 @@ SPAN_TEST(begin_end) { ASSERT_NE(it, beyond); CHECK_THROW(*beyond, fail_fast); - ASSERT_EQ(beyond - first, 4); - ASSERT_EQ(first - first, 0); - ASSERT_EQ(beyond - beyond, 0); + ASSERT_EQ(beyond - first, 4U); + ASSERT_EQ(first - first, 0U); + ASSERT_EQ(beyond - beyond, 0U); ++it; - ASSERT_EQ(it - first, 1); + ASSERT_EQ(it - first, 1U); ASSERT_EQ(*it, 2); *it = 22; ASSERT_EQ(*it, 22); - ASSERT_EQ(beyond - it, 3); + ASSERT_EQ(beyond - it, 3U); it = first; ASSERT_EQ(it, first); @@ -1649,7 +1649,7 @@ SPAN_TEST(begin_end) { } ASSERT_EQ(it, beyond); - ASSERT_EQ(it - beyond, 0); + ASSERT_EQ(it - beyond, 0U); for (auto& n : s) { ASSERT_EQ(n, 5); @@ -1685,14 +1685,14 @@ SPAN_TEST(cbegin_cend) { ASSERT_NE(it, beyond); CHECK_THROW(*beyond, fail_fast); - ASSERT_EQ(beyond - first, 4); - ASSERT_EQ(first - first, 0); - ASSERT_EQ(beyond - beyond, 0); + ASSERT_EQ(beyond - first, 4U); + ASSERT_EQ(first - first, 0U); + ASSERT_EQ(beyond - beyond, 0U); ++it; - ASSERT_EQ(it - first, 1); + ASSERT_EQ(it - first, 1U); ASSERT_EQ(*it, 2); - ASSERT_EQ(beyond - it, 3); + ASSERT_EQ(beyond - it, 3U); int last = 0; it = first; @@ -1705,7 +1705,7 @@ SPAN_TEST(cbegin_cend) { } ASSERT_EQ(it, beyond); - ASSERT_EQ(it - beyond, 0); + ASSERT_EQ(it - beyond, 0U); } } @@ -1723,16 +1723,16 @@ SPAN_TEST(rbegin_rend) { ASSERT_NE(it, beyond); CHECK_THROW(*beyond, fail_fast); - ASSERT_EQ(beyond - first, 4); - ASSERT_EQ(first - first, 0); - ASSERT_EQ(beyond - beyond, 0); + ASSERT_EQ(beyond - first, 4U); + ASSERT_EQ(first - first, 0U); + ASSERT_EQ(beyond - beyond, 0U); ++it; - ASSERT_EQ(it - first, 1); + ASSERT_EQ(it - first, 1U); ASSERT_EQ(*it, 3); *it = 22; ASSERT_EQ(*it, 22); - ASSERT_EQ(beyond - it, 3); + ASSERT_EQ(beyond - it, 3U); it = first; ASSERT_EQ(it, first); @@ -1742,7 +1742,7 @@ SPAN_TEST(rbegin_rend) { } ASSERT_EQ(it, beyond); - ASSERT_EQ(it - beyond, 0); + ASSERT_EQ(it - beyond, 0U); for (auto& n : s) { ASSERT_EQ(n, 5); @@ -1764,14 +1764,14 @@ SPAN_TEST(crbegin_crend) { ASSERT_NE(it, beyond); CHECK_THROW(*beyond, fail_fast); - ASSERT_EQ(beyond - first, 4); - ASSERT_EQ(first - first, 0); - ASSERT_EQ(beyond - beyond, 0); + ASSERT_EQ(beyond - first, 4U); + ASSERT_EQ(first - first, 0U); + ASSERT_EQ(beyond - beyond, 0U); ++it; - ASSERT_EQ(it - first, 1); + ASSERT_EQ(it - first, 1U); ASSERT_EQ(*it, 3); - ASSERT_EQ(beyond - it, 3); + ASSERT_EQ(beyond - it, 3U); it = first; ASSERT_EQ(it, first); @@ -1784,7 +1784,7 @@ SPAN_TEST(crbegin_crend) { } ASSERT_EQ(it, beyond); - ASSERT_EQ(it - beyond, 0); + ASSERT_EQ(it - beyond, 0U); } } diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 8abc7026f1384..6ba7e8a6cf4ab 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -5775,11 +5775,6 @@ #endif mirror: always -- name: gfx.color_management.display_profile - type: DataMutexString - value: "" - mirror: always # But be warned: We cache the result. - - name: gfx.color_management.force_srgb type: RelaxedAtomicBool value: false @@ -5787,7 +5782,7 @@ - name: gfx.color_management.native_srgb type: RelaxedAtomicBool -#if defined(XP_MACOSX) || defined(XP_WIN) +#if defined(XP_MACOSX) value: true #else value: false @@ -5812,16 +5807,6 @@ value: 0 mirror: always -- name: gfx.color_management.rec709_gamma_as_srgb - type: RelaxedAtomicBool - value: true # Tragic backwards compat. - mirror: always - -- name: gfx.color_management.rec2020_gamma_as_rec709 - type: RelaxedAtomicBool - value: true # Match naive behavior, but hopefully we can stop soon! - mirror: always - - name: gfx.compositor.clearstate type: RelaxedAtomicBool value: false diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index fe9c9b0ee842d..955fe0bd077d1 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -454,6 +454,8 @@ pref("formhelper.autozoom.force-disable.test-only", false); pref("gfx.hidpi.enabled", 2); #endif +pref("gfx.color_management.display_profile", ""); + pref("gfx.downloadable_fonts.enabled", true); pref("gfx.downloadable_fonts.fallback_delay", 3000); pref("gfx.downloadable_fonts.fallback_delay_short", 100); diff --git a/netwerk/dns/DNSPacket.cpp b/netwerk/dns/DNSPacket.cpp index 1822e396ca41f..4d28889294829 100644 --- a/netwerk/dns/DNSPacket.cpp +++ b/netwerk/dns/DNSPacket.cpp @@ -1177,7 +1177,7 @@ bool ODoHDNSPacket::ParseODoHConfigs(Span<const uint8_t> aData, } nsTArray<ObliviousDoHConfig> result; - static const int kMinimumConfigContentLength = 12; + static const uint32_t kMinimumConfigContentLength = 12; while (std::distance(it, aData.cend()) > kMinimumConfigContentLength) { ObliviousDoHConfig config; if (!get16bit(aData, it, config.mVersion)) { -- GitLab