Bug 1176363 - Part 1: Stop using DrawTargets off the main thread. r=mattwoodrow

This commit is contained in:
Bas Schouten 2015-07-27 15:47:29 +00:00
Родитель c7b835ce08
Коммит 1a51d15b0f
15 изменённых файлов: 260 добавлений и 64 удалений

Просмотреть файл

@ -639,20 +639,17 @@ CairoImage::GetTextureClient(CompositableClient *aClient)
if (!textureClient) {
return nullptr;
}
MOZ_ASSERT(textureClient->CanExposeDrawTarget());
if (!textureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) {
return nullptr;
}
TextureClientAutoUnlock autoUnolck(textureClient);
{
// We must not keep a reference to the DrawTarget after it has been unlocked.
DrawTarget* dt = textureClient->BorrowDrawTarget();
if (!dt) {
return nullptr;
}
dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
}
TextureClientAutoUnlock autoUnlock(textureClient);
RefPtr<DataSourceSurface> dataSurf = surface->GetDataSurface();
textureClient->UpdateFromSurface(dataSurf);
textureClient->SyncWithObject(forwarder->GetSyncObject());
mTextureClients.Put(forwarder->GetSerial(), textureClient);
return textureClient;

Просмотреть файл

@ -56,6 +56,25 @@ TextureClientDIB::BorrowDrawTarget()
return mDrawTarget;
}
void
TextureClientDIB::UpdateFromSurface(gfx::DataSourceSurface* aSurface)
{
MOZ_ASSERT(mIsLocked && IsAllocated());
nsRefPtr<gfxImageSurface> imgSurf = mSurface->GetAsImageSurface();
DataSourceSurface::MappedSurface sourceMap;
aSurface->Map(DataSourceSurface::READ, &sourceMap);
for (int y = 0; y < aSurface->GetSize().height; y++) {
memcpy(imgSurf->Data() + imgSurf->Stride() * y,
sourceMap.mData + sourceMap.mStride * y,
aSurface->GetSize().width * BytesPerPixel(aSurface->GetFormat()));
}
aSurface->Unmap();
}
TextureClientMemoryDIB::TextureClientMemoryDIB(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags)

Просмотреть файл

@ -34,6 +34,8 @@ public:
virtual gfx::DrawTarget* BorrowDrawTarget() override;
virtual void UpdateFromSurface(gfx::DataSourceSurface* aSurface) override;
virtual bool HasInternalBuffer() const override { return true; }
protected:

Просмотреть файл

@ -152,3 +152,18 @@ TextureClientX11::BorrowDrawTarget()
return mDrawTarget;
}
void
TextureClientX11::UpdateFromSurface(gfx::DataSourceSurface* aSurface)
{
MOZ_ASSERT(CanExposeDrawTarget());
DrawTarget* dt = BorrowDrawTarget();
if (!dt) {
gfxCriticalError() << "Failed to borrow drawtarget for TextureClientX11::UpdateFromSurface";
return;
}
dt->CopySurface(aSurface, IntRect(IntPoint(), aSurface->GetSize()), IntPoint());
}

Просмотреть файл

@ -43,6 +43,8 @@ class TextureClientX11 : public TextureClient
virtual gfx::DrawTarget* BorrowDrawTarget() override;
virtual void UpdateFromSurface(gfx::DataSourceSurface* aSurface) override;
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
virtual bool HasInternalBuffer() const override { return false; }

Просмотреть файл

