Merge Mozilla-Central to autoland on a CLOSED TREE

This commit is contained in:
Narcis Beleuzu
2022-07-14 00:55:03 +03:00
35 changed files with 654 additions and 2960 deletions

View File

@@ -375,7 +375,7 @@
"win64-aarch64-devedition", "win64-aarch64-devedition",
"win64-devedition" "win64-devedition"
], ],
"revision": "67eaf7b8567d2218ee41e471f3a005ca1600ef73" "revision": "6b4b0ae8e0ffa38f93c2c22f03fef69773fcd07b"
}, },
"dsb": { "dsb": {
"pin": false, "pin": false,
@@ -573,7 +573,7 @@
"win64-aarch64-devedition", "win64-aarch64-devedition",
"win64-devedition" "win64-devedition"
], ],
"revision": "0514b8ca1030ff90e0a7b29a9ebea755168b2313" "revision": "174b873f4533e337d6dc38c2078659c88c84410b"
}, },
"fa": { "fa": {
"pin": false, "pin": false,
@@ -645,7 +645,7 @@
"win64-aarch64-devedition", "win64-aarch64-devedition",
"win64-devedition" "win64-devedition"
], ],
"revision": "6882ca7fa00f38b0d3bcad53e21c89cb9abed6eb" "revision": "487e032424d7446a5f61a54ca3da24587f8f4828"
}, },
"fy-NL": { "fy-NL": {
"pin": false, "pin": false,
@@ -735,7 +735,7 @@
"win64-aarch64-devedition", "win64-aarch64-devedition",
"win64-devedition" "win64-devedition"
], ],
"revision": "8f98871656645963a427efede7d78370054777ad" "revision": "6cd831b171157b9afb805ddb1f50a659cce4be9c"
}, },
"gu-IN": { "gu-IN": {
"pin": false, "pin": false,
@@ -825,7 +825,7 @@
"win64-aarch64-devedition", "win64-aarch64-devedition",
"win64-devedition" "win64-devedition"
], ],
"revision": "691ca84c8ed6e7a8f34e5a333145256e710daa8f" "revision": "ed7657e98e5cc37d7d34bdb94d3f1b47aa1a5778"
}, },
"hu": { "hu": {
"pin": false, "pin": false,
@@ -933,7 +933,7 @@
"win64-aarch64-devedition", "win64-aarch64-devedition",
"win64-devedition" "win64-devedition"
], ],
"revision": "4a8c06a8ce86e4eca903415dc8f238cd238befb8" "revision": "a1016f7482f79804a71669a0d2482ada4da28079"
}, },
"it": { "it": {
"pin": false, "pin": false,
@@ -951,7 +951,7 @@
"win64-aarch64-devedition", "win64-aarch64-devedition",
"win64-devedition" "win64-devedition"
], ],
"revision": "83829ea070d72aa3c7739a853fc02006ee2edfa3" "revision": "112cd454a1ae890b74e6b8993f02793484c58aaf"
}, },
"ja": { "ja": {
"pin": false, "pin": false,
@@ -1011,7 +1011,7 @@
"win64-aarch64-devedition", "win64-aarch64-devedition",
"win64-devedition" "win64-devedition"
], ],
"revision": "bd32464f21975d130a3bb976cd927210521a14e8" "revision": "38978bbf4ce2f47769782d25d9f74b86eaffc873"
}, },
"kk": { "kk": {
"pin": false, "pin": false,
@@ -1335,7 +1335,7 @@
"win64-aarch64-devedition", "win64-aarch64-devedition",
"win64-devedition" "win64-devedition"
], ],
"revision": "f912fd6abb8923552022efc143b3ce0575f7c42f" "revision": "ffd0b6679b71b869f34f421717c870cffbe85c0a"
}, },
"oc": { "oc": {
"pin": false, "pin": false,
@@ -1407,7 +1407,7 @@
"win64-aarch64-devedition", "win64-aarch64-devedition",
"win64-devedition" "win64-devedition"
], ],
"revision": "09bbb0128669de4ad46eee4fb33898dcaf29c33f" "revision": "adc85a64d9ed66b77c6577fa7de696accd900026"
}, },
"pt-PT": { "pt-PT": {
"pin": false, "pin": false,
@@ -1605,7 +1605,7 @@
"win64-aarch64-devedition", "win64-aarch64-devedition",
"win64-devedition" "win64-devedition"
], ],
"revision": "379d4ad776376de619b6dac7bdeec5fb07b460bf" "revision": "edeac7a9fcfc5cf99328b1eb8f1b8a04e9960d0a"
}, },
"son": { "son": {
"pin": false, "pin": false,
@@ -1677,7 +1677,7 @@
"win64-aarch64-devedition", "win64-aarch64-devedition",
"win64-devedition" "win64-devedition"
], ],
"revision": "a81d25fcbdb14eb04a5c7c25b75d781a2102dd0c" "revision": "b9610eb563b3906b4aef08694d48182c7d306516"
}, },
"szl": { "szl": {
"pin": false, "pin": false,
@@ -1749,7 +1749,7 @@
"win64-aarch64-devedition", "win64-aarch64-devedition",
"win64-devedition" "win64-devedition"
], ],
"revision": "f84d4717f7e9fd9bd0061715e19aa956812e9743" "revision": "c630543e2422ff1fed3fa36a97b5524be3debbff"
}, },
"th": { "th": {
"pin": false, "pin": false,

View File

@@ -895,11 +895,13 @@ ClientWebGLContext::SetContextOptions(JSContext* cx,
if (attributes.mAntialias.WasPassed()) { if (attributes.mAntialias.WasPassed()) {
newOpts.antialias = attributes.mAntialias.Value(); newOpts.antialias = attributes.mAntialias.Value();
} }
newOpts.ignoreColorSpace = true;
if (attributes.mColorSpace.WasPassed()) { if (attributes.mColorSpace.WasPassed()) {
newOpts.ignoreColorSpace = false;
newOpts.colorSpace = attributes.mColorSpace.Value(); newOpts.colorSpace = attributes.mColorSpace.Value();
} }
if (StaticPrefs::gfx_color_management_native_srgb()) {
newOpts.ignoreColorSpace = false;
}
// Don't do antialiasing if we've disabled MSAA. // Don't do antialiasing if we've disabled MSAA.
if (!StaticPrefs::webgl_msaa_samples()) { if (!StaticPrefs::webgl_msaa_samples()) {

View File

@@ -106,6 +106,22 @@ WebGLContextOptions::WebGLContextOptions() {
antialias = StaticPrefs::webgl_default_antialias(); antialias = StaticPrefs::webgl_default_antialias();
} }
bool WebGLContextOptions::operator==(const WebGLContextOptions& r) const {
bool eq = true;
eq &= (alpha == r.alpha);
eq &= (depth == r.depth);
eq &= (stencil == r.stencil);
eq &= (premultipliedAlpha == r.premultipliedAlpha);
eq &= (antialias == r.antialias);
eq &= (preserveDrawingBuffer == r.preserveDrawingBuffer);
eq &= (failIfMajorPerformanceCaveat == r.failIfMajorPerformanceCaveat);
eq &= (xrCompatible == r.xrCompatible);
eq &= (powerPreference == r.powerPreference);
eq &= (colorSpace == r.colorSpace);
eq &= (ignoreColorSpace == r.ignoreColorSpace);
return eq;
}
StaticMutex WebGLContext::sLruMutex; StaticMutex WebGLContext::sLruMutex;
std::list<WebGLContext*> WebGLContext::sLru; std::list<WebGLContext*> WebGLContext::sLru;
@@ -894,14 +910,10 @@ constexpr auto MakeArray(Args... args) -> std::array<T, sizeof...(Args)> {
} }
inline gfx::ColorSpace2 ToColorSpace2(const WebGLContextOptions& options) { inline gfx::ColorSpace2 ToColorSpace2(const WebGLContextOptions& options) {
auto ret = gfx::ColorSpace2::UNKNOWN; if (options.ignoreColorSpace) {
if (StaticPrefs::gfx_color_management_native_srgb()) { return gfx::ColorSpace2::UNKNOWN;
ret = gfx::ColorSpace2::SRGB;
} }
if (!options.ignoreColorSpace) { return gfx::ToColorSpace2(options.colorSpace);
ret = gfx::ToColorSpace2(options.colorSpace);
}
return ret;
} }
// - // -

View File

@@ -247,10 +247,7 @@ struct ParamTraits<mozilla::WebGLContextOptions> final
using T = mozilla::WebGLContextOptions; using T = mozilla::WebGLContextOptions;
static bool Validate(const T& val) { static bool Validate(const T& val) {
bool ok = true; return ValidateParam(val.powerPreference) && ValidateParam(val.colorSpace);
ok &= ValidateParam(val.powerPreference);
ok &= ValidateParam(val.colorSpace);
return ok;
} }
}; };

View File

@@ -8,7 +8,6 @@
#include <limits> #include <limits>
#include <string> #include <string>
#include <tuple>
#include <type_traits> #include <type_traits>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@@ -349,57 +348,29 @@ struct FloatOrInt final // For TexParameter[fi] and friends.
explicit FloatOrInt(GLfloat x) : isFloat(true), f(x), i(roundf(x)) {} explicit FloatOrInt(GLfloat x) : isFloat(true), f(x), i(roundf(x)) {}
}; };
struct WebGLContextOptions final { struct WebGLContextOptions {
bool alpha = true; bool alpha = true;
bool depth = true; bool depth = true;
bool stencil = false; bool stencil = false;
bool premultipliedAlpha = true; bool premultipliedAlpha = true;
bool antialias = true; bool antialias = true;
bool preserveDrawingBuffer = false; bool preserveDrawingBuffer = false;
bool failIfMajorPerformanceCaveat = false; bool failIfMajorPerformanceCaveat = false;
bool xrCompatible = false; bool xrCompatible = false;
dom::WebGLPowerPreference powerPreference = dom::WebGLPowerPreference powerPreference =
dom::WebGLPowerPreference::Default; dom::WebGLPowerPreference::Default;
bool ignoreColorSpace = true;
dom::PredefinedColorSpace colorSpace = dom::PredefinedColorSpace::Srgb; dom::PredefinedColorSpace colorSpace = dom::PredefinedColorSpace::Srgb;
bool ignoreColorSpace = true; // Our legacy behavior.
bool shouldResistFingerprinting = true; bool shouldResistFingerprinting = true;
bool enableDebugRendererInfo = false; bool enableDebugRendererInfo = false;
// -
WebGLContextOptions(); WebGLContextOptions();
WebGLContextOptions(const WebGLContextOptions&) = default; WebGLContextOptions(const WebGLContextOptions&) = default;
auto Fields() const { bool operator==(const WebGLContextOptions&) const;
// clang-format off bool operator!=(const WebGLContextOptions& rhs) const {
return std::tie( return !(*this == rhs);
alpha,
depth,
stencil,
premultipliedAlpha,
antialias,
preserveDrawingBuffer,
failIfMajorPerformanceCaveat,
xrCompatible,
powerPreference,
ignoreColorSpace,
colorSpace,
shouldResistFingerprinting,
enableDebugRendererInfo);
// clang-format on
} }
using Self = WebGLContextOptions;
friend bool operator==(const Self& a, const Self& b) {
return a.Fields() == b.Fields();
}
friend bool operator!=(const Self& a, const Self& b) { return !(a == b); }
}; };
namespace gfx { namespace gfx {

View File

@@ -1047,9 +1047,8 @@ D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample,
NS_ENSURE_TRUE(aOutImage, E_POINTER); NS_ENSURE_TRUE(aOutImage, E_POINTER);
MOZ_ASSERT(mTextureClientAllocator); MOZ_ASSERT(mTextureClientAllocator);
RefPtr<D3D11ShareHandleImage> image = RefPtr<D3D11ShareHandleImage> image = new D3D11ShareHandleImage(
new D3D11ShareHandleImage(gfx::IntSize(mWidth, mHeight), aRegion, gfx::IntSize(mWidth, mHeight), aRegion, mYUVColorSpace, mColorRange);
ToColorSpace2(mYUVColorSpace), mColorRange);
// Retrieve the DXGI_FORMAT for the current video sample. // Retrieve the DXGI_FORMAT for the current video sample.
RefPtr<IMFMediaBuffer> buffer; RefPtr<IMFMediaBuffer> buffer;
@@ -1174,7 +1173,7 @@ HRESULT D3D11DXVA2Manager::WrapTextureWithImage(IMFSample* aVideoSample,
RefPtr<D3D11TextureIMFSampleImage> image = new D3D11TextureIMFSampleImage( RefPtr<D3D11TextureIMFSampleImage> image = new D3D11TextureIMFSampleImage(
aVideoSample, texture, arrayIndex, gfx::IntSize(mWidth, mHeight), aRegion, aVideoSample, texture, arrayIndex, gfx::IntSize(mWidth, mHeight), aRegion,
ToColorSpace2(mYUVColorSpace), mColorRange); mYUVColorSpace, mColorRange);
image->AllocateTextureClient(mKnowsCompositor, mIMFSampleUsageInfo); image->AllocateTextureClient(mKnowsCompositor, mIMFSampleUsageInfo);
RefPtr<IMFSampleWrapper> wrapper = image->GetIMFSampleWrapper(); RefPtr<IMFSampleWrapper> wrapper = image->GetIMFSampleWrapper();

View File

@@ -386,50 +386,18 @@ enum class YUVRangedColorSpace : uint8_t {
// one. // one.
// Some times Worse Is Better. // Some times Worse Is Better.
enum class ColorSpace2 : uint8_t { enum class ColorSpace2 : uint8_t {
UNKNOWN, // Really "DISPLAY". Eventually we will remove this. UNKNOWN, // Eventually we will remove this.
SRGB, SRGB,
DISPLAY_P3,
BT601_525, // aka smpte170m NTSC BT601_525, // aka smpte170m NTSC
BT709, // Same gamut as SRGB, but different gamma. BT709, // Same gamut as SRGB, but different gamma.
BT601_625 = BT601_625 =
BT709, // aka bt470bg PAL. Basically BT709, just Xg is 0.290 not 0.300. BT709, // aka bt470bg PAL. Basically BT709, just Xg is 0.290 not 0.300.
BT2020, BT2020,
DISPLAY_P3,
_First = UNKNOWN, _First = UNKNOWN,
_Last = BT2020, _Last = DISPLAY_P3,
}; };
inline ColorSpace2 ToColorSpace2(const YUVColorSpace in) {
switch (in) {
case YUVColorSpace::BT601:
return ColorSpace2::BT601_525;
case YUVColorSpace::BT709:
return ColorSpace2::BT709;
case YUVColorSpace::BT2020:
return ColorSpace2::BT2020;
case YUVColorSpace::Identity:
return ColorSpace2::SRGB;
}
MOZ_ASSERT_UNREACHABLE();
}
inline YUVColorSpace ToYUVColorSpace(const ColorSpace2 in) {
switch (in) {
case ColorSpace2::BT601_525:
return YUVColorSpace::BT601;
case ColorSpace2::BT709:
return YUVColorSpace::BT709;
case ColorSpace2::BT2020:
return YUVColorSpace::BT2020;
case ColorSpace2::SRGB:
return YUVColorSpace::Identity;
case ColorSpace2::UNKNOWN:
case ColorSpace2::DISPLAY_P3:
MOZ_CRASH("Bad ColorSpace2 for ToYUVColorSpace");
}
MOZ_ASSERT_UNREACHABLE();
}
struct FromYUVRangedColorSpaceT final { struct FromYUVRangedColorSpaceT final {
const YUVColorSpace space; const YUVColorSpace space;
const ColorRange range; const ColorRange range;

View File

@@ -1,148 +0,0 @@
/* 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_AUTO_MAPPABLE_H
#define MOZILLA_AUTO_MAPPABLE_H
// Here be dragons.
#include <functional>
namespace mozilla::gfx {
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);
}
//-
// From Boost:
// https://www.boost.org/doc/libs/1_37_0/doc/html/hash/reference.html#boost.hash_combine
inline size_t HashCombine(size_t seed, const size_t hash) {
seed ^= hash + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
// -
// See
// https://codereview.stackexchange.com/questions/136770/hashing-a-tuple-in-c17
template <class... Args, size_t... Ids>
size_t HashTupleN(const std::tuple<Args...>& tup,
const std::index_sequence<Ids...>&) {
size_t seed = 0;
for (const auto& hash : {Hash(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)>());
}
// -
template <class T>
auto MembersEq(const T& a, const T& b) {
const auto atup = a.Members();
const auto btup = b.Members();
return atup == btup;
}
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);
}
template <class T>
struct MembersHasher final {
auto operator()(const T& v) const { return v.hash(); }
};
/** E.g.:
struct Foo {
int i;
bool b;
auto Members() const { return std::tie(i, b); }
INLINE_AUTO_MAPPABLE(Foo)
};
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;
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)
};
} // namespace mozilla::gfx
#endif // MOZILLA_AUTO_MAPPABLE_H

View File

@@ -1,229 +0,0 @@
/* 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/. */
// We are going to be doing so, so many transforms, so descriptive labels are
// critical.
#include "Colorspaces.h"
namespace mozilla::color {
// tf = { k * linear | linear < b
// { a * pow(linear, 1/g) - (1-a) | linear >= b
float TfFromLinear(const PiecewiseGammaDesc& desc, const float linear) {
if (linear < desc.b) {
return linear * desc.k;
}
float ret = linear;
ret = powf(ret, 1.0f / desc.g);
ret *= desc.a;
ret -= (desc.a - 1);
return ret;
}
float LinearFromTf(const PiecewiseGammaDesc& desc, const float tf) {
const auto linear_if_low = tf / desc.k;
if (linear_if_low < desc.b) {
return linear_if_low;
}
float ret = tf;
ret += (desc.a - 1);
ret /= desc.a;
ret = powf(ret, 1.0f * desc.g);
return ret;
}
// -
mat3 YuvFromRgb(const YuvLumaCoeffs& yc) {
// Y is always [0,1]
// U and V are signed, and could be either [-1,+1] or [-0.5,+0.5].
// Specs generally use [-0.5,+0.5], so we use that too.
// E.g.
// y = 0.2126*r + 0.7152*g + 0.0722*b
// u = (b - y) / (u_range = u_max - u_min) // u_min = -u_max
// = (b - y) / (u(0,0,1) - u(1,1,0))
// = (b - y) / (2 * u(0,0,1))
// = (b - y) / (2 * u.b))
// = (b - y) / (2 * (1 - 0.0722))
// = (-0.2126*r + -0.7152*g + (1-0.0722)*b) / 1.8556
// v = (r - y) / 1.5748;
// = ((1-0.2126)*r + -0.7152*g + -0.0722*b) / 1.5748
const auto y = vec3({yc.r, yc.g, yc.b});
const auto u = vec3({0, 0, 1}) - y;
const auto v = vec3({1, 0, 0}) - y;
// From rows:
return mat3({y, u / (2 * u.z()), v / (2 * v.x())});
}
mat4 YuvFromYcbcr(const YcbcrDesc& d) {
// E.g.
// y = (yy - 16) / (235 - 16); // 16->0, 235->1
// u = (cb - 128) / (240 - 16); // 16->-0.5, 128->0, 240->+0.5
// v = (cr - 128) / (240 - 16);
const auto yRange = d.y1 - d.y0;
const auto uHalfRange = d.uPlusHalf - d.u0;
const auto uRange = 2 * uHalfRange;
const auto ycbcrFromYuv = mat4{{vec4{{yRange, 0, 0, d.y0}},
{{0, uRange, 0, d.u0}},
{{0, 0, uRange, d.u0}},
{{0, 0, 0, 1}}}};
const auto yuvFromYcbcr = inverse(ycbcrFromYuv);
return yuvFromYcbcr;
}
mat3 XyzFromLinearRgb(const Chromaticities& c) {
// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
// Given red (xr, yr), green (xg, yg), blue (xb, yb),
// and whitepoint (XW, YW, ZW)
// [ X ] [ R ]
// [ Y ] = M x [ G ]
// [ Z ] [ B ]
// [ Sr*Xr Sg*Xg Sb*Xb ]
// M = [ Sr*Yr Sg*Yg Sb*Yb ]
// [ Sr*Zr Sg*Zg Sb*Zb ]
// Xr = xr / yr
// Yr = 1
// Zr = (1 - xr - yr) / yr
// Xg = xg / yg
// Yg = 1
// Zg = (1 - xg - yg) / yg
// Xb = xb / yb
// Yb = 1
// Zb = (1 - xb - yb) / yb
// [ Sr ] [ Xr Xg Xb ]^-1 [ XW ]
// [ Sg ] = [ Yr Yg Yb ] x [ YW ]
// [ Sb ] [ Zr Zg Zb ] [ ZW ]
const auto xrgb = vec3({c.rx, c.gx, c.bx});
const auto yrgb = vec3({c.ry, c.gy, c.by});
const auto Xrgb = xrgb / yrgb;
const auto Yrgb = vec3(1);
const auto Zrgb = (vec3(1) - xrgb - yrgb) / yrgb;
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});
const auto Srgb = XYZrgb_inv * XYZwhitepoint;
const auto M = mat3({Srgb * Xrgb, Srgb * Yrgb, Srgb * Zrgb});
return M;
}
// -
ColorspaceTransform ColorspaceTransform::Create(const ColorspaceDesc& src,
const ColorspaceDesc& dst) {
auto ct = ColorspaceTransform{src, dst};
ct.srcTf = src.tf;
ct.dstTf = dst.tf;
const auto RgbTfFrom = [&](const ColorspaceDesc& cs) {
auto rgbFrom = mat4::Identity();
if (cs.yuv) {
const auto yuvFromYcbcr = YuvFromYcbcr(cs.yuv->ycbcr);
const auto yuvFromRgb = YuvFromRgb(cs.yuv->yCoeffs);
const auto rgbFromYuv = inverse(yuvFromRgb);
const auto rgbFromYuv4 = mat4(rgbFromYuv);
const auto rgbFromYcbcr = rgbFromYuv4 * yuvFromYcbcr;
rgbFrom = rgbFromYcbcr;
}
return rgbFrom;
};
ct.srcRgbTfFromSrc = RgbTfFrom(src);
const auto dstRgbTfFromDst = RgbTfFrom(dst);
ct.dstFromDstRgbTf = inverse(dstRgbTfFromDst);
// -
ct.dstRgbLinFromSrcRgbLin = mat3::Identity();
if (!(src.chrom == dst.chrom)) {
const auto xyzFromSrcRgbLin = XyzFromLinearRgb(src.chrom);
const auto xyzFromDstRgbLin = XyzFromLinearRgb(dst.chrom);
const auto dstRgbLinFromXyz = inverse(xyzFromDstRgbLin);
ct.dstRgbLinFromSrcRgbLin = dstRgbLinFromXyz * xyzFromSrcRgbLin;
}
return ct;
}
vec3 ColorspaceTransform::DstFromSrc(const vec3 src) const {
const auto srcRgbTf = srcRgbTfFromSrc * vec4(src, 1);
auto srcRgbLin = srcRgbTf;
if (srcTf) {
srcRgbLin.x(LinearFromTf(*srcTf, srcRgbTf.x()));
srcRgbLin.y(LinearFromTf(*srcTf, srcRgbTf.y()));
srcRgbLin.z(LinearFromTf(*srcTf, srcRgbTf.z()));
}
const auto dstRgbLin = dstRgbLinFromSrcRgbLin * vec3(srcRgbLin);
auto dstRgbTf = dstRgbLin;
if (dstTf) {
dstRgbTf.x(TfFromLinear(*dstTf, dstRgbLin.x()));
dstRgbTf.y(TfFromLinear(*dstTf, dstRgbLin.y()));
dstRgbTf.z(TfFromLinear(*dstTf, dstRgbLin.z()));
}
const auto dst4 = dstFromDstRgbTf * vec4(dstRgbTf, 1);
return vec3(dst4);
}
// -
std::optional<mat4> ColorspaceTransform::ToMat4() const {
mat4 fromSrc = srcRgbTfFromSrc;
if (srcTf) return {};
fromSrc = mat4(dstRgbLinFromSrcRgbLin) * fromSrc;
if (dstTf) return {};
fromSrc = dstFromDstRgbTf * fromSrc;
return fromSrc;
}
Lut3 ColorspaceTransform::ToLut3(const ivec3 size) const {
auto lut = Lut3::Create(size);
lut.SetMap([&](const vec3& srcVal) { return DstFromSrc(srcVal); });
return lut;
}
vec3 Lut3::Sample(const vec3 in01) const {
const auto coord = vec3(size - 1) * in01;
const auto p0 = floor(coord);
const auto dp = coord - p0;
const auto ip0 = ivec3(p0);
// Trilinear
const auto f000 = Fetch(ip0 + ivec3({0, 0, 0}));
const auto f100 = Fetch(ip0 + ivec3({1, 0, 0}));
const auto f010 = Fetch(ip0 + ivec3({0, 1, 0}));
const auto f110 = Fetch(ip0 + ivec3({1, 1, 0}));
const auto f001 = Fetch(ip0 + ivec3({0, 0, 1}));
const auto f101 = Fetch(ip0 + ivec3({1, 0, 1}));
const auto f011 = Fetch(ip0 + ivec3({0, 1, 1}));
const auto f111 = Fetch(ip0 + ivec3({1, 1, 1}));
const auto fx00 = mix(f000, f100, dp.x());
const auto fx10 = mix(f010, f110, dp.x());
const auto fx01 = mix(f001, f101, dp.x());
const auto fx11 = mix(f011, f111, dp.x());
const auto fxy0 = mix(fx00, fx10, dp.y());
const auto fxy1 = mix(fx01, fx11, dp.y());
const auto fxyz = mix(fxy0, fxy1, dp.z());
return fxyz;
}
} // namespace mozilla::color

View File

@@ -1,658 +0,0 @@
/* 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_GL_COLORSPACES_H_
#define MOZILLA_GFX_GL_COLORSPACES_H_
// Reference: https://hackmd.io/0wkiLmP7RWOFjcD13M870A
// We are going to be doing so, so many transforms, so descriptive labels are
// critical.
// Colorspace background info: https://hackmd.io/0wkiLmP7RWOFjcD13M870A
#include <algorithm>
#include <array>
#include <cmath>
#include <cstdlib>
#include <optional>
#include <vector>
#include "AutoMappable.h"
#include "mozilla/Attributes.h"
#ifdef DEBUG
# define ASSERT(EXPR) \
do { \
if (!(EXPR)) { \
__builtin_trap(); \
} \
} while (false)
#else
# define ASSERT(EXPR) (void)(EXPR)
#endif
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)
static constexpr auto Rec709() { return YuvLumaCoeffs(); }
static constexpr auto Rec2020() {
return YuvLumaCoeffs{0.2627, 0.6780, 0.0593};
}
};
struct PiecewiseGammaDesc final {
// tf = { k * linear | linear < b
// { a * pow(linear, 1/g) - (1-a) | linear >= b
// Default to Srgb
float a = 1.055;
float b = 0.04045 / 12.92;
float g = 2.4;
float k = 12.92;
auto Members() const { return std::tie(a, b, g, k); }
INLINE_AUTO_MAPPABLE(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,
};
}
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,
};
}
};
struct YcbcrDesc final {
float y0 = 16 / 255.0;
float y1 = 235 / 255.0;
float u0 = 128 / 255.0;
float uPlusHalf = 240 / 255.0;
auto Members() const { return std::tie(y0, y1, u0, uPlusHalf); }
INLINE_AUTO_MAPPABLE(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,
};
}
static constexpr auto Float() { // Best for a LUT
return YcbcrDesc{0.0, 1.0, 0.5, 1.0};
}
};
struct Chromaticities final {
float rx = 0.640;
float ry = 0.330;
float gx = 0.300;
float gy = 0.600;
float bx = 0.150;
float by = 0.060;
// D65:
static constexpr float wx = 0.3127;
static constexpr float wy = 0.3290;
auto Members() const { return std::tie(rx, ry, gx, gy, bx, by); }
INLINE_AUTO_MAPPABLE(Chromaticities)
// -
static constexpr auto Rec709() { // AKA limited/studio/tv
return Chromaticities();
}
static constexpr auto Srgb() { return Rec709(); }
static constexpr auto Rec601_625_Pal() {
auto ret = Rec709();
ret.gx = 0.290;
return ret;
}
static constexpr auto Rec601_525_Ntsc() {
return Chromaticities{
0.630, 0.340, // r
0.310, 0.595, // g
0.155, 0.070, // b
};
}
static constexpr auto Rec2020() {
return Chromaticities{
0.708, 0.292, // r
0.170, 0.797, // g
0.131, 0.046, // b
};
}
static constexpr auto DisplayP3() {
return Chromaticities{
0.680, 0.320, // r
0.265, 0.690, // g
0.150, 0.060, // b
};
}
};
// -
struct YuvDesc final {
YuvLumaCoeffs yCoeffs;
YcbcrDesc ycbcr;
auto Members() const { return std::tie(yCoeffs, ycbcr); }
INLINE_AUTO_MAPPABLE(YuvDesc);
};
struct ColorspaceDesc final {
Chromaticities chrom;
std::optional<PiecewiseGammaDesc> tf;
std::optional<YuvDesc> yuv;
auto Members() const { return std::tie(chrom, tf, yuv); }
INLINE_AUTO_MAPPABLE(ColorspaceDesc);
};
// -
template <class TT, int NN>
struct avec final {
using T = TT;
static constexpr auto N = NN;
std::array<T, N> data = {};
// -
constexpr avec() = default;
constexpr avec(const avec&) = default;
constexpr avec(const avec<T, N - 1>& v, T a) {
for (int i = 0; i < N - 1; i++) {
data[i] = v[i];
}
data[N - 1] = a;
}
constexpr avec(const avec<T, N - 2>& v, T a, T b) {
for (int i = 0; i < N - 2; i++) {
data[i] = v[i];
}
data[N - 2] = a;
data[N - 1] = b;
}
MOZ_IMPLICIT constexpr avec(const std::array<T, N>& data) {
this->data = data;
}
explicit constexpr avec(const T v) {
for (int i = 0; i < N; i++) {
data[i] = v;
}
}
template <class T2, int N2>
explicit constexpr avec(const avec<T2, N2>& v) {
const auto n = std::min(N, N2);
for (int i = 0; i < n; i++) {
data[i] = static_cast<T>(v[i]);
}
}
// -
const auto& operator[](const size_t n) const { return data[n]; }
auto& operator[](const size_t n) { return data[n]; }
template <int i>
constexpr auto get() const {
return (i < N) ? data[i] : 0;
}
constexpr auto x() const { return get<0>(); }
constexpr auto y() const { return get<1>(); }
constexpr auto z() const { return get<2>(); }
constexpr auto w() const { return get<3>(); }
constexpr auto xyz() const { return vec3({x(), y(), z()}); }
template <int i>
void set(const T v) {
if (i < N) {
data[i] = v;
}
}
void x(const T v) { set<0>(v); }
void y(const T v) { set<1>(v); }
void z(const T v) { set<2>(v); }
void w(const T v) { set<3>(v); }
// -
#define _(OP) \
friend avec operator OP(const avec a, const avec b) { \
avec c; \
for (int i = 0; i < N; i++) { \
c[i] = a[i] OP b[i]; \
} \
return c; \
} \
friend avec operator OP(const avec a, const T b) { \
avec c; \
for (int i = 0; i < N; i++) { \
c[i] = a[i] OP b; \
} \
return c; \
} \
friend avec operator OP(const T a, const avec b) { \
avec c; \
for (int i = 0; i < N; i++) { \
c[i] = a OP b[i]; \
} \
return c; \
}
_(+)
_(-)
_(*)
_(/)
#undef _
friend bool operator==(const avec a, const avec b) {
bool eq = true;
for (int i = 0; i < N; i++) {
eq &= (a[i] == b[i]);
}
return eq;
}
};
using vec3 = avec<float, 3>;
using vec4 = avec<float, 4>;
using ivec3 = avec<int32_t, 3>;
using ivec4 = avec<int32_t, 4>;
template <class T, int N>
T dot(const avec<T, N>& a, const avec<T, N>& b) {
const auto c = a * b;
T ret = 0;
for (int i = 0; i < N; i++) {
ret += c[i];
}
return ret;
}
template <class V>
V mix(const V& zero, const V& one, const float val) {
return zero * (1 - val) + one * val;
}
template <class T, int N>
auto min(const avec<T, N>& a, const avec<T, N>& b) {
auto ret = avec<T, N>{};
for (int i = 0; i < ret.N; i++) {
ret[i] = std::min(a[i], b[i]);
}
return ret;
}
template <class T, int N>
auto max(const avec<T, N>& a, const avec<T, N>& b) {
auto ret = avec<T, N>{};
for (int i = 0; i < ret.N; i++) {
ret[i] = std::max(a[i], b[i]);
}
return ret;
}
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++) {
ret[i] = floorf(a[i]);
}
return ret;
}
template <class T, int N>
auto round(const avec<T, N>& a) {
auto ret = avec<T, N>{};
for (int i = 0; i < ret.N; i++) {
ret[i] = roundf(a[i]);
}
return ret;
}
template <class T, int N>
auto abs(const avec<T, N>& a) {
auto ret = avec<T, N>{};
for (int i = 0; i < ret.N; i++) {
ret[i] = std::abs(a[i]);
}
return ret;
}
// -
template <int Y_Rows, int X_Cols>
struct mat final {
static constexpr int y_rows = Y_Rows;
static constexpr int x_cols = X_Cols;
static constexpr auto Identity() {
auto ret = mat{};
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;
}
std::array<avec<float, X_Cols>, Y_Rows> rows = {}; // row-major
// -
constexpr mat() = default;
explicit constexpr mat(const std::array<avec<float, X_Cols>, Y_Rows>& rows) {
this->rows = rows;
}
template <int Y_Rows2, int X_Cols2>
explicit constexpr mat(const mat<Y_Rows2, X_Cols2>& m) {
*this = Identity();
for (int x = 0; x < std::min(X_Cols, X_Cols2); x++) {
for (int y = 0; y < std::min(Y_Rows, Y_Rows2); y++) {
at(x, y) = m.at(x, y);
}
}
}
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]; }
friend auto operator*(const mat& a, const avec<float, X_Cols>& b_colvec) {
avec<float, Y_Rows> c_colvec;
for (int i = 0; i < y_rows; i++) {
c_colvec[i] = dot(a.rows.at(i), b_colvec);
}
return c_colvec;
}
friend auto operator*(const mat& a, const float b) {
mat c;
for (int x = 0; x < x_cols; x++) {
for (int y = 0; y < y_rows; y++) {
c.at(x, y) = a.at(x, y) * b;
}
}
return c;
}
friend auto operator/(const mat& a, const float b) { return a * (1 / b); }
template <int BCols, int BRows = X_Cols>
friend auto operator*(const mat& a, const mat<BRows, BCols>& b) {
const auto bt = transpose(b);
const auto& b_cols = bt.rows;
mat<Y_Rows, BCols> c;
for (int x = 0; x < BCols; x++) {
for (int y = 0; y < Y_Rows; y++) {
c.at(x, y) = dot(a.rows.at(y), b_cols.at(x));
}
}
return c;
}
};
using mat3 = mat<3, 3>;
using mat4 = mat<4, 4>;
inline float determinant(const mat<1, 1>& m) { return m.at(0, 0); }
template <class T>
float determinant(const T& m) {
static_assert(T::x_cols == T::y_rows);
float ret = 0;
for (int i = 0; i < T::x_cols; i++) {
const auto cofact = cofactor(m, i, 0);
ret += m.at(i, 0) * cofact;
}
return ret;
}
// -
template <class T>
float cofactor(const T& m, const int x_col, const int y_row) {
ASSERT(0 <= x_col && x_col < T::x_cols);
ASSERT(0 <= y_row && y_row < T::y_rows);
auto cofactor = minor_val(m, x_col, y_row);
if ((x_col + y_row) % 2 == 1) {
cofactor *= -1;
}
return cofactor;
}
// -
// Unfortunately, can't call this `minor(...)` because there is
// `#define minor(dev) gnu_dev_minor (dev)`
// in /usr/include/x86_64-linux-gnu/sys/sysmacros.h:62
template <class T>
float minor_val(const T& a, const int skip_x, const int skip_y) {
ASSERT(0 <= skip_x && skip_x < T::x_cols);
ASSERT(0 <= skip_y && skip_y < T::y_rows);
// A minor matrix is a matrix without its x_col and y_row.
mat<T::y_rows - 1, T::x_cols - 1> b;
int x_skips = 0;
for (int ax = 0; ax < T::x_cols; ax++) {
if (ax == skip_x) {
x_skips = 1;
continue;
}
int y_skips = 0;
for (int ay = 0; ay < T::y_rows; ay++) {
if (ay == skip_y) {
y_skips = 1;
continue;
}
b.at(ax - x_skips, ay - y_skips) = a.at(ax, ay);
}
}
const auto minor = determinant(b);
return minor;
}
// -
/// The matrix of cofactors.
template <class T>
auto comatrix(const T& a) {
auto b = T{};
for (int x = 0; x < T::x_cols; x++) {
for (int y = 0; y < T::y_rows; y++) {
b.at(x, y) = cofactor(a, x, y);
}
}
return b;
}
// -
template <class T>
auto transpose(const T& a) {
auto b = mat<T::x_cols, T::y_rows>{};
for (int x = 0; x < T::x_cols; x++) {
for (int y = 0; y < T::y_rows; y++) {
b.at(y, x) = a.at(x, y);
}
}
return b;
}
// -
template <class T>
inline T inverse(const T& a) {
const auto det = determinant(a);
const auto comat = comatrix(a);
const auto adjugate = transpose(comat);
const auto inv = adjugate / det;
return inv;
}
// -
template <class F>
void ForEachIntWithin(const ivec3 size, const F& f) {
ivec3 p;
for (p.z(0); p.z() < size.z(); p.z(p.z() + 1)) {
for (p.y(0); p.y() < size.y(); p.y(p.y() + 1)) {
for (p.x(0); p.x() < size.x(); p.x(p.x() + 1)) {
f(p);
}
}
}
}
template <class F>
void ForEachSampleWithin(const ivec3 size, const F& f) {
const auto div = vec3(size - 1);
ForEachIntWithin(size, [&](const ivec3& isrc) {
const auto fsrc = vec3(isrc) / div;
f(fsrc);
});
}
// -
struct Lut3 final {
ivec3 size;
std::vector<vec3> data;
// -
static Lut3 Create(const ivec3 size) {
Lut3 lut;
lut.size = size;
lut.data.resize(size.x() * size.y() * size.z());
return lut;
}
// -
/// p: [0, N-1] (clamps)
size_t Index(ivec3 p) const {
const auto scales = ivec3({1, size.x(), size.x() * size.y()});
p = max(ivec3(0), min(p, size - 1)); // clamp
return dot(p, scales);
}
// -
template <class F>
void SetMap(const F& dstFromSrc01) {
ForEachIntWithin(size, [&](const ivec3 p) {
const auto i = Index(p);
const auto src01 = vec3(p) / vec3(size - 1);
const auto dstVal = dstFromSrc01(src01);
data.at(i) = dstVal;
});
}
// -
/// p: [0, N-1] (clamps)
vec3 Fetch(ivec3 p) const {
const auto i = Index(p);
return data.at(i);
}
/// in01: [0.0, 1.0] (clamps)
vec3 Sample(vec3 in01) const;
};
// -
/**
Naively, it would be ideal to map directly from ycbcr to rgb,
but headroom and footroom are problematic: For e.g. narrow-range-8-bit,
our naive LUT would start at absolute y=0/255. However, values only start
at y=16/255, and depending on where your first LUT sample is, you might get
very poor approximations for y=16/255.
Further, even for full-range-8-bit, y=-0.5 is encoded as 1/255. U and v
aren't *as* important as y, but we should try be accurate for the min and
max values. Additionally, it would be embarassing to get whites/greys wrong,
so preserving u=0.0 should also be a goal.
Finally, when using non-linear transfer functions, the linear approximation of a
point between two samples will be fairly inaccurate.
We preserve min and max by choosing our input range such that min and max are
the endpoints of their LUT axis.
We preserve accuracy (at and around) mid by choosing odd sizes for dimentions.
But also, the LUT is surprisingly robust, so check if the simple version works
before adding complexity!
**/
struct ColorspaceTransform final {
ColorspaceDesc srcSpace;
ColorspaceDesc dstSpace;
mat4 srcRgbTfFromSrc;
std::optional<PiecewiseGammaDesc> srcTf;
mat3 dstRgbLinFromSrcRgbLin;
std::optional<PiecewiseGammaDesc> dstTf;
mat4 dstFromDstRgbTf;
static ColorspaceTransform Create(const ColorspaceDesc& src,
const ColorspaceDesc& dst);
// -
vec3 DstFromSrc(vec3 src) const;
std::optional<mat4> ToMat4() const;
Lut3 ToLut3(const ivec3 size) const;
Lut3 ToLut3() const {
auto defaultSize = ivec3({31, 31, 15}); // Order of importance: G, R, B
if (srcSpace.yuv) {
defaultSize = ivec3({31, 15, 31}); // Y, Cb, Cr
}
return ToLut3(defaultSize);
}
};
} // namespace mozilla::color
#undef ASSERT
#endif // MOZILLA_GFX_GL_COLORSPACES_H_

View File

@@ -14,9 +14,7 @@
#include "ScopedGLHelpers.h" #include "ScopedGLHelpers.h"
#include "gfxUtils.h" #include "gfxUtils.h"
#include "mozilla/ArrayUtils.h" #include "mozilla/ArrayUtils.h"
#include "mozilla/Casting.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
#include "mozilla/gfx/Logging.h" #include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/Matrix.h" #include "mozilla/gfx/Matrix.h"
@@ -52,177 +50,140 @@ namespace gl {
// -- // --
static const char kFragPreprocHeader[] = R"( const char* const kFragHeader_Tex2D =
#ifdef GL_ES "\
#ifdef GL_FRAGMENT_PRECISION_HIGH #define SAMPLER sampler2D \n\
#define MAXP highp #if __VERSION__ >= 130 \n\
#endif #define TEXTURE texture \n\
#else #else \n\
#define MAXP highp #define TEXTURE texture2D \n\
#endif #endif \n\
#ifndef MAXP ";
#define MAXP mediump const char* const kFragHeader_Tex2DRect =
#endif "\
#define SAMPLER sampler2DRect \n\
#if __VERSION__ >= 130 \n\
#define TEXTURE texture \n\
#else \n\
#define TEXTURE texture2DRect \n\
#endif \n\
";
const char* const kFragHeader_TexExt =
"\
#extension GL_OES_EGL_image_external : require \n\
#if __VERSION__ >= 130 \n\
#define TEXTURE texture \n\
#else \n\
#define TEXTURE texture2D \n\
#endif \n\
#define SAMPLER samplerExternalOES \n\
";
#if __VERSION__ >= 130 const char* const kFragBody_RGBA =
#define VARYING in "\
#else VARYING vec2 vTexCoord0; \n\
#define VARYING varying uniform SAMPLER uTex0; \n\
#endif \n\
#if __VERSION__ >= 120 void main(void) \n\
#define MAT4X3 mat4x3 { \n\
#else FRAG_COLOR = TEXTURE(uTex0, vTexCoord0); \n\
#define MAT4X3 mat4 } \n\
#endif ";
)"; const char* const kFragBody_BGRA =
"\
// - VARYING vec2 vTexCoord0; \n\
uniform SAMPLER uTex0; \n\
const char* const kFragHeader_Tex2D = R"( \n\
#define SAMPLER sampler2D void main(void) \n\
#if __VERSION__ >= 130 { \n\
#define TEXTURE texture FRAG_COLOR = TEXTURE(uTex0, vTexCoord0).bgra; \n\
#else } \n\
#define TEXTURE texture2D ";
#endif const char* const kFragBody_CrYCb =
)"; "\
const char* const kFragHeader_Tex2DRect = R"( VARYING vec2 vTexCoord0; \n\
#define SAMPLER sampler2DRect uniform SAMPLER uTex0; \n\
#if __VERSION__ >= 130 uniform MAT4X3 uColorMatrix; \n\
#define TEXTURE texture \n\
#else void main(void) \n\
#define TEXTURE texture2DRect { \n\
#endif vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).gbr, \n\
)"; 1.0); \n\
const char* const kFragHeader_TexExt = R"( FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
#extension GL_OES_EGL_image_external : enable } \n\
#extension GL_OES_EGL_image_external_essl3 : enable ";
#if __VERSION__ >= 130 const char* const kFragBody_NV12 =
#define TEXTURE texture "\
#else VARYING vec2 vTexCoord0; \n\
#define TEXTURE texture2D VARYING vec2 vTexCoord1; \n\
#endif uniform SAMPLER uTex0; \n\
#define SAMPLER samplerExternalOES uniform SAMPLER uTex1; \n\
)"; uniform MAT4X3 uColorMatrix; \n\
\n\
// - void main(void) \n\
{ \n\
static const char kFragDeclHeader[] = R"( vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x, \n\
precision PRECISION float; TEXTURE(uTex1, vTexCoord1).xy, \n\
#if __VERSION__ >= 130 1.0); \n\
#define FRAG_COLOR oFragColor FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
out vec4 FRAG_COLOR; } \n\
#else ";
#define FRAG_COLOR gl_FragColor const char* const kFragBody_PlanarYUV =
#endif "\
)"; VARYING vec2 vTexCoord0; \n\
VARYING vec2 vTexCoord1; \n\
// - uniform SAMPLER uTex0; \n\
uniform SAMPLER uTex1; \n\
const char* const kFragSample_OnePlane = R"( uniform SAMPLER uTex2; \n\
VARYING mediump vec2 vTexCoord0; uniform MAT4X3 uColorMatrix; \n\
uniform PRECISION SAMPLER uTex0; \n\
void main(void) \n\
vec4 metaSample() { { \n\
vec4 src = TEXTURE(uTex0, vTexCoord0); vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x, \n\
return src; TEXTURE(uTex1, vTexCoord1).x, \n\
} TEXTURE(uTex2, vTexCoord1).x, \n\
)"; 1.0); \n\
// Ideally this would just change the color-matrix it uses, but this is FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
// acceptable debt for now. } \n\
// `extern` so that we don't get ifdef-dependent const-var-unused Werrors. ";
extern const char* const kFragSample_OnePlane_YUV_via_GBR = R"(
VARYING mediump vec2 vTexCoord0;
uniform PRECISION SAMPLER uTex0;
vec4 metaSample() {
vec4 yuva = TEXTURE(uTex0, vTexCoord0).gbra;
return yuva;
}
)";
const char* const kFragSample_TwoPlane = R"(
VARYING mediump vec2 vTexCoord0;
VARYING mediump vec2 vTexCoord1;
uniform PRECISION SAMPLER uTex0;
uniform PRECISION SAMPLER uTex1;
vec4 metaSample() {
vec4 src = TEXTURE(uTex0, vTexCoord0); // Keep r and a.
src.gb = TEXTURE(uTex1, vTexCoord1).rg;
return src;
}
)";
const char* const kFragSample_ThreePlane = R"(
VARYING mediump vec2 vTexCoord0;
VARYING mediump vec2 vTexCoord1;
uniform PRECISION SAMPLER uTex0;
uniform PRECISION SAMPLER uTex1;
uniform PRECISION SAMPLER uTex2;
vec4 metaSample() {
vec4 src = TEXTURE(uTex0, vTexCoord0); // Keep r and a.
src.g = TEXTURE(uTex1, vTexCoord1).r;
src.b = TEXTURE(uTex2, vTexCoord1).r;
return src;
}
)";
// -
const char* const kFragConvert_None = R"(
vec3 metaConvert(vec3 src) {
return src;
}
)";
const char* const kFragConvert_BGR = R"(
vec3 metaConvert(vec3 src) {
return src.bgr;
}
)";
const char* const kFragConvert_ColorMatrix = R"(
uniform mediump MAT4X3 uColorMatrix;
vec3 metaConvert(vec3 src) {
return (uColorMatrix * vec4(src, 1)).rgb;
}
)";
const char* const kFragConvert_ColorLut = 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.
// 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
vec3 size = vec3(textureSize(uColorLut, 0));
src = (0.5 + src * (size - 1.0)) / size;
return texture(uColorLut, src).rgb;
}
)";
// -
static const char kFragBody[] = R"(
void main(void) {
vec4 src = metaSample();
vec3 dst = metaConvert(src.rgb);
FRAG_COLOR = vec4(dst, src.a);
}
)";
// -- // --
template <uint8_t N>
/*static*/ Mat<N> Mat<N>::Zero() {
Mat<N> ret;
for (auto& x : ret.m) {
x = 0.0f;
}
return ret;
}
template <uint8_t N>
/*static*/ Mat<N> Mat<N>::I() {
auto ret = Mat<N>::Zero();
for (uint8_t i = 0; i < N; i++) {
ret.at(i, i) = 1.0f;
}
return ret;
}
template <uint8_t N>
Mat<N> Mat<N>::operator*(const Mat<N>& r) const {
Mat<N> ret;
for (uint8_t x = 0; x < N; x++) {
for (uint8_t y = 0; y < N; y++) {
float sum = 0.0f;
for (uint8_t i = 0; i < N; i++) {
sum += at(i, y) * r.at(x, i);
}
ret.at(x, y) = sum;
}
}
return ret;
}
Mat3 SubRectMat3(const float x, const float y, const float w, const float h) { Mat3 SubRectMat3(const float x, const float y, const float w, const float h) {
auto ret = Mat3{}; auto ret = Mat3::Zero();
ret.at(0, 0) = w; ret.at(0, 0) = w;
ret.at(1, 1) = h; ret.at(1, 1) = h;
ret.at(2, 0) = x; ret.at(2, 0) = x;
@@ -251,10 +212,10 @@ Mat3 SubRectMat3(const gfx::IntRect& bigSubrect, const gfx::IntSize& smallSize,
// -- // --
ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext* const gl, ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext* const gl,
const std::vector<uint8_t>& texUnits, const uint8_t texCount,
const GLenum texTarget) const GLenum texTarget)
: mGL(*gl), : mGL(*gl),
mTexUnits(texUnits), mTexCount(texCount),
mTexTarget(texTarget), mTexTarget(texTarget),
mOldTexUnit(mGL.GetIntAs<GLenum>(LOCAL_GL_ACTIVE_TEXTURE)) { mOldTexUnit(mGL.GetIntAs<GLenum>(LOCAL_GL_ACTIVE_TEXTURE)) {
GLenum texBinding; GLenum texBinding;
@@ -262,9 +223,6 @@ ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext* const gl,
case LOCAL_GL_TEXTURE_2D: case LOCAL_GL_TEXTURE_2D:
texBinding = LOCAL_GL_TEXTURE_BINDING_2D; texBinding = LOCAL_GL_TEXTURE_BINDING_2D;
break; break;
case LOCAL_GL_TEXTURE_3D:
texBinding = LOCAL_GL_TEXTURE_BINDING_3D;
break;
case LOCAL_GL_TEXTURE_RECTANGLE: case LOCAL_GL_TEXTURE_RECTANGLE:
texBinding = LOCAL_GL_TEXTURE_BINDING_RECTANGLE; texBinding = LOCAL_GL_TEXTURE_BINDING_RECTANGLE;
break; break;
@@ -275,26 +233,21 @@ ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext* const gl,
gfxCriticalError() << "Unhandled texTarget: " << texTarget; gfxCriticalError() << "Unhandled texTarget: " << texTarget;
} }
for (const auto i : IntegerRange(mTexUnits.size())) { for (uint8_t i = 0; i < mTexCount; i++) {
const auto& unit = mTexUnits[i]; mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + i);
mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + unit);
if (mGL.IsSupported(GLFeature::sampler_objects)) { if (mGL.IsSupported(GLFeature::sampler_objects)) {
mOldTexSampler[i] = mGL.GetIntAs<GLuint>(LOCAL_GL_SAMPLER_BINDING); mOldTexSampler[i] = mGL.GetIntAs<GLuint>(LOCAL_GL_SAMPLER_BINDING);
mGL.fBindSampler(unit, 0); mGL.fBindSampler(i, 0);
} }
mOldTex[i] = mGL.GetIntAs<GLuint>(texBinding); mOldTex[i] = mGL.GetIntAs<GLuint>(texBinding);
} }
} }
ScopedSaveMultiTex::~ScopedSaveMultiTex() { ScopedSaveMultiTex::~ScopedSaveMultiTex() {
// Unbind in reverse order, in case we have repeats. for (uint8_t i = 0; i < mTexCount; i++) {
// Order matters because we unbound samplers during ctor, so now we have to mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + i);
// 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);
if (mGL.IsSupported(GLFeature::sampler_objects)) { if (mGL.IsSupported(GLFeature::sampler_objects)) {
mGL.fBindSampler(unit, mOldTexSampler[i]); mGL.fBindSampler(i, mOldTexSampler[i]);
} }
mGL.fBindTexture(mTexTarget, mOldTex[i]); mGL.fBindTexture(mTexTarget, mOldTex[i]);
} }
@@ -426,7 +379,6 @@ DrawBlitProg::DrawBlitProg(const GLBlitHelper* const parent, const GLuint prog)
mLoc_uDestMatrix(mParent.mGL->fGetUniformLocation(mProg, "uDestMatrix")), mLoc_uDestMatrix(mParent.mGL->fGetUniformLocation(mProg, "uDestMatrix")),
mLoc_uTexMatrix0(mParent.mGL->fGetUniformLocation(mProg, "uTexMatrix0")), mLoc_uTexMatrix0(mParent.mGL->fGetUniformLocation(mProg, "uTexMatrix0")),
mLoc_uTexMatrix1(mParent.mGL->fGetUniformLocation(mProg, "uTexMatrix1")), mLoc_uTexMatrix1(mParent.mGL->fGetUniformLocation(mProg, "uTexMatrix1")),
mLoc_uColorLut(mParent.mGL->fGetUniformLocation(mProg, "uColorLut")),
mLoc_uColorMatrix( mLoc_uColorMatrix(
mParent.mGL->fGetUniformLocation(mProg, "uColorMatrix")) { mParent.mGL->fGetUniformLocation(mProg, "uColorMatrix")) {
const auto& gl = mParent.mGL; const auto& gl = mParent.mGL;
@@ -491,18 +443,12 @@ void DrawBlitProg::Draw(const BaseArgs& args,
gl->fUniformMatrix3fv(mLoc_uDestMatrix, 1, false, destMatrix.m); gl->fUniformMatrix3fv(mLoc_uDestMatrix, 1, false, destMatrix.m);
gl->fUniformMatrix3fv(mLoc_uTexMatrix0, 1, false, args.texMatrix0.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)); MOZ_ASSERT(bool(argsYUV) == (mLoc_uColorMatrix != -1));
if (argsYUV) { if (argsYUV) {
gl->fUniformMatrix3fv(mLoc_uTexMatrix1, 1, false, argsYUV->texMatrix1.m); gl->fUniformMatrix3fv(mLoc_uTexMatrix1, 1, false, argsYUV->texMatrix1.m);
if (mLoc_uColorMatrix != -1) {
const auto& colorMatrix = const auto& colorMatrix =
gfxUtils::YuvToRgbMatrix4x4ColumnMajor(*argsYUV->colorSpaceForMatrix); gfxUtils::YuvToRgbMatrix4x4ColumnMajor(argsYUV->colorSpace);
float mat4x3[4 * 3]; float mat4x3[4 * 3];
switch (mType_uColorMatrix) { switch (mType_uColorMatrix) {
case LOCAL_GL_FLOAT_MAT4: case LOCAL_GL_FLOAT_MAT4:
@@ -517,9 +463,8 @@ void DrawBlitProg::Draw(const BaseArgs& args,
gl->fUniformMatrix4x3fv(mLoc_uColorMatrix, 1, false, mat4x3); gl->fUniformMatrix4x3fv(mLoc_uColorMatrix, 1, false, mat4x3);
break; break;
default: default:
gfxCriticalError() gfxCriticalError() << "Bad mType_uColorMatrix: "
<< "Bad mType_uColorMatrix: " << gfx::hexa(mType_uColorMatrix); << gfx::hexa(mType_uColorMatrix);
}
} }
} }
@@ -605,17 +550,11 @@ GLBlitHelper::GLBlitHelper(GLContext* const gl)
const auto glslVersion = mGL->ShadingLanguageVersion(); const auto glslVersion = mGL->ShadingLanguageVersion();
// Always use 100 on ES because some devices have OES_EGL_image_external but
// not OES_EGL_image_external_essl3. We could just use 100 in that particular
// case, but this is a lot easier and is not harmful to other usages.
if (mGL->IsGLES()) { if (mGL->IsGLES()) {
// If you run into problems on old android devices, it might be because some
// devices have OES_EGL_image_external but not OES_EGL_image_external_essl3.
// We could just use 100 in that particular case, but then we lose out on
// e.g. sampler3D. Let's just try 300 for now, and if we get regressions
// we'll add an essl100 fallback.
if (glslVersion >= 300) {
mDrawBlitProg_VersionLine = nsCString("#version 300 es\n");
} else {
mDrawBlitProg_VersionLine = nsCString("#version 100\n"); mDrawBlitProg_VersionLine = nsCString("#version 100\n");
}
} else if (glslVersion >= 130) { } else if (glslVersion >= 130) {
mDrawBlitProg_VersionLine = nsPrintfCString("#version %u\n", glslVersion); mDrawBlitProg_VersionLine = nsPrintfCString("#version %u\n", glslVersion);
} }
@@ -686,47 +625,36 @@ const DrawBlitProg* GLBlitHelper::GetDrawBlitProg(
const DrawBlitProg* GLBlitHelper::CreateDrawBlitProg( const DrawBlitProg* GLBlitHelper::CreateDrawBlitProg(
const DrawBlitProg::Key& key) const { const DrawBlitProg::Key& key) const {
const auto precisionPref = StaticPrefs::gfx_blithelper_precision(); const char kFragHeader_Global[] =
const char* precision; "\
switch (precisionPref) { #ifdef GL_ES \n\
case 0: #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
precision = "lowp"; precision highp float; \n\
break; #else \n\
case 1: precision mediump float; \n\
precision = "mediump"; #endif \n\
break; #endif \n\
default: \n\
if (precisionPref != 2) { #if __VERSION__ >= 130 \n\
NS_WARNING("gfx.blithelper.precision clamped to 2."); #define VARYING in \n\
} #define FRAG_COLOR oFragColor \n\
precision = "MAXP"; out vec4 FRAG_COLOR; \n\
break; #else \n\
} #define VARYING varying \n\
#define FRAG_COLOR gl_FragColor \n\
nsPrintfCString precisionLine("\n#define PRECISION %s\n", precision); #endif \n\
\n\
// - #if __VERSION__ >= 120 \n\
#define MAT4X3 mat4x3 \n\
#else \n\
#define MAT4X3 mat4 \n\
#endif \n\
";
const ScopedShader fs(mGL, LOCAL_GL_FRAGMENT_SHADER); const ScopedShader fs(mGL, LOCAL_GL_FRAGMENT_SHADER);
const char* const parts[] = {mDrawBlitProg_VersionLine.get(), key.fragHeader,
std::vector<const char*> parts; kFragHeader_Global, key.fragBody};
{ mGL->fShaderSource(fs, ArrayLength(parts), parts, nullptr);
parts.push_back(mDrawBlitProg_VersionLine.get());
parts.push_back(kFragPreprocHeader);
if (key.fragHeader) {
parts.push_back(key.fragHeader);
}
parts.push_back(precisionLine.BeginReading());
parts.push_back(kFragDeclHeader);
for (const auto& part : key.fragParts) {
if (part) {
parts.push_back(part);
}
}
parts.push_back(kFragBody);
}
mGL->fShaderSource(fs, AssertedCast<GLint>(parts.size()), parts.data(),
nullptr);
mGL->fCompileShader(fs); mGL->fCompileShader(fs);
const auto prog = mGL->fCreateProgram(); const auto prog = mGL->fCreateProgram();
@@ -770,19 +698,11 @@ const DrawBlitProg* GLBlitHelper::CreateDrawBlitProg(
mGL->fGetShaderInfoLog(fs, fsLogLen, nullptr, fsLog.get()); mGL->fGetShaderInfoLog(fs, fsLogLen, nullptr, fsLog.get());
fsLog[fsLogLen] = 0; fsLog[fsLogLen] = 0;
const auto logs = gfxCriticalError() << "DrawBlitProg link failed:\n"
std::string("DrawBlitProg link failed:\n") + "progLog: " + progLog.get() + << "progLog: " << progLog.get() << "\n"
"\n" + "vsLog: " + vsLog.get() + "\n" + "fsLog: " + fsLog.get() + "\n"; << "vsLog: " << vsLog.get() << "\n"
gfxCriticalError() << logs; << "fsLog: " << fsLog.get() << "\n";
MOZ_CRASH();
printf_stderr("Frag source:\n");
int i = 0;
for (const auto& part : parts) {
printf_stderr("// parts[%i]:\n%s\n", i, part);
i += 1;
}
MOZ_CRASH("DrawBlitProg link failed");
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -945,8 +865,7 @@ bool GLBlitHelper::Blit(const java::GeckoSurfaceTexture::Ref& surfaceTexture,
const auto transform3 = Mat3::I(); const auto transform3 = Mat3::I();
const auto srcOrigin = OriginPos::TopLeft; const auto srcOrigin = OriginPos::TopLeft;
const bool yFlip = (srcOrigin != destOrigin); const bool yFlip = (srcOrigin != destOrigin);
const auto& prog = GetDrawBlitProg( const auto& prog = GetDrawBlitProg({kFragHeader_TexExt, kFragBody_RGBA});
{kFragHeader_TexExt, {kFragSample_OnePlane, kFragConvert_None}});
const DrawBlitProg::BaseArgs baseArgs = {transform3, yFlip, destSize, const DrawBlitProg::BaseArgs baseArgs = {transform3, yFlip, destSize,
Nothing()}; Nothing()};
prog->Draw(baseArgs, nullptr); prog->Draw(baseArgs, nullptr);
@@ -976,8 +895,7 @@ bool GuessDivisors(const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
bool GLBlitHelper::BlitPlanarYCbCr(const PlanarYCbCrData& yuvData, bool GLBlitHelper::BlitPlanarYCbCr(const PlanarYCbCrData& yuvData,
const gfx::IntSize& destSize, const gfx::IntSize& destSize,
const OriginPos destOrigin) { const OriginPos destOrigin) {
const auto& prog = GetDrawBlitProg( const auto& prog = GetDrawBlitProg({kFragHeader_Tex2D, kFragBody_PlanarYUV});
{kFragHeader_Tex2D, {kFragSample_ThreePlane, kFragConvert_ColorMatrix}});
if (!mYuvUploads[0]) { if (!mYuvUploads[0]) {
mGL->fGenTextures(3, mYuvUploads); mGL->fGenTextures(3, mYuvUploads);
@@ -1039,7 +957,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 ResetUnpackState reset(mGL);
const gfx::IntSize yTexSize(yuvData.mYStride, yuvData.YDataSize().height); const gfx::IntSize yTexSize(yuvData.mYStride, yuvData.YDataSize().height);
const gfx::IntSize uvTexSize(yuvData.mCbCrStride, const gfx::IntSize uvTexSize(yuvData.mCbCrStride,
@@ -1090,7 +1008,7 @@ bool GLBlitHelper::BlitPlanarYCbCr(const PlanarYCbCrData& yuvData,
const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, yTexSize), const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, yTexSize),
yFlip, destSize, Nothing()}; yFlip, destSize, Nothing()};
const DrawBlitProg::YUVArgs yuvArgs = { const DrawBlitProg::YUVArgs yuvArgs = {
SubRectMat3(clipRect, uvTexSize, divisors), Some(yuvData.mYUVColorSpace)}; SubRectMat3(clipRect, uvTexSize, divisors), yuvData.mYUVColorSpace};
prog->Draw(baseArgs, &yuvArgs); prog->Draw(baseArgs, &yuvArgs);
return true; return true;
} }
@@ -1140,7 +1058,7 @@ bool GLBlitHelper::BlitImage(MacIOSurface* const iosurf,
// TODO: The colorspace is known by the IOSurface, why override it? // TODO: The colorspace is known by the IOSurface, why override it?
// See GetYUVColorSpace/GetFullRange() // See GetYUVColorSpace/GetFullRange()
DrawBlitProg::YUVArgs yuvArgs; DrawBlitProg::YUVArgs yuvArgs;
yuvArgs.colorSpaceForMatrix = Some(iosurf->GetYUVColorSpace()); yuvArgs.colorSpace = iosurf->GetYUVColorSpace();
const DrawBlitProg::YUVArgs* pYuvArgs = nullptr; const DrawBlitProg::YUVArgs* pYuvArgs = nullptr;
@@ -1150,12 +1068,9 @@ bool GLBlitHelper::BlitImage(MacIOSurface* const iosurf,
} }
const GLenum texTarget = LOCAL_GL_TEXTURE_RECTANGLE; const GLenum texTarget = LOCAL_GL_TEXTURE_RECTANGLE;
const char* const fragHeader = kFragHeader_Tex2DRect;
std::vector<uint8_t> texUnits; const ScopedSaveMultiTex saveTex(mGL, planes, texTarget);
for (uint8_t i = 0; i < planes; i++) {
texUnits.push_back(i);
}
const ScopedSaveMultiTex saveTex(mGL, texUnits, texTarget);
const ScopedTexture tex0(mGL); const ScopedTexture tex0(mGL);
const ScopedTexture tex1(mGL); const ScopedTexture tex1(mGL);
const ScopedTexture tex2(mGL); const ScopedTexture tex2(mGL);
@@ -1168,7 +1083,7 @@ bool GLBlitHelper::BlitImage(MacIOSurface* const iosurf,
pixelFormat); pixelFormat);
} }
const char* fragSample; const char* fragBody;
switch (planes) { switch (planes) {
case 1: case 1:
switch (pixelFormat) { switch (pixelFormat) {
@@ -1180,11 +1095,11 @@ bool GLBlitHelper::BlitImage(MacIOSurface* const iosurf,
case kCVPixelFormatType_32RGBA: case kCVPixelFormatType_32RGBA:
case kCVPixelFormatType_64ARGB: case kCVPixelFormatType_64ARGB:
case kCVPixelFormatType_48RGB: case kCVPixelFormatType_48RGB:
fragSample = kFragSample_OnePlane; fragBody = kFragBody_RGBA;
break; break;
case kCVPixelFormatType_422YpCbCr8: case kCVPixelFormatType_422YpCbCr8:
case kCVPixelFormatType_422YpCbCr8_yuvs: case kCVPixelFormatType_422YpCbCr8_yuvs:
fragSample = kFragSample_OnePlane_YUV_via_GBR; fragBody = kFragBody_CrYCb;
pYuvArgs = &yuvArgs; pYuvArgs = &yuvArgs;
break; break;
default: { default: {
@@ -1195,19 +1110,19 @@ bool GLBlitHelper::BlitImage(MacIOSurface* const iosurf,
str = IntAsAscii(pixelFormat); str = IntAsAscii(pixelFormat);
} }
gfxCriticalError() << "Unhandled kCVPixelFormatType_*: " << str; gfxCriticalError() << "Unhandled kCVPixelFormatType_*: " << str;
}
// Probably YUV though // Probably YUV though
fragSample = kFragSample_OnePlane_YUV_via_GBR; fragBody = kFragBody_CrYCb;
pYuvArgs = &yuvArgs; pYuvArgs = &yuvArgs;
break; break;
} }
}
break; break;
case 2: case 2:
fragSample = kFragSample_TwoPlane; fragBody = kFragBody_NV12;
pYuvArgs = &yuvArgs; pYuvArgs = &yuvArgs;
break; break;
case 3: case 3:
fragSample = kFragSample_ThreePlane; fragBody = kFragBody_PlanarYUV;
pYuvArgs = &yuvArgs; pYuvArgs = &yuvArgs;
break; break;
default: default:
@@ -1233,10 +1148,7 @@ bool GLBlitHelper::BlitImage(MacIOSurface* const iosurf,
} }
} }
const auto& prog = GetDrawBlitProg({ const auto& prog = GetDrawBlitProg({fragHeader, fragBody});
kFragHeader_Tex2DRect,
{fragSample, kFragConvert_ColorMatrix},
});
prog->Draw(baseArgs, pYuvArgs); prog->Draw(baseArgs, pYuvArgs);
return true; return true;
} }
@@ -1264,13 +1176,10 @@ void GLBlitHelper::DrawBlitTextureToFramebuffer(const GLuint srcTex,
gfxCriticalError() << "Unexpected srcTarget: " << srcTarget; gfxCriticalError() << "Unexpected srcTarget: " << srcTarget;
return; return;
} }
const auto fragConvert = srcIsBGRA ? kFragConvert_BGR : kFragConvert_None; const char* fragBody = srcIsBGRA ? kFragBody_BGRA : kFragBody_RGBA;
const auto& prog = GetDrawBlitProg({ const auto& prog = GetDrawBlitProg({fragHeader, fragBody});
fragHeader,
{kFragSample_OnePlane, fragConvert},
});
const ScopedSaveMultiTex saveTex(mGL, {0}, srcTarget); const ScopedSaveMultiTex saveTex(mGL, 1, srcTarget);
mGL->fBindTexture(srcTarget, srcTex); mGL->fBindTexture(srcTarget, srcTex);
const bool yFlip = false; const bool yFlip = false;
@@ -1428,35 +1337,28 @@ bool GLBlitHelper::Blit(DMABufSurface* surface, const gfx::IntSize& destSize,
// TODO: The colorspace is known by the DMABUFSurface, why override it? // TODO: The colorspace is known by the DMABUFSurface, why override it?
// See GetYUVColorSpace/GetFullRange() // See GetYUVColorSpace/GetFullRange()
DrawBlitProg::YUVArgs yuvArgs; DrawBlitProg::YUVArgs yuvArgs;
yuvArgs.colorSpaceForMatrix = Some(surface->GetYUVColorSpace()); yuvArgs.colorSpace = surface->GetYUVColorSpace();
const DrawBlitProg::YUVArgs* pYuvArgs = nullptr; const DrawBlitProg::YUVArgs* pYuvArgs = nullptr;
const auto planes = surface->GetTextureCount(); const auto planes = surface->GetTextureCount();
const GLenum texTarget = LOCAL_GL_TEXTURE_2D; const GLenum texTarget = LOCAL_GL_TEXTURE_2D;
std::vector<uint8_t> texUnits; const ScopedSaveMultiTex saveTex(mGL, planes, texTarget);
for (uint8_t i = 0; i < planes; i++) {
texUnits.push_back(i);
}
const ScopedSaveMultiTex saveTex(mGL, texUnits, texTarget);
const auto pixelFormat = surface->GetSurfaceType(); const auto pixelFormat = surface->GetSurfaceType();
const char* fragSample; const char* fragBody;
auto fragConvert = kFragConvert_None;
switch (pixelFormat) { switch (pixelFormat) {
case DMABufSurface::SURFACE_RGBA: case DMABufSurface::SURFACE_RGBA:
fragSample = kFragSample_OnePlane; fragBody = kFragBody_RGBA;
break; break;
case DMABufSurface::SURFACE_NV12: case DMABufSurface::SURFACE_NV12:
fragSample = kFragSample_TwoPlane; fragBody = kFragBody_NV12;
pYuvArgs = &yuvArgs; pYuvArgs = &yuvArgs;
fragConvert = kFragConvert_ColorMatrix;
break; break;
case DMABufSurface::SURFACE_YUV420: case DMABufSurface::SURFACE_YUV420:
fragSample = kFragSample_ThreePlane; fragBody = kFragBody_PlanarYUV;
pYuvArgs = &yuvArgs; pYuvArgs = &yuvArgs;
fragConvert = kFragConvert_ColorMatrix;
break; break;
default: default:
gfxCriticalError() << "Unexpected pixel format: " << pixelFormat; gfxCriticalError() << "Unexpected pixel format: " << pixelFormat;
@@ -1474,8 +1376,7 @@ bool GLBlitHelper::Blit(DMABufSurface* surface, const gfx::IntSize& destSize,
baseArgs.texMatrix0 = SubRectMat3(0, 0, 1, 1); baseArgs.texMatrix0 = SubRectMat3(0, 0, 1, 1);
yuvArgs.texMatrix1 = SubRectMat3(0, 0, 1, 1); yuvArgs.texMatrix1 = SubRectMat3(0, 0, 1, 1);
const auto& prog = const auto& prog = GetDrawBlitProg({kFragHeader_Tex2D, fragBody});
GetDrawBlitProg({kFragHeader_Tex2D, {fragSample, fragConvert}});
prog->Draw(baseArgs, pYuvArgs); prog->Draw(baseArgs, pYuvArgs);
return true; return true;
@@ -1493,105 +1394,5 @@ bool GLBlitHelper::BlitImage(layers::DMABUFSurfaceImage* srcImage,
} }
#endif #endif
// -
template <size_t N>
static void PushUnorm(uint32_t* const out, const float inVal) {
const uint32_t mask = (1 << N) - 1;
auto fval = inVal;
fval = std::max(0.0f, std::min(fval, 1.0f));
fval *= mask;
fval = roundf(fval);
auto ival = static_cast<uint32_t>(fval);
ival &= mask;
*out <<= N;
*out |= ival;
}
static uint32_t toRgb10A2(const color::vec4& val) {
// R in LSB
uint32_t ret = 0;
PushUnorm<2>(&ret, val.w());
PushUnorm<10>(&ret, val.z());
PushUnorm<10>(&ret, val.y());
PushUnorm<10>(&ret, val.x());
return ret;
}
std::shared_ptr<gl::Texture> GLBlitHelper::GetColorLutTex(
const ColorLutKey& key) const {
auto& weak = mColorLutTexMap[key];
auto strong = weak.lock();
if (!strong) {
auto& gl = *mGL;
strong = std::make_shared<gl::Texture>(gl);
weak = strong;
const auto ct = color::ColorspaceTransform::Create(key.src, key.dst);
// -
const auto minLutSize = color::ivec3{2};
const auto maxLutSize = color::ivec3{256};
auto lutSize = minLutSize;
if (ct.srcSpace.yuv) {
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()));
} else {
lutSize.x(int(StaticPrefs::gfx_blithelper_lut_size_rgb_r()));
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);
const auto& size = lut.size;
// -
constexpr GLenum target = LOCAL_GL_TEXTURE_3D;
const auto bind = gl::ScopedBindTexture(&gl, strong->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);
gl.fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
gl.fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
bool useFloat16 = true;
if (useFloat16) {
// Use rgba16f, which we can thankfully upload as rgba32f
static_assert(sizeof(color::vec4) == sizeof(float) * 4);
std::vector<color::vec4> uploadData;
uploadData.reserve(lut.data.size());
for (const auto& src : lut.data) {
const auto dst = color::vec4{src, 1};
uploadData.push_back(dst);
}
gl.fTexStorage3D(target, 1, LOCAL_GL_RGBA16F, size.x(), size.y(),
size.z());
gl.fTexSubImage3D(target, 0, 0, 0, 0, size.x(), size.y(), size.z(),
LOCAL_GL_RGBA, LOCAL_GL_FLOAT, uploadData.data());
} else {
// Use Rgb10A2
std::vector<uint32_t> uploadData;
uploadData.reserve(lut.data.size());
for (const auto& src : lut.data) {
const auto dst = toRgb10A2({src, 1});
uploadData.push_back(dst);
}
gl.fTexStorage3D(target, 1, LOCAL_GL_RGB10_A2, size.x(), size.y(),
size.z());
gl.fTexSubImage3D(target, 0, 0, 0, 0, size.x(), size.y(), size.z(),
LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV,
uploadData.data());
}
}
return strong;
}
} // namespace gl } // namespace gl
} // namespace mozilla } // namespace mozilla

View File

@@ -7,12 +7,8 @@
#ifndef GLBLITHELPER_H_ #ifndef GLBLITHELPER_H_
#define GLBLITHELPER_H_ #define GLBLITHELPER_H_
#include <array>
#include <cstdint> #include <cstdint>
#include <map> #include <map>
#include <memory>
#include <unordered_map>
#include "Colorspaces.h"
#include "GLConsts.h" #include "GLConsts.h"
#include "GLContextTypes.h" #include "GLContextTypes.h"
#include "GLTypes.h" #include "GLTypes.h"
@@ -82,9 +78,8 @@ class DMABUFSurfaceImage;
namespace gl { namespace gl {
class BindAnglePlanes; class BindAnglePlanes;
class GLBlitHelper;
class GLContext; class GLContext;
class Texture; class GLBlitHelper;
bool GuessDivisors(const gfx::IntSize& ySize, const gfx::IntSize& uvSize, bool GuessDivisors(const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
gfx::IntSize* const out_divisors); gfx::IntSize* const out_divisors);
@@ -95,27 +90,10 @@ struct Mat {
float& at(const uint8_t x, const uint8_t y) { return m[N * x + y]; } float& at(const uint8_t x, const uint8_t y) { return m[N * x + y]; }
static Mat<N> I() { static Mat<N> Zero();
auto ret = Mat<N>{}; static Mat<N> I();
for (uint8_t i = 0; i < N; i++) {
ret.at(i, i) = 1.0f;
}
return ret;
}
Mat<N> operator*(const Mat<N>& r) const { Mat<N> operator*(const Mat<N>& r) const;
Mat<N> ret;
for (uint8_t x = 0; x < N; x++) {
for (uint8_t y = 0; y < N; y++) {
float sum = 0.0f;
for (uint8_t i = 0; i < N; i++) {
sum += at(i, y) * r.at(x, i);
}
ret.at(x, y) = sum;
}
}
return ret;
}
}; };
typedef Mat<3> Mat3; typedef Mat<3> Mat3;
@@ -130,18 +108,17 @@ class DrawBlitProg final {
const GLint mLoc_uDestMatrix; const GLint mLoc_uDestMatrix;
const GLint mLoc_uTexMatrix0; const GLint mLoc_uTexMatrix0;
const GLint mLoc_uTexMatrix1; const GLint mLoc_uTexMatrix1;
const GLint mLoc_uColorLut;
const GLint mLoc_uColorMatrix; const GLint mLoc_uColorMatrix;
GLenum mType_uColorMatrix = 0; GLenum mType_uColorMatrix = 0;
public: public:
struct Key final { struct Key final {
const char* fragHeader = nullptr; const char* const fragHeader;
std::array<const char*, 2> fragParts = {}; const char* const fragBody;
auto Members() const { return std::tie(fragHeader, fragParts); } bool operator<(const Key& x) const {
friend bool operator<(const Key& a, const Key& b) { if (fragHeader != x.fragHeader) return fragHeader < x.fragHeader;
return a.Members() < b.Members(); return fragBody < x.fragBody;
} }
}; };
@@ -154,11 +131,10 @@ class DrawBlitProg final {
gfx::IntSize gfx::IntSize
destSize; // Always needed for (at least) setting the viewport. destSize; // Always needed for (at least) setting the viewport.
Maybe<gfx::IntRect> destRect; Maybe<gfx::IntRect> destRect;
Maybe<uint32_t> texUnitForColorLut;
}; };
struct YUVArgs final { struct YUVArgs final {
Mat3 texMatrix1; Mat3 texMatrix1;
Maybe<gfx::YUVColorSpace> colorSpaceForMatrix; gfx::YUVColorSpace colorSpace;
}; };
void Draw(const BaseArgs& args, const YUVArgs* argsYUV = nullptr) const; void Draw(const BaseArgs& args, const YUVArgs* argsYUV = nullptr) const;
@@ -166,15 +142,14 @@ class DrawBlitProg final {
class ScopedSaveMultiTex final { class ScopedSaveMultiTex final {
GLContext& mGL; GLContext& mGL;
const std::vector<uint8_t> mTexUnits; const uint8_t mTexCount;
const GLenum mTexTarget; const GLenum mTexTarget;
const GLuint mOldTexUnit; const GLuint mOldTexUnit;
GLuint mOldTexSampler[3]; GLuint mOldTexSampler[3];
GLuint mOldTex[3]; GLuint mOldTex[3];
public: public:
ScopedSaveMultiTex(GLContext* gl, const std::vector<uint8_t>& texUnits, ScopedSaveMultiTex(GLContext* gl, uint8_t texCount, GLenum texTarget);
GLenum texTarget);
~ScopedSaveMultiTex(); ~ScopedSaveMultiTex();
}; };
@@ -196,23 +171,6 @@ class GLBlitHelper final {
gfx::IntSize mYuvUploads_YSize = {0, 0}; gfx::IntSize mYuvUploads_YSize = {0, 0};
gfx::IntSize mYuvUploads_UVSize = {0, 0}; gfx::IntSize mYuvUploads_UVSize = {0, 0};
public:
struct ColorLutKey {
color::ColorspaceDesc src;
color::ColorspaceDesc dst;
auto Members() const { return std::tie(src, dst); }
INLINE_AUTO_MAPPABLE(ColorLutKey)
};
private:
mutable std::unordered_map<ColorLutKey, std::weak_ptr<gl::Texture>,
ColorLutKey::Hasher>
mColorLutTexMap;
public:
std::shared_ptr<gl::Texture> GetColorLutTex(const ColorLutKey& key) const;
#ifdef XP_WIN #ifdef XP_WIN
mutable RefPtr<ID3D11Device> mD3D11; mutable RefPtr<ID3D11Device> mD3D11;
@@ -312,21 +270,13 @@ class GLBlitHelper final {
#endif #endif
}; };
// -
// For DrawBlitProg::Key::fragParts
extern const char* const kFragHeader_Tex2D; extern const char* const kFragHeader_Tex2D;
extern const char* const kFragHeader_Tex2DRect; extern const char* const kFragHeader_Tex2DRect;
extern const char* const kFragHeader_TexExt; extern const char* const kFragHeader_TexExt;
extern const char* const kFragBody_RGBA;
extern const char* const kFragSample_OnePlane; extern const char* const kFragBody_CrYCb;
extern const char* const kFragSample_TwoPlane; extern const char* const kFragBody_NV12;
extern const char* const kFragSample_ThreePlane; extern const char* const kFragBody_PlanarYUV;
extern const char* const kFragConvert_None;
extern const char* const kFragConvert_BGR;
extern const char* const kFragConvert_ColorMatrix;
extern const char* const kFragConvert_ColorLut;
} // namespace gl } // namespace gl
} // namespace mozilla } // namespace mozilla

View File

@@ -84,16 +84,7 @@ class BindAnglePlanes final {
const EGLAttrib* const* postAttribsList = nullptr) const EGLAttrib* const* postAttribsList = nullptr)
: mParent(*parent), : mParent(*parent),
mNumPlanes(numPlanes), mNumPlanes(numPlanes),
mMultiTex( mMultiTex(mParent.mGL, mNumPlanes, LOCAL_GL_TEXTURE_EXTERNAL),
mParent.mGL,
[&]() {
std::vector<uint8_t> ret;
for (int i = 0; i < numPlanes; i++) {
ret.push_back(i);
}
return ret;
}(),
LOCAL_GL_TEXTURE_EXTERNAL),
mTempTexs{0}, mTempTexs{0},
mStreams{0}, mStreams{0},
mSuccess(true) { mSuccess(true) {
@@ -239,7 +230,7 @@ bool GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc,
const auto srcOrigin = OriginPos::BottomLeft; const auto srcOrigin = OriginPos::BottomLeft;
const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height); const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height);
const auto colorSpace = desc.colorSpace(); const auto colorSpace = desc.yUVColorSpace();
if (format != gfx::SurfaceFormat::NV12 && if (format != gfx::SurfaceFormat::NV12 &&
format != gfx::SurfaceFormat::P010 && format != gfx::SurfaceFormat::P010 &&
@@ -295,30 +286,13 @@ bool GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc,
const gfx::IntSize uvSize(ySize.width / divisors.width, const gfx::IntSize uvSize(ySize.width / divisors.width,
ySize.height / divisors.height); ySize.height / divisors.height);
const auto yuvColorSpace = [&]() {
switch (colorSpace) {
case gfx::ColorSpace2::UNKNOWN:
case gfx::ColorSpace2::SRGB:
case gfx::ColorSpace2::DISPLAY_P3:
MOZ_CRASH("Expected BT* colorspace");
case gfx::ColorSpace2::BT601_525:
return gfx::YUVColorSpace::BT601;
case gfx::ColorSpace2::BT709:
return gfx::YUVColorSpace::BT709;
case gfx::ColorSpace2::BT2020:
return gfx::YUVColorSpace::BT2020;
}
MOZ_ASSERT_UNREACHABLE();
}();
const bool yFlip = destOrigin != srcOrigin; const bool yFlip = destOrigin != srcOrigin;
const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, ySize), yFlip, const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, ySize), yFlip,
destSize, Nothing()}; destSize, Nothing()};
const DrawBlitProg::YUVArgs yuvArgs = { const DrawBlitProg::YUVArgs yuvArgs = {
SubRectMat3(clipRect, uvSize, divisors), Some(yuvColorSpace)}; SubRectMat3(clipRect, uvSize, divisors), colorSpace};
const auto& prog = GetDrawBlitProg( const auto& prog = GetDrawBlitProg({kFragHeader_TexExt, kFragBody_NV12});
{kFragHeader_TexExt, {kFragSample_TwoPlane, kFragConvert_ColorMatrix}});
prog->Draw(baseArgs, &yuvArgs); prog->Draw(baseArgs, &yuvArgs);
return true; return true;
} }
@@ -366,10 +340,9 @@ bool GLBlitHelper::BlitAngleYCbCr(const WindowsHandle (&handleList)[3],
const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, ySize), yFlip, const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, ySize), yFlip,
destSize, Nothing()}; destSize, Nothing()};
const DrawBlitProg::YUVArgs yuvArgs = { const DrawBlitProg::YUVArgs yuvArgs = {
SubRectMat3(clipRect, uvSize, divisors), Some(colorSpace)}; SubRectMat3(clipRect, uvSize, divisors), colorSpace};
const auto& prog = GetDrawBlitProg( const auto& prog = GetDrawBlitProg({kFragHeader_TexExt, kFragBody_PlanarYUV});
{kFragHeader_TexExt, {kFragSample_ThreePlane, kFragConvert_ColorMatrix}});
prog->Draw(baseArgs, &yuvArgs); prog->Draw(baseArgs, &yuvArgs);
return true; return true;
} }

