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;
}
Ejemplo n.º 4
0
// 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;
}