Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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(uint64_t aTextureId) {
mGpuProcessTextureId = Some(aTextureId);
}
Maybe<uint64_t> 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<uint64_t> 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<uint64_t> 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 uint64_t GetNextTextureId();
GpuProcessD3D11TextureMap();
~GpuProcessD3D11TextureMap();
void Register(uint64_t aTextureId, ID3D11Texture2D* aTexture,
uint32_t aArrayIndex, const gfx::IntSize& aSize,
RefPtr<IMFSampleUsageInfo> aUsageInfo);
void Unregister(uint64_t aTextureId);
RefPtr<ID3D11Texture2D> GetTexture(uint64_t aTextureId);
Maybe<HANDLE> GetSharedHandleOfCopiedTexture(uint64_t 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<uint64_t, TextureHolder>> mD3D11TexturesById;
static StaticAutoPtr<GpuProcessD3D11TextureMap> sInstance;
};
} // namespace layers
} // namespace mozilla
#endif /* MOZILLA_GFX_TEXTURED3D11_H */