View File

@@ -143,7 +143,7 @@ SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor() {
const auto format = gfx::SurfaceFormat::B8G8R8A8; const auto format = gfx::SurfaceFormat::B8G8R8A8;
return Some(layers::SurfaceDescriptorD3D10( return Some(layers::SurfaceDescriptorD3D10(
(WindowsHandle)mShareHandle, /* gpuProcessTextureId */ Nothing(), (WindowsHandle)mShareHandle, /* gpuProcessTextureId */ Nothing(),
/* arrayIndex */ 0, format, mDesc.size, mDesc.colorSpace, /* arrayIndex */ 0, format, mDesc.size, gfx::YUVColorSpace::Identity,
gfx::ColorRange::FULL)); gfx::ColorRange::FULL));
} }

View File

@@ -439,7 +439,7 @@ SharedSurface_D3D11Interop::ToSurfaceDescriptor() {
const auto format = gfx::SurfaceFormat::B8G8R8A8; const auto format = gfx::SurfaceFormat::B8G8R8A8;
return Some(layers::SurfaceDescriptorD3D10( return Some(layers::SurfaceDescriptorD3D10(
WindowsHandle(mData.dxgiHandle), /* gpuProcessTextureId */ Nothing(), WindowsHandle(mData.dxgiHandle), /* gpuProcessTextureId */ Nothing(),
/* arrayIndex */ 0, format, mDesc.size, mDesc.colorSpace, /* arrayIndex */ 0, format, mDesc.size, gfx::YUVColorSpace::Identity,
gfx::ColorRange::FULL)); gfx::ColorRange::FULL));
} }

