Source code
Revision control
Copy as Markdown
Other Tools
/* 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 "mozilla/layers/NativeLayerRemoteMac.h"
#include <algorithm>
#include <utility>
#include "CFTypeRefPtr.h"
#include "gfxUtils.h"
#include "GLBlitHelper.h"
#ifdef XP_MACOSX
# include "GLContextCGL.h"
#else
# include "GLContextEAGL.h"
#endif
#include "GLContextProvider.h"
#include "MozFramebuffer.h"
#include "mozilla/gfx/Swizzle.h"
#include "mozilla/glean/GfxMetrics.h"
#include "mozilla/webrender/RenderMacIOSurfaceTextureHost.h"
#include "NativeLayerCA.h"
#include "ScopedGLHelpers.h"
namespace mozilla {
namespace layers {
using gfx::IntPoint;
using gfx::IntRect;
using gfx::IntRegion;
using gfx::IntSize;
using gfx::Matrix4x4;
NativeLayerRemoteMac::NativeLayerRemoteMac(
const IntSize& aSize, bool aIsOpaque,
SurfacePoolHandleCA* aSurfacePoolHandle)
: mIsOpaque(aIsOpaque) {
// We need a surface handler for this type of layer.
mSurfaceHandler.emplace(aSize, aSurfacePoolHandle);
}
NativeLayerRemoteMac::NativeLayerRemoteMac(bool aIsOpaque)
: mIsOpaque(aIsOpaque) {}
NativeLayerRemoteMac::NativeLayerRemoteMac(gfx::DeviceColor aColor)
: mColor(Some(aColor)), mIsOpaque(aColor.a >= 1.0f) {}
NativeLayerRemoteMac::~NativeLayerRemoteMac() {
if (mCommandQueue) {
mCommandQueue->AppendCommand(mozilla::layers::CommandLayerDestroyed(
reinterpret_cast<uint64_t>(this)));
}
}
void NativeLayerRemoteMac::AttachExternalImage(
wr::RenderTextureHost* aExternalImage) {
MOZ_ASSERT(XRE_IsGPUProcess());
MOZ_ASSERT(!mSurfaceHandler);
wr::RenderMacIOSurfaceTextureHost* texture =
aExternalImage->AsRenderMacIOSurfaceTextureHost();
MOZ_ASSERT(texture);
auto externalImage = texture->GetSurface()->GetIOSurfaceRef();
mExternalImage = externalImage;
auto texSize = texture->GetSize(0);
mSize = texSize;
auto displayRect = IntRect(IntPoint{}, mSize);
bool changedDisplayRect = !mDisplayRect.IsEqualInterior(displayRect);
mDisplayRect = displayRect;
bool isDRM = aExternalImage->IsFromDRMSource();
bool changedIsDRM = mIsDRM != isDRM;
mIsDRM = isDRM;
bool isHDR = false;
MacIOSurface* macIOSurface = texture->GetSurface();
if (macIOSurface->GetYUVColorSpace() == gfx::YUVColorSpace::BT2020 &&
StaticPrefs::gfx_color_management_hdr_video_assume_rec2020_uses_pq()) {
// BT2020 colorSpace is a signifier of HDR.
isHDR = true;
}
if (macIOSurface->GetColorDepth() == gfx::ColorDepth::COLOR_10) {
// 10-bit color is a signifier of HDR.
isHDR = true;
}
mIsHDR = isHDR && StaticPrefs::gfx_color_management_hdr_video();
mDirtyLayerInfo |= changedDisplayRect;
mSnapshotLayer.mMutatedFrontSurface = true;
mSnapshotLayer.mMutatedSize |= changedDisplayRect;
mSnapshotLayer.mMutatedDisplayRect |= changedDisplayRect;
mSnapshotLayer.mMutatedIsDRM |= changedIsDRM;
mDirtyChangedSurface = true;
}
GpuFence* NativeLayerRemoteMac::GetGpuFence() { return nullptr; }
IntSize NativeLayerRemoteMac::GetSize() {
if (mSurfaceHandler) {
return mSurfaceHandler->Size();
}
return mSize;
}
void NativeLayerRemoteMac::SetPosition(const IntPoint& aPosition) {
if (mPosition != aPosition) {
mDirtyLayerInfo = true;
mSnapshotLayer.mMutatedPosition = true;
mPosition = aPosition;
}
}
IntPoint NativeLayerRemoteMac::GetPosition() { return mPosition; }
void NativeLayerRemoteMac::SetTransform(const Matrix4x4& aTransform) {
MOZ_ASSERT(aTransform.IsRectilinear());
if (mTransform != aTransform) {
mDirtyLayerInfo = true;
mSnapshotLayer.mMutatedTransform = true;
mTransform = aTransform;
}
}
void NativeLayerRemoteMac::SetSamplingFilter(
gfx::SamplingFilter aSamplingFilter) {
if (mSamplingFilter != aSamplingFilter) {
mDirtyLayerInfo = true;
mSnapshotLayer.mMutatedSamplingFilter = true;
mSamplingFilter = aSamplingFilter;
}
}
gfx::SamplingFilter NativeLayerRemoteMac::SamplingFilter() {
return mSamplingFilter;
}
Matrix4x4 NativeLayerRemoteMac::GetTransform() { return mTransform; }
IntRect NativeLayerRemoteMac::GetRect() {
IntSize size = mSize;
if (mSurfaceHandler) {
size = mSurfaceHandler->Size();
}
return IntRect(mPosition, size);
}
bool NativeLayerRemoteMac::IsOpaque() { return mIsOpaque; }
void NativeLayerRemoteMac::SetClipRect(const Maybe<gfx::IntRect>& aClipRect) {
if (mClipRect != aClipRect) {
mDirtyLayerInfo = true;
mClipRect = aClipRect;
}
}
Maybe<gfx::IntRect> NativeLayerRemoteMac::ClipRect() { return mClipRect; }
void NativeLayerRemoteMac::SetRoundedClipRect(
const Maybe<gfx::RoundedRect>& aRoundedClipRect) {
if (mRoundedClipRect != aRoundedClipRect) {
mDirtyLayerInfo = true;
mSnapshotLayer.mMutatedRoundedClipRect = true;
mRoundedClipRect = aRoundedClipRect;
}
}
Maybe<gfx::RoundedRect> NativeLayerRemoteMac::RoundedClipRect() {
return mRoundedClipRect;
}
gfx::IntRect NativeLayerRemoteMac::CurrentSurfaceDisplayRect() {
if (mSurfaceHandler) {
return mSurfaceHandler->DisplayRect();
}
return mDisplayRect;
}
void NativeLayerRemoteMac::SetSurfaceIsFlipped(bool aIsFlipped) {
if (SurfaceIsFlipped() != aIsFlipped) {
mDirtyLayerInfo = true;
mSnapshotLayer.mMutatedSurfaceIsFlipped = true;
if (mSurfaceHandler) {
mSurfaceHandler->SetSurfaceIsFlipped(aIsFlipped);
} else {
mSurfaceIsFlipped = aIsFlipped;
}
}
}
bool NativeLayerRemoteMac::SurfaceIsFlipped() {
if (mSurfaceHandler) {
return mSurfaceHandler->SurfaceIsFlipped();
}
return mSurfaceIsFlipped;
}
RefPtr<gfx::DrawTarget> NativeLayerRemoteMac::NextSurfaceAsDrawTarget(
const IntRect& aDisplayRect, const IntRegion& aUpdateRegion,
gfx::BackendType aBackendType) {
MOZ_ASSERT(mSurfaceHandler);
return mSurfaceHandler->NextSurfaceAsDrawTarget(aDisplayRect, aUpdateRegion,
aBackendType);
}
Maybe<GLuint> NativeLayerRemoteMac::NextSurfaceAsFramebuffer(
const IntRect& aDisplayRect, const IntRegion& aUpdateRegion,
bool aNeedsDepth) {
MOZ_ASSERT(mSurfaceHandler);
return mSurfaceHandler->NextSurfaceAsFramebuffer(aDisplayRect, aUpdateRegion,
aNeedsDepth);
}
Maybe<SurfaceWithInvalidRegion> NativeLayerRemoteMac::FrontSurface() {
if (mSurfaceHandler) {
return mSurfaceHandler->FrontSurface();
}
if (mExternalImage) {
return Some(SurfaceWithInvalidRegion{mExternalImage, GetRect()});
}
return Nothing();
}
void NativeLayerRemoteMac::NotifySurfaceReady() {
MOZ_ASSERT(mSurfaceHandler);
// When we call the surface handler NotifySurfaceReady(), we get a
// return value indicating if the display rect has changed. Set our
// dirty flag (covering all non-surface changes) if that is true.
bool changedDisplayRect = mSurfaceHandler->NotifySurfaceReady();
mDirtyLayerInfo |= changedDisplayRect;
mDirtyChangedSurface = true;
mSnapshotLayer.mMutatedFrontSurface = true;
}
void NativeLayerRemoteMac::DiscardBackbuffers() {
MOZ_ASSERT(mSurfaceHandler);
mSurfaceHandler->DiscardBackbuffers();
}
void NativeLayerRemoteMac::FlushDirtyLayerInfoToCommandQueue() {
auto ID = reinterpret_cast<uint64_t>(this);
if (mDirtyChangedSurface) {
IOSurfacePort surfacePort;
auto surfaceWithInvalidRegion = FrontSurface();
if (surfaceWithInvalidRegion) {
surfacePort =
IOSurfacePort::FromSurface(surfaceWithInvalidRegion->mSurface);
}
mCommandQueue->AppendCommand(mozilla::layers::CommandChangedSurface(
ID, std::move(surfacePort), IsDRM(), IsHDR(), GetSize()));
mDirtyChangedSurface = false;
}
if (mDirtyLayerInfo) {
mCommandQueue->AppendCommand(mozilla::layers::CommandLayerInfo(
ID, GetPosition(), CurrentSurfaceDisplayRect(), ClipRect(),
RoundedClipRect(), GetTransform(),
static_cast<int8_t>(SamplingFilter()), SurfaceIsFlipped()));
mDirtyLayerInfo = false;
}
}
void NativeLayerRemoteMac::UpdateSnapshotLayer() {
CFTypeRefPtr<IOSurfaceRef> surface;
if (auto frontSurface = FrontSurface()) {
surface = frontSurface->mSurface;
}
IntRect rect = GetRect();
IntRect displayRect = CurrentSurfaceDisplayRect();
bool specializeVideo = false;
bool isVideo = false;
mSnapshotLayer.ApplyChanges(
NativeLayerCAUpdateType::All, rect.Size(), mIsOpaque, rect.TopLeft(),
mTransform, displayRect, mClipRect, mRoundedClipRect, mBackingScale,
mSurfaceIsFlipped, mSamplingFilter, specializeVideo, surface, mColor,
mIsDRM, isVideo);
}
CALayer* NativeLayerRemoteMac::CALayerForSnapshot() {
return mSnapshotLayer.UnderlyingCALayer();
}
} // namespace layers
} // namespace mozilla