Bug 1913305 - Add test. r=mtigley
[gecko.git] / gfx / webrender_bindings / DCLayerTree.h
blob2709452e5f07a4a4b66ffa522a89c1d98a27db8f
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef MOZILLA_GFX_DCLAYER_TREE_H
8 #define MOZILLA_GFX_DCLAYER_TREE_H
10 #include <dxgiformat.h>
11 #include <unordered_map>
12 #include <vector>
13 #include <windows.h>
15 #include "Colorspaces.h"
16 #include "GLTypes.h"
17 #include "mozilla/HashFunctions.h"
18 #include "mozilla/layers/OverlayInfo.h"
19 #include "mozilla/Maybe.h"
20 #include "mozilla/RefPtr.h"
21 #include "mozilla/StaticPtr.h"
22 #include "mozilla/UniquePtr.h"
23 #include "mozilla/webrender/WebRenderTypes.h"
25 struct ID3D11Device;
26 struct ID3D11DeviceContext;
27 struct ID3D11VideoDevice;
28 struct ID3D11VideoContext;
29 struct ID3D11VideoProcessor;
30 struct ID3D11VideoProcessorEnumerator;
31 struct ID3D11VideoProcessorOutputView;
32 struct IDCompositionColorMatrixEffect;
33 struct IDCompositionFilterEffect;
34 struct IDCompositionTableTransferEffect;
35 struct IDCompositionDevice2;
36 struct IDCompositionDevice3;
37 struct IDCompositionSurface;
38 struct IDCompositionTarget;
39 struct IDCompositionVisual2;
40 struct IDXGIDecodeSwapChain;
41 struct IDXGIResource;
42 struct IDXGISwapChain1;
43 struct IDCompositionVirtualSurface;
45 namespace mozilla {
47 namespace gfx {
48 color::ColorProfileDesc QueryOutputColorProfile();
51 namespace gl {
52 class GLContext;
55 namespace wr {
57 // The size of the virtual surface. This is large enough such that we
58 // will never render a surface larger than this.
59 #define VIRTUAL_SURFACE_SIZE (1024 * 1024)
61 class DCTile;
62 class DCSurface;
63 class DCSurfaceVideo;
64 class DCSurfaceHandle;
65 class RenderTextureHost;
66 class RenderTextureHostUsageInfo;
67 class RenderDcompSurfaceTextureHost;
69 struct GpuOverlayInfo {
70 bool mSupportsOverlays = false;
71 bool mSupportsHardwareOverlays = false;
72 DXGI_FORMAT mOverlayFormatUsed = DXGI_FORMAT_B8G8R8A8_UNORM;
73 DXGI_FORMAT mOverlayFormatUsedHdr = DXGI_FORMAT_R10G10B10A2_UNORM;
74 UINT mNv12OverlaySupportFlags = 0;
75 UINT mYuy2OverlaySupportFlags = 0;
76 UINT mBgra8OverlaySupportFlags = 0;
77 UINT mRgb10a2OverlaySupportFlags = 0;
79 bool mSupportsVpSuperResolution = false;
80 bool mSupportsVpAutoHDR = false;
83 // -
85 struct ColorManagementChain {
86 RefPtr<IDCompositionColorMatrixEffect> srcRgbFromSrcYuv;
87 RefPtr<IDCompositionTableTransferEffect> srcLinearFromSrcTf;
88 RefPtr<IDCompositionColorMatrixEffect> dstLinearFromSrcLinear;
89 RefPtr<IDCompositionTableTransferEffect> dstTfFromDstLinear;
90 RefPtr<IDCompositionFilterEffect> last;
92 static ColorManagementChain From(IDCompositionDevice3& dcomp,
93 const color::ColorProfileConversionDesc&);
95 ~ColorManagementChain();
98 // -
100 enum class DCompOverlayTypes : uint8_t {
101 NO_OVERLAY = 0,
102 HARDWARE_DECODED_VIDEO = 1 << 0,
103 SOFTWARE_DECODED_VIDEO = 1 << 1,
105 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(DCompOverlayTypes)
107 // -
110 * DCLayerTree manages direct composition layers.
111 * It does not manage gecko's layers::Layer.
113 class DCLayerTree {
114 public:
115 static UniquePtr<DCLayerTree> Create(gl::GLContext* aGL, EGLConfig aEGLConfig,
116 ID3D11Device* aDevice,
117 ID3D11DeviceContext* aCtx, HWND aHwnd,
118 nsACString& aError);
120 static void Shutdown();
122 explicit DCLayerTree(gl::GLContext* aGL, EGLConfig aEGLConfig,
123 ID3D11Device* aDevice, ID3D11DeviceContext* aCtx,
124 HWND aHwnd, IDCompositionDevice2* aCompositionDevice);
125 ~DCLayerTree();
127 void SetDefaultSwapChain(IDXGISwapChain1* aSwapChain);
128 void MaybeUpdateDebug();
129 void MaybeCommit();
130 void WaitForCommitCompletion();
131 void DisableNativeCompositor();
133 // Interface for wr::Compositor
134 void CompositorBeginFrame();
135 void CompositorEndFrame();
136 void Bind(wr::NativeTileId aId, wr::DeviceIntPoint* aOffset, uint32_t* aFboId,
137 wr::DeviceIntRect aDirtyRect, wr::DeviceIntRect aValidRect);
138 void Unbind();
139 void CreateSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aVirtualOffset,
140 wr::DeviceIntSize aTileSize, bool aIsOpaque);
141 void CreateExternalSurface(wr::NativeSurfaceId aId, bool aIsOpaque);
142 void DestroySurface(NativeSurfaceId aId);
143 void CreateTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY);
144 void DestroyTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY);
145 void AttachExternalImage(wr::NativeSurfaceId aId,
146 wr::ExternalImageId aExternalImage);
147 void AddSurface(wr::NativeSurfaceId aId,
148 const wr::CompositorSurfaceTransform& aTransform,
149 wr::DeviceIntRect aClipRect,
150 wr::ImageRendering aImageRendering);
152 gl::GLContext* GetGLContext() const { return mGL; }
153 EGLConfig GetEGLConfig() const { return mEGLConfig; }
154 ID3D11Device* GetDevice() const { return mDevice; }
155 ID3D11DeviceContext* GetDeviceContext() const { return mCtx; }
156 IDCompositionDevice2* GetCompositionDevice() const {
157 return mCompositionDevice;
159 ID3D11VideoDevice* GetVideoDevice() const { return mVideoDevice; }
160 ID3D11VideoContext* GetVideoContext() const { return mVideoContext; }
161 ID3D11VideoProcessor* GetVideoProcessor() const { return mVideoProcessor; }
162 ID3D11VideoProcessorEnumerator* GetVideoProcessorEnumerator() const {
163 return mVideoProcessorEnumerator;
165 bool EnsureVideoProcessor(const gfx::IntSize& aInputSize,
166 const gfx::IntSize& aOutputSize);
168 DCSurface* GetSurface(wr::NativeSurfaceId aId) const;
170 HWND GetHwnd() const { return mHwnd; }
172 // Get or create an FBO with depth buffer suitable for specified dimensions
173 GLuint GetOrCreateFbo(int aWidth, int aHeight);
175 bool SupportsHardwareOverlays();
176 DXGI_FORMAT GetOverlayFormatForSDR();
178 bool SupportsSwapChainTearing();
180 void SetUsedOverlayTypeInFrame(DCompOverlayTypes aTypes);
182 protected:
183 bool Initialize(HWND aHwnd, nsACString& aError);
184 bool InitializeVideoOverlaySupport();
185 bool MaybeUpdateDebugCounter();
186 bool MaybeUpdateDebugVisualRedrawRegions();
187 void DestroyEGLSurface();
188 GLuint CreateEGLSurfaceForCompositionSurface(
189 wr::DeviceIntRect aDirtyRect, wr::DeviceIntPoint* aOffset,
190 RefPtr<IDCompositionSurface> aCompositionSurface,
191 wr::DeviceIntPoint aSurfaceOffset);
192 void ReleaseNativeCompositorResources();
193 layers::OverlayInfo GetOverlayInfo();
195 RefPtr<gl::GLContext> mGL;
196 EGLConfig mEGLConfig;
198 RefPtr<ID3D11Device> mDevice;
199 RefPtr<ID3D11DeviceContext> mCtx;
200 HWND mHwnd;
202 RefPtr<IDCompositionDevice2> mCompositionDevice;
203 RefPtr<IDCompositionTarget> mCompositionTarget;
204 RefPtr<IDCompositionVisual2> mRootVisual;
205 RefPtr<IDCompositionVisual2> mDefaultSwapChainVisual;
207 RefPtr<ID3D11VideoDevice> mVideoDevice;
208 RefPtr<ID3D11VideoContext> mVideoContext;
209 RefPtr<ID3D11VideoProcessor> mVideoProcessor;
210 RefPtr<ID3D11VideoProcessorEnumerator> mVideoProcessorEnumerator;
211 gfx::IntSize mVideoInputSize;
212 gfx::IntSize mVideoOutputSize;
214 bool mDebugCounter;
215 bool mDebugVisualRedrawRegions;
217 Maybe<RefPtr<IDCompositionSurface>> mCurrentSurface;
219 // The EGL image that is bound to the D3D texture provided by
220 // DirectComposition.
221 EGLImage mEGLImage;
223 // The GL render buffer ID that maps the EGLImage to an RBO for attaching to
224 // an FBO.
225 GLuint mColorRBO;
227 struct SurfaceIdHashFn {
228 std::size_t operator()(const wr::NativeSurfaceId& aId) const {
229 return HashGeneric(wr::AsUint64(aId));
233 std::unordered_map<wr::NativeSurfaceId, UniquePtr<DCSurface>, SurfaceIdHashFn>
234 mDCSurfaces;
236 // A list of layer IDs as they are added to the visual tree this frame.
237 std::vector<wr::NativeSurfaceId> mCurrentLayers;
239 // The previous frame's list of layer IDs in visual order.
240 std::vector<wr::NativeSurfaceId> mPrevLayers;
242 // Information about a cached FBO that is retained between frames.
243 struct CachedFrameBuffer {
244 int width;
245 int height;
246 GLuint fboId;
247 GLuint depthRboId;
248 int lastFrameUsed;
251 // A cache of FBOs, containing a depth buffer allocated to a specific size.
252 // TODO(gw): Might be faster as a hashmap? The length is typically much less
253 // than 10.
254 nsTArray<CachedFrameBuffer> mFrameBuffers;
255 int mCurrentFrame = 0;
257 bool mPendingCommit;
259 mutable Maybe<color::ColorProfileDesc> mOutputColorProfile;
261 DCompOverlayTypes mUsedOverlayTypesInFrame = DCompOverlayTypes::NO_OVERLAY;
262 int mSlowCommitCount = 0;
264 public:
265 const color::ColorProfileDesc& OutputColorProfile() const {
266 if (!mOutputColorProfile) {
267 mOutputColorProfile = Some(gfx::QueryOutputColorProfile());
269 return *mOutputColorProfile;
272 protected:
273 static StaticAutoPtr<GpuOverlayInfo> sGpuOverlayInfo;
277 Represents a single picture cache slice. Each surface contains some
278 number of tiles. An implementation may choose to allocate individual
279 tiles to render in to (as the current impl does), or allocate a large
280 single virtual surface to draw into (e.g. the DirectComposition virtual
281 surface API in future).
283 class DCSurface {
284 public:
285 const bool mIsVirtualSurface;
287 explicit DCSurface(wr::DeviceIntSize aTileSize,
288 wr::DeviceIntPoint aVirtualOffset, bool aIsVirtualSurface,
289 bool aIsOpaque, DCLayerTree* aDCLayerTree);
290 virtual ~DCSurface();
292 bool Initialize();
293 void CreateTile(int32_t aX, int32_t aY);
294 void DestroyTile(int32_t aX, int32_t aY);
296 IDCompositionVisual2* GetVisual() const { return mVisual; }
297 DCTile* GetTile(int32_t aX, int32_t aY) const;
299 struct TileKey {
300 TileKey(int32_t aX, int32_t aY) : mX(aX), mY(aY) {}
302 int32_t mX;
303 int32_t mY;
306 wr::DeviceIntSize GetTileSize() const { return mTileSize; }
307 wr::DeviceIntPoint GetVirtualOffset() const { return mVirtualOffset; }
309 IDCompositionVirtualSurface* GetCompositionSurface() const {
310 return mVirtualSurface;
313 void UpdateAllocatedRect();
314 void DirtyAllocatedRect();
316 // Implement these if the inherited surface supports attaching external image.
317 virtual void AttachExternalImage(wr::ExternalImageId aExternalImage) {
318 MOZ_RELEASE_ASSERT(true, "Not support attaching external image");
320 virtual void PresentExternalSurface(gfx::Matrix& aTransform) {
321 MOZ_RELEASE_ASSERT(true, "Not support presenting external surface");
324 virtual DCSurfaceVideo* AsDCSurfaceVideo() { return nullptr; }
325 virtual DCSurfaceHandle* AsDCSurfaceHandle() { return nullptr; }
327 protected:
328 DCLayerTree* mDCLayerTree;
330 struct TileKeyHashFn {
331 std::size_t operator()(const TileKey& aId) const {
332 return HashGeneric(aId.mX, aId.mY);
336 // The visual for this surface. No content is attached to here, but tiles
337 // that belong to this surface are added as children. In this way, we can
338 // set the clip and scroll offset once, on this visual, to affect all
339 // children.
341 // However when using a virtual surface, it is directly attached to this
342 // visual and the tiles do not own visuals.
344 // Whether mIsVirtualSurface is enabled is decided at DCSurface creation
345 // time based on the pref gfx.webrender.dcomp-use-virtual-surfaces
346 RefPtr<IDCompositionVisual2> mVisual;
348 wr::DeviceIntSize mTileSize;
349 bool mIsOpaque;
350 bool mAllocatedRectDirty;
351 std::unordered_map<TileKey, UniquePtr<DCTile>, TileKeyHashFn> mDCTiles;
352 wr::DeviceIntPoint mVirtualOffset;
353 RefPtr<IDCompositionVirtualSurface> mVirtualSurface;
357 * A wrapper surface which can contain either a DCVideo or a DCSurfaceHandle.
359 class DCExternalSurfaceWrapper : public DCSurface {
360 public:
361 DCExternalSurfaceWrapper(bool aIsOpaque, DCLayerTree* aDCLayerTree)
362 : DCSurface(wr::DeviceIntSize{}, wr::DeviceIntPoint{},
363 false /* virtual surface */, false /* opaque */,
364 aDCLayerTree),
365 mIsOpaque(aIsOpaque) {}
366 ~DCExternalSurfaceWrapper() = default;
368 void AttachExternalImage(wr::ExternalImageId aExternalImage) override;
370 void PresentExternalSurface(gfx::Matrix& aTransform) override;
372 DCSurfaceVideo* AsDCSurfaceVideo() override {
373 return mSurface ? mSurface->AsDCSurfaceVideo() : nullptr;
376 DCSurfaceHandle* AsDCSurfaceHandle() override {
377 return mSurface ? mSurface->AsDCSurfaceHandle() : nullptr;
380 private:
381 DCSurface* EnsureSurfaceForExternalImage(wr::ExternalImageId aExternalImage);
383 UniquePtr<DCSurface> mSurface;
384 const bool mIsOpaque;
385 Maybe<ColorManagementChain> mCManageChain;
388 class DCSurfaceVideo : public DCSurface {
389 public:
390 DCSurfaceVideo(bool aIsOpaque, DCLayerTree* aDCLayerTree);
392 void AttachExternalImage(wr::ExternalImageId aExternalImage) override;
393 bool CalculateSwapChainSize(gfx::Matrix& aTransform);
394 void PresentVideo();
396 DCSurfaceVideo* AsDCSurfaceVideo() override { return this; }
398 void DisableVideoOverlay();
400 protected:
401 virtual ~DCSurfaceVideo();
403 DXGI_FORMAT GetSwapChainFormat(bool aUseVpAutoHDR);
404 bool CreateVideoSwapChain(DXGI_FORMAT aFormat);
405 bool CallVideoProcessorBlt();
406 void ReleaseDecodeSwapChainResources();
408 RefPtr<ID3D11VideoProcessorOutputView> mOutputView;
409 RefPtr<IDXGIResource> mDecodeResource;
410 RefPtr<IDXGISwapChain1> mVideoSwapChain;
411 RefPtr<IDXGIDecodeSwapChain> mDecodeSwapChain;
412 HANDLE mSwapChainSurfaceHandle = 0;
413 gfx::IntSize mVideoSize;
414 gfx::IntSize mSwapChainSize;
415 DXGI_FORMAT mSwapChainFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
416 bool mIsDRM = false;
417 bool mFailedYuvSwapChain = false;
418 RefPtr<RenderTextureHost> mRenderTextureHost;
419 RefPtr<RenderTextureHost> mPrevTexture;
420 RefPtr<RenderTextureHostUsageInfo> mRenderTextureHostUsageInfo;
421 int mSlowPresentCount = 0;
422 bool mFirstPresent = true;
423 const UINT mSwapChainBufferCount;
424 bool mUseVpAutoHDR = false;
425 bool mVpAutoHDRFailed = false;
426 bool mVpSuperResolutionFailed = false;
430 * A DC surface contains a IDCompositionSurface that is directly constructed by
431 * a handle. This is used by the Media Foundataion media engine, which would
432 * store the decoded video content in the surface.
434 class DCSurfaceHandle : public DCSurface {
435 public:
436 DCSurfaceHandle(bool aIsOpaque, DCLayerTree* aDCLayerTree);
437 ~DCSurfaceHandle() = default;
439 void AttachExternalImage(wr::ExternalImageId aExternalImage) override;
440 void PresentSurfaceHandle();
442 DCSurfaceHandle* AsDCSurfaceHandle() override { return this; }
444 protected:
445 HANDLE GetSurfaceHandle() const;
446 IDCompositionSurface* EnsureSurface();
448 RefPtr<RenderDcompSurfaceTextureHost> mDcompTextureHost;
451 class DCTile {
452 public:
453 gfx::IntRect mValidRect;
455 DCLayerTree* mDCLayerTree;
456 // Indicates that when the first BeginDraw occurs on the surface it must be
457 // full size - required by dcomp on non-virtual surfaces.
458 bool mNeedsFullDraw;
460 explicit DCTile(DCLayerTree* aDCLayerTree);
461 ~DCTile();
462 bool Initialize(int aX, int aY, wr::DeviceIntSize aSize,
463 bool aIsVirtualSurface, bool aIsOpaque,
464 RefPtr<IDCompositionVisual2> mSurfaceVisual);
465 RefPtr<IDCompositionSurface> Bind(wr::DeviceIntRect aValidRect);
466 IDCompositionVisual2* GetVisual() { return mVisual; }
468 protected:
469 // Size in pixels of this tile, some may be unused. Set by Initialize.
470 wr::DeviceIntSize mSize;
471 // Whether the tile is composited as opaque (ignores alpha) or transparent.
472 // Set by Initialize.
473 bool mIsOpaque;
474 // Some code paths differ based on whether parent surface is virtual.
475 bool mIsVirtualSurface;
476 // Visual that displays the composition surface, or NULL if the tile belongs
477 // to a virtual surface.
478 RefPtr<IDCompositionVisual2> mVisual;
479 // Surface for the visual, or NULL if the tile has not had its first Bind or
480 // belongs to a virtual surface.
481 RefPtr<IDCompositionSurface> mCompositionSurface;
483 RefPtr<IDCompositionSurface> CreateCompositionSurface(wr::DeviceIntSize aSize,
484 bool aIsOpaque);
487 static inline bool operator==(const DCSurface::TileKey& a0,
488 const DCSurface::TileKey& a1) {
489 return a0.mX == a1.mX && a0.mY == a1.mY;
492 } // namespace wr
493 } // namespace mozilla
495 #endif