diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/layers/d3d11/TextureD3D11.h | 649 |
1 files changed, 649 insertions, 0 deletions
diff --git a/gfx/layers/d3d11/TextureD3D11.h b/gfx/layers/d3d11/TextureD3D11.h new file mode 100644 index 0000000000..2d43835d5b --- /dev/null +++ b/gfx/layers/d3d11/TextureD3D11.h @@ -0,0 +1,649 @@ +/* -*- 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 <d3d11.h> + +#include <vector> + +#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 gl { +class GLBlitHelper; +} + +namespace layers { + +already_AddRefed<TextureHost> 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<IDXGIKeyedMutex> 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<TextureClient> CreateTextureClient( + ID3D11Texture2D* aTexture, uint32_t aIndex, gfx::IntSize aSize, + gfx::SurfaceFormat aFormat, gfx::ColorSpace2 aColorSpace, + gfx::ColorRange aColorRange, KnowsCompositor* aKnowsCompositor, + RefPtr<IMFSampleUsageInfo> aUsageInfo); + + virtual ~D3D11TextureData(); + + bool UpdateFromSurface(gfx::SourceSurface* aSurface) override; + + bool Lock(OpenMode aMode) override; + + void Unlock() override; + + already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override; + + TextureData* CreateSimilar(LayersIPCChannel* aAllocator, + LayersBackend aLayersBackend, TextureFlags aFlags, + TextureAllocationFlags aAllocFlags) const override; + + void SyncWithObject(RefPtr<SyncObjectClient> aSyncObject) override; + + ID3D11Texture2D* GetD3D11Texture() const { return mTexture; } + + void Deallocate(LayersIPCChannel* aAllocator) override; + + D3D11TextureData* AsD3D11TextureData() override { return this; } + + TextureAllocationFlags GetTextureAllocationFlags() const { + return mAllocationFlags; + } + + 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<GpuProcessTextureId> GetGpuProcessTextureId() { + return mGpuProcessTextureId; + } + + private: + D3D11TextureData(ID3D11Texture2D* aTexture, uint32_t aArrayIndex, + gfx::IntSize aSize, gfx::SurfaceFormat aFormat, + TextureAllocationFlags aFlags); + + void GetDXGIResource(IDXGIResource** aOutResource); + + 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<gfx::DrawTarget> 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 mHasSynchronization; + + RefPtr<ID3D11Texture2D> mTexture; + Maybe<GpuProcessTextureId> mGpuProcessTextureId; + uint32_t mArrayIndex = 0; + const TextureAllocationFlags mAllocationFlags; +}; + +class DXGIYCbCrTextureData : public TextureData { + friend class gl::GLBlitHelper; + + public: + static DXGIYCbCrTextureData* Create( + IDirect3DTexture9* aTextureY, IDirect3DTexture9* aTextureCb, + IDirect3DTexture9* aTextureCr, HANDLE aHandleY, HANDLE aHandleCb, + HANDLE aHandleCr, const gfx::IntSize& aSize, const gfx::IntSize& aSizeY, + const gfx::IntSize& aSizeCbCr, gfx::ColorDepth aColorDepth, + gfx::YUVColorSpace aYUVColorSpace, gfx::ColorRange aColorRange); + + 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<gfx::DrawTarget> 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<ID3D11Texture2D> mD3D11Textures[3]; + RefPtr<IDirect3DTexture9> mD3D9Textures[3]; + HANDLE 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<ID3D11Texture2D> mTexture; + RefPtr<ID3D11ShaderResourceView> 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<TextureSource> ExtractCurrentTile() override; + + void Reset(); + + protected: + gfx::IntRect GetTileRect(uint32_t aIndex) const; + + std::vector<RefPtr<ID3D11Texture2D>> mTileTextures; + std::vector<RefPtr<ID3D11ShaderResourceView>> mTileSRVs; + RefPtr<ID3D11Device> 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<gfx::DataSourceSurface> GetAsSurface() override; + + void CreateRenderTexture( + const wr::ExternalImageId& aExternalImageId) override; + + uint32_t NumSubTextures() override; + + void PushResourceUpdates(wr::TransactionBuilder& aResources, + ResourceUpdateOp aOp, + const Range<wr::ImageKey>& aImageKeys, + const wr::ExternalImageId& aExtID) override; + + void PushDisplayItems(wr::DisplayListBuilder& aBuilder, + const wr::LayoutRect& aBounds, + const wr::LayoutRect& aClip, wr::ImageRendering aFilter, + const Range<wr::ImageKey>& aImageKeys, + PushDisplayItemFlagSet aFlags) override; + + bool SupportsExternalCompositing(WebRenderBackend aBackend) override; + + protected: + bool LockInternal(); + void UnlockInternal(); + + bool EnsureTextureSource(); + + RefPtr<ID3D11Device> GetDevice(); + + bool EnsureTexture(); + + RefPtr<ID3D11Device> mDevice; + RefPtr<ID3D11Texture2D> mTexture; + Maybe<GpuProcessTextureId> mGpuProcessTextureId; + uint32_t mArrayIndex = 0; + RefPtr<DataTextureSourceD3D11> mTextureSource; + gfx::IntSize mSize; + WindowsHandle mHandle; + gfx::SurfaceFormat mFormat; + + 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<gfx::DataSourceSurface> GetAsSurface() override { + return nullptr; + } + + void CreateRenderTexture( + const wr::ExternalImageId& aExternalImageId) override; + + uint32_t NumSubTextures() override; + + void PushResourceUpdates(wr::TransactionBuilder& aResources, + ResourceUpdateOp aOp, + const Range<wr::ImageKey>& aImageKeys, + const wr::ExternalImageId& aExtID) override; + + void PushDisplayItems(wr::DisplayListBuilder& aBuilder, + const wr::LayoutRect& aBounds, + const wr::LayoutRect& aClip, wr::ImageRendering aFilter, + const Range<wr::ImageKey>& aImageKeys, + PushDisplayItemFlagSet aFlags) override; + + bool SupportsExternalCompositing(WebRenderBackend aBackend) override; + + private: + bool EnsureTextureSource(); + + protected: + RefPtr<ID3D11Device> GetDevice(); + + bool EnsureTexture(); + + RefPtr<ID3D11Texture2D> mTextures[3]; + RefPtr<DataTextureSourceD3D11> mTextureSources[3]; + + gfx::IntSize mSize; + gfx::IntSize mSizeY; + gfx::IntSize mSizeCbCr; + WindowsHandle 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<ID3D11RenderTargetView> 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<ID3D11Device> mDevice; + RefPtr<IDXGIResource> mSyncTexture; + RefPtr<IDXGIKeyedMutex> 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<ID3D11Texture2D> mSyncTexture; + std::vector<ID3D11Texture2D*> mSyncedTextures; + + private: + const SyncHandle mSyncHandle; + RefPtr<IDXGIKeyedMutex> mKeyedMutex; + const RefPtr<ID3D11Device> mDevice; +}; + +class SyncObjectD3D11ClientContentDevice : public SyncObjectD3D11Client { + public: + explicit SyncObjectD3D11ClientContentDevice(SyncHandle aSyncHandle); + + bool Synchronize(bool aFallible) override; + + bool IsSyncObjectValid() override; + + void EnsureInitialized() override; + + private: + RefPtr<ID3D11Device> 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<IDXGIKeyedMutex> mMutex; +}; + +class D3D11MTAutoEnter { + public: + explicit D3D11MTAutoEnter(already_AddRefed<ID3D10Multithread> aMT) + : mMT(aMT) { + if (mMT) { + mMT->Enter(); + } + } + ~D3D11MTAutoEnter() { + if (mMT) { + mMT->Leave(); + } + } + + private: + RefPtr<ID3D10Multithread> mMT; +}; + +/** + * A class to manage ID3D11Texture2Ds that is shared without using shared handle + * in GPU process. On some GPUs, ID3D11Texture2Ds of hardware decoded video + * frames with zero video frame copy could not use shared handle. + */ +class GpuProcessD3D11TextureMap { + public: + static void Init(); + static void Shutdown(); + static GpuProcessD3D11TextureMap* Get() { return sInstance; } + static GpuProcessTextureId GetNextTextureId(); + + GpuProcessD3D11TextureMap(); + ~GpuProcessD3D11TextureMap(); + + void Register(GpuProcessTextureId aTextureId, ID3D11Texture2D* aTexture, + uint32_t aArrayIndex, const gfx::IntSize& aSize, + RefPtr<IMFSampleUsageInfo> aUsageInfo); + void Unregister(GpuProcessTextureId aTextureId); + + RefPtr<ID3D11Texture2D> GetTexture(GpuProcessTextureId aTextureId); + Maybe<HANDLE> GetSharedHandleOfCopiedTexture(GpuProcessTextureId aTextureId); + + private: + struct TextureHolder { + TextureHolder(ID3D11Texture2D* aTexture, uint32_t aArrayIndex, + const gfx::IntSize& aSize, + RefPtr<IMFSampleUsageInfo> aUsageInfo); + TextureHolder() = default; + + RefPtr<ID3D11Texture2D> mTexture; + uint32_t mArrayIndex = 0; + gfx::IntSize mSize; + RefPtr<IMFSampleUsageInfo> mIMFSampleUsageInfo; + RefPtr<ID3D11Texture2D> mCopiedTexture; + Maybe<HANDLE> mCopiedTextureSharedHandle; + }; + + DataMutex<std::unordered_map<GpuProcessTextureId, TextureHolder, + GpuProcessTextureId::HashFn>> + mD3D11TexturesById; + + static StaticAutoPtr<GpuProcessD3D11TextureMap> sInstance; +}; + +} // namespace layers +} // namespace mozilla + +#endif /* MOZILLA_GFX_TEXTURED3D11_H */ |