mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 04:41:11 +00:00
c70ca80cfd
Original work by Nika Layzell and Ted Mielczarek. Of note: - GLdouble and GLclampd are not defined in the iPhoneOS SDK opengl headers. - GL_CONTEXT_PROVIDER_DEFAULT was defined too early for GLContextProviderEAGL to be used as intended. - GLContextProviderEAGL::CreateForCompositorWidget was aligned with GLContextProviderCGL::CreateForCompositorWidget. There is a ton of overlap between both, but sharing more code was left out of scope. - MacIOSurface::BindTexImage and SurfacePoolCA::LockedPool::GetFramebufferForSurface were left unimplemented. - RootSnapshotter is disabled. Differential Revision: https://phabricator.services.mozilla.com/D204323
673 lines
22 KiB
C++
673 lines
22 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* 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 "RenderCompositorNative.h"
|
|
|
|
#include "GLContext.h"
|
|
#include "GLContextProvider.h"
|
|
#include "mozilla/ProfilerLabels.h"
|
|
#include "mozilla/ProfilerMarkers.h"
|
|
#include "mozilla/gfx/gfxVars.h"
|
|
#include "mozilla/gfx/Logging.h"
|
|
#include "mozilla/layers/CompositionRecorder.h"
|
|
#include "mozilla/layers/NativeLayer.h"
|
|
#include "mozilla/layers/SurfacePool.h"
|
|
#include "mozilla/StaticPrefs_gfx.h"
|
|
#include "mozilla/webrender/RenderThread.h"
|
|
#include "mozilla/widget/CompositorWidget.h"
|
|
#include "RenderCompositorRecordedFrame.h"
|
|
|
|
namespace mozilla::wr {
|
|
|
|
extern LazyLogModule gRenderThreadLog;
|
|
#define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__))
|
|
|
|
RenderCompositorNative::RenderCompositorNative(
|
|
const RefPtr<widget::CompositorWidget>& aWidget, gl::GLContext* aGL)
|
|
: RenderCompositor(aWidget),
|
|
mNativeLayerRoot(GetWidget()->GetNativeLayerRoot()) {
|
|
LOG("RenderCompositorNative::RenderCompositorNative()");
|
|
|
|
#if defined(XP_DARWIN) || defined(MOZ_WAYLAND)
|
|
auto pool = RenderThread::Get()->SharedSurfacePool();
|
|
if (pool) {
|
|
mSurfacePoolHandle = pool->GetHandleForGL(aGL);
|
|
}
|
|
#endif
|
|
MOZ_RELEASE_ASSERT(mSurfacePoolHandle);
|
|
}
|
|
|
|
RenderCompositorNative::~RenderCompositorNative() {
|
|
LOG("RRenderCompositorNative::~RenderCompositorNative()");
|
|
|
|
Pause();
|
|
mProfilerScreenshotGrabber.Destroy();
|
|
mNativeLayerRoot->SetLayers({});
|
|
mNativeLayerForEntireWindow = nullptr;
|
|
mNativeLayerRootSnapshotter = nullptr;
|
|
mNativeLayerRoot = nullptr;
|
|
}
|
|
|
|
bool RenderCompositorNative::BeginFrame() {
|
|
if (!MakeCurrent()) {
|
|
gfxCriticalNote << "Failed to make render context current, can't draw.";
|
|
return false;
|
|
}
|
|
|
|
gfx::IntSize bufferSize = GetBufferSize().ToUnknownSize();
|
|
if (!ShouldUseNativeCompositor()) {
|
|
if (bufferSize.IsEmpty()) {
|
|
return false;
|
|
}
|
|
if (mNativeLayerForEntireWindow &&
|
|
mNativeLayerForEntireWindow->GetSize() != bufferSize) {
|
|
mNativeLayerRoot->RemoveLayer(mNativeLayerForEntireWindow);
|
|
mNativeLayerForEntireWindow = nullptr;
|
|
}
|
|
if (!mNativeLayerForEntireWindow) {
|
|
mNativeLayerForEntireWindow =
|
|
mNativeLayerRoot->CreateLayer(bufferSize, false, mSurfacePoolHandle);
|
|
mNativeLayerRoot->AppendLayer(mNativeLayerForEntireWindow);
|
|
}
|
|
}
|
|
|
|
gfx::IntRect bounds({}, bufferSize);
|
|
if (!InitDefaultFramebuffer(bounds)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
RenderedFrameId RenderCompositorNative::EndFrame(
|
|
const nsTArray<DeviceIntRect>& aDirtyRects) {
|
|
RenderedFrameId frameId = GetNextRenderFrameId();
|
|
|
|
DoSwap();
|
|
|
|
if (mNativeLayerForEntireWindow) {
|
|
mNativeLayerForEntireWindow->NotifySurfaceReady();
|
|
mNativeLayerRoot->CommitToScreen();
|
|
}
|
|
|
|
return frameId;
|
|
}
|
|
|
|
void RenderCompositorNative::Pause() {}
|
|
|
|
bool RenderCompositorNative::Resume() { return true; }
|
|
|
|
inline layers::WebRenderCompositor RenderCompositorNative::CompositorType()
|
|
const {
|
|
if (gfx::gfxVars::UseWebRenderCompositor()) {
|
|
#if defined(XP_DARWIN)
|
|
return layers::WebRenderCompositor::CORE_ANIMATION;
|
|
#elif defined(MOZ_WAYLAND)
|
|
return layers::WebRenderCompositor::WAYLAND;
|
|
#endif
|
|
}
|
|
return layers::WebRenderCompositor::DRAW;
|
|
}
|
|
|
|
LayoutDeviceIntSize RenderCompositorNative::GetBufferSize() {
|
|
return mWidget->GetClientSize();
|
|
}
|
|
|
|
bool RenderCompositorNative::ShouldUseNativeCompositor() {
|
|
return gfx::gfxVars::UseWebRenderCompositor();
|
|
}
|
|
|
|
void RenderCompositorNative::GetCompositorCapabilities(
|
|
CompositorCapabilities* aCaps) {
|
|
RenderCompositor::GetCompositorCapabilities(aCaps);
|
|
#if defined(XP_DARWIN)
|
|
aCaps->supports_surface_for_backdrop = !gfx::gfxVars::UseSoftwareWebRender();
|
|
#endif
|
|
}
|
|
|
|
bool RenderCompositorNative::MaybeReadback(
|
|
const gfx::IntSize& aReadbackSize, const wr::ImageFormat& aReadbackFormat,
|
|
const Range<uint8_t>& aReadbackBuffer, bool* aNeedsYFlip) {
|
|
if (!ShouldUseNativeCompositor()) {
|
|
return false;
|
|
}
|
|
|
|
MOZ_RELEASE_ASSERT(aReadbackFormat == wr::ImageFormat::BGRA8);
|
|
if (!mNativeLayerRootSnapshotter) {
|
|
mNativeLayerRootSnapshotter = mNativeLayerRoot->CreateSnapshotter();
|
|
|
|
if (!mNativeLayerRootSnapshotter) {
|
|
return false;
|
|
}
|
|
}
|
|
bool success = mNativeLayerRootSnapshotter->ReadbackPixels(
|
|
aReadbackSize, gfx::SurfaceFormat::B8G8R8A8, aReadbackBuffer);
|
|
|
|
// ReadbackPixels might have changed the current context. Make sure GL is
|
|
// current again.
|
|
MakeCurrent();
|
|
|
|
if (aNeedsYFlip) {
|
|
*aNeedsYFlip = true;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
bool RenderCompositorNative::MaybeRecordFrame(
|
|
layers::CompositionRecorder& aRecorder) {
|
|
if (!ShouldUseNativeCompositor()) {
|
|
return false;
|
|
}
|
|
|
|
if (!mNativeLayerRootSnapshotter) {
|
|
mNativeLayerRootSnapshotter = mNativeLayerRoot->CreateSnapshotter();
|
|
}
|
|
|
|
if (!mNativeLayerRootSnapshotter) {
|
|
return true;
|
|
}
|
|
|
|
gfx::IntSize size = GetBufferSize().ToUnknownSize();
|
|
RefPtr<layers::profiler_screenshots::RenderSource> snapshot =
|
|
mNativeLayerRootSnapshotter->GetWindowContents(size);
|
|
if (!snapshot) {
|
|
return true;
|
|
}
|
|
|
|
RefPtr<layers::profiler_screenshots::AsyncReadbackBuffer> buffer =
|
|
mNativeLayerRootSnapshotter->CreateAsyncReadbackBuffer(size);
|
|
buffer->CopyFrom(snapshot);
|
|
|
|
RefPtr<layers::RecordedFrame> frame =
|
|
new RenderCompositorRecordedFrame(TimeStamp::Now(), std::move(buffer));
|
|
aRecorder.RecordFrame(frame);
|
|
|
|
// GetWindowContents might have changed the current context. Make sure our
|
|
// context is current again.
|
|
MakeCurrent();
|
|
return true;
|
|
}
|
|
|
|
bool RenderCompositorNative::MaybeGrabScreenshot(
|
|
const gfx::IntSize& aWindowSize) {
|
|
if (!ShouldUseNativeCompositor()) {
|
|
return false;
|
|
}
|
|
|
|
if (!mNativeLayerRootSnapshotter) {
|
|
mNativeLayerRootSnapshotter = mNativeLayerRoot->CreateSnapshotter();
|
|
}
|
|
|
|
if (mNativeLayerRootSnapshotter) {
|
|
mProfilerScreenshotGrabber.MaybeGrabScreenshot(*mNativeLayerRootSnapshotter,
|
|
aWindowSize);
|
|
|
|
// MaybeGrabScreenshot might have changed the current context. Make sure our
|
|
// context is current again.
|
|
MakeCurrent();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool RenderCompositorNative::MaybeProcessScreenshotQueue() {
|
|
if (!ShouldUseNativeCompositor()) {
|
|
return false;
|
|
}
|
|
|
|
mProfilerScreenshotGrabber.MaybeProcessQueue();
|
|
|
|
// MaybeProcessQueue might have changed the current context. Make sure our
|
|
// context is current again.
|
|
MakeCurrent();
|
|
|
|
return true;
|
|
}
|
|
|
|
void RenderCompositorNative::CompositorBeginFrame() {
|
|
mAddedLayers.Clear();
|
|
mAddedTilePixelCount = 0;
|
|
mAddedClippedPixelCount = 0;
|
|
mBeginFrameTimeStamp = TimeStamp::Now();
|
|
mSurfacePoolHandle->OnBeginFrame();
|
|
mNativeLayerRoot->PrepareForCommit();
|
|
}
|
|
|
|
void RenderCompositorNative::CompositorEndFrame() {
|
|
if (profiler_thread_is_being_profiled_for_markers()) {
|
|
auto bufferSize = GetBufferSize();
|
|
[[maybe_unused]] uint64_t windowPixelCount =
|
|
uint64_t(bufferSize.width) * bufferSize.height;
|
|
int nativeLayerCount = 0;
|
|
for (const auto& it : mSurfaces) {
|
|
nativeLayerCount += int(it.second.mNativeLayers.size());
|
|
}
|
|
PROFILER_MARKER_TEXT(
|
|
"WR OS Compositor frame", GRAPHICS,
|
|
MarkerTiming::IntervalUntilNowFrom(mBeginFrameTimeStamp),
|
|
nsPrintfCString("%d%% painting, %d%% overdraw, %d used "
|
|
"layers (%d%% memory) + %d unused layers (%d%% memory)",
|
|
int(mDrawnPixelCount * 100 / windowPixelCount),
|
|
int(mAddedClippedPixelCount * 100 / windowPixelCount),
|
|
int(mAddedLayers.Length()),
|
|
int(mAddedTilePixelCount * 100 / windowPixelCount),
|
|
int(nativeLayerCount - mAddedLayers.Length()),
|
|
int((mTotalTilePixelCount - mAddedTilePixelCount) *
|
|
100 / windowPixelCount)));
|
|
}
|
|
mDrawnPixelCount = 0;
|
|
|
|
DoFlush();
|
|
|
|
mNativeLayerRoot->SetLayers(mAddedLayers);
|
|
mNativeLayerRoot->CommitToScreen();
|
|
mSurfacePoolHandle->OnEndFrame();
|
|
}
|
|
|
|
void RenderCompositorNative::BindNativeLayer(wr::NativeTileId aId,
|
|
const gfx::IntRect& aDirtyRect) {
|
|
MOZ_RELEASE_ASSERT(!mCurrentlyBoundNativeLayer);
|
|
|
|
auto surfaceCursor = mSurfaces.find(aId.surface_id);
|
|
MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
|
|
Surface& surface = surfaceCursor->second;
|
|
|
|
auto layerCursor = surface.mNativeLayers.find(TileKey(aId.x, aId.y));
|
|
MOZ_RELEASE_ASSERT(layerCursor != surface.mNativeLayers.end());
|
|
RefPtr<layers::NativeLayer> layer = layerCursor->second;
|
|
|
|
mCurrentlyBoundNativeLayer = layer;
|
|
|
|
mDrawnPixelCount += aDirtyRect.Area();
|
|
}
|
|
|
|
void RenderCompositorNative::UnbindNativeLayer() {
|
|
MOZ_RELEASE_ASSERT(mCurrentlyBoundNativeLayer);
|
|
|
|
mCurrentlyBoundNativeLayer->NotifySurfaceReady();
|
|
mCurrentlyBoundNativeLayer = nullptr;
|
|
}
|
|
|
|
void RenderCompositorNative::CreateSurface(wr::NativeSurfaceId aId,
|
|
wr::DeviceIntPoint aVirtualOffset,
|
|
wr::DeviceIntSize aTileSize,
|
|
bool aIsOpaque) {
|
|
MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end());
|
|
mSurfaces.insert({aId, Surface{aTileSize, aIsOpaque}});
|
|
}
|
|
|
|
void RenderCompositorNative::CreateExternalSurface(wr::NativeSurfaceId aId,
|
|
bool aIsOpaque) {
|
|
MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end());
|
|
|
|
RefPtr<layers::NativeLayer> layer =
|
|
mNativeLayerRoot->CreateLayerForExternalTexture(aIsOpaque);
|
|
|
|
Surface surface{DeviceIntSize{}, aIsOpaque};
|
|
surface.mIsExternal = true;
|
|
surface.mNativeLayers.insert({TileKey(0, 0), layer});
|
|
|
|
mSurfaces.insert({aId, std::move(surface)});
|
|
}
|
|
|
|
void RenderCompositorNative::CreateBackdropSurface(wr::NativeSurfaceId aId,
|
|
wr::ColorF aColor) {
|
|
MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end());
|
|
|
|
gfx::DeviceColor color(aColor.r, aColor.g, aColor.b, aColor.a);
|
|
RefPtr<layers::NativeLayer> layer =
|
|
mNativeLayerRoot->CreateLayerForColor(color);
|
|
|
|
Surface surface{DeviceIntSize{}, (aColor.a >= 1.0f)};
|
|
surface.mNativeLayers.insert({TileKey(0, 0), layer});
|
|
|
|
mSurfaces.insert({aId, std::move(surface)});
|
|
}
|
|
|
|
void RenderCompositorNative::AttachExternalImage(
|
|
wr::NativeSurfaceId aId, wr::ExternalImageId aExternalImage) {
|
|
RenderTextureHost* image =
|
|
RenderThread::Get()->GetRenderTexture(aExternalImage);
|
|
MOZ_RELEASE_ASSERT(image);
|
|
|
|
auto surfaceCursor = mSurfaces.find(aId);
|
|
MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
|
|
|
|
Surface& surface = surfaceCursor->second;
|
|
MOZ_RELEASE_ASSERT(surface.mNativeLayers.size() == 1);
|
|
MOZ_RELEASE_ASSERT(surface.mIsExternal);
|
|
surface.mNativeLayers.begin()->second->AttachExternalImage(image);
|
|
}
|
|
|
|
void RenderCompositorNative::DestroySurface(NativeSurfaceId aId) {
|
|
auto surfaceCursor = mSurfaces.find(aId);
|
|
MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
|
|
|
|
Surface& surface = surfaceCursor->second;
|
|
if (!surface.mIsExternal) {
|
|
for (const auto& iter : surface.mNativeLayers) {
|
|
mTotalTilePixelCount -= gfx::IntRect({}, iter.second->GetSize()).Area();
|
|
}
|
|
}
|
|
|
|
mSurfaces.erase(surfaceCursor);
|
|
}
|
|
|
|
void RenderCompositorNative::CreateTile(wr::NativeSurfaceId aId, int aX,
|
|
int aY) {
|
|
auto surfaceCursor = mSurfaces.find(aId);
|
|
MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
|
|
Surface& surface = surfaceCursor->second;
|
|
MOZ_RELEASE_ASSERT(!surface.mIsExternal);
|
|
|
|
RefPtr<layers::NativeLayer> layer = mNativeLayerRoot->CreateLayer(
|
|
surface.TileSize(), surface.mIsOpaque, mSurfacePoolHandle);
|
|
surface.mNativeLayers.insert({TileKey(aX, aY), layer});
|
|
mTotalTilePixelCount += gfx::IntRect({}, layer->GetSize()).Area();
|
|
}
|
|
|
|
void RenderCompositorNative::DestroyTile(wr::NativeSurfaceId aId, int aX,
|
|
int aY) {
|
|
auto surfaceCursor = mSurfaces.find(aId);
|
|
MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
|
|
Surface& surface = surfaceCursor->second;
|
|
MOZ_RELEASE_ASSERT(!surface.mIsExternal);
|
|
|
|
auto layerCursor = surface.mNativeLayers.find(TileKey(aX, aY));
|
|
MOZ_RELEASE_ASSERT(layerCursor != surface.mNativeLayers.end());
|
|
RefPtr<layers::NativeLayer> layer = std::move(layerCursor->second);
|
|
surface.mNativeLayers.erase(layerCursor);
|
|
mTotalTilePixelCount -= gfx::IntRect({}, layer->GetSize()).Area();
|
|
|
|
// If the layer is currently present in mNativeLayerRoot, it will be destroyed
|
|
// once CompositorEndFrame() replaces mNativeLayerRoot's layers and drops that
|
|
// reference. So until that happens, the layer still needs to hold on to its
|
|
// front buffer. However, we can tell it to drop its back buffers now, because
|
|
// we know that we will never draw to it again.
|
|
// Dropping the back buffers now puts them back in the surface pool, so those
|
|
// surfaces can be immediately re-used for drawing in other layers in the
|
|
// current frame.
|
|
layer->DiscardBackbuffers();
|
|
}
|
|
|
|
gfx::SamplingFilter ToSamplingFilter(wr::ImageRendering aImageRendering) {
|
|
if (aImageRendering == wr::ImageRendering::Auto) {
|
|
return gfx::SamplingFilter::LINEAR;
|
|
}
|
|
return gfx::SamplingFilter::POINT;
|
|
}
|
|
|
|
void RenderCompositorNative::AddSurface(
|
|
wr::NativeSurfaceId aId, const wr::CompositorSurfaceTransform& aTransform,
|
|
wr::DeviceIntRect aClipRect, wr::ImageRendering aImageRendering) {
|
|
MOZ_RELEASE_ASSERT(!mCurrentlyBoundNativeLayer);
|
|
|
|
auto surfaceCursor = mSurfaces.find(aId);
|
|
MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
|
|
const Surface& surface = surfaceCursor->second;
|
|
|
|
float sx = aTransform.scale.x;
|
|
float sy = aTransform.scale.y;
|
|
float tx = aTransform.offset.x;
|
|
float ty = aTransform.offset.y;
|
|
gfx::Matrix4x4 transform(sx, 0.0, 0.0, 0.0, 0.0, sy, 0.0, 0.0, 0.0, 0.0, 1.0,
|
|
0.0, tx, ty, 0.0, 1.0);
|
|
|
|
for (auto it = surface.mNativeLayers.begin();
|
|
it != surface.mNativeLayers.end(); ++it) {
|
|
RefPtr<layers::NativeLayer> layer = it->second;
|
|
gfx::IntSize layerSize = layer->GetSize();
|
|
gfx::IntPoint layerPosition(surface.mTileSize.width * it->first.mX,
|
|
surface.mTileSize.height * it->first.mY);
|
|
layer->SetPosition(layerPosition);
|
|
gfx::IntRect clipRect(aClipRect.min.x, aClipRect.min.y, aClipRect.width(),
|
|
aClipRect.height());
|
|
layer->SetClipRect(Some(clipRect));
|
|
layer->SetTransform(transform);
|
|
layer->SetSamplingFilter(ToSamplingFilter(aImageRendering));
|
|
mAddedLayers.AppendElement(layer);
|
|
|
|
if (!surface.mIsExternal) {
|
|
mAddedTilePixelCount += layerSize.width * layerSize.height;
|
|
}
|
|
gfx::Rect r = transform.TransformBounds(
|
|
gfx::Rect(layer->CurrentSurfaceDisplayRect()));
|
|
gfx::IntRect visibleRect =
|
|
clipRect.Intersect(RoundedToInt(r) + layerPosition);
|
|
mAddedClippedPixelCount += visibleRect.Area();
|
|
}
|
|
}
|
|
|
|
/* static */
|
|
UniquePtr<RenderCompositor> RenderCompositorNativeOGL::Create(
|
|
const RefPtr<widget::CompositorWidget>& aWidget, nsACString& aError) {
|
|
RefPtr<gl::GLContext> gl = RenderThread::Get()->SingletonGL();
|
|
if (!gl) {
|
|
gl = gl::GLContextProvider::CreateForCompositorWidget(
|
|
aWidget, /* aHardwareWebRender */ true, /* aForceAccelerated */ true);
|
|
RenderThread::MaybeEnableGLDebugMessage(gl);
|
|
}
|
|
if (!gl || !gl->MakeCurrent()) {
|
|
gfxCriticalNote << "Failed GL context creation for WebRender: "
|
|
<< gfx::hexa(gl.get());
|
|
return nullptr;
|
|
}
|
|
return MakeUnique<RenderCompositorNativeOGL>(aWidget, std::move(gl));
|
|
}
|
|
|
|
RenderCompositorNativeOGL::RenderCompositorNativeOGL(
|
|
const RefPtr<widget::CompositorWidget>& aWidget,
|
|
RefPtr<gl::GLContext>&& aGL)
|
|
: RenderCompositorNative(aWidget, aGL), mGL(aGL) {
|
|
MOZ_ASSERT(mGL);
|
|
}
|
|
|
|
RenderCompositorNativeOGL::~RenderCompositorNativeOGL() {
|
|
if (!mGL->MakeCurrent()) {
|
|
gfxCriticalNote
|
|
<< "Failed to make render context current during destroying.";
|
|
// Leak resources!
|
|
mPreviousFrameDoneSync = nullptr;
|
|
mThisFrameDoneSync = nullptr;
|
|
return;
|
|
}
|
|
|
|
if (mPreviousFrameDoneSync) {
|
|
mGL->fDeleteSync(mPreviousFrameDoneSync);
|
|
}
|
|
if (mThisFrameDoneSync) {
|
|
mGL->fDeleteSync(mThisFrameDoneSync);
|
|
}
|
|
}
|
|
|
|
bool RenderCompositorNativeOGL::InitDefaultFramebuffer(
|
|
const gfx::IntRect& aBounds) {
|
|
if (mNativeLayerForEntireWindow) {
|
|
Maybe<GLuint> fbo = mNativeLayerForEntireWindow->NextSurfaceAsFramebuffer(
|
|
aBounds, aBounds, true);
|
|
if (!fbo) {
|
|
return false;
|
|
}
|
|
mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, *fbo);
|
|
} else {
|
|
mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mGL->GetDefaultFramebuffer());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void RenderCompositorNativeOGL::DoSwap() {
|
|
InsertFrameDoneSync();
|
|
if (mNativeLayerForEntireWindow) {
|
|
mGL->fFlush();
|
|
}
|
|
}
|
|
|
|
void RenderCompositorNativeOGL::DoFlush() { mGL->fFlush(); }
|
|
|
|
void RenderCompositorNativeOGL::InsertFrameDoneSync() {
|
|
#ifdef XP_DARWIN
|
|
// Only do this on macOS.
|
|
// On other platforms, SwapBuffers automatically applies back-pressure.
|
|
if (mThisFrameDoneSync) {
|
|
mGL->fDeleteSync(mThisFrameDoneSync);
|
|
}
|
|
mThisFrameDoneSync = mGL->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
|
#endif
|
|
}
|
|
|
|
bool RenderCompositorNativeOGL::WaitForGPU() {
|
|
if (mPreviousFrameDoneSync) {
|
|
AUTO_PROFILER_LABEL("Waiting for GPU to finish previous frame", GRAPHICS);
|
|
mGL->fClientWaitSync(mPreviousFrameDoneSync,
|
|
LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT,
|
|
LOCAL_GL_TIMEOUT_IGNORED);
|
|
mGL->fDeleteSync(mPreviousFrameDoneSync);
|
|
}
|
|
mPreviousFrameDoneSync = mThisFrameDoneSync;
|
|
mThisFrameDoneSync = nullptr;
|
|
|
|
return true;
|
|
}
|
|
|
|
void RenderCompositorNativeOGL::Bind(wr::NativeTileId aId,
|
|
wr::DeviceIntPoint* aOffset,
|
|
uint32_t* aFboId,
|
|
wr::DeviceIntRect aDirtyRect,
|
|
wr::DeviceIntRect aValidRect) {
|
|
gfx::IntRect validRect(aValidRect.min.x, aValidRect.min.y, aValidRect.width(),
|
|
aValidRect.height());
|
|
gfx::IntRect dirtyRect(aDirtyRect.min.x, aDirtyRect.min.y, aDirtyRect.width(),
|
|
aDirtyRect.height());
|
|
|
|
BindNativeLayer(aId, dirtyRect);
|
|
|
|
Maybe<GLuint> fbo = mCurrentlyBoundNativeLayer->NextSurfaceAsFramebuffer(
|
|
validRect, dirtyRect, true);
|
|
|
|
*aFboId = *fbo;
|
|
*aOffset = wr::DeviceIntPoint{0, 0};
|
|
}
|
|
|
|
void RenderCompositorNativeOGL::Unbind() {
|
|
mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
|
|
|
|
UnbindNativeLayer();
|
|
}
|
|
|
|
/* static */
|
|
UniquePtr<RenderCompositor> RenderCompositorNativeSWGL::Create(
|
|
const RefPtr<widget::CompositorWidget>& aWidget, nsACString& aError) {
|
|
void* ctx = wr_swgl_create_context();
|
|
if (!ctx) {
|
|
gfxCriticalNote << "Failed SWGL context creation for WebRender";
|
|
return nullptr;
|
|
}
|
|
return MakeUnique<RenderCompositorNativeSWGL>(aWidget, ctx);
|
|
}
|
|
|
|
RenderCompositorNativeSWGL::RenderCompositorNativeSWGL(
|
|
const RefPtr<widget::CompositorWidget>& aWidget, void* aContext)
|
|
: RenderCompositorNative(aWidget), mContext(aContext) {
|
|
MOZ_ASSERT(mContext);
|
|
}
|
|
|
|
RenderCompositorNativeSWGL::~RenderCompositorNativeSWGL() {
|
|
wr_swgl_destroy_context(mContext);
|
|
}
|
|
|
|
bool RenderCompositorNativeSWGL::MakeCurrent() {
|
|
wr_swgl_make_current(mContext);
|
|
return true;
|
|
}
|
|
|
|
bool RenderCompositorNativeSWGL::InitDefaultFramebuffer(
|
|
const gfx::IntRect& aBounds) {
|
|
if (mNativeLayerForEntireWindow) {
|
|
if (!MapNativeLayer(mNativeLayerForEntireWindow, aBounds, aBounds)) {
|
|
return false;
|
|
}
|
|
wr_swgl_init_default_framebuffer(mContext, aBounds.x, aBounds.y,
|
|
aBounds.width, aBounds.height,
|
|
mLayerStride, mLayerValidRectData);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void RenderCompositorNativeSWGL::CancelFrame() {
|
|
if (mNativeLayerForEntireWindow && mLayerTarget) {
|
|
wr_swgl_init_default_framebuffer(mContext, 0, 0, 0, 0, 0, nullptr);
|
|
UnmapNativeLayer();
|
|
}
|
|
}
|
|
|
|
void RenderCompositorNativeSWGL::DoSwap() {
|
|
if (mNativeLayerForEntireWindow && mLayerTarget) {
|
|
wr_swgl_init_default_framebuffer(mContext, 0, 0, 0, 0, 0, nullptr);
|
|
UnmapNativeLayer();
|
|
}
|
|
}
|
|
|
|
bool RenderCompositorNativeSWGL::MapNativeLayer(
|
|
layers::NativeLayer* aLayer, const gfx::IntRect& aDirtyRect,
|
|
const gfx::IntRect& aValidRect) {
|
|
uint8_t* data = nullptr;
|
|
gfx::IntSize size;
|
|
int32_t stride = 0;
|
|
gfx::SurfaceFormat format = gfx::SurfaceFormat::UNKNOWN;
|
|
RefPtr<gfx::DrawTarget> dt = aLayer->NextSurfaceAsDrawTarget(
|
|
aValidRect, gfx::IntRegion(aDirtyRect), gfx::BackendType::SKIA);
|
|
if (!dt || !dt->LockBits(&data, &size, &stride, &format)) {
|
|
return false;
|
|
}
|
|
MOZ_ASSERT(format == gfx::SurfaceFormat::B8G8R8A8 ||
|
|
format == gfx::SurfaceFormat::B8G8R8X8);
|
|
mLayerTarget = std::move(dt);
|
|
mLayerData = data;
|
|
mLayerValidRectData = data + aValidRect.y * stride + aValidRect.x * 4;
|
|
mLayerStride = stride;
|
|
return true;
|
|
}
|
|
|
|
void RenderCompositorNativeSWGL::UnmapNativeLayer() {
|
|
MOZ_ASSERT(mLayerTarget && mLayerData);
|
|
mLayerTarget->ReleaseBits(mLayerData);
|
|
mLayerTarget = nullptr;
|
|
mLayerData = nullptr;
|
|
mLayerValidRectData = nullptr;
|
|
mLayerStride = 0;
|
|
}
|
|
|
|
bool RenderCompositorNativeSWGL::MapTile(wr::NativeTileId aId,
|
|
wr::DeviceIntRect aDirtyRect,
|
|
wr::DeviceIntRect aValidRect,
|
|
void** aData, int32_t* aStride) {
|
|
if (mNativeLayerForEntireWindow) {
|
|
return false;
|
|
}
|
|
gfx::IntRect dirtyRect(aDirtyRect.min.x, aDirtyRect.min.y, aDirtyRect.width(),
|
|
aDirtyRect.height());
|
|
gfx::IntRect validRect(aValidRect.min.x, aValidRect.min.y, aValidRect.width(),
|
|
aValidRect.height());
|
|
BindNativeLayer(aId, dirtyRect);
|
|
if (!MapNativeLayer(mCurrentlyBoundNativeLayer, dirtyRect, validRect)) {
|
|
UnbindNativeLayer();
|
|
return false;
|
|
}
|
|
*aData = mLayerValidRectData;
|
|
*aStride = mLayerStride;
|
|
return true;
|
|
}
|
|
|
|
void RenderCompositorNativeSWGL::UnmapTile() {
|
|
if (!mNativeLayerForEntireWindow && mCurrentlyBoundNativeLayer) {
|
|
UnmapNativeLayer();
|
|
UnbindNativeLayer();
|
|
}
|
|
}
|
|
|
|
} // namespace mozilla::wr
|