Bug 1799258 - Do color-management on Windows+DComp via IDCompositionFilterEffects. r=sotaro

+ Add gfx.color_management.rec709_gamma_as_srgb:true. :'(

In particular, rec709(16/255) -> srgb(31/255). Even though it's
technically correct, it's practically-speaking incorrect, since that's
not what Chrome does, nor what the web expected for years and years.

In practice, basically everyone expects gamma to just be completely
ignored.

What people expect:
* Pretend gamut is srgb(==rec709), but stretch this naively for the
  display. If you have a display-p3-gamut display, srgb:0.5 expects to
  be displayed as display:0.5, which will be display-p3:0.5 to the eyes.
* Pretend all content gammas (TFs) are srgb(!=rec790), and then bitcast this
  naively for the display. E.g. rec709(16/255) should
  display the same as srgb(16/255), not srgb(31/255). (Note: display-p3
  uses srgb gamma) But if your display has e.g. gamma=3.0, don't
  convert or compensate.

This is a formalization of what you get when you spend decades ignoring
color management, and people build things based on behavior-in-practice,
not behavior-in-theory.

Also:
+ gfx.color_management.native_srgb:true for Windows, so we don't use the
  display color profile, which no one else does.
+ Add rec2020_gamma_as_rec709, so we have a path towards maybe having
  rec2020 use its correct transfer function, rather than srgb (like
  rec709).

Differential Revision: https://phabricator.services.mozilla.com/D161857
This commit is contained in:
Kelsey Gilbert 2023-03-13 21:04:10 +00:00
parent 000ff9b4e5
commit 2a633b2502
10 changed files with 325 additions and 30 deletions

View File

@ -17,7 +17,7 @@ defaults pref(media.av1.enabled,true)
fuzzy(16-51,5234-5622) fuzzy-if(swgl,32-38,1600-91746) fuzzy-if(useDrawSnapshot,16-16,11600-11600) fuzzy-if(OSX,16-73,5212-5622) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm ../reftest_img.html?src=color_quads/720p.png fuzzy(16-51,5234-5622) fuzzy-if(swgl,32-38,1600-91746) fuzzy-if(useDrawSnapshot,16-16,11600-11600) fuzzy-if(OSX,16-73,5212-5622) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm ../reftest_img.html?src=color_quads/720p.png
fuzzy-if(winWidget&&swgl,0-20,0-5620) fuzzy-if(winWidget&&!swgl,0-1,0-78) fuzzy-if(Android,254-255,273680-273807) fuzzy-if(OSX,0-35,0-1947) fuzzy-if(OSX&&swgl,0-67,0-5451) fuzzy-if(appleSilicon,30-48,1760-187409) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.vp9.webm ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm fuzzy-if(winWidget&&swgl,0-20,0-5620) fuzzy-if(winWidget&&!swgl,0-1,0-78) fuzzy-if(Android,254-255,273680-273807) fuzzy-if(OSX,0-35,0-1947) fuzzy-if(OSX&&swgl,0-67,0-5451) fuzzy-if(appleSilicon,30-48,1760-187409) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.vp9.webm ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm
fuzzy-if(winWidget,0-1,0-78) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.mp4 ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm fuzzy-if(winWidget,0-1,0-78) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.mp4 ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm
skip-if(winWidget&&isCoverageBuild) fuzzy(0-16,75-1861) fuzzy-if(Android,254-255,273680-273807) fuzzy-if(OSX,30-32,187326-187407) fuzzy-if(appleSilicon,30-48,1835-187409) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.h264.mp4 ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm skip-if(winWidget&&isCoverageBuild) fuzzy(0-16,75-1941) fuzzy-if(Android,254-255,273680-273807) fuzzy-if(OSX,30-32,187326-187407) fuzzy-if(appleSilicon,30-48,1835-187409) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.h264.mp4 ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm
fuzzy-if(winWidget&&swgl,0-20,0-5620) fuzzy-if(winWidget&&!swgl,0-1,0-78) fuzzy-if(Android,254-255,273680-273807) fuzzy-if(OSX,0-35,0-1947) fuzzy-if(OSX&&swgl,0-67,0-5451) fuzzy-if(appleSilicon,30-48,1760-187409) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.vp9.mp4 ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm fuzzy-if(winWidget&&swgl,0-20,0-5620) fuzzy-if(winWidget&&!swgl,0-1,0-78) fuzzy-if(Android,254-255,273680-273807) fuzzy-if(OSX,0-35,0-1947) fuzzy-if(OSX&&swgl,0-67,0-5451) fuzzy-if(appleSilicon,30-48,1760-187409) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.vp9.mp4 ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.tv.yuv420p.av1.webm
skip-if(Android) fuzzy(16-48,8107-8818) fuzzy-if(winWidget&&swgl,31-38,8240-184080) fuzzy-if(appleSilicon,33-38,8819-11705) fuzzy-if(useDrawSnapshot,20-20,187200-187200) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.pc.yuv420p.av1.webm ../reftest_img.html?src=color_quads/720p.png skip-if(Android) fuzzy(16-48,8107-8818) fuzzy-if(winWidget&&swgl,31-38,8240-184080) fuzzy-if(appleSilicon,33-38,8819-11705) fuzzy-if(useDrawSnapshot,20-20,187200-187200) == ../reftest_video.html?src=color_quads/720p.png.bt709.bt709.pc.yuv420p.av1.webm ../reftest_img.html?src=color_quads/720p.png

