332 lines
11 KiB
C++
332 lines
11 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/DMABufFormats.h"
|
|
#include "nsRegion.h"
|
|
#include "nsTArray.h"
|
|
|
|
namespace mozilla::wr {
|
|
class RenderDMABUFTextureHost;
|
|
} // namespace mozilla::wr
|
|
|
|
namespace mozilla::widget {
|
|
class WaylandSurfaceLock;
|
|
} // namespace mozilla::widget
|
|
|
|
namespace mozilla::layers {
|
|
class NativeLayerWaylandExternal;
|
|
|
|
struct LayerState {
|
|
bool mIsVisible : 1;
|
|
};
|
|
|
|
class NativeLayerRootWayland final : public NativeLayerRoot {
|
|
public:
|
|
static already_AddRefed<NativeLayerRootWayland> Create(
|
|
RefPtr<widget::WaylandSurface> aWaylandSurface);
|
|
|
|
// 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 ClearLayers();
|
|
|
|
void PrepareForCommit() override { mFrameInProcess = true; };
|
|
bool CommitToScreen() override;
|
|
|
|
// Main thread only
|
|
GdkWindow* GetGdkWindow() const;
|
|
|
|
RefPtr<widget::WaylandSurface> GetWaylandSurface() { return mSurface; }
|
|
|
|
RefPtr<widget::DRMFormat> GetDRMFormat() { return mDRMFormat; }
|
|
|
|
void FrameCallbackHandler(uint32_t aTime);
|
|
|
|
#ifdef MOZ_LOGGING
|
|
nsAutoCString GetDebugTag() const;
|
|
void* GetLoggingWidget() const;
|
|
#endif
|
|
|
|
void Init();
|
|
void Shutdown();
|
|
|
|
void UpdateLayersOnMainThread();
|
|
void RequestUpdateOnMainThreadLocked(const MutexAutoLock& aProofOfLock);
|
|
|
|
explicit NativeLayerRootWayland(
|
|
RefPtr<widget::WaylandSurface> aWaylandSurface);
|
|
|
|
private:
|
|
~NativeLayerRootWayland();
|
|
|
|
bool CommitToScreenLocked(const MutexAutoLock& aProofOfLock);
|
|
|
|
// Map NativeLayerRootWayland and all child surfaces.
|
|
// Returns true if we're set.
|
|
bool MapLocked(const MutexAutoLock& aProofOfLock);
|
|
|
|
bool UpdateLayersLocked(const MutexAutoLock& aProofOfLock);
|
|
|
|
bool IsEmptyLocked(const MutexAutoLock& aProofOfLock);
|
|
|
|
#ifdef MOZ_LOGGING
|
|
void LogStatsLocked(const MutexAutoLock& aProofOfLock);
|
|
#endif
|
|
|
|
Mutex mMutex MOZ_UNANNOTATED;
|
|
|
|
#ifdef MOZ_LOGGING
|
|
void* mLoggingWidget = nullptr;
|
|
#endif
|
|
|
|
// WaylandSurface of nsWindow (our root window).
|
|
// This WaylandSurface is owned by nsWindow so we don't map/unmap it
|
|
// or handle any callbacks.
|
|
RefPtr<widget::WaylandSurface> mSurface;
|
|
|
|
// Copy of DRM format we use to create DMABuf surfaces
|
|
RefPtr<widget::DRMFormat> mDRMFormat;
|
|
|
|
// Empty buffer attached to mSurface. We need to have something
|
|
// attached to make mSurface and all child visible.
|
|
RefPtr<widget::WaylandBufferSHM> mTmpBuffer;
|
|
|
|
// Child layers attached to this root, they're all on the same level
|
|
// so all child layers are attached to mContainer as subsurfaces.
|
|
// Layer visibility is sorted by Z-order, mSublayers[0] is on bottom.
|
|
nsTArray<RefPtr<NativeLayerWayland>> mSublayers;
|
|
|
|
// Child layers which needs to be updated on main thread,
|
|
// they have been added or removed.
|
|
nsTArray<RefPtr<NativeLayerWayland>> mMainThreadUpdateSublayers;
|
|
|
|
// We're between CompositorBeginFrame() / CompositorEndFrame() calls.
|
|
mozilla::Atomic<bool, mozilla::Relaxed> mFrameInProcess{false};
|
|
|
|
uint32_t mLastFrameCallbackTime = 0;
|
|
|
|
// State flags used for optimizations
|
|
// Layers have been added/removed
|
|
bool mNeedsLayerUpdate = false;
|
|
bool mMainThreadUpdateQueued = false;
|
|
};
|
|
|
|
class NativeLayerWayland : public NativeLayer {
|
|
public:
|
|
virtual NativeLayerWayland* AsNativeLayerWayland() override { return this; }
|
|
virtual NativeLayerWaylandExternal* AsNativeLayerWaylandExternal() {
|
|
return nullptr;
|
|
}
|
|
|
|
// 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;
|
|
|
|
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 UpdateLayer(double aScale);
|
|
// TODO
|
|
GpuFence* GetGpuFence() override { return nullptr; }
|
|
|
|
RefPtr<widget::WaylandSurface> GetWaylandSurface() { return mSurface; }
|
|
|
|
virtual void CommitSurfaceToScreenLocked(
|
|
const MutexAutoLock& aProofOfLock,
|
|
widget::WaylandSurfaceLock& aSurfaceLock) = 0;
|
|
void RemoveAttachedBufferLocked(const MutexAutoLock& aProofOfLock,
|
|
widget::WaylandSurfaceLock& aSurfaceLock);
|
|
|
|
// Surface Map/Unamp happens on rendering thread.
|
|
//
|
|
// We can use surface right after map but we need to finish mapping
|
|
// on main thread to render it correctly.
|
|
//
|
|
// Also Unmap() needs to be finished on main thread.
|
|
bool IsMapped();
|
|
bool Map(widget::WaylandSurfaceLock* aParentWaylandSurfaceLock);
|
|
void Unmap();
|
|
|
|
void UpdateOnMainThread();
|
|
void MainThreadMap();
|
|
void MainThreadUnmap();
|
|
|
|
void ForceCommit();
|
|
|
|
void PlaceAbove(NativeLayerWayland* aLowerLayer);
|
|
|
|
#ifdef MOZ_LOGGING
|
|
nsAutoCString GetDebugTag() const;
|
|
#endif
|
|
|
|
virtual void DiscardBackbuffersLocked(const MutexAutoLock& aProofOfLock,
|
|
bool aForce = false) = 0;
|
|
void DiscardBackbuffers() override;
|
|
|
|
NativeLayerWayland(NativeLayerRootWayland* aRootLayer,
|
|
const gfx::IntSize& aSize, bool aIsOpaque);
|
|
|
|
// No need to lock as we used it when new layers are added only
|
|
constexpr static int sLayerClear = 0;
|
|
constexpr static int sLayerRemoved = 1;
|
|
constexpr static int sLayerAdded = 2;
|
|
|
|
void MarkClear() { mUsageCount = sLayerClear; }
|
|
void MarkRemoved() { mUsageCount = sLayerRemoved; }
|
|
void MarkAdded() { mUsageCount += sLayerAdded; }
|
|
|
|
bool IsRemoved() const { return mUsageCount == sLayerRemoved; }
|
|
bool IsNew() const { return mUsageCount == sLayerAdded; }
|
|
|
|
LayerState* State() { return &mState; }
|
|
|
|
protected:
|
|
~NativeLayerWayland();
|
|
|
|
Mutex mMutex MOZ_UNANNOTATED;
|
|
|
|
// There's a cycle dependency here as NativeLayerRootWayland holds strong
|
|
// reference to NativeLayerWayland and vice versa.
|
|
//
|
|
// Shutdown sequence is:
|
|
//
|
|
// 1) NativeLayerRootWayland is released by GtkCompositorWidget
|
|
// 2) NativeLayerRootWayland calls childs NativeLayerWayland release code and
|
|
// unrefs them.
|
|
// 3) Child NativeLayerWayland register main thread callback to clean up
|
|
// and release itself.
|
|
// 4) Child NativeLayerWayland unref itself and parent NativeLayerRootWayland.
|
|
// 5) NativeLayerRootWayland is released when there isn't any
|
|
// NativeLayerWayland left.
|
|
//
|
|
RefPtr<NativeLayerRootWayland> mRootLayer;
|
|
|
|
RefPtr<widget::WaylandSurface> mSurface;
|
|
|
|
const bool mIsOpaque = false;
|
|
|
|
// Used at SetLayers() when we need to identify removed layers, new layers
|
|
// and layers removed but returned back.
|
|
// We're adding respective constants to mUsageCount for each layer
|
|
// so removed layers have usage count 1, newly added 2 and removed+added 3.
|
|
int mUsageCount = 0;
|
|
|
|
gfx::IntSize mSize;
|
|
gfx::IntPoint mPosition;
|
|
gfx::Matrix4x4 mTransform;
|
|
gfx::IntRect mDisplayRect;
|
|
Maybe<gfx::IntRect> mClipRect;
|
|
gfx::SamplingFilter mSamplingFilter = gfx::SamplingFilter::POINT;
|
|
LayerState mState{};
|
|
bool mSurfaceIsFlipped = false;
|
|
bool mIsHDR = false;
|
|
|
|
enum class MainThreadUpdate {
|
|
None,
|
|
Map,
|
|
Unmap,
|
|
};
|
|
|
|
// Indicate that we need to finish surface map/unmap
|
|
// on main thread.
|
|
// We need to perform main thread unmap even if mapping on main thread
|
|
// is not finished, some main thread resources are created
|
|
// by WaylandSurface itself.
|
|
Atomic<MainThreadUpdate, mozilla::Relaxed> mNeedsMainThreadUpdate{
|
|
MainThreadUpdate::None};
|
|
};
|
|
|
|
class NativeLayerWaylandRender final : public NativeLayerWayland {
|
|
public:
|
|
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 AttachExternalImage(wr::RenderTextureHost* aExternalImage) override;
|
|
void CommitSurfaceToScreenLocked(
|
|
const MutexAutoLock& aProofOfLock,
|
|
widget::WaylandSurfaceLock& aSurfaceLock) override;
|
|
|
|
NativeLayerWaylandRender(NativeLayerRootWayland* aRootLayer,
|
|
const gfx::IntSize& aSize, bool aIsOpaque,
|
|
SurfacePoolHandleWayland* aSurfacePoolHandle);
|
|
|
|
private:
|
|
~NativeLayerWaylandRender() override;
|
|
|
|
void DiscardBackbuffersLocked(const MutexAutoLock& aProofOfLock,
|
|
bool aForce) override;
|
|
void HandlePartialUpdateLocked(const MutexAutoLock& aProofOfLock);
|
|
|
|
const RefPtr<SurfacePoolHandleWayland> mSurfacePoolHandle;
|
|
RefPtr<widget::WaylandBuffer> mInProgressBuffer;
|
|
RefPtr<widget::WaylandBuffer> mFrontBuffer;
|
|
gfx::IntRegion mDirtyRegion;
|
|
};
|
|
|
|
class NativeLayerWaylandExternal final : public NativeLayerWayland {
|
|
public:
|
|
// Overridden methods
|
|
virtual NativeLayerWaylandExternal* AsNativeLayerWaylandExternal() override {
|
|
return this;
|
|
}
|
|
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 AttachExternalImage(wr::RenderTextureHost* aExternalImage) override;
|
|
void CommitSurfaceToScreenLocked(
|
|
const MutexAutoLock& aProofOfLock,
|
|
widget::WaylandSurfaceLock& aSurfaceLock) override;
|
|
|
|
NativeLayerWaylandExternal(NativeLayerRootWayland* aRootLayer,
|
|
bool aIsOpaque);
|
|
|
|
private:
|
|
~NativeLayerWaylandExternal() override;
|
|
|
|
void DiscardBackbuffersLocked(const MutexAutoLock& aProofOfLock,
|
|
bool aForce) override;
|
|
void FreeUnusedBackBuffers();
|
|
|
|
bool mBufferInvalided = false;
|
|
RefPtr<wr::RenderDMABUFTextureHost> mTextureHost;
|
|
RefPtr<widget::WaylandBuffer> mFrontBuffer;
|
|
};
|
|
|
|
} // namespace mozilla::layers
|
|
|
|
#endif // mozilla_layers_NativeLayerWayland_h
|