/* 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 <windows.h>
#include <deque>
#include <dxgicommon.h>
#include <dxgiformat.h>
#include <unordered_map>
#include <vector>

#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/StaticPtr.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/webrender/WebRenderTypes.h"

struct ID3D11Device;
struct ID3D11DeviceContext;
struct ID3D11Texture2D;
struct ID3D11VideoDevice;
struct ID3D11VideoContext;
struct ID3D11VideoProcessor;
struct ID3D11VideoProcessorEnumerator;
struct ID3D11VideoProcessorOutputView;
struct IDCompositionColorMatrixEffect;
struct IDCompositionFilterEffect;
struct IDCompositionTableTransferEffect;
struct IDCompositionTexture;
struct IDCompositionDevice2;
struct IDCompositionDevice3;
struct IDCompositionSurface;
struct IDCompositionTarget;
struct IDCompositionVisual2;
struct IDXGIDecodeSwapChain;
struct IDXGIResource;
struct IDXGISwapChain1;
struct IDCompositionVirtualSurface;
struct IDCompositionRectangleClip;
struct ID3D11VertexShader;
struct ID3D11PixelShader;
struct ID3D10Blob;
typedef ID3D10Blob ID3DBlob;
struct D3D11_SHADER_RESOURCE_VIEW_DESC;
struct ID3D11Buffer;
struct ID3D11InputLayout;
struct ID3D11ShaderResourceView;
struct ID3D11RasterizerState;
struct ID3D11BlendState;
struct ID3D11SamplerState;

namespace mozilla {

namespace gfx {
color::ColorProfileDesc QueryOutputColorProfile();
}

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 DCLayerSurface;
class DCLayerDCompositionTexture;
class DCSurface;
class DCSwapChain;
class DCSurfaceDCompositionTextureOverlay;
class DCSurfaceVideo;
class DCSurfaceHandle;
class RenderTextureHost;
class RenderTextureHostUsageInfo;
class RenderDcompSurfaceTextureHost;

struct GpuOverlayInfo {
  bool mSupportsOverlays = false;
  bool mSupportsHardwareOverlays = false;
  bool mSupportsHardwareOverlayRGB10A2 = false;
  bool mSupportsHardwareOverlayRGBA16F = false;
  DXGI_FORMAT mOverlayFormatUsed = DXGI_FORMAT_B8G8R8A8_UNORM;
  DXGI_FORMAT mOverlayFormatUsedHdr = DXGI_FORMAT_R16G16B16A16_FLOAT;
  UINT mNv12OverlaySupportFlags = 0;
  UINT mYuy2OverlaySupportFlags = 0;
  UINT mBgra8OverlaySupportFlags = 0;
  UINT mRgb10a2OverlaySupportFlags = 0;
  UINT mRgba16fOverlaySupportFlags = 0;

  bool mSupportsVpSuperResolution = false;
  bool mSupportsVpAutoHDR = false;
  bool mSupportsHDR = false;
};

// -

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();
};

// -

enum class DCompOverlayTypes : uint8_t {
  NO_OVERLAY = 0,
  HARDWARE_DECODED_VIDEO = 1 << 0,
  SOFTWARE_DECODED_VIDEO = 1 << 1,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(DCompOverlayTypes)

// -

/**
 * 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,
                       HWND aHwnd, IDCompositionDevice2* aCompositionDevice);
  ~DCLayerTree();

  void SetDefaultSwapChain(IDXGISwapChain1* aSwapChain);
  void MaybeUpdateDebug();
  void MaybeCommit();
  void WaitForCommitCompletion();

  bool UseCompositor() const;
  bool UseLayerCompositor() const;
  void DisableNativeCompositor();
  bool EnableAsyncScreenshot();
  bool GetAsyncScreenshotEnabled() const { return mEnableAsyncScreenshot; }

  // 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 CreateSwapChainSurface(wr::NativeSurfaceId aId, wr::DeviceIntSize aSize,
                              bool aIsOpaque, bool aNeedsSyncDcompCommit);
  void ResizeSwapChainSurface(wr::NativeSurfaceId aId, wr::DeviceIntSize aSize);
  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,
                  wr::DeviceIntRect aRoundedClipRect,
                  wr::ClipRadius aClipRadius);
  void BindSwapChain(wr::NativeSurfaceId aId,
                     const wr::DeviceIntRect* aDirtyRects,
                     size_t aNumDirtyRects);
  void PresentSwapChain(wr::NativeSurfaceId aId,
                        const wr::DeviceIntRect* aDirtyRects,
                        size_t aNumDirtyRects);

  gl::GLContext* GetGLContext() const { return mGL; }
  EGLConfig GetEGLConfig() const { return mEGLConfig; }
  ID3D11Device* GetDevice() const { return mDevice; }
  ID3D11DeviceContext* GetDeviceContext() const { return mCtx; }
  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;

  HWND GetHwnd() const { return mHwnd; }

  // Get or create an FBO with depth buffer suitable for specified dimensions
  GLuint GetOrCreateFbo(int aWidth, int aHeight);

  bool SupportsHardwareOverlays();
  bool SupportsHardwareOverlayRGB10A2();
  bool SupportsHardwareOverlayRGBA16F();
  DXGI_FORMAT GetOverlayFormatForSDR();

  bool SupportsSwapChainTearing();
  bool UseDCLayerDCompositionTexture();

  void SetUsedOverlayTypeInFrame(DCompOverlayTypes aTypes);

  int GetFrameId() { return mCurrentFrame; }

  void SetPendingCommit() { mPendingCommit = true; }

 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();

  enum class WebRenderOsCompositorKind {
    LayerCompositor,
  };

  Maybe<WebRenderOsCompositorKind> mCompositorKind;
  bool mEnableAsyncScreenshot = false;
  bool mEnableAsyncScreenshotInNextFrame = false;
  int mAsyncScreenshotLastFrameUsed = 0;

  RefPtr<gl::GLContext> mGL;
  EGLConfig mEGLConfig;

  RefPtr<ID3D11Device> mDevice;
  RefPtr<ID3D11DeviceContext> mCtx;
  HWND mHwnd;

  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;

  // 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;

  mutable Maybe<color::ColorProfileDesc> mOutputColorProfile;

  DCompOverlayTypes mUsedOverlayTypesInFrame = DCompOverlayTypes::NO_OVERLAY;

 public:
  const color::ColorProfileDesc& OutputColorProfile() const {
    if (!mOutputColorProfile) {
      mOutputColorProfile = Some(gfx::QueryOutputColorProfile());
    }
    return *mOutputColorProfile;
  }

 protected:
  static StaticAutoPtr<GpuOverlayInfo> sGpuOverlayInfo;
};

/**
 Represents a single picture cache slice.
 */
