fune/gfx/layers/NativeLayerWayland.h
Robert Mader 7aea8e97e7 Bug 1720375 - Restructure surface pool into a buffer pool,r=stransky,gfx-reviewers,lsalzman
Note: Sorry in advance that this patch is so big. Unfortunately
splitting it up would create lots of redundant changes.
This should be the last big refactoring for the Wayland compositor
backend for now.

Up until now SurfacePoolWayland was a pool of actual `wl_surface`s,
as before bug 1718569 we had no direct access to `wl_buffer`s when
using EGL. However, the way `SurfacePoolCA` manages native surfaces
is closer to what in Wayland terminology would be a buffer pool:
buffers are heavy-weight and expansive to allocate, while
`wl_surface` objects are cheap to recreate.

So instead of having a pool of surfaces, each of them having its
own pool of buffers, make `wl_surface`s part of tiles and make
`SurfacePoolWayland` manage `wl_buffer`s (in the form of SHM- or
DMABuf buffers). This will allow us to share buffers (especially
depth buffers) more efficiently, reducing VRAM usage and allocation
times.
Apart from that it will also simplify our tile management logic.
Most importantly, we'll need to reorder `wl_surface`s less often and
less complex (no `place_below` the parent surface) and can also drop
reattaching subsurfaces to compositors. Especially the former will
likely decrease CPU time in compositors.

Overall this patch makes `NativeLayerWayland` behave more like
`NativeLayerCA` while taking in lessons learned from
`WindowSurfaceWaylandMB`.

Differential Revision: https://phabricator.services.mozilla.com/D119993
2021-08-04 12:43:21 +00:00

187 lines
6.4 KiB
C++

