Bug 1703654 - Prototype display-p3 for WebGL canvas. r=lsalzman,emilio,webidl,smaug

Enable (direct) external surface compositing for MacIOSurfaces.
Works on Mac.

Differential Revision: https://phabricator.services.mozilla.com/D144073
This commit is contained in:
Kelsey Gilbert 2022-05-02 23:54:09 +00:00
parent 2fc91917b4
commit e722cdd3ed
16 changed files with 130 additions and 17 deletions

View File

@ -837,11 +837,19 @@ ClientWebGLContext::SetContextOptions(JSContext* cx,
newOpts.antialias = attributes.mAntialias.Value();
}
if (attributes.mColorSpace.WasPassed()) {
newOpts.colorSpace = Some(attributes.mColorSpace.Value());
} else if (StaticPrefs::gfx_color_management_native_srgb()) {
newOpts.colorSpace = Some(dom::PredefinedColorSpace::Srgb);
}
// Don't do antialiasing if we've disabled MSAA.
if (!StaticPrefs::webgl_msaa_samples()) {
newOpts.antialias = false;
}
// -
if (mInitialOptions && *mInitialOptions != newOpts) {
// Err if the options asked for aren't the same as what they were
// originally.

View File

@ -113,6 +113,7 @@ bool WebGLContextOptions::operator==(const WebGLContextOptions& r) const {
eq &= (failIfMajorPerformanceCaveat == r.failIfMajorPerformanceCaveat);
eq &= (xrCompatible == r.xrCompatible);
eq &= (powerPreference == r.powerPreference);
eq &= (colorSpace == r.colorSpace);
return eq;
}
@ -875,7 +876,8 @@ bool WebGLContext::PresentInto(gl::SwapChain& swapChain) {
if (!ValidateAndInitFB(nullptr)) return false;
{
auto presenter = swapChain.Acquire(mDefaultFB->mSize);
const auto colorSpace = gfx::ToColorSpace2(mOptions.colorSpace);
auto presenter = swapChain.Acquire(mDefaultFB->mSize, colorSpace);
if (!presenter) {
GenerateWarning("Swap chain surface creation failed.");
LoseContext();
@ -916,7 +918,8 @@ bool WebGLContext::PresentIntoXR(gl::SwapChain& swapChain,
const gl::MozFramebuffer& fb) {
OnEndOfFrame();
auto presenter = swapChain.Acquire(fb.mSize);
const auto colorSpace = gfx::ToColorSpace2(mOptions.colorSpace);
auto presenter = swapChain.Acquire(fb.mSize, colorSpace);
if (!presenter) {
GenerateWarning("Swap chain surface creation failed.");
LoseContext();
@ -1002,7 +1005,9 @@ void WebGLContext::CopyToSwapChain(WebGLFramebuffer* const srcFb,
InitSwapChain(*gl, srcFb->mSwapChain, consumerType);
auto presenter = srcFb->mSwapChain.Acquire(size);
// ColorSpace will need to be part of SwapChainOptions for DTWebgl.
const auto colorSpace = gfx::ToColorSpace2(mOptions.colorSpace);
auto presenter = srcFb->mSwapChain.Acquire(size, colorSpace);
if (!presenter) {
GenerateWarning("Swap chain surface creation failed.");
LoseContext();

View File

@ -364,6 +364,7 @@ struct WebGLContextOptions {
bool xrCompatible = false;
dom::WebGLPowerPreference powerPreference =
dom::WebGLPowerPreference::Default;
Maybe<dom::PredefinedColorSpace> colorSpace;
bool shouldResistFingerprinting = true;
bool enableDebugRendererInfo = false;
@ -376,6 +377,26 @@ struct WebGLContextOptions {
}
};
namespace gfx {
inline ColorSpace2 ToColorSpace2(const Maybe<dom::PredefinedColorSpace> cs) {
if (!cs) {
return ColorSpace2::UNKNOWN;
}
switch (*cs) {
case dom::PredefinedColorSpace::Srgb:
return ColorSpace2::SRGB;
case dom::PredefinedColorSpace::Display_p3:
return ColorSpace2::DISPLAY_P3;
case dom::PredefinedColorSpace::EndGuard_:
break;
}
MOZ_CRASH("Exhaustive switch");
}
} // namespace gfx
// -
template <typename _T>

View File

@ -35,6 +35,7 @@ typedef unsigned long long GLuint64EXT;
// The power preference settings are documented in the WebGLContextAttributes
// section of the specification.
enum WebGLPowerPreference { "default", "low-power", "high-performance" };
enum PredefinedColorSpace { "srgb", "display-p3" };
[GenerateInit]
dictionary WebGLContextAttributes {
@ -51,6 +52,10 @@ dictionary WebGLContextAttributes {
GLboolean preserveDrawingBuffer = false;
GLboolean failIfMajorPerformanceCaveat = false;
WebGLPowerPreference powerPreference = "default";
// We are experimenting here, though this should be close to where we end up.
[Pref="webgl.colorspaces.prototype"]
PredefinedColorSpace colorSpace; // = "srgb"; Default is gfx::ColorSpace2::UNKNOWN for now.
};
[Exposed=(Window,Worker),

View File

@ -634,3 +634,27 @@ CGLError MacIOSurface::CGLTexImageIOSurface2D(
}
return err;
}
void MacIOSurface::SetColorSpace(const mozilla::gfx::ColorSpace2 cs) const {
Maybe<CFStringRef> str;
switch (cs) {
case gfx::ColorSpace2::UNKNOWN:
break;
case gfx::ColorSpace2::SRGB:
str = Some(kCGColorSpaceSRGB);
break;
case gfx::ColorSpace2::DISPLAY_P3:
str = Some(kCGColorSpaceDisplayP3);
break;
case gfx::ColorSpace2::BT601_525: // Doesn't really have a better option.
case gfx::ColorSpace2::BT709:
str = Some(kCGColorSpaceITUR_709);
break;
case gfx::ColorSpace2::BT2020:
str = Some(kCGColorSpaceITUR_2020);
break;
}
if (str) {
IOSurfaceSetValue(mIOSurfaceRef.get(), CFSTR("IOSurfaceColorSpace"), *str);
}
}

View File

@ -152,6 +152,8 @@ class MacIOSurface final
static size_t GetMaxHeight();
CFTypeRefPtr<IOSurfaceRef> GetIOSurfaceRef() { return mIOSurfaceRef; }
void SetColorSpace(mozilla::gfx::ColorSpace2) const;
private:
CFTypeRefPtr<IOSurfaceRef> mIOSurfaceRef;
const bool mHasAlpha;

View File

@ -365,7 +365,7 @@ enum class ColorRange : uint8_t {
_Last = FULL,
};
// Really "YcbcrColorSpace"
// Really "YcbcrColorColorSpace"
enum class YUVRangedColorSpace : uint8_t {
BT601_Narrow = 0,
BT601_Full,
@ -380,6 +380,23 @@ enum class YUVRangedColorSpace : uint8_t {
Default = BT709_Narrow,
};
// I can either come up with a longer "very clever" name that doesn't conflict
// with FilterSupport.h, embrace and expand FilterSupport, or rename the old
// one.
// Some times Worse Is Better.
enum class ColorSpace2 : uint8_t {
UNKNOWN, // Eventually we will remove this.
SRGB,
BT601_525, // aka smpte170m NTSC
BT709, // Same gamut as SRGB, but different gamma.
BT601_625 =
BT709, // aka bt470bg PAL. Basically BT709, just Xg is 0.290 not 0.300.
BT2020,
DISPLAY_P3,
_First = UNKNOWN,
_Last = DISPLAY_P3,
};
struct FromYUVRangedColorSpaceT final {
const YUVColorSpace space;
const ColorRange range;

View File

@ -26,20 +26,27 @@ static constexpr size_t kPoolSize =
0;
#endif
UniquePtr<SwapChainPresenter> SwapChain::Acquire(const gfx::IntSize& size) {
UniquePtr<SwapChainPresenter> SwapChain::Acquire(
const gfx::IntSize& size, const gfx::ColorSpace2 colorSpace) {
MOZ_ASSERT(mFactory);
std::shared_ptr<SharedSurface> surf;
if (!mPool.empty() &&
(mPool.front()->mDesc.size != size || !mPool.front()->IsValid())) {
mPool = {};
if (!mPool.empty()) {
// Try reuse
const auto& existingDesc = mPool.front()->mDesc;
auto newDesc = existingDesc;
newDesc.size = size;
newDesc.colorSpace = colorSpace;
if (newDesc != existingDesc || !mPool.front()->IsValid()) {
mPool = {};
}
}
if (kPoolSize && mPool.size() == kPoolSize) {
surf = mPool.front();
mPool.pop();
}
if (!surf) {
auto uniquePtrSurf = mFactory->CreateShared(size);
auto uniquePtrSurf = mFactory->CreateShared(size, colorSpace);
if (!uniquePtrSurf) return nullptr;
surf.reset(uniquePtrSurf.release());
}

View File

@ -69,7 +69,7 @@ class SwapChain final {
void ClearPool();
const auto& FrontBuffer() const { return mFrontBuffer; }
UniquePtr<SwapChainPresenter> Acquire(const gfx::IntSize&);
UniquePtr<SwapChainPresenter> Acquire(const gfx::IntSize&, gfx::ColorSpace2);
};
} // namespace gl

View File

@ -60,9 +60,23 @@ struct PartialSharedSurfaceDesc {
const SharedSurfaceType type;
const layers::TextureType consumerType;
const bool canRecycle;
bool operator==(const PartialSharedSurfaceDesc& rhs) const {
return gl == rhs.gl && type == rhs.type &&
consumerType == rhs.consumerType && canRecycle == rhs.canRecycle;
}
};
struct SharedSurfaceDesc : public PartialSharedSurfaceDesc {
gfx::IntSize size = {};
gfx::ColorSpace2 colorSpace = gfx::ColorSpace2::UNKNOWN;
bool operator==(const SharedSurfaceDesc& rhs) const {
return PartialSharedSurfaceDesc::operator==(rhs) && size == rhs.size &&
colorSpace == rhs.colorSpace;
}
bool operator!=(const SharedSurfaceDesc& rhs) const {
return !(*this == rhs);
}
};
class SharedSurface {
@ -166,8 +180,9 @@ class SurfaceFactory {
const SharedSurfaceDesc&) = 0;
public:
UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) {
return CreateSharedImpl({mDesc, size});
UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size,
gfx::ColorSpace2 cs) {
return CreateSharedImpl({mDesc, size, cs});
}
};

View File

@ -60,7 +60,8 @@ class SurfaceFactory_DMABUF : public SurfaceFactory {
}
bool CanCreateSurface() {
UniquePtr<SharedSurface> test = CreateShared(gfx::IntSize(1, 1));
UniquePtr<SharedSurface> test =
CreateShared(gfx::IntSize(1, 1), gfx::ColorSpace2::SRGB);
return test != nullptr;
}
};

View File

@ -60,6 +60,10 @@ UniquePtr<SharedSurface_IOSurface> SharedSurface_IOSurface::Create(
return nullptr;
}
ioSurf->SetColorSpace(desc.colorSpace);
// -
auto tex = MakeUnique<Texture>(*desc.gl);
BackTextureWithIOSurf(desc.gl, tex->name, ioSurf);

View File

@ -1322,8 +1322,6 @@ bool NativeLayerCA::Representation::EnqueueSurface(IOSurfaceRef aSurfaceRef) {
CFTypeRefPtr<CGColorSpaceRef> colorSpace =
CFTypeRefPtr<CGColorSpaceRef>::WrapUnderGetRule(CVImageBufferGetColorSpace(pixelBuffer));
if (!colorSpace) {
printf("VIDEO_LOG: pixel buffer created by EnqueueSurface has no color space.\n");
// Use our main display color space.
colorSpace = CFTypeRefPtr<CGColorSpaceRef>::WrapUnderCreateRule(
CGDisplayCopyColorSpace(CGMainDisplayID()));

View File

@ -11,9 +11,10 @@ using mozilla::StereoMode from "ImageTypes.h";
using struct mozilla::null_t from "mozilla/ipc/IPCCore.h";
using mozilla::WindowsHandle from "mozilla/ipc/IPCTypes.h";
using mozilla::gfx::YUVColorSpace from "mozilla/gfx/Types.h";
using mozilla::gfx::ChromaSubsampling from "mozilla/gfx/Types.h";
using mozilla::gfx::ColorDepth from "mozilla/gfx/Types.h";
using mozilla::gfx::ColorRange from "mozilla/gfx/Types.h";
using mozilla::gfx::ChromaSubsampling from "mozilla/gfx/Types.h";
using mozilla::gfx::ColorSpace2 from "mozilla/gfx/Types.h";
using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
using mozilla::gfx::IntRect from "mozilla/gfx/Rect.h";
using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";

View File

@ -192,7 +192,7 @@ void MacIOSurfaceTextureHostOGL::PushDisplayItems(
!(mFlags & TextureFlags::NON_PREMULTIPLIED),
wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f},
preferCompositorSurface,
/* aSupportsExternalCompositing */ false);
/* aSupportsExternalCompositing */ true);
break;
}
case gfx::SurfaceFormat::YUV422: {

View File

@ -12670,6 +12670,11 @@
value: true
mirror: always
- name: webgl.colorspaces.prototype
type: RelaxedAtomicBool
value: false
mirror: always
- name: webgl.debug.incomplete-tex-color
type: RelaxedAtomicUint32
value: 0