class DCSurface {
 public:
  explicit DCSurface(bool aIsOpaque, DCLayerTree* aDCLayerTree);
  virtual ~DCSurface();

  virtual bool Initialize();
  void SetClip(wr::DeviceIntRect aClipRect, wr::ClipRadius aClipRadius);

  IDCompositionVisual2* GetContentVisual() const { return mContentVisual; }
  IDCompositionVisual2* GetRootVisual() const { return mRootVisual; }

  // 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; }
  virtual DCLayerSurface* AsDCLayerSurface() { return nullptr; }
  virtual DCSwapChain* AsDCSwapChain() { return nullptr; }
  virtual DCLayerDCompositionTexture* AsDCLayerDCompositionTexture() {
    return nullptr;
  }
  virtual DCSurfaceDCompositionTextureOverlay*
  AsDCSurfaceDCompositionTextureOverlay() {
    return nullptr;
  }

  bool IsUpdated(const wr::CompositorSurfaceTransform& aTransform,
                 const wr::DeviceIntRect& aClipRect,
                 const wr::ImageRendering aImageRendering,
                 const wr::DeviceIntRect& aRoundedClipRect,
                 const wr::ClipRadius& aClipRadius);

 protected:
  DCLayerTree* mDCLayerTree;

  struct DCSurfaceData {
    DCSurfaceData(const wr::CompositorSurfaceTransform& aTransform,
                  const wr::DeviceIntRect& aClipRect,
                  const wr::ImageRendering aImageRendering,
                  const wr::DeviceIntRect& aRoundedClipRect,
                  const wr::ClipRadius& aClipRadius)
        : mTransform(aTransform),
          mClipRect(aClipRect),
          mImageRendering(aImageRendering),
          mRoundedClipRect(aRoundedClipRect),
          mClipRadius(aClipRadius) {}

    wr::CompositorSurfaceTransform mTransform;
    wr::DeviceIntRect mClipRect;
    wr::ImageRendering mImageRendering;
    wr::DeviceIntRect mRoundedClipRect;
    wr::ClipRadius mClipRadius;
  };

  // Each surface creates two visuals. The root is where it gets attached
  // to parent visuals, the content is where surface (or child visuals)
  // get attached. Most of the time, the root visual does nothing, but
  // in the case of a complex clip, we attach the clip here. This allows
  // us to implement the simple rectangle clip on the content, and apply
  // the complex clip, if present, in a way that it's not affected by
  // the transform of the content visual.

