bool PluginViewPrivate::destroyBuffers() { PthreadMutexLocker backLock(&m_backBufferMutex); PthreadWriteLocker frontLock(&m_frontBufferRwLock); for (int i = 0; i < PLUGIN_BUFFERS; i++) { if (m_pluginBuffers[i]) { BlackBerry::Platform::Graphics::destroyBuffer(m_pluginBuffers[i]); m_pluginBuffers[i] = 0; } } m_pluginBufferSize = IntSize(); return true; }
bool PluginViewPrivate::resizeBuffers(NPSurfaceFormat format, int width, int height) { bool success = true; // If there is no buffer created, then try to create it. if (!m_pluginBufferSize.width() || !m_pluginBufferSize.height()) return createBuffers(format, width, height); if (!width || !height) return destroyBuffers(); PthreadMutexLocker backLock(&m_backBufferMutex); PthreadWriteLocker frontLock(&m_frontBufferRwLock); for (int i = 0; i < PLUGIN_BUFFERS && success; i++) { success &= BlackBerry::Platform::Graphics::reallocBuffer(m_pluginBuffers[i], BlackBerry::Platform::IntSize(width, height), toBufferType(format)); } if (success) { m_pluginBufferSize = IntSize(width, height); m_pluginBufferType = toBufferType(format); return true; } // Attempt to undo if we failed to get the new size/format. We can't guarantee // we will get it back though. if (!m_pluginBufferSize.width() || !m_pluginBufferSize.height()) { destroyBuffers(); return false; } bool undone = true; for (int i = 0; i < PLUGIN_BUFFERS; i++) { undone &= BlackBerry::Platform::Graphics::reallocBuffer(m_pluginBuffers[i], m_pluginBufferSize, m_pluginBufferType); } // If we fail to undo, delete the buffers altogether. if (!undone) destroyBuffers(); return false; }
bool PluginViewPrivate::createBuffers(NPSurfaceFormat format, int width, int height) { bool success = true; PthreadMutexLocker backLock(&m_backBufferMutex); PthreadWriteLocker frontLock(&m_frontBufferRwLock); for (int i = 0; i < PLUGIN_BUFFERS; i++) { if (m_pluginBuffers[i]) { BlackBerry::Platform::Graphics::destroyBuffer(m_pluginBuffers[i]); m_pluginBuffers[i] = 0; } if (width <= 0 || height <= 0) success = true; else { m_pluginBuffers[i] = BlackBerry::Platform::Graphics::createBuffer( BlackBerry::Platform::IntSize(width, height), toBufferType(format)); if (!m_pluginBuffers[i]) success = false; } } if (success) { m_pluginBufferSize = IntSize(width, height); m_pluginBufferType = toBufferType(format); } else { m_pluginBufferSize = IntSize(); m_pluginBufferType = BlackBerry::Platform::Graphics::PluginBufferWithAlpha; destroyBuffers(); } return success; }
// Sync front/back buffers content // After executing, the new back buffer has the same (interesting) pixels as // the new front buffer, and mValidRegion et al. are correct wrt the new // back buffer (i.e. as they were for the old back buffer) void ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw) { if (mTextureClient) { DebugOnly<bool> locked = mTextureClient->Lock(OpenMode::OPEN_READ_WRITE); MOZ_ASSERT(locked); } if (mTextureClientOnWhite) { DebugOnly<bool> locked = mTextureClientOnWhite->Lock(OpenMode::OPEN_READ_WRITE); MOZ_ASSERT(locked); } if (!mFrontAndBackBufferDiffer) { MOZ_ASSERT(!mDidSelfCopy, "If we have to copy the world, then our buffers are different, right?"); return; } MOZ_ASSERT(mFrontClient); if (!mFrontClient) { return; } MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>", this, mFrontUpdatedRegion.GetBounds().x, mFrontUpdatedRegion.GetBounds().y, mFrontUpdatedRegion.GetBounds().width, mFrontUpdatedRegion.GetBounds().height)); mFrontAndBackBufferDiffer = false; nsIntRegion updateRegion = mFrontUpdatedRegion; if (mDidSelfCopy) { mDidSelfCopy = false; updateRegion = mBufferRect; } // No point in sync'ing what we are going to draw over anyway. And if there is // nothing to sync at all, there is nothing to do and we can go home early. updateRegion.Sub(updateRegion, aRegionToDraw); if (updateRegion.IsEmpty()) { return; } // We need to ensure that we lock these two buffers in the same // order as the compositor to prevent deadlocks. TextureClientAutoLock frontLock(mFrontClient, OpenMode::OPEN_READ_ONLY); if (!frontLock.Succeeded()) { return; } Maybe<TextureClientAutoLock> frontOnWhiteLock; if (mFrontClientOnWhite) { frontOnWhiteLock.emplace(mFrontClientOnWhite, OpenMode::OPEN_READ_ONLY); if (!frontOnWhiteLock->Succeeded()) { return; } } // Restrict the DrawTargets and frontBuffer to a scope to make // sure there is no more external references to the DrawTargets // when we Unlock the TextureClients. gfx::DrawTarget* dt = mFrontClient->BorrowDrawTarget(); gfx::DrawTarget* dtw = mFrontClientOnWhite ? mFrontClientOnWhite->BorrowDrawTarget() : nullptr; if (dt && dt->IsValid()) { RefPtr<SourceSurface> surf = dt->Snapshot(); RefPtr<SourceSurface> surfOnWhite = dtw ? dtw->Snapshot() : nullptr; SourceRotatedBuffer frontBuffer(surf, surfOnWhite, mFrontBufferRect, mFrontBufferRotation); UpdateDestinationFrom(frontBuffer, updateRegion); } else { // We know this can happen, but we want to track it somewhat, in case it leads // to other problems. gfxCriticalNote << "Invalid draw target(s) " << hexa(dt) << " and " << hexa(dtw); } }
void ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData, bool aIsProgressive) { mWasLastPaintProgressive = aIsProgressive; // Compare layer valid region size to current backbuffer size, discard if not matching. gfx::IntSize size = aNewValidRegion.GetBounds().Size(); gfx::IntPoint origin = aNewValidRegion.GetBounds().TopLeft(); nsIntRegion paintRegion = aPaintRegion; RefPtr<TextureClient> discardedFrontBuffer = nullptr; RefPtr<TextureClient> discardedFrontBufferOnWhite = nullptr; nsIntRegion discardedValidRegion; if (mSize != size || mTilingOrigin != origin) { discardedFrontBuffer = mTile.mFrontBuffer; discardedFrontBufferOnWhite = mTile.mFrontBufferOnWhite; discardedValidRegion = mValidRegion; TILING_LOG("TILING %p: Single-tile valid region changed. Discarding buffers.\n", &mPaintedLayer) ; ResetPaintedAndValidState(); mSize = size; mTilingOrigin = origin; paintRegion = aNewValidRegion; } SurfaceMode mode; gfxContentType content = GetContentType(&mode); mFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(content); if (mTile.IsPlaceholderTile()) { mTile.SetTextureAllocator(this); } // The dirty region relative to the top-left of the tile. nsIntRegion tileDirtyRegion = paintRegion.MovedBy(-mTilingOrigin); nsIntRegion extraPainted; RefPtr<TextureClient> backBufferOnWhite; RefPtr<TextureClient> backBuffer = mTile.GetBackBuffer(mCompositableClient, tileDirtyRegion, content, mode, extraPainted, &backBufferOnWhite); mTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(extraPainted.GetBounds()); extraPainted.MoveBy(mTilingOrigin); extraPainted.And(extraPainted, aNewValidRegion); mPaintedRegion.OrWith(paintRegion); mPaintedRegion.OrWith(extraPainted); if (!backBuffer) { return; } RefPtr<gfx::DrawTarget> dt = backBuffer->BorrowDrawTarget(); RefPtr<gfx::DrawTarget> dtOnWhite; if (backBufferOnWhite) { dtOnWhite = backBufferOnWhite->BorrowDrawTarget(); } if (mode != SurfaceMode::SURFACE_OPAQUE) { for (auto iter = tileDirtyRegion.RectIter(); !iter.Done(); iter.Next()) { const gfx::IntRect& rect = iter.Get(); if (dtOnWhite) { dt->FillRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height), gfx::ColorPattern(gfx::Color(0.0, 0.0, 0.0, 1.0))); dtOnWhite->FillRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height), gfx::ColorPattern(gfx::Color(1.0, 1.0, 1.0, 1.0))); } else { dt->ClearRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height)); } } } // If the old frontbuffer was discarded then attempt to copy what we // can from it to the new backbuffer. if (discardedFrontBuffer) { nsIntRegion copyableRegion; copyableRegion.And(aNewValidRegion, discardedValidRegion); copyableRegion.SubOut(aDirtyRegion); if (!copyableRegion.IsEmpty()) { TextureClientAutoLock frontLock(discardedFrontBuffer, OpenMode::OPEN_READ); if (frontLock.Succeeded()) { for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) { const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft(); const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin; discardedFrontBuffer->CopyToTextureClient(backBuffer, &rect, &dest); } } if (discardedFrontBufferOnWhite && backBufferOnWhite) { TextureClientAutoLock frontOnWhiteLock(discardedFrontBufferOnWhite, OpenMode::OPEN_READ); if (frontOnWhiteLock.Succeeded()) { for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) { const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft(); const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin; discardedFrontBufferOnWhite->CopyToTextureClient(backBufferOnWhite, &rect, &dest); } } } TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str()); // We don't need to repaint valid content that was just copied. paintRegion.SubOut(copyableRegion); } } if (dtOnWhite) { dt = gfx::Factory::CreateDualDrawTarget(dt, dtOnWhite); dtOnWhite = nullptr; } { RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt); if (!ctx) { gfxDevCrash(gfx::LogReason::InvalidContext) << "SingleTiledContextClient context problem " << gfx::hexa(dt); return; } ctx->SetMatrix(ctx->CurrentMatrix().Translate(-mTilingOrigin.x, -mTilingOrigin.y)); aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData); } // Mark the area we just drew into the back buffer as invalid in the front buffer as they're // now out of sync. mTile.mInvalidFront.OrWith(tileDirtyRegion); // The new buffer is now validated, remove the dirty region from it. mTile.mInvalidBack.SubOut(tileDirtyRegion); dt = nullptr; mTile.Flip(); UnlockTile(mTile); if (backBuffer->HasIntermediateBuffer()) { // If our new buffer has an internal buffer, we don't want to keep another // TextureClient around unnecessarily, so discard the back-buffer. mTile.DiscardBackBuffer(); } mValidRegion = aNewValidRegion; mLastPaintSurfaceMode = mode; mLastPaintContentType = content; }
void PluginViewPrivate::swapBuffers() { PthreadMutexLocker backLock(&m_backBufferMutex); PthreadWriteLocker frontLock(&m_frontBufferRwLock); m_pluginFrontBuffer = (m_pluginFrontBuffer + 1) % 2; }