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
;
48 color::ColorProfileDesc
QueryOutputColorProfile();
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)
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;
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();
100 enum class DCompOverlayTypes
: uint8_t {
102 HARDWARE_DECODED_VIDEO
= 1 << 0,
103 SOFTWARE_DECODED_VIDEO
= 1 << 1,
105 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(DCompOverlayTypes
)
110 * DCLayerTree manages direct composition layers.
111 * It does not manage gecko's layers::Layer.
115 static UniquePtr
<DCLayerTree
> Create(gl::GLContext
* aGL
, EGLConfig aEGLConfig
,
116 ID3D11Device
* aDevice
,
117 ID3D11DeviceContext
* aCtx
, HWND aHwnd
,
120 static void Shutdown();
122 explicit DCLayerTree(gl::GLContext
* aGL
, EGLConfig aEGLConfig
,
123 ID3D11Device
* aDevice
, ID3D11DeviceContext
* aCtx
,
124 HWND aHwnd
, IDCompositionDevice2
* aCompositionDevice
);
127 void SetDefaultSwapChain(IDXGISwapChain1
* aSwapChain
);
128 void MaybeUpdateDebug();
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
);
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
);
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
;
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
;
215 bool mDebugVisualRedrawRegions
;
217 Maybe
<RefPtr
<IDCompositionSurface
>> mCurrentSurface
;
219 // The EGL image that is bound to the D3D texture provided by
220 // DirectComposition.
223 // The GL render buffer ID that maps the EGLImage to an RBO for attaching to
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
>
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
{
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
254 nsTArray
<CachedFrameBuffer
> mFrameBuffers
;
255 int mCurrentFrame
= 0;
259 mutable Maybe
<color::ColorProfileDesc
> mOutputColorProfile
;
261 DCompOverlayTypes mUsedOverlayTypesInFrame
= DCompOverlayTypes::NO_OVERLAY
;
262 int mSlowCommitCount
= 0;
265 const color::ColorProfileDesc
& OutputColorProfile() const {
266 if (!mOutputColorProfile
) {
267 mOutputColorProfile
= Some(gfx::QueryOutputColorProfile());
269 return *mOutputColorProfile
;
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).
285 const bool mIsVirtualSurface
;
287 explicit DCSurface(wr::DeviceIntSize aTileSize
,
288 wr::DeviceIntPoint aVirtualOffset
, bool aIsVirtualSurface
,
289 bool aIsOpaque
, DCLayerTree
* aDCLayerTree
);
290 virtual ~DCSurface();
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;
300 TileKey(int32_t aX
, int32_t aY
) : mX(aX
), mY(aY
) {}
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; }
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
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
;
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
{
361 DCExternalSurfaceWrapper(bool aIsOpaque
, DCLayerTree
* aDCLayerTree
)
362 : DCSurface(wr::DeviceIntSize
{}, wr::DeviceIntPoint
{},
363 false /* virtual surface */, false /* opaque */,
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;
381 DCSurface
* EnsureSurfaceForExternalImage(wr::ExternalImageId aExternalImage
);
383 UniquePtr
<DCSurface
> mSurface
;
384 const bool mIsOpaque
;
385 Maybe
<ColorManagementChain
> mCManageChain
;
388 class DCSurfaceVideo
: public DCSurface
{
390 DCSurfaceVideo(bool aIsOpaque
, DCLayerTree
* aDCLayerTree
);
392 void AttachExternalImage(wr::ExternalImageId aExternalImage
) override
;
393 bool CalculateSwapChainSize(gfx::Matrix
& aTransform
);
396 DCSurfaceVideo
* AsDCSurfaceVideo() override
{ return this; }
398 void DisableVideoOverlay();
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
;
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
{
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; }
445 HANDLE
GetSurfaceHandle() const;
446 IDCompositionSurface
* EnsureSurface();
448 RefPtr
<RenderDcompSurfaceTextureHost
> mDcompTextureHost
;
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.
460 explicit DCTile(DCLayerTree
* aDCLayerTree
);
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
; }
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.
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
,
487 static inline bool operator==(const DCSurface::TileKey
& a0
,
488 const DCSurface::TileKey
& a1
) {
489 return a0
.mX
== a1
.mX
&& a0
.mY
== a1
.mY
;
493 } // namespace mozilla