  RefPtr<IDCompositionVisual2> mRootVisual;
  RefPtr<IDCompositionVisual2> mContentVisual;
  RefPtr<IDCompositionRectangleClip> mClip;

  bool mIsOpaque;
  Maybe<DCSurfaceData> mDCSurfaceData;
};

class DCLayerSurface : public DCSurface {
 public:
  DCLayerSurface(bool aIsOpaque, DCLayerTree* aDCLayerTree)
      : DCSurface(aIsOpaque, aDCLayerTree) {}
  virtual ~DCLayerSurface() = default;

  virtual void Bind(const wr::DeviceIntRect* aDirtyRects,
                    size_t aNumDirtyRects) = 0;
  virtual bool Resize(wr::DeviceIntSize aSize) = 0;
  virtual void Present(const wr::DeviceIntRect* aDirtyRects,
                       size_t aNumDirtyRects) = 0;

  DCLayerSurface* AsDCLayerSurface() override { return this; }
};

class DCLayerDCompositionTexture : public DCLayerSurface {
 public:
  DCLayerDCompositionTexture(wr::DeviceIntSize aSize, bool aIsOpaque,
                             DCLayerTree* aDCLayerTree);
  virtual ~DCLayerDCompositionTexture();

  bool Initialize() override;

  void Bind(const wr::DeviceIntRect* aDirtyRects,
            size_t aNumDirtyRects) override;
  bool Resize(wr::DeviceIntSize aSize) override;
  void Present(const wr::DeviceIntRect* aDirtyRects,
               size_t aNumDirtyRects) override;

  DCLayerDCompositionTexture* AsDCLayerDCompositionTexture() override {
    return this;
  }

  const size_t mSwapChainBufferCount;

 private:
  struct TextureHolder {
    TextureHolder(ID3D11Texture2D* aTexture,
                  IDCompositionTexture* aDCompositionTexture,
                  EGLSurface aEGLSurface);
    TextureHolder() = default;

    RefPtr<ID3D11Texture2D> mTexture;
    RefPtr<IDCompositionTexture> mDCompositionTexture;
    EGLSurface mEGLSurface;
  };

  bool AllocateTextures();
  void DestroyTextures();
  UniquePtr<TextureHolder> GetNextTexture();
  void UpdateCurrentTexture();

  wr::DeviceIntSize mSize;
  std::deque<UniquePtr<TextureHolder>> mAvailableTextureHolders;

  UniquePtr<TextureHolder> mCurrentTextureHolder;
  UniquePtr<TextureHolder> mPresentingTextureHolder;
};

class DCSwapChain : public DCLayerSurface {
 public:
  DCSwapChain(wr::DeviceIntSize aSize, bool aIsOpaque,
              DCLayerTree* aDCLayerTree);
  virtual ~DCSwapChain();

  bool Initialize() override;

  void Bind(const wr::DeviceIntRect* aDirtyRects,
            size_t aNumDirtyRects) override;
  bool Resize(wr::DeviceIntSize aSize) override;
  void Present(const wr::DeviceIntRect* aDirtyRects,
               size_t aNumDirtyRects) override;

  DCSwapChain* AsDCSwapChain() override { return this; }

  const int mSwapChainBufferCount;

 private:
  wr::DeviceIntSize mSize;
  RefPtr<IDXGISwapChain1> mSwapChain;
  EGLSurface mEGLSurface;
  bool mFirstPresent = true;
};

class DCLayerCompositionSurface : public DCLayerSurface {
 public:
  DCLayerCompositionSurface(wr::DeviceIntSize aSize, bool aIsOpaque,
                            DCLayerTree* aDCLayerTree);
  virtual ~DCLayerCompositionSurface();

  bool Initialize() override;

  void Bind(const wr::DeviceIntRect* aDirtyRects,
            size_t aNumDirtyRects) override;
  bool Resize(wr::DeviceIntSize aSize) override;
  void Present(const wr::DeviceIntRect* aDirtyRects,
               size_t aNumDirtyRects) override;

 private:
  wr::DeviceIntSize mSize;
  EGLSurface mEGLSurface = EGL_NO_SURFACE;
  RefPtr<IDCompositionSurface> mCompositionSurface;
  bool mFirstDraw = true;
};

/**
 * A wrapper surface which can contain either a DCVideo or a DCSurfaceHandle.
 */
