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>
15 #include "Colorspaces.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"
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
;
42 struct IDXGISwapChain1
;
43 struct IDCompositionVirtualSurface
;
53 // The size of the virtual surface. This is large enough such that we
54 // will never render a surface larger than this.
55 #define VIRTUAL_SURFACE_SIZE (1024 * 1024)
60 class DCSurfaceHandle
;
61 class RenderTextureHost
;
62 class RenderDcompSurfaceTextureHost
;
64 struct GpuOverlayInfo
{
65 bool mSupportsOverlays
= false;
66 bool mSupportsHardwareOverlays
= false;
67 DXGI_FORMAT mOverlayFormatUsed
= DXGI_FORMAT_B8G8R8A8_UNORM
;
68 DXGI_FORMAT mOverlayFormatUsedHdr
= DXGI_FORMAT_R10G10B10A2_UNORM
;
69 UINT mNv12OverlaySupportFlags
= 0;
70 UINT mYuy2OverlaySupportFlags
= 0;
71 UINT mBgra8OverlaySupportFlags
= 0;
72 UINT mRgb10a2OverlaySupportFlags
= 0;
77 struct ColorManagementChain
{
78 RefPtr
<IDCompositionColorMatrixEffect
> srcRgbFromSrcYuv
;
79 RefPtr
<IDCompositionTableTransferEffect
> srcLinearFromSrcTf
;
80 RefPtr
<IDCompositionColorMatrixEffect
> dstLinearFromSrcLinear
;
81 RefPtr
<IDCompositionTableTransferEffect
> dstTfFromDstLinear
;
82 RefPtr
<IDCompositionFilterEffect
> last
;
84 static ColorManagementChain
From(IDCompositionDevice3
& dcomp
,
85 const color::ColorProfileConversionDesc
&);
87 ~ColorManagementChain();
92 enum class DCompOverlayTypes
: uint8_t {
94 HARDWARE_DECODED_VIDEO
= 1 << 0,
95 SOFTWARE_DECODED_VIDEO
= 1 << 1,
97 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(DCompOverlayTypes
)
102 * DCLayerTree manages direct composition layers.
103 * It does not manage gecko's layers::Layer.
107 static UniquePtr
<DCLayerTree
> Create(gl::GLContext
* aGL
, EGLConfig aEGLConfig
,
108 ID3D11Device
* aDevice
,
109 ID3D11DeviceContext
* aCtx
, HWND aHwnd
,
112 static void Shutdown();
114 explicit DCLayerTree(gl::GLContext
* aGL
, EGLConfig aEGLConfig
,
115 ID3D11Device
* aDevice
, ID3D11DeviceContext
* aCtx
,
116 IDCompositionDevice2
* aCompositionDevice
);
119 void SetDefaultSwapChain(IDXGISwapChain1
* aSwapChain
);
120 void MaybeUpdateDebug();
122 void WaitForCommitCompletion();
123 void DisableNativeCompositor();
125 // Interface for wr::Compositor
126 void CompositorBeginFrame();
127 void CompositorEndFrame();
128 void Bind(wr::NativeTileId aId
, wr::DeviceIntPoint
* aOffset
, uint32_t* aFboId
,
129 wr::DeviceIntRect aDirtyRect
, wr::DeviceIntRect aValidRect
);
131 void CreateSurface(wr::NativeSurfaceId aId
, wr::DeviceIntPoint aVirtualOffset
,
132 wr::DeviceIntSize aTileSize
, bool aIsOpaque
);
133 void CreateExternalSurface(wr::NativeSurfaceId aId
, bool aIsOpaque
);
134 void DestroySurface(NativeSurfaceId aId
);
135 void CreateTile(wr::NativeSurfaceId aId
, int32_t aX
, int32_t aY
);
136 void DestroyTile(wr::NativeSurfaceId aId
, int32_t aX
, int32_t aY
);
137 void AttachExternalImage(wr::NativeSurfaceId aId
,
138 wr::ExternalImageId aExternalImage
);
139 void AddSurface(wr::NativeSurfaceId aId
,
140 const wr::CompositorSurfaceTransform
& aTransform
,
141 wr::DeviceIntRect aClipRect
,
142 wr::ImageRendering aImageRendering
);
144 gl::GLContext
* GetGLContext() const { return mGL
; }
145 EGLConfig
GetEGLConfig() const { return mEGLConfig
; }
146 ID3D11Device
* GetDevice() const { return mDevice
; }
147 ID3D11DeviceContext
* GetDeviceContext() const { return mCtx
; }
148 IDCompositionDevice2
* GetCompositionDevice() const {
149 return mCompositionDevice
;
151 ID3D11VideoDevice
* GetVideoDevice() const { return mVideoDevice
; }
152 ID3D11VideoContext
* GetVideoContext() const { return mVideoContext
; }
153 ID3D11VideoProcessor
* GetVideoProcessor() const { return mVideoProcessor
; }
154 ID3D11VideoProcessorEnumerator
* GetVideoProcessorEnumerator() const {
155 return mVideoProcessorEnumerator
;
157 bool EnsureVideoProcessor(const gfx::IntSize
& aInputSize
,
158 const gfx::IntSize
& aOutputSize
);
160 DCSurface
* GetSurface(wr::NativeSurfaceId aId
) const;
162 // Get or create an FBO with depth buffer suitable for specified dimensions
163 GLuint
GetOrCreateFbo(int aWidth
, int aHeight
);
165 bool SupportsHardwareOverlays();
166 DXGI_FORMAT
GetOverlayFormatForSDR();
168 bool SupportsSwapChainTearing();
170 void SetUsedOverlayTypeInFrame(DCompOverlayTypes aTypes
);
173 bool Initialize(HWND aHwnd
, nsACString
& aError
);
174 bool InitializeVideoOverlaySupport();
175 bool MaybeUpdateDebugCounter();
176 bool MaybeUpdateDebugVisualRedrawRegions();
177 void DestroyEGLSurface();
178 GLuint
CreateEGLSurfaceForCompositionSurface(
179 wr::DeviceIntRect aDirtyRect
, wr::DeviceIntPoint
* aOffset
,
180 RefPtr
<IDCompositionSurface
> aCompositionSurface
,
181 wr::DeviceIntPoint aSurfaceOffset
);
182 void ReleaseNativeCompositorResources();
183 layers::OverlayInfo
GetOverlayInfo();
185 RefPtr
<gl::GLContext
> mGL
;
186 EGLConfig mEGLConfig
;
188 RefPtr
<ID3D11Device
> mDevice
;
189 RefPtr
<ID3D11DeviceContext
> mCtx
;
191 RefPtr
<IDCompositionDevice2
> mCompositionDevice
;
192 RefPtr
<IDCompositionTarget
> mCompositionTarget
;
193 RefPtr
<IDCompositionVisual2
> mRootVisual
;
194 RefPtr
<IDCompositionVisual2
> mDefaultSwapChainVisual
;
196 RefPtr
<ID3D11VideoDevice
> mVideoDevice
;
197 RefPtr
<ID3D11VideoContext
> mVideoContext
;
198 RefPtr
<ID3D11VideoProcessor
> mVideoProcessor
;
199 RefPtr
<ID3D11VideoProcessorEnumerator
> mVideoProcessorEnumerator
;
200 gfx::IntSize mVideoInputSize
;
201 gfx::IntSize mVideoOutputSize
;
204 bool mDebugVisualRedrawRegions
;
206 Maybe
<RefPtr
<IDCompositionSurface
>> mCurrentSurface
;
208 // The EGL image that is bound to the D3D texture provided by
209 // DirectComposition.
212 // The GL render buffer ID that maps the EGLImage to an RBO for attaching to
216 struct SurfaceIdHashFn
{
217 std::size_t operator()(const wr::NativeSurfaceId
& aId
) const {
218 return HashGeneric(wr::AsUint64(aId
));
222 std::unordered_map
<wr::NativeSurfaceId
, UniquePtr
<DCSurface
>, SurfaceIdHashFn
>
225 // A list of layer IDs as they are added to the visual tree this frame.
226 std::vector
<wr::NativeSurfaceId
> mCurrentLayers
;
228 // The previous frame's list of layer IDs in visual order.
229 std::vector
<wr::NativeSurfaceId
> mPrevLayers
;
231 // Information about a cached FBO that is retained between frames.
232 struct CachedFrameBuffer
{
240 // A cache of FBOs, containing a depth buffer allocated to a specific size.
241 // TODO(gw): Might be faster as a hashmap? The length is typically much less
243 nsTArray
<CachedFrameBuffer
> mFrameBuffers
;
244 int mCurrentFrame
= 0;
248 static color::ColorProfileDesc
QueryOutputColorProfile();
250 mutable Maybe
<color::ColorProfileDesc
> mOutputColorProfile
;
252 DCompOverlayTypes mUsedOverlayTypesInFrame
= DCompOverlayTypes::NO_OVERLAY
;
253 int mSlowCommitCount
= 0;
256 const color::ColorProfileDesc
& OutputColorProfile() const {
257 if (!mOutputColorProfile
) {
258 mOutputColorProfile
= Some(QueryOutputColorProfile());
260 return *mOutputColorProfile
;
264 static StaticAutoPtr
<GpuOverlayInfo
> sGpuOverlayInfo
;
268 Represents a single picture cache slice. Each surface contains some
269 number of tiles. An implementation may choose to allocate individual
270 tiles to render in to (as the current impl does), or allocate a large
271 single virtual surface to draw into (e.g. the DirectComposition virtual
272 surface API in future).
276 const bool mIsVirtualSurface
;
278 explicit DCSurface(wr::DeviceIntSize aTileSize
,
279 wr::DeviceIntPoint aVirtualOffset
, bool aIsVirtualSurface
,
280 bool aIsOpaque
, DCLayerTree
* aDCLayerTree
);
281 virtual ~DCSurface();
284 void CreateTile(int32_t aX
, int32_t aY
);
285 void DestroyTile(int32_t aX
, int32_t aY
);
287 IDCompositionVisual2
* GetVisual() const { return mVisual
; }
288 DCTile
* GetTile(int32_t aX
, int32_t aY
) const;
291 TileKey(int32_t aX
, int32_t aY
) : mX(aX
), mY(aY
) {}
297 wr::DeviceIntSize
GetTileSize() const { return mTileSize
; }
298 wr::DeviceIntPoint
GetVirtualOffset() const { return mVirtualOffset
; }
300 IDCompositionVirtualSurface
* GetCompositionSurface() const {
301 return mVirtualSurface
;
304 void UpdateAllocatedRect();
305 void DirtyAllocatedRect();
307 // Implement these if the inherited surface supports attaching external image.
308 virtual void AttachExternalImage(wr::ExternalImageId aExternalImage
) {
309 MOZ_RELEASE_ASSERT(true, "Not support attaching external image");
311 virtual void PresentExternalSurface(gfx::Matrix
& aTransform
) {
312 MOZ_RELEASE_ASSERT(true, "Not support presenting external surface");
315 virtual DCSurfaceVideo
* AsDCSurfaceVideo() { return nullptr; }
316 virtual DCSurfaceHandle
* AsDCSurfaceHandle() { return nullptr; }
319 DCLayerTree
* mDCLayerTree
;
321 struct TileKeyHashFn
{
322 std::size_t operator()(const TileKey
& aId
) const {
323 return HashGeneric(aId
.mX
, aId
.mY
);
327 // The visual for this surface. No content is attached to here, but tiles
328 // that belong to this surface are added as children. In this way, we can
329 // set the clip and scroll offset once, on this visual, to affect all
332 // However when using a virtual surface, it is directly attached to this
333 // visual and the tiles do not own visuals.
335 // Whether mIsVirtualSurface is enabled is decided at DCSurface creation
336 // time based on the pref gfx.webrender.dcomp-use-virtual-surfaces
337 RefPtr
<IDCompositionVisual2
> mVisual
;
339 wr::DeviceIntSize mTileSize
;
341 bool mAllocatedRectDirty
;
342 std::unordered_map
<TileKey
, UniquePtr
<DCTile
>, TileKeyHashFn
> mDCTiles
;
343 wr::DeviceIntPoint mVirtualOffset
;
344 RefPtr
<IDCompositionVirtualSurface
> mVirtualSurface
;
348 * A wrapper surface which can contain either a DCVideo or a DCSurfaceHandle.
350 class DCExternalSurfaceWrapper
: public DCSurface
{
352 DCExternalSurfaceWrapper(bool aIsOpaque
, DCLayerTree
* aDCLayerTree
)
353 : DCSurface(wr::DeviceIntSize
{}, wr::DeviceIntPoint
{},
354 false /* virtual surface */, false /* opaque */,
356 mIsOpaque(aIsOpaque
) {}
357 ~DCExternalSurfaceWrapper() = default;
359 void AttachExternalImage(wr::ExternalImageId aExternalImage
) override
;
361 void PresentExternalSurface(gfx::Matrix
& aTransform
) override
;
363 DCSurfaceVideo
* AsDCSurfaceVideo() override
{
364 return mSurface
? mSurface
->AsDCSurfaceVideo() : nullptr;
367 DCSurfaceHandle
* AsDCSurfaceHandle() override
{
368 return mSurface
? mSurface
->AsDCSurfaceHandle() : nullptr;
372 DCSurface
* EnsureSurfaceForExternalImage(wr::ExternalImageId aExternalImage
);
374 UniquePtr
<DCSurface
> mSurface
;
375 const bool mIsOpaque
;
376 Maybe
<ColorManagementChain
> mCManageChain
;
379 class DCSurfaceVideo
: public DCSurface
{
381 DCSurfaceVideo(bool aIsOpaque
, DCLayerTree
* aDCLayerTree
);
383 void AttachExternalImage(wr::ExternalImageId aExternalImage
) override
;
384 bool CalculateSwapChainSize(gfx::Matrix
& aTransform
);
387 DCSurfaceVideo
* AsDCSurfaceVideo() override
{ return this; }
390 virtual ~DCSurfaceVideo();
392 DXGI_FORMAT
GetSwapChainFormat(bool aUseVpAutoHDR
);
393 bool CreateVideoSwapChain(DXGI_FORMAT aFormat
);
394 bool CallVideoProcessorBlt();
395 void ReleaseDecodeSwapChainResources();
397 RefPtr
<ID3D11VideoProcessorOutputView
> mOutputView
;
398 RefPtr
<IDXGIResource
> mDecodeResource
;
399 RefPtr
<IDXGISwapChain1
> mVideoSwapChain
;
400 RefPtr
<IDXGIDecodeSwapChain
> mDecodeSwapChain
;
401 HANDLE mSwapChainSurfaceHandle
= 0;
402 gfx::IntSize mVideoSize
;
403 gfx::IntSize mSwapChainSize
;
404 DXGI_FORMAT mSwapChainFormat
= DXGI_FORMAT_B8G8R8A8_UNORM
;
406 bool mFailedYuvSwapChain
= false;
407 RefPtr
<RenderTextureHost
> mRenderTextureHost
;
408 RefPtr
<RenderTextureHost
> mPrevTexture
;
409 int mSlowPresentCount
= 0;
410 bool mFirstPresent
= true;
411 const UINT mSwapChainBufferCount
;
412 bool mUseVpAutoHDR
= false;
413 bool mVpAutoHDRFailed
= false;
414 bool mVpSuperResolutionFailed
= false;
418 * A DC surface contains a IDCompositionSurface that is directly constructed by
419 * a handle. This is used by the Media Foundataion media engine, which would
420 * store the decoded video content in the surface.
422 class DCSurfaceHandle
: public DCSurface
{
424 DCSurfaceHandle(bool aIsOpaque
, DCLayerTree
* aDCLayerTree
);
425 ~DCSurfaceHandle() = default;
427 void AttachExternalImage(wr::ExternalImageId aExternalImage
) override
;
428 void PresentSurfaceHandle();
430 DCSurfaceHandle
* AsDCSurfaceHandle() override
{ return this; }
433 HANDLE
GetSurfaceHandle() const;
434 IDCompositionSurface
* EnsureSurface();
436 RefPtr
<RenderDcompSurfaceTextureHost
> mDcompTextureHost
;
441 gfx::IntRect mValidRect
;
443 DCLayerTree
* mDCLayerTree
;
444 // Indicates that when the first BeginDraw occurs on the surface it must be
445 // full size - required by dcomp on non-virtual surfaces.
448 explicit DCTile(DCLayerTree
* aDCLayerTree
);
450 bool Initialize(int aX
, int aY
, wr::DeviceIntSize aSize
,
451 bool aIsVirtualSurface
, bool aIsOpaque
,
452 RefPtr
<IDCompositionVisual2
> mSurfaceVisual
);
453 RefPtr
<IDCompositionSurface
> Bind(wr::DeviceIntRect aValidRect
);
454 IDCompositionVisual2
* GetVisual() { return mVisual
; }
457 // Size in pixels of this tile, some may be unused. Set by Initialize.
458 wr::DeviceIntSize mSize
;
459 // Whether the tile is composited as opaque (ignores alpha) or transparent.
460 // Set by Initialize.
462 // Some code paths differ based on whether parent surface is virtual.
463 bool mIsVirtualSurface
;
464 // Visual that displays the composition surface, or NULL if the tile belongs
465 // to a virtual surface.
466 RefPtr
<IDCompositionVisual2
> mVisual
;
467 // Surface for the visual, or NULL if the tile has not had its first Bind or
468 // belongs to a virtual surface.
469 RefPtr
<IDCompositionSurface
> mCompositionSurface
;
471 RefPtr
<IDCompositionSurface
> CreateCompositionSurface(wr::DeviceIntSize aSize
,
475 static inline bool operator==(const DCSurface::TileKey
& a0
,
476 const DCSurface::TileKey
& a1
) {
477 return a0
.mX
== a1
.mX
&& a0
.mY
== a1
.mY
;
481 } // namespace mozilla