/* -*- 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/. */
#ifndef mozilla_layers_NativeLayerWayland_h
#define mozilla_layers_NativeLayerWayland_h
#include <deque>
#include <unordered_map>
#include "mozilla/Mutex.h"
#include "mozilla/layers/NativeLayer.h"
#include "mozilla/layers/SurfacePoolWayland.h"
#include "mozilla/widget/MozContainerWayland.h"
#include "nsRegion.h"
#include "nsTArray.h"
namespace mozilla::layers {
typedef void (*CallbackFunc)(void* aData, uint32_t aTime);
class CallbackMultiplexHelper final {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CallbackMultiplexHelper);
explicit CallbackMultiplexHelper(CallbackFunc aCallbackFunc,
void* aCallbackData);
void Callback(uint32_t aTime);
bool IsActive() { return mActive; }
private:
~CallbackMultiplexHelper() = default;
void RunCallback(uint32_t aTime);
bool mActive = true;
CallbackFunc mCallbackFunc = nullptr;
void* mCallbackData = nullptr;
};
class NativeLayerRootWayland final : public NativeLayerRoot {
public:
static already_AddRefed<NativeLayerRootWayland> CreateForMozContainer(
MozContainer* aContainer);
virtual NativeLayerRootWayland* AsNativeLayerRootWayland() override {
return this;
}
// Overridden methods
already_AddRefed<NativeLayer> CreateLayer(
const gfx::IntSize& aSize, bool aIsOpaque,
SurfacePoolHandle* aSurfacePoolHandle) override;
already_AddRefed<NativeLayer> CreateLayerForExternalTexture(
bool aIsOpaque) override;
void AppendLayer(NativeLayer* aLayer) override;
void RemoveLayer(NativeLayer* aLayer) override;
void SetLayers(const nsTArray<RefPtr<NativeLayer>>& aLayers) override;
void PrepareForCommit() override { mFrameInProcess = true; };
bool CommitToScreen() override;
// When the compositor is paused the wl_surface of the MozContainer will
// get destroyed. We thus have to recreate subsurface relationships for
// all tiles after resume. This is a implementation specific quirk of
// our GTK-Wayland backend.
void PauseCompositor() override;
void UpdateLayersOnMainThread();
void AfterFrameClockAfterPaint();
void RequestFrameCallback(CallbackFunc aCallbackFunc, void* aCallbackData);
private:
explicit NativeLayerRootWayland(MozContainer* aContainer);
~NativeLayerRootWayland();
bool CommitToScreen(const MutexAutoLock& aProofOfLock);
Mutex mMutex;
MozContainer* mContainer = nullptr;
wl_surface* mWlSurface = nullptr;
RefPtr<widget::WaylandBufferSHM> mShmBuffer;
nsTArray<RefPtr<NativeLayerWayland>> mSublayers;
nsTArray<RefPtr<NativeLayerWayland>> mOldSublayers;
nsTArray<RefPtr<NativeLayerWayland>> mSublayersOnMainThread;
bool mNewLayers = false;
bool mFrameInProcess = false;
bool mCallbackRequested = false;
gulong mGdkAfterPaintId = 0;
RefPtr<CallbackMultiplexHelper> mCallbackMultiplexHelper;
};
class NativeLayerWayland final : public NativeLayer {
public:
virtual NativeLayerWayland* AsNativeLayerWayland() override { return this; }
// Overridden methods
gfx::IntSize GetSize() override;
void SetPosition(const gfx::IntPoint& aPosition) override;
gfx::IntPoint GetPosition() override;
void SetTransform(const gfx::Matrix4x4& aTransform) override;
gfx::Matrix4x4 GetTransform() override;
gfx::IntRect GetRect() override;
void SetSamplingFilter(gfx::SamplingFilter aSamplingFilter) override;
RefPtr<gfx::DrawTarget> NextSurfaceAsDrawTarget(
const gfx::IntRect& aDisplayRect, const gfx::IntRegion& aUpdateRegion,
gfx::BackendType aBackendType) override;
Maybe<GLuint> NextSurfaceAsFramebuffer(const gfx::IntRect& aDisplayRect,
const gfx::IntRegion& aUpdateRegion,
bool aNeedsDepth) override;
void NotifySurfaceReady() override;
void DiscardBackbuffers() override;
bool IsOpaque() override;
void SetClipRect(const Maybe<gfx::IntRect>& aClipRect) override;
Maybe<gfx::IntRect> ClipRect() override;
gfx::IntRect CurrentSurfaceDisplayRect() override;
void SetSurfaceIsFlipped(bool aIsFlipped) override;
bool SurfaceIsFlipped() override;
void AttachExternalImage(wr::RenderTextureHost* aExternalImage) override;
void Commit();
void Unmap();
void EnsureParentSurface(wl_surface* aParentSurface);
const RefPtr<SurfacePoolHandleWayland> GetSurfacePoolHandle() {
return mSurfacePoolHandle;
};
void SetBufferTransformFlipped(bool aFlipped);
void SetSubsurfacePosition(int aX, int aY);
void SetViewportSourceRect(const gfx::Rect aSourceRect);
void SetViewportDestinationSize(int aWidth, int aHeight);
void RequestFrameCallback(
const RefPtr<CallbackMultiplexHelper>& aMultiplexHelper);
static void FrameCallbackHandler(void* aData, wl_callback* aCallback,
uint32_t aTime);
private:
friend class NativeLayerRootWayland;
NativeLayerWayland(const gfx::IntSize& aSize, bool aIsOpaque,
SurfacePoolHandleWayland* aSurfacePoolHandle);
explicit NativeLayerWayland(bool aIsOpaque);
~NativeLayerWayland() override;
void HandlePartialUpdate(const MutexAutoLock& aProofOfLock);
void FrameCallbackHandler(wl_callback* aCallback, uint32_t aTime);
Mutex mMutex;
const RefPtr<SurfacePoolHandleWayland> mSurfacePoolHandle;
const gfx::IntSize mSize;
const bool mIsOpaque = false;
gfx::IntPoint mPosition;
gfx::Matrix4x4 mTransform;
gfx::IntRect mDisplayRect;
gfx::IntRegion mDirtyRegion;
Maybe<gfx::IntRect> mClipRect;
gfx::SamplingFilter mSamplingFilter = gfx::SamplingFilter::POINT;
bool mSurfaceIsFlipped = false;
bool mHasBufferAttached = false;
wl_surface* mWlSurface = nullptr;
wl_surface* mParentWlSurface = nullptr;
wl_subsurface* mWlSubsurface = nullptr;
wl_callback* mCallback = nullptr;
wp_viewport* mViewport = nullptr;
bool mBufferTransformFlipped = false;
gfx::IntPoint mSubsurfacePosition = gfx::IntPoint(0, 0);
gfx::Rect mViewportSourceRect = gfx::Rect(-1, -1, -1, -1);
gfx::IntSize mViewportDestinationSize = gfx::IntSize(-1, -1);
nsTArray<RefPtr<CallbackMultiplexHelper>> mCallbackMultiplexHelpers;
RefPtr<widget::WaylandBuffer> mInProgressBuffer;
RefPtr<widget::WaylandBuffer> mFrontBuffer;
};
} // namespace mozilla::layers
#endif // mozilla_layers_NativeLayerWayland_h