class DCExternalSurfaceWrapper : public DCSurface {
 public:
  DCExternalSurfaceWrapper(bool aIsOpaque, DCLayerTree* aDCLayerTree)
      : DCSurface(false /* opaque */, aDCLayerTree), mIsOpaque(aIsOpaque) {}
  virtual ~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;
  }

  DCSurfaceDCompositionTextureOverlay* AsDCSurfaceDCompositionTextureOverlay()
      override {
    return mSurface ? mSurface->AsDCSurfaceDCompositionTextureOverlay()
                    : nullptr;
  }

 private:
  DCSurface* EnsureSurfaceForExternalImage(wr::ExternalImageId aExternalImage);

  UniquePtr<DCSurface> mSurface;
  const bool mIsOpaque;
  Maybe<ColorManagementChain> mCManageChain;
};

class DCSurfaceDCompositionTextureOverlay : public DCSurface {
 public:
  DCSurfaceDCompositionTextureOverlay(bool aIsOpaque,
                                      DCLayerTree* aDCLayerTree);

  void AttachExternalImage(wr::ExternalImageId aExternalImage) override;
  void Present();

  DCSurfaceDCompositionTextureOverlay* AsDCSurfaceDCompositionTextureOverlay()
      override {
    return this;
  }

 protected:
  virtual ~DCSurfaceDCompositionTextureOverlay();

  RefPtr<RenderTextureHost> mRenderTextureHost;
  RefPtr<RenderTextureHost> mPrevRenderTextureHost;
  int mSlowGetCount = 0;
};

class DCSurfaceVideo : public DCSurface {
 public:
  DCSurfaceVideo(bool aIsOpaque, DCLayerTree* aDCLayerTree);

  void AttachExternalImage(wr::ExternalImageId aExternalImage) override;
  bool CalculateSwapChainSize(gfx::Matrix& aTransform);
  void PresentVideo();
  void OnCompositorEndFrame(int aFrameId, uint32_t aDurationMs);

  DCSurfaceVideo* AsDCSurfaceVideo() override { return this; }

 protected:
  virtual ~DCSurfaceVideo();

  DXGI_FORMAT GetSwapChainFormat(bool aUseVpAutoHDR, bool aUseRGB10A2,
                                 bool aUseRGBA16F);
  bool CreateVideoSwapChain(DXGI_FORMAT aFormat);
  bool CallVideoProcessorBlt();
  bool ShaderBltSetup();
  bool ShaderBlt(DXGI_COLOR_SPACE_TYPE inputColorSpace, const RECT& sourceRect,
                 DXGI_COLOR_SPACE_TYPE outputColorSpace, const RECT& destRect);
  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 mIsDRM = false;
  bool mFailedYuvSwapChain = false;
  // Indicates if VideoProcessorBlt is unable to convert YUV HLG to RGB PQ.
  bool mFailedVideoProcessorBltYUVHLGToRGBPQ = false;
  // Indicates if VideoProcessorBlt is unable to convert YUV PQ to RGB PQ.
  bool mFailedVideoProcessorBltYUVPQtoRGBPQ = false;
  RefPtr<RenderTextureHost> mRenderTextureHost;
  RefPtr<RenderTextureHost> mPrevTexture;
  RefPtr<RenderTextureHostUsageInfo> mRenderTextureHostUsageInfo;
  bool mFirstPresent = true;
  const UINT mSwapChainBufferCount;
  bool mUseVpAutoHDR = false;
  bool mVpAutoHDRFailed = false;
  bool mVpSuperResolutionFailed = false;
  bool mContentIsHDR = false;
  bool mUseHDR = false;
  RefPtr<ID3D11VertexShader> mShaderBltVertexShader;
  RefPtr<ID3DBlob> mShaderBltVSBlob;
  RefPtr<ID3D11PixelShader> mShaderBltPixelShader;
  RefPtr<ID3DBlob> mShaderBltPSBlob;
  RefPtr<ID3D11Buffer> mShaderBltIndexBuffer;
  RefPtr<ID3D11Buffer> mShaderBltVertexBuffer;
  RefPtr<ID3D11InputLayout> mShaderBltInputLayout;
  RefPtr<ID3D11RasterizerState> mShaderBltRasterizerState;
  RefPtr<ID3D11BlendState> mShaderBltBlendState;
  RefPtr<ID3D11Buffer> mShaderBltConstantBuffer;
  RefPtr<ID3D11SamplerState> mShaderBltSamplerState;
};

/**
 * 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);
  virtual ~DCSurfaceHandle() = default;

  void AttachExternalImage(wr::ExternalImageId aExternalImage) override;
  void PresentSurfaceHandle();

  DCSurfaceHandle* AsDCSurfaceHandle() override { return this; }

 protected:
  HANDLE GetSurfaceHandle() const;
  IDCompositionSurface* EnsureSurface();

  RefPtr<RenderDcompSurfaceTextureHost> mDcompTextureHost;
};

}  // namespace wr
}  // namespace mozilla

#endif