View File

@ -30,6 +30,10 @@
#undef NTDDI_VERSION #undef NTDDI_VERSION
#define NTDDI_VERSION NTDDI_WINBLUE #define NTDDI_VERSION NTDDI_WINBLUE
// We also need this, or dcomp.h won't give us e.g. IDCompositionDevice3:
#undef _WIN32_WINNT_WINTHRESHOLD
#define _WIN32_WINNT_WINTHRESHOLD _WIN32_WINNT
#include <d3d11.h> #include <d3d11.h>
#include <dcomp.h> #include <dcomp.h>
#include <ddraw.h> #include <ddraw.h>
@ -50,6 +54,7 @@ decltype(D3D11CreateDevice)* sD3D11CreateDeviceFn = nullptr;
// It should only be used within CreateDirectCompositionDevice. // It should only be used within CreateDirectCompositionDevice.
decltype(DCompositionCreateDevice2)* sDcompCreateDevice2Fn = nullptr; decltype(DCompositionCreateDevice2)* sDcompCreateDevice2Fn = nullptr;
decltype(DCompositionCreateDevice3)* sDcompCreateDevice3Fn = nullptr;
// It should only be used within CreateDCompSurfaceHandle // It should only be used within CreateDCompSurfaceHandle
decltype(DCompositionCreateSurfaceHandle)* sDcompCreateSurfaceHandleFn = decltype(DCompositionCreateSurfaceHandle)* sDcompCreateSurfaceHandleFn =
@ -117,7 +122,7 @@ bool DeviceManagerDx::LoadDcomp() {
MOZ_ASSERT(gfxVars::UseWebRenderDCompWin()); MOZ_ASSERT(gfxVars::UseWebRenderDCompWin());
if (sDcompCreateDevice2Fn) { if (sDcompCreateDevice2Fn) {
return true; return true; // Already loaded.
} }
nsModuleHandle module(LoadLibrarySystem32(L"dcomp.dll")); nsModuleHandle module(LoadLibrarySystem32(L"dcomp.dll"));
@ -127,6 +132,8 @@ bool DeviceManagerDx::LoadDcomp() {
sDcompCreateDevice2Fn = (decltype(DCompositionCreateDevice2)*)GetProcAddress( sDcompCreateDevice2Fn = (decltype(DCompositionCreateDevice2)*)GetProcAddress(
module, "DCompositionCreateDevice2"); module, "DCompositionCreateDevice2");
sDcompCreateDevice3Fn = (decltype(DCompositionCreateDevice3)*)GetProcAddress(
module, "DCompositionCreateDevice3");
if (!sDcompCreateDevice2Fn) { if (!sDcompCreateDevice2Fn) {
return false; return false;
} }
@ -135,9 +142,6 @@ bool DeviceManagerDx::LoadDcomp() {
sDcompCreateSurfaceHandleFn = sDcompCreateSurfaceHandleFn =
(decltype(DCompositionCreateSurfaceHandle)*)::GetProcAddress( (decltype(DCompositionCreateSurfaceHandle)*)::GetProcAddress(
module, "DCompositionCreateSurfaceHandle"); module, "DCompositionCreateSurfaceHandle");
if (!sDcompCreateDevice2Fn) {
return false;
}
mDcompModule.steal(module); mDcompModule.steal(module);
return true; return true;
@ -448,10 +452,16 @@ void DeviceManagerDx::CreateDirectCompositionDeviceLocked() {
HRESULT hr; HRESULT hr;
RefPtr<IDCompositionDesktopDevice> desktopDevice; RefPtr<IDCompositionDesktopDevice> desktopDevice;
MOZ_SEH_TRY { MOZ_SEH_TRY {
hr = sDcompCreateDevice2Fn( hr = sDcompCreateDevice3Fn(
dxgiDevice.get(), dxgiDevice.get(),
IID_PPV_ARGS( IID_PPV_ARGS(
(IDCompositionDesktopDevice**)getter_AddRefs(desktopDevice))); (IDCompositionDesktopDevice**)getter_AddRefs(desktopDevice)));
if (!desktopDevice) {
hr = sDcompCreateDevice2Fn(
dxgiDevice.get(),
IID_PPV_ARGS(
(IDCompositionDesktopDevice**)getter_AddRefs(desktopDevice)));
}
} }
MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { return; } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { return; }

View File

@ -2037,15 +2037,10 @@ DeviceColor gfxPlatform::TransformPixel(const sRGBColor& in,
return DeviceColor(in.r, in.g, in.b, in.a); return DeviceColor(in.r, in.g, in.b, in.a);
} }
nsTArray<uint8_t> gfxPlatform::GetPlatformCMSOutputProfileData() {
return GetPrefCMSOutputProfileData();
}
nsTArray<uint8_t> gfxPlatform::GetPrefCMSOutputProfileData() { nsTArray<uint8_t> gfxPlatform::GetPrefCMSOutputProfileData() {
nsAutoCString fname; const auto mirror = StaticPrefs::gfx_color_management_display_profile();
Preferences::GetCString("gfx.color_management.display_profile", fname); const auto fname = *mirror;
if (fname == "") {
if (fname.IsEmpty()) {
return nsTArray<uint8_t>(); return nsTArray<uint8_t>();
} }

View File

@ -753,7 +753,9 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener {
* Returns a buffer containing the CMS output profile data. The way this * Returns a buffer containing the CMS output profile data. The way this
* is obtained is platform-specific. * is obtained is platform-specific.
*/ */
virtual nsTArray<uint8_t> GetPlatformCMSOutputProfileData(); virtual nsTArray<uint8_t> GetPlatformCMSOutputProfileData() {
return GetPrefCMSOutputProfileData();
}
/** /**
* Return information on how child processes should initialize graphics * Return information on how child processes should initialize graphics
@ -865,13 +867,15 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener {
virtual void ImportContentDeviceData( virtual void ImportContentDeviceData(
const mozilla::gfx::ContentDeviceData& aData); const mozilla::gfx::ContentDeviceData& aData);
public:
/** /**
* Returns the contents of the file pointed to by the * Returns the contents of the file pointed to by the
* gfx.color_management.display_profile pref, if set. * gfx.color_management.display_profile pref, if set.
* Returns an empty array if not set, or if an error occurs * Returns an empty array if not set, or if an error occurs
*/ */
nsTArray<uint8_t> GetPrefCMSOutputProfileData(); static nsTArray<uint8_t> GetPrefCMSOutputProfileData();
protected:
/** /**
* If inside a child process and currently being initialized by the * If inside a child process and currently being initialized by the
* SetXPCOMProcessAttributes message, this can be used by subclasses to * SetXPCOMProcessAttributes message, this can be used by subclasses to

View File

@ -1036,16 +1036,21 @@ nsTArray<uint8_t> gfxWindowsPlatform::GetPlatformCMSOutputProfileData() {
return result; return result;
} }
if (!mCachedOutputColorProfile.IsEmpty()) { return GetPlatformCMSOutputProfileData_Impl();
return mCachedOutputColorProfile.Clone(); }
}
mCachedOutputColorProfile = [&] { nsTArray<uint8_t> gfxWindowsPlatform::GetPlatformCMSOutputProfileData_Impl() {
nsTArray<uint8_t> prefProfileData = GetPrefCMSOutputProfileData(); static nsTArray<uint8_t> sCached = [&] {
// Check override pref first:
nsTArray<uint8_t> prefProfileData =
gfxPlatform::GetPrefCMSOutputProfileData();
if (!prefProfileData.IsEmpty()) { if (!prefProfileData.IsEmpty()) {
return prefProfileData; return prefProfileData;
} }
// -
// Otherwise, create a dummy DC and pull from that.
HDC dc = ::GetDC(nullptr); HDC dc = ::GetDC(nullptr);
if (!dc) { if (!dc) {
return nsTArray<uint8_t>(); return nsTArray<uint8_t>();
@ -1078,7 +1083,7 @@ nsTArray<uint8_t> gfxWindowsPlatform::GetPlatformCMSOutputProfileData() {
return result; return result;
}(); }();
return mCachedOutputColorProfile.Clone(); return sCached.Clone();
} }
void gfxWindowsPlatform::GetDLLVersion(char16ptr_t aDLLPath, void gfxWindowsPlatform::GetDLLVersion(char16ptr_t aDLLPath,

View File

@ -200,7 +200,13 @@ class gfxWindowsPlatform final : public gfxPlatform {
protected: protected:
bool AccelerateLayersByDefault() override { return true; } bool AccelerateLayersByDefault() override { return true; }
nsTArray<uint8_t> GetPlatformCMSOutputProfileData() override; nsTArray<uint8_t> GetPlatformCMSOutputProfileData() override;
public:
static nsTArray<uint8_t> GetPlatformCMSOutputProfileData_Impl();
protected:
void GetPlatformDisplayInfo(mozilla::widget::InfoObject& aObj) override; void GetPlatformDisplayInfo(mozilla::widget::InfoObject& aObj) override;
void ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData) override; void ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData) override;

View File

@ -6,6 +6,7 @@
#include "DCLayerTree.h" #include "DCLayerTree.h"
#include "gfxWindowsPlatform.h"
#include "GLContext.h" #include "GLContext.h"
#include "GLContextEGL.h" #include "GLContextEGL.h"
#include "mozilla/gfx/DeviceManagerDx.h" #include "mozilla/gfx/DeviceManagerDx.h"
@ -28,6 +29,10 @@
#undef NTDDI_VERSION #undef NTDDI_VERSION
#define NTDDI_VERSION NTDDI_WINBLUE #define NTDDI_VERSION NTDDI_WINBLUE
// We also need this, or dcomp.h won't give us e.g. IDCompositionFilterEffect:
#undef _WIN32_WINNT_WINTHRESHOLD
#define _WIN32_WINNT_WINTHRESHOLD _WIN32_WINNT
#include <d3d11.h> #include <d3d11.h>
#include <d3d11_1.h> #include <d3d11_1.h>
#include <dcomp.h> #include <dcomp.h>
@ -567,6 +572,16 @@ void DCExternalSurfaceWrapper::AttachExternalImage(
} }
} }
template <class ToT>
struct QI {
template <class FromT>
[[nodiscard]] static inline RefPtr<ToT> From(FromT* const from) {
RefPtr<ToT> to;
(void)from->QueryInterface(static_cast<ToT**>(getter_AddRefs(to)));
return to;
}
};
DCSurface* DCExternalSurfaceWrapper::EnsureSurfaceForExternalImage( DCSurface* DCExternalSurfaceWrapper::EnsureSurfaceForExternalImage(
wr::ExternalImageId aExternalImage) { wr::ExternalImageId aExternalImage) {
if (mSurface) { if (mSurface) {
@ -591,14 +606,117 @@ DCSurface* DCExternalSurfaceWrapper::EnsureSurfaceForExternalImage(
mSurface = nullptr; mSurface = nullptr;
} }
} }
if (!mSurface) {
if (mSurface) {
// Add surface's visual which will contain video data to our root visual.
mVisual->AddVisual(mSurface->GetVisual(), TRUE, nullptr);
} else {
gfxCriticalNote << "Failed to create a surface for external image: " gfxCriticalNote << "Failed to create a surface for external image: "
<< gfx::hexa(texture); << gfx::hexa(texture);
return nullptr;
} }
const auto textureSwgl = texture->AsRenderTextureHostSWGL();
MOZ_ASSERT(textureSwgl); // Covered above.
// Add surface's visual which will contain video data to our root visual.
const auto surfaceVisual = mSurface->GetVisual();
mVisual->AddVisual(surfaceVisual, true, nullptr);
// -
// Apply color management.
[&]() {
const auto cmsMode = GfxColorManagementMode();
if (cmsMode == CMSMode::Off) return;
const auto dcomp = mDCLayerTree->GetCompositionDevice();
const auto dcomp3 = QI<IDCompositionDevice3>::From(dcomp);
if (!dcomp3) {
NS_WARNING(
"No IDCompositionDevice3, cannot use dcomp for color management.");
return;
}
// -
const auto cspace = [&]() {
const auto rangedCspace = textureSwgl->GetYUVColorSpace();
const auto info = FromYUVRangedColorSpace(rangedCspace);
auto ret = ToColorSpace2(info.space);
if (ret == gfx::ColorSpace2::Display && cmsMode == CMSMode::All) {
ret = gfx::ColorSpace2::SRGB;
}
return ret;
}();
const bool rec709GammaAsSrgb =
StaticPrefs::gfx_color_management_rec709_gamma_as_srgb();
const bool rec2020GammaAsRec709 =
StaticPrefs::gfx_color_management_rec2020_gamma_as_rec709();
auto cspaceDesc = color::ColorspaceDesc{};
switch (cspace) {
case gfx::ColorSpace2::Display:
return; // No color management needed!
case gfx::ColorSpace2::SRGB:
cspaceDesc.chrom = color::Chromaticities::Srgb();
cspaceDesc.tf = color::PiecewiseGammaDesc::Srgb();
break;
case gfx::ColorSpace2::DISPLAY_P3:
cspaceDesc.chrom = color::Chromaticities::DisplayP3();
cspaceDesc.tf = color::PiecewiseGammaDesc::DisplayP3();
break;
case gfx::ColorSpace2::BT601_525:
cspaceDesc.chrom = color::Chromaticities::Rec601_525_Ntsc();
if (rec709GammaAsSrgb) {
cspaceDesc.tf = color::PiecewiseGammaDesc::Srgb();
} else {
cspaceDesc.tf = color::PiecewiseGammaDesc::Rec709();
}
break;
case gfx::ColorSpace2::BT709:
cspaceDesc.chrom = color::Chromaticities::Rec709();
if (rec709GammaAsSrgb) {
cspaceDesc.tf = color::PiecewiseGammaDesc::Srgb();
} else {
cspaceDesc.tf = color::PiecewiseGammaDesc::Rec709();
}
break;
case gfx::ColorSpace2::BT2020:
cspaceDesc.chrom = color::Chromaticities::Rec2020();
if (rec2020GammaAsRec709 && rec709GammaAsSrgb) {
cspaceDesc.tf = color::PiecewiseGammaDesc::Srgb();
} else if (rec2020GammaAsRec709) {
cspaceDesc.tf = color::PiecewiseGammaDesc::Rec709();
} else {
// Just Rec709 with slightly more precision.
cspaceDesc.tf = color::PiecewiseGammaDesc::Rec2020_12bit();
}
break;
}
const auto cprofileIn = color::ColorProfileDesc::From(cspaceDesc);
auto cprofileOut = mDCLayerTree->OutputColorProfile();
bool pretendSrgb = StaticPrefs::gfx_color_management_native_srgb();
if (pretendSrgb) {
cprofileOut = color::ColorProfileDesc::From({
color::Chromaticities::Srgb(),
color::PiecewiseGammaDesc::Srgb(),
});
}
const auto conversion = color::ColorProfileConversionDesc::From({
.src = cprofileIn,
.dst = cprofileOut,
});
// -
auto chain = ColorManagementChain::From(*dcomp3, conversion);
mCManageChain = Some(chain);
surfaceVisual->SetEffect(mCManageChain->last.get());
}();
return mSurface.get(); return mSurface.get();
} }
@ -1615,6 +1733,114 @@ void DCLayerTree::DestroyEGLSurface() {
} }
} }
// -
color::ColorProfileDesc DCLayerTree::QueryOutputColorProfile() {
// GPU process can't simply init gfxPlatform, (and we don't need most of it)
// but we do need gfxPlatform::GetCMSOutputProfile().
// So we steal what we need through the window:
const auto outputProfileData =
gfxWindowsPlatform::GetPlatformCMSOutputProfileData_Impl();
const auto qcmsProfile = qcms_profile_from_memory(
outputProfileData.Elements(), outputProfileData.Length());
MOZ_ASSERT(qcmsProfile);
const auto release =
MakeScopeExit([&]() { qcms_profile_release(qcmsProfile); });
const auto ret = color::ColorProfileDesc::From(*qcmsProfile);
bool print = gfxEnv::MOZ_GL_SPEW();
if (print) {
const auto gammaGuess = color::GuessGamma(ret.linearFromTf.r);
printf_stderr(
"Display profile:\n"
" Approx Gamma: %f\n"
" XYZ-D65 Red : %f, %f, %f\n"
" XYZ-D65 Green: %f, %f, %f\n"
" XYZ-D65 Blue : %f, %f, %f\n",
gammaGuess, ret.xyzd65FromLinearRgb.at(0, 0),
ret.xyzd65FromLinearRgb.at(0, 1), ret.xyzd65FromLinearRgb.at(0, 2),
ret.xyzd65FromLinearRgb.at(1, 0), ret.xyzd65FromLinearRgb.at(1, 1),
ret.xyzd65FromLinearRgb.at(1, 2),
ret.xyzd65FromLinearRgb.at(2, 0), ret.xyzd65FromLinearRgb.at(2, 1),
ret.xyzd65FromLinearRgb.at(2, 2));
}
return ret;
}
inline D2D1_MATRIX_5X4_F to_D2D1_MATRIX_5X4_F(const color::mat4& m) {
return D2D1_MATRIX_5X4_F{{{
m.rows[0][0],
m.rows[1][0],
m.rows[2][0],
m.rows[3][0],
m.rows[0][1],
m.rows[1][1],
m.rows[2][1],
m.rows[3][1],
m.rows[0][2],
m.rows[1][2],
m.rows[2][2],
m.rows[3][2],
m.rows[0][3],
m.rows[1][3],
m.rows[2][3],
m.rows[3][3],
0,
0,
0,
0,
}}};
}
ColorManagementChain ColorManagementChain::From(
IDCompositionDevice3& dcomp,
const color::ColorProfileConversionDesc& conv) {
auto ret = ColorManagementChain{};
const auto Append = [&](const RefPtr<IDCompositionFilterEffect>& afterLast) {
if (ret.last) {
afterLast->SetInput(0, ret.last, 0);
}
ret.last = afterLast;
};
const auto MaybeAppendColorMatrix = [&](const color::mat4& m) {
RefPtr<IDCompositionColorMatrixEffect> e;
if (approx(m, color::mat4::Identity())) return e;
dcomp.CreateColorMatrixEffect(getter_AddRefs(e));
MOZ_ASSERT(e);
if (!e) return e;
e->SetMatrix(to_D2D1_MATRIX_5X4_F(m));
Append(e);
return e;
};
const auto MaybeAppendTableTransfer = [&](const color::RgbTransferTables& t) {
RefPtr<IDCompositionTableTransferEffect> e;
if (!t.r.size() && !t.g.size() && !t.b.size()) return e;
dcomp.CreateTableTransferEffect(getter_AddRefs(e));
MOZ_ASSERT(e);
if (!e) return e;
e->SetRedTable(t.r.data(), t.r.size());
e->SetGreenTable(t.g.data(), t.g.size());
e->SetBlueTable(t.b.data(), t.b.size());
Append(e);
return e;
};
ret.srcRgbFromSrcYuv = MaybeAppendColorMatrix(conv.srcRgbFromSrcYuv);
ret.srcLinearFromSrcTf = MaybeAppendTableTransfer(conv.srcLinearFromSrcTf);
ret.dstLinearFromSrcLinear =
MaybeAppendColorMatrix(color::mat4(conv.dstLinearFromSrcLinear));
ret.dstTfFromDstLinear = MaybeAppendTableTransfer(conv.dstTfFromDstLinear);
return ret;
}
ColorManagementChain::~ColorManagementChain() = default;
} // namespace wr } // namespace wr
} // namespace mozilla } // namespace mozilla

View File

@ -12,6 +12,7 @@
#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"
@ -27,7 +28,11 @@ struct ID3D11VideoContext;
struct ID3D11VideoProcessor; struct ID3D11VideoProcessor;
struct ID3D11VideoProcessorEnumerator; struct ID3D11VideoProcessorEnumerator;
struct ID3D11VideoProcessorOutputView; struct ID3D11VideoProcessorOutputView;
struct IDCompositionColorMatrixEffect;
struct IDCompositionFilterEffect;
struct IDCompositionTableTransferEffect;
struct IDCompositionDevice2; struct IDCompositionDevice2;
struct IDCompositionDevice3;
struct IDCompositionSurface; struct IDCompositionSurface;
struct IDCompositionTarget; struct IDCompositionTarget;
struct IDCompositionVisual2; struct IDCompositionVisual2;
@ -66,6 +71,23 @@ struct GpuOverlayInfo {
UINT mRgb10a2OverlaySupportFlags = 0; UINT mRgb10a2OverlaySupportFlags = 0;
}; };
// -
struct ColorManagementChain {
RefPtr<IDCompositionColorMatrixEffect> srcRgbFromSrcYuv;
RefPtr<IDCompositionTableTransferEffect> srcLinearFromSrcTf;
RefPtr<IDCompositionColorMatrixEffect> dstLinearFromSrcLinear;
RefPtr<IDCompositionTableTransferEffect> dstTfFromDstLinear;
RefPtr<IDCompositionFilterEffect> last;
static ColorManagementChain From(IDCompositionDevice3& dcomp,
const color::ColorProfileConversionDesc&);
~ColorManagementChain();
};
// -
/** /**
* DCLayerTree manages direct composition layers. * DCLayerTree manages direct composition layers.
* It does not manage gecko's layers::Layer. * It does not manage gecko's layers::Layer.
@ -210,6 +232,19 @@ class DCLayerTree {
bool mPendingCommit; bool mPendingCommit;
static color::ColorProfileDesc QueryOutputColorProfile();
mutable Maybe<color::ColorProfileDesc> mOutputColorProfile;
public:
const color::ColorProfileDesc& OutputColorProfile() const {
if (!mOutputColorProfile) {
mOutputColorProfile = Some(QueryOutputColorProfile());
}
return *mOutputColorProfile;
}
protected:
static UniquePtr<GpuOverlayInfo> sGpuOverlayInfo; static UniquePtr<GpuOverlayInfo> sGpuOverlayInfo;
}; };
@ -322,6 +357,7 @@ class DCExternalSurfaceWrapper : public DCSurface {
UniquePtr<DCSurface> mSurface; UniquePtr<DCSurface> mSurface;
const bool mIsOpaque; const bool mIsOpaque;
Maybe<ColorManagementChain> mCManageChain;
}; };
class DCSurfaceVideo : public DCSurface { class DCSurfaceVideo : public DCSurface {

View File

@ -5767,6 +5767,11 @@
#endif #endif
mirror: always mirror: always
- name: gfx.color_management.display_profile
type: DataMutexString
value: ""
mirror: always # But be warned: We cache the result.
- name: gfx.color_management.force_srgb - name: gfx.color_management.force_srgb
type: RelaxedAtomicBool type: RelaxedAtomicBool
value: false value: false
@ -5774,7 +5779,7 @@
- name: gfx.color_management.native_srgb - name: gfx.color_management.native_srgb
type: RelaxedAtomicBool type: RelaxedAtomicBool
#if defined(XP_MACOSX) #if defined(XP_MACOSX) || defined(XP_WIN)
value: true value: true
#else #else
value: false value: false
@ -5799,6 +5804,16 @@
value: 0 value: 0
mirror: always mirror: always
- name: gfx.color_management.rec709_gamma_as_srgb
type: RelaxedAtomicBool
value: true # Tragic backwards compat.
mirror: always
- name: gfx.color_management.rec2020_gamma_as_rec709
type: RelaxedAtomicBool
value: true # Match naive behavior, but hopefully we can stop soon!
mirror: always
- name: gfx.compositor.clearstate - name: gfx.compositor.clearstate
type: RelaxedAtomicBool type: RelaxedAtomicBool
value: false value: false

View File

@ -449,8 +449,6 @@ pref("formhelper.autozoom.force-disable.test-only", false);
pref("gfx.hidpi.enabled", 2); pref("gfx.hidpi.enabled", 2);
#endif #endif
pref("gfx.color_management.display_profile", "");
pref("gfx.downloadable_fonts.enabled", true); pref("gfx.downloadable_fonts.enabled", true);
pref("gfx.downloadable_fonts.fallback_delay", 3000); pref("gfx.downloadable_fonts.fallback_delay", 3000);
pref("gfx.downloadable_fonts.fallback_delay_short", 100); pref("gfx.downloadable_fonts.fallback_delay_short", 100);