void PersistentBufferProviderShared::Destroy() { mSnapshot = nullptr; mDrawTarget = nullptr; for (uint32_t i = 0; i < mTextures.length(); ++i) { TextureClient* texture = mTextures[i]; if (texture && texture->IsLocked()) { MOZ_ASSERT(false); texture->Unlock(); } } mTextures.clear(); }
bool PersistentBufferProviderShared::ReturnDrawTarget(already_AddRefed<gfx::DrawTarget> aDT) { RefPtr<gfx::DrawTarget> dt(aDT); MOZ_ASSERT(mDrawTarget == dt); // Can't change the current front buffer while its snapshot is borrowed! MOZ_ASSERT(!mSnapshot); mDrawTarget = nullptr; dt = nullptr; TextureClient* back = GetTexture(mBack); MOZ_ASSERT(back); if (back) { back->Unlock(); mFront = mBack; } return !!back; }
already_AddRefed<gfx::DrawTarget> PersistentBufferProviderShared::BorrowDrawTarget(const gfx::IntRect& aPersistedRect) { if (!mFwd->GetTextureForwarder()->IPCOpen()) { return nullptr; } MOZ_ASSERT(!mSnapshot); if (IsActivityTracked()) { mFwd->GetActiveResourceTracker().MarkUsed(this); } else { mFwd->GetActiveResourceTracker().AddObject(this); } if (mDrawTarget) { RefPtr<gfx::DrawTarget> dt(mDrawTarget); return dt.forget(); } mFront = Nothing(); auto previousBackBuffer = mBack; TextureClient* tex = GetTexture(mBack); // First try to reuse the current back buffer. If we can do that it means // we can skip copying its content to the new back buffer. if (tex && tex->IsReadLocked()) { // The back buffer is currently used by the compositor, we can't draw // into it. tex = nullptr; } if (!tex) { // Try to grab an already allocated texture if any is available. for (uint32_t i = 0; i < mTextures.length(); ++i) { if (!mTextures[i]->IsReadLocked()) { mBack = Some(i); tex = mTextures[i]; break; } } } if (!tex) { // We have to allocate a new texture. if (mTextures.length() >= 4) { // We should never need to buffer that many textures, something's wrong. MOZ_ASSERT(false); // In theory we throttle the main thread when the compositor can't keep up, // so we shoud never get in a situation where we sent 4 textures to the // compositor and the latter as not released any of them. // This seems to happen, however, in some edge cases such as just after a // device reset (cf. Bug 1291163). // It would be pretty bad to keep piling textures up at this point so we // call NotifyInactive to remove some of our textures. NotifyInactive(); // Give up now. The caller can fall-back to a non-shared buffer provider. return nullptr; } RefPtr<TextureClient> newTexture = TextureClient::CreateForDrawing( mFwd, mFormat, mSize, BackendSelector::Canvas, TextureFlags::DEFAULT, TextureAllocationFlags::ALLOC_DEFAULT ); MOZ_ASSERT(newTexture); if (newTexture) { if (mTextures.append(newTexture)) { tex = newTexture; mBack = Some<uint32_t>(mTextures.length() - 1); } } } if (!tex || !tex->Lock(OpenMode::OPEN_READ_WRITE)) { return nullptr; } if (mBack != previousBackBuffer && !aPersistedRect.IsEmpty()) { TextureClient* previous = GetTexture(previousBackBuffer); if (previous && previous->Lock(OpenMode::OPEN_READ)) { DebugOnly<bool> success = previous->CopyToTextureClient(tex, &aPersistedRect, nullptr); MOZ_ASSERT(success); previous->Unlock(); } } mDrawTarget = tex->BorrowDrawTarget(); RefPtr<gfx::DrawTarget> dt(mDrawTarget); return dt.forget(); }