summaryrefslogtreecommitdiffstats
path: root/gfx/gl
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/gl')
-rw-r--r--gfx/gl/AutoMappable.h139
-rw-r--r--gfx/gl/Colorspaces.h128
-rw-r--r--gfx/gl/GLBlitHelper.cpp333
-rw-r--r--gfx/gl/GLBlitHelper.h33
-rw-r--r--gfx/gl/GLBlitHelperD3D.cpp15
-rw-r--r--gfx/gl/GLContext.h51
-rw-r--r--gfx/gl/GLContextGLX.h6
-rw-r--r--gfx/gl/GLContextProviderGLX.cpp16
-rw-r--r--gfx/gl/GLScreenBuffer.cpp38
-rw-r--r--gfx/gl/GLScreenBuffer.h9
-rw-r--r--gfx/gl/SharedSurface.h5
-rw-r--r--gfx/gl/SharedSurfaceIO.h2
-rw-r--r--gfx/gl/gtest/TestColorspaces.cpp12
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);
+}