View File

@@ -1,405 +0,0 @@
/* -*- Mode: C++; tab-width: 2; 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/. */
#include "gtest/gtest.h"
#include "Colorspaces.h"
#include <limits>
namespace mozilla::color {
mat4 YuvFromYcbcr(const YcbcrDesc&);
float TfFromLinear(const PiecewiseGammaDesc&, float linear);
float LinearFromTf(const PiecewiseGammaDesc&, float tf);
} // namespace mozilla::color
using namespace mozilla::color;
auto Calc8From8(const ColorspaceTransform& ct, const ivec3 in8) {
const auto in = vec3(in8) / vec3(255);
const auto out = ct.DstFromSrc(in);
const auto out8 = ivec3(round(out * vec3(255)));
return out8;
}
auto Sample8From8(const Lut3& lut, const vec3 in8) {
const auto in = in8 / vec3(255);
const auto out = lut.Sample(in);
const auto out8 = ivec3(round(out * vec3(255)));
return out8;
}
TEST(Colorspaces, YcbcrDesc_Narrow8)
{
const auto m = YuvFromYcbcr(YcbcrDesc::Narrow8());
const auto Yuv8 = [&](const ivec3 ycbcr8) {
const auto ycbcr = vec4(vec3(ycbcr8) / 255, 1);
const auto yuv = m * ycbcr;
return ivec3(round(yuv * 255));
};
EXPECT_EQ(Yuv8({{16, 128, 128}}), (ivec3{{0, 0, 0}}));
EXPECT_EQ(Yuv8({{17, 128, 128}}), (ivec3{{1, 0, 0}}));
// y = 0.5 => (16 + 235) / 2 = 125.5
EXPECT_EQ(Yuv8({{125, 128, 128}}), (ivec3{{127, 0, 0}}));
EXPECT_EQ(Yuv8({{126, 128, 128}}), (ivec3{{128, 0, 0}}));
EXPECT_EQ(Yuv8({{234, 128, 128}}), (ivec3{{254, 0, 0}}));
EXPECT_EQ(Yuv8({{235, 128, 128}}), (ivec3{{255, 0, 0}}));
// Check that we get the naive out-of-bounds behavior we'd expect:
EXPECT_EQ(Yuv8({{15, 128, 128}}), (ivec3{{-1, 0, 0}}));
EXPECT_EQ(Yuv8({{236, 128, 128}}), (ivec3{{256, 0, 0}}));
}
TEST(Colorspaces, YcbcrDesc_Full8)
{
const auto m = YuvFromYcbcr(YcbcrDesc::Full8());
const auto Yuv8 = [&](const ivec3 ycbcr8) {
const auto ycbcr = vec4(vec3(ycbcr8) / 255, 1);
const auto yuv = m * ycbcr;
return ivec3(round(yuv * 255));
};
EXPECT_EQ(Yuv8({{0, 128, 128}}), (ivec3{{0, 0, 0}}));
EXPECT_EQ(Yuv8({{1, 128, 128}}), (ivec3{{1, 0, 0}}));
EXPECT_EQ(Yuv8({{127, 128, 128}}), (ivec3{{127, 0, 0}}));
EXPECT_EQ(Yuv8({{128, 128, 128}}), (ivec3{{128, 0, 0}}));
EXPECT_EQ(Yuv8({{254, 128, 128}}), (ivec3{{254, 0, 0}}));
EXPECT_EQ(Yuv8({{255, 128, 128}}), (ivec3{{255, 0, 0}}));
}
TEST(Colorspaces, YcbcrDesc_Float)
{
const auto m = YuvFromYcbcr(YcbcrDesc::Float());
const auto Yuv8 = [&](const vec3 ycbcr8) {
const auto ycbcr = vec4(vec3(ycbcr8) / 255, 1);
const auto yuv = m * ycbcr;
return ivec3(round(yuv * 255));
};
EXPECT_EQ(Yuv8({{0, 0.5 * 255, 0.5 * 255}}), (ivec3{{0, 0, 0}}));
EXPECT_EQ(Yuv8({{1, 0.5 * 255, 0.5 * 255}}), (ivec3{{1, 0, 0}}));
EXPECT_EQ(Yuv8({{127, 0.5 * 255, 0.5 * 255}}), (ivec3{{127, 0, 0}}));
EXPECT_EQ(Yuv8({{128, 0.5 * 255, 0.5 * 255}}), (ivec3{{128, 0, 0}}));
EXPECT_EQ(Yuv8({{254, 0.5 * 255, 0.5 * 255}}), (ivec3{{254, 0, 0}}));
EXPECT_EQ(Yuv8({{255, 0.5 * 255, 0.5 * 255}}), (ivec3{{255, 0, 0}}));
}
TEST(Colorspaces, ColorspaceTransform_Rec709Narrow)
{
const auto src = ColorspaceDesc{
Chromaticities::Rec709(),
PiecewiseGammaDesc::Rec709(),
{{YuvLumaCoeffs::Rec709(), YcbcrDesc::Narrow8()}},
};
const auto dst = ColorspaceDesc{
Chromaticities::Rec709(),
PiecewiseGammaDesc::Rec709(),
{},
};
const auto ct = ColorspaceTransform::Create(src, dst);
EXPECT_EQ(Calc8From8(ct, {{16, 128, 128}}), (ivec3{0}));
EXPECT_EQ(Calc8From8(ct, {{17, 128, 128}}), (ivec3{1}));
EXPECT_EQ(Calc8From8(ct, {{126, 128, 128}}), (ivec3{128}));
EXPECT_EQ(Calc8From8(ct, {{234, 128, 128}}), (ivec3{254}));
EXPECT_EQ(Calc8From8(ct, {{235, 128, 128}}), (ivec3{255}));
// Check that we get the naive out-of-bounds behavior we'd expect:
EXPECT_EQ(Calc8From8(ct, {{15, 128, 128}}), (ivec3{-1}));
EXPECT_EQ(Calc8From8(ct, {{236, 128, 128}}), (ivec3{256}));
}
TEST(Colorspaces, LutSample_Rec709Float)
{
const auto src = ColorspaceDesc{
Chromaticities::Rec709(),
PiecewiseGammaDesc::Rec709(),
{{YuvLumaCoeffs::Rec709(), YcbcrDesc::Float()}},
};
const auto dst = ColorspaceDesc{
Chromaticities::Rec709(),
PiecewiseGammaDesc::Rec709(),
{},
};
const auto lut = ColorspaceTransform::Create(src, dst).ToLut3();
EXPECT_EQ(Sample8From8(lut, {{0, 0.5 * 255, 0.5 * 255}}), (ivec3{0}));
EXPECT_EQ(Sample8From8(lut, {{1, 0.5 * 255, 0.5 * 255}}), (ivec3{1}));
EXPECT_EQ(Sample8From8(lut, {{127, 0.5 * 255, 0.5 * 255}}), (ivec3{127}));
EXPECT_EQ(Sample8From8(lut, {{128, 0.5 * 255, 0.5 * 255}}), (ivec3{128}));
EXPECT_EQ(Sample8From8(lut, {{254, 0.5 * 255, 0.5 * 255}}), (ivec3{254}));
EXPECT_EQ(Sample8From8(lut, {{255, 0.5 * 255, 0.5 * 255}}), (ivec3{255}));
}
TEST(Colorspaces, LutSample_Rec709Narrow)
{
const auto src = ColorspaceDesc{
Chromaticities::Rec709(),
PiecewiseGammaDesc::Rec709(),
{{YuvLumaCoeffs::Rec709(), YcbcrDesc::Narrow8()}},
};
const auto dst = ColorspaceDesc{
Chromaticities::Rec709(),
PiecewiseGammaDesc::Rec709(),
{},
};
const auto lut = ColorspaceTransform::Create(src, dst).ToLut3();
EXPECT_EQ(Sample8From8(lut, {{16, 128, 128}}), (ivec3{0}));
EXPECT_EQ(Sample8From8(lut, {{17, 128, 128}}), (ivec3{1}));
EXPECT_EQ(Sample8From8(lut, {{int((235 + 16) / 2), 128, 128}}), (ivec3{127}));
EXPECT_EQ(Sample8From8(lut, {{int((235 + 16) / 2) + 1, 128, 128}}),
(ivec3{128}));
EXPECT_EQ(Sample8From8(lut, {{234, 128, 128}}), (ivec3{254}));
EXPECT_EQ(Sample8From8(lut, {{235, 128, 128}}), (ivec3{255}));
}
TEST(Colorspaces, LutSample_Rec709Full)
{
const auto src = ColorspaceDesc{
Chromaticities::Rec709(),
PiecewiseGammaDesc::Rec709(),
{{YuvLumaCoeffs::Rec709(), YcbcrDesc::Full8()}},
};
const auto dst = ColorspaceDesc{
Chromaticities::Rec709(),
PiecewiseGammaDesc::Rec709(),
{},
};
const auto lut = ColorspaceTransform::Create(src, dst).ToLut3();
EXPECT_EQ(Sample8From8(lut, {{0, 128, 128}}), (ivec3{0}));
EXPECT_EQ(Sample8From8(lut, {{1, 128, 128}}), (ivec3{1}));
EXPECT_EQ(Sample8From8(lut, {{16, 128, 128}}), (ivec3{16}));
EXPECT_EQ(Sample8From8(lut, {{128, 128, 128}}), (ivec3{128}));
EXPECT_EQ(Sample8From8(lut, {{235, 128, 128}}), (ivec3{235}));
EXPECT_EQ(Sample8From8(lut, {{254, 128, 128}}), (ivec3{254}));
EXPECT_EQ(Sample8From8(lut, {{255, 128, 128}}), (ivec3{255}));
}
TEST(Colorspaces, PiecewiseGammaDesc_Srgb)
{
const auto tf = PiecewiseGammaDesc::Srgb();
EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x00 / 255.0) * 255)), 0x00);
EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x01 / 255.0) * 255)), 0x0d);
EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x37 / 255.0) * 255)), 0x80);
EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x80 / 255.0) * 255)), 0xbc);
EXPECT_EQ(int(roundf(TfFromLinear(tf, 0xfd / 255.0) * 255)), 0xfe);
EXPECT_EQ(int(roundf(TfFromLinear(tf, 0xfe / 255.0) * 255)), 0xff);
EXPECT_EQ(int(roundf(TfFromLinear(tf, 0xff / 255.0) * 255)), 0xff);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x00 / 255.0) * 255)), 0x00);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x01 / 255.0) * 255)), 0x00);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x06 / 255.0) * 255)), 0x00);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x07 / 255.0) * 255)), 0x01);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x0d / 255.0) * 255)), 0x01);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x80 / 255.0) * 255)), 0x37);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0xbc / 255.0) * 255)), 0x80);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0xfe / 255.0) * 255)), 0xfd);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0xff / 255.0) * 255)), 0xff);
}
TEST(Colorspaces, PiecewiseGammaDesc_Rec709)
{
const auto tf = PiecewiseGammaDesc::Rec709();
EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x00 / 255.0) * 255)), 0x00);
EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x01 / 255.0) * 255)), 0x05);
EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x43 / 255.0) * 255)), 0x80);
EXPECT_EQ(int(roundf(TfFromLinear(tf, 0x80 / 255.0) * 255)), 0xb4);
EXPECT_EQ(int(roundf(TfFromLinear(tf, 0xfd / 255.0) * 255)), 0xfe);
EXPECT_EQ(int(roundf(TfFromLinear(tf, 0xfe / 255.0) * 255)), 0xff);
EXPECT_EQ(int(roundf(TfFromLinear(tf, 0xff / 255.0) * 255)), 0xff);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x00 / 255.0) * 255)), 0x00);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x01 / 255.0) * 255)), 0x00);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x02 / 255.0) * 255)), 0x00);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x03 / 255.0) * 255)), 0x01);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x05 / 255.0) * 255)), 0x01);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0x80 / 255.0) * 255)), 0x43);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0xb4 / 255.0) * 255)), 0x80);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0xfe / 255.0) * 255)), 0xfd);
EXPECT_EQ(int(roundf(LinearFromTf(tf, 0xff / 255.0) * 255)), 0xff);
}
TEST(Colorspaces, ColorspaceTransform_PiecewiseGammaDesc)
{
const auto src = ColorspaceDesc{
Chromaticities::Srgb(),
{},
{},
};
const auto dst = ColorspaceDesc{
Chromaticities::Srgb(),
PiecewiseGammaDesc::Srgb(),
{},
};
const auto toGamma = ColorspaceTransform::Create(src, dst);
const auto toLinear = ColorspaceTransform::Create(dst, src);
EXPECT_EQ(Calc8From8(toGamma, ivec3{0x00}), (ivec3{0x00}));
EXPECT_EQ(Calc8From8(toGamma, ivec3{0x01}), (ivec3{0x0d}));
EXPECT_EQ(Calc8From8(toGamma, ivec3{0x37}), (ivec3{0x80}));
EXPECT_EQ(Calc8From8(toGamma, ivec3{0x80}), (ivec3{0xbc}));
EXPECT_EQ(Calc8From8(toGamma, ivec3{0xfd}), (ivec3{0xfe}));
EXPECT_EQ(Calc8From8(toGamma, ivec3{0xff}), (ivec3{0xff}));
EXPECT_EQ(Calc8From8(toLinear, ivec3{0x00}), (ivec3{0x00}));
EXPECT_EQ(Calc8From8(toLinear, ivec3{0x0d}), (ivec3{0x01}));
EXPECT_EQ(Calc8From8(toLinear, ivec3{0x80}), (ivec3{0x37}));
EXPECT_EQ(Calc8From8(toLinear, ivec3{0xbc}), (ivec3{0x80}));
EXPECT_EQ(Calc8From8(toLinear, ivec3{0xfe}), (ivec3{0xfd}));
EXPECT_EQ(Calc8From8(toLinear, ivec3{0xff}), (ivec3{0xff}));
}
// -
// Actual end-to-end tests
TEST(Colorspaces, SrgbFromRec709)
{
const auto src = ColorspaceDesc{
Chromaticities::Rec709(),
PiecewiseGammaDesc::Rec709(),
{{YuvLumaCoeffs::Rec709(), YcbcrDesc::Narrow8()}},
};
const auto dst = ColorspaceDesc{
Chromaticities::Srgb(),
PiecewiseGammaDesc::Srgb(),
{},
};
const auto ct = ColorspaceTransform::Create(src, dst);
EXPECT_EQ(Calc8From8(ct, ivec3{{16, 128, 128}}), (ivec3{0}));
EXPECT_EQ(Calc8From8(ct, ivec3{{17, 128, 128}}), (ivec3{3}));
EXPECT_EQ(Calc8From8(ct, ivec3{{115, 128, 128}}), (ivec3{128}));
EXPECT_EQ(Calc8From8(ct, ivec3{{126, 128, 128}}), (ivec3{140}));
EXPECT_EQ(Calc8From8(ct, ivec3{{234, 128, 128}}), (ivec3{254}));
EXPECT_EQ(Calc8From8(ct, ivec3{{235, 128, 128}}), (ivec3{255}));
}
TEST(Colorspaces, SrgbFromDisplayP3)
{
const auto p3C = ColorspaceDesc{
Chromaticities::DisplayP3(),
PiecewiseGammaDesc::DisplayP3(),
};
const auto srgbC = ColorspaceDesc{
Chromaticities::Srgb(),
PiecewiseGammaDesc::Srgb(),
};
const auto srgbLinearC = ColorspaceDesc{
Chromaticities::Srgb(),
{},
};
const auto srgbFromP3 = ColorspaceTransform::Create(p3C, srgbC);
const auto srgbLinearFromP3 = ColorspaceTransform::Create(p3C, srgbLinearC);
// E.g.
// https://colorjs.io/apps/convert/?color=color(display-p3%200.4%200.8%200.4)&precision=4
auto srgb = srgbFromP3.DstFromSrc(vec3{{0.4, 0.8, 0.4}});
EXPECT_NEAR(srgb.x(), 0.179, 0.001);
EXPECT_NEAR(srgb.y(), 0.812, 0.001);
EXPECT_NEAR(srgb.z(), 0.342, 0.001);
auto srgbLinear = srgbLinearFromP3.DstFromSrc(vec3{{0.4, 0.8, 0.4}});
EXPECT_NEAR(srgbLinear.x(), 0.027, 0.001);
EXPECT_NEAR(srgbLinear.y(), 0.624, 0.001);
EXPECT_NEAR(srgbLinear.z(), 0.096, 0.001);
}
// -
struct Stats {
double mean = 0;
double variance = 0;
double min = std::numeric_limits<double>::infinity();
double max = -std::numeric_limits<double>::infinity();
template <class T>
static Stats For(const T& iterable) {
auto ret = Stats{};
for (const auto& cur : iterable) {
ret.mean += cur;
ret.min = std::min(ret.min, cur);
ret.max = std::max(ret.max, cur);
}
ret.mean /= iterable.size();
for (const auto& cur : iterable) {
ret.variance += pow(cur - ret.mean, 2);
}
ret.variance /= iterable.size();
return ret;
}
double standardDeviation() const { return sqrt(variance); }
};
static Stats StatsForLutError(const ColorspaceTransform& ct,
const ivec3 srcQuants, const ivec3 dstQuants) {
const auto lut = ct.ToLut3();
const auto dstScale = vec3(dstQuants - 1);
std::vector<double> quantErrors;
quantErrors.reserve(srcQuants.x() * srcQuants.y() * srcQuants.z());
ForEachSampleWithin(srcQuants, [&](const vec3& src) {
const auto sampled = lut.Sample(src);
const auto actual = ct.DstFromSrc(src);
const auto isampled = ivec3(round(sampled * dstScale));
const auto iactual = ivec3(round(actual * dstScale));
const auto ierr = abs(isampled - iactual);
const auto quantError = dot(ierr, ivec3{1});
quantErrors.push_back(quantError);
if (quantErrors.size() % 100000 == 0) {
printf("%zu of %zu\n", quantErrors.size(), quantErrors.capacity());
}
});
const auto quantErrStats = Stats::For(quantErrors);
return quantErrStats;
}
TEST(Colorspaces, LutError_Rec709Full_Rec709Rgb)
{
const auto src = ColorspaceDesc{
Chromaticities::Rec709(),
PiecewiseGammaDesc::Rec709(),
{{YuvLumaCoeffs::Rec709(), YcbcrDesc::Full8()}},
};
const auto dst = ColorspaceDesc{
Chromaticities::Rec709(),
PiecewiseGammaDesc::Rec709(),
{},
};
const auto ct = ColorspaceTransform::Create(src, dst);
const auto stats = StatsForLutError(ct, ivec3{64}, ivec3{256});
EXPECT_NEAR(stats.mean, 0.000, 0.001);
EXPECT_NEAR(stats.standardDeviation(), 0.008, 0.001);
EXPECT_NEAR(stats.min, 0, 0.001);
EXPECT_NEAR(stats.max, 1, 0.001);
}
TEST(Colorspaces, LutError_Rec709Full_Srgb)
{
const auto src = ColorspaceDesc{
Chromaticities::Rec709(),
PiecewiseGammaDesc::Rec709(),
{{YuvLumaCoeffs::Rec709(), YcbcrDesc::Full8()}},
};
const auto dst = ColorspaceDesc{
Chromaticities::Srgb(),
PiecewiseGammaDesc::Srgb(),
{},
};
const auto ct = ColorspaceTransform::Create(src, dst);
const auto stats = StatsForLutError(ct, ivec3{64}, ivec3{256});
EXPECT_NEAR(stats.mean, 0.530, 0.001);
EXPECT_NEAR(stats.standardDeviation(), 1.674, 0.001);
EXPECT_NEAR(stats.min, 0, 0.001);
EXPECT_NEAR(stats.max, 17, 0.001);
}

