--- a/gfx/layers/CompositorTypes.h
+++ b/gfx/layers/CompositorTypes.h
@@ -243,24 +243,25 @@ struct TextureInfo
* How a SurfaceDescriptor will be opened.
*
* See ShadowLayerForwarder::OpenDescriptor for example.
*/
enum class OpenMode : uint8_t {
OPEN_NONE = 0,
OPEN_READ = 0x1,
OPEN_WRITE = 0x2,
- OPEN_READ_WRITE = OPEN_READ|OPEN_WRITE,
- OPEN_READ_ONLY = OPEN_READ,
- OPEN_WRITE_ONLY = OPEN_WRITE,
-
// This is only used in conjunction with OMTP to indicate that the DrawTarget
// that is being borrowed will be painted asynchronously, and so will outlive
// the write lock.
- OPEN_ASYNC_WRITE = 0x04
+ OPEN_ASYNC_WRITE = 0x04,
+
+ OPEN_READ_WRITE = OPEN_READ|OPEN_WRITE,
+ OPEN_READ_ASYNC_WRITE = OPEN_READ|OPEN_WRITE|OPEN_ASYNC_WRITE,
+ OPEN_READ_ONLY = OPEN_READ,
+ OPEN_WRITE_ONLY = OPEN_WRITE,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(OpenMode)
// The kinds of mask texture a shader can support
// We rely on the items in this enum being sequential
enum class MaskType : uint8_t {
MaskNone = 0, // no mask layer
Mask, // mask layer
--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -284,29 +284,16 @@ WrapRotationAxis(int32_t* aRotationPoint
{
if (*aRotationPoint < 0) {
*aRotationPoint += aSize;
} else if (*aRotationPoint >= aSize) {
*aRotationPoint -= aSize;
}
}
-static IntRect
-ComputeBufferRect(const IntRect& aRequestedRect)
-{
- IntRect rect(aRequestedRect);
- // Set a minimum width to guarantee a minimum size of buffers we
- // allocate (and work around problems on some platforms with smaller
- // dimensions). 64 used to be the magic number needed to work around
- // a rendering glitch on b2g (see bug 788411). Now that we don't support
- // this device anymore we should be fine with 8 pixels as the minimum.
- rect.SetWidth(std::max(aRequestedRect.Width(), 8));
- return rect;
-}
-
bool
RotatedBuffer::AdjustTo(const gfx::IntRect& aDestBufferRect,
const gfx::IntRect& aDrawBounds,
bool aCanHaveRotation,
bool aCanDrawRotated)
{
IntRect keepArea;
if (keepArea.IntersectRect(aDestBufferRect, mBufferRect)) {
@@ -464,16 +451,28 @@ RotatedBuffer::BorrowDrawTargetForQuadra
MOZ_ASSERT(aOutMatrix);
*aOutMatrix = Matrix::Translation(-quadrantRect.x, -quadrantRect.y);
mSetTransform = false;
}
return mLoanedDrawTarget;
}
+gfx::SurfaceFormat
+RemoteRotatedBuffer::GetFormat() const
+{
+ return mClient->GetFormat();
+}
+
+bool
+RemoteRotatedBuffer::IsLocked()
+{
+ return mClient->IsLocked();
+}
+
bool
RemoteRotatedBuffer::Lock(OpenMode aMode)
{
MOZ_ASSERT(!mTarget);
MOZ_ASSERT(!mTargetOnWhite);
bool locked = mClient->Lock(aMode) &&
(!mClientOnWhite || mClientOnWhite->Lock(aMode));
@@ -514,16 +513,25 @@ RemoteRotatedBuffer::Unlock()
mClient->Unlock();
}
if (mClientOnWhite && mClientOnWhite->IsLocked()) {
mClientOnWhite->Unlock();
}
}
void
+RemoteRotatedBuffer::SyncWithObject(SyncObjectClient* aSyncObject)
+{
+ mClient->SyncWithObject(aSyncObject);
+ if (mClientOnWhite) {
+ mClientOnWhite->SyncWithObject(aSyncObject);
+ }
+}
+
+void
RemoteRotatedBuffer::Clear()
{
MOZ_ASSERT(!mTarget && !mTargetOnWhite);
mClient = nullptr;
mClientOnWhite = nullptr;
}
already_AddRefed<gfx::SourceSurface>
@@ -544,16 +552,22 @@ RemoteRotatedBuffer::GetDTBuffer() const
}
gfx::DrawTarget*
RemoteRotatedBuffer::GetDTBufferOnWhite() const
{
return mTargetOnWhite;
}
+gfx::SurfaceFormat
+DrawTargetRotatedBuffer::GetFormat() const
+{
+ return mTarget->GetFormat();
+}
+
already_AddRefed<gfx::SourceSurface>
DrawTargetRotatedBuffer::GetSourceSurface(ContextSource aSource) const
{
if (aSource == ContextSource::BUFFER_BLACK) {
return mTarget->Snapshot();
} else {
MOZ_ASSERT(aSource == ContextSource::BUFFER_WHITE);
return mTargetOnWhite->Snapshot();
@@ -567,477 +581,32 @@ DrawTargetRotatedBuffer::GetDTBuffer() c
}
gfx::DrawTarget*
DrawTargetRotatedBuffer::GetDTBufferOnWhite() const
{
return mTargetOnWhite;
}
+gfx::SurfaceFormat
+SourceRotatedBuffer::GetFormat() const
+{
+ return mSource->GetFormat();
+}
+
already_AddRefed<SourceSurface>
SourceRotatedBuffer::GetSourceSurface(ContextSource aSource) const
{
RefPtr<SourceSurface> surf;
if (aSource == BUFFER_BLACK) {
surf = mSource;
} else {
MOZ_ASSERT(aSource == BUFFER_WHITE);
surf = mSourceOnWhite;
}
MOZ_ASSERT(surf);
return surf.forget();
}
-RotatedContentBuffer::BufferDecision
-RotatedContentBuffer::CalculateBufferForPaint(PaintedLayer* aLayer,
- uint32_t aFlags)
-{
- ContentType layerContentType =
- aLayer->CanUseOpaqueSurface() ? gfxContentType::COLOR :
- gfxContentType::COLOR_ALPHA;
-
- SurfaceMode mode;
- ContentType contentType;
- IntRect destBufferRect;
- nsIntRegion neededRegion;
- nsIntRegion validRegion = aLayer->GetValidRegion();
-
- bool canReuseBuffer = HaveBuffer();
- bool canKeepBufferContents = true;
-
- while (true) {
- mode = aLayer->GetSurfaceMode();
- neededRegion = aLayer->GetVisibleRegion().ToUnknownRegion();
- canReuseBuffer &= BufferSizeOkFor(neededRegion.GetBounds().Size());
- contentType = layerContentType;
-
- if (canReuseBuffer) {
- if (mBufferRect.Contains(neededRegion.GetBounds())) {
- // We don't need to adjust mBufferRect.
- destBufferRect = mBufferRect;
- } else if (neededRegion.GetBounds().Size() <= mBufferRect.Size()) {
- // The buffer's big enough but doesn't contain everything that's
- // going to be visible. We'll move it.
- destBufferRect = IntRect(neededRegion.GetBounds().TopLeft(), mBufferRect.Size());
- } else {
- destBufferRect = neededRegion.GetBounds();
- }
- } else {
- // We won't be reusing the buffer. Compute a new rect.
- destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
- }
-
- if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
-#if defined(MOZ_GFX_OPTIMIZE_MOBILE)
- mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
-#else
- if (!aLayer->GetParent() ||
- !aLayer->GetParent()->SupportsComponentAlphaChildren() ||
- !aLayer->AsShadowableLayer() ||
- !aLayer->AsShadowableLayer()->HasShadow()) {
- mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
- } else {
- contentType = gfxContentType::COLOR;
- }
-#endif
- }
-
- if ((aFlags & PAINT_WILL_RESAMPLE) &&
- (!neededRegion.GetBounds().IsEqualInterior(destBufferRect) ||
- neededRegion.GetNumRects() > 1))
- {
- // The area we add to neededRegion might not be painted opaquely.
- if (mode == SurfaceMode::SURFACE_OPAQUE) {
- contentType = gfxContentType::COLOR_ALPHA;
- mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
- }
-
- // We need to validate the entire buffer, to make sure that only valid
- // pixels are sampled.
- neededRegion = destBufferRect;
- }
-
- // If we have an existing buffer, but the content type has changed or we
- // have transitioned into/out of component alpha, then we need to recreate it.
- if (canReuseBuffer &&
- (contentType != BufferContentType() ||
- (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != HaveBufferOnWhite()))
- {
- // Restart the decision process; we won't re-enter since we guard on
- // being able to re-use the buffer.
- canReuseBuffer = false;
- canKeepBufferContents = false;
- validRegion.SetEmpty();
- continue;
- }
-
- break;
- }
-
- NS_ASSERTION(destBufferRect.Contains(neededRegion.GetBounds()),
- "Destination rect doesn't contain what we need to paint");
-
- BufferDecision dest;
- dest.mNeededRegion = Move(neededRegion);
- dest.mValidRegion = Move(validRegion);
- dest.mBufferRect = destBufferRect;
- dest.mBufferMode = mode;
- dest.mBufferContentType = contentType;
- dest.mCanReuseBuffer = canReuseBuffer;
- dest.mCanKeepBufferContents = canKeepBufferContents;
- return dest;
-}
-
-gfxContentType
-RotatedContentBuffer::BufferContentType()
-{
- if (mBufferProvider || (mDTBuffer && mDTBuffer->IsValid())) {
- SurfaceFormat format = SurfaceFormat::B8G8R8A8;
-
- if (mBufferProvider) {
- format = mBufferProvider->GetFormat();
- } else if (mDTBuffer && mDTBuffer->IsValid()) {
- format = mDTBuffer->GetFormat();
- }
-
- return ContentForFormat(format);
- }
- return gfxContentType::SENTINEL;
-}
-
-bool
-RotatedContentBuffer::BufferSizeOkFor(const IntSize& aSize)
-{
- return (aSize == mBufferRect.Size() ||
- (SizedToVisibleBounds != mBufferSizePolicy &&
- aSize < mBufferRect.Size()));
-}
-
-bool
-RotatedContentBuffer::EnsureBuffer()
-{
- NS_ASSERTION(!mLoanedDrawTarget, "Loaned draw target must be returned");
- if (!mDTBuffer || !mDTBuffer->IsValid()) {
- if (mBufferProvider) {
- mDTBuffer = mBufferProvider->BorrowDrawTarget();
- }
- }
-
- NS_WARNING_ASSERTION(mDTBuffer && mDTBuffer->IsValid(), "no buffer");
- return !!mDTBuffer;
-}
-
-bool
-RotatedContentBuffer::EnsureBufferOnWhite()
-{
- NS_ASSERTION(!mLoanedDrawTarget, "Loaned draw target must be returned");
- if (!mDTBufferOnWhite) {
- if (mBufferProviderOnWhite) {
- mDTBufferOnWhite =
- mBufferProviderOnWhite->BorrowDrawTarget();
- }
- }
-
- NS_WARNING_ASSERTION(mDTBufferOnWhite, "no buffer");
- return !!mDTBufferOnWhite;
-}
-
-bool
-RotatedContentBuffer::HaveBuffer() const
-{
- return mBufferProvider || (mDTBuffer && mDTBuffer->IsValid());
-}
-
-bool
-RotatedContentBuffer::HaveBufferOnWhite() const
-{
- return mBufferProviderOnWhite || (mDTBufferOnWhite && mDTBufferOnWhite->IsValid());
-}
-
-void
-RotatedContentBuffer::FlushBuffers()
-{
- if (mDTBuffer) {
- mDTBuffer->Flush();
- }
- if (mDTBufferOnWhite) {
- mDTBufferOnWhite->Flush();
- }
-}
-
-RotatedContentBuffer::PaintState
-RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer,
- uint32_t aFlags)
-{
- PaintState result;
-
- BufferDecision dest = CalculateBufferForPaint(aLayer, aFlags);
- result.mContentType = dest.mBufferContentType;
-
- if (!dest.mCanKeepBufferContents) {
- // We're effectively clearing the valid region, so we need to draw
- // the entire needed region now.
- MOZ_ASSERT(!dest.mCanReuseBuffer);
- MOZ_ASSERT(dest.mValidRegion.IsEmpty());
-
- result.mRegionToInvalidate = aLayer->GetValidRegion();
- Clear();
-
-#if defined(MOZ_DUMP_PAINTING)
- if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
- if (result.mContentType != BufferContentType()) {
- printf_stderr("Invalidating entire rotated buffer (layer %p): content type changed\n", aLayer);
- } else if ((dest.mBufferMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != HaveBufferOnWhite()) {
- printf_stderr("Invalidating entire rotated buffer (layer %p): component alpha changed\n", aLayer);
- }
- }
-#endif
- }
-
- result.mRegionToDraw.Sub(dest.mNeededRegion,
- dest.mValidRegion);
-
- if (result.mRegionToDraw.IsEmpty())
- return result;
-
- if (HaveBuffer()) {
- if (LockBuffers()) {
- // Do not modify result.mRegionToDraw or result.mContentType after this call.
- // Do not modify mBufferRect, mBufferRotation, or mDidSelfCopy,
- // or call CreateBuffer before this call.
- FinalizeFrame(result.mRegionToDraw);
- } else {
- // Abandon everything and redraw it all. Ideally we'd reallocate and copy
- // the old to the new and then call FinalizeFrame on the new buffer so that
- // we only need to draw the latest bits, but we need a big refactor to support
- // that ordering.
- result.mRegionToDraw = dest.mNeededRegion;
- dest.mCanReuseBuffer = false;
- Clear();
- }
- }
-
- // We need to disable rotation if we're going to be resampled when
- // drawing, because we might sample across the rotation boundary.
- // Also disable buffer rotation when using webrender.
- bool canHaveRotation = gfxPlatform::BufferRotationEnabled() &&
- !(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION)) &&
- !(aLayer->Manager()->AsWebRenderLayerManager());
- bool canDrawRotated = aFlags & PAINT_CAN_DRAW_ROTATED;
-
- IntRect drawBounds = result.mRegionToDraw.GetBounds();
- RefPtr<DrawTarget> destDTBuffer;
- RefPtr<DrawTarget> destDTBufferOnWhite;
- uint32_t bufferFlags = 0;
- if (dest.mBufferMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
- bufferFlags |= BUFFER_COMPONENT_ALPHA;
- }
- if (dest.mCanReuseBuffer) {
- if (!EnsureBuffer() ||
- (HaveBufferOnWhite() && !EnsureBufferOnWhite())) {
- return result;
- }
-
- if (!AdjustTo(dest.mBufferRect,
- drawBounds,
- canHaveRotation,
- canDrawRotated)) {
- dest.mBufferRect = ComputeBufferRect(dest.mNeededRegion.GetBounds());
- CreateBuffer(result.mContentType, dest.mBufferRect, bufferFlags,
- &destDTBuffer, &destDTBufferOnWhite);
-
- if (!destDTBuffer ||
- (!destDTBufferOnWhite && (bufferFlags & BUFFER_COMPONENT_ALPHA))) {
- if (Factory::ReasonableSurfaceSize(IntSize(dest.mBufferRect.Width(), dest.mBufferRect.Height()))) {
- gfxCriticalNote << "Failed 1 buffer db=" << hexa(destDTBuffer.get())
- << " dw=" << hexa(destDTBufferOnWhite.get())
- << " for " << dest.mBufferRect.x << ", "
- << dest.mBufferRect.y << ", "
- << dest.mBufferRect.Width() << ", "
- << dest.mBufferRect.Height();
- }
- return result;
- }
- }
- } else {
- // The buffer's not big enough, so allocate a new one
- CreateBuffer(result.mContentType, dest.mBufferRect, bufferFlags,
- &destDTBuffer, &destDTBufferOnWhite);
- if (!destDTBuffer ||
- (!destDTBufferOnWhite && (bufferFlags & BUFFER_COMPONENT_ALPHA))) {
- if (Factory::ReasonableSurfaceSize(IntSize(dest.mBufferRect.Width(), dest.mBufferRect.Height()))) {
- gfxCriticalNote << "Failed 2 buffer db=" << hexa(destDTBuffer.get())
- << " dw=" << hexa(destDTBufferOnWhite.get())
- << " for " << dest.mBufferRect.x << ", "
- << dest.mBufferRect.y << ", "
- << dest.mBufferRect.Width() << ", "
- << dest.mBufferRect.Height();
- }
- return result;
- }
- }
-
- NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || dest.mBufferRect == dest.mNeededRegion.GetBounds(),
- "If we're resampling, we need to validate the entire buffer");
-
- // If needed, copy the old buffer over to the new one
- if (destDTBuffer) {
- if ((HaveBuffer() && EnsureBuffer()) &&
- (dest.mBufferMode != SurfaceMode::SURFACE_COMPONENT_ALPHA || (HaveBufferOnWhite() && EnsureBufferOnWhite()))) {
- DrawTargetRotatedBuffer oldBuffer = DrawTargetRotatedBuffer(mDTBuffer, mDTBufferOnWhite,
- mBufferRect, mBufferRotation);
-
- mDTBuffer = destDTBuffer.forget();
- mDTBufferOnWhite = destDTBufferOnWhite.forget();
- mBufferRect = dest.mBufferRect;
- mBufferRotation = IntPoint(0,0);
-
- UpdateDestinationFrom(oldBuffer, nsIntRegion(mBufferRect));
- } else {
- mDTBuffer = destDTBuffer.forget();
- mDTBufferOnWhite = destDTBufferOnWhite.forget();
- mBufferRect = dest.mBufferRect;
- mBufferRotation = IntPoint(0,0);
- }
- }
- NS_ASSERTION(canHaveRotation || mBufferRotation == IntPoint(0,0),
- "Rotation disabled, but we have nonzero rotation?");
-
- nsIntRegion invalidate;
- invalidate.Sub(aLayer->GetValidRegion(), dest.mBufferRect);
- result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
-
- result.mClip = DrawRegionClip::DRAW;
- result.mMode = dest.mBufferMode;
-
- return result;
-}
-
-RefPtr<CapturedPaintState>
-RotatedContentBuffer::BorrowDrawTargetForRecording(PaintState& aPaintState,
- DrawIterator* aIter,
- bool aSetTransform)
-{
- if (aPaintState.mMode == SurfaceMode::SURFACE_NONE ||
- !EnsureBuffer() ||
- (HaveBufferOnWhite() && !EnsureBufferOnWhite())) {
- return nullptr;
- }
-
- Matrix transform;
- DrawTarget* result = BorrowDrawTargetForQuadrantUpdate(aPaintState.mRegionToDraw.GetBounds(),
- BUFFER_BOTH, aIter,
- aSetTransform,
- &transform);
- if (!result) {
- return nullptr;
- }
-
- nsIntRegion regionToDraw =
- ExpandDrawRegion(aPaintState, aIter, result->GetBackendType());
-
- RefPtr<CapturedPaintState> state =
- new CapturedPaintState(regionToDraw,
- result,
- mDTBufferOnWhite,
- transform,
- aPaintState.mMode,
- aPaintState.mContentType);
- return state;
-}
-
-/*static */ bool
-RotatedContentBuffer::PrepareDrawTargetForPainting(CapturedPaintState* aState)
-{
- MOZ_ASSERT(aState);
- RefPtr<DrawTarget> target = aState->mTarget;
- RefPtr<DrawTarget> whiteTarget = aState->mTargetOnWhite;
-
- if (aState->mSurfaceMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
- if (!target || !target->IsValid() ||
- !whiteTarget || !whiteTarget->IsValid()) {
- // This can happen in release builds if allocating one of the two buffers
- // failed. This in turn can happen if unreasonably large textures are
- // requested.
- return false;
- }
- for (auto iter = aState->mRegionToDraw.RectIter(); !iter.Done(); iter.Next()) {
- const IntRect& rect = iter.Get();
- target->FillRect(Rect(rect.x, rect.y, rect.Width(), rect.Height()),
- ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));
- whiteTarget->FillRect(Rect(rect.x, rect.y, rect.Width(), rect.Height()),
- ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
- }
- } else if (aState->mContentType == gfxContentType::COLOR_ALPHA &&
- target->IsValid()) {
- // HaveBuffer() => we have an existing buffer that we must clear
- for (auto iter = aState->mRegionToDraw.RectIter(); !iter.Done(); iter.Next()) {
- const IntRect& rect = iter.Get();
- target->ClearRect(Rect(rect.x, rect.y, rect.Width(), rect.Height()));
- }
- }
-
- return true;
-}
-
-nsIntRegion
-RotatedContentBuffer::ExpandDrawRegion(PaintState& aPaintState,
- DrawIterator* aIter,
- BackendType aBackendType)
-{
- nsIntRegion* drawPtr = &aPaintState.mRegionToDraw;
- if (aIter) {
- // The iterators draw region currently only contains the bounds of the region,
- // this makes it the precise region.
- aIter->mDrawRegion.And(aIter->mDrawRegion, aPaintState.mRegionToDraw);
- drawPtr = &aIter->mDrawRegion;
- }
- if (aBackendType == BackendType::DIRECT2D ||
- aBackendType == BackendType::DIRECT2D1_1) {
- // Simplify the draw region to avoid hitting expensive drawing paths
- // for complex regions.
- drawPtr->SimplifyOutwardByArea(100 * 100);
- }
- return *drawPtr;
-}
-
-DrawTarget*
-RotatedContentBuffer::BorrowDrawTargetForPainting(PaintState& aPaintState,
- DrawIterator* aIter /* = nullptr */)
-{
- RefPtr<CapturedPaintState> capturedState =
- BorrowDrawTargetForRecording(aPaintState, aIter, true);
-
- if (!capturedState) {
- return nullptr;
- }
-
- if (!RotatedContentBuffer::PrepareDrawTargetForPainting(capturedState)) {
- return nullptr;
- }
-
- return capturedState->mTarget;
-}
-
-already_AddRefed<SourceSurface>
-RotatedContentBuffer::GetSourceSurface(ContextSource aSource) const
-{
- if (!mDTBuffer || !mDTBuffer->IsValid()) {
- gfxCriticalNote << "Invalid buffer in RotatedContentBuffer::GetSourceSurface " << gfx::hexa(mDTBuffer);
- return nullptr;
- }
-
- if (aSource == BUFFER_BLACK) {
- return mDTBuffer->Snapshot();
- } else {
- if (!mDTBufferOnWhite || !mDTBufferOnWhite->IsValid()) {
- gfxCriticalNote << "Invalid buffer on white in RotatedContentBuffer::GetSourceSurface " << gfx::hexa(mDTBufferOnWhite);
- return nullptr;
- }
- MOZ_ASSERT(aSource == BUFFER_WHITE);
- return mDTBufferOnWhite->Snapshot();
- }
-}
-
} // namespace layers
} // namespace mozilla
--- a/gfx/layers/RotatedBuffer.h
+++ b/gfx/layers/RotatedBuffer.h
@@ -28,19 +28,20 @@ class CapturedPaintState;
typedef bool (*PrepDrawTargetForPaintingCallback)(CapturedPaintState*);
class PaintedLayer;
// Mixin class for classes which need logic for loaning out a draw target.
// See comments on BorrowDrawTargetForQuadrantUpdate.
class BorrowDrawTarget
{
-protected:
+public:
void ReturnDrawTarget(gfx::DrawTarget*& aReturned);
+protected:
// The draw target loaned by BorrowDrawTargetForQuadrantUpdate. It should not
// be used, we just keep a reference to ensure it is kept alive and so we can
// correctly restore state when it is returned.
RefPtr<gfx::DrawTarget> mLoanedDrawTarget;
gfx::Matrix mLoanedTransform;
// This flag denotes whether or not a transform was already applied
// to mLoanedDrawTarget and thus needs to be reset to mLoanedTransform
@@ -63,16 +64,18 @@ protected:
* at row H-N on the screen.
* mBufferRotation.y would be N in this example.
*/
class RotatedBuffer : public BorrowDrawTarget
{
public:
typedef gfxContentType ContentType;
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RotatedBuffer)
+
RotatedBuffer(const gfx::IntRect& aBufferRect,
const gfx::IntPoint& aBufferRotation)
: mBufferRect(aBufferRect)
, mBufferRotation(aBufferRotation)
, mDidSelfCopy(false)
{ }
RotatedBuffer()
: mDidSelfCopy(false)
@@ -134,26 +137,64 @@ public:
/**
* |BufferRect()| is the rect of device pixels that this
* RotatedBuffer covers. That is what DrawBufferWithRotation()
* will paint when it's called.
*/
const gfx::IntRect& BufferRect() const { return mBufferRect; }
const gfx::IntPoint& BufferRotation() const { return mBufferRotation; }
+ void SetBufferRect(const gfx::IntRect& aBufferRect) {
+ mBufferRect = aBufferRect;
+ }
+ void SetBufferRotation(const gfx::IntPoint& aBufferRotation) {
+ mBufferRotation = aBufferRotation;
+ }
+
+ bool DidSelfCopy() const { return mDidSelfCopy; }
+ void ClearDidSelfCopy() { mDidSelfCopy = false; }
+
+ virtual gfx::SurfaceFormat GetFormat() const = 0;
+
virtual bool HaveBuffer() const = 0;
virtual bool HaveBufferOnWhite() const = 0;
+ virtual bool IsLocked() = 0;
+ virtual bool Lock(OpenMode aMode) = 0;
+ virtual void Unlock() = 0;
+
virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const = 0;
-protected:
+ /**
+ * Get a draw target at the specified resolution for updating |aBounds|,
+ * which must be contained within a single quadrant.
+ *
+ * The result should only be held temporarily by the caller (it will be kept
+ * alive by this). Once used it should be returned using ReturnDrawTarget.
+ * BorrowDrawTargetForQuadrantUpdate may not be called more than once without
+ * first calling ReturnDrawTarget.
+ *
+ * ReturnDrawTarget will by default restore the transform on the draw target.
+ * But it is the callers responsibility to restore the clip.
+ * The caller should flush the draw target, if necessary.
+ * If aSetTransform is false, the required transform will be set in aOutTransform.
+ */
+ gfx::DrawTarget*
+ BorrowDrawTargetForQuadrantUpdate(const gfx::IntRect& aBounds,
+ ContextSource aSource,
+ DrawIterator* aIter,
+ bool aSetTransform = true,
+ gfx::Matrix* aOutTransform = nullptr);
virtual gfx::DrawTarget* GetDTBuffer() const = 0;
virtual gfx::DrawTarget* GetDTBufferOnWhite() const = 0;
+protected:
+ virtual ~RotatedBuffer() {}
+
enum XSide {
LEFT, RIGHT
};
enum YSide {
TOP, BOTTOM
};
gfx::IntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide) const;
@@ -166,37 +207,16 @@ protected:
*/
void DrawBufferQuadrant(gfx::DrawTarget* aTarget, XSide aXSide, YSide aYSide,
ContextSource aSource,
float aOpacity,
gfx::CompositionOp aOperator,
gfx::SourceSurface* aMask,
const gfx::Matrix* aMaskTransform) const;
- /**
- * Get a draw target at the specified resolution for updating |aBounds|,
- * which must be contained within a single quadrant.
- *
- * The result should only be held temporarily by the caller (it will be kept
- * alive by this). Once used it should be returned using ReturnDrawTarget.
- * BorrowDrawTargetForQuadrantUpdate may not be called more than once without
- * first calling ReturnDrawTarget.
- *
- * ReturnDrawTarget will by default restore the transform on the draw target.
- * But it is the callers responsibility to restore the clip.
- * The caller should flush the draw target, if necessary.
- * If aSetTransform is false, the required transform will be set in aOutTransform.
- */
- gfx::DrawTarget*
- BorrowDrawTargetForQuadrantUpdate(const gfx::IntRect& aBounds,
- ContextSource aSource,
- DrawIterator* aIter,
- bool aSetTransform = true,
- gfx::Matrix* aOutTransform = nullptr);
-
/** The area of the PaintedLayer that is covered by the buffer as a whole */
gfx::IntRect mBufferRect;
/**
* The x and y rotation of the buffer. Conceptually the buffer
* has its origin translated to mBufferRect.TopLeft() - mBufferRotation,
* is tiled to fill the plane, and the result is clipped to mBufferRect.
* So the pixel at mBufferRotation within the buffer is what gets painted at
* mBufferRect.TopLeft().
@@ -216,24 +236,28 @@ public:
RemoteRotatedBuffer(TextureClient* aClient, TextureClient* aClientOnWhite,
const gfx::IntRect& aBufferRect,
const gfx::IntPoint& aBufferRotation)
: RotatedBuffer(aBufferRect, aBufferRotation)
, mClient(aClient)
, mClientOnWhite(aClientOnWhite)
{ }
- bool Lock(OpenMode aMode);
- void Unlock();
+ virtual bool IsLocked() override;
+ virtual bool Lock(OpenMode aMode) override;
+ virtual void Unlock() override;
+ void SyncWithObject(SyncObjectClient* aSyncObject);
void Clear();
TextureClient* GetClient() const { return mClient; }
TextureClient* GetClientOnWhite() const { return mClientOnWhite; }
+ virtual gfx::SurfaceFormat GetFormat() const override;
+
virtual bool HaveBuffer() const override { return !!mClient; }
virtual bool HaveBufferOnWhite() const override { return !!mClientOnWhite; }
virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const override;
protected:
virtual gfx::DrawTarget* GetDTBuffer() const override;
virtual gfx::DrawTarget* GetDTBufferOnWhite() const override;
@@ -252,16 +276,22 @@ public:
DrawTargetRotatedBuffer(gfx::DrawTarget* aTarget, gfx::DrawTarget* aTargetOnWhite,
const gfx::IntRect& aBufferRect,
const gfx::IntPoint& aBufferRotation)
: RotatedBuffer(aBufferRect, aBufferRotation)
, mTarget(aTarget)
, mTargetOnWhite(aTargetOnWhite)
{ }
+ virtual bool IsLocked() override { return false; }
+ virtual bool Lock(OpenMode aMode) override { return true; }
+ virtual void Unlock() override {}
+
+ virtual gfx::SurfaceFormat GetFormat() const override;
+
virtual bool HaveBuffer() const override { return !!mTarget; }
virtual bool HaveBufferOnWhite() const override { return !!mTargetOnWhite; }
virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const override;
protected:
virtual gfx::DrawTarget* GetDTBuffer() const override;
virtual gfx::DrawTarget* GetDTBufferOnWhite() const override;
@@ -277,270 +307,32 @@ public:
SourceRotatedBuffer(gfx::SourceSurface* aSource, gfx::SourceSurface* aSourceOnWhite,
const gfx::IntRect& aBufferRect,
const gfx::IntPoint& aBufferRotation)
: RotatedBuffer(aBufferRect, aBufferRotation)
, mSource(aSource)
, mSourceOnWhite(aSourceOnWhite)
{ }
+ virtual bool IsLocked() override { return false; }
+ virtual bool Lock(OpenMode aMode) override { return false; }
+ virtual void Unlock() override {}
+
virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const;
+ virtual gfx::SurfaceFormat GetFormat() const override;
+
virtual bool HaveBuffer() const { return !!mSource; }
virtual bool HaveBufferOnWhite() const { return !!mSourceOnWhite; }
protected:
virtual gfx::DrawTarget* GetDTBuffer() const { return nullptr; }
virtual gfx::DrawTarget* GetDTBufferOnWhite() const { return nullptr; }
private:
RefPtr<gfx::SourceSurface> mSource;
RefPtr<gfx::SourceSurface> mSourceOnWhite;
};
-/**
- * This class encapsulates the buffer used to retain PaintedLayer contents,
- * i.e., the contents of the layer's GetVisibleRegion().
- */
-class RotatedContentBuffer : public RotatedBuffer
-{
-public:
- typedef gfxContentType ContentType;
-
- /**
- * Controls the size of the backing buffer of this.
- * - SizedToVisibleBounds: the backing buffer is exactly the same
- * size as the bounds of PaintedLayer's visible region
- * - ContainsVisibleBounds: the backing buffer is large enough to
- * fit visible bounds. May be larger.
- */
- enum BufferSizePolicy {
- SizedToVisibleBounds,
- ContainsVisibleBounds
- };
-
- explicit RotatedContentBuffer(BufferSizePolicy aBufferSizePolicy)
- : mBufferProvider(nullptr)
- , mBufferProviderOnWhite(nullptr)
- , mBufferSizePolicy(aBufferSizePolicy)
- {
- MOZ_COUNT_CTOR(RotatedContentBuffer);
- }
- virtual ~RotatedContentBuffer()
- {
- MOZ_COUNT_DTOR(RotatedContentBuffer);
- }
-
- /**
- * Wipe out all retained contents. Call this when the entire
- * buffer becomes invalid.
- */
- void Clear()
- {
- UnlockBuffers();
- mDTBuffer = nullptr;
- mDTBufferOnWhite = nullptr;
- mBufferProvider = nullptr;
- mBufferProviderOnWhite = nullptr;
- mBufferRect.SetEmpty();
- }
-
- /**
- * This is returned by BeginPaint. The caller should draw into mTarget.
- * mRegionToDraw must be drawn. mRegionToInvalidate has been invalidated
- * by RotatedContentBuffer and must be redrawn on the screen.
- * mRegionToInvalidate is set when the buffer has changed from
- * opaque to transparent or vice versa, since the details of rendering can
- * depend on the buffer type.
- */
- struct PaintState {
- PaintState()
- : mRegionToDraw()
- , mRegionToInvalidate()
- , mMode(SurfaceMode::SURFACE_NONE)
- , mClip(DrawRegionClip::NONE)
- , mContentType(gfxContentType::SENTINEL)
- {}
-
- nsIntRegion mRegionToDraw;
- nsIntRegion mRegionToInvalidate;
- SurfaceMode mMode;
- DrawRegionClip mClip;
- ContentType mContentType;
- };
-
- enum {
- PAINT_WILL_RESAMPLE = 0x01,
- PAINT_NO_ROTATION = 0x02,
- PAINT_CAN_DRAW_ROTATED = 0x04
- };
- /**
- * Start a drawing operation. This returns a PaintState describing what
- * needs to be drawn to bring the buffer up to date in the visible region.
- * This queries aLayer to get the currently valid and visible regions.
- * The returned mTarget may be null if mRegionToDraw is empty.
- * Otherwise it must not be null.
- * mRegionToInvalidate will contain mRegionToDraw.
- * @param aFlags when PAINT_WILL_RESAMPLE is passed, this indicates that
- * buffer will be resampled when rendering (i.e the effective transform
- * combined with the scale for the resolution is not just an integer
- * translation). This will disable buffer rotation (since we don't want
- * to resample across the rotation boundary) and will ensure that we
- * make the entire buffer contents valid (since we don't want to sample
- * invalid pixels outside the visible region, if the visible region doesn't
- * fill the buffer bounds).
- * PAINT_CAN_DRAW_ROTATED can be passed if the caller supports drawing
- * rotated content that crosses the physical buffer boundary. The caller
- * will need to call BorrowDrawTargetForPainting multiple times to achieve
- * this.
- */
- PaintState BeginPaint(PaintedLayer* aLayer,
- uint32_t aFlags);
-
- /**
- * Fetch a DrawTarget for rendering. The DrawTarget remains owned by
- * this. See notes on BorrowDrawTargetForQuadrantUpdate.
- * May return null. If the return value is non-null, it must be
- * 'un-borrowed' using ReturnDrawTarget.
- *
- * If PAINT_CAN_DRAW_ROTATED was specified for BeginPaint, then the caller
- * must call this function repeatedly (with an iterator) until it returns
- * nullptr. The caller should draw the mDrawRegion of the iterator instead
- * of mRegionToDraw in the PaintState.
- *
- * @param aPaintState Paint state data returned by a call to BeginPaint
- * @param aIter Paint state iterator. Only required if PAINT_CAN_DRAW_ROTATED
- * was specified to BeginPaint.
- */
- gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
- DrawIterator* aIter = nullptr);
-
- /**
- * Borrow a draw target for recording. The required transform for correct painting
- * is not applied to the returned DrawTarget by default, BUT it is
- * required to be whenever drawing does happen.
- */
- RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(PaintState& aPaintState,
- DrawIterator* aIter,
- bool aSetTransform = false);
-
- nsIntRegion ExpandDrawRegion(PaintState& aPaintState,
- DrawIterator* aIter,
- gfx::BackendType aBackendType);
-
- static bool PrepareDrawTargetForPainting(CapturedPaintState*);
- enum {
- BUFFER_COMPONENT_ALPHA = 0x02 // Dual buffers should be created for drawing with
- // component alpha.
- };
- /**
- * Return a new surface of |aSize| and |aType|.
- *
- * If the created buffer supports azure content, then the result(s) will
- * be returned in aBlackDT/aWhiteDT, otherwise aBlackSurface/aWhiteSurface
- * will be used.
- */
- virtual void
- CreateBuffer(ContentType aType, const gfx::IntRect& aRect, uint32_t aFlags,
- RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) = 0;
-
- virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const;
-
-protected:
- // new texture client versions
- void SetBufferProvider(TextureClient* aClient)
- {
- // Only this buffer provider can give us a buffer. If we
- // already have one, something has gone wrong.
- MOZ_ASSERT(!aClient || !mDTBuffer || !mDTBuffer->IsValid());
-
- mBufferProvider = aClient;
- if (!mBufferProvider) {
- mDTBuffer = nullptr;
- }
- }
-
- void SetBufferProviderOnWhite(TextureClient* aClient)
- {
- // Only this buffer provider can give us a buffer. If we
- // already have one, something has gone wrong.
- MOZ_ASSERT(!aClient || !mDTBufferOnWhite || !mDTBufferOnWhite->IsValid());
-
- mBufferProviderOnWhite = aClient;
- if (!mBufferProviderOnWhite) {
- mDTBufferOnWhite = nullptr;
- }
- }
-
-protected:
- struct BufferDecision {
- nsIntRegion mNeededRegion;
- nsIntRegion mValidRegion;
- gfx::IntRect mBufferRect;
- SurfaceMode mBufferMode;
- ContentType mBufferContentType;
- bool mCanReuseBuffer;
- bool mCanKeepBufferContents;
- };
-
- BufferDecision CalculateBufferForPaint(PaintedLayer* aLayer,
- uint32_t aFlags);
-
- /**
- * Return the buffer's content type. Requires a valid buffer or
- * buffer provider.
- */
- gfxContentType BufferContentType();
- bool BufferSizeOkFor(const gfx::IntSize& aSize);
- /**
- * If the buffer hasn't been mapped, map it.
- */
- bool EnsureBuffer();
- bool EnsureBufferOnWhite();
-
- // Flush our buffers if they are mapped.
- void FlushBuffers();
-
- /**
- * Get the underlying buffer, if any. This is useful because we can pass
- * in the buffer as the default "reference surface" if there is one.
- * Don't use it for anything else!
- */
- virtual gfx::DrawTarget* GetDTBuffer() const { return mDTBuffer; }
- virtual gfx::DrawTarget* GetDTBufferOnWhite() const { return mDTBufferOnWhite; }
-
- /**
- * True if we have a buffer where we can get it (but not necessarily
- * mapped currently).
- */
- virtual bool HaveBuffer() const;
- virtual bool HaveBufferOnWhite() const;
-
- /**
- * Any actions that should be performed at the last moment before we begin
- * rendering the next frame. I.e., after we calculate what we will draw,
- * but before we rotate the buffer and possibly create new buffers.
- * aRegionToDraw is the region which is guaranteed to be overwritten when
- * drawing the next frame.
- */
- virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) {}
-
- virtual bool LockBuffers() { return true; }
- virtual void UnlockBuffers() {}
-
- RefPtr<gfx::DrawTarget> mDTBuffer;
- RefPtr<gfx::DrawTarget> mDTBufferOnWhite;
-
- /**
- * These members are only set transiently. They're used to map mDTBuffer
- * when we're using surfaces that require explicit map/unmap. Only one
- * may be used at a time.
- */
- TextureClient* mBufferProvider;
- TextureClient* mBufferProviderOnWhite;
-
- BufferSizePolicy mBufferSizePolicy;
-};
-
} // namespace layers
} // namespace mozilla
#endif /* ROTATEDBUFFER_H_ */
--- a/gfx/layers/basic/BasicPaintedLayer.cpp
+++ b/gfx/layers/basic/BasicPaintedLayer.cpp
@@ -145,26 +145,26 @@ BasicPaintedLayer::Validate(LayerManager
nsTArray<ReadbackProcessor::Update> readbackUpdates;
if (aReadback && UsedForReadback()) {
aReadback->GetPaintedLayerUpdates(this, &readbackUpdates);
}
uint32_t flags = 0;
#ifndef MOZ_WIDGET_ANDROID
if (BasicManager()->CompositorMightResample()) {
- flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE;
+ flags |= ContentClient::PAINT_WILL_RESAMPLE;
}
- if (!(flags & RotatedContentBuffer::PAINT_WILL_RESAMPLE)) {
+ if (!(flags & ContentClient::PAINT_WILL_RESAMPLE)) {
if (MayResample()) {
- flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE;
+ flags |= ContentClient::PAINT_WILL_RESAMPLE;
}
}
#endif
if (mDrawAtomically) {
- flags |= RotatedContentBuffer::PAINT_NO_ROTATION;
+ flags |= ContentClient::PAINT_NO_ROTATION;
}
PaintState state =
mContentClient->BeginPaintBuffer(this, flags);
SubtractFromValidRegion(state.mRegionToInvalidate);
DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state);
if (target && target->IsValid()) {
// The area that became invalid and is visible needs to be repainted
--- a/gfx/layers/basic/BasicPaintedLayer.h
+++ b/gfx/layers/basic/BasicPaintedLayer.h
@@ -22,18 +22,18 @@ class gfxContext;
namespace mozilla {
namespace layers {
class ReadbackProcessor;
class BasicPaintedLayer : public PaintedLayer, public BasicImplData {
public:
- typedef RotatedContentBuffer::PaintState PaintState;
- typedef RotatedContentBuffer::ContentType ContentType;
+ typedef ContentClient::PaintState PaintState;
+ typedef ContentClient::ContentType ContentType;
explicit BasicPaintedLayer(BasicLayerManager* aLayerManager, gfx::BackendType aBackend) :
PaintedLayer(aLayerManager, static_cast<BasicImplData*>(this)),
mContentClient(nullptr)
, mBackend(aBackend)
{
MOZ_COUNT_CTOR(BasicPaintedLayer);
}
--- a/gfx/layers/client/ClientPaintedLayer.cpp
+++ b/gfx/layers/client/ClientPaintedLayer.cpp
@@ -111,24 +111,24 @@ ClientPaintedLayer::UpdatePaintRegion(Pa
aState.mRegionToInvalidate.And(aState.mRegionToInvalidate,
GetLocalVisibleRegion().ToUnknownRegion());
return true;
}
uint32_t
ClientPaintedLayer::GetPaintFlags()
{
- uint32_t flags = RotatedContentBuffer::PAINT_CAN_DRAW_ROTATED;
+ uint32_t flags = ContentClient::PAINT_CAN_DRAW_ROTATED;
#ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
if (ClientManager()->CompositorMightResample()) {
- flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE;
+ flags |= ContentClient::PAINT_WILL_RESAMPLE;
}
- if (!(flags & RotatedContentBuffer::PAINT_WILL_RESAMPLE)) {
+ if (!(flags & ContentClient::PAINT_WILL_RESAMPLE)) {
if (MayResample()) {
- flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE;
+ flags |= ContentClient::PAINT_WILL_RESAMPLE;
}
}
#endif
return flags;
}
void
ClientPaintedLayer::PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
@@ -143,17 +143,17 @@ ClientPaintedLayer::PaintThebes(nsTArray
uint32_t flags = GetPaintFlags();
PaintState state = mContentClient->BeginPaintBuffer(this, flags);
if (!UpdatePaintRegion(state)) {
return;
}
bool didUpdate = false;
- RotatedContentBuffer::DrawIterator iter;
+ RotatedBuffer::DrawIterator iter;
while (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
if (!target || !target->IsValid()) {
if (target) {
mContentClient->ReturnDrawTargetToBuffer(target);
}
continue;
}
@@ -213,17 +213,17 @@ ClientPaintedLayer::PaintOffMainThread()
uint32_t flags = GetPaintFlags();
PaintState state = mContentClient->BeginPaintBuffer(this, flags);
if (!UpdatePaintRegion(state)) {
return false;
}
bool didUpdate = false;
- RotatedContentBuffer::DrawIterator iter;
+ RotatedBuffer::DrawIterator iter;
// Debug Protip: Change to BorrowDrawTargetForPainting if using sync OMTP.
while (RefPtr<CapturedPaintState> captureState =
mContentClient->BorrowDrawTargetForRecording(state, &iter))
{
DrawTarget* target = captureState->mTarget;
if (!target || !target->IsValid()) {
if (target) {
@@ -250,17 +250,17 @@ ClientPaintedLayer::PaintOffMainThread()
state.mClip,
state.mRegionToInvalidate,
ClientManager()->GetPaintedLayerCallbackData());
ctx = nullptr;
captureState->mCapture = captureDT.forget();
PaintThread::Get()->PaintContents(captureState,
- RotatedContentBuffer::PrepareDrawTargetForPainting);
+ ContentClient::PrepareDrawTargetForPainting);
mContentClient->ReturnDrawTargetToBuffer(target);
didUpdate = true;
}
PaintThread::Get()->EndLayer();
mContentClient->EndPaint(nullptr);
--- a/gfx/layers/client/ClientPaintedLayer.h
+++ b/gfx/layers/client/ClientPaintedLayer.h
@@ -27,18 +27,18 @@ class DrawTargetCapture;
namespace layers {
class CompositableClient;
class ShadowableLayer;
class SpecificLayerAttributes;
class ClientPaintedLayer : public PaintedLayer,
public ClientLayer {
public:
- typedef RotatedContentBuffer::PaintState PaintState;
- typedef RotatedContentBuffer::ContentType ContentType;
+ typedef ContentClient::PaintState PaintState;
+ typedef ContentClient::ContentType ContentType;
explicit ClientPaintedLayer(ClientLayerManager* aLayerManager,
LayerManager::PaintedLayerCreationHint aCreationHint = LayerManager::NONE) :
PaintedLayer(aLayerManager, static_cast<ClientLayer*>(this), aCreationHint),
mContentClient(nullptr)
{
MOZ_COUNT_CTOR(ClientPaintedLayer);
}
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -8,17 +8,16 @@
#include "gfxContext.h" // for gfxContext, etc
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxEnv.h" // for gfxEnv
#include "gfxPrefs.h" // for gfxPrefs
#include "gfxPoint.h" // for IntSize, gfxPoint
#include "gfxUtils.h" // for gfxUtils
#include "ipc/ShadowLayers.h" // for ShadowLayerForwarder
#include "mozilla/ArrayUtils.h" // for ArrayLength
-#include "mozilla/Maybe.h"
#include "mozilla/gfx/2D.h" // for DrawTarget, Factory
#include "mozilla/gfx/BasePoint.h" // for BasePoint
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/Rect.h" // for Rect
#include "mozilla/gfx/Types.h"
#include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/LayersMessages.h" // for ThebesBufferData
@@ -30,37 +29,51 @@
#ifdef XP_WIN
#include "gfxWindowsPlatform.h"
#endif
#ifdef MOZ_WIDGET_GTK
#include "gfxPlatformGtk.h"
#endif
#include "ReadbackLayer.h"
+#include <utility>
#include <vector>
using namespace std;
namespace mozilla {
using namespace gfx;
namespace layers {
-static TextureFlags TextureFlagsForRotatedContentBufferFlags(uint32_t aBufferFlags)
+static TextureFlags TextureFlagsForContentClientFlags(uint32_t aBufferFlags)
{
TextureFlags result = TextureFlags::NO_FLAGS;
- if (aBufferFlags & RotatedContentBuffer::BUFFER_COMPONENT_ALPHA) {
+ if (aBufferFlags & ContentClient::BUFFER_COMPONENT_ALPHA) {
result |= TextureFlags::COMPONENT_ALPHA;
}
return result;
}
+static IntRect
+ComputeBufferRect(const IntRect& aRequestedRect)
+{
+ IntRect rect(aRequestedRect);
+ // Set a minimum width to guarantee a minimum size of buffers we
+ // allocate (and work around problems on some platforms with smaller
+ // dimensions). 64 used to be the magic number needed to work around
+ // a rendering glitch on b2g (see bug 788411). Now that we don't support
+ // this device anymore we should be fine with 8 pixels as the minimum.
+ rect.SetWidth(std::max(aRequestedRect.Width(), 8));
+ return rect;
+}
+
/* static */ already_AddRefed<ContentClient>
ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
{
LayersBackend backend = aForwarder->GetCompositorBackendType();
if (backend != LayersBackend::LAYERS_OPENGL &&
backend != LayersBackend::LAYERS_D3D11 &&
backend != LayersBackend::LAYERS_WR &&
backend != LayersBackend::LAYERS_BASIC) {
@@ -87,16 +100,388 @@ ContentClient::CreateContentClient(Compo
if (useDoubleBuffering || gfxEnv::ForceDoubleBuffering()) {
return MakeAndAddRef<ContentClientDoubleBuffered>(aForwarder);
}
return MakeAndAddRef<ContentClientSingleBuffered>(aForwarder);
}
void
+ContentClient::Clear()
+{
+ mBuffer = nullptr;
+}
+
+ContentClient::PaintState
+ContentClient::BeginPaintBuffer(PaintedLayer* aLayer,
+ uint32_t aFlags)
+{
+ PaintState result;
+
+ BufferDecision dest = CalculateBufferForPaint(aLayer, aFlags);
+ result.mContentType = dest.mBufferContentType;
+
+ if (!dest.mCanKeepBufferContents) {
+ // We're effectively clearing the valid region, so we need to draw
+ // the entire needed region now.
+ MOZ_ASSERT(!dest.mCanReuseBuffer);
+ MOZ_ASSERT(dest.mValidRegion.IsEmpty());
+
+ result.mRegionToInvalidate = aLayer->GetValidRegion();
+ Clear();
+
+#if defined(MOZ_DUMP_PAINTING)
+ if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
+ if (result.mContentType != BufferContentType()) {
+ printf_stderr("Invalidating entire rotated buffer (layer %p): content type changed\n", aLayer);
+ } else if ((dest.mBufferMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != mBuffer->HaveBufferOnWhite()) {
+ printf_stderr("Invalidating entire rotated buffer (layer %p): component alpha changed\n", aLayer);
+ }
+ }
+#endif
+ }
+
+ result.mRegionToDraw.Sub(dest.mNeededRegion,
+ dest.mValidRegion);
+
+ if (result.mRegionToDraw.IsEmpty())
+ return result;
+
+ if (mBuffer) {
+ if (mBuffer->Lock(LockMode())) {
+ // Do not modify result.mRegionToDraw or result.mContentType after this call.
+ // Do not modify mBufferRect, mBufferRotation, or mDidSelfCopy,
+ // or call CreateBuffer before this call.
+ FinalizeFrame(result.mRegionToDraw);
+ } else {
+ // Abandon everything and redraw it all. Ideally we'd reallocate and copy
+ // the old to the new and then call FinalizeFrame on the new buffer so that
+ // we only need to draw the latest bits, but we need a big refactor to support
+ // that ordering.
+ result.mRegionToDraw = dest.mNeededRegion;
+ dest.mCanReuseBuffer = false;
+ Clear();
+ }
+ }
+
+ // We need to disable rotation if we're going to be resampled when
+ // drawing, because we might sample across the rotation boundary.
+ // Also disable buffer rotation when using webrender.
+ bool canHaveRotation = gfxPlatform::BufferRotationEnabled() &&
+ !(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION)) &&
+ !(aLayer->Manager()->AsWebRenderLayerManager());
+ bool canDrawRotated = aFlags & PAINT_CAN_DRAW_ROTATED;
+
+ IntRect drawBounds = result.mRegionToDraw.GetBounds();
+ RefPtr<RotatedBuffer> newBuffer;
+ uint32_t bufferFlags = 0;
+ if (dest.mBufferMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
+ bufferFlags |= BUFFER_COMPONENT_ALPHA;
+ }
+ if (dest.mCanReuseBuffer && mBuffer) {
+ if (!mBuffer->AdjustTo(dest.mBufferRect,
+ drawBounds,
+ canHaveRotation,
+ canDrawRotated)) {
+ dest.mBufferRect = ComputeBufferRect(dest.mNeededRegion.GetBounds());
+ newBuffer = CreateBuffer(result.mContentType, dest.mBufferRect, bufferFlags);
+
+ if (!newBuffer) {
+ if (Factory::ReasonableSurfaceSize(IntSize(dest.mBufferRect.Width(), dest.mBufferRect.Height()))) {
+ gfxCriticalNote << "Failed 1 buffer for "
+ << dest.mBufferRect.x << ", "
+ << dest.mBufferRect.y << ", "
+ << dest.mBufferRect.Width() << ", "
+ << dest.mBufferRect.Height();
+ }
+ return result;
+ }
+ }
+ } else {
+ // The buffer's not big enough, so allocate a new one
+ newBuffer = CreateBuffer(result.mContentType, dest.mBufferRect, bufferFlags);
+ if (!newBuffer) {
+ if (Factory::ReasonableSurfaceSize(IntSize(dest.mBufferRect.Width(), dest.mBufferRect.Height()))) {
+ gfxCriticalNote << "Failed 2 buffer for "
+ << dest.mBufferRect.x << ", "
+ << dest.mBufferRect.y << ", "
+ << dest.mBufferRect.Width() << ", "
+ << dest.mBufferRect.Height();
+ }
+ return result;
+ }
+ }
+
+ NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || dest.mBufferRect == dest.mNeededRegion.GetBounds(),
+ "If we're resampling, we need to validate the entire buffer");
+
+ // If needed, copy the old buffer over to the new one
+ if (newBuffer) {
+ if (mBuffer) {
+ newBuffer->UpdateDestinationFrom(*mBuffer, nsIntRegion(newBuffer->BufferRect()));
+ }
+
+ // Ensure our reference to the front buffer is released
+ // as well as the old back buffer.
+ Clear();
+
+ mBuffer = newBuffer;
+ }
+
+ NS_ASSERTION(canHaveRotation || mBuffer->BufferRotation() == IntPoint(0,0),
+ "Rotation disabled, but we have nonzero rotation?");
+
+ nsIntRegion invalidate;
+ invalidate.Sub(aLayer->GetValidRegion(), dest.mBufferRect);
+ result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
+
+ result.mClip = DrawRegionClip::DRAW;
+ result.mMode = dest.mBufferMode;
+
+ return result;
+}
+
+DrawTarget*
+ContentClient::BorrowDrawTargetForPainting(ContentClient::PaintState& aPaintState,
+ RotatedBuffer::DrawIterator* aIter /* = nullptr */)
+{
+ RefPtr<CapturedPaintState> capturedState =
+ BorrowDrawTargetForRecording(aPaintState, aIter, true);
+
+ if (!capturedState) {
+ return nullptr;
+ }
+
+ if (!ContentClient::PrepareDrawTargetForPainting(capturedState)) {
+ return nullptr;
+ }
+
+ return capturedState->mTarget;
+}
+
+RefPtr<CapturedPaintState>
+ContentClient::BorrowDrawTargetForRecording(ContentClient::PaintState& aPaintState,
+ RotatedBuffer::DrawIterator* aIter,
+ bool aSetTransform)
+{
+ if (aPaintState.mMode == SurfaceMode::SURFACE_NONE ||
+ !mBuffer || !mBuffer->IsLocked()) {
+ return nullptr;
+ }
+
+ Matrix transform;
+ DrawTarget* result = mBuffer->BorrowDrawTargetForQuadrantUpdate(
+ aPaintState.mRegionToDraw.GetBounds(),
+ RotatedBuffer::BUFFER_BOTH, aIter,
+ aSetTransform,
+ &transform);
+ if (!result) {
+ return nullptr;
+ }
+
+ nsIntRegion regionToDraw =
+ ExpandDrawRegion(aPaintState, aIter, result->GetBackendType());
+
+ RefPtr<CapturedPaintState> state =
+ new CapturedPaintState(regionToDraw,
+ result,
+ mBuffer->GetDTBufferOnWhite(),
+ transform,
+ aPaintState.mMode,
+ aPaintState.mContentType);
+ return state;
+}
+
+void
+ContentClient::ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned)
+{
+ mBuffer->ReturnDrawTarget(aReturned);
+}
+
+nsIntRegion
+ContentClient::ExpandDrawRegion(ContentClient::PaintState& aPaintState,
+ RotatedBuffer::DrawIterator* aIter,
+ BackendType aBackendType)
+{
+ nsIntRegion* drawPtr = &aPaintState.mRegionToDraw;
+ if (aIter) {
+ // The iterators draw region currently only contains the bounds of the region,
+ // this makes it the precise region.
+ aIter->mDrawRegion.And(aIter->mDrawRegion, aPaintState.mRegionToDraw);
+ drawPtr = &aIter->mDrawRegion;
+ }
+ if (aBackendType == BackendType::DIRECT2D ||
+ aBackendType == BackendType::DIRECT2D1_1) {
+ // Simplify the draw region to avoid hitting expensive drawing paths
+ // for complex regions.
+ drawPtr->SimplifyOutwardByArea(100 * 100);
+ }
+ return *drawPtr;
+}
+
+/*static */ bool
+ContentClient::PrepareDrawTargetForPainting(CapturedPaintState* aState)
+{
+ MOZ_ASSERT(aState);
+ RefPtr<DrawTarget> target = aState->mTarget;
+ RefPtr<DrawTarget> whiteTarget = aState->mTargetOnWhite;
+
+ if (aState->mSurfaceMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
+ if (!target || !target->IsValid() ||
+ !whiteTarget || !whiteTarget->IsValid()) {
+ // This can happen in release builds if allocating one of the two buffers
+ // failed. This in turn can happen if unreasonably large textures are
+ // requested.
+ return false;
+ }
+ for (auto iter = aState->mRegionToDraw.RectIter(); !iter.Done(); iter.Next()) {
+ const IntRect& rect = iter.Get();
+ target->FillRect(Rect(rect.x, rect.y, rect.Width(), rect.Height()),
+ ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));
+ whiteTarget->FillRect(Rect(rect.x, rect.y, rect.Width(), rect.Height()),
+ ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
+ }
+ } else if (aState->mContentType == gfxContentType::COLOR_ALPHA &&
+ target->IsValid()) {
+ // HaveBuffer() => we have an existing buffer that we must clear
+ for (auto iter = aState->mRegionToDraw.RectIter(); !iter.Done(); iter.Next()) {
+ const IntRect& rect = iter.Get();
+ target->ClearRect(Rect(rect.x, rect.y, rect.Width(), rect.Height()));
+ }
+ }
+
+ return true;
+}
+
+ContentClient::BufferDecision
+ContentClient::CalculateBufferForPaint(PaintedLayer* aLayer,
+ uint32_t aFlags)
+{
+ gfxContentType layerContentType =
+ aLayer->CanUseOpaqueSurface() ? gfxContentType::COLOR :
+ gfxContentType::COLOR_ALPHA;
+
+ SurfaceMode mode;
+ gfxContentType contentType;
+ IntRect destBufferRect;
+ nsIntRegion neededRegion;
+ nsIntRegion validRegion = aLayer->GetValidRegion();
+
+ bool canReuseBuffer = !!mBuffer;
+ bool canKeepBufferContents = true;
+
+ while (true) {
+ mode = aLayer->GetSurfaceMode();
+ neededRegion = aLayer->GetVisibleRegion().ToUnknownRegion();
+ canReuseBuffer = canReuseBuffer && BufferSizeOkFor(neededRegion.GetBounds().Size());
+ contentType = layerContentType;
+
+ if (canReuseBuffer) {
+ if (mBuffer->BufferRect().Contains(neededRegion.GetBounds())) {
+ // We don't need to adjust mBufferRect.
+ destBufferRect = mBuffer->BufferRect();
+ } else if (neededRegion.GetBounds().Size() <= mBuffer->BufferRect().Size()) {
+ // The buffer's big enough but doesn't contain everything that's
+ // going to be visible. We'll move it.
+ destBufferRect = IntRect(neededRegion.GetBounds().TopLeft(), mBuffer->BufferRect().Size());
+ } else {
+ destBufferRect = neededRegion.GetBounds();
+ }
+ } else {
+ // We won't be reusing the buffer. Compute a new rect.
+ destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
+ }
+
+ if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
+#if defined(MOZ_GFX_OPTIMIZE_MOBILE)
+ mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
+#else
+ if (!aLayer->GetParent() ||
+ !aLayer->GetParent()->SupportsComponentAlphaChildren() ||
+ !aLayer->AsShadowableLayer() ||
+ !aLayer->AsShadowableLayer()->HasShadow()) {
+ mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
+ } else {
+ contentType = gfxContentType::COLOR;
+ }
+#endif
+ }
+
+ if ((aFlags & PAINT_WILL_RESAMPLE) &&
+ (!neededRegion.GetBounds().IsEqualInterior(destBufferRect) ||
+ neededRegion.GetNumRects() > 1))
+ {
+ // The area we add to neededRegion might not be painted opaquely.
+ if (mode == SurfaceMode::SURFACE_OPAQUE) {
+ contentType = gfxContentType::COLOR_ALPHA;
+ mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
+ }
+
+ // We need to validate the entire buffer, to make sure that only valid
+ // pixels are sampled.
+ neededRegion = destBufferRect;
+ }
+
+ // If we have an existing buffer, but the content type has changed or we
+ // have transitioned into/out of component alpha, then we need to recreate it.
+ if (canReuseBuffer &&
+ (contentType != BufferContentType() ||
+ (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != mBuffer->HaveBufferOnWhite()))
+ {
+ // Restart the decision process; we won't re-enter since we guard on
+ // being able to re-use the buffer.
+ canReuseBuffer = false;
+ canKeepBufferContents = false;
+ validRegion.SetEmpty();
+ continue;
+ }
+
+ break;
+ }
+
+ NS_ASSERTION(destBufferRect.Contains(neededRegion.GetBounds()),
+ "Destination rect doesn't contain what we need to paint");
+
+ BufferDecision dest;
+ dest.mNeededRegion = Move(neededRegion);
+ dest.mValidRegion = Move(validRegion);
+ dest.mBufferRect = destBufferRect;
+ dest.mBufferMode = mode;
+ dest.mBufferContentType = contentType;
+ dest.mCanReuseBuffer = canReuseBuffer;
+ dest.mCanKeepBufferContents = canKeepBufferContents;
+ return dest;
+}
+
+gfxContentType
+ContentClient::BufferContentType()
+{
+ if (mBuffer) {
+ return ContentForFormat(mBuffer->GetFormat());
+ }
+ return gfxContentType::SENTINEL;
+}
+
+bool
+ContentClient::BufferSizeOkFor(const IntSize& aSize)
+{
+ MOZ_ASSERT(mBuffer);
+ return (aSize == mBuffer->BufferRect().Size() ||
+ (SizedToVisibleBounds != mBufferSizePolicy &&
+ aSize < mBuffer->BufferRect().Size()));
+}
+
+OpenMode
+ContentClient::LockMode() const
+{
+ return mInAsyncPaint ? OpenMode::OPEN_READ_ASYNC_WRITE
+ : OpenMode::OPEN_READ_WRITE;
+}
+
+void
ContentClient::BeginAsyncPaint()
{
mInAsyncPaint = true;
}
void
ContentClient::EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
{
@@ -108,105 +493,90 @@ ContentClient::PrintInfo(std::stringstre
{
aStream << aPrefix;
aStream << nsPrintfCString("ContentClient (0x%p)", this).get();
}
// We pass a null pointer for the ContentClient Forwarder argument, which means
// this client will not have a ContentHost on the other side.
ContentClientBasic::ContentClientBasic(gfx::BackendType aBackend)
- : ContentClient(nullptr)
- , RotatedContentBuffer(ContainsVisibleBounds)
+ : ContentClient(nullptr, ContainsVisibleBounds)
, mBackend(aBackend)
{}
void
ContentClientBasic::DrawTo(PaintedLayer* aLayer,
gfx::DrawTarget* aTarget,
float aOpacity,
gfx::CompositionOp aOp,
gfx::SourceSurface* aMask,
const gfx::Matrix* aMaskTransform)
{
- if (!EnsureBuffer()) {
+ if (!mBuffer) {
return;
}
- RotatedContentBuffer::DrawTo(aLayer, aTarget, aOpacity, aOp,
- aMask, aMaskTransform);
+ mBuffer->DrawTo(aLayer, aTarget, aOpacity, aOp,
+ aMask, aMaskTransform);
}
-void
-ContentClientBasic::CreateBuffer(ContentType aType,
+RefPtr<RotatedBuffer>
+ContentClientBasic::CreateBuffer(gfxContentType aType,
const IntRect& aRect,
- uint32_t aFlags,
- RefPtr<gfx::DrawTarget>* aBlackDT,
- RefPtr<gfx::DrawTarget>* aWhiteDT)
+ uint32_t aFlags)
{
MOZ_ASSERT(!(aFlags & BUFFER_COMPONENT_ALPHA));
if (aFlags & BUFFER_COMPONENT_ALPHA) {
gfxDevCrash(LogReason::AlphaWithBasicClient) << "Asking basic content client for component alpha";
}
IntSize size(aRect.Width(), aRect.Height());
+ RefPtr<gfx::DrawTarget> drawTarget;
+
#ifdef XP_WIN
if (mBackend == BackendType::CAIRO &&
(aType == gfxContentType::COLOR || aType == gfxContentType::COLOR_ALPHA)) {
RefPtr<gfxASurface> surf =
new gfxWindowsSurface(size, aType == gfxContentType::COLOR ? gfxImageFormat::X8R8G8B8_UINT32 :
gfxImageFormat::A8R8G8B8_UINT32);
- *aBlackDT = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf, size);
-
- if (*aBlackDT) {
- return;
- }
+ drawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf, size);
}
#endif
- *aBlackDT = gfxPlatform::GetPlatform()->CreateDrawTargetForBackend(
- mBackend, size,
- gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aType));
+ if (!drawTarget) {
+ drawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForBackend(
+ mBackend, size,
+ gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aType));
+ }
+
+ return new DrawTargetRotatedBuffer(drawTarget, nullptr, aRect, IntPoint(0,0));
}
RefPtr<CapturedPaintState>
-ContentClientBasic::BorrowDrawTargetForRecording(PaintState& aPaintState,
- RotatedContentBuffer::DrawIterator* aIter)
+ContentClientBasic::BorrowDrawTargetForRecording(ContentClient::PaintState& aPaintState,
+ RotatedBuffer::DrawIterator* aIter,
+ bool aSetTransform)
{
// BasicLayers does not yet support OMTP.
return nullptr;
}
-void
-ContentClientRemoteBuffer::DestroyBuffers()
+RefPtr<CapturedPaintState>
+ContentClientRemoteBuffer::BorrowDrawTargetForRecording(ContentClient::PaintState& aPaintState,
+ RotatedBuffer::DrawIterator* aIter,
+ bool aSetTransform)
{
- if (!mTextureClient) {
- return;
- }
-
- mOldTextures.AppendElement(mTextureClient);
- mTextureClient = nullptr;
- if (mTextureClientOnWhite) {
- mOldTextures.AppendElement(mTextureClientOnWhite);
- mTextureClientOnWhite = nullptr;
- }
-
- DestroyFrontBuffer();
-}
-
-RefPtr<CapturedPaintState>
-ContentClientRemoteBuffer::BorrowDrawTargetForRecording(PaintState& aPaintState,
- RotatedContentBuffer::DrawIterator* aIter)
-{
- RefPtr<CapturedPaintState> cps = RotatedContentBuffer::BorrowDrawTargetForRecording(aPaintState, aIter);
+ RefPtr<CapturedPaintState> cps = ContentClient::BorrowDrawTargetForRecording(aPaintState, aIter, aSetTransform);
if (!cps) {
return nullptr;
}
- cps->mTextureClient = mTextureClient;
- cps->mTextureClientOnWhite = mTextureClientOnWhite;
+ RemoteRotatedBuffer* remoteBuffer = GetRemoteBuffer();
+ cps->mTextureClient = remoteBuffer->GetClient();
+ cps->mTextureClientOnWhite = remoteBuffer->GetClientOnWhite();
return cps.forget();
}
class RemoteBufferReadbackProcessor : public TextureReadbackSink
{
public:
RemoteBufferReadbackProcessor(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates,
const IntRect& aBufferRect, const nsIntPoint& aBufferRotation)
@@ -260,352 +630,262 @@ private:
IntRect mBufferRect;
nsIntPoint mBufferRotation;
};
void
ContentClientRemoteBuffer::BeginPaint()
{
EnsureBackBufferIfFrontBuffer();
-
- // XXX: So we might not have a TextureClient yet.. because it will
- // only be created by CreateBuffer.. which will deliver a locked surface!.
- if (mTextureClient) {
- SetBufferProvider(mTextureClient);
- }
- if (mTextureClientOnWhite) {
- SetBufferProviderOnWhite(mTextureClientOnWhite);
- }
}
void
ContentClientRemoteBuffer::BeginAsyncPaint()
{
BeginPaint();
mInAsyncPaint = true;
}
void
ContentClientRemoteBuffer::EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
{
- MOZ_ASSERT(!mTextureClientOnWhite || !aReadbackUpdates || aReadbackUpdates->Length() == 0);
+ MOZ_ASSERT(!mBuffer || !mBuffer->HaveBufferOnWhite() ||
+ !aReadbackUpdates || aReadbackUpdates->Length() == 0);
+
+ RemoteRotatedBuffer* remoteBuffer = GetRemoteBuffer();
- // XXX: We might still not have a texture client if PaintThebes
- // decided we didn't need one yet because the region to draw was empty.
- SetBufferProvider(nullptr);
- SetBufferProviderOnWhite(nullptr);
- for (unsigned i = 0; i< mOldTextures.Length(); ++i) {
- if (mOldTextures[i]->IsLocked()) {
- mOldTextures[i]->Unlock();
- }
- }
- mOldTextures.Clear();
+ if (remoteBuffer && remoteBuffer->IsLocked()) {
+ if (aReadbackUpdates && aReadbackUpdates->Length() > 0) {
+ RefPtr<TextureReadbackSink> readbackSink = new RemoteBufferReadbackProcessor(aReadbackUpdates,
+ remoteBuffer->BufferRect(),
+ remoteBuffer->BufferRotation());
- if (mTextureClient && mTextureClient->IsLocked()) {
- if (aReadbackUpdates && aReadbackUpdates->Length() > 0) {
- RefPtr<TextureReadbackSink> readbackSink = new RemoteBufferReadbackProcessor(aReadbackUpdates, mBufferRect, mBufferRotation);
-
- mTextureClient->SetReadbackSink(readbackSink);
+ remoteBuffer->GetClient()->SetReadbackSink(readbackSink);
}
- mTextureClient->Unlock();
- mTextureClient->SyncWithObject(mForwarder->GetSyncObject());
- }
- if (mTextureClientOnWhite && mTextureClientOnWhite->IsLocked()) {
- mTextureClientOnWhite->Unlock();
- mTextureClientOnWhite->SyncWithObject(mForwarder->GetSyncObject());
+ remoteBuffer->Unlock();
+ remoteBuffer->SyncWithObject(mForwarder->GetSyncObject());
}
ContentClient::EndPaint(aReadbackUpdates);
}
-void
-ContentClientRemoteBuffer::BuildTextureClients(SurfaceFormat aFormat,
- const IntRect& aRect,
- uint32_t aFlags)
+RefPtr<RotatedBuffer>
+ContentClientRemoteBuffer::CreateBuffer(gfxContentType aType,
+ const IntRect& aRect,
+ uint32_t aFlags)
{
// If we hit this assertion, then it might be due to an empty transaction
// followed by a real transaction. Our buffers should be created (but not
// painted in the empty transaction) and then painted (but not created) in the
// real transaction. That is kind of fragile, and this assert will catch
// circumstances where we screw that up, e.g., by unnecessarily recreating our
// buffers.
MOZ_ASSERT(!mIsNewBuffer,
"Bad! Did we create a buffer twice without painting?");
- mIsNewBuffer = true;
-
- DestroyBuffers();
+ gfx::SurfaceFormat format = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aType);
- mSurfaceFormat = aFormat;
- mSize = IntSize(aRect.Width(), aRect.Height());
- mTextureFlags = TextureFlagsForRotatedContentBufferFlags(aFlags);
+ TextureFlags textureFlags = TextureFlagsForContentClientFlags(aFlags);
+ if (aFlags & BUFFER_COMPONENT_ALPHA) {
+ textureFlags |= TextureFlags::COMPONENT_ALPHA;
+ }
- if (aFlags & BUFFER_COMPONENT_ALPHA) {
- mTextureFlags |= TextureFlags::COMPONENT_ALPHA;
+ RefPtr<RotatedBuffer> buffer = CreateBufferInternal(aRect, format, textureFlags);
+
+ if (!buffer) {
+ return nullptr;
}
- CreateBackBuffer(mBufferRect);
+ DebugOnly<bool> locked = buffer->Lock(LockMode());
+ MOZ_ASSERT(locked, "Could not lock the RemoteRotatedBuffer");
+
+ mIsNewBuffer = true;
+ mTextureFlags = textureFlags;
+
+ return buffer;
}
-void
-ContentClientRemoteBuffer::CreateBackBuffer(const IntRect& aBufferRect)
+RefPtr<RotatedBuffer>
+ContentClientRemoteBuffer::CreateBufferInternal(const gfx::IntRect& aRect,
+ gfx::SurfaceFormat aFormat,
+ TextureFlags aFlags)
{
- // gfx::BackendType::NONE means fallback to the content backend
TextureAllocationFlags textureAllocFlags
- = (mTextureFlags & TextureFlags::COMPONENT_ALPHA) ?
+ = (aFlags & TextureFlags::COMPONENT_ALPHA) ?
TextureAllocationFlags::ALLOC_CLEAR_BUFFER_BLACK :
TextureAllocationFlags::ALLOC_CLEAR_BUFFER;
- mTextureClient = CreateTextureClientForDrawing(
- mSurfaceFormat, mSize, BackendSelector::Content,
- mTextureFlags | ExtraTextureFlags(),
+ RefPtr<TextureClient> textureClient = CreateTextureClientForDrawing(
+ aFormat, aRect.Size(), BackendSelector::Content,
+ aFlags | ExtraTextureFlags(),
textureAllocFlags
);
- if (!mTextureClient || !AddTextureClient(mTextureClient)) {
- AbortTextureClientCreation();
- return;
+
+ if (!textureClient || !AddTextureClient(textureClient)) {
+ return nullptr;
}
- mTextureClient->EnableBlockingReadLock();
+ textureClient->EnableBlockingReadLock();
- if (mTextureFlags & TextureFlags::COMPONENT_ALPHA) {
- mTextureClientOnWhite = mTextureClient->CreateSimilar(
+ RefPtr<TextureClient> textureClientOnWhite;
+ if (aFlags & TextureFlags::COMPONENT_ALPHA) {
+ textureClientOnWhite = textureClient->CreateSimilar(
mForwarder->GetCompositorBackendType(),
- mTextureFlags | ExtraTextureFlags(),
+ aFlags | ExtraTextureFlags(),
TextureAllocationFlags::ALLOC_CLEAR_BUFFER_WHITE
);
- if (!mTextureClientOnWhite || !AddTextureClient(mTextureClientOnWhite)) {
- AbortTextureClientCreation();
- return;
+ if (!textureClientOnWhite || !AddTextureClient(textureClientOnWhite)) {
+ return nullptr;
}
// We don't enable the readlock for the white buffer since we always
// use them together and waiting on the lock for the black
// should be sufficient.
}
-}
-void
-ContentClientRemoteBuffer::CreateBuffer(ContentType aType,
- const IntRect& aRect,
- uint32_t aFlags,
- RefPtr<gfx::DrawTarget>* aBlackDT,
- RefPtr<gfx::DrawTarget>* aWhiteDT)
-{
- BuildTextureClients(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aType), aRect, aFlags);
- if (!mTextureClient) {
- return;
- }
-
- OpenMode mode = OpenMode::OPEN_READ_WRITE;
- if (mInAsyncPaint) {
- mode |= OpenMode::OPEN_ASYNC_WRITE;
- }
-
- // We just created the textures and we are about to get their draw targets
- // so we have to lock them here.
- DebugOnly<bool> locked = mTextureClient->Lock(mode);
- MOZ_ASSERT(locked, "Could not lock the TextureClient");
-
- *aBlackDT = mTextureClient->BorrowDrawTarget();
- if (aFlags & BUFFER_COMPONENT_ALPHA) {
- locked = mTextureClientOnWhite->Lock(mode);
- MOZ_ASSERT(locked, "Could not lock the second TextureClient for component alpha");
-
- *aWhiteDT = mTextureClientOnWhite->BorrowDrawTarget();
- }
+ return new RemoteRotatedBuffer(textureClient,
+ textureClientOnWhite,
+ aRect,
+ IntPoint(0,0));
}
nsIntRegion
ContentClientRemoteBuffer::GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
const nsIntRegion& aVisibleRegion)
{
nsIntRegion updatedRegion;
- if (mIsNewBuffer || mDidSelfCopy) {
+ if (mIsNewBuffer || mBuffer->DidSelfCopy()) {
// 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.GetBounds();
mIsNewBuffer = false;
} else {
updatedRegion = aRegionToDraw;
}
- NS_ASSERTION(BufferRect().Contains(aRegionToDraw.GetBounds()),
+ MOZ_ASSERT(mBuffer, "should have a back buffer by now");
+ NS_ASSERTION(mBuffer->BufferRect().Contains(aRegionToDraw.GetBounds()),
"Update outside of buffer rect!");
- MOZ_ASSERT(mTextureClient, "should have a back buffer by now");
return updatedRegion;
}
void
ContentClientRemoteBuffer::Updated(const nsIntRegion& aRegionToDraw,
const nsIntRegion& aVisibleRegion)
{
nsIntRegion updatedRegion = GetUpdatedRegion(aRegionToDraw,
aVisibleRegion);
- MOZ_ASSERT(mTextureClient);
- if (mTextureClientOnWhite) {
- mForwarder->UseComponentAlphaTextures(this, mTextureClient,
- mTextureClientOnWhite);
+ RemoteRotatedBuffer* remoteBuffer = GetRemoteBuffer();
+
+ MOZ_ASSERT(remoteBuffer && remoteBuffer->GetClient());
+ if (remoteBuffer->HaveBufferOnWhite()) {
+ mForwarder->UseComponentAlphaTextures(this,
+ remoteBuffer->GetClient(),
+ remoteBuffer->GetClientOnWhite());
} else {
AutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
- t->mTextureClient = mTextureClient;
- IntSize size = mTextureClient->GetSize();
+ t->mTextureClient = remoteBuffer->GetClient();
+ IntSize size = remoteBuffer->GetClient()->GetSize();
t->mPictureRect = nsIntRect(0, 0, size.width, size.height);
GetForwarder()->UseTextures(this, textures);
}
+
// This forces a synchronous transaction, so we can swap buffers now
// and know that we'll have sole ownership of the old front buffer
// by the time we paint next.
mForwarder->UpdateTextureRegion(this,
- ThebesBufferData(BufferRect(),
- BufferRotation()),
+ ThebesBufferData(remoteBuffer->BufferRect(),
+ remoteBuffer->BufferRotation()),
updatedRegion);
SwapBuffers(updatedRegion);
}
-bool
-ContentClientRemoteBuffer::LockBuffers()
-{
- OpenMode mode = OpenMode::OPEN_READ_WRITE;
- if (mInAsyncPaint) {
- mode |= OpenMode::OPEN_ASYNC_WRITE;
- }
- if (mTextureClient) {
- bool locked = mTextureClient->Lock(mode);
- if (!locked) {
- return false;
- }
- }
- if (mTextureClientOnWhite) {
- bool locked = mTextureClientOnWhite->Lock(mode);
- if (!locked) {
- UnlockBuffers();
- return false;
- }
- }
- return true;
-}
-
-void
-ContentClientRemoteBuffer::UnlockBuffers()
-{
- if (mTextureClient && mTextureClient->IsLocked()) {
- mTextureClient->Unlock();
- }
- if (mTextureClientOnWhite && mTextureClientOnWhite->IsLocked()) {
- mTextureClientOnWhite->Unlock();
- }
-}
-
void
ContentClientRemoteBuffer::Dump(std::stringstream& aStream,
const char* aPrefix,
bool aDumpHtml, TextureDumpMode aCompress)
{
+ RemoteRotatedBuffer* remoteBuffer = GetRemoteBuffer();
+
// TODO We should combine the OnWhite/OnBlack here an just output a single image.
if (!aDumpHtml) {
aStream << "\n" << aPrefix << "Surface: ";
}
- CompositableClient::DumpTextureClient(aStream, mTextureClient, aCompress);
+ CompositableClient::DumpTextureClient(aStream,
+ remoteBuffer ? remoteBuffer->GetClient() : nullptr,
+ aCompress);
}
void
ContentClientDoubleBuffered::Dump(std::stringstream& aStream,
const char* aPrefix,
bool aDumpHtml, TextureDumpMode aCompress)
{
// TODO We should combine the OnWhite/OnBlack here an just output a single image.
if (!aDumpHtml) {
aStream << "\n" << aPrefix << "Surface: ";
}
- if (mFrontBuffer) {
- CompositableClient::DumpTextureClient(aStream, mFrontBuffer->GetClient(), aCompress);
- }
-}
-
-void
-ContentClientDoubleBuffered::DestroyFrontBuffer()
-{
- if (mFrontBuffer) {
- RefPtr<TextureClient> client = mFrontBuffer->GetClient();
- RefPtr<TextureClient> clientOnWhite = mFrontBuffer->GetClientOnWhite();
-
- if (client) {
- mOldTextures.AppendElement(client);
- }
- if (clientOnWhite) {
- mOldTextures.AppendElement(clientOnWhite);
- }
-
- mFrontBuffer = Nothing();
- }
+ CompositableClient::DumpTextureClient(aStream,
+ mFrontBuffer ? mFrontBuffer->GetClient() : nullptr,
+ aCompress);
}
void
ContentClientDoubleBuffered::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion)
{
mFrontUpdatedRegion = aFrontUpdatedRegion;
- RefPtr<TextureClient> newBack;
- RefPtr<TextureClient> newBackOnWhite;
- IntRect newBackBufferRect;
- nsIntPoint newBackBufferRotation;
+ RefPtr<RemoteRotatedBuffer> frontBuffer = mFrontBuffer;
+ RefPtr<RemoteRotatedBuffer> backBuffer = GetRemoteBuffer();
- if (mFrontBuffer) {
- newBack = mFrontBuffer->GetClient();
- newBackOnWhite = mFrontBuffer->GetClientOnWhite();
- newBackBufferRect = mFrontBuffer->BufferRect();
- newBackBufferRotation = mFrontBuffer->BufferRotation();
- }
+ std::swap(frontBuffer, backBuffer);
- mFrontBuffer = Some(RemoteRotatedBuffer(mTextureClient, mTextureClientOnWhite,
- mBufferRect, mBufferRotation));
-
- mTextureClient = newBack;
- mTextureClientOnWhite = newBackOnWhite;
- mBufferRect = newBackBufferRect;
- mBufferRotation = newBackBufferRotation;
+ mFrontBuffer = frontBuffer;
+ mBuffer = backBuffer;
mFrontAndBackBufferDiffer = true;
}
void
ContentClientDoubleBuffered::BeginPaint()
{
ContentClientRemoteBuffer::BeginPaint();
mIsNewBuffer = false;
if (!mFrontAndBackBufferDiffer) {
return;
}
- if (!mFrontBuffer) {
+ if (!mFrontBuffer || !mBuffer) {
mFrontAndBackBufferDiffer = false;
return;
}
- if (mDidSelfCopy) {
+ if (mFrontBuffer->DidSelfCopy()) {
// We can't easily draw our front buffer into us, since we're going to be
// copying stuff around anyway it's easiest if we just move our situation
// to non-rotated while we're at it. If this situation occurs we'll have
// hit a self-copy path in PaintThebes before as well anyway.
- mBufferRect.MoveTo(mFrontBuffer->BufferRect().TopLeft());
- mBufferRotation = nsIntPoint();
+ gfx::IntRect backBufferRect = mBuffer->BufferRect();
+ backBufferRect.MoveTo(mFrontBuffer->BufferRect().TopLeft());
+
+ mBuffer->SetBufferRect(backBufferRect);
+ mBuffer->SetBufferRotation(IntPoint(0,0));
return;
}
- mBufferRect = mFrontBuffer->BufferRect();
- mBufferRotation = mFrontBuffer->BufferRotation();
+ mBuffer->SetBufferRect(mFrontBuffer->BufferRect());
+ mBuffer->SetBufferRotation(mFrontBuffer->BufferRotation());
}
void
ContentClientDoubleBuffered::BeginAsyncPaint()
{
BeginPaint();
mInAsyncPaint = true;
}
@@ -613,17 +893,17 @@ ContentClientDoubleBuffered::BeginAsyncP
// 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 (!mFrontAndBackBufferDiffer) {
- MOZ_ASSERT(!mDidSelfCopy, "If we have to copy the world, then our buffers are different, right?");
+ MOZ_ASSERT(!mFrontBuffer->DidSelfCopy(), "If we have to copy the world, then our buffers are different, right?");
return;
}
MOZ_ASSERT(mFrontBuffer);
if (!mFrontBuffer) {
return;
}
MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>",
@@ -631,44 +911,43 @@ ContentClientDoubleBuffered::FinalizeFra
mFrontUpdatedRegion.GetBounds().x,
mFrontUpdatedRegion.GetBounds().y,
mFrontUpdatedRegion.GetBounds().Width(),
mFrontUpdatedRegion.GetBounds().Height()));
mFrontAndBackBufferDiffer = false;
nsIntRegion updateRegion = mFrontUpdatedRegion;
- if (mDidSelfCopy) {
- mDidSelfCopy = false;
- updateRegion = mBufferRect;
+ if (mFrontBuffer->DidSelfCopy()) {
+ mFrontBuffer->ClearDidSelfCopy();
+ updateRegion = mBuffer->BufferRect();
}
// 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;
}
- if (!EnsureBuffer() ||
- (HaveBufferOnWhite() && !EnsureBufferOnWhite())) {
+ if (!mBuffer) {
return;
}
if (mFrontBuffer->Lock(OpenMode::OPEN_READ_ONLY)) {
- UpdateDestinationFrom(*mFrontBuffer, updateRegion);
+ mBuffer->UpdateDestinationFrom(*mFrontBuffer, updateRegion);
mFrontBuffer->Unlock();
}
}
void
ContentClientDoubleBuffered::EnsureBackBufferIfFrontBuffer()
{
- if (!mTextureClient && mFrontBuffer) {
- CreateBackBuffer(mFrontBuffer->BufferRect());
-
- mBufferRect = mFrontBuffer->BufferRect();
- mBufferRotation = mFrontBuffer->BufferRotation();
+ if (!mBuffer && mFrontBuffer) {
+ mBuffer = CreateBufferInternal(mFrontBuffer->BufferRect(),
+ mFrontBuffer->GetFormat(),
+ mTextureFlags);
+ MOZ_ASSERT(mBuffer);
}
}
} // namespace layers
} // namespace mozilla
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -71,100 +71,222 @@ class CapturedPaintState;
* Then return that DrawTarget using ReturnDrawTarget.
* Call EndPaint on the content client;
*
* SwapBuffers is called in response to the transaction reply from the compositor.
*/
class ContentClient : public CompositableClient
{
public:
+ typedef gfxContentType ContentType;
+
/**
* Creates, configures, and returns a new content client. If necessary, a
* message will be sent to the compositor to create a corresponding content
* host.
*/
static already_AddRefed<ContentClient> CreateContentClient(CompositableForwarder* aFwd);
- explicit ContentClient(CompositableForwarder* aForwarder)
- : CompositableClient(aForwarder),
- mInAsyncPaint(false)
+ /**
+ * Controls the size of the backing buffer of this.
+ * - SizedToVisibleBounds: the backing buffer is exactly the same
+ * size as the bounds of PaintedLayer's visible region
+ * - ContainsVisibleBounds: the backing buffer is large enough to
+ * fit visible bounds. May be larger.
+ */
+ enum BufferSizePolicy {
+ SizedToVisibleBounds,
+ ContainsVisibleBounds
+ };
+
+ explicit ContentClient(CompositableForwarder* aForwarder,
+ BufferSizePolicy aBufferSizePolicy)
+ : CompositableClient(aForwarder)
+ , mBufferSizePolicy(aBufferSizePolicy)
+ , mInAsyncPaint(false)
{}
virtual ~ContentClient()
{}
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
- virtual void Clear() = 0;
- virtual RotatedContentBuffer::PaintState BeginPaintBuffer(PaintedLayer* aLayer,
- uint32_t aFlags) = 0;
- virtual gfx::DrawTarget* BorrowDrawTargetForPainting(RotatedContentBuffer::PaintState& aPaintState,
- RotatedContentBuffer::DrawIterator* aIter = nullptr) = 0;
- virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) = 0;
+ virtual void Clear();
+
+ /**
+ * This is returned by BeginPaint. The caller should draw into mTarget.
+ * mRegionToDraw must be drawn. mRegionToInvalidate has been invalidated
+ * by RotatedContentBuffer and must be redrawn on the screen.
+ * mRegionToInvalidate is set when the buffer has changed from
+ * opaque to transparent or vice versa, since the details of rendering can
+ * depend on the buffer type.
+ */
+ struct PaintState {
+ PaintState()
+ : mRegionToDraw()
+ , mRegionToInvalidate()
+ , mMode(SurfaceMode::SURFACE_NONE)
+ , mClip(DrawRegionClip::NONE)
+ , mContentType(gfxContentType::SENTINEL)
+ {}
+
+ nsIntRegion mRegionToDraw;
+ nsIntRegion mRegionToInvalidate;
+ SurfaceMode mMode;
+ DrawRegionClip mClip;
+ gfxContentType mContentType;
+ };
+
+ enum {
+ PAINT_WILL_RESAMPLE = 0x01,
+ PAINT_NO_ROTATION = 0x02,
+ PAINT_CAN_DRAW_ROTATED = 0x04
+ };
+
+ /**
+ * Start a drawing operation. This returns a PaintState describing what
+ * needs to be drawn to bring the buffer up to date in the visible region.
+ * This queries aLayer to get the currently valid and visible regions.
+ * The returned mTarget may be null if mRegionToDraw is empty.
+ * Otherwise it must not be null.
+ * mRegionToInvalidate will contain mRegionToDraw.
+ * @param aFlags when PAINT_WILL_RESAMPLE is passed, this indicates that
+ * buffer will be resampled when rendering (i.e the effective transform
+ * combined with the scale for the resolution is not just an integer
+ * translation). This will disable buffer rotation (since we don't want
+ * to resample across the rotation boundary) and will ensure that we
+ * make the entire buffer contents valid (since we don't want to sample
+ * invalid pixels outside the visible region, if the visible region doesn't
+ * fill the buffer bounds).
+ * PAINT_CAN_DRAW_ROTATED can be passed if the caller supports drawing
+ * rotated content that crosses the physical buffer boundary. The caller
+ * will need to call BorrowDrawTargetForPainting multiple times to achieve
+ * this.
+ */
+ PaintState BeginPaintBuffer(PaintedLayer* aLayer, uint32_t aFlags);
+
+ /**
+ * Fetch a DrawTarget for rendering. The DrawTarget remains owned by
+ * this. See notes on BorrowDrawTargetForQuadrantUpdate.
+ * May return null. If the return value is non-null, it must be
+ * 'un-borrowed' using ReturnDrawTarget.
+ *
+ * If PAINT_CAN_DRAW_ROTATED was specified for BeginPaint, then the caller
+ * must call this function repeatedly (with an iterator) until it returns
+ * nullptr. The caller should draw the mDrawRegion of the iterator instead
+ * of mRegionToDraw in the PaintState.
+ *
+ * @param aPaintState Paint state data returned by a call to BeginPaint
+ * @param aIter Paint state iterator. Only required if PAINT_CAN_DRAW_ROTATED
+ * was specified to BeginPaint.
+ */
+ virtual gfx::DrawTarget* BorrowDrawTargetForPainting(
+ PaintState& aPaintState,
+ RotatedBuffer::DrawIterator* aIter = nullptr);
+
+ /**
+ * Borrow a draw target for recording. The required transform for correct painting
+ * is not applied to the returned DrawTarget by default, BUT it is
+ * required to be whenever drawing does happen.
+ */
virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(
- RotatedContentBuffer::PaintState& aPaintState,
- RotatedContentBuffer::DrawIterator* aIter) = 0;
+ PaintState& aPaintState,
+ RotatedBuffer::DrawIterator* aIter,
+ bool aSetTransform = false);
+
+ virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned);
// Called as part of the layers transation reply. Conveys data about our
// buffer(s) from the compositor. If appropriate we should swap references
// to our buffers.
virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) {}
- // call before and after painting into this content client
+ // Call before and after painting into this content client
virtual void BeginPaint() {}
virtual void BeginAsyncPaint();
virtual void EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr);
+ nsIntRegion ExpandDrawRegion(PaintState& aPaintState,
+ RotatedBuffer::DrawIterator* aIter,
+ gfx::BackendType aBackendType);
+
+ static bool PrepareDrawTargetForPainting(CapturedPaintState*);
+
+ enum {
+ BUFFER_COMPONENT_ALPHA = 0x02 // Dual buffers should be created for drawing with
+ // component alpha.
+ };
+
protected:
+ struct BufferDecision {
+ nsIntRegion mNeededRegion;
+ nsIntRegion mValidRegion;
+ gfx::IntRect mBufferRect;
+ SurfaceMode mBufferMode;
+ gfxContentType mBufferContentType;
+ bool mCanReuseBuffer;
+ bool mCanKeepBufferContents;
+ };
+
+ BufferDecision CalculateBufferForPaint(PaintedLayer* aLayer,
+ uint32_t aFlags);
+
+ /**
+ * Return the buffer's content type. Requires a valid buffer or
+ * buffer provider.
+ */
+ gfxContentType BufferContentType();
+ bool BufferSizeOkFor(const gfx::IntSize& aSize);
+
+ OpenMode LockMode() const;
+
+ /**
+ * Any actions that should be performed at the last moment before we begin
+ * rendering the next frame. I.e., after we calculate what we will draw,
+ * but before we rotate the buffer and possibly create new buffers.
+ * aRegionToDraw is the region which is guaranteed to be overwritten when
+ * drawing the next frame.
+ */
+ virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) {}
+
+ virtual RefPtr<RotatedBuffer> CreateBuffer(gfxContentType aType,
+ const gfx::IntRect& aRect,
+ uint32_t aFlags) = 0;
+
+ RefPtr<RotatedBuffer> mBuffer;
+ BufferSizePolicy mBufferSizePolicy;
bool mInAsyncPaint;
};
-// thin wrapper around RotatedContentBuffer, for on-mtc
+// Thin wrapper around DrawTargetRotatedBuffer, for on-mtc
class ContentClientBasic final : public ContentClient
- , protected RotatedContentBuffer
{
public:
explicit ContentClientBasic(gfx::BackendType aBackend);
- typedef RotatedContentBuffer::PaintState PaintState;
- typedef RotatedContentBuffer::ContentType ContentType;
-
- virtual void Clear() override { RotatedContentBuffer::Clear(); }
- virtual PaintState BeginPaintBuffer(PaintedLayer* aLayer,
- uint32_t aFlags) override
- {
- return RotatedContentBuffer::BeginPaint(aLayer, aFlags);
- }
- virtual gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
- RotatedContentBuffer::DrawIterator* aIter = nullptr) override
- {
- return RotatedContentBuffer::BorrowDrawTargetForPainting(aPaintState, aIter);
- }
virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(PaintState& aPaintState,
- RotatedContentBuffer::DrawIterator* aIter) override;
-
- virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) override
- {
- BorrowDrawTarget::ReturnDrawTarget(aReturned);
- }
+ RotatedBuffer::DrawIterator* aIter,
+ bool aSetTransform) override;
void DrawTo(PaintedLayer* aLayer,
gfx::DrawTarget* aTarget,
float aOpacity,
gfx::CompositionOp aOp,
gfx::SourceSurface* aMask,
const gfx::Matrix* aMaskTransform);
- virtual void CreateBuffer(ContentType aType, const gfx::IntRect& aRect, uint32_t aFlags,
- RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) override;
-
virtual TextureInfo GetTextureInfo() const override
{
MOZ_CRASH("GFX: Should not be called on non-remote ContentClient");
}
+protected:
+ virtual RefPtr<RotatedBuffer> CreateBuffer(gfxContentType aType,
+ const gfx::IntRect& aRect,
+ uint32_t aFlags) override;
+
private:
gfx::BackendType mBackend;
};
/**
* A ContentClient backed by a RotatedContentBuffer.
*
* When using a ContentClientRemoteBuffer, SurfaceDescriptors are created on
@@ -176,134 +298,74 @@ private:
* compositor should assign the corresponding TextureHosts to our corresponding
* ContentHost.
*
* If the size or type of our buffer(s) change(s), then we simply destroy and
* create them.
*/
// Version using new texture clients
class ContentClientRemoteBuffer : public ContentClient
- , protected RotatedContentBuffer
{
- using RotatedContentBuffer::BufferRect;
- using RotatedContentBuffer::BufferRotation;
public:
explicit ContentClientRemoteBuffer(CompositableForwarder* aForwarder)
- : ContentClient(aForwarder)
- , RotatedContentBuffer(ContainsVisibleBounds)
+ : ContentClient(aForwarder, ContainsVisibleBounds)
, mIsNewBuffer(false)
- , mSurfaceFormat(gfx::SurfaceFormat::B8G8R8A8)
{}
- typedef RotatedContentBuffer::PaintState PaintState;
- typedef RotatedContentBuffer::ContentType ContentType;
-
- virtual void Clear() override
- {
- RotatedContentBuffer::Clear();
- mTextureClient = nullptr;
- mTextureClientOnWhite = nullptr;
- }
-
virtual void Dump(std::stringstream& aStream,
const char* aPrefix="",
bool aDumpHtml=false,
TextureDumpMode aCompress=TextureDumpMode::Compress) override;
- virtual PaintState BeginPaintBuffer(PaintedLayer* aLayer,
- uint32_t aFlags) override
- {
- return RotatedContentBuffer::BeginPaint(aLayer, aFlags);
- }
- virtual gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
- RotatedContentBuffer::DrawIterator* aIter = nullptr) override
- {
- return RotatedContentBuffer::BorrowDrawTargetForPainting(aPaintState, aIter);
- }
virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(PaintState& aPaintState,
- RotatedContentBuffer::DrawIterator* aIter) override;
-
- virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) override
- {
- BorrowDrawTarget::ReturnDrawTarget(aReturned);
- }
+ RotatedBuffer::DrawIterator* aIter,
+ bool aSetTransform) override;
/**
* Begin/End Paint map a gfxASurface from the texture client
* into the buffer of RotatedBuffer. The surface is only
* valid when the texture client is locked, so is mapped out
* of RotatedContentBuffer when we are done painting.
* None of the underlying buffer attributes (rect, rotation)
* are affected by mapping/unmapping.
*/
virtual void BeginPaint() override;
virtual void BeginAsyncPaint() override;
virtual void EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr) override;
virtual void Updated(const nsIntRegion& aRegionToDraw,
const nsIntRegion& aVisibleRegion);
- // Expose these protected methods from the superclass.
- virtual const gfx::IntRect& BufferRect() const
- {
- return RotatedContentBuffer::BufferRect();
- }
- virtual const nsIntPoint& BufferRotation() const
- {
- return RotatedContentBuffer::BufferRotation();
- }
-
- virtual void CreateBuffer(ContentType aType, const gfx::IntRect& aRect, uint32_t aFlags,
- RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) override;
-
virtual TextureFlags ExtraTextureFlags() const
{
return TextureFlags::IMMEDIATE_UPLOAD;
}
protected:
- void DestroyBuffers();
-
virtual nsIntRegion GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
const nsIntRegion& aVisibleRegion);
- void BuildTextureClients(gfx::SurfaceFormat aFormat,
- const gfx::IntRect& aRect,
- uint32_t aFlags);
-
- void CreateBackBuffer(const gfx::IntRect& aBufferRect);
-
// Ensure we have a valid back buffer if we have a valid front buffer (i.e.
// if a backbuffer has been created.)
virtual void EnsureBackBufferIfFrontBuffer() {}
- // Create the front buffer for the ContentClient/Host pair if necessary
- // and notify the compositor that we have created the buffer(s).
- virtual void DestroyFrontBuffer() {}
+ virtual RefPtr<RotatedBuffer> CreateBuffer(gfxContentType aType,
+ const gfx::IntRect& aRect,
+ uint32_t aFlags) override;
- virtual void AbortTextureClientCreation()
+ RefPtr<RotatedBuffer> CreateBufferInternal(const gfx::IntRect& aRect,
+ gfx::SurfaceFormat aFormat,
+ TextureFlags aFlags);
+
+ RemoteRotatedBuffer* GetRemoteBuffer() const
{
- mTextureClient = nullptr;
- mTextureClientOnWhite = nullptr;
- mIsNewBuffer = false;
+ return static_cast<RemoteRotatedBuffer*>(mBuffer.get());
}
- virtual bool LockBuffers() override;
- virtual void UnlockBuffers() override;
-
- RefPtr<TextureClient> mTextureClient;
- RefPtr<TextureClient> mTextureClientOnWhite;
- // keep a record of texture clients we have created and need to keep around
- // (for RotatedBuffer to access), then unlock and remove them when we are done
- // painting.
- nsTArray<RefPtr<TextureClient> > mOldTextures;
-
bool mIsNewBuffer;
- gfx::IntSize mSize;
- gfx::SurfaceFormat mSurfaceFormat;
};
/**
* A double buffered ContentClient. mTextureClient is the back buffer, which
* we draw into. mFrontClient is the front buffer which we may read from, but
* not write to, when the compositor does not have the 'soft' lock. We can write
* into mTextureClient at any time.
*
@@ -317,53 +379,43 @@ class ContentClientDoubleBuffered : publ
public:
explicit ContentClientDoubleBuffered(CompositableForwarder* aFwd)
: ContentClientRemoteBuffer(aFwd)
, mFrontAndBackBufferDiffer(false)
{}
virtual ~ContentClientDoubleBuffered() {}
+ virtual void Dump(std::stringstream& aStream,
+ const char* aPrefix="",
+ bool aDumpHtml=false,
+ TextureDumpMode aCompress=TextureDumpMode::Compress) override;
+
virtual void Clear() override
{
- ContentClientRemoteBuffer::Clear();
- mFrontBuffer = Nothing();
+ ContentClient::Clear();
+ mFrontBuffer = nullptr;
}
virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) override;
virtual void BeginPaint() override;
virtual void BeginAsyncPaint() override;
virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) override;
virtual void EnsureBackBufferIfFrontBuffer() override;
virtual TextureInfo GetTextureInfo() const override
{
return TextureInfo(CompositableType::CONTENT_DOUBLE, mTextureFlags);
}
- virtual void Dump(std::stringstream& aStream,
- const char* aPrefix="",
- bool aDumpHtml=false,
- TextureDumpMode aCompress=TextureDumpMode::Compress) override;
-protected:
- virtual void DestroyFrontBuffer() override;
-
private:
-
- virtual void AbortTextureClientCreation() override
- {
- mTextureClient = nullptr;
- mTextureClientOnWhite = nullptr;
- mFrontBuffer = Nothing();
- }
-
- Maybe<RemoteRotatedBuffer> mFrontBuffer;
+ RefPtr<RemoteRotatedBuffer> mFrontBuffer;
nsIntRegion mFrontUpdatedRegion;
bool mFrontAndBackBufferDiffer;
};
/**
* A single buffered ContentClient. We have a single TextureClient/Host
* which we update and then send a message to the compositor that we are
* done updating. It is not safe for the compositor to use the corresponding
--- a/gfx/layers/composite/ContentHost.h
+++ b/gfx/layers/composite/ContentHost.h
@@ -15,16 +15,17 @@
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/gfx/BasePoint.h" // for BasePoint
#include "mozilla/gfx/MatrixFwd.h" // for Matrix4x4
#include "mozilla/gfx/Point.h" // for Point
#include "mozilla/gfx/Polygon.h" // for Polygon
#include "mozilla/gfx/Rect.h" // for Rect
#include "mozilla/gfx/Types.h" // for SamplingFilter
#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc
+#include "mozilla/layers/ContentClient.h" // for ContentClient
#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/layers/LayersTypes.h" // for etc
#include "mozilla/layers/TextureHost.h" // for TextureHost
#include "mozilla/mozalloc.h" // for operator delete
#include "mozilla/UniquePtr.h" // for UniquePtr
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsDebug.h" // for NS_RUNTIMEABORT
@@ -86,18 +87,18 @@ protected:
* texture hosts (for single and double buffering) to the ContentHost.
*
* It is the responsibility of the ContentHost to destroy its resources when
* they are recreated or the ContentHost dies.
*/
class ContentHostBase : public ContentHost
{
public:
- typedef RotatedContentBuffer::ContentType ContentType;
- typedef RotatedContentBuffer::PaintState PaintState;
+ typedef ContentClient::ContentType ContentType;
+ typedef ContentClient::PaintState PaintState;
explicit ContentHostBase(const TextureInfo& aTextureInfo);
virtual ~ContentHostBase();
virtual gfx::IntRect GetBufferRect() override { return mBufferRect; }
virtual nsIntPoint GetOriginOffset()
{