Merge Mozilla-Central to autoland on a CLOSED TREE
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -
|
// -
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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_
|
|
||||||
@@ -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,35 +443,28 @@ 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->colorSpace);
|
||||||
gfxUtils::YuvToRgbMatrix4x4ColumnMajor(*argsYUV->colorSpaceForMatrix);
|
float mat4x3[4 * 3];
|
||||||
float mat4x3[4 * 3];
|
switch (mType_uColorMatrix) {
|
||||||
switch (mType_uColorMatrix) {
|
case LOCAL_GL_FLOAT_MAT4:
|
||||||
case LOCAL_GL_FLOAT_MAT4:
|
gl->fUniformMatrix4fv(mLoc_uColorMatrix, 1, false, colorMatrix);
|
||||||
gl->fUniformMatrix4fv(mLoc_uColorMatrix, 1, false, colorMatrix);
|
break;
|
||||||
break;
|
case LOCAL_GL_FLOAT_MAT4x3:
|
||||||
case LOCAL_GL_FLOAT_MAT4x3:
|
for (int x = 0; x < 4; x++) {
|
||||||
for (int x = 0; x < 4; x++) {
|
for (int y = 0; y < 3; y++) {
|
||||||
for (int y = 0; y < 3; y++) {
|
mat4x3[3 * x + y] = colorMatrix[4 * x + y];
|
||||||
mat4x3[3 * x + y] = colorMatrix[4 * x + y];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
gl->fUniformMatrix4x3fv(mLoc_uColorMatrix, 1, false, mat4x3);
|
}
|
||||||
break;
|
gl->fUniformMatrix4x3fv(mLoc_uColorMatrix, 1, false, mat4x3);
|
||||||
default:
|
break;
|
||||||
gfxCriticalError()
|
default:
|
||||||
<< "Bad mType_uColorMatrix: " << gfx::hexa(mType_uColorMatrix);
|
gfxCriticalError() << "Bad 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
|
mDrawBlitProg_VersionLine = nsCString("#version 100\n");
|
||||||
// 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");
|
|
||||||
}
|
|
||||||
} 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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
@@ -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"
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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,8 +119,8 @@ 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 {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user