@ -353,7 +353,8 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
aMoz2DBackend == gfx::BackendType::CAIRO &&
aAllocator->IsSameProcess() &&
aSize.width <= maxTextureSize &&
aSize.height <= maxTextureSize) {
aSize.height <= maxTextureSize &&
NS_IsMainThread()) {
if (gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
texture = new TextureClientD3D9(aAllocator, aFormat, aTextureFlags);
}
@ -361,7 +362,8 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
if (!texture && aFormat == SurfaceFormat::B8G8R8X8 &&
aAllocator->IsSameProcess() &&
aMoz2DBackend == gfx::BackendType::CAIRO) {
aMoz2DBackend == gfx::BackendType::CAIRO &&
NS_IsMainThread()) {
if (aAllocator->IsSameProcess()) {
texture = new TextureClientMemoryDIB(aAllocator, aFormat, aTextureFlags);
} else {
@ -801,6 +803,7 @@ gfx::DrawTarget*
BufferTextureClient::BorrowDrawTarget()
{
MOZ_ASSERT(IsValid());
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mLocked, "BorrowDrawTarget should be called on locked textures only");
if (!mLocked) {
return nullptr;
@ -826,6 +829,33 @@ BufferTextureClient::BorrowDrawTarget()
return mDrawTarget;
}
void
BufferTextureClient::UpdateFromSurface(gfx::DataSourceSurface* aSurface)
{
ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
RefPtr<DataSourceSurface> surface = serializer.GetAsSurface();
if (surface->GetSize() != aSurface->GetSize() || surface->GetFormat() != aSurface->GetFormat()) {
gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format! This: " << surface->GetSize() << " " << surface->GetFormat() << " Other: " << aSurface->GetSize() << " " << aSurface->GetFormat();
return;
}
DataSourceSurface::MappedSurface sourceMap;
DataSourceSurface::MappedSurface destMap;
aSurface->Map(DataSourceSurface::READ, &sourceMap);
surface->Map(DataSourceSurface::WRITE, &destMap);
for (int y = 0; y < aSurface->GetSize().height; y++) {
memcpy(destMap.mData + destMap.mStride * y,
sourceMap.mData + sourceMap.mStride * y,
aSurface->GetSize().width * BytesPerPixel(aSurface->GetFormat()));
}
aSurface->Unmap();
surface->Unmap();
}
bool
BufferTextureClient::Lock(OpenMode aMode)
{

Просмотреть файл

@ -243,6 +243,7 @@ public:
/**
* Returns a DrawTarget to draw into the TextureClient.
* This function should never be called when not on the main thread!
*
* This must never be called on a TextureClient that is not sucessfully locked.
* When called several times within one Lock/Unlock pair, this method should
@ -268,6 +269,12 @@ public:
*/
virtual gfx::DrawTarget* BorrowDrawTarget() { return nullptr; }
/**
* This function can be used to update the contents of the TextureClient
* off the main thread.
*/
virtual void UpdateFromSurface(gfx::DataSourceSurface* aSurface) { MOZ_CRASH(); }
// TextureClients that can expose a DrawTarget should override this method.
virtual gfx::SurfaceFormat GetFormat() const
{
@ -586,6 +593,8 @@ public:
virtual gfx::DrawTarget* BorrowDrawTarget() override;
virtual void UpdateFromSurface(gfx::DataSourceSurface* aSurface) override;
virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;

Просмотреть файл

@ -244,7 +244,8 @@ TextureClientD3D11::CreateSimilar(TextureFlags aFlags,
void
TextureClientD3D11::SyncWithObject(SyncObject* aSyncObject)
{
if (!aSyncObject) {
if (!aSyncObject || !NS_IsMainThread()) {
// When off the main thread we sync using a keyed mutex per texture.
return;
}
@ -278,33 +279,35 @@ TextureClientD3D11::Lock(OpenMode aMode)
return false;
}
// Make sure that successful write-lock means we will have a DrawTarget to
// write into.
if (aMode & OpenMode::OPEN_WRITE) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
Unlock();
return false;
if (NS_IsMainThread()) {
// Make sure that successful write-lock means we will have a DrawTarget to
// write into.
if (aMode & OpenMode::OPEN_WRITE) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
Unlock();
return false;
}
}
}
if (mNeedsClear) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
if (mNeedsClear) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
Unlock();
return false;
}
mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
mNeedsClear = false;
}
mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
mNeedsClear = false;
}
if (mNeedsClearWhite) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
if (mNeedsClearWhite) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
Unlock();
return false;
}
mDrawTarget->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
mNeedsClearWhite = false;
}
mDrawTarget->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
mNeedsClearWhite = false;
}
return true;
@ -327,7 +330,7 @@ TextureClientD3D11::Unlock()
mDrawTarget->Flush();
}
if (mReadbackSink && mTexture10) {
if (NS_IsMainThread() && mReadbackSink && mTexture10) {
ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
D3D10_TEXTURE2D_DESC desc;
@ -363,6 +366,7 @@ DrawTarget*
TextureClientD3D11::BorrowDrawTarget()
{
MOZ_ASSERT(mIsLocked, "Calling TextureClient::BorrowDrawTarget without locking :(");
MOZ_ASSERT(NS_IsMainThread());
if (!mIsLocked || (!mTexture && !mTexture10)) {
gfxCriticalError() << "Attempted to borrow a DrawTarget without locking the texture.";
@ -387,6 +391,53 @@ TextureClientD3D11::BorrowDrawTarget()
return mDrawTarget;
}
void
TextureClientD3D11::UpdateFromSurface(gfx::DataSourceSurface* aSurface)
{
DataSourceSurface::MappedSurface sourceMap;
aSurface->Map(DataSourceSurface::READ, &sourceMap);
if (mDrawTarget) {
// Ensure unflushed work from our outstanding drawtarget won't override this
// update later.
mDrawTarget->Flush();
}
if (mSize != aSurface->GetSize() || mFormat != aSurface->GetFormat()) {
gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format!";
return;
}
if (mTexture) {
RefPtr<ID3D11Device> device;
mTexture->GetDevice(byRef(device));
RefPtr<ID3D11DeviceContext> ctx;
device->GetImmediateContext(byRef(ctx));
D3D11_BOX box;
box.front = 0;
box.back = 1;
box.top = box.left = 0;
box.right = aSurface->GetSize().width;
box.bottom = aSurface->GetSize().height;
ctx->UpdateSubresource(mTexture, 0, &box, sourceMap.mData, sourceMap.mStride, 0);
} else {
RefPtr<ID3D10Device> device;
mTexture10->GetDevice(byRef(device));
D3D10_BOX box;
box.front = 0;
box.back = 1;
box.top = box.left = 0;
box.right = aSurface->GetSize().width;
box.bottom = aSurface->GetSize().height;
device->UpdateSubresource(mTexture10, 0, &box, sourceMap.mData, sourceMap.mStride, 0);
}
aSurface->Unmap();
}
static const GUID sD3D11TextureUsage =
{ 0xd89275b0, 0x6c7d, 0x4038, { 0xb5, 0xfa, 0x4d, 0x87, 0x16, 0xd5, 0xcc, 0x4e } };
@ -447,8 +498,11 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag
}
gfxWindowsPlatform* windowsPlatform = gfxWindowsPlatform::GetPlatform();
ID3D11Device* d3d11device = windowsPlatform->GetD3D11ContentDevice();
bool haveD3d11Backend = windowsPlatform->GetContentBackend() == BackendType::DIRECT2D1_1;
ID3D11Device* d3d11device = windowsPlatform->GetD3D11DeviceForCurrentThread();
// When we're not on the main thread we're not going to be using Direct2D
// to access the contents of this texture client so we will always use D3D11.
bool haveD3d11Backend = windowsPlatform->GetContentBackend() == BackendType::DIRECT2D1_1 || !NS_IsMainThread();
if (haveD3d11Backend) {
MOZ_ASSERT(d3d11device != nullptr);
@ -459,6 +513,11 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag
newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
if (!NS_IsMainThread()) {
// On the main thread we use the syncobject to handle synchronization.
newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
}
hr = d3d11device->CreateTexture2D(&newDesc, nullptr, byRef(mTexture));
if (FAILED(hr)) {
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize))) << "[D3D11] 2 CreateTexture2D failure " << aSize << " Code: " << gfx::hexa(hr);

Просмотреть файл

@ -64,6 +64,8 @@ public:
virtual gfx::DrawTarget* BorrowDrawTarget() override;
virtual void UpdateFromSurface(gfx::DataSourceSurface* aSurface) override;
virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;

Просмотреть файл

@ -498,35 +498,6 @@ TextureClientD3D9::Lock(OpenMode aMode)
mIsLocked = true;
// Make sure that successful write-lock means we will have a DrawTarget to
// write into.
if (aMode & OpenMode::OPEN_WRITE) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
Unlock();
return false;
}
}
if (mNeedsClear) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
Unlock();
return false;
}
mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
mNeedsClear = false;
}
if (mNeedsClearWhite) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
Unlock();
return false;
}
mDrawTarget->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
mNeedsClearWhite = false;
}
return true;
}
@ -601,9 +572,51 @@ TextureClientD3D9::BorrowDrawTarget()
mLockRect = true;
}
if (mNeedsClear) {
mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
mNeedsClear = false;
}
if (mNeedsClearWhite) {
mDrawTarget->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
mNeedsClearWhite = false;
}
return mDrawTarget;
}
void
TextureClientD3D9::UpdateFromSurface(gfx::DataSourceSurface* aSurface)
{
MOZ_ASSERT(mIsLocked && mD3D9Surface);
// gfxWindowsSurface don't support transparency so we can't use the d3d9
// windows surface optimization.
// Instead we have to use a gfxImageSurface and fallback for font drawing.
D3DLOCKED_RECT rect;
HRESULT hr = mD3D9Surface->LockRect(&rect, nullptr, 0);
if (FAILED(hr) || !rect.pBits) {
gfxCriticalError() << "Failed to lock rect borrowing the target in D3D9 " << hexa(hr);
return;
}
if (mSize != aSurface->GetSize() || mFormat != aSurface->GetFormat()) {
gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format! This: " << mSize << " " << mFormat << " Other: " << aSurface->GetSize() << " " << aSurface->GetFormat();
return;
}
DataSourceSurface::MappedSurface sourceMap;
aSurface->Map(DataSourceSurface::READ, &sourceMap);
for (int y = 0; y < aSurface->GetSize().height; y++) {
memcpy((uint8_t*)rect.pBits + rect.Pitch * y,
sourceMap.mData + sourceMap.mStride * y,
aSurface->GetSize().width * BytesPerPixel(aSurface->GetFormat()));
}
aSurface->Unmap();
mD3D9Surface->UnlockRect();
}
bool
TextureClientD3D9::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
{

Просмотреть файл

@ -202,6 +202,8 @@ public:
virtual gfx::DrawTarget* BorrowDrawTarget() override;
virtual void UpdateFromSurface(gfx::DataSourceSurface* aSurface) override;
virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;

Просмотреть файл

@ -214,6 +214,40 @@ GrallocTextureClientOGL::BorrowDrawTarget()
return mDrawTarget;
}
void
GrallocTextureClientOGL::UpdateFromSurface(gfx::DataSourceSurface* aSurface)
{
MOZ_ASSERT(IsValid());
MOZ_ASSERT(mMappedBuffer, "Calling TextureClient::BorrowDrawTarget without locking :(");
if (!IsValid() || !IsAllocated() || !mMappedBuffer) {
return;
}
gfx::SurfaceFormat format = SurfaceFormatForPixelFormat(mGraphicBuffer->getPixelFormat());
if (mSize != aSurface->GetSize() || mFormat != aSurface->GetFormat()) {
gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format! This: " << mSize << " " << format << " Other: " << aSurface->GetSize() << " " << aSurface->GetFormat();
return;
}
long pixelStride = mGraphicBuffer->getStride();
long byteStride = pixelStride * BytesPerPixel(format);
DataSourceSurface::MappedSurface sourceMap;
aSurface->Map(DataSourceSurface::READ, &sourceMap);
uint8_t* buffer = GetBuffer();
for (int y = 0; y < aSurface->GetSize().height; y++) {
memcpy(buffer + byteStride * y,
sourceMap.mData + sourceMap.mStride * y,
aSurface->GetSize().width * BytesPerPixel(aSurface->GetFormat()));
}
aSurface->Unmap();
}
bool
GrallocTextureClientOGL::AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags)

Просмотреть файл

@ -82,6 +82,8 @@ public:
virtual gfx::DrawTarget* BorrowDrawTarget() override;
virtual void UpdateFromSurface(gfx::DataSourceSurface* aSurface) override;
virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;

Просмотреть файл

@ -1588,6 +1588,15 @@ gfxWindowsPlatform::GetD3D11ImageBridgeDevice()
return mD3D11ImageBridgeDevice;
}
ID3D11Device*
gfxWindowsPlatform::GetD3D11DeviceForCurrentThread()
{
if (NS_IsMainThread()) {
return GetD3D11ContentDevice();
} else {
return GetD3D11ImageBridgeDevice();
}
}
ReadbackManagerD3D11*
gfxWindowsPlatform::GetReadbackManager()

Просмотреть файл

@ -244,6 +244,7 @@ public:
ID3D10Device1 *GetD3D10Device() { return mD3D10Device; }
ID3D11Device *GetD3D11Device();
ID3D11Device *GetD3D11ContentDevice();
ID3D11Device* GetD3D11DeviceForCurrentThread();
// Device to be used on the ImageBridge thread
ID3D11Device *GetD3D11ImageBridgeDevice();