summaryrefslogtreecommitdiffstats
path: root/gfx/webrender_bindings/DCLayerTree.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/webrender_bindings/DCLayerTree.h')
-rw-r--r--gfx/webrender_bindings/DCLayerTree.h461
1 files changed, 461 insertions, 0 deletions
diff --git a/gfx/webrender_bindings/DCLayerTree.h b/gfx/webrender_bindings/DCLayerTree.h
new file mode 100644
index 0000000000..2dd3a061ac
--- /dev/null
+++ b/gfx/webrender_bindings/DCLayerTree.h
@@ -0,0 +1,461 @@
+/* -*- 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/. */
+
+#ifndef MOZILLA_GFX_DCLAYER_TREE_H
+#define MOZILLA_GFX_DCLAYER_TREE_H
+
+#include <dxgiformat.h>
+#include <unordered_map>
+#include <vector>
+#include <windows.h>
+
+#include "Colorspaces.h"
+#include "GLTypes.h"
+#include "mozilla/HashFunctions.h"
+#include "mozilla/layers/OverlayInfo.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+
+struct ID3D11Device;
+struct ID3D11DeviceContext;
+struct ID3D11VideoDevice;
+struct ID3D11VideoContext;
+struct ID3D11VideoProcessor;
+struct ID3D11VideoProcessorEnumerator;
+struct ID3D11VideoProcessorOutputView;
+struct IDCompositionColorMatrixEffect;
+struct IDCompositionFilterEffect;
+struct IDCompositionTableTransferEffect;
+struct IDCompositionDevice2;
+struct IDCompositionDevice3;
+struct IDCompositionSurface;
+struct IDCompositionTarget;
+struct IDCompositionVisual2;
+struct IDXGIDecodeSwapChain;
+struct IDXGIResource;
+struct IDXGISwapChain1;
+struct IDCompositionVirtualSurface;
+
+namespace mozilla {
+
+namespace gl {
+class GLContext;
+}
+
+namespace wr {
+
+// The size of the virtual surface. This is large enough such that we
+// will never render a surface larger than this.
+#define VIRTUAL_SURFACE_SIZE (1024 * 1024)
+
+class DCTile;
+class DCSurface;
+class DCSurfaceVideo;
+class DCSurfaceHandle;
+class RenderTextureHost;
+class RenderDcompSurfaceTextureHost;
+
+struct GpuOverlayInfo {
+ bool mSupportsOverlays = false;
+ bool mSupportsHardwareOverlays = false;
+ DXGI_FORMAT mOverlayFormatUsed = DXGI_FORMAT_B8G8R8A8_UNORM;
+ DXGI_FORMAT mOverlayFormatUsedHdr = DXGI_FORMAT_R10G10B10A2_UNORM;
+ UINT mNv12OverlaySupportFlags = 0;
+ UINT mYuy2OverlaySupportFlags = 0;
+ UINT mBgra8OverlaySupportFlags = 0;
+ UINT mRgb10a2OverlaySupportFlags = 0;
+};
+
+// -
+
+struct ColorManagementChain {
+ RefPtr<IDCompositionColorMatrixEffect> srcRgbFromSrcYuv;
+ RefPtr<IDCompositionTableTransferEffect> srcLinearFromSrcTf;
+ RefPtr<IDCompositionColorMatrixEffect> dstLinearFromSrcLinear;
+ RefPtr<IDCompositionTableTransferEffect> dstTfFromDstLinear;
+ RefPtr<IDCompositionFilterEffect> last;
+
+ static ColorManagementChain From(IDCompositionDevice3& dcomp,
+ const color::ColorProfileConversionDesc&);
+
+ ~ColorManagementChain();
+};
+
+// -
+
+/**
+ * DCLayerTree manages direct composition layers.
+ * It does not manage gecko's layers::Layer.
+ */
+class DCLayerTree {
+ public:
+ static UniquePtr<DCLayerTree> Create(gl::GLContext* aGL, EGLConfig aEGLConfig,
+ ID3D11Device* aDevice,
+ ID3D11DeviceContext* aCtx, HWND aHwnd,
+ nsACString& aError);
+
+ static void Shutdown();
+
+ explicit DCLayerTree(gl::GLContext* aGL, EGLConfig aEGLConfig,
+ ID3D11Device* aDevice, ID3D11DeviceContext* aCtx,
+ IDCompositionDevice2* aCompositionDevice);
+ ~DCLayerTree();
+
+ void SetDefaultSwapChain(IDXGISwapChain1* aSwapChain);
+ void MaybeUpdateDebug();
+ void MaybeCommit();
+ void WaitForCommitCompletion();
+ void DisableNativeCompositor();
+
+ // Interface for wr::Compositor
+ void CompositorBeginFrame();
+ void CompositorEndFrame();
+ void Bind(wr::NativeTileId aId, wr::DeviceIntPoint* aOffset, uint32_t* aFboId,
+ wr::DeviceIntRect aDirtyRect, wr::DeviceIntRect aValidRect);
+ void Unbind();
+ void CreateSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aVirtualOffset,
+ wr::DeviceIntSize aTileSize, bool aIsOpaque);
+ void CreateExternalSurface(wr::NativeSurfaceId aId, bool aIsOpaque);
+ void DestroySurface(NativeSurfaceId aId);
+ void CreateTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY);
+ void DestroyTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY);
+ void AttachExternalImage(wr::NativeSurfaceId aId,
+ wr::ExternalImageId aExternalImage);
+ void AddSurface(wr::NativeSurfaceId aId,
+ const wr::CompositorSurfaceTransform& aTransform,
+ wr::DeviceIntRect aClipRect,
+ wr::ImageRendering aImageRendering);
+
+ gl::GLContext* GetGLContext() const { return mGL; }
+ EGLConfig GetEGLConfig() const { return mEGLConfig; }
+ ID3D11Device* GetDevice() const { return mDevice; }
+ IDCompositionDevice2* GetCompositionDevice() const {
+ return mCompositionDevice;
+ }
+ ID3D11VideoDevice* GetVideoDevice() const { return mVideoDevice; }
+ ID3D11VideoContext* GetVideoContext() const { return mVideoContext; }
+ ID3D11VideoProcessor* GetVideoProcessor() const { return mVideoProcessor; }
+ ID3D11VideoProcessorEnumerator* GetVideoProcessorEnumerator() const {
+ return mVideoProcessorEnumerator;
+ }
+ bool EnsureVideoProcessor(const gfx::IntSize& aInputSize,
+ const gfx::IntSize& aOutputSize);
+
+ DCSurface* GetSurface(wr::NativeSurfaceId aId) const;
+
+ // Get or create an FBO with depth buffer suitable for specified dimensions
+ GLuint GetOrCreateFbo(int aWidth, int aHeight);
+
+ bool SupportsHardwareOverlays();
+ DXGI_FORMAT GetOverlayFormatForSDR();
+
+ bool SupportsSwapChainTearing();
+
+ protected:
+ bool Initialize(HWND aHwnd, nsACString& aError);
+ bool InitializeVideoOverlaySupport();
+ bool MaybeUpdateDebugCounter();
+ bool MaybeUpdateDebugVisualRedrawRegions();
+ void DestroyEGLSurface();
+ GLuint CreateEGLSurfaceForCompositionSurface(
+ wr::DeviceIntRect aDirtyRect, wr::DeviceIntPoint* aOffset,
+ RefPtr<IDCompositionSurface> aCompositionSurface,
+ wr::DeviceIntPoint aSurfaceOffset);
+ void ReleaseNativeCompositorResources();
+ layers::OverlayInfo GetOverlayInfo();
+
+ RefPtr<gl::GLContext> mGL;
+ EGLConfig mEGLConfig;
+
+ RefPtr<ID3D11Device> mDevice;
+ RefPtr<ID3D11DeviceContext> mCtx;
+
+ RefPtr<IDCompositionDevice2> mCompositionDevice;
+ RefPtr<IDCompositionTarget> mCompositionTarget;
+ RefPtr<IDCompositionVisual2> mRootVisual;
+ RefPtr<IDCompositionVisual2> mDefaultSwapChainVisual;
+
+ RefPtr<ID3D11VideoDevice> mVideoDevice;
+ RefPtr<ID3D11VideoContext> mVideoContext;
+ RefPtr<ID3D11VideoProcessor> mVideoProcessor;
+ RefPtr<ID3D11VideoProcessorEnumerator> mVideoProcessorEnumerator;
+ gfx::IntSize mVideoInputSize;
+ gfx::IntSize mVideoOutputSize;
+
+ bool mDebugCounter;
+ bool mDebugVisualRedrawRegions;
+
+ Maybe<RefPtr<IDCompositionSurface>> mCurrentSurface;
+
+ // The EGL image that is bound to the D3D texture provided by
+ // DirectComposition.
+ EGLImage mEGLImage;
+
+ // The GL render buffer ID that maps the EGLImage to an RBO for attaching to
+ // an FBO.
+ GLuint mColorRBO;
+
+ struct SurfaceIdHashFn {
+ std::size_t operator()(const wr::NativeSurfaceId& aId) const {
+ return HashGeneric(wr::AsUint64(aId));
+ }
+ };
+
+ std::unordered_map<wr::NativeSurfaceId, UniquePtr<DCSurface>, SurfaceIdHashFn>
+ mDCSurfaces;
+
+ // A list of layer IDs as they are added to the visual tree this frame.
+ std::vector<wr::NativeSurfaceId> mCurrentLayers;
+
+ // The previous frame's list of layer IDs in visual order.
+ std::vector<wr::NativeSurfaceId> mPrevLayers;
+
+ // Information about a cached FBO that is retained between frames.
+ struct CachedFrameBuffer {
+ int width;
+ int height;
+ GLuint fboId;
+ GLuint depthRboId;
+ int lastFrameUsed;
+ };
+
+ // A cache of FBOs, containing a depth buffer allocated to a specific size.
+ // TODO(gw): Might be faster as a hashmap? The length is typically much less
+ // than 10.
+ nsTArray<CachedFrameBuffer> mFrameBuffers;
+ int mCurrentFrame = 0;
+
+ bool mPendingCommit;
+
+ static color::ColorProfileDesc QueryOutputColorProfile();
+
+ mutable Maybe<color::ColorProfileDesc> mOutputColorProfile;
+
+ public:
+ const color::ColorProfileDesc& OutputColorProfile() const {
+ if (!mOutputColorProfile) {
+ mOutputColorProfile = Some(QueryOutputColorProfile());
+ }
+ return *mOutputColorProfile;
+ }
+
+ protected:
+ static UniquePtr<GpuOverlayInfo> sGpuOverlayInfo;
+};
+
+/**
+ Represents a single picture cache slice. Each surface contains some
+ number of tiles. An implementation may choose to allocate individual
+ tiles to render in to (as the current impl does), or allocate a large
+ single virtual surface to draw into (e.g. the DirectComposition virtual
+ surface API in future).
+ */
+class DCSurface {
+ public:
+ const bool mIsVirtualSurface;
+
+ explicit DCSurface(wr::DeviceIntSize aTileSize,
+ wr::DeviceIntPoint aVirtualOffset, bool aIsVirtualSurface,
+ bool aIsOpaque, DCLayerTree* aDCLayerTree);
+ virtual ~DCSurface();
+
+ bool Initialize();
+ void CreateTile(int32_t aX, int32_t aY);
+ void DestroyTile(int32_t aX, int32_t aY);
+
+ IDCompositionVisual2* GetVisual() const { return mVisual; }
+ DCTile* GetTile(int32_t aX, int32_t aY) const;
+
+ struct TileKey {
+ TileKey(int32_t aX, int32_t aY) : mX(aX), mY(aY) {}
+
+ int32_t mX;
+ int32_t mY;
+ };
+
+ wr::DeviceIntSize GetTileSize() const { return mTileSize; }
+ wr::DeviceIntPoint GetVirtualOffset() const { return mVirtualOffset; }
+
+ IDCompositionVirtualSurface* GetCompositionSurface() const {
+ return mVirtualSurface;
+ }
+
+ void UpdateAllocatedRect();
+ void DirtyAllocatedRect();
+
+ // Implement these if the inherited surface supports attaching external image.
+ virtual void AttachExternalImage(wr::ExternalImageId aExternalImage) {
+ MOZ_RELEASE_ASSERT(true, "Not support attaching external image");
+ }
+ virtual void PresentExternalSurface(gfx::Matrix& aTransform) {
+ MOZ_RELEASE_ASSERT(true, "Not support presenting external surface");
+ }
+
+ virtual DCSurfaceVideo* AsDCSurfaceVideo() { return nullptr; }
+ virtual DCSurfaceHandle* AsDCSurfaceHandle() { return nullptr; }
+
+ protected:
+ DCLayerTree* mDCLayerTree;
+
+ struct TileKeyHashFn {
+ std::size_t operator()(const TileKey& aId) const {
+ return HashGeneric(aId.mX, aId.mY);
+ }
+ };
+
+ // The visual for this surface. No content is attached to here, but tiles
+ // that belong to this surface are added as children. In this way, we can
+ // set the clip and scroll offset once, on this visual, to affect all
+ // children.
+ //
+ // However when using a virtual surface, it is directly attached to this
+ // visual and the tiles do not own visuals.
+ //
+ // Whether mIsVirtualSurface is enabled is decided at DCSurface creation
+ // time based on the pref gfx.webrender.dcomp-use-virtual-surfaces
+ RefPtr<IDCompositionVisual2> mVisual;
+
+ wr::DeviceIntSize mTileSize;
+ bool mIsOpaque;
+ bool mAllocatedRectDirty;
+ std::unordered_map<TileKey, UniquePtr<DCTile>, TileKeyHashFn> mDCTiles;
+ wr::DeviceIntPoint mVirtualOffset;
+ RefPtr<IDCompositionVirtualSurface> mVirtualSurface;
+};
+
+/**
+ * A wrapper surface which can contain either a DCVideo or a DCSurfaceHandle.
+ */
+class DCExternalSurfaceWrapper : public DCSurface {
+ public:
+ DCExternalSurfaceWrapper(bool aIsOpaque, DCLayerTree* aDCLayerTree)
+ : DCSurface(wr::DeviceIntSize{}, wr::DeviceIntPoint{},
+ false /* virtual surface */, false /* opaque */,
+ aDCLayerTree),
+ mIsOpaque(aIsOpaque) {}
+ ~DCExternalSurfaceWrapper() = default;
+
+ void AttachExternalImage(wr::ExternalImageId aExternalImage) override;
+
+ void PresentExternalSurface(gfx::Matrix& aTransform) override;
+
+ DCSurfaceVideo* AsDCSurfaceVideo() override {
+ return mSurface ? mSurface->AsDCSurfaceVideo() : nullptr;
+ }
+
+ DCSurfaceHandle* AsDCSurfaceHandle() override {
+ return mSurface ? mSurface->AsDCSurfaceHandle() : nullptr;
+ }
+
+ private:
+ DCSurface* EnsureSurfaceForExternalImage(wr::ExternalImageId aExternalImage);
+
+ UniquePtr<DCSurface> mSurface;
+ const bool mIsOpaque;
+ Maybe<ColorManagementChain> mCManageChain;
+};
+
+class DCSurfaceVideo : public DCSurface {
+ public:
+ DCSurfaceVideo(bool aIsOpaque, DCLayerTree* aDCLayerTree);
+
+ void AttachExternalImage(wr::ExternalImageId aExternalImage) override;
+ bool CalculateSwapChainSize(gfx::Matrix& aTransform);
+ void PresentVideo();
+
+ DCSurfaceVideo* AsDCSurfaceVideo() override { return this; }
+
+ protected:
+ virtual ~DCSurfaceVideo();
+
+ DXGI_FORMAT GetSwapChainFormat();
+ bool CreateVideoSwapChain();
+ bool CallVideoProcessorBlt();
+ void ReleaseDecodeSwapChainResources();
+
+ RefPtr<ID3D11VideoProcessorOutputView> mOutputView;
+ RefPtr<IDXGIResource> mDecodeResource;
+ RefPtr<IDXGISwapChain1> mVideoSwapChain;
+ RefPtr<IDXGIDecodeSwapChain> mDecodeSwapChain;
+ HANDLE mSwapChainSurfaceHandle = 0;
+ gfx::IntSize mVideoSize;
+ gfx::IntSize mSwapChainSize;
+ DXGI_FORMAT mSwapChainFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
+ bool mFailedYuvSwapChain = false;
+ RefPtr<RenderTextureHost> mRenderTextureHost;
+ RefPtr<RenderTextureHost> mPrevTexture;
+ int mSlowPresentCount = 0;
+};
+
+/**
+ * A DC surface contains a IDCompositionSurface that is directly constructed by
+ * a handle. This is used by the Media Foundataion media engine, which would
+ * store the decoded video content in the surface.
+ */
+class DCSurfaceHandle : public DCSurface {
+ public:
+ DCSurfaceHandle(bool aIsOpaque, DCLayerTree* aDCLayerTree);
+ ~DCSurfaceHandle() = default;
+
+ void AttachExternalImage(wr::ExternalImageId aExternalImage) override;
+ void PresentSurfaceHandle();
+
+ DCSurfaceHandle* AsDCSurfaceHandle() override { return this; }
+
+ protected:
+ HANDLE GetSurfaceHandle() const;
+ IDCompositionSurface* EnsureSurface();
+
+ RefPtr<RenderDcompSurfaceTextureHost> mDcompTextureHost;
+};
+
+class DCTile {
+ public:
+ gfx::IntRect mValidRect;
+
+ DCLayerTree* mDCLayerTree;
+ // Indicates that when the first BeginDraw occurs on the surface it must be
+ // full size - required by dcomp on non-virtual surfaces.
+ bool mNeedsFullDraw;
+
+ explicit DCTile(DCLayerTree* aDCLayerTree);
+ ~DCTile();
+ bool Initialize(int aX, int aY, wr::DeviceIntSize aSize,
+ bool aIsVirtualSurface, bool aIsOpaque,
+ RefPtr<IDCompositionVisual2> mSurfaceVisual);
+ RefPtr<IDCompositionSurface> Bind(wr::DeviceIntRect aValidRect);
+ IDCompositionVisual2* GetVisual() { return mVisual; }
+
+ protected:
+ // Size in pixels of this tile, some may be unused. Set by Initialize.
+ wr::DeviceIntSize mSize;
+ // Whether the tile is composited as opaque (ignores alpha) or transparent.
+ // Set by Initialize.
+ bool mIsOpaque;
+ // Some code paths differ based on whether parent surface is virtual.
+ bool mIsVirtualSurface;
+ // Visual that displays the composition surface, or NULL if the tile belongs
+ // to a virtual surface.
+ RefPtr<IDCompositionVisual2> mVisual;
+ // Surface for the visual, or NULL if the tile has not had its first Bind or
+ // belongs to a virtual surface.
+ RefPtr<IDCompositionSurface> mCompositionSurface;
+
+ RefPtr<IDCompositionSurface> CreateCompositionSurface(wr::DeviceIntSize aSize,
+ bool aIsOpaque);
+};
+
+static inline bool operator==(const DCSurface::TileKey& a0,
+ const DCSurface::TileKey& a1) {
+ return a0.mX == a1.mX && a0.mY == a1.mY;
+}
+
+} // namespace wr
+} // namespace mozilla
+
+#endif