Example #1
0
TemporaryRef<DrawTarget>
ContentClientIncremental::GetUpdateSurface(BufferType aType,
        const nsIntRegion& aUpdateRegion)
{
    nsIntRect rgnSize = aUpdateRegion.GetBounds();
    if (!mBufferRect.Contains(rgnSize)) {
        NS_ERROR("update outside of image");
        return nullptr;
    }
    SurfaceDescriptor desc;
    if (!mForwarder->AllocSurfaceDescriptor(rgnSize.Size().ToIntSize(),
                                            mContentType,
                                            &desc)) {
        NS_WARNING("creating SurfaceDescriptor failed!");
        Clear();
        return nullptr;
    }

    if (aType == BUFFER_BLACK) {
        MOZ_ASSERT(!IsSurfaceDescriptorValid(mUpdateDescriptor));
        mUpdateDescriptor = desc;
    } else {
        MOZ_ASSERT(!IsSurfaceDescriptorValid(mUpdateDescriptorOnWhite));
        MOZ_ASSERT(aType == BUFFER_WHITE);
        mUpdateDescriptorOnWhite = desc;
    }

    return GetDrawTargetForDescriptor(desc, gfx::BackendType::COREGRAPHICS);
}
Example #2
0
nsIntRegion
ContentClientRemote::GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
                                      const nsIntRegion& aVisibleRegion,
                                      bool aDidSelfCopy)
{
  nsIntRegion updatedRegion;
  if (mIsNewBuffer || aDidSelfCopy) {
    // A buffer reallocation clears both buffers. The front buffer has all the
    // content by now, but the back buffer is still clear. Here, in effect, we
    // are saying to copy all of the pixels of the front buffer to the back.
    // Also when we self-copied in the buffer, the buffer space
    // changes and some changed buffer content isn't reflected in the
    // draw or invalidate region (on purpose!).  When this happens, we
    // need to read back the entire buffer too.
    updatedRegion = aVisibleRegion;
    mIsNewBuffer = false;
  } else {
    updatedRegion = aRegionToDraw;
  }

  NS_ASSERTION(BufferRect().Contains(aRegionToDraw.GetBounds()),
               "Update outside of buffer rect!");
  NS_ABORT_IF_FALSE(mTextureClient, "should have a back buffer by now");

  return updatedRegion;
}
already_AddRefed<gfxASurface>
ContentClientIncremental::GetUpdateSurface(BufferType aType,
                                           nsIntRegion& aUpdateRegion)
{
  nsIntRect rgnSize = aUpdateRegion.GetBounds();
  if (!mBufferRect.Contains(rgnSize)) {
    NS_ERROR("update outside of image");
    return nullptr;
  }
  SurfaceDescriptor desc;
  if (!mForwarder->AllocSurfaceDescriptor(gfxIntSize(rgnSize.width, rgnSize.height),
                                          mContentType,
                                          &desc)) {
    NS_WARNING("creating SurfaceDescriptor failed!");
    return nullptr;
  }

  nsRefPtr<gfxASurface> tmpASurface =
    ShadowLayerForwarder::OpenDescriptor(OPEN_READ_WRITE, desc);

  if (aType == BUFFER_BLACK) {
    MOZ_ASSERT(!IsSurfaceDescriptorValid(mUpdateDescriptor));
    mUpdateDescriptor = desc;
  } else {
    MOZ_ASSERT(!IsSurfaceDescriptorValid(mUpdateDescriptorOnWhite));
    MOZ_ASSERT(aType == BUFFER_WHITE);
    mUpdateDescriptorOnWhite = desc;
  }

  return tmpASurface.forget();
}
bool
TextureImageEGL::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */)
{
    nsIntRect bounds = aRegion.GetBounds();

    nsIntRegion region;
    if (mTextureState != Valid) {
        bounds = nsIntRect(0, 0, mSize.width, mSize.height);
        region = nsIntRegion(bounds);
    } else {
        region = aRegion;
    }

    mTextureFormat =
      UploadSurfaceToTexture(mGLContext,
                             aSurf,
                             region,
                             mTexture,
                             mTextureState == Created,
                             bounds.TopLeft() + aFrom,
                             false);

    mTextureState = Valid;
    return true;
}
/* static */ void
nsBaseWidget::debug_DumpPaintEvent(FILE *                aFileOut,
                                   nsIWidget *           aWidget,
                                   const nsIntRegion &   aRegion,
                                   const nsAutoCString & aWidgetName,
                                   int32_t               aWindowID)
{
  NS_ASSERTION(nullptr != aFileOut,"cmon, null output FILE");
  NS_ASSERTION(nullptr != aWidget,"cmon, the widget is null");

  if (!debug_GetCachedBoolPref("nglayout.debug.paint_dumping"))
    return;

  nsIntRect rect = aRegion.GetBounds();
  fprintf(aFileOut,
          "%4d PAINT      widget=%p name=%-12s id=0x%-6x bounds-rect=%3d,%-3d %3d,%-3d",
          _GetPrintCount(),
          (void *) aWidget,
          aWidgetName.get(),
          aWindowID,
          rect.x, rect.y, rect.width, rect.height
    );

  fprintf(aFileOut,"\n");
}
Example #6
0
/**
   aRegion is given in device coordinates!!
   aContext may be null, in which case layers should be used for
   rendering.
*/
void nsViewManager::Refresh(nsView *aView, const nsIntRegion& aRegion,
                            bool aWillSendDidPaint)
{
    NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");

    // damageRegion is the damaged area, in twips, relative to the view origin
    nsRegion damageRegion = aRegion.ToAppUnits(AppUnitsPerDevPixel());
    // move region from widget coordinates into view coordinates
    damageRegion.MoveBy(-aView->ViewToWidgetOffset());

    if (damageRegion.IsEmpty()) {
#ifdef DEBUG_roc
        nsRect viewRect = aView->GetDimensions();
        nsRect damageRect = damageRegion.GetBounds();
        printf("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n",
               damageRect.x, damageRect.y, damageRect.width, damageRect.height,
               viewRect.x, viewRect.y, viewRect.width, viewRect.height);
#endif
        return;
    }

    nsIWidget *widget = aView->GetWidget();
    if (!widget) {
        return;
    }

    NS_ASSERTION(!IsPainting(), "recursive painting not permitted");
    if (IsPainting()) {
        RootViewManager()->mRecursiveRefreshPending = true;
        return;
    }

    {
        nsAutoScriptBlocker scriptBlocker;
        SetPainting(true);

        NS_ASSERTION(GetDisplayRootFor(aView) == aView,
                     "Widgets that we paint must all be display roots");

        if (mPresShell) {
#ifdef DEBUG_INVALIDATIONS
            printf("--COMPOSITE-- %p\n", mPresShell);
#endif
            mPresShell->Paint(aView, damageRegion,
                              nsIPresShell::PAINT_COMPOSITE |
                              (aWillSendDidPaint ? nsIPresShell::PAINT_WILL_SEND_DID_PAINT : 0));
#ifdef DEBUG_INVALIDATIONS
            printf("--ENDCOMPOSITE--\n");
#endif
            mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT);
        }

        SetPainting(false);
    }

    if (RootViewManager()->mRecursiveRefreshPending) {
        RootViewManager()->mRecursiveRefreshPending = false;
        InvalidateAllViews();
    }
}
RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder,
                                 MLGRenderTarget* aTarget,
                                 const nsIntRegion& aInvalidRegion)
    : RenderViewMLGPU(aBuilder, nullptr) {
  mTarget = aTarget;
  mInvalidBounds = aInvalidRegion.GetBounds();

  // The clear region on the layer manager is the area that must be clear after
  // we finish drawing.
  mPostClearRegion = aBuilder->GetManager()->GetRegionToClear();

  // Clamp the post-clear region to the invalid bounds, since clears don't go
  // through the scissor rect if using ClearView.
  mPostClearRegion.AndWith(mInvalidBounds);

  // Since the post-clear will occlude everything, we include it in the final
  // opaque area.
  mOccludedRegion.OrWith(ViewAs<LayerPixel>(
      mPostClearRegion,
      PixelCastJustification::RenderTargetIsParentLayerForRoot));

  AL_LOG("RenderView %p root with invalid area %s, clear area %s\n", this,
         Stringify(mInvalidBounds).c_str(),
         Stringify(mPostClearRegion).c_str());
}
void
ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
                                                   const nsIntRegion& aUpdateRegion)
{
  nsRefPtr<gfxContext> destCtx =
    GetContextForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK);
  destCtx->SetOperator(gfxContext::OPERATOR_SOURCE);

  bool isClippingCheap = IsClippingCheap(destCtx, aUpdateRegion);
  if (isClippingCheap) {
    gfxUtils::ClipToRegion(destCtx, aUpdateRegion);
  }

  if (SupportsAzureContent()) {
    MOZ_ASSERT(!destCtx->IsCairo());

    if (destCtx->GetDrawTarget()->GetFormat() == FORMAT_B8G8R8A8) {
      destCtx->GetDrawTarget()->ClearRect(Rect(0, 0, mFrontBufferRect.width, mFrontBufferRect.height));
    }
    aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_BLACK);
  } else {
    aSource.DrawBufferWithRotation(destCtx, BUFFER_BLACK);
  }

  if (aSource.HaveBufferOnWhite()) {
    MOZ_ASSERT(HaveBufferOnWhite());
    nsRefPtr<gfxContext> destCtx =
      GetContextForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE);
    destCtx->SetOperator(gfxContext::OPERATOR_SOURCE);

    bool isClippingCheap = IsClippingCheap(destCtx, aUpdateRegion);
    if (isClippingCheap) {
      gfxUtils::ClipToRegion(destCtx, aUpdateRegion);
    }

    if (SupportsAzureContent()) {
      MOZ_ASSERT(!destCtx->IsCairo());

      if (destCtx->GetDrawTarget()->GetFormat() == FORMAT_B8G8R8A8) {
        destCtx->GetDrawTarget()->ClearRect(Rect(0, 0, mFrontBufferRect.width, mFrontBufferRect.height));
      }
      aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_WHITE);
    } else {
      aSource.DrawBufferWithRotation(destCtx, BUFFER_WHITE);
    }
  }
}
Example #9
0
static Layer*
FindBackgroundLayer(ReadbackLayer* aLayer, nsIntPoint* aOffset)
{
  gfx::Matrix transform;
  if (!aLayer->GetTransform().Is2D(&transform) ||
      transform.HasNonIntegerTranslation())
    return nullptr;
  nsIntPoint transformOffset(int32_t(transform._31), int32_t(transform._32));

  for (Layer* l = aLayer->GetPrevSibling(); l; l = l->GetPrevSibling()) {
    gfx::Matrix backgroundTransform;
    if (!l->GetTransform().Is2D(&backgroundTransform) ||
        gfx::ThebesMatrix(backgroundTransform).HasNonIntegerTranslation())
      return nullptr;

    nsIntPoint backgroundOffset(int32_t(backgroundTransform._31), int32_t(backgroundTransform._32));
    IntRect rectInBackground(transformOffset - backgroundOffset, aLayer->GetSize());
    const nsIntRegion visibleRegion = l->GetEffectiveVisibleRegion().ToUnknownRegion();
    if (!visibleRegion.Intersects(rectInBackground))
      continue;
    // Since l is present in the background, from here on we either choose l
    // or nothing.
    if (!visibleRegion.Contains(rectInBackground))
      return nullptr;

    if (l->GetEffectiveOpacity() != 1.0 ||
        l->HasMaskLayers() ||
        !(l->GetContentFlags() & Layer::CONTENT_OPAQUE))
    {
      return nullptr;
    }

    // cliprects are post-transform
    const Maybe<ParentLayerIntRect>& clipRect = l->GetEffectiveClipRect();
    if (clipRect && !clipRect->Contains(ViewAs<ParentLayerPixel>(IntRect(transformOffset, aLayer->GetSize()))))
      return nullptr;

    Layer::LayerType type = l->GetType();
    if (type != Layer::TYPE_COLOR && type != Layer::TYPE_PAINTED)
      return nullptr;

    *aOffset = backgroundOffset - transformOffset;
    return l;
  }

  return nullptr;
}
Example #10
0
static bool
IsClippingCheap(gfxContext* aTarget, const nsIntRegion& aRegion)
{
  // Assume clipping is cheap if the context just has an integer
  // translation, and the visible region is simple.
  return !aTarget->CurrentMatrix().HasNonIntegerTranslation() &&
         aRegion.GetNumRects() <= 1; 
}
bool
ClientTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion,
                                         nsIntRegion& aInvalidRegion,
                                         const nsIntRegion& aOldValidRegion,
                                         BasicTiledLayerPaintData* aPaintData,
                                         LayerManager::DrawThebesLayerCallback aCallback,
                                         void* aCallbackData)
{
  bool repeat = false;
  bool isBufferChanged = false;
  do {
    // Compute the region that should be updated. Repeat as many times as
    // is required.
    nsIntRegion regionToPaint;
    repeat = ComputeProgressiveUpdateRegion(aInvalidRegion,
                                            aOldValidRegion,
                                            regionToPaint,
                                            aPaintData,
                                            repeat);

    // There's no further work to be done.
    if (regionToPaint.IsEmpty()) {
      break;
    }

    isBufferChanged = true;

    // Keep track of what we're about to refresh.
    aValidRegion.Or(aValidRegion, regionToPaint);

    // aValidRegion may have been altered by InvalidateRegion, but we still
    // want to display stale content until it gets progressively updated.
    // Create a region that includes stale content.
    nsIntRegion validOrStale;
    validOrStale.Or(aValidRegion, aOldValidRegion);

    // Paint the computed region and subtract it from the invalid region.
    PaintThebes(validOrStale, regionToPaint, aCallback, aCallbackData);
    aInvalidRegion.Sub(aInvalidRegion, regionToPaint);
  } while (repeat);

  // Return false if nothing has been drawn, or give what has been drawn
  // to the shadow layer to upload.
  return isBufferChanged;
}
Example #12
0
bool
ContentHostSingleBuffered::UpdateThebes(const ThebesBufferData& aData,
                                        const nsIntRegion& aUpdated,
                                        const nsIntRegion& aOldValidRegionBack,
                                        nsIntRegion* aUpdatedRegionBack)
{
  aUpdatedRegionBack->SetEmpty();

  if (!mTextureHost) {
    mInitialised = false;
    return true; // FIXME should we return false? Returning true for now
  }              // to preserve existing behavior of NOT causing IPC errors.

  // updated is in screen coordinates. Convert it to buffer coordinates.
  nsIntRegion destRegion(aUpdated);
  destRegion.MoveBy(-aData.rect().TopLeft());

  if (!aData.rect().Contains(aUpdated.GetBounds()) ||
      aData.rotation().x > aData.rect().width ||
      aData.rotation().y > aData.rect().height) {
    NS_ERROR("Invalid update data");
    return false;
  }

  // destRegion is now in logical coordinates relative to the buffer, but we
  // need to account for rotation. We do that by moving the region to the
  // rotation offset and then wrapping any pixels that extend off the
  // bottom/right edges.

  // Shift to the rotation point
  destRegion.MoveBy(aData.rotation());

  nsIntSize bufferSize = aData.rect().Size();

  // Select only the pixels that are still within the buffer.
  nsIntRegion finalRegion;
  finalRegion.And(nsIntRect(nsIntPoint(), bufferSize), destRegion);

  // For each of the overlap areas (right, bottom-right, bottom), select those
  // pixels and wrap them around to the opposite edge of the buffer rect.
  AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().width, 0));
  AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().width, aData.rect().height));
  AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(0, aData.rect().height));

  MOZ_ASSERT(nsIntRect(0, 0, aData.rect().width, aData.rect().height).Contains(finalRegion.GetBounds()));

  mTextureHost->Updated(&finalRegion);
  if (mTextureHostOnWhite) {
    mTextureHostOnWhite->Updated(&finalRegion);
  }
  mInitialised = true;

  mBufferRect = aData.rect();
  mBufferRotation = aData.rotation();

  return true;
}
Example #13
0
static inline void
AddWrappedRegion(const nsIntRegion& aInput, nsIntRegion& aOutput,
                 const nsIntSize& aSize, const nsIntPoint& aShift)
{
  nsIntRegion tempRegion;
  tempRegion.And(nsIntRect(aShift, aSize), aInput);
  tempRegion.MoveBy(-aShift);
  aOutput.Or(aOutput, tempRegion);
}
void
LayerManagerComposite::InvalidateDebugOverlay(nsIntRegion& aInvalidRegion, const IntRect& aBounds)
{
  bool drawFps = gfxPrefs::LayersDrawFPS();
  bool drawFrameCounter = gfxPrefs::DrawFrameCounter();
  bool drawFrameColorBars = gfxPrefs::CompositorDrawColorBars();
  bool drawPaintTimes = gfxPrefs::AlwaysPaint();

  if (drawFps || drawFrameCounter) {
    aInvalidRegion.Or(aInvalidRegion, nsIntRect(0, 0, 256, 256));
  }
  if (drawFrameColorBars) {
    aInvalidRegion.Or(aInvalidRegion, nsIntRect(0, 0, 10, aBounds.height));
  }
  if (drawPaintTimes) {
    aInvalidRegion.Or(aInvalidRegion, nsIntRect(PaintCounter::GetPaintRect()));
  }
}
nsIntRegion
nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(nsIFrame* aFrame,
                                                      const nsPoint& aToReferenceFrame,
                                                      const nsIntRegion& aInvalidRegion)
{
  if (aInvalidRegion.IsEmpty()) {
    return nsIntRect();
  }

  // Don't bother calling GetEffectProperties; the filter property should
  // already have been set up during reflow/ComputeFrameEffectsRect
  nsIFrame* firstFrame =
    nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
  nsSVGFilterProperty *prop = nsSVGEffects::GetFilterProperty(firstFrame);
  if (!prop || !prop->IsInObserverLists()) {
    return aInvalidRegion;
  }

  int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();

  if (!prop || !prop->ReferencesValidResources()) {
    // The frame is either not there or not currently available,
    // perhaps because we're in the middle of tearing stuff down.
    // Be conservative, return our visual overflow rect relative
    // to the reference frame.
    nsRect overflow = aFrame->GetVisualOverflowRect() + aToReferenceFrame;
    return overflow.ToOutsidePixels(appUnitsPerDevPixel);
  }

  // Convert aInvalidRegion into bounding box frame space in app units:
  nsPoint toBoundingBox =
    aFrame->GetOffsetTo(firstFrame) + GetOffsetToBoundingBox(firstFrame);
  // The initial rect was relative to the reference frame, so we need to
  // remove that offset to get a rect relative to the current frame.
  toBoundingBox -= aToReferenceFrame;
  nsRegion preEffectsRegion = aInvalidRegion.ToAppUnits(appUnitsPerDevPixel).MovedBy(toBoundingBox);

  // Adjust the dirty area for effects, and shift it back to being relative to
  // the reference frame.
  nsRegion result = nsFilterInstance::GetPostFilterDirtyArea(firstFrame,
    preEffectsRegion).MovedBy(-toBoundingBox);
  // Return the result, in pixels relative to the reference frame.
  return result.ToOutsidePixels(appUnitsPerDevPixel);
}
nsRegion
nsFilterInstance::FilterSpaceToFrameSpace(const nsIntRegion& aRegion) const
{
  nsRegion result;
  for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
    // FilterSpaceToFrameSpace rounds out, so this works.
    result.Or(result, FilterSpaceToFrameSpace(iter.Get()));
  }
  return result;
}
void
ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
                                                   const nsIntRegion& aUpdateRegion)
{
  nsRefPtr<gfxContext> destCtx =
    GetContextForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK);
  if (!destCtx) {
    return;
  }
  destCtx->SetOperator(gfxContext::OPERATOR_SOURCE);

  bool isClippingCheap = IsClippingCheap(destCtx, aUpdateRegion);
  if (isClippingCheap) {
    gfxUtils::ClipToRegion(destCtx, aUpdateRegion);
  }

  if (SupportsAzureContent()) {
    MOZ_ASSERT(!destCtx->IsCairo());
    aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_BLACK, 1.0, OP_SOURCE);
  } else {
    aSource.DrawBufferWithRotation(destCtx, BUFFER_BLACK);
  }

  if (aSource.HaveBufferOnWhite()) {
    MOZ_ASSERT(HaveBufferOnWhite());
    nsRefPtr<gfxContext> destCtx =
      GetContextForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE);
    destCtx->SetOperator(gfxContext::OPERATOR_SOURCE);

    bool isClippingCheap = IsClippingCheap(destCtx, aUpdateRegion);
    if (isClippingCheap) {
      gfxUtils::ClipToRegion(destCtx, aUpdateRegion);
    }

    if (SupportsAzureContent()) {
      MOZ_ASSERT(!destCtx->IsCairo());
      aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_WHITE, 1.0, OP_SOURCE);
    } else {
      aSource.DrawBufferWithRotation(destCtx, BUFFER_WHITE);
    }
  }
}
static void
SubtractTransformedRegion(nsIntRegion& aRegion,
                          const nsIntRegion& aRegionToSubtract,
                          const Matrix4x4& aTransform)
{
  if (aRegionToSubtract.IsEmpty()) {
    return;
  }

  // For each rect in the region, find out its bounds in screen space and
  // subtract it from the screen region.
  nsIntRegionRectIterator it(aRegionToSubtract);
  while (const IntRect* rect = it.Next()) {
    Rect incompleteRect = aTransform.TransformBounds(ToRect(*rect));
    aRegion.Sub(aRegion, IntRect(incompleteRect.x,
                                   incompleteRect.y,
                                   incompleteRect.width,
                                   incompleteRect.height));
  }
}
bool
ClientTiledPaintedLayer::RenderHighPrecision(const nsIntRegion& aInvalidRegion,
                                            const nsIntRegion& aVisibleRegion,
                                            LayerManager::DrawPaintedLayerCallback aCallback,
                                            void* aCallbackData)
{
  // If we have started drawing low-precision already, then we
  // shouldn't do anything there.
  if (mPaintData.mLowPrecisionPaintCount != 0) {
    return false;
  }

  // Only draw progressively when there is something to paint and the
  // resolution is unchanged
  if (!aInvalidRegion.IsEmpty() &&
      UseProgressiveDraw() &&
      mContentClient->GetTiledBuffer()->GetFrameResolution() == mPaintData.mResolution) {
    // Store the old valid region, then clear it before painting.
    // We clip the old valid region to the visible region, as it only gets
    // used to decide stale content (currently valid and previously visible)
    nsIntRegion oldValidRegion = mContentClient->GetTiledBuffer()->GetValidRegion();
    oldValidRegion.And(oldValidRegion, aVisibleRegion);
    if (mPaintData.mCriticalDisplayPort) {
      oldValidRegion.And(oldValidRegion, mPaintData.mCriticalDisplayPort->ToUnknownRect());
    }

    TILING_LOG("TILING %p: Progressive update with old valid region %s\n", this, Stringify(oldValidRegion).c_str());

    nsIntRegion drawnRegion;
    bool updatedBuffer =
      mContentClient->GetTiledBuffer()->ProgressiveUpdate(GetValidRegion(), aInvalidRegion,
                      oldValidRegion, drawnRegion, &mPaintData, aCallback, aCallbackData);
    AddToValidRegion(drawnRegion);
    return updatedBuffer;
  }

  // Otherwise do a non-progressive paint. We must do this even when
  // the region to paint is empty as the valid region may have shrunk.

  nsIntRegion validRegion = aVisibleRegion;
  if (mPaintData.mCriticalDisplayPort) {
    validRegion.AndWith(mPaintData.mCriticalDisplayPort->ToUnknownRect());
  }
  SetValidRegion(validRegion);

  TILING_LOG("TILING %p: Non-progressive paint invalid region %s\n", this, Stringify(aInvalidRegion).c_str());
  TILING_LOG("TILING %p: Non-progressive paint new valid region %s\n", this, Stringify(GetValidRegion()).c_str());

  mContentClient->GetTiledBuffer()->SetFrameResolution(mPaintData.mResolution);
  mContentClient->GetTiledBuffer()->PaintThebes(GetValidRegion(), aInvalidRegion, aInvalidRegion,
                                                aCallback, aCallbackData);
  mPaintData.mPaintFinished = true;
  return true;
}
Example #20
0
SurfaceFormat
UploadSurfaceToTexture(GLContext* gl,
                       gfxASurface *aSurface,
                       const nsIntRegion& aDstRegion,
                       GLuint& aTexture,
                       bool aOverwrite,
                       const nsIntPoint& aSrcPoint,
                       bool aPixelBuffer,
                       GLenum aTextureUnit,
                       GLenum aTextureTarget)
{

    nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface();
    unsigned char* data = nullptr;

    if (!imageSurface ||
        (imageSurface->Format() != gfxImageFormatARGB32 &&
         imageSurface->Format() != gfxImageFormatRGB24 &&
         imageSurface->Format() != gfxImageFormatRGB16_565 &&
         imageSurface->Format() != gfxImageFormatA8)) {
        // We can't get suitable pixel data for the surface, make a copy
        nsIntRect bounds = aDstRegion.GetBounds();
        imageSurface =
          new gfxImageSurface(gfxIntSize(bounds.width, bounds.height),
                              gfxImageFormatARGB32);

        nsRefPtr<gfxContext> context = new gfxContext(imageSurface);

        context->Translate(-gfxPoint(aSrcPoint.x, aSrcPoint.y));
        context->SetSource(aSurface);
        context->Paint();
        data = imageSurface->Data();
        NS_ASSERTION(!aPixelBuffer,
                     "Must be using an image compatible surface with pixel buffers!");
    } else {
        // If a pixel buffer is bound the data pointer parameter is relative
        // to the start of the data block.
        if (!aPixelBuffer) {
              data = imageSurface->Data();
        }
        data += DataOffset(aSrcPoint, imageSurface->Stride(),
                           imageSurface->Format());
    }

    MOZ_ASSERT(imageSurface);
    imageSurface->Flush();

    return UploadImageDataToTexture(gl,
                                    data,
                                    imageSurface->Stride(),
                                    imageSurface->Format(),
                                    aDstRegion, aTexture, aOverwrite,
                                    aPixelBuffer, aTextureUnit, aTextureTarget);
}
Example #21
0
void
ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
                                                   const nsIntRegion& aUpdateRegion)
{
  DrawIterator iter;
  while (DrawTarget* destDT =
    BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK, &iter)) {
    bool isClippingCheap = IsClippingCheap(destDT, iter.mDrawRegion);
    if (isClippingCheap) {
      gfxUtils::ClipToRegion(destDT, iter.mDrawRegion);
    }

    aSource.DrawBufferWithRotation(destDT, BUFFER_BLACK, 1.0, CompositionOp::OP_SOURCE);
    if (isClippingCheap) {
      destDT->PopClip();
    }
    // Flush the destination before the sources become inaccessible (Unlock).
    destDT->Flush();
    ReturnDrawTargetToBuffer(destDT);
  }

  if (aSource.HaveBufferOnWhite()) {
    MOZ_ASSERT(HaveBufferOnWhite());
    DrawIterator whiteIter;
    while (DrawTarget* destDT =
      BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE, &whiteIter)) {
      bool isClippingCheap = IsClippingCheap(destDT, whiteIter.mDrawRegion);
      if (isClippingCheap) {
        gfxUtils::ClipToRegion(destDT, whiteIter.mDrawRegion);
      }

      aSource.DrawBufferWithRotation(destDT, BUFFER_WHITE, 1.0, CompositionOp::OP_SOURCE);
      if (isClippingCheap) {
        destDT->PopClip();
      }
      // Flush the destination before the sources become inaccessible (Unlock).
      destDT->Flush();
      ReturnDrawTargetToBuffer(destDT);
    }
  }
}
void
TiledLayerBufferComposite::Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer,
                                  const nsIntRegion& aNewValidRegion,
                                  const nsIntRegion& aInvalidateRegion,
                                  const gfxSize& aResolution)
{
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
  printf_stderr("Upload %i, %i, %i, %i\n", aInvalidateRegion.GetBounds().x, aInvalidateRegion.GetBounds().y, aInvalidateRegion.GetBounds().width, aInvalidateRegion.GetBounds().height);
  long start = PR_IntervalNow();
#endif

  mFrameResolution = aResolution;
  mMainMemoryTiledBuffer = aMainMemoryTiledBuffer;
  Update(aNewValidRegion, aInvalidateRegion);
  mMainMemoryTiledBuffer = nullptr;
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
  if (PR_IntervalNow() - start > 10) {
    printf_stderr("Time to upload %i\n", PR_IntervalNow() - start);
  }
#endif
}
Example #23
0
void
Compositor::DrawDiagnostics(DiagnosticFlags aFlags,
                            const nsIntRegion& aVisibleRegion,
                            const gfx::IntRect& aClipRect,
                            const gfx::Matrix4x4& aTransform,
                            uint32_t aFlashCounter)
{
  if (!ShouldDrawDiagnostics(aFlags)) {
    return;
  }

  if (aVisibleRegion.GetNumRects() > 1) {
    for (auto iter = aVisibleRegion.RectIter(); !iter.Done(); iter.Next()) {
      DrawDiagnostics(aFlags | DiagnosticFlags::REGION_RECT,
                      IntRectToRect(iter.Get()), aClipRect, aTransform,
                      aFlashCounter);
    }
  }

  DrawDiagnostics(aFlags, IntRectToRect(aVisibleRegion.GetBounds()),
                  aClipRect, aTransform, aFlashCounter);
}
Example #24
0
void
Compositor::DrawDiagnostics(DiagnosticFlags aFlags,
                            const nsIntRegion& aVisibleRegion,
                            const gfx::Rect& aClipRect,
                            const gfx::Matrix4x4& aTransform)
{
  if (!ShouldDrawDiagnostics(aFlags)) {
    return;
  }

  if (aVisibleRegion.GetNumRects() > 1) {
    nsIntRegionRectIterator screenIter(aVisibleRegion);

    while (const nsIntRect* rect = screenIter.Next())
    {
      DrawDiagnostics(aFlags | DIAGNOSTIC_REGION_RECT,
                      ToRect(*rect), aClipRect, aTransform);
    }
  }

  DrawDiagnostics(aFlags, ToRect(aVisibleRegion.GetBounds()),
                  aClipRect, aTransform);
}
Example #25
0
void
AppendToString(std::stringstream& aStream, const nsIntRegion& r,
               const char* pfx, const char* sfx)
{
  aStream << pfx;

  aStream << "< ";
  for (auto iter = r.RectIter(); !iter.Done(); iter.Next()) {
    AppendToString(aStream, iter.Get());
    aStream << "; ";
  }
  aStream << ">";

  aStream << sfx;
}
Example #26
0
void
TextureImageEGL::GetUpdateRegion(nsIntRegion& aForRegion)
{
    if (mTextureState != Valid) {
        // if the texture hasn't been initialized yet, force the
        // client to paint everything
        aForRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
    }

    // We can only draw a rectangle, not subregions due to
    // the way that our texture upload functions work.  If
    // needed, we /could/ do multiple texture uploads if we have
    // non-overlapping rects, but that's a tradeoff.
    aForRegion = nsIntRegion(aForRegion.GetBounds());
}
void
TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
                                        bool aCanRerasterizeValidRegion)
{
  if (mBackBuffer && mFrontBuffer) {
    const nsIntRect tileRect = nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);

    if (aDirtyRegion.Contains(tileRect)) {
      // The dirty region means that we no longer need the front buffer, so
      // discard it.
      DiscardFrontBuffer();
    } else {
      // Region that needs copying.
      nsIntRegion regionToCopy = mInvalidBack;

      regionToCopy.Sub(regionToCopy, aDirtyRegion);

      if (regionToCopy.IsEmpty() ||
          (aCanRerasterizeValidRegion &&
           regionToCopy.Area() < MINIMUM_TILE_COPY_AREA)) {
        // Just redraw it all.
        return;
      }

      if (!mFrontBuffer->Lock(OPEN_READ)) {
        NS_WARNING("Failed to lock the tile's front buffer");
        return;
      }
      TextureClientAutoUnlock autoFront(mFrontBuffer);

      if (!mBackBuffer->Lock(OPEN_WRITE)) {
        NS_WARNING("Failed to lock the tile's back buffer");
        return;
      }
      TextureClientAutoUnlock autoBack(mBackBuffer);

      // Copy the bounding rect of regionToCopy. As tiles are quite small, it
      // is unlikely that we'd save much by copying each individual rect of the
      // region, but we can reevaluate this if it becomes an issue.
      const nsIntRect rectToCopy = regionToCopy.GetBounds();
      gfx::IntRect gfxRectToCopy(rectToCopy.x, rectToCopy.y, rectToCopy.width, rectToCopy.height);
      gfx::IntPoint gfxRectToCopyTopLeft = gfxRectToCopy.TopLeft();
      mFrontBuffer->CopyToTextureClient(mBackBuffer, &gfxRectToCopy, &gfxRectToCopyTopLeft);

      mInvalidBack.SetEmpty();
    }
  }
}
void
LayerManagerComposite::ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaqueRegion)
{
  nsIntRegion localOpaque;
  Matrix transform2d;
  bool isTranslation = false;
  // If aLayer has a simple transform (only an integer translation) then we
  // can easily convert aOpaqueRegion into pre-transform coordinates and include
  // that region.
  if (aLayer->GetLocalTransform().Is2D(&transform2d)) {
    if (transform2d.IsIntegerTranslation()) {
      isTranslation = true;
      localOpaque = aOpaqueRegion;
      localOpaque.MoveBy(-transform2d._31, -transform2d._32);
    }
  }

  // Subtract any areas that we know to be opaque from our
  // visible region.
  LayerComposite *composite = aLayer->AsLayerComposite();
  if (!localOpaque.IsEmpty()) {
    nsIntRegion visible = composite->GetShadowVisibleRegion();
    visible.Sub(visible, localOpaque);
    composite->SetShadowVisibleRegion(visible);
  }

  // Compute occlusions for our descendants (in front-to-back order) and allow them to
  // contribute to localOpaque.
  for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
    ApplyOcclusionCulling(child, localOpaque);
  }

  // If we have a simple transform, then we can add our opaque area into
  // aOpaqueRegion.
  if (isTranslation &&
      !aLayer->HasMaskLayers() &&
      aLayer->GetLocalOpacity() == 1.0f) {
    if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) {
      localOpaque.Or(localOpaque, composite->GetFullyRenderedRegion());
    }
    localOpaque.MoveBy(transform2d._31, transform2d._32);
    const Maybe<ParentLayerIntRect>& clip = aLayer->GetEffectiveClipRect();
    if (clip) {
      localOpaque.And(localOpaque, ParentLayerIntRect::ToUntyped(*clip));
    }
    aOpaqueRegion.Or(aOpaqueRegion, localOpaque);
  }
}
Example #29
0
/* static */ bool
HwcUtils::PrepareVisibleRegion(const nsIntRegion& aVisible,
                               const gfx::Matrix& aLayerTransform,
                               const gfx::Matrix& aLayerBufferTransform,
                               nsIntRect aClip, nsIntRect aBufferRect,
                               RectVector* aVisibleRegionScreen,
                               bool& aIsVisible) {
    const float MIN_SRC_WIDTH = 2.f;
    const float MIN_SRC_HEIGHT = 2.f;

    gfxMatrix layerTransform = gfx::ThebesMatrix(aLayerTransform);
    gfxMatrix layerBufferTransform = gfx::ThebesMatrix(aLayerBufferTransform);
    gfxRect bufferRect =
        layerBufferTransform.TransformBounds(ThebesRect(aBufferRect));
    gfxMatrix inverse = gfx::ThebesMatrix(aLayerBufferTransform);
    inverse.Invert();
    aIsVisible = false;

    for (auto iter = aVisible.RectIter(); !iter.Done(); iter.Next()) {
        gfxRect screenRect =
            layerTransform.TransformBounds(ThebesRect(iter.Get()));
        screenRect.IntersectRect(screenRect, bufferRect);
        screenRect.IntersectRect(screenRect, ThebesRect(aClip));
        screenRect.Round();
        if (screenRect.IsEmpty()) {
            continue;
        }

        hwc_rect_t visibleRectScreen;
        visibleRectScreen.left = screenRect.x;
        visibleRectScreen.top  = screenRect.y;
        visibleRectScreen.right  = screenRect.XMost();
        visibleRectScreen.bottom = screenRect.YMost();

        gfxRect srcCrop = inverse.TransformBounds(screenRect);
        // When src crop is very small, HWC could not render correctly in some cases.
        // See Bug 1169093
        if(srcCrop.Width() < MIN_SRC_WIDTH || srcCrop.Height() < MIN_SRC_HEIGHT) {
            return false;
        }

        aVisibleRegionScreen->push_back(visibleRectScreen);
        aIsVisible = true;
    }

    return true;
}
bool
ClientTiledPaintedLayer::RenderHighPrecision(nsIntRegion& aInvalidRegion,
                                            const nsIntRegion& aVisibleRegion,
                                            LayerManager::DrawPaintedLayerCallback aCallback,
                                            void* aCallbackData)
{
  // If we have no high-precision stuff to draw, or we have started drawing low-precision
  // already, then we shouldn't do anything there.
  if (aInvalidRegion.IsEmpty() || mPaintData.mLowPrecisionPaintCount != 0) {
    return false;
  }

  // Only draw progressively when the resolution is unchanged, and we're not
  // in a reftest scenario (that's what the HasShadowManager() check is for).
  if (gfxPlatform::GetPlatform()->UseProgressivePaint() &&
      !ClientManager()->HasShadowTarget() &&
      mContentClient->mTiledBuffer.GetFrameResolution() == mPaintData.mResolution) {
    // Store the old valid region, then clear it before painting.
    // We clip the old valid region to the visible region, as it only gets
    // used to decide stale content (currently valid and previously visible)
    nsIntRegion oldValidRegion = mContentClient->mTiledBuffer.GetValidRegion();
    oldValidRegion.And(oldValidRegion, aVisibleRegion);
    if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
      oldValidRegion.And(oldValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
    }

    TILING_LOG("TILING %p: Progressive update with old valid region %s\n", this, Stringify(oldValidRegion).c_str());

    return mContentClient->mTiledBuffer.ProgressiveUpdate(mValidRegion, aInvalidRegion,
                      oldValidRegion, &mPaintData, aCallback, aCallbackData);
  }

  // Otherwise do a non-progressive paint

  mValidRegion = aVisibleRegion;
  if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
    mValidRegion.And(mValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
  }

  TILING_LOG("TILING %p: Non-progressive paint invalid region %s\n", this, Stringify(aInvalidRegion).c_str());
  TILING_LOG("TILING %p: Non-progressive paint new valid region %s\n", this, Stringify(mValidRegion).c_str());

  mContentClient->mTiledBuffer.SetFrameResolution(mPaintData.mResolution);
  mContentClient->mTiledBuffer.PaintThebes(mValidRegion, aInvalidRegion, aCallback, aCallbackData);
  return true;
}