зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1709603: Use a separate permanent canvas back buffer when texture has synchronization. r=lsalzman
Differential Revision: https://phabricator.services.mozilla.com/D125201
This commit is contained in:
Родитель
82f617d91d
Коммит
74b9880c08
|
@ -147,8 +147,17 @@ PersistentBufferProviderShared::PersistentBufferProviderShared(
|
|||
mKnowsCompositor(aKnowsCompositor),
|
||||
mFront(Nothing()) {
|
||||
MOZ_ASSERT(aKnowsCompositor);
|
||||
if (mTextures.append(aTexture)) {
|
||||
mBack = Some<uint32_t>(0);
|
||||
|
||||
// If our textures have synchronization use a separate permanent back buffer.
|
||||
if (aTexture->HasSynchronization()) {
|
||||
mPermanentBackBuffer = aTexture;
|
||||
if (!mPermanentBackBuffer->Lock(OpenMode::OPEN_READ_WRITE)) {
|
||||
mPermanentBackBuffer = nullptr;
|
||||
}
|
||||
} else {
|
||||
if (mTextures.append(aTexture)) {
|
||||
mBack = Some<uint32_t>(0);
|
||||
}
|
||||
}
|
||||
|
||||
// If we are using webrender and our textures don't have an intermediate
|
||||
|
@ -230,6 +239,24 @@ bool PersistentBufferProviderShared::SetKnowsCompositor(
|
|||
// Destroy. Not ideal but at least we won't try to use it with a
|
||||
// an incompatible ipc channel.
|
||||
|
||||
// If our new texture has internal synchronization then create a new
|
||||
// permanent back buffer as well.
|
||||
if (newTexture->HasSynchronization()) {
|
||||
RefPtr<TextureClient> mPermanentBackBuffer =
|
||||
TextureClient::CreateForDrawing(
|
||||
aKnowsCompositor, mFormat, mSize, BackendSelector::Canvas,
|
||||
TextureFlags::DEFAULT | TextureFlags::NON_BLOCKING_READ_LOCK,
|
||||
TextureAllocationFlags::ALLOC_DEFAULT);
|
||||
if (!mPermanentBackBuffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mPermanentBackBuffer->Lock(OpenMode::OPEN_READ_WRITE)) {
|
||||
mPermanentBackBuffer = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!newTexture->Lock(OpenMode::OPEN_WRITE)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -242,6 +269,11 @@ bool PersistentBufferProviderShared::SetKnowsCompositor(
|
|||
bool success =
|
||||
prevTexture->CopyToTextureClient(newTexture, nullptr, nullptr);
|
||||
|
||||
if (success && mPermanentBackBuffer) {
|
||||
success = prevTexture->CopyToTextureClient(mPermanentBackBuffer,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
prevTexture->Unlock();
|
||||
newTexture->Unlock();
|
||||
|
||||
|
@ -369,7 +401,17 @@ PersistentBufferProviderShared::BorrowDrawTarget(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
if (mPermanentBackBuffer) {
|
||||
// If we have a permanent back buffer lock the selected one and switch to
|
||||
// the permanent one before borrowing the DrawTarget. We will copy back into
|
||||
// the selected one when ReturnDrawTarget is called, before we make it the
|
||||
// new front buffer.
|
||||
if (!tex->Lock(OpenMode::OPEN_WRITE)) {
|
||||
return nullptr;
|
||||
}
|
||||
tex = mPermanentBackBuffer;
|
||||
} else {
|
||||
// Copy from the previous back buffer if required.
|
||||
Maybe<TextureClientAutoLock> autoReadLock;
|
||||
TextureClient* previous = nullptr;
|
||||
if (mBack != previousBackBuffer && !aPersistedRect.IsEmpty()) {
|
||||
|
@ -421,6 +463,17 @@ bool PersistentBufferProviderShared::ReturnDrawTarget(
|
|||
mDrawTarget = nullptr;
|
||||
dt = nullptr;
|
||||
|
||||
// If we have a permanent back buffer we have actually been drawing to that,
|
||||
// so now we must copy to the shared one.
|
||||
if (mPermanentBackBuffer && back) {
|
||||
DebugOnly<bool> success =
|
||||
mPermanentBackBuffer->CopyToTextureClient(back, nullptr, nullptr);
|
||||
MOZ_ASSERT(success);
|
||||
|
||||
// Let our permanent back buffer know that we have finished drawing.
|
||||
mPermanentBackBuffer->EndDraw();
|
||||
}
|
||||
|
||||
if (back) {
|
||||
back->Unlock();
|
||||
mFront = mBack;
|
||||
|
@ -469,6 +522,12 @@ TextureClient* PersistentBufferProviderShared::GetTextureClient() {
|
|||
|
||||
already_AddRefed<gfx::SourceSurface>
|
||||
PersistentBufferProviderShared::BorrowSnapshot() {
|
||||
// If we have a permanent back buffer we can always use that to snapshot.
|
||||
if (mPermanentBackBuffer) {
|
||||
mSnapshot = mPermanentBackBuffer->BorrowSnapshot();
|
||||
return do_AddRef(mSnapshot);
|
||||
}
|
||||
|
||||
if (mDrawTarget) {
|
||||
auto back = GetTexture(mBack);
|
||||
MOZ_ASSERT(back && back->IsLocked());
|
||||
|
@ -499,7 +558,7 @@ void PersistentBufferProviderShared::ReturnSnapshot(
|
|||
mSnapshot = nullptr;
|
||||
snapshot = nullptr;
|
||||
|
||||
if (mDrawTarget) {
|
||||
if (mDrawTarget || mPermanentBackBuffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -543,6 +602,11 @@ void PersistentBufferProviderShared::Destroy() {
|
|||
mSnapshot = nullptr;
|
||||
mDrawTarget = nullptr;
|
||||
|
||||
if (mPermanentBackBuffer) {
|
||||
mPermanentBackBuffer->Unlock();
|
||||
mPermanentBackBuffer = nullptr;
|
||||
}
|
||||
|
||||
for (auto& mTexture : mTextures) {
|
||||
TextureClient* texture = mTexture;
|
||||
if (texture && texture->IsLocked()) {
|
||||
|
|
|
@ -174,6 +174,11 @@ class PersistentBufferProviderShared : public PersistentBufferProvider,
|
|||
gfx::IntSize mSize;
|
||||
gfx::SurfaceFormat mFormat;
|
||||
RefPtr<KnowsCompositor> mKnowsCompositor;
|
||||
// If the texture has its own synchronization then copying back from the
|
||||
// previous texture can cause contention issues and even deadlocks. So we use
|
||||
// a separate permanent back buffer and copy into the shared back buffer when
|
||||
// the DrawTarget is returned, before making it the new front buffer.
|
||||
RefPtr<TextureClient> mPermanentBackBuffer;
|
||||
// We may need two extra textures if webrender is enabled.
|
||||
static const size_t kMaxTexturesAllowed = 4;
|
||||
Vector<RefPtr<TextureClient>, kMaxTexturesAllowed + 2> mTextures;
|
||||
|
|
|
@ -819,6 +819,13 @@ gfx::DrawTarget* TextureClient::BorrowDrawTarget() {
|
|||
return mBorrowedDrawTarget;
|
||||
}
|
||||
|
||||
void TextureClient::EndDraw() {
|
||||
MOZ_ASSERT(!mBorrowedDrawTarget ||
|
||||
mBorrowedDrawTarget->refCount() <= mExpectedDtRefs);
|
||||
mBorrowedDrawTarget = nullptr;
|
||||
mData->EndDraw();
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::SourceSurface> TextureClient::BorrowSnapshot() {
|
||||
MOZ_ASSERT(mIsLocked);
|
||||
|
||||
|
|
|
@ -269,6 +269,12 @@ class TextureData {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the TextureData is not being Unlocked, this can be used to inform a
|
||||
* TextureData that drawing has finished until the next BorrowDrawTarget.
|
||||
*/
|
||||
virtual void EndDraw() {}
|
||||
|
||||
virtual already_AddRefed<gfx::SourceSurface> BorrowSnapshot() {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -466,6 +472,12 @@ class TextureClient : public AtomicRefCountedWithFinalize<TextureClient> {
|
|||
*/
|
||||
gfx::DrawTarget* BorrowDrawTarget();
|
||||
|
||||
/**
|
||||
* When the TextureClient is not being Unlocked, this can be used to inform it
|
||||
* that drawing has finished until the next BorrowDrawTarget.
|
||||
*/
|
||||
void EndDraw();
|
||||
|
||||
already_AddRefed<gfx::SourceSurface> BorrowSnapshot();
|
||||
|
||||
/**
|
||||
|
|
|
@ -61,27 +61,30 @@ bool RecordedTextureData::Lock(OpenMode aMode) {
|
|||
mCanvasChild->RecordEvent(RecordedTextureLock(mTextureId, aMode));
|
||||
if (aMode & OpenMode::OPEN_WRITE) {
|
||||
mCanvasChild->OnTextureWriteLock();
|
||||
mSnapshot = nullptr;
|
||||
}
|
||||
mLockedMode = aMode;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RecordedTextureData::Unlock() {
|
||||
if ((mLockedMode & OpenMode::OPEN_WRITE) &&
|
||||
mCanvasChild->ShouldCacheDataSurface()) {
|
||||
mSnapshot = mDT->Snapshot();
|
||||
mDT->DetachAllSnapshots();
|
||||
}
|
||||
|
||||
mCanvasChild->RecordEvent(RecordedTextureUnlock(mTextureId));
|
||||
mLockedMode = OpenMode::OPEN_NONE;
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DrawTarget> RecordedTextureData::BorrowDrawTarget() {
|
||||
mSnapshot = nullptr;
|
||||
return do_AddRef(mDT);
|
||||
}
|
||||
|
||||
void RecordedTextureData::EndDraw() {
|
||||
MOZ_ASSERT(mDT->hasOneRef());
|
||||
|
||||
if (mCanvasChild->ShouldCacheDataSurface()) {
|
||||
mSnapshot = mDT->Snapshot();
|
||||
mCanvasChild->RecordEvent(RecordedCacheDataSurface(mSnapshot.get()));
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::SourceSurface> RecordedTextureData::BorrowSnapshot() {
|
||||
MOZ_ASSERT(mDT);
|
||||
|
||||
|
@ -101,9 +104,6 @@ bool RecordedTextureData::Serialize(SurfaceDescriptor& aDescriptor) {
|
|||
|
||||
void RecordedTextureData::OnForwardedToHost() {
|
||||
mCanvasChild->OnTextureForwarded();
|
||||
if (mSnapshot && mCanvasChild->ShouldCacheDataSurface()) {
|
||||
mCanvasChild->RecordEvent(RecordedCacheDataSurface(mSnapshot.get()));
|
||||
}
|
||||
}
|
||||
|
||||
TextureFlags RecordedTextureData::GetTextureFlags() const {
|
||||
|
|
|
@ -28,6 +28,8 @@ class RecordedTextureData final : public TextureData {
|
|||
|
||||
already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() final;
|
||||
|
||||
void EndDraw() final;
|
||||
|
||||
already_AddRefed<gfx::SourceSurface> BorrowSnapshot() final;
|
||||
|
||||
void Deallocate(LayersIPCChannel* aAllocator) final;
|
||||
|
|
Загрузка…
Ссылка в новой задаче