/* -*- 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_TEXTURED3D11_H #define MOZILLA_GFX_TEXTURED3D11_H #include #include #include #include "d3d9.h" #include "gfxWindowsPlatform.h" #include "mozilla/DataMutex.h" #include "mozilla/GfxMessageUtils.h" #include "mozilla/Maybe.h" #include "mozilla/gfx/2D.h" #include "mozilla/layers/Compositor.h" #include "mozilla/layers/SyncObject.h" #include "mozilla/layers/TextureClient.h" #include "mozilla/layers/TextureHost.h" namespace mozilla { namespace gfx { class FileHandleWrapper; struct FenceInfo; } // namespace gfx namespace gl { class GLBlitHelper; } namespace layers { already_AddRefed CreateTextureHostD3D11( const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator, LayersBackend aBackend, TextureFlags aFlags); class MOZ_RAII AutoTextureLock final { public: AutoTextureLock(IDXGIKeyedMutex* aMutex, HRESULT& aResult, uint32_t aTimeout = 0); ~AutoTextureLock(); private: RefPtr mMutex; HRESULT mResult; }; class CompositorD3D11; class IMFSampleUsageInfo; class D3D11TextureData final : public TextureData { public: // If aDevice is null, use one provided by gfxWindowsPlatform. static D3D11TextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, TextureAllocationFlags aAllocFlags, ID3D11Device* aDevice = nullptr); static D3D11TextureData* Create(gfx::SourceSurface* aSurface, TextureAllocationFlags aAllocFlags, ID3D11Device* aDevice = nullptr); static already_AddRefed CreateTextureClient( ID3D11Texture2D* aTexture, uint32_t aIndex, gfx::IntSize aSize, gfx::SurfaceFormat aFormat, gfx::ColorSpace2 aColorSpace, gfx::ColorRange aColorRange, KnowsCompositor* aKnowsCompositor, RefPtr aUsageInfo); virtual ~D3D11TextureData(); bool UpdateFromSurface(gfx::SourceSurface* aSurface) override; bool Lock(OpenMode aMode) override; void Unlock() override; already_AddRefed BorrowDrawTarget() override; TextureData* CreateSimilar(LayersIPCChannel* aAllocator, LayersBackend aLayersBackend, TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const override; void SyncWithObject(RefPtr aSyncObject) override; ID3D11Texture2D* GetD3D11Texture() const { return mTexture; } void Deallocate(LayersIPCChannel* aAllocator) override; D3D11TextureData* AsD3D11TextureData() override { return this; } TextureAllocationFlags GetTextureAllocationFlags() const { return mAllocationFlags; } TextureType GetTextureType() const override { return TextureType::D3D11; } void FillInfo(TextureData::Info& aInfo) const override; bool Serialize(SurfaceDescriptor& aOutDescrptor) override; void GetSubDescriptor(RemoteDecoderVideoSubDescriptor* aOutDesc) override; gfx::ColorRange GetColorRange() const { return mColorRange; } void SetColorRange(gfx::ColorRange aColorRange) { mColorRange = aColorRange; } gfx::IntSize GetSize() const { return mSize; } gfx::SurfaceFormat GetSurfaceFormat() const { return mFormat; } TextureFlags GetTextureFlags() const override; void SetGpuProcessTextureId(GpuProcessTextureId aTextureId) { mGpuProcessTextureId = Some(aTextureId); } Maybe GetGpuProcessTextureId() { return mGpuProcessTextureId; } void RegisterQuery(RefPtr aQuery); private: D3D11TextureData(ID3D11Texture2D* aTexture, uint32_t aArrayIndex, RefPtr aSharedHandle, gfx::IntSize aSize, gfx::SurfaceFormat aFormat, TextureAllocationFlags aFlags); bool PrepareDrawTargetInLock(OpenMode aMode); friend class gl::GLBlitHelper; bool SerializeSpecific(SurfaceDescriptorD3D10* aOutDesc); static D3D11TextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, gfx::SourceSurface* aSurface, TextureAllocationFlags aAllocFlags, ID3D11Device* aDevice = nullptr); // Hold on to the DrawTarget because it is expensive to create one each // ::Lock. RefPtr mDrawTarget; const gfx::IntSize mSize; const gfx::SurfaceFormat mFormat; public: gfx::ColorSpace2 mColorSpace = gfx::ColorSpace2::SRGB; private: gfx::ColorRange mColorRange = gfx::ColorRange::LIMITED; bool mNeedsClear = false; const bool mHasKeyedMutex; RefPtr mTexture; const RefPtr mSharedHandle; Maybe mGpuProcessTextureId; uint32_t mArrayIndex = 0; const TextureAllocationFlags mAllocationFlags; Maybe mGpuProcessQueryId; }; class DXGIYCbCrTextureData : public TextureData { friend class gl::GLBlitHelper; public: static DXGIYCbCrTextureData* Create( ID3D11Texture2D* aTextureCb, ID3D11Texture2D* aTextureY, ID3D11Texture2D* aTextureCr, const gfx::IntSize& aSize, const gfx::IntSize& aSizeY, const gfx::IntSize& aSizeCbCr, gfx::ColorDepth aColorDepth, gfx::YUVColorSpace aYUVColorSpace, gfx::ColorRange aColorRange); bool Lock(OpenMode) override { return true; } void Unlock() override {} void FillInfo(TextureData::Info& aInfo) const override; void SerializeSpecific(SurfaceDescriptorDXGIYCbCr* aOutDesc); bool Serialize(SurfaceDescriptor& aOutDescriptor) override; void GetSubDescriptor(RemoteDecoderVideoSubDescriptor* aOutDesc) override; already_AddRefed BorrowDrawTarget() override { return nullptr; } void Deallocate(LayersIPCChannel* aAllocator) override; bool UpdateFromSurface(gfx::SourceSurface*) override { return false; } TextureFlags GetTextureFlags() const override; DXGIYCbCrTextureData* AsDXGIYCbCrTextureData() override { return this; } gfx::IntSize GetYSize() const { return mSizeY; } gfx::IntSize GetCbCrSize() const { return mSizeCbCr; } gfx::ColorDepth GetColorDepth() const { return mColorDepth; } gfx::YUVColorSpace GetYUVColorSpace() const { return mYUVColorSpace; } gfx::ColorRange GetColorRange() const { return mColorRange; } ID3D11Texture2D* GetD3D11Texture(size_t index) { return mD3D11Textures[index]; } protected: RefPtr mD3D11Textures[3]; RefPtr mHandles[3]; gfx::IntSize mSize; gfx::IntSize mSizeY; gfx::IntSize mSizeCbCr; gfx::ColorDepth mColorDepth; gfx::YUVColorSpace mYUVColorSpace; gfx::ColorRange mColorRange; }; /** * TextureSource that provides with the necessary APIs to be composited by a * CompositorD3D11. */ class TextureSourceD3D11 { public: TextureSourceD3D11() : mFormatOverride(DXGI_FORMAT_UNKNOWN) {} virtual ~TextureSourceD3D11() = default; virtual ID3D11Texture2D* GetD3D11Texture() const { return mTexture; } virtual ID3D11ShaderResourceView* GetShaderResourceView(); protected: virtual gfx::IntSize GetSize() const { return mSize; } gfx::IntSize mSize; RefPtr mTexture; RefPtr mSRV; DXGI_FORMAT mFormatOverride; }; /** * A TextureSource that implements the DataTextureSource interface. * it can be used without a TextureHost and is able to upload texture data * from a gfx::DataSourceSurface. */ class DataTextureSourceD3D11 : public DataTextureSource, public TextureSourceD3D11, public BigImageIterator { public: /// Constructor allowing the texture to perform texture uploads. /// /// The texture can be used as an actual DataTextureSource. DataTextureSourceD3D11(ID3D11Device* aDevice, gfx::SurfaceFormat aFormat, TextureFlags aFlags); /// Constructor for textures created around DXGI shared handles, disallowing /// texture uploads. /// /// The texture CANNOT be used as a DataTextureSource. DataTextureSourceD3D11(ID3D11Device* aDevice, gfx::SurfaceFormat aFormat, ID3D11Texture2D* aTexture); DataTextureSourceD3D11(gfx::SurfaceFormat aFormat, TextureSourceProvider* aProvider, ID3D11Texture2D* aTexture); DataTextureSourceD3D11(gfx::SurfaceFormat aFormat, TextureSourceProvider* aProvider, TextureFlags aFlags); virtual ~DataTextureSourceD3D11(); const char* Name() const override { return "DataTextureSourceD3D11"; } // DataTextureSource bool Update(gfx::DataSourceSurface* aSurface, nsIntRegion* aDestRegion = nullptr, gfx::IntPoint* aSrcOffset = nullptr, gfx::IntPoint* aDstOffset = nullptr) override; // TextureSource TextureSourceD3D11* AsSourceD3D11() override { return this; } ID3D11Texture2D* GetD3D11Texture() const override; ID3D11ShaderResourceView* GetShaderResourceView() override; // Returns nullptr if this texture was created by a DXGI TextureHost. DataTextureSource* AsDataTextureSource() override { return mAllowTextureUploads ? this : nullptr; } void DeallocateDeviceData() override { mTexture = nullptr; } gfx::IntSize GetSize() const override { return mSize; } gfx::SurfaceFormat GetFormat() const override { return mFormat; } // BigImageIterator BigImageIterator* AsBigImageIterator() override { return mIsTiled ? this : nullptr; } size_t GetTileCount() override { return mTileTextures.size(); } bool NextTile() override { return (++mCurrentTile < mTileTextures.size()); } gfx::IntRect GetTileRect() override; void EndBigImageIteration() override { mIterating = false; } void BeginBigImageIteration() override { mIterating = true; mCurrentTile = 0; } RefPtr ExtractCurrentTile() override; void Reset(); protected: gfx::IntRect GetTileRect(uint32_t aIndex) const; std::vector> mTileTextures; std::vector> mTileSRVs; RefPtr mDevice; gfx::SurfaceFormat mFormat; TextureFlags mFlags; uint32_t mCurrentTile; bool mIsTiled; bool mIterating; // Sadly, the code was originally organized so that this class is used both in // the cases where we want to perform texture uploads through the // DataTextureSource interface, and the cases where we wrap the texture around // an existing DXGI handle in which case we should not use it as a // DataTextureSource. This member differentiates the two scenarios. When it is // false the texture "pretends" to not be a DataTextureSource. bool mAllowTextureUploads; }; /** * A TextureHost for shared D3D11 textures. */ class DXGITextureHostD3D11 : public TextureHost { public: DXGITextureHostD3D11(TextureFlags aFlags, const SurfaceDescriptorD3D10& aDescriptor); void DeallocateDeviceData() override {} gfx::SurfaceFormat GetFormat() const override { return mFormat; } bool LockWithoutCompositor() override; void UnlockWithoutCompositor() override; gfx::IntSize GetSize() const override { return mSize; } gfx::ColorRange GetColorRange() const override { return mColorRange; } already_AddRefed GetAsSurface() override; void CreateRenderTexture( const wr::ExternalImageId& aExternalImageId) override; uint32_t NumSubTextures() override; void PushResourceUpdates(wr::TransactionBuilder& aResources, ResourceUpdateOp aOp, const Range& aImageKeys, const wr::ExternalImageId& aExtID) override; void PushDisplayItems(wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, wr::ImageRendering aFilter, const Range& aImageKeys, PushDisplayItemFlagSet aFlags) override; bool SupportsExternalCompositing(WebRenderBackend aBackend) override; protected: bool LockInternal(); void UnlockInternal(); bool EnsureTextureSource(); RefPtr GetDevice(); bool EnsureTexture(); RefPtr mDevice; RefPtr mTexture; Maybe mGpuProcessTextureId; Maybe mGpuProcessQueryId; uint32_t mArrayIndex = 0; RefPtr mTextureSource; gfx::IntSize mSize; const RefPtr mHandle; gfx::SurfaceFormat mFormat; bool mHasKeyedMutex; gfx::FenceInfo mAcquireFenceInfo; public: const gfx::ColorSpace2 mColorSpace; protected: const gfx::ColorRange mColorRange; bool mIsLocked; }; class DXGIYCbCrTextureHostD3D11 : public TextureHost { public: DXGIYCbCrTextureHostD3D11(TextureFlags aFlags, const SurfaceDescriptorDXGIYCbCr& aDescriptor); void DeallocateDeviceData() override {} gfx::SurfaceFormat GetFormat() const override { return gfx::SurfaceFormat::YUV; } gfx::ColorDepth GetColorDepth() const override { return mColorDepth; } gfx::YUVColorSpace GetYUVColorSpace() const override { return mYUVColorSpace; } gfx::ColorRange GetColorRange() const override { return mColorRange; } gfx::IntSize GetSize() const override { return mSize; } already_AddRefed GetAsSurface() override { return nullptr; } void CreateRenderTexture( const wr::ExternalImageId& aExternalImageId) override; uint32_t NumSubTextures() override; void PushResourceUpdates(wr::TransactionBuilder& aResources, ResourceUpdateOp aOp, const Range& aImageKeys, const wr::ExternalImageId& aExtID) override; void PushDisplayItems(wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, wr::ImageRendering aFilter, const Range& aImageKeys, PushDisplayItemFlagSet aFlags) override; bool SupportsExternalCompositing(WebRenderBackend aBackend) override; protected: RefPtr mTextures[3]; gfx::IntSize mSize; gfx::IntSize mSizeY; gfx::IntSize mSizeCbCr; // Handles will be closed automatically when `UniqueFileHandle` gets // destroyed. RefPtr mHandles[3]; bool mIsLocked; gfx::ColorDepth mColorDepth; gfx::YUVColorSpace mYUVColorSpace; gfx::ColorRange mColorRange; }; class CompositingRenderTargetD3D11 : public CompositingRenderTarget, public TextureSourceD3D11 { public: CompositingRenderTargetD3D11( ID3D11Texture2D* aTexture, const gfx::IntPoint& aOrigin, DXGI_FORMAT aFormatOverride = DXGI_FORMAT_UNKNOWN); const char* Name() const override { return "CompositingRenderTargetD3D11"; } TextureSourceD3D11* AsSourceD3D11() override { return this; } void BindRenderTarget(ID3D11DeviceContext* aContext); gfx::IntSize GetSize() const override; void SetSize(const gfx::IntSize& aSize) { mSize = aSize; } private: friend class CompositorD3D11; RefPtr mRTView; }; class SyncObjectD3D11Host : public SyncObjectHost { public: explicit SyncObjectD3D11Host(ID3D11Device* aDevice); bool Init() override; SyncHandle GetSyncHandle() override; bool Synchronize(bool aFallible) override; IDXGIKeyedMutex* GetKeyedMutex() { return mKeyedMutex.get(); }; private: virtual ~SyncObjectD3D11Host() = default; SyncHandle mSyncHandle; RefPtr mDevice; RefPtr mSyncTexture; RefPtr mKeyedMutex; }; class SyncObjectD3D11Client : public SyncObjectClient { public: SyncObjectD3D11Client(SyncHandle aSyncHandle, ID3D11Device* aDevice); bool Synchronize(bool aFallible) override; bool IsSyncObjectValid() override; void EnsureInitialized() override {} SyncType GetSyncType() override { return SyncType::D3D11; } void RegisterTexture(ID3D11Texture2D* aTexture); protected: explicit SyncObjectD3D11Client(SyncHandle aSyncHandle); bool Init(ID3D11Device* aDevice, bool aFallible); bool SynchronizeInternal(ID3D11Device* aDevice, bool aFallible); Mutex mSyncLock MOZ_UNANNOTATED; RefPtr mSyncTexture; std::vector mSyncedTextures; private: SyncHandle mSyncHandle; RefPtr mKeyedMutex; const RefPtr mDevice; }; class SyncObjectD3D11ClientContentDevice : public SyncObjectD3D11Client { public: explicit SyncObjectD3D11ClientContentDevice(SyncHandle aSyncHandle); bool Synchronize(bool aFallible) override; bool IsSyncObjectValid() override; void EnsureInitialized() override; private: RefPtr mContentDevice; }; inline uint32_t GetMaxTextureSizeForFeatureLevel( D3D_FEATURE_LEVEL aFeatureLevel) { int32_t maxTextureSize; switch (aFeatureLevel) { case D3D_FEATURE_LEVEL_11_1: case D3D_FEATURE_LEVEL_11_0: maxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; break; case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: maxTextureSize = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; break; case D3D_FEATURE_LEVEL_9_3: maxTextureSize = D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; break; default: maxTextureSize = D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; } return maxTextureSize; } uint32_t GetMaxTextureSizeFromDevice(ID3D11Device* aDevice); void ReportTextureMemoryUsage(ID3D11Texture2D* aTexture, size_t aBytes); class AutoLockD3D11Texture { public: explicit AutoLockD3D11Texture(ID3D11Texture2D* aTexture); ~AutoLockD3D11Texture(); private: RefPtr mMutex; }; class D3D11MTAutoEnter { public: explicit D3D11MTAutoEnter(already_AddRefed aMT) : mMT(aMT) { if (mMT) { mMT->Enter(); } } ~D3D11MTAutoEnter() { if (mMT) { mMT->Leave(); } } private: RefPtr mMT; }; } // namespace layers } // namespace mozilla #endif /* MOZILLA_GFX_TEXTURED3D11_H */