diff options
Diffstat (limited to 'gfx/gl')
-rw-r--r-- | gfx/gl/AutoMappable.h | 139 | ||||
-rw-r--r-- | gfx/gl/Colorspaces.h | 128 | ||||
-rw-r--r-- | gfx/gl/GLBlitHelper.cpp | 333 | ||||
-rw-r--r-- | gfx/gl/GLBlitHelper.h | 33 | ||||
-rw-r--r-- | gfx/gl/GLBlitHelperD3D.cpp | 15 | ||||
-rw-r--r-- | gfx/gl/GLContext.h | 51 | ||||
-rw-r--r-- | gfx/gl/GLContextGLX.h | 6 | ||||
-rw-r--r-- | gfx/gl/GLContextProviderGLX.cpp | 16 | ||||
-rw-r--r-- | gfx/gl/GLScreenBuffer.cpp | 38 | ||||
-rw-r--r-- | gfx/gl/GLScreenBuffer.h | 9 | ||||
-rw-r--r-- | gfx/gl/SharedSurface.h | 5 | ||||
-rw-r--r-- | gfx/gl/SharedSurfaceIO.h | 2 | ||||
-rw-r--r-- | gfx/gl/gtest/TestColorspaces.cpp | 12 |
13 files changed, 523 insertions, 264 deletions
diff --git a/gfx/gl/AutoMappable.h b/gfx/gl/AutoMappable.h index f93b2ccb57..700e45d680 100644 --- a/gfx/gl/AutoMappable.h +++ b/gfx/gl/AutoMappable.h @@ -8,38 +8,13 @@ // Here be dragons. #include <functional> +#include <tuple> -namespace mozilla::gfx { +namespace mozilla { template <class T> -size_t Hash(const T&); - -template <class T> -struct StaticStdHasher { - static auto HashImpl(const T& v) { return std::hash<T>()(v); } -}; - -template <class T> -struct StaticHasher { - static auto HashImpl(const T& v) { return v.hash(); } -}; -template <class T> -struct StaticHasher<std::optional<T>> { - static size_t HashImpl(const std::optional<T>& v) { - if (!v) return 0; - return Hash(*v); - } -}; -template <> -struct StaticHasher<int> : public StaticStdHasher<int> {}; -template <> -struct StaticHasher<bool> : public StaticStdHasher<bool> {}; -template <> -struct StaticHasher<float> : public StaticStdHasher<float> {}; - -template <class T> -size_t Hash(const T& v) { - return StaticHasher<T>::HashImpl(v); +size_t StdHash(const T& t) { + return std::hash<T>()(t); } //- @@ -52,97 +27,59 @@ inline size_t HashCombine(size_t seed, const size_t hash) { } // - -// See -// https://codereview.stackexchange.com/questions/136770/hashing-a-tuple-in-c17 +namespace detail { template <class... Args, size_t... Ids> -size_t HashTupleN(const std::tuple<Args...>& tup, - const std::index_sequence<Ids...>&) { +size_t StdHashTupleN(const std::tuple<Args...>& tup, + const std::index_sequence<Ids...>&) { size_t seed = 0; - for (const auto& hash : {Hash(std::get<Ids>(tup))...}) { + for (const auto& hash : {StdHash(std::get<Ids>(tup))...}) { seed = HashCombine(seed, hash); } return seed; } - -template <class... Args> -size_t HashTuple(const std::tuple<Args...>& tup) { - return HashTupleN(tup, std::make_index_sequence<sizeof...(Args)>()); -} +} // namespace detail // - template <class T> -auto MembersEq(const T& a, const T& b) { - const auto atup = a.Members(); - const auto btup = b.Members(); - return atup == btup; -} +struct StdHashMembers { + size_t operator()(const T& t) const { + const auto members = t.Members(); + return StdHash(members); + } +}; -template <class T> -auto MembersLt(const T& a, const T& b) { - const auto atup = a.Members(); - const auto btup = b.Members(); - return atup == btup; -} +// - -template <class T> -auto MembersHash(const T& a) { - const auto atup = a.Members(); - return HashTuple(atup); -} +#define MOZ_MIXIN_DERIVE_CMP_OP_BY_MEMBERS(OP, T) \ + bool operator OP(const T& rhs) const { return Members() OP rhs.Members(); } -template <class T> -struct MembersHasher final { - auto operator()(const T& v) const { return v.hash(); } -}; +#define MOZ_MIXIN_DERIVE_CMP_OPS_BY_MEMBERS(T) \ + MOZ_MIXIN_DERIVE_CMP_OP_BY_MEMBERS(==, T) \ + MOZ_MIXIN_DERIVE_CMP_OP_BY_MEMBERS(!=, T) \ + MOZ_MIXIN_DERIVE_CMP_OP_BY_MEMBERS(<, T) \ + MOZ_MIXIN_DERIVE_CMP_OP_BY_MEMBERS(<=, T) \ + MOZ_MIXIN_DERIVE_CMP_OP_BY_MEMBERS(>, T) \ + MOZ_MIXIN_DERIVE_CMP_OP_BY_MEMBERS(>=, T) -/** E.g.: -struct Foo { - int i; - bool b; +template <class T> +struct DeriveCmpOpMembers { + private: + auto Members() const { return reinterpret_cast<const T*>(this)->Members(); } - auto Members() const { return std::tie(i, b); } - INLINE_AUTO_MAPPABLE(Foo) + public: + MOZ_MIXIN_DERIVE_CMP_OPS_BY_MEMBERS(T) }; -std::unordered_set<T, T::Hasher> easy; -**/ -#define INLINE_DERIVE_MEMBERS_EQ(T) \ - friend bool operator==(const T& a, const T& b) { \ - return mozilla::gfx::MembersEq(a, b); \ - } \ - friend bool operator!=(const T& a, const T& b) { return !operator==(a, b); } -#define INLINE_AUTO_MAPPABLE(T) \ - friend bool operator<(const T& a, const T& b) { \ - return mozilla::gfx::MembersLt(a, b); \ - } \ - INLINE_DERIVE_MEMBERS_EQ(T) \ - size_t hash() const { \ - return mozilla::gfx::MembersHash(*reinterpret_cast<const T*>(this)); \ - } \ - using Hasher = mozilla::gfx::MembersHasher<T>; - -// - -/** E.g.: -``` -struct Foo : public AutoMappable<Foo> { - int i; - bool b; +} // namespace mozilla - auto Members() const { return std::tie(i, b); } -}; -std::unordered_set<T, T::Hasher> easy; -``` -`easy.insert({{}, 2, true});` -The initial {} is needed for aggregate initialization of AutoMappable<Foo>. -Use INLINE_AUTO_MAPPABLE if this is too annoying. -**/ -template <class T> -struct AutoMappable { - INLINE_AUTO_MAPPABLE(T) +template <class... Args> +struct std::hash<std::tuple<Args...>> { + size_t operator()(const std::tuple<Args...>& t) const { + return mozilla::detail::StdHashTupleN( + t, std::make_index_sequence<sizeof...(Args)>()); + } }; -} // namespace mozilla::gfx - #endif // MOZILLA_AUTO_MAPPABLE_H diff --git a/gfx/gl/Colorspaces.h b/gfx/gl/Colorspaces.h index 8f36854d2d..062897d2dd 100644 --- a/gfx/gl/Colorspaces.h +++ b/gfx/gl/Colorspaces.h @@ -42,19 +42,27 @@ typedef struct _qcms_profile qcms_profile; namespace mozilla::color { +// - + struct YuvLumaCoeffs final { float r = 0.2126; float g = 0.7152; float b = 0.0722; auto Members() const { return std::tie(r, g, b); } - INLINE_AUTO_MAPPABLE(YuvLumaCoeffs) + MOZ_MIXIN_DERIVE_CMP_OPS_BY_MEMBERS(YuvLumaCoeffs) static constexpr auto Rec709() { return YuvLumaCoeffs(); } static constexpr auto Rec2020() { - return YuvLumaCoeffs{0.2627, 0.6780, 0.0593}; + return YuvLumaCoeffs{ + .r = 0.2627, + .g = 0.6780, + .b = 0.0593, + }; } + + static constexpr auto Gbr() { return YuvLumaCoeffs{.r = 0, .g = 1, .b = 0}; } }; struct PiecewiseGammaDesc final { @@ -68,26 +76,26 @@ struct PiecewiseGammaDesc final { float k = 12.92; auto Members() const { return std::tie(a, b, g, k); } - INLINE_AUTO_MAPPABLE(PiecewiseGammaDesc) + MOZ_MIXIN_DERIVE_CMP_OPS_BY_MEMBERS(PiecewiseGammaDesc) static constexpr auto Srgb() { return PiecewiseGammaDesc(); } static constexpr auto DisplayP3() { return Srgb(); } static constexpr auto Rec709() { return PiecewiseGammaDesc{ - 1.099, - 0.018, - 1.0 / 0.45, // ~2.222 - 4.5, + .a = 1.099, + .b = 0.018, + .g = 1.0 / 0.45, // ~2.222 + .k = 4.5, }; } // FYI: static constexpr auto Rec2020_10bit() { return Rec709(); } static constexpr auto Rec2020_12bit() { return PiecewiseGammaDesc{ - 1.0993, - 0.0181, - 1.0 / 0.45, // ~2.222 - 4.5, + .a = 1.0993, + .b = 0.0181, + .g = 1.0 / 0.45, // ~2.222 + .k = 4.5, }; } }; @@ -99,21 +107,21 @@ struct YcbcrDesc final { float uPlusHalf = 240 / 255.0; auto Members() const { return std::tie(y0, y1, u0, uPlusHalf); } - INLINE_AUTO_MAPPABLE(YcbcrDesc) + MOZ_MIXIN_DERIVE_CMP_OPS_BY_MEMBERS(YcbcrDesc) static constexpr auto Narrow8() { // AKA limited/studio/tv return YcbcrDesc(); } static constexpr auto Full8() { // AKA pc return YcbcrDesc{ - 0 / 255.0, - 255 / 255.0, - 128 / 255.0, - 254 / 255.0, + .y0 = 0 / 255.0, + .y1 = 255 / 255.0, + .u0 = 128 / 255.0, + .uPlusHalf = 254 / 255.0, }; } static constexpr auto Float() { // Best for a LUT - return YcbcrDesc{0.0, 1.0, 0.5, 1.0}; + return YcbcrDesc{.y0 = 0.0, .y1 = 1.0, .u0 = 0.5, .uPlusHalf = 1.0}; } }; @@ -129,7 +137,7 @@ struct Chromaticities final { static constexpr float wy = 0.3290; auto Members() const { return std::tie(rx, ry, gx, gy, bx, by); } - INLINE_AUTO_MAPPABLE(Chromaticities) + MOZ_MIXIN_DERIVE_CMP_OPS_BY_MEMBERS(Chromaticities) // - @@ -145,23 +153,32 @@ struct Chromaticities final { } static constexpr auto Rec601_525_Ntsc() { return Chromaticities{ - 0.630, 0.340, // r - 0.310, 0.595, // g - 0.155, 0.070, // b + .rx = 0.630, + .ry = 0.340, // r + .gx = 0.310, + .gy = 0.595, // g + .bx = 0.155, + .by = 0.070, // b }; } static constexpr auto Rec2020() { return Chromaticities{ - 0.708, 0.292, // r - 0.170, 0.797, // g - 0.131, 0.046, // b + .rx = 0.708, + .ry = 0.292, // r + .gx = 0.170, + .gy = 0.797, // g + .bx = 0.131, + .by = 0.046, // b }; } static constexpr auto DisplayP3() { return Chromaticities{ - 0.680, 0.320, // r - 0.265, 0.690, // g - 0.150, 0.060, // b + .rx = 0.680, + .ry = 0.320, // r + .gx = 0.265, + .gy = 0.690, // g + .bx = 0.150, + .by = 0.060, // b }; } }; @@ -173,7 +190,7 @@ struct YuvDesc final { YcbcrDesc ycbcr; auto Members() const { return std::tie(yCoeffs, ycbcr); } - INLINE_AUTO_MAPPABLE(YuvDesc); + MOZ_MIXIN_DERIVE_CMP_OPS_BY_MEMBERS(YuvDesc) }; struct ColorspaceDesc final { @@ -182,11 +199,30 @@ struct ColorspaceDesc final { std::optional<YuvDesc> yuv; auto Members() const { return std::tie(chrom, tf, yuv); } - INLINE_AUTO_MAPPABLE(ColorspaceDesc); + MOZ_MIXIN_DERIVE_CMP_OPS_BY_MEMBERS(ColorspaceDesc) }; // - +} // namespace mozilla::color + +#define _(X) \ + template <> \ + struct std::hash<X> : mozilla::StdHashMembers<X> {}; + +_(mozilla::color::YuvLumaCoeffs) +_(mozilla::color::PiecewiseGammaDesc) +_(mozilla::color::YcbcrDesc) +_(mozilla::color::Chromaticities) +_(mozilla::color::YuvDesc) +_(mozilla::color::ColorspaceDesc) + +#undef _ + +namespace mozilla::color { + +// - + template <class TT, int NN> struct avec final { using T = TT; @@ -336,6 +372,11 @@ auto max(const avec<T, N>& a, const avec<T, N>& b) { } template <class T, int N> +auto clamp(const avec<T, N>& v, const avec<T, N>& lo, const avec<T, N>& hi) { + return max(lo, min(v, hi)); +} + +template <class T, int N> auto floor(const avec<T, N>& a) { auto ret = avec<T, N>{}; for (int i = 0; i < ret.N; i++) { @@ -404,6 +445,11 @@ struct mat final { } } + constexpr bool operator==(const mat& rhs) const { + return this->rows == rhs.rows; + } + constexpr bool operator!=(const mat& rhs) const { return !(*this == rhs); } + const auto& at(const int x, const int y) const { return rows.at(y)[x]; } auto& at(const int x, const int y) { return rows.at(y)[x]; } @@ -722,17 +768,19 @@ inline float SampleOutByIn(const C& outByIn, const float in) { 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); + // Estimate based on nearest (first) derivative: + // Find the nearest point to `in` in `outByIn`. + const auto inId = in * (outByIn.size() - 1); + const auto inId0F = std::clamp(floorf(inId), 0.f, float(outByIn.size() - 2)); + const auto inId0 = size_t(inId0F); + const auto out0 = outByIn.at(inId0 + 0); + const auto out1 = outByIn.at(inId0 + 1); + const auto d_inId0 = float(1); + const auto d_out0 = out1 - out0; + const auto d_inId = inId - inId0; + + const auto out = out0 + (d_out0 / d_inId0) * d_inId; // printf("SampleOutByIn(%f)->%f\n", in, out); return out; } @@ -963,7 +1011,7 @@ struct ColorProfileConversionDesc { }; static ColorProfileConversionDesc From(const FromDesc&); - vec3 Apply(const vec3 src) const { + vec3 DstFromSrc(const vec3 src) const { const auto srcRgb = vec3(srcRgbFromSrcYuv * vec4(src, 1)); const auto srcLinear = vec3{{ SampleOutByIn(srcLinearFromSrcTf.r, srcRgb.x()), diff --git a/gfx/gl/GLBlitHelper.cpp b/gfx/gl/GLBlitHelper.cpp index c5c8995dab..fdecbfda99 100644 --- a/gfx/gl/GLBlitHelper.cpp +++ b/gfx/gl/GLBlitHelper.cpp @@ -19,6 +19,7 @@ #include "mozilla/Preferences.h" #include "mozilla/StaticPrefs_gfx.h" #include "mozilla/UniquePtr.h" +#include "mozilla/gfx/BuildConstants.h" #include "mozilla/gfx/Logging.h" #include "mozilla/gfx/Matrix.h" #include "mozilla/layers/ImageDataSerializer.h" @@ -189,16 +190,16 @@ const char* const kFragConvert_ColorMatrix = R"( return (uColorMatrix * vec4(src, 1)).rgb; } )"; -const char* const kFragConvert_ColorLut = R"( +const char* const kFragConvert_ColorLut3d = R"( uniform PRECISION sampler3D uColorLut; vec3 metaConvert(vec3 src) { // Half-texel filtering hazard! // E.g. For texture size of 2, - // E.g. 0.5/2=0.25 is still sampling 100% of texel 0, 0% of texel 1. - // For the LUT, we need 0.5/2=0.25 to filter 25/75 texel 0 and 1. - // That is, we need to adjust our sampling point such that it's 0.25 of the - // way from texel 0's center to texel 1's center. + // E.g. x=0.25 is still sampling 100% of texel x=0, 0% of texel x=1. + // For the LUT, we need r=0.25 to filter 75/25 from texel 0 and 1. + // That is, we need to adjust our sampling point such that it starts in the + // center of texel 0, and ends in the center of texel N-1. // We need, for N=2: // v=0.0|N=2 => v'=0.5/2 // v=1.0|N=2 => v'=1.5/2 @@ -211,6 +212,44 @@ const char* const kFragConvert_ColorLut = R"( return texture(uColorLut, src).rgb; } )"; +// Delete if unused after 2024-10-01: +const char* const kFragConvert_ColorLut2d = R"( + uniform PRECISION sampler2D uColorLut; + uniform mediump vec3 uColorLut3dSize; + + vec3 metaConvert(vec3 src) { + // Half-texel filtering hazard! + // E.g. For texture size of 2, + // E.g. x=0.25 is still sampling 100% of texel x=0, 0% of texel x=1. + // For the LUT, we need r=0.25 to filter 75/25 from texel 0 and 1. + // That is, we need to adjust our sampling point such that it starts in the + // center of texel 0, and ends in the center of texel N-1. + // We need, for N=2: + // v=0.0|N=2 => v'=0.5/2 + // v=1.0|N=2 => v'=1.5/2 + // For N=3: + // v=0.0|N=3 => v'=0.5/3 + // v=1.0|N=3 => v'=2.5/3 + // => v' = ( 0.5 + v * (3 - 1) )/3 + src = clamp(src, vec3(0,0,0), vec3(1,1,1)); + vec3 lut3dSize = uColorLut3dSize; + vec2 lut2dSize = vec2(lut3dSize.x, lut3dSize.y * lut3dSize.z); + vec3 texelSrc3d = 0.5 + src * (lut3dSize - 1.0); + + vec3 texelSrc3d_zFloor = texelSrc3d; + texelSrc3d_zFloor.z = floor(texelSrc3d_zFloor.z); + vec3 texelSrc3d_zNext = texelSrc3d_zFloor + vec3(0,0,1); + texelSrc3d_zNext.z = min(texelSrc3d_zNext.z, lut3dSize.z - 1.0); + + vec2 texelSrc2d_zFloor = texelSrc3d_zFloor.xy + vec2(0, texelSrc3d_zFloor.z * lut3dSize.y); + vec2 texelSrc2d_zNext = texelSrc3d_zNext.xy + vec2(0, texelSrc3d_zNext.z * lut3dSize.y); + + vec4 dst_zFloor = texture(uColorLut, texelSrc2d_zFloor / lut2dSize); + vec4 dst_zNext = texture(uColorLut, texelSrc2d_zNext / lut2dSize); + + return mix(dst_zFloor, dst_zNext, texelSrc3d.z - texelSrc3d_zFloor.z); + } +)"; // - @@ -277,13 +316,13 @@ Mat3 SubRectMat3(const gfx::IntRect& bigSubrect, const gfx::IntSize& smallSize, // -- ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext* const gl, - const std::vector<uint8_t>& texUnits, + const size_t texUnits, const GLenum texTarget) : mGL(*gl), mTexUnits(texUnits), mTexTarget(texTarget), mOldTexUnit(mGL.GetIntAs<GLenum>(LOCAL_GL_ACTIVE_TEXTURE)) { - MOZ_RELEASE_ASSERT(texUnits.size() >= 1); + MOZ_RELEASE_ASSERT(texUnits >= 1); GLenum texBinding; switch (mTexTarget) { @@ -304,12 +343,11 @@ ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext* const gl, MOZ_CRASH(); } - for (const auto i : IntegerRange(mTexUnits.size())) { - const auto& unit = mTexUnits[i]; - mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + unit); + for (const auto i : IntegerRange(mTexUnits)) { + mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + i); if (mGL.IsSupported(GLFeature::sampler_objects)) { mOldTexSampler[i] = mGL.GetIntAs<GLuint>(LOCAL_GL_SAMPLER_BINDING); - mGL.fBindSampler(unit, 0); + mGL.fBindSampler(i, 0); } mOldTex[i] = mGL.GetIntAs<GLuint>(texBinding); } @@ -319,11 +357,10 @@ ScopedSaveMultiTex::~ScopedSaveMultiTex() { // Unbind in reverse order, in case we have repeats. // Order matters because we unbound samplers during ctor, so now we have to // make sure we rebind them in the right order. - for (const auto i : Reversed(IntegerRange(mTexUnits.size()))) { - const auto& unit = mTexUnits[i]; - mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + unit); + for (const auto i : Reversed(IntegerRange(mTexUnits))) { + mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + i); if (mGL.IsSupported(GLFeature::sampler_objects)) { - mGL.fBindSampler(unit, mOldTexSampler[i]); + mGL.fBindSampler(i, mOldTexSampler[i]); } mGL.fBindTexture(mTexTarget, mOldTex[i]); } @@ -520,11 +557,6 @@ void DrawBlitProg::Draw(const BaseArgs& args, gl->fUniformMatrix3fv(mLoc_uDestMatrix, 1, false, destMatrix.m); gl->fUniformMatrix3fv(mLoc_uTexMatrix0, 1, false, args.texMatrix0.m); - if (args.texUnitForColorLut) { - gl->fUniform1i(mLoc_uColorLut, - AssertedCast<GLint>(*args.texUnitForColorLut)); - } - MOZ_ASSERT(bool(argsYUV) == (mLoc_uColorMatrix != -1)); if (argsYUV) { gl->fUniformMatrix3fv(mLoc_uTexMatrix1, 1, false, argsYUV->texMatrix1.m); @@ -684,10 +716,6 @@ GLBlitHelper::GLBlitHelper(GLContext* const gl) } GLBlitHelper::~GLBlitHelper() { - for (const auto& pair : mDrawBlitProgs) { - const auto& ptr = pair.second; - delete ptr; - } mDrawBlitProgs.clear(); if (!mGL->MakeCurrent()) return; @@ -702,18 +730,16 @@ GLBlitHelper::~GLBlitHelper() { // -- -const DrawBlitProg* GLBlitHelper::GetDrawBlitProg( +const DrawBlitProg& GLBlitHelper::GetDrawBlitProg( const DrawBlitProg::Key& key) const { - const auto& res = mDrawBlitProgs.insert({key, nullptr}); - auto& pair = *(res.first); - const auto& didInsert = res.second; - if (didInsert) { - pair.second = CreateDrawBlitProg(pair.first); + auto& ret = mDrawBlitProgs[key]; + if (!ret) { + ret = CreateDrawBlitProg(key); } - return pair.second; + return *ret; } -const DrawBlitProg* GLBlitHelper::CreateDrawBlitProg( +std::unique_ptr<const DrawBlitProg> GLBlitHelper::CreateDrawBlitProg( const DrawBlitProg::Key& key) const { const auto precisionPref = StaticPrefs::gfx_blithelper_precision(); const char* precision; @@ -790,7 +816,7 @@ const DrawBlitProg* GLBlitHelper::CreateDrawBlitProg( mGL->fUniform1i(loc, i); } - return new DrawBlitProg(this, prog); + return std::make_unique<DrawBlitProg>(this, prog); } GLuint progLogLen = 0; @@ -997,7 +1023,7 @@ bool GLBlitHelper::Blit(const java::GeckoSurfaceTexture::Ref& surfaceTexture, {kFragHeader_TexExt, {kFragSample_OnePlane, kFragConvert_None}}); const DrawBlitProg::BaseArgs baseArgs = {transform3, yFlip, destSize, Nothing()}; - prog->Draw(baseArgs, nullptr); + prog.Draw(baseArgs, nullptr); if (surfaceTexture->IsSingleBuffer()) { surfaceTexture->ReleaseTexImage(); @@ -1087,7 +1113,7 @@ bool GLBlitHelper::BlitPlanarYCbCr(const PlanarYCbCrData& yuvData, // -- - const ScopedSaveMultiTex saveTex(mGL, {0, 1, 2}, LOCAL_GL_TEXTURE_2D); + const ScopedSaveMultiTex saveTex(mGL, 3, LOCAL_GL_TEXTURE_2D); const ResetUnpackState reset(mGL); const gfx::IntSize yTexSize(yuvData.mYStride, yuvData.YDataSize().height); const gfx::IntSize uvTexSize(yuvData.mCbCrStride, @@ -1139,7 +1165,7 @@ bool GLBlitHelper::BlitPlanarYCbCr(const PlanarYCbCrData& yuvData, yFlip, destSize, Nothing()}; const DrawBlitProg::YUVArgs yuvArgs = { SubRectMat3(clipRect, uvTexSize, divisors), Some(yuvData.mYUVColorSpace)}; - prog->Draw(baseArgs, &yuvArgs); + prog.Draw(baseArgs, &yuvArgs); return true; } @@ -1197,11 +1223,7 @@ bool GLBlitHelper::BlitImage(MacIOSurface* const iosurf, const GLenum texTarget = LOCAL_GL_TEXTURE_RECTANGLE; - std::vector<uint8_t> texUnits; - for (uint8_t i = 0; i < planes; i++) { - texUnits.push_back(i); - } - const ScopedSaveMultiTex saveTex(mGL, texUnits, texTarget); + const ScopedSaveMultiTex saveTex(mGL, planes, texTarget); const ScopedTexture tex0(mGL); const ScopedTexture tex1(mGL); const ScopedTexture tex2(mGL); @@ -1282,7 +1304,7 @@ bool GLBlitHelper::BlitImage(MacIOSurface* const iosurf, kFragHeader_Tex2DRect, {fragSample, kFragConvert_ColorMatrix}, }); - prog->Draw(baseArgs, pYuvArgs); + prog.Draw(baseArgs, pYuvArgs); return true; } #endif @@ -1315,14 +1337,14 @@ void GLBlitHelper::DrawBlitTextureToFramebuffer(const GLuint srcTex, {kFragSample_OnePlane, fragConvert}, }); - const ScopedSaveMultiTex saveTex(mGL, {0}, srcTarget); + const ScopedSaveMultiTex saveTex(mGL, 1, srcTarget); mGL->fActiveTexture(LOCAL_GL_TEXTURE0); mGL->fBindTexture(srcTarget, srcTex); const bool yFlip = false; const DrawBlitProg::BaseArgs baseArgs = {texMatrix0, yFlip, destSize, Nothing()}; - prog->Draw(baseArgs); + prog.Draw(baseArgs); } // ----------------------------------------------------------------------------- @@ -1519,11 +1541,7 @@ bool GLBlitHelper::Blit(DMABufSurface* surface, const gfx::IntSize& destSize, const GLenum texTarget = LOCAL_GL_TEXTURE_2D; - std::vector<uint8_t> texUnits; - for (uint8_t i = 0; i < planes; i++) { - texUnits.push_back(i); - } - const ScopedSaveMultiTex saveTex(mGL, texUnits, texTarget); + const ScopedSaveMultiTex saveTex(mGL, planes, texTarget); const auto pixelFormat = surface->GetSurfaceType(); const char* fragSample; @@ -1560,7 +1578,7 @@ bool GLBlitHelper::Blit(DMABufSurface* surface, const gfx::IntSize& destSize, const auto& prog = GetDrawBlitProg({kFragHeader_Tex2D, {fragSample, fragConvert}}); - prog->Draw(baseArgs, pYuvArgs); + prog.Draw(baseArgs, pYuvArgs); return true; } @@ -1603,23 +1621,205 @@ static uint32_t toRgb10A2(const color::vec4& val) { return ret; } +// - + +color::ColorspaceDesc ToColorspaceDesc(const gfx::YUVRangedColorSpace cs) { + switch (cs) { + case gfx::YUVRangedColorSpace::BT601_Narrow: + return { + .chrom = color::Chromaticities::Rec601_525_Ntsc(), + .tf = color::PiecewiseGammaDesc::Rec709(), + .yuv = + color::YuvDesc{ + .yCoeffs = color::YuvLumaCoeffs::Rec709(), + .ycbcr = color::YcbcrDesc::Narrow8(), + }, + }; + case gfx::YUVRangedColorSpace::BT601_Full: + return { + .chrom = color::Chromaticities::Rec601_525_Ntsc(), + .tf = color::PiecewiseGammaDesc::Rec709(), + .yuv = + color::YuvDesc{ + .yCoeffs = color::YuvLumaCoeffs::Rec709(), + .ycbcr = color::YcbcrDesc::Full8(), + }, + }; + case gfx::YUVRangedColorSpace::BT709_Narrow: + return { + .chrom = color::Chromaticities::Rec709(), + .tf = color::PiecewiseGammaDesc::Rec709(), + .yuv = + color::YuvDesc{ + .yCoeffs = color::YuvLumaCoeffs::Rec709(), + .ycbcr = color::YcbcrDesc::Narrow8(), + }, + }; + case gfx::YUVRangedColorSpace::BT709_Full: + return { + .chrom = color::Chromaticities::Rec709(), + .tf = color::PiecewiseGammaDesc::Rec709(), + .yuv = + color::YuvDesc{ + .yCoeffs = color::YuvLumaCoeffs::Rec709(), + .ycbcr = color::YcbcrDesc::Full8(), + }, + }; + case gfx::YUVRangedColorSpace::BT2020_Narrow: + return { + .chrom = color::Chromaticities::Rec2020(), + .tf = color::PiecewiseGammaDesc::Rec2020_12bit(), + .yuv = + color::YuvDesc{ + .yCoeffs = color::YuvLumaCoeffs::Rec709(), + .ycbcr = color::YcbcrDesc::Narrow8(), + }, + }; + case gfx::YUVRangedColorSpace::BT2020_Full: + return { + .chrom = color::Chromaticities::Rec2020(), + .tf = color::PiecewiseGammaDesc::Rec2020_12bit(), + .yuv = + color::YuvDesc{ + .yCoeffs = color::YuvLumaCoeffs::Rec2020(), + .ycbcr = color::YcbcrDesc::Full8(), + }, + }; + case gfx::YUVRangedColorSpace::GbrIdentity: + return { + .chrom = color::Chromaticities::Rec709(), + .tf = color::PiecewiseGammaDesc::Rec709(), + .yuv = + color::YuvDesc{ + .yCoeffs = color::YuvLumaCoeffs::Gbr(), + .ycbcr = color::YcbcrDesc::Full8(), + }, + }; + } + MOZ_CRASH("Bad YUVRangedColorSpace."); +} + +static std::optional<color::ColorProfileDesc> ToColorProfileDesc( + gfx::ColorSpace2); + +} // namespace gl +namespace gfx { + +color::ColorProfileDesc QueryOutputColorProfile(); + +} // namespace gfx +namespace gl { + +// - + +static std::optional<color::ColorProfileDesc> ToColorProfileDesc( + const gfx::ColorSpace2 cspace) { + color::ColorspaceDesc cspaceDesc; + switch (cspace) { + case gfx::ColorSpace2::Display: + if (kIsWindows) { +#ifdef XP_WIN + return gfx::QueryOutputColorProfile(); +#endif + } + return {}; + + case gfx::ColorSpace2::SRGB: + cspaceDesc = {.chrom = color::Chromaticities::Srgb(), + .tf = color::PiecewiseGammaDesc::Srgb()}; + break; + case gfx::ColorSpace2::DISPLAY_P3: + cspaceDesc = {.chrom = color::Chromaticities::DisplayP3(), + .tf = color::PiecewiseGammaDesc::DisplayP3()}; + break; + case gfx::ColorSpace2::BT601_525: // aka smpte170m NTSC + cspaceDesc = {.chrom = color::Chromaticities::Rec601_525_Ntsc(), + .tf = color::PiecewiseGammaDesc::Rec709()}; + break; + case gfx::ColorSpace2::BT709: // Same gamut as SRGB, but different gamma. + cspaceDesc = {.chrom = color::Chromaticities::Rec709(), + .tf = color::PiecewiseGammaDesc::Rec709()}; + break; + case gfx::ColorSpace2::BT2020: + cspaceDesc = {.chrom = color::Chromaticities::Rec2020(), + .tf = color::PiecewiseGammaDesc::Rec2020_12bit()}; + break; + } + const auto profileDesc = color::ColorProfileDesc::From(cspaceDesc); + return profileDesc; +} + +// - + +// For std::visit +template <class... Ts> +struct overloaded : Ts... { + using Ts::operator()...; +}; +// explicit deduction guide (not needed as of C++20) +template <class... Ts> +overloaded(Ts...) -> overloaded<Ts...>; + +// - + +template <typename C, typename K> +inline auto MaybeFind(C& container, const K& key) + -> decltype(&(container.find(key)->second)) { + const auto itr = container.find(key); + if (itr == container.end()) return nullptr; + return &(itr->second); +} + +// - + std::shared_ptr<gl::Texture> GLBlitHelper::GetColorLutTex( - const ColorLutKey& key) const { - auto& weak = mColorLutTexMap[key]; - auto strong = weak.lock(); - if (!strong) { + const ColorLutKey& request) const { + if (const auto found = MaybeFind(mColorLutTexMap, request)) { + return *found; // Might be *Some(nullptr) -> nullptr! + } + + return mColorLutTexMap[request] = [&]() -> std::shared_ptr<gl::Texture> { auto& gl = *mGL; - strong = std::make_shared<gl::Texture>(gl); - weak = strong; + const auto tex = std::make_shared<gl::Texture>(gl); + + // - - const auto ct = color::ColorspaceTransform::Create(key.src, key.dst); + const std::optional<color::ColorProfileDesc> srcProfile = + std::visit(overloaded{ + [&](const gfx::ColorSpace2& cs) + -> std::optional<color::ColorProfileDesc> { + MOZ_ASSERT(cs != request.dst); + const auto cpd = ToColorProfileDesc(cs); + return cpd; + }, + [&](const gfx::YUVRangedColorSpace& cs) + -> std::optional<color::ColorProfileDesc> { + const auto csd = ToColorspaceDesc(cs); + const auto cpd = color::ColorProfileDesc::From(csd); + return cpd; + }, + }, + request.src); + MOZ_ASSERT(srcProfile); + + const auto dstProfile = ToColorProfileDesc(request.dst); + if (kIsWindows) { + MOZ_ASSERT(dstProfile); + } + if (!srcProfile || !dstProfile) return nullptr; + const auto conversion = color::ColorProfileConversionDesc::From({ + .src = *srcProfile, + .dst = *dstProfile, + }); // - const auto minLutSize = color::ivec3{2}; const auto maxLutSize = color::ivec3{256}; auto lutSize = minLutSize; - if (ct.srcSpace.yuv) { + const bool isYcbcr = + (conversion.srcRgbFromSrcYuv != color::mat4::Identity()); + if (isYcbcr) { lutSize.x(int(StaticPrefs::gfx_blithelper_lut_size_ycbcr_y())); lutSize.y(int(StaticPrefs::gfx_blithelper_lut_size_ycbcr_cb())); lutSize.z(int(StaticPrefs::gfx_blithelper_lut_size_ycbcr_cr())); @@ -1628,15 +1828,20 @@ std::shared_ptr<gl::Texture> GLBlitHelper::GetColorLutTex( lutSize.y(int(StaticPrefs::gfx_blithelper_lut_size_rgb_g())); lutSize.z(int(StaticPrefs::gfx_blithelper_lut_size_rgb_b())); } - lutSize = max(minLutSize, min(lutSize, maxLutSize)); // Clamp - - const auto lut = ct.ToLut3(lutSize); + lutSize = clamp(lutSize, minLutSize, maxLutSize); + + const auto lut = [&]() { + auto lut = color::Lut3::Create(lutSize); + lut.SetMap( + [&](const color::vec3& src) { return conversion.DstFromSrc(src); }); + return lut; + }(); const auto& size = lut.size; // - constexpr GLenum target = LOCAL_GL_TEXTURE_3D; - const auto bind = gl::ScopedBindTexture(&gl, strong->name, target); + const auto bind = gl::ScopedBindTexture(&gl, tex->name, target); gl.fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); gl.fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); gl.fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE); @@ -1673,8 +1878,8 @@ std::shared_ptr<gl::Texture> GLBlitHelper::GetColorLutTex( LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV, uploadData.data()); } - } - return strong; + return tex; + }(); } } // namespace gl diff --git a/gfx/gl/GLBlitHelper.h b/gfx/gl/GLBlitHelper.h index 8391509097..3f9e066c0e 100644 --- a/gfx/gl/GLBlitHelper.h +++ b/gfx/gl/GLBlitHelper.h @@ -12,6 +12,7 @@ #include <map> #include <memory> #include <unordered_map> +#include <variant> #include "Colorspaces.h" #include "GLConsts.h" #include "GLContextTypes.h" @@ -126,6 +127,8 @@ Mat3 SubRectMat3(const gfx::IntRect& bigSubrect, const gfx::IntSize& smallSize, class DrawBlitProg final { const GLBlitHelper& mParent; + + public: const GLuint mProg; const GLint mLoc_uDestMatrix; const GLint mLoc_uTexMatrix0; @@ -154,7 +157,6 @@ class DrawBlitProg final { gfx::IntSize destSize; // Always needed for (at least) setting the viewport. Maybe<gfx::IntRect> destRect; - Maybe<uint32_t> texUnitForColorLut; }; struct YUVArgs final { Mat3 texMatrix1; @@ -166,15 +168,14 @@ class DrawBlitProg final { class ScopedSaveMultiTex final { GLContext& mGL; - const std::vector<uint8_t> mTexUnits; + const size_t mTexUnits; const GLenum mTexTarget; const GLuint mOldTexUnit; GLuint mOldTexSampler[3]; GLuint mOldTex[3]; public: - ScopedSaveMultiTex(GLContext* gl, const std::vector<uint8_t>& texUnits, - GLenum texTarget); + ScopedSaveMultiTex(GLContext* gl, size_t texUnits, GLenum texTarget); ~ScopedSaveMultiTex(); }; @@ -185,7 +186,8 @@ class GLBlitHelper final { friend class GLContext; GLContext* const mGL; - mutable std::map<DrawBlitProg::Key, const DrawBlitProg*> mDrawBlitProgs; + mutable std::map<DrawBlitProg::Key, std::unique_ptr<const DrawBlitProg>> + mDrawBlitProgs; GLuint mQuadVAO = 0; GLuint mQuadVBO = 0; @@ -197,16 +199,19 @@ class GLBlitHelper final { gfx::IntSize mYuvUploads_UVSize = {0, 0}; public: - struct ColorLutKey { - color::ColorspaceDesc src; - color::ColorspaceDesc dst; + struct ColorLutKey : DeriveCmpOpMembers<ColorLutKey> { + std::variant<gfx::ColorSpace2, gfx::YUVRangedColorSpace> src; + gfx::ColorSpace2 dst; auto Members() const { return std::tie(src, dst); } - INLINE_AUTO_MAPPABLE(ColorLutKey) + + MOZ_MIXIN_DERIVE_CMP_OPS_BY_MEMBERS(ColorLutKey) + + struct Hasher : mozilla::StdHashMembers<ColorLutKey> {}; }; private: - mutable std::unordered_map<ColorLutKey, std::weak_ptr<gl::Texture>, + mutable std::unordered_map<ColorLutKey, std::shared_ptr<gl::Texture>, ColorLutKey::Hasher> mColorLutTexMap; @@ -219,10 +224,11 @@ class GLBlitHelper final { ID3D11Device* GetD3D11() const; #endif - const DrawBlitProg* GetDrawBlitProg(const DrawBlitProg::Key& key) const; + const DrawBlitProg& GetDrawBlitProg(const DrawBlitProg::Key& key) const; private: - const DrawBlitProg* CreateDrawBlitProg(const DrawBlitProg::Key& key) const; + std::unique_ptr<const DrawBlitProg> CreateDrawBlitProg( + const DrawBlitProg::Key& key) const; public: bool BlitPlanarYCbCr(const layers::PlanarYCbCrData&, @@ -326,7 +332,8 @@ extern const char* const kFragSample_ThreePlane; extern const char* const kFragConvert_None; extern const char* const kFragConvert_BGR; extern const char* const kFragConvert_ColorMatrix; -extern const char* const kFragConvert_ColorLut; +extern const char* const kFragConvert_ColorLut3d; +extern const char* const kFragConvert_ColorLut2d; extern const char* const kFragMixin_AlphaMultColors; extern const char* const kFragMixin_AlphaClampColors; diff --git a/gfx/gl/GLBlitHelperD3D.cpp b/gfx/gl/GLBlitHelperD3D.cpp index ae6362e278..1c101d8980 100644 --- a/gfx/gl/GLBlitHelperD3D.cpp +++ b/gfx/gl/GLBlitHelperD3D.cpp @@ -95,16 +95,7 @@ class BindAnglePlanes final { const EGLAttrib* const* postAttribsList = nullptr) : mParent(*parent), mNumPlanes(numPlanes), - mMultiTex( - mParent.mGL, - [&]() { - std::vector<uint8_t> ret; - for (int i = 0; i < numPlanes; i++) { - ret.push_back(i); - } - return ret; - }(), - LOCAL_GL_TEXTURE_EXTERNAL), + mMultiTex(mParent.mGL, mNumPlanes, LOCAL_GL_TEXTURE_EXTERNAL), mTempTexs{0}, mStreams{0}, mSuccess(true) { @@ -336,7 +327,7 @@ bool GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc, const auto& prog = GetDrawBlitProg( {kFragHeader_TexExt, {kFragSample_TwoPlane, kFragConvert_ColorMatrix}}); - prog->Draw(baseArgs, &yuvArgs); + prog.Draw(baseArgs, &yuvArgs); return true; } @@ -391,7 +382,7 @@ bool GLBlitHelper::BlitAngleYCbCr(const WindowsHandle (&handleList)[3], const auto& prog = GetDrawBlitProg( {kFragHeader_TexExt, {kFragSample_ThreePlane, kFragConvert_ColorMatrix}}); - prog->Draw(baseArgs, &yuvArgs); + prog.Draw(baseArgs, &yuvArgs); return true; } diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index eea26024ae..4ee256b053 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -45,6 +45,12 @@ #include "mozilla/GenericRefCounted.h" #include "mozilla/WeakPtr.h" +template <class ElemT, class... More> +constexpr inline std::array<ElemT, 1 + sizeof...(More)> make_array( + ElemT&& arg1, More&&... more) { + return {std::forward<ElemT>(arg1), std::forward<ElemT>(more)...}; +} + #ifdef MOZ_WIDGET_ANDROID # include "mozilla/ProfilerLabels.h" #endif @@ -797,8 +803,15 @@ class GLContext : public GenericAtomicRefCounted, public SupportsWeakPtr { AFTER_GL_CALL; } + void InvalidateFramebuffer(GLenum target) { + constexpr auto ATTACHMENTS = make_array(GLenum{LOCAL_GL_COLOR_ATTACHMENT0}, + LOCAL_GL_DEPTH_STENCIL_ATTACHMENT); + fInvalidateFramebuffer(target, ATTACHMENTS.size(), ATTACHMENTS.data()); + } + void fInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments) { + if (!mSymbols.fInvalidateFramebuffer) return; BeforeGLDrawCall(); BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fInvalidateFramebuffer); @@ -810,6 +823,7 @@ class GLContext : public GenericAtomicRefCounted, public SupportsWeakPtr { void fInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) { + if (!mSymbols.fInvalidateSubFramebuffer) return; BeforeGLDrawCall(); BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fInvalidateSubFramebuffer); @@ -825,6 +839,13 @@ class GLContext : public GenericAtomicRefCounted, public SupportsWeakPtr { AFTER_GL_CALL; } + void BindSamplerTexture(GLuint texUnitId, GLuint samplerHandle, + GLenum texTarget, GLuint texHandle) { + fBindSampler(texUnitId, samplerHandle); + fActiveTexture(LOCAL_GL_TEXTURE0 + texUnitId); + fBindTexture(texTarget, texHandle); + } + void fBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { BEFORE_GL_CALL; mSymbols.fBlendColor(red, green, blue, alpha); @@ -2028,7 +2049,11 @@ class GLContext : public GenericAtomicRefCounted, public SupportsWeakPtr { public: bool mElideDuplicateBindFramebuffers = false; - void fBindFramebuffer(const GLenum target, const GLuint fb) const { + // If e.g. GL_DRAW_FRAMEBUFFER isn't supported, will bind GL_FRAMEBUFFER. + void fBindFramebuffer(GLenum target, const GLuint fb) const { + if (!IsSupported(gl::GLFeature::framebuffer_blit)) { + target = LOCAL_GL_FRAMEBUFFER; + } if (mElideDuplicateBindFramebuffers) { MOZ_ASSERT(mCachedDrawFb == GetIntAs<GLuint>(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING)); @@ -3861,6 +3886,30 @@ class Texture final { } }; +// - + +class Sampler final { + public: + const WeakPtr<GLContext> weakGl; + const GLuint name; + + private: + static GLuint Create(GLContext& gl) { + GLuint ret = 0; + gl.fGenSamplers(1, &ret); + return ret; + } + + public: + explicit Sampler(GLContext& gl) : weakGl(&gl), name(Create(gl)) {} + + ~Sampler() { + const RefPtr<GLContext> gl = weakGl.get(); + if (!gl || !gl->MakeCurrent()) return; + gl->fDeleteSamplers(1, &name); + } +}; + /** * Helper function that creates a 2D texture aSize.width x aSize.height with * storage type specified by aFormats. Returns GL texture object id. diff --git a/gfx/gl/GLContextGLX.h b/gfx/gl/GLContextGLX.h index b6f6e9a959..c7fce3f86a 100644 --- a/gfx/gl/GLContextGLX.h +++ b/gfx/gl/GLContextGLX.h @@ -24,9 +24,9 @@ class GLContextGLX : public GLContext { static bool FindVisual(Display* display, int screen, int* const out_visualId); // Finds a GLXFBConfig compatible with the provided window. - static bool FindFBConfigForWindow( - Display* display, int screen, Window window, - GLXFBConfig* const out_config, int* const out_visid, bool aWebRender); + static bool FindFBConfigForWindow(Display* display, int screen, Window window, + GLXFBConfig* const out_config, + int* const out_visid, bool aWebRender); virtual ~GLContextGLX(); diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp index cdc5e7ce1a..a7218cd39f 100644 --- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -603,9 +603,8 @@ already_AddRefed<GLContext> CreateForWidget(Display* aXDisplay, Window aXWindow, GLXFBConfig config; int visid; - if (!GLContextGLX::FindFBConfigForWindow(aXDisplay, xscreen, aXWindow, - &config, &visid, - aHardwareWebRender)) { + if (!GLContextGLX::FindFBConfigForWindow( + aXDisplay, xscreen, aXWindow, &config, &visid, aHardwareWebRender)) { return nullptr; } @@ -658,7 +657,8 @@ static bool ChooseConfig(GLXLibrary* glx, Display* display, int screen, }; int numConfigs = 0; - const auto scopedConfigArr = glx->fChooseFBConfig(display, screen, attribs, &numConfigs); + const auto scopedConfigArr = + glx->fChooseFBConfig(display, screen, attribs, &numConfigs); const auto freeConfigList = MakeScopeExit([&]() { if (scopedConfigArr) { XFree(scopedConfigArr); @@ -764,9 +764,11 @@ bool GLContextGLX::FindVisual(Display* display, int screen, return false; } -bool GLContextGLX::FindFBConfigForWindow( - Display* display, int screen, Window window, - GLXFBConfig* const out_config, int* const out_visid, bool aWebRender) { +bool GLContextGLX::FindFBConfigForWindow(Display* display, int screen, + Window window, + GLXFBConfig* const out_config, + int* const out_visid, + bool aWebRender) { // XXX the visual ID is almost certainly the LOCAL_GLX_FBCONFIG_ID, so // we could probably do this first and replace the glXGetFBConfigs // with glXChooseConfigs. Docs are sparklingly clear as always. diff --git a/gfx/gl/GLScreenBuffer.cpp b/gfx/gl/GLScreenBuffer.cpp index 9dda11b41a..6550698eb5 100644 --- a/gfx/gl/GLScreenBuffer.cpp +++ b/gfx/gl/GLScreenBuffer.cpp @@ -10,22 +10,13 @@ #include "gfx2DGlue.h" #include "MozFramebuffer.h" #include "SharedSurface.h" +#include "mozilla/gfx/BuildConstants.h" namespace mozilla::gl { // - // SwapChainPresenter -// We need to apply pooling on Android because of the AndroidSurface slow -// destructor bugs. They cause a noticeable performance hit. See bug -// #1646073. -static constexpr size_t kPoolSize = -#if defined(MOZ_WIDGET_ANDROID) - 4; -#else - 0; -#endif - UniquePtr<SwapChainPresenter> SwapChain::Acquire( const gfx::IntSize& size, const gfx::ColorSpace2 colorSpace) { MOZ_ASSERT(mFactory); @@ -42,11 +33,9 @@ UniquePtr<SwapChainPresenter> SwapChain::Acquire( } } - // When mDestroyedCallback exists, recycling of SharedSurfaces is managed by - // the owner of the SwapChain by calling StoreRecycledSurface(). - const auto poolSize = mDestroyedCallback ? 0 : kPoolSize; - - if (!mPool.empty() && (!poolSize || mPool.size() == poolSize)) { + // When pooling is disabled, recycling of SharedSurfaces is managed by the + // owner of the SwapChain by calling StoreRecycledSurface(). + if (!mPool.empty() && (!mPoolLimit || mPool.size() >= mPoolLimit)) { surf = mPool.front(); mPool.pop(); } @@ -55,9 +44,11 @@ UniquePtr<SwapChainPresenter> SwapChain::Acquire( if (!uniquePtrSurf) return nullptr; surf.reset(uniquePtrSurf.release()); } - mPool.push(surf); - while (mPool.size() > poolSize) { - mPool.pop(); + if (mPoolLimit > 0) { + mPool.push(surf); + while (mPool.size() > mPoolLimit) { + mPool.pop(); + } } auto ret = MakeUnique<SwapChainPresenter>(*this); @@ -74,7 +65,10 @@ void SwapChain::ClearPool() { bool SwapChain::StoreRecycledSurface( const std::shared_ptr<SharedSurface>& surf) { MOZ_ASSERT(mFactory); - if (!mFactory || NS_WARN_IF(surf->mDesc.gl != mFactory->mDesc.gl)) { + // Don't allow external recycled surfaces if SwapChain is managing own pool. + MOZ_ASSERT(!mPoolLimit); + if (mPoolLimit > 0 || !mFactory || + NS_WARN_IF(surf->mDesc.gl != mFactory->mDesc.gl)) { // Ensure we don't accidentally store an expired shared surface or from a // different context. return false; @@ -130,7 +124,11 @@ GLuint SwapChainPresenter::Fb() const { // - // SwapChain -SwapChain::SwapChain() = default; +SwapChain::SwapChain() + : // We need to apply pooling on Android because of the AndroidSurface slow + // destructor bugs. They cause a noticeable performance hit. See bug + // #1646073. + mPoolLimit(kIsAndroid ? 4 : 0) {} SwapChain::~SwapChain() { if (mPresenter) { diff --git a/gfx/gl/GLScreenBuffer.h b/gfx/gl/GLScreenBuffer.h index d281249771..ace3145f7a 100644 --- a/gfx/gl/GLScreenBuffer.h +++ b/gfx/gl/GLScreenBuffer.h @@ -55,6 +55,7 @@ class SwapChain final { UniquePtr<SurfaceFactory> mFactory; private: + size_t mPoolLimit; std::queue<std::shared_ptr<SharedSurface>> mPool; std::shared_ptr<SharedSurface> mFrontBuffer; std::function<void()> mDestroyedCallback; @@ -69,6 +70,14 @@ class SwapChain final { SwapChain(); virtual ~SwapChain(); + void DisablePool() { + if (mPoolLimit) { + MOZ_ASSERT(mPool.empty()); + mPool = {}; + mPoolLimit = 0; + } + } + void ClearPool(); bool StoreRecycledSurface(const std::shared_ptr<SharedSurface>& surf); const auto& FrontBuffer() const { return mFrontBuffer; } diff --git a/gfx/gl/SharedSurface.h b/gfx/gl/SharedSurface.h index 4168de69a2..12aace9e9e 100644 --- a/gfx/gl/SharedSurface.h +++ b/gfx/gl/SharedSurface.h @@ -182,8 +182,13 @@ class SurfaceFactory { const SharedSurfaceDesc&) = 0; public: + virtual bool SupportsCspaces() const { return false; } + UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size, gfx::ColorSpace2 cs) { + if (!SupportsCspaces()) { + cs = gfx::ColorSpace2::Display; + } return CreateSharedImpl({mDesc, size, cs}); } }; diff --git a/gfx/gl/SharedSurfaceIO.h b/gfx/gl/SharedSurfaceIO.h index 938173b982..94804e3d0c 100644 --- a/gfx/gl/SharedSurfaceIO.h +++ b/gfx/gl/SharedSurfaceIO.h @@ -47,6 +47,8 @@ class SurfaceFactory_IOSurface : public SurfaceFactory { explicit SurfaceFactory_IOSurface(GLContext& gl); + bool SupportsCspaces() const override { return true; } + virtual UniquePtr<SharedSurface> CreateSharedImpl( const SharedSurfaceDesc& desc) override { if (desc.size.width > mMaxDims.width || diff --git a/gfx/gl/gtest/TestColorspaces.cpp b/gfx/gl/gtest/TestColorspaces.cpp index c437e204af..31a907115f 100644 --- a/gfx/gl/gtest/TestColorspaces.cpp +++ b/gfx/gl/gtest/TestColorspaces.cpp @@ -650,7 +650,7 @@ TEST(Colorspaces, ColorProfileConversionDesc_SrgbFromRec709) .dst = srgb, }); auto src = vec3(16.0); - auto dst = conv.Apply(src / 255) * 255; + auto dst = conv.DstFromSrc(src / 255) * 255; const auto tfa = PiecewiseGammaDesc::Srgb(); const auto tfb = PiecewiseGammaDesc::Srgb(); @@ -667,7 +667,7 @@ TEST(Colorspaces, ColorProfileConversionDesc_SrgbFromRec709) .dst = rec709, }); auto src = vec3(16.0); - auto dst = conv.Apply(src / 255) * 255; + auto dst = conv.DstFromSrc(src / 255) * 255; const auto tfa = PiecewiseGammaDesc::Rec709(); const auto tfb = PiecewiseGammaDesc::Rec709(); @@ -684,7 +684,7 @@ TEST(Colorspaces, ColorProfileConversionDesc_SrgbFromRec709) .dst = srgb, }); auto src = vec3(16.0); - auto dst = conv.Apply(src / 255) * 255; + auto dst = conv.DstFromSrc(src / 255) * 255; const auto tfa = PiecewiseGammaDesc::Rec709(); const auto tfb = PiecewiseGammaDesc::Srgb(); @@ -696,3 +696,9 @@ TEST(Colorspaces, ColorProfileConversionDesc_SrgbFromRec709) EXPECT_LT(Stats::Diff(dst.data, vec3(expected).data), (Stats::Error{0.12})); } } + +TEST(Colorspaces, SampleOutByIn_NegativeInputs) +{ + const auto tf = MakeGamma(1.0 / 2.2, 256); + EXPECT_LT(SampleOutByIn(tf, -0.1f), 0.0f); +} |