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); }
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"); }
/** 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); } } }
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; }
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; }
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; }
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; }
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); }
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 }
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); }
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); }
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; }
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); } }
/* 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; }