View File

@@ -1,15 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
LOCAL_INCLUDES += [
"/gfx/gl",
]
UNIFIED_SOURCES += [
"TestColorspaces.cpp",
]
FINAL_LIBRARY = "xul-gtest"

View File

@@ -22,8 +22,6 @@ if CONFIG["MOZ_GL_PROVIDER"]:
EXPORTS += [ EXPORTS += [
"AndroidSurfaceTexture.h", "AndroidSurfaceTexture.h",
"AutoMappable.h",
"Colorspaces.h",
"ForceDiscreteGPUHelperCGL.h", "ForceDiscreteGPUHelperCGL.h",
"GfxTexturesReporter.h", "GfxTexturesReporter.h",
"GLBlitHelper.h", "GLBlitHelper.h",
@@ -119,7 +117,6 @@ if CONFIG["MOZ_WAYLAND"]:
UNIFIED_SOURCES += [ UNIFIED_SOURCES += [
"AndroidSurfaceTexture.cpp", "AndroidSurfaceTexture.cpp",
"Colorspaces.cpp",
"GfxTexturesReporter.cpp", "GfxTexturesReporter.cpp",
"GLBlitHelper.cpp", "GLBlitHelper.cpp",
"GLContext.cpp", "GLContext.cpp",
@@ -141,10 +138,6 @@ SOURCES += [
"GLScreenBuffer.cpp", "GLScreenBuffer.cpp",
] ]
TEST_DIRS += [
"gtest",
]
include("/ipc/chromium/chromium-config.mozbuild") include("/ipc/chromium/chromium-config.mozbuild")
FINAL_LIBRARY = "xul" FINAL_LIBRARY = "xul"

View File

@@ -714,12 +714,6 @@ struct ParamTraits<mozilla::gfx::YUVRangedColorSpace>
mozilla::gfx::YUVRangedColorSpace::_First, mozilla::gfx::YUVRangedColorSpace::_First,
mozilla::gfx::YUVRangedColorSpace::_Last> {}; mozilla::gfx::YUVRangedColorSpace::_Last> {};
template <>
struct ParamTraits<mozilla::gfx::ColorSpace2>
: public ContiguousEnumSerializerInclusive<
mozilla::gfx::ColorSpace2, mozilla::gfx::ColorSpace2::_First,
mozilla::gfx::ColorSpace2::_Last> {};
template <> template <>
struct ParamTraits<mozilla::StereoMode> struct ParamTraits<mozilla::StereoMode>
: public ContiguousEnumSerializer<mozilla::StereoMode, : public ContiguousEnumSerializer<mozilla::StereoMode,

View File

@@ -25,19 +25,19 @@ using namespace gfx;
D3D11ShareHandleImage::D3D11ShareHandleImage(const gfx::IntSize& aSize, D3D11ShareHandleImage::D3D11ShareHandleImage(const gfx::IntSize& aSize,
const gfx::IntRect& aRect, const gfx::IntRect& aRect,
gfx::ColorSpace2 aColorSpace, gfx::YUVColorSpace aColorSpace,
gfx::ColorRange aColorRange) gfx::ColorRange aColorRange)
: Image(nullptr, ImageFormat::D3D11_SHARE_HANDLE_TEXTURE), : Image(nullptr, ImageFormat::D3D11_SHARE_HANDLE_TEXTURE),
mSize(aSize), mSize(aSize),
mPictureRect(aRect), mPictureRect(aRect),
mColorSpace(aColorSpace), mYUVColorSpace(aColorSpace),
mColorRange(aColorRange) {} mColorRange(aColorRange) {}
bool D3D11ShareHandleImage::AllocateTexture(D3D11RecycleAllocator* aAllocator, bool D3D11ShareHandleImage::AllocateTexture(D3D11RecycleAllocator* aAllocator,
ID3D11Device* aDevice) { ID3D11Device* aDevice) {
if (aAllocator) { if (aAllocator) {
mTextureClient = mTextureClient =
aAllocator->CreateOrRecycleClient(mColorSpace, mColorRange, mSize); aAllocator->CreateOrRecycleClient(mYUVColorSpace, mColorRange, mSize);
if (mTextureClient) { if (mTextureClient) {
D3D11TextureData* textureData = GetData(); D3D11TextureData* textureData = GetData();
MOZ_DIAGNOSTIC_ASSERT(textureData, "Wrong TextureDataType"); MOZ_DIAGNOSTIC_ASSERT(textureData, "Wrong TextureDataType");
@@ -83,7 +83,7 @@ class MOZ_RAII D3D11TextureClientAllocationHelper
: public ITextureClientAllocationHelper { : public ITextureClientAllocationHelper {
public: public:
D3D11TextureClientAllocationHelper(gfx::SurfaceFormat aFormat, D3D11TextureClientAllocationHelper(gfx::SurfaceFormat aFormat,
gfx::ColorSpace2 aColorSpace, gfx::YUVColorSpace aColorSpace,
gfx::ColorRange aColorRange, gfx::ColorRange aColorRange,
const gfx::IntSize& aSize, const gfx::IntSize& aSize,
TextureAllocationFlags aAllocFlags, TextureAllocationFlags aAllocFlags,
@@ -91,7 +91,7 @@ class MOZ_RAII D3D11TextureClientAllocationHelper
TextureFlags aTextureFlags) TextureFlags aTextureFlags)
: ITextureClientAllocationHelper(aFormat, aSize, BackendSelector::Content, : ITextureClientAllocationHelper(aFormat, aSize, BackendSelector::Content,
aTextureFlags, aAllocFlags), aTextureFlags, aAllocFlags),
mColorSpace(aColorSpace), mYUVColorSpace(aColorSpace),
mColorRange(aColorRange), mColorRange(aColorRange),
mDevice(aDevice) {} mDevice(aDevice) {}
@@ -106,7 +106,7 @@ class MOZ_RAII D3D11TextureClientAllocationHelper
return (aTextureClient->GetFormat() != gfx::SurfaceFormat::NV12 && return (aTextureClient->GetFormat() != gfx::SurfaceFormat::NV12 &&
aTextureClient->GetFormat() != gfx::SurfaceFormat::P010 && aTextureClient->GetFormat() != gfx::SurfaceFormat::P010 &&
aTextureClient->GetFormat() != gfx::SurfaceFormat::P016) || aTextureClient->GetFormat() != gfx::SurfaceFormat::P016) ||
(textureData->mColorSpace == mColorSpace && (textureData->GetYUVColorSpace() == mYUVColorSpace &&
textureData->GetColorRange() == mColorRange && textureData->GetColorRange() == mColorRange &&
textureData->GetTextureAllocationFlags() == mAllocationFlags); textureData->GetTextureAllocationFlags() == mAllocationFlags);
} }
@@ -118,14 +118,14 @@ class MOZ_RAII D3D11TextureClientAllocationHelper
if (!data) { if (!data) {
return nullptr; return nullptr;
} }
data->mColorSpace = mColorSpace; data->SetYUVColorSpace(mYUVColorSpace);
data->SetColorRange(mColorRange); data->SetColorRange(mColorRange);
return MakeAndAddRef<TextureClient>(data, mTextureFlags, return MakeAndAddRef<TextureClient>(data, mTextureFlags,
aAllocator->GetTextureForwarder()); aAllocator->GetTextureForwarder());
} }
private: private:
const gfx::ColorSpace2 mColorSpace; const gfx::YUVColorSpace mYUVColorSpace;
const gfx::ColorRange mColorRange; const gfx::ColorRange mColorRange;
const RefPtr<ID3D11Device> mDevice; const RefPtr<ID3D11Device> mDevice;
}; };
@@ -158,7 +158,7 @@ void D3D11RecycleAllocator::SetPreferredSurfaceFormat(
} }
already_AddRefed<TextureClient> D3D11RecycleAllocator::CreateOrRecycleClient( already_AddRefed<TextureClient> D3D11RecycleAllocator::CreateOrRecycleClient(
gfx::ColorSpace2 aColorSpace, gfx::ColorRange aColorRange, gfx::YUVColorSpace aColorSpace, gfx::ColorRange aColorRange,
const gfx::IntSize& aSize) { const gfx::IntSize& aSize) {
// When CompositorDevice or ContentDevice is updated, // When CompositorDevice or ContentDevice is updated,
// we could not reuse old D3D11Textures. It could cause video flickering. // we could not reuse old D3D11Textures. It could cause video flickering.

View File

@@ -28,7 +28,7 @@ class D3D11RecycleAllocator final : public TextureClientRecycleAllocator {
gfx::SurfaceFormat aPreferredFormat); gfx::SurfaceFormat aPreferredFormat);
already_AddRefed<TextureClient> CreateOrRecycleClient( already_AddRefed<TextureClient> CreateOrRecycleClient(
gfx::ColorSpace2 aColorSpace, gfx::ColorRange aColorRange, gfx::YUVColorSpace aColorSpace, gfx::ColorRange aColorRange,
const gfx::IntSize& aSize); const gfx::IntSize& aSize);
void SetPreferredSurfaceFormat(gfx::SurfaceFormat aPreferredFormat); void SetPreferredSurfaceFormat(gfx::SurfaceFormat aPreferredFormat);
@@ -52,7 +52,7 @@ class D3D11RecycleAllocator final : public TextureClientRecycleAllocator {
class D3D11ShareHandleImage final : public Image { class D3D11ShareHandleImage final : public Image {
public: public:
D3D11ShareHandleImage(const gfx::IntSize& aSize, const gfx::IntRect& aRect, D3D11ShareHandleImage(const gfx::IntSize& aSize, const gfx::IntRect& aRect,
gfx::ColorSpace2 aColorSpace, gfx::YUVColorSpace aColorSpace,
gfx::ColorRange aColorRange); gfx::ColorRange aColorRange);
virtual ~D3D11ShareHandleImage() = default; virtual ~D3D11ShareHandleImage() = default;
@@ -66,6 +66,7 @@ class D3D11ShareHandleImage final : public Image {
ID3D11Texture2D* GetTexture() const; ID3D11Texture2D* GetTexture() const;
gfx::YUVColorSpace GetYUVColorSpace() const { return mYUVColorSpace; }
gfx::ColorRange GetColorRange() const { return mColorRange; } gfx::ColorRange GetColorRange() const { return mColorRange; }
private: private:
@@ -79,11 +80,7 @@ class D3D11ShareHandleImage final : public Image {
gfx::IntSize mSize; gfx::IntSize mSize;
gfx::IntRect mPictureRect; gfx::IntRect mPictureRect;
gfx::YUVColorSpace mYUVColorSpace;
public:
const gfx::ColorSpace2 mColorSpace;
private:
gfx::ColorRange mColorRange; gfx::ColorRange mColorRange;
RefPtr<TextureClient> mTextureClient; RefPtr<TextureClient> mTextureClient;
RefPtr<ID3D11Texture2D> mTexture; RefPtr<ID3D11Texture2D> mTexture;

View File

@@ -35,14 +35,14 @@ void IMFSampleWrapper::ClearVideoSample() { mVideoSample = nullptr; }
D3D11TextureIMFSampleImage::D3D11TextureIMFSampleImage( D3D11TextureIMFSampleImage::D3D11TextureIMFSampleImage(
IMFSample* aVideoSample, ID3D11Texture2D* aTexture, uint32_t aArrayIndex, IMFSample* aVideoSample, ID3D11Texture2D* aTexture, uint32_t aArrayIndex,
const gfx::IntSize& aSize, const gfx::IntRect& aRect, const gfx::IntSize& aSize, const gfx::IntRect& aRect,
gfx::ColorSpace2 aColorSpace, gfx::ColorRange aColorRange) gfx::YUVColorSpace aColorSpace, gfx::ColorRange aColorRange)
: Image(nullptr, ImageFormat::D3D11_TEXTURE_IMF_SAMPLE), : Image(nullptr, ImageFormat::D3D11_TEXTURE_IMF_SAMPLE),
mVideoSample(IMFSampleWrapper::Create(aVideoSample)), mVideoSample(IMFSampleWrapper::Create(aVideoSample)),
mTexture(aTexture), mTexture(aTexture),
mArrayIndex(aArrayIndex), mArrayIndex(aArrayIndex),
mSize(aSize), mSize(aSize),
mPictureRect(aRect), mPictureRect(aRect),
mColorSpace(aColorSpace), mYUVColorSpace(aColorSpace),
mColorRange(aColorRange) { mColorRange(aColorRange) {
MOZ_ASSERT(XRE_IsGPUProcess()); MOZ_ASSERT(XRE_IsGPUProcess());
} }
@@ -50,7 +50,7 @@ D3D11TextureIMFSampleImage::D3D11TextureIMFSampleImage(
void D3D11TextureIMFSampleImage::AllocateTextureClient( void D3D11TextureIMFSampleImage::AllocateTextureClient(
KnowsCompositor* aKnowsCompositor, RefPtr<IMFSampleUsageInfo> aUsageInfo) { KnowsCompositor* aKnowsCompositor, RefPtr<IMFSampleUsageInfo> aUsageInfo) {
mTextureClient = D3D11TextureData::CreateTextureClient( mTextureClient = D3D11TextureData::CreateTextureClient(
mTexture, mArrayIndex, mSize, gfx::SurfaceFormat::NV12, mColorSpace, mTexture, mArrayIndex, mSize, gfx::SurfaceFormat::NV12, mYUVColorSpace,
mColorRange, aKnowsCompositor, aUsageInfo); mColorRange, aKnowsCompositor, aUsageInfo);
MOZ_ASSERT(mTextureClient); MOZ_ASSERT(mTextureClient);
} }

View File

@@ -59,7 +59,7 @@ class D3D11TextureIMFSampleImage final : public Image {
D3D11TextureIMFSampleImage(IMFSample* aVideoSample, ID3D11Texture2D* aTexture, D3D11TextureIMFSampleImage(IMFSample* aVideoSample, ID3D11Texture2D* aTexture,
uint32_t aArrayIndex, const gfx::IntSize& aSize, uint32_t aArrayIndex, const gfx::IntSize& aSize,
const gfx::IntRect& aRect, const gfx::IntRect& aRect,
gfx::ColorSpace2 aColorSpace, gfx::YUVColorSpace aColorSpace,
gfx::ColorRange aColorRange); gfx::ColorRange aColorRange);
virtual ~D3D11TextureIMFSampleImage() = default; virtual ~D3D11TextureIMFSampleImage() = default;
@@ -74,6 +74,7 @@ class D3D11TextureIMFSampleImage final : public Image {
ID3D11Texture2D* GetTexture() const; ID3D11Texture2D* GetTexture() const;
RefPtr<IMFSampleWrapper> GetIMFSampleWrapper(); RefPtr<IMFSampleWrapper> GetIMFSampleWrapper();
gfx::YUVColorSpace GetYUVColorSpace() const { return mYUVColorSpace; }
gfx::ColorRange GetColorRange() const { return mColorRange; } gfx::ColorRange GetColorRange() const { return mColorRange; }
private: private:
@@ -89,15 +90,11 @@ class D3D11TextureIMFSampleImage final : public Image {
// IMFTransform. // IMFTransform.
RefPtr<IMFSampleWrapper> mVideoSample; RefPtr<IMFSampleWrapper> mVideoSample;
RefPtr<ID3D11Texture2D> mTexture; RefPtr<ID3D11Texture2D> mTexture;
public:
const uint32_t mArrayIndex; const uint32_t mArrayIndex;
const gfx::IntSize mSize; const gfx::IntSize mSize;
const gfx::IntRect mPictureRect; const gfx::IntRect mPictureRect;
const gfx::ColorSpace2 mColorSpace; const gfx::YUVColorSpace mYUVColorSpace;
const gfx::ColorRange mColorRange; const gfx::ColorRange mColorRange;
private:
RefPtr<TextureClient> mTextureClient; RefPtr<TextureClient> mTextureClient;
}; };

View File

@@ -80,10 +80,10 @@ already_AddRefed<IDirect3DSurface9> DXGID3D9TextureData::GetD3D9Surface()
} }
bool DXGID3D9TextureData::Serialize(SurfaceDescriptor& aOutDescriptor) { bool DXGID3D9TextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
SurfaceDescriptorD3D10 desc((WindowsHandle)(mHandle), SurfaceDescriptorD3D10 desc(
/* gpuProcessTextureId */ Nothing(), (WindowsHandle)(mHandle), /* gpuProcessTextureId */ Nothing(),
/* arrayIndex */ 0, mFormat, GetSize(), /* arrayIndex */ 0, mFormat, GetSize(), gfx::YUVColorSpace::Identity,
gfx::ColorSpace2::SRGB, gfx::ColorRange::FULL); gfx::ColorRange::FULL);
// In reality, with D3D9 we will only ever deal with RGBA textures. // In reality, with D3D9 we will only ever deal with RGBA textures.
bool isYUV = mFormat == gfx::SurfaceFormat::NV12 || bool isYUV = mFormat == gfx::SurfaceFormat::NV12 ||
mFormat == gfx::SurfaceFormat::P010 || mFormat == gfx::SurfaceFormat::P010 ||
@@ -91,7 +91,7 @@ bool DXGID3D9TextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
if (isYUV) { if (isYUV) {
gfxCriticalError() << "Unexpected YUV format for DXGID3D9TextureData: " gfxCriticalError() << "Unexpected YUV format for DXGID3D9TextureData: "
<< mFormat; << mFormat;
desc.colorSpace() = gfx::ColorSpace2::BT601_525; desc.yUVColorSpace() = gfx::YUVColorSpace::BT601;
desc.colorRange() = gfx::ColorRange::LIMITED; desc.colorRange() = gfx::ColorRange::LIMITED;
} }
aOutDescriptor = desc; aOutDescriptor = desc;

View File

@@ -8,7 +8,6 @@
#define mozilla_gfx_layers_d3d11_HelpersD3D11_h #define mozilla_gfx_layers_d3d11_HelpersD3D11_h
#include <d3d11.h> #include <d3d11.h>
#include <array>
#include "mozilla/Telemetry.h" #include "mozilla/Telemetry.h"
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
@@ -51,16 +50,6 @@ static inline bool WaitForFrameGPUQuery(ID3D11Device* aDevice,
return success; return success;
} }
inline void ClearResource(ID3D11Device* const device, ID3D11Resource* const res,
const std::array<float, 4>& vals) {
RefPtr<ID3D11RenderTargetView> rtv;
(void)device->CreateRenderTargetView(res, nullptr, getter_AddRefs(rtv));
RefPtr<ID3D11DeviceContext> context;
device->GetImmediateContext(getter_AddRefs(context));
context->ClearRenderTargetView(rtv, vals.data());
}
} // namespace layers } // namespace layers
} // namespace mozilla } // namespace mozilla

View File

@@ -402,7 +402,7 @@ bool D3D11TextureData::SerializeSpecific(
} }
*aOutDesc = SurfaceDescriptorD3D10((WindowsHandle)sharedHandle, *aOutDesc = SurfaceDescriptorD3D10((WindowsHandle)sharedHandle,
mGpuProcessTextureId, mArrayIndex, mFormat, mGpuProcessTextureId, mArrayIndex, mFormat,
mSize, mColorSpace, mColorRange); mSize, mYUVColorSpace, mColorRange);
return true; return true;
} }
@@ -425,13 +425,13 @@ void D3D11TextureData::GetSubDescriptor(
/* static */ /* static */
already_AddRefed<TextureClient> D3D11TextureData::CreateTextureClient( already_AddRefed<TextureClient> D3D11TextureData::CreateTextureClient(
ID3D11Texture2D* aTexture, uint32_t aIndex, gfx::IntSize aSize, ID3D11Texture2D* aTexture, uint32_t aIndex, gfx::IntSize aSize,
gfx::SurfaceFormat aFormat, gfx::ColorSpace2 aColorSpace, gfx::SurfaceFormat aFormat, gfx::YUVColorSpace aColorSpace,
gfx::ColorRange aColorRange, KnowsCompositor* aKnowsCompositor, gfx::ColorRange aColorRange, KnowsCompositor* aKnowsCompositor,
RefPtr<IMFSampleUsageInfo> aUsageInfo) { RefPtr<IMFSampleUsageInfo> aUsageInfo) {
D3D11TextureData* data = new D3D11TextureData( D3D11TextureData* data = new D3D11TextureData(
aTexture, aIndex, aSize, aFormat, aTexture, aIndex, aSize, aFormat,
TextureAllocationFlags::ALLOC_MANUAL_SYNCHRONIZATION); TextureAllocationFlags::ALLOC_MANUAL_SYNCHRONIZATION);
data->mColorSpace = aColorSpace; data->SetYUVColorSpace(aColorSpace);
data->SetColorRange(aColorRange); data->SetColorRange(aColorRange);
RefPtr<TextureClient> textureClient = MakeAndAddRef<TextureClient>( RefPtr<TextureClient> textureClient = MakeAndAddRef<TextureClient>(
@@ -812,7 +812,7 @@ DXGITextureHostD3D11::DXGITextureHostD3D11(
mSize(aDescriptor.size()), mSize(aDescriptor.size()),
mHandle(aDescriptor.handle()), mHandle(aDescriptor.handle()),
mFormat(aDescriptor.format()), mFormat(aDescriptor.format()),
mColorSpace(aDescriptor.colorSpace()), mYUVColorSpace(aDescriptor.yUVColorSpace()),
mColorRange(aDescriptor.colorRange()), mColorRange(aDescriptor.colorRange()),
mIsLocked(false) {} mIsLocked(false) {}
@@ -963,9 +963,9 @@ void DXGITextureHostD3D11::UnlockInternal() {
void DXGITextureHostD3D11::CreateRenderTexture( void DXGITextureHostD3D11::CreateRenderTexture(
const wr::ExternalImageId& aExternalImageId) { const wr::ExternalImageId& aExternalImageId) {
RefPtr<wr::RenderTextureHost> texture = RefPtr<wr::RenderTextureHost> texture = new wr::RenderDXGITextureHost(
new wr::RenderDXGITextureHost(mHandle, mGpuProcessTextureId, mArrayIndex, mHandle, mGpuProcessTextureId, mArrayIndex, mFormat, mYUVColorSpace,
mFormat, mColorSpace, mColorRange, mSize); mColorRange, mSize);
wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId, wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId,
texture.forget()); texture.forget());
} }
@@ -1092,7 +1092,7 @@ void DXGITextureHostD3D11::PushDisplayItems(
aBounds, aClip, true, aImageKeys[0], aImageKeys[1], aBounds, aClip, true, aImageKeys[0], aImageKeys[1],
GetFormat() == gfx::SurfaceFormat::NV12 ? wr::ColorDepth::Color8 GetFormat() == gfx::SurfaceFormat::NV12 ? wr::ColorDepth::Color8
: wr::ColorDepth::Color16, : wr::ColorDepth::Color16,
wr::ToWrYuvColorSpace(ToYUVColorSpace(mColorSpace)), wr::ToWrYuvColorSpace(mYUVColorSpace),
wr::ToWrColorRange(mColorRange), aFilter, preferCompositorSurface, wr::ToWrColorRange(mColorRange), aFilter, preferCompositorSurface,
SupportsExternalCompositing(aBuilder.GetBackendType())); SupportsExternalCompositing(aBuilder.GetBackendType()));
break; break;
@@ -1109,7 +1109,8 @@ bool DXGITextureHostD3D11::SupportsExternalCompositing(
return true; return true;
} }
// XXX Add P010 and P016 support. // XXX Add P010 and P016 support.
if (gfx::gfxVars::UseWebRenderDCompVideoOverlayWin()) { if (GetFormat() == gfx::SurfaceFormat::NV12 &&
gfx::gfxVars::UseWebRenderDCompVideoOverlayWin()) {
return true; return true;
} }
return false; return false;

View File

@@ -60,7 +60,7 @@ class D3D11TextureData final : public TextureData {
static already_AddRefed<TextureClient> CreateTextureClient( static already_AddRefed<TextureClient> CreateTextureClient(
ID3D11Texture2D* aTexture, uint32_t aIndex, gfx::IntSize aSize, ID3D11Texture2D* aTexture, uint32_t aIndex, gfx::IntSize aSize,
gfx::SurfaceFormat aFormat, gfx::ColorSpace2 aColorSpace, gfx::SurfaceFormat aFormat, gfx::YUVColorSpace aColorSpace,
gfx::ColorRange aColorRange, KnowsCompositor* aKnowsCompositor, gfx::ColorRange aColorRange, KnowsCompositor* aKnowsCompositor,
RefPtr<IMFSampleUsageInfo> aUsageInfo); RefPtr<IMFSampleUsageInfo> aUsageInfo);
@@ -95,6 +95,10 @@ class D3D11TextureData final : public TextureData {
bool Serialize(SurfaceDescriptor& aOutDescrptor) override; bool Serialize(SurfaceDescriptor& aOutDescrptor) override;
void GetSubDescriptor(RemoteDecoderVideoSubDescriptor* aOutDesc) override; void GetSubDescriptor(RemoteDecoderVideoSubDescriptor* aOutDesc) override;
gfx::YUVColorSpace GetYUVColorSpace() const { return mYUVColorSpace; }
void SetYUVColorSpace(gfx::YUVColorSpace aColorSpace) {
mYUVColorSpace = aColorSpace;
}
gfx::ColorRange GetColorRange() const { return mColorRange; } gfx::ColorRange GetColorRange() const { return mColorRange; }
void SetColorRange(gfx::ColorRange aColorRange) { mColorRange = aColorRange; } void SetColorRange(gfx::ColorRange aColorRange) { mColorRange = aColorRange; }
@@ -132,11 +136,7 @@ class D3D11TextureData final : public TextureData {
RefPtr<gfx::DrawTarget> mDrawTarget; RefPtr<gfx::DrawTarget> mDrawTarget;
const gfx::IntSize mSize; const gfx::IntSize mSize;
const gfx::SurfaceFormat mFormat; const gfx::SurfaceFormat mFormat;
gfx::YUVColorSpace mYUVColorSpace = gfx::YUVColorSpace::Identity;
public:
gfx::ColorSpace2 mColorSpace = gfx::ColorSpace2::SRGB;
private:
gfx::ColorRange mColorRange = gfx::ColorRange::LIMITED; gfx::ColorRange mColorRange = gfx::ColorRange::LIMITED;
bool mNeedsClear = false; bool mNeedsClear = false;
const bool mHasSynchronization; const bool mHasSynchronization;
@@ -349,6 +349,9 @@ class DXGITextureHostD3D11 : public TextureHost {
void UnlockWithoutCompositor() override; void UnlockWithoutCompositor() override;
gfx::IntSize GetSize() const override { return mSize; } gfx::IntSize GetSize() const override { return mSize; }
gfx::YUVColorSpace GetYUVColorSpace() const override {
return mYUVColorSpace;
}
gfx::ColorRange GetColorRange() const override { return mColorRange; } gfx::ColorRange GetColorRange() const override { return mColorRange; }
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override; already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
@@ -389,11 +392,7 @@ class DXGITextureHostD3D11 : public TextureHost {
gfx::IntSize mSize; gfx::IntSize mSize;
WindowsHandle mHandle; WindowsHandle mHandle;
gfx::SurfaceFormat mFormat; gfx::SurfaceFormat mFormat;
const gfx::YUVColorSpace mYUVColorSpace;
public:
const gfx::ColorSpace2 mColorSpace;
protected:
const gfx::ColorRange mColorRange; const gfx::ColorRange mColorRange;
bool mIsLocked; bool mIsLocked;
}; };

View File

@@ -34,7 +34,7 @@ namespace layers {
uint32_t arrayIndex; uint32_t arrayIndex;
SurfaceFormat format; SurfaceFormat format;
IntSize size; IntSize size;
ColorSpace2 colorSpace; YUVColorSpace yUVColorSpace;
ColorRange colorRange; ColorRange colorRange;
}; };

View File

@@ -24,7 +24,6 @@
#include "mozilla/gfx/CanvasManagerParent.h" #include "mozilla/gfx/CanvasManagerParent.h"
#include "mozilla/gfx/CanvasRenderThread.h" #include "mozilla/gfx/CanvasRenderThread.h"
#include "mozilla/ClearOnShutdown.h" #include "mozilla/ClearOnShutdown.h"
#include "mozilla/EnumTypeTraits.h"
#include "mozilla/StaticPrefs_accessibility.h" #include "mozilla/StaticPrefs_accessibility.h"
#include "mozilla/StaticPrefs_apz.h" #include "mozilla/StaticPrefs_apz.h"
#include "mozilla/StaticPrefs_bidi.h" #include "mozilla/StaticPrefs_bidi.h"
@@ -2022,14 +2021,6 @@ const mozilla::gfx::ContentDeviceData* gfxPlatform::GetInitContentDeviceData() {
return gContentDeviceInitData; return gContentDeviceInitData;
} }
CMSMode GfxColorManagementMode() {
const auto mode = StaticPrefs::gfx_color_management_mode();
if (mode >= 0 && mode < UnderlyingValue(CMSMode::AllCount)) {
return CMSMode(mode);
}
return CMSMode::Off;
}
void gfxPlatform::InitializeCMS() { void gfxPlatform::InitializeCMS() {
if (gCMSInitialized) { if (gCMSInitialized) {
return; return;
@@ -2048,7 +2039,12 @@ void gfxPlatform::InitializeCMS() {
return; return;
} }
gCMSMode = GfxColorManagementMode(); {
int32_t mode = StaticPrefs::gfx_color_management_mode();
if (mode >= 0 && mode < int32_t(CMSMode::AllCount)) {
gCMSMode = CMSMode(mode);
}
}
gCMSsRGBProfile = qcms_profile_sRGB(); gCMSsRGBProfile = qcms_profile_sRGB();

View File

@@ -1027,6 +1027,4 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener {
const gfxSkipChars kEmptySkipChars; const gfxSkipChars kEmptySkipChars;
}; };
CMSMode GfxColorManagementMode();
#endif /* GFX_PLATFORM_H */ #endif /* GFX_PLATFORM_H */

File diff suppressed because it is too large Load Diff

View File

@@ -7,14 +7,11 @@
#ifndef MOZILLA_GFX_DCLAYER_TREE_H #ifndef MOZILLA_GFX_DCLAYER_TREE_H
#define MOZILLA_GFX_DCLAYER_TREE_H #define MOZILLA_GFX_DCLAYER_TREE_H
#include "WinUtils.h"
#include <DXGIType.h>
#include <dxgiformat.h> #include <dxgiformat.h>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <windows.h> #include <windows.h>
#include "Colorspaces.h"
#include "GLTypes.h" #include "GLTypes.h"
#include "mozilla/HashFunctions.h" #include "mozilla/HashFunctions.h"
#include "mozilla/layers/OverlayInfo.h" #include "mozilla/layers/OverlayInfo.h"
@@ -37,14 +34,12 @@ struct IDCompositionVisual2;
struct IDXGIDecodeSwapChain; struct IDXGIDecodeSwapChain;
struct IDXGIResource; struct IDXGIResource;
struct IDXGISwapChain1; struct IDXGISwapChain1;
struct IDXGISwapChain3;
struct IDCompositionVirtualSurface; struct IDCompositionVirtualSurface;
namespace mozilla { namespace mozilla {
namespace gl { namespace gl {
class GLContext; class GLContext;
class Texture;
} }
namespace wr { namespace wr {
@@ -55,9 +50,8 @@ namespace wr {
class DCTile; class DCTile;
class DCSurface; class DCSurface;
class DCSurfaceSwapChain; class DCSurfaceVideo;
class RenderTextureHost; class RenderTextureHost;
class RenderDXGITextureHost;
struct GpuOverlayInfo { struct GpuOverlayInfo {
bool mSupportsOverlays = false; bool mSupportsOverlays = false;
@@ -125,7 +119,7 @@ class DCLayerTree {
ID3D11VideoProcessorEnumerator* GetVideoProcessorEnumerator() const { ID3D11VideoProcessorEnumerator* GetVideoProcessorEnumerator() const {
return mVideoProcessorEnumerator; return mVideoProcessorEnumerator;
} }
bool EnsureVideoProcessorAtLeast(const gfx::IntSize& aInputSize, bool EnsureVideoProcessor(const gfx::IntSize& aInputSize,
const gfx::IntSize& aOutputSize); const gfx::IntSize& aOutputSize);
DCSurface* GetSurface(wr::NativeSurfaceId aId) const; DCSurface* GetSurface(wr::NativeSurfaceId aId) const;
@@ -253,7 +247,7 @@ class DCSurface {
void UpdateAllocatedRect(); void UpdateAllocatedRect();
void DirtyAllocatedRect(); void DirtyAllocatedRect();
virtual DCSurfaceSwapChain* AsDCSurfaceSwapChain() { return nullptr; } virtual DCSurfaceVideo* AsDCSurfaceVideo() { return nullptr; }
protected: protected:
DCLayerTree* mDCLayerTree; DCLayerTree* mDCLayerTree;
@@ -278,87 +272,33 @@ class DCSurface {
RefPtr<IDCompositionVirtualSurface> mVirtualSurface; RefPtr<IDCompositionVirtualSurface> mVirtualSurface;
}; };
struct RaiiHANDLE final { class DCSurfaceVideo : public DCSurface {
const HANDLE val;
explicit RaiiHANDLE(HANDLE val) : val(val) {}
operator HANDLE() const { return val; }
~RaiiHANDLE() {
if (val) {
::CloseHandle(val);
}
}
};
struct CspaceAndRange final {
gfx::ColorSpace2 space;
Maybe<gfx::ColorRange> yuvRange;
auto Members() const { return std::tie(space, yuvRange); }
INLINE_DERIVE_MEMBERS_EQ(CspaceAndRange);
};
struct CspaceTransformPlan final {
struct WithVideoProcessor final {
DXGI_COLOR_SPACE_TYPE srcSpace;
Maybe<DXGI_COLOR_SPACE_TYPE> dstYuvSpace;
DXGI_COLOR_SPACE_TYPE dstRgbSpace;
};
struct WithGLBlitHelper final {
color::ColorspaceDesc srcSpace;
color::ColorspaceDesc dstSpace;
DXGI_COLOR_SPACE_TYPE dstDxgiSpace;
DXGI_FORMAT dstDxgiFormat;
};
Maybe<WithVideoProcessor> videoProcessor;
Maybe<WithGLBlitHelper> blitHelper;
};
class DCSurfaceSwapChain : public DCSurface {
public: public:
DCSurfaceSwapChain(bool aIsOpaque, DCLayerTree* aDCLayerTree); DCSurfaceVideo(bool aIsOpaque, DCLayerTree* aDCLayerTree);
void AttachExternalImage(wr::ExternalImageId aExternalImage); void AttachExternalImage(wr::ExternalImageId aExternalImage);
Maybe<gfx::Matrix> EnsurePresented(const gfx::Matrix&); bool CalculateSwapChainSize(gfx::Matrix& aTransform);
void PresentVideo();
DCSurfaceSwapChain* AsDCSurfaceSwapChain() override { return this; } DCSurfaceVideo* AsDCSurfaceVideo() override { return this; }
struct Src final {
RefPtr<RenderDXGITextureHost> texture;
gfx::IntSize size;
gfx::SurfaceFormat format;
CspaceAndRange space;
// When RenderTextureHost, swapChainSize or VideoSwapChain are updated,
// then DCSurfaceSwapChain::Present() needs to be called.
bool needsPresent = true;
};
struct Dest final {
RefPtr<IDXGISwapChain3> swapChain; // Destination
UniquePtr<RaiiHANDLE> swapChainSurfaceHandle;
gfx::IntSize size;
DXGI_FORMAT format;
DXGI_COLOR_SPACE_TYPE space;
};
struct PlanAndDest final {
CspaceAndRange srcSpace;
CspaceTransformPlan plan;
Maybe<Dest> dest;
mutable std::shared_ptr<gl::Texture> lut;
bool needsPresent = true;
};
protected: protected:
bool CallVideoProcessorBlt() const; DXGI_FORMAT GetSwapChainFormat();
bool CallBlitHelper() const; bool CreateVideoSwapChain();
bool CallVideoProcessorBlt();
void ReleaseDecodeSwapChainResources();
// - RefPtr<ID3D11VideoProcessorOutputView> mOutputView;
RefPtr<IDXGIResource> mDecodeResource;
Maybe<DXGI_FORMAT> mOverlayFormat; RefPtr<IDXGISwapChain1> mVideoSwapChain;
Maybe<Src> mSrc; RefPtr<IDXGIDecodeSwapChain> mDecodeSwapChain;
Maybe<PlanAndDest> mDest; HANDLE mSwapChainSurfaceHandle = 0;
gfx::IntSize mVideoSize;
gfx::IntSize mSwapChainSize;
DXGI_FORMAT mSwapChainFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
bool mFailedYuvSwapChain = false;
RefPtr<RenderTextureHost> mRenderTextureHost;
RefPtr<RenderTextureHost> mPrevTexture;
}; };
class DCTile { class DCTile {

View File

@@ -20,7 +20,7 @@ namespace wr {
RenderDXGITextureHost::RenderDXGITextureHost( RenderDXGITextureHost::RenderDXGITextureHost(
WindowsHandle aHandle, Maybe<uint64_t>& aGpuProcessTextureId, WindowsHandle aHandle, Maybe<uint64_t>& aGpuProcessTextureId,
uint32_t aArrayIndex, gfx::SurfaceFormat aFormat, uint32_t aArrayIndex, gfx::SurfaceFormat aFormat,
gfx::ColorSpace2 aColorSpace, gfx::ColorRange aColorRange, gfx::YUVColorSpace aYUVColorSpace, gfx::ColorRange aColorRange,
gfx::IntSize aSize) gfx::IntSize aSize)
: mHandle(aHandle), : mHandle(aHandle),
mGpuProcessTextureId(aGpuProcessTextureId), mGpuProcessTextureId(aGpuProcessTextureId),
@@ -29,7 +29,7 @@ RenderDXGITextureHost::RenderDXGITextureHost(
mStream(0), mStream(0),
mTextureHandle{0}, mTextureHandle{0},
mFormat(aFormat), mFormat(aFormat),
mColorSpace(aColorSpace), mYUVColorSpace(aYUVColorSpace),
mColorRange(aColorRange), mColorRange(aColorRange),
mSize(aSize), mSize(aSize),
mLocked(false) { mLocked(false) {

View File

@@ -22,8 +22,8 @@ class RenderDXGITextureHost final : public RenderTextureHostSWGL {
RenderDXGITextureHost(WindowsHandle aHandle, RenderDXGITextureHost(WindowsHandle aHandle,
Maybe<uint64_t>& aGpuProcessTextureId, Maybe<uint64_t>& aGpuProcessTextureId,
uint32_t aArrayIndex, gfx::SurfaceFormat aFormat, uint32_t aArrayIndex, gfx::SurfaceFormat aFormat,
gfx::ColorSpace2, gfx::ColorRange aColorRange, gfx::YUVColorSpace aYUVColorSpace,
gfx::IntSize aSize); gfx::ColorRange aColorRange, gfx::IntSize aSize);
wr::WrExternalImage Lock(uint8_t aChannelIndex, gl::GLContext* aGL, wr::WrExternalImage Lock(uint8_t aChannelIndex, gl::GLContext* aGL,
wr::ImageRendering aRendering) override; wr::ImageRendering aRendering) override;
@@ -58,7 +58,7 @@ class RenderDXGITextureHost final : public RenderTextureHostSWGL {
PlaneInfo& aPlaneInfo) override; PlaneInfo& aPlaneInfo) override;
void UnmapPlanes() override; void UnmapPlanes() override;
gfx::YUVRangedColorSpace GetYUVColorSpace() const override { gfx::YUVRangedColorSpace GetYUVColorSpace() const override {
return ToYUVRangedColorSpace(ToYUVColorSpace(mColorSpace), mColorRange); return ToYUVRangedColorSpace(mYUVColorSpace, GetColorRange());
} }
bool EnsureD3D11Texture2D(ID3D11Device* aDevice); bool EnsureD3D11Texture2D(ID3D11Device* aDevice);
@@ -108,13 +108,11 @@ class RenderDXGITextureHost final : public RenderTextureHostSWGL {
// handles for Y and CbCr data. // handles for Y and CbCr data.
GLuint mTextureHandle[2]; GLuint mTextureHandle[2];
public:
const gfx::SurfaceFormat mFormat; const gfx::SurfaceFormat mFormat;
const gfx::ColorSpace2 mColorSpace; const gfx::YUVColorSpace mYUVColorSpace;
const gfx::ColorRange mColorRange; const gfx::ColorRange mColorRange;
const gfx::IntSize mSize; const gfx::IntSize mSize;
private:
bool mLocked; bool mLocked;
}; };

View File

@@ -5235,37 +5235,6 @@
value: false value: false
mirror: once mirror: once
- name: gfx.blithelper.precision
type: RelaxedAtomicUint32
value: 2 # { 0: lowp, 1: mediump, 2: highp }
mirror: always
- name: gfx.blithelper.lut-size.rgb.b
type: RelaxedAtomicUint32
value: 15
mirror: always
- name: gfx.blithelper.lut-size.rgb.g
type: RelaxedAtomicUint32
value: 31
mirror: always
- name: gfx.blithelper.lut-size.rgb.r
type: RelaxedAtomicUint32
value: 31
mirror: always
- name: gfx.blithelper.lut-size.ycbcr.cb
type: RelaxedAtomicUint32
value: 15
mirror: always
- name: gfx.blithelper.lut-size.ycbcr.cr
type: RelaxedAtomicUint32
value: 31
mirror: always
- name: gfx.blithelper.lut-size.ycbcr.y
type: RelaxedAtomicUint32
value: 31
mirror: always
# Nb: we ignore this pref on release and beta. # Nb: we ignore this pref on release and beta.
- name: gfx.blocklist.all - name: gfx.blocklist.all
type: int32_t type: int32_t