mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 739679 - Part 3: BasicTiledThebesLayer. r=mwoodrow,roc
This commit is contained in:
parent
757a6fa342
commit
9a37018a8c
@ -72,6 +72,7 @@ EXPORTS = \
|
||||
CPPSRCS = \
|
||||
BasicImages.cpp \
|
||||
BasicLayers.cpp \
|
||||
BasicTiledThebesLayer.cpp \
|
||||
Layers.cpp \
|
||||
RenderTrace.cpp \
|
||||
ReadbackProcessor.cpp \
|
||||
|
@ -49,6 +49,7 @@
|
||||
|
||||
#include "BasicLayers.h"
|
||||
#include "BasicImplData.h"
|
||||
#include "BasicTiledThebesLayer.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "RenderTrace.h"
|
||||
|
||||
@ -3126,10 +3127,23 @@ already_AddRefed<ThebesLayer>
|
||||
BasicShadowLayerManager::CreateThebesLayer()
|
||||
{
|
||||
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
|
||||
nsRefPtr<BasicShadowableThebesLayer> layer =
|
||||
new BasicShadowableThebesLayer(this);
|
||||
MAYBE_CREATE_SHADOW(Thebes);
|
||||
return layer.forget();
|
||||
#ifdef FORCE_BASICTILEDTHEBESLAYER
|
||||
if (HasShadowManager()) {
|
||||
// BasicTiledThebesLayer doesn't support main
|
||||
// thread compositing so only return this layer
|
||||
// type if we have a shadow manager.
|
||||
nsRefPtr<BasicTiledThebesLayer> layer =
|
||||
new BasicTiledThebesLayer(this);
|
||||
MAYBE_CREATE_SHADOW(Thebes);
|
||||
return layer.forget();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
nsRefPtr<BasicShadowableThebesLayer> layer =
|
||||
new BasicShadowableThebesLayer(this);
|
||||
MAYBE_CREATE_SHADOW(Thebes);
|
||||
return layer.forget();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<ContainerLayer>
|
||||
|
227
gfx/layers/basic/BasicTiledThebesLayer.cpp
Normal file
227
gfx/layers/basic/BasicTiledThebesLayer.cpp
Normal file
@ -0,0 +1,227 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/layers/PLayersChild.h"
|
||||
#include "BasicTiledThebesLayer.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "sampler.h"
|
||||
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
#include "cairo.h"
|
||||
#include <sstream>
|
||||
using mozilla::layers::Layer;
|
||||
static void DrawDebugOverlay(gfxImageSurface* imgSurf, int x, int y)
|
||||
{
|
||||
gfxContext c(imgSurf);
|
||||
|
||||
// Draw border
|
||||
c.NewPath();
|
||||
c.SetDeviceColor(gfxRGBA(0.0, 0.0, 0.0, 1.0));
|
||||
c.Rectangle(gfxRect(gfxPoint(0,0),imgSurf->GetSize()));
|
||||
c.Stroke();
|
||||
|
||||
// Build tile description
|
||||
std::stringstream ss;
|
||||
ss << x << ", " << y;
|
||||
|
||||
// Draw text using cairo toy text API
|
||||
cairo_t* cr = c.GetCairo();
|
||||
cairo_set_font_size(cr, 10);
|
||||
cairo_text_extents_t extents;
|
||||
cairo_text_extents(cr, ss.str().c_str(), &extents);
|
||||
|
||||
int textWidth = extents.width + 6;
|
||||
|
||||
c.NewPath();
|
||||
c.SetDeviceColor(gfxRGBA(0.0, 0.0, 0.0, 1.0));
|
||||
c.Rectangle(gfxRect(gfxPoint(2,2),gfxSize(textWidth, 15)));
|
||||
c.Fill();
|
||||
|
||||
c.NewPath();
|
||||
c.SetDeviceColor(gfxRGBA(1.0, 0.0, 0.0, 1.0));
|
||||
c.Rectangle(gfxRect(gfxPoint(2,2),gfxSize(textWidth, 15)));
|
||||
c.Stroke();
|
||||
|
||||
c.NewPath();
|
||||
cairo_move_to(cr, 4, 13);
|
||||
cairo_show_text(cr, ss.str().c_str());
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
void
|
||||
BasicTiledLayerBuffer::PaintThebes(BasicTiledThebesLayer* aLayer,
|
||||
const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aPaintRegion,
|
||||
LayerManager::DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData)
|
||||
{
|
||||
mThebesLayer = aLayer;
|
||||
mCallback = aCallback;
|
||||
mCallbackData = aCallbackData;
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
long start = PR_IntervalNow();
|
||||
#endif
|
||||
if (UseSinglePaintBuffer()) {
|
||||
SAMPLE_LABEL("BasicTiledLayerBuffer", "PaintThebesSingleBuffer");
|
||||
const nsIntRect bounds = aPaintRegion.GetBounds();
|
||||
mSinglePaintBuffer = new gfxImageSurface(gfxIntSize(bounds.width, bounds.height), gfxASurface::ImageFormatRGB16_565);
|
||||
mSinglePaintBufferOffset = nsIntPoint(bounds.x, bounds.y);
|
||||
nsRefPtr<gfxContext> ctxt = new gfxContext(mSinglePaintBuffer);
|
||||
ctxt->NewPath();
|
||||
ctxt->Translate(gfxPoint(-bounds.x, -bounds.y));
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (PR_IntervalNow() - start > 3) {
|
||||
printf_stderr("Slow alloc %i\n", PR_IntervalNow() - start);
|
||||
}
|
||||
start = PR_IntervalNow();
|
||||
#endif
|
||||
mCallback(mThebesLayer, ctxt, aPaintRegion, aPaintRegion, mCallbackData);
|
||||
}
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (PR_IntervalNow() - start > 30) {
|
||||
const nsIntRect bounds = aPaintRegion.GetBounds();
|
||||
printf_stderr("Time to draw %i: %i, %i, %i, %i\n", PR_IntervalNow() - start, bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
if (aPaintRegion.IsComplex()) {
|
||||
printf_stderr("Complex region\n");
|
||||
nsIntRegionRectIterator it(aPaintRegion);
|
||||
for (const nsIntRect* rect = it.Next(); rect != nsnull; rect = it.Next()) {
|
||||
printf_stderr(" rect %i, %i, %i, %i\n", rect->x, rect->y, rect->width, rect->height);
|
||||
}
|
||||
}
|
||||
}
|
||||
start = PR_IntervalNow();
|
||||
#endif
|
||||
|
||||
SAMPLE_LABEL("BasicTiledLayerBuffer", "PaintThebesUpdate");
|
||||
Update(aNewValidRegion, aPaintRegion);
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (PR_IntervalNow() - start > 10) {
|
||||
const nsIntRect bounds = aPaintRegion.GetBounds();
|
||||
printf_stderr("Time to tile %i: %i, %i, %i, %i\n", PR_IntervalNow() - start, bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
}
|
||||
#endif
|
||||
|
||||
mThebesLayer = nsnull;
|
||||
mCallback = nsnull;
|
||||
mCallbackData = nsnull;
|
||||
mSinglePaintBuffer = nsnull;
|
||||
}
|
||||
|
||||
BasicTiledLayerTile
|
||||
BasicTiledLayerBuffer::ValidateTileInternal(BasicTiledLayerTile aTile,
|
||||
const nsIntPoint& aTileOrigin,
|
||||
const nsIntRect& aDirtyRect)
|
||||
{
|
||||
if (aTile == GetPlaceholderTile()) {
|
||||
gfxImageSurface* tmpTile = new gfxImageSurface(gfxIntSize(GetTileLength(), GetTileLength()), gfxASurface::ImageFormatRGB16_565);
|
||||
aTile = BasicTiledLayerTile(tmpTile);
|
||||
}
|
||||
|
||||
gfxRect drawRect(aDirtyRect.x - aTileOrigin.x, aDirtyRect.y - aTileOrigin.y,
|
||||
aDirtyRect.width, aDirtyRect.height);
|
||||
|
||||
// Use the gfxReusableSurfaceWrapper, which will reuse the surface
|
||||
// if the compositor no longer has a read lock, otherwise the surface
|
||||
// will be copied into a new writable surface.
|
||||
gfxImageSurface* writableSurface;
|
||||
aTile.mSurface = aTile.mSurface->GetWritable(&writableSurface);
|
||||
|
||||
// Bug 742100, this gfxContext really should live on the stack.
|
||||
nsRefPtr<gfxContext> ctxt = new gfxContext(writableSurface);
|
||||
ctxt->NewPath();
|
||||
ctxt->SetOperator(gfxContext::OPERATOR_CLEAR);
|
||||
ctxt->Rectangle(drawRect, true);
|
||||
ctxt->Fill();
|
||||
ctxt->SetOperator(gfxContext::OPERATOR_OVER);
|
||||
if (mSinglePaintBuffer) {
|
||||
ctxt->NewPath();
|
||||
ctxt->SetSource(mSinglePaintBuffer.get(),
|
||||
gfxPoint(mSinglePaintBufferOffset.x - aDirtyRect.x + drawRect.x,
|
||||
mSinglePaintBufferOffset.y - aDirtyRect.y + drawRect.y));
|
||||
ctxt->Rectangle(drawRect, true);
|
||||
ctxt->Fill();
|
||||
} else {
|
||||
ctxt->NewPath();
|
||||
ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));
|
||||
nsIntPoint a = aTileOrigin;
|
||||
mCallback(mThebesLayer, ctxt, nsIntRegion(nsIntRect(a, nsIntSize(GetTileLength(), GetTileLength()))), aDirtyRect, mCallbackData);
|
||||
}
|
||||
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
DrawDebugOverlay(writableSurface, aTileOrigin.x, aTileOrigin.y);
|
||||
//aTile->DumpAsDataURL();
|
||||
#endif
|
||||
|
||||
return aTile;
|
||||
}
|
||||
|
||||
BasicTiledLayerTile
|
||||
BasicTiledLayerBuffer::ValidateTile(BasicTiledLayerTile aTile,
|
||||
const nsIntPoint& aTileOrigin,
|
||||
const nsIntRegion& aDirtyRegion)
|
||||
{
|
||||
|
||||
SAMPLE_LABEL("BasicTiledLayerBuffer", "ValidateTile");
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (aDirtyRegion.IsComplex()) {
|
||||
printf_stderr("Complex region\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIntRegionRectIterator it(aDirtyRegion);
|
||||
for (const nsIntRect* rect = it.Next(); rect != nsnull; rect = it.Next()) {
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
printf_stderr(" break into subrect %i, %i, %i, %i\n", rect->x, rect->y, rect->width, rect->height);
|
||||
#endif
|
||||
aTile = ValidateTileInternal(aTile, aTileOrigin, *rect);
|
||||
}
|
||||
|
||||
return aTile;
|
||||
}
|
||||
|
||||
void
|
||||
BasicTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
|
||||
{
|
||||
aAttrs = ThebesLayerAttributes(GetValidRegion());
|
||||
}
|
||||
|
||||
void
|
||||
BasicTiledThebesLayer::PaintThebes(gfxContext* aContext,
|
||||
LayerManager::DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
ReadbackProcessor* aReadback)
|
||||
{
|
||||
if (!aCallback) {
|
||||
BasicManager()->SetTransactionIncomplete();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasShadow()) {
|
||||
NS_ASSERTION(false, "Shadow requested for painting\n");
|
||||
return;
|
||||
}
|
||||
|
||||
nsIntRegion regionToPaint = mVisibleRegion;
|
||||
regionToPaint.Sub(regionToPaint, mValidRegion);
|
||||
if (regionToPaint.IsEmpty())
|
||||
return;
|
||||
|
||||
mTiledBuffer.PaintThebes(this, mVisibleRegion, regionToPaint, aCallback, aCallbackData);
|
||||
mTiledBuffer.ReadLock();
|
||||
mValidRegion = mVisibleRegion;
|
||||
|
||||
BasicManager()->PaintedTiledLayerBuffer(BasicManager()->Hold(this), &mTiledBuffer);
|
||||
}
|
||||
|
||||
} // mozilla
|
||||
} // layers
|
211
gfx/layers/basic/BasicTiledThebesLayer.h
Normal file
211
gfx/layers/basic/BasicTiledThebesLayer.h
Normal file
@ -0,0 +1,211 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_BASICTILEDTHEBESLAYER_H
|
||||
#define GFX_BASICTILEDTHEBESLAYER_H
|
||||
|
||||
#include "TiledLayerBuffer.h"
|
||||
#include "gfxReusableSurfaceWrapper.h"
|
||||
#include "mozilla/layers/ShadowLayers.h"
|
||||
#include "BasicLayers.h"
|
||||
#include "BasicImplData.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/**
|
||||
* Represent a single tile in tiled buffer. It's backed
|
||||
* by a gfxReusableSurfaceWrapper that implements a
|
||||
* copy-on-write mechanism while locked. The tile should be
|
||||
* locked before being sent to the compositor and unlocked
|
||||
* as soon as it is uploaded to prevent a copy.
|
||||
* Ideal place to store per tile debug information.
|
||||
*/
|
||||
struct BasicTiledLayerTile {
|
||||
nsRefPtr<gfxReusableSurfaceWrapper> mSurface;
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
TimeStamp mLastUpdate;
|
||||
#endif
|
||||
|
||||
// Placeholder
|
||||
BasicTiledLayerTile()
|
||||
: mSurface(NULL)
|
||||
{}
|
||||
explicit BasicTiledLayerTile(gfxImageSurface* aSurface)
|
||||
: mSurface(new gfxReusableSurfaceWrapper(aSurface))
|
||||
{
|
||||
}
|
||||
BasicTiledLayerTile(const BasicTiledLayerTile& o) {
|
||||
mSurface = o.mSurface;
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
mLastUpdate = o.mLastUpdate;
|
||||
#endif
|
||||
}
|
||||
BasicTiledLayerTile& operator=(const BasicTiledLayerTile& o) {
|
||||
if (this == &o) return *this;
|
||||
mSurface = o.mSurface;
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
mLastUpdate = o.mLastUpdate;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
bool operator== (const BasicTiledLayerTile& o) const {
|
||||
return mSurface == o.mSurface;
|
||||
}
|
||||
bool operator!= (const BasicTiledLayerTile& o) const {
|
||||
return mSurface != o.mSurface;
|
||||
}
|
||||
void ReadUnlock() {
|
||||
mSurface->ReadUnlock();
|
||||
}
|
||||
void ReadLock() {
|
||||
mSurface->ReadLock();
|
||||
}
|
||||
};
|
||||
|
||||
class BasicTiledThebesLayer;
|
||||
|
||||
/**
|
||||
* Provide an instance of TiledLayerBuffer backed by image surfaces.
|
||||
* This buffer provides an implementation to ValidateTile using a
|
||||
* thebes callback and can support painting using a single paint buffer
|
||||
* which is much faster then painting directly into the tiles.
|
||||
*/
|
||||
|
||||
class BasicTiledLayerBuffer : public TiledLayerBuffer<BasicTiledLayerBuffer, BasicTiledLayerTile>
|
||||
{
|
||||
friend class TiledLayerBuffer<BasicTiledLayerBuffer, BasicTiledLayerTile>;
|
||||
|
||||
public:
|
||||
void PaintThebes(BasicTiledThebesLayer* aLayer,
|
||||
const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aPaintRegion,
|
||||
LayerManager::DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData);
|
||||
|
||||
BasicTiledLayerTile GetPlaceholderTile() const {
|
||||
return mPlaceholder;
|
||||
}
|
||||
|
||||
void ReadUnlock() {
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
if (mRetainedTiles[i] == GetPlaceholderTile()) continue;
|
||||
mRetainedTiles[i].ReadUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
void ReadLock() {
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
if (mRetainedTiles[i] == GetPlaceholderTile()) continue;
|
||||
mRetainedTiles[i].ReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
BasicTiledLayerTile ValidateTile(BasicTiledLayerTile aTile,
|
||||
const nsIntPoint& aTileRect,
|
||||
const nsIntRegion& dirtyRect);
|
||||
|
||||
// If this returns true, we perform the paint operation into a single large
|
||||
// buffer and copy it out to the tiles instead of calling PaintThebes() on
|
||||
// each tile individually. Somewhat surprisingly, this turns out to be faster
|
||||
// on Android.
|
||||
bool UseSinglePaintBuffer() { return true; }
|
||||
|
||||
void ReleaseTile(BasicTiledLayerTile aTile) { /* No-op. */ }
|
||||
|
||||
void SwapTiles(BasicTiledLayerTile& aTileA, BasicTiledLayerTile& aTileB) {
|
||||
std::swap(aTileA, aTileB);
|
||||
}
|
||||
|
||||
private:
|
||||
BasicTiledThebesLayer* mThebesLayer;
|
||||
LayerManager::DrawThebesLayerCallback mCallback;
|
||||
void* mCallbackData;
|
||||
|
||||
// The buffer we use when UseSinglePaintBuffer() above is true.
|
||||
nsRefPtr<gfxImageSurface> mSinglePaintBuffer;
|
||||
nsIntPoint mSinglePaintBufferOffset;
|
||||
|
||||
BasicTiledLayerTile mPlaceholder;
|
||||
|
||||
BasicTiledLayerTile ValidateTileInternal(BasicTiledLayerTile aTile,
|
||||
const nsIntPoint& aTileOrigin,
|
||||
const nsIntRect& aDirtyRect);
|
||||
};
|
||||
|
||||
/**
|
||||
* An implementation of ThebesLayer that ONLY supports remote
|
||||
* composition that is backed by tiles. This thebes layer implementation
|
||||
* is better suited to mobile hardware to work around slow implementation
|
||||
* of glTexImage2D (for OGL compositors), and restrait memory bandwidth.
|
||||
*/
|
||||
class BasicTiledThebesLayer : public ThebesLayer,
|
||||
public BasicImplData,
|
||||
public BasicShadowableLayer
|
||||
{
|
||||
typedef ThebesLayer Base;
|
||||
|
||||
public:
|
||||
BasicTiledThebesLayer(BasicShadowLayerManager* const aManager)
|
||||
: ThebesLayer(aManager, static_cast<BasicImplData*>(this))
|
||||
{
|
||||
MOZ_COUNT_CTOR(BasicTiledThebesLayer);
|
||||
}
|
||||
|
||||
~BasicTiledThebesLayer()
|
||||
{
|
||||
MOZ_COUNT_DTOR(BasicTiledThebesLayer);
|
||||
}
|
||||
|
||||
|
||||
// Thebes Layer
|
||||
virtual Layer* AsLayer() { return this; }
|
||||
virtual void InvalidateRegion(const nsIntRegion& aRegion) {
|
||||
mValidRegion.Sub(mValidRegion, aRegion);
|
||||
}
|
||||
|
||||
// BasicImplData
|
||||
virtual bool MustRetainContent() { return HasShadow(); }
|
||||
|
||||
// Shadow methods
|
||||
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs);
|
||||
virtual ShadowableLayer* AsShadowableLayer() { return this; }
|
||||
|
||||
virtual void Disconnect()
|
||||
{
|
||||
BasicShadowableLayer::Disconnect();
|
||||
}
|
||||
|
||||
virtual void PaintThebes(gfxContext* aContext,
|
||||
LayerManager::DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
ReadbackProcessor* aReadback);
|
||||
|
||||
private:
|
||||
BasicShadowLayerManager* BasicManager()
|
||||
{
|
||||
return static_cast<BasicShadowLayerManager*>(mManager);
|
||||
}
|
||||
|
||||
// BasicImplData
|
||||
virtual void
|
||||
PaintBuffer(gfxContext* aContext,
|
||||
const nsIntRegion& aRegionToDraw,
|
||||
const nsIntRegion& aExtendedRegionToDraw,
|
||||
const nsIntRegion& aRegionToInvalidate,
|
||||
bool aDidSelfCopy,
|
||||
LayerManager::DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData)
|
||||
{ NS_RUNTIMEABORT("Not reached."); }
|
||||
|
||||
// Members
|
||||
BasicTiledLayerBuffer mTiledBuffer;
|
||||
};
|
||||
|
||||
} // layers
|
||||
} // mozilla
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user