Switch GPU Optimization code to SkRecord
R=mtklein@google.com, bsalomon@google.com Author: robertphillips@google.com Review URL: https://codereview.chromium.org/504393002
This commit is contained in:
parent
9c3d24b9d1
commit
d62833079f
@ -296,7 +296,7 @@ private:
|
||||
friend class SkPictureData; // to access OperationList
|
||||
friend class SkPictureRecorder; // just for SkPicture-based constructor
|
||||
friend class SkGpuDevice; // for EXPERIMENTAL_getActiveOps/OperationList
|
||||
friend class GrGatherCanvas; // needs to know if old or new picture
|
||||
friend class CollectLayers; // access to fRecord
|
||||
friend class SkPicturePlayback; // to get fData & OperationList
|
||||
friend class SkPictureReplacementPlayback; // to access OperationList
|
||||
|
||||
|
@ -6,12 +6,10 @@
|
||||
*/
|
||||
|
||||
#include "GrPictureUtils.h"
|
||||
#include "SkCanvasPriv.h"
|
||||
#include "SkDevice.h"
|
||||
#include "SkDraw.h"
|
||||
|
||||
#include "SkPaintPriv.h"
|
||||
#include "SkPictureData.h"
|
||||
#include "SkPicturePlayback.h"
|
||||
#include "SkRecord.h"
|
||||
#include "SkRecords.h"
|
||||
|
||||
SkPicture::AccelData::Key GrAccelData::ComputeAccelDataKey() {
|
||||
static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
|
||||
@ -19,261 +17,261 @@ SkPicture::AccelData::Key GrAccelData::ComputeAccelDataKey() {
|
||||
return gGPUID;
|
||||
}
|
||||
|
||||
// The GrGather device performs GPU-backend-specific preprocessing on
|
||||
// a picture. The results are stored in a GrAccelData.
|
||||
//
|
||||
// Currently the only interesting work is done in drawDevice (i.e., when a
|
||||
// saveLayer is collapsed back into its parent) and, maybe, in onCreateDevice.
|
||||
// All the current work could be done much more efficiently by just traversing the
|
||||
// raw op codes in the SkPicture (although we would still need to replay all the
|
||||
// clip calls).
|
||||
class GrGatherDevice : public SkBaseDevice {
|
||||
// SkRecord visitor to gather saveLayer/restore information.
|
||||
class CollectLayers {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(GrGatherDevice)
|
||||
CollectLayers(const SkPicture* pict, GrAccelData* accelData)
|
||||
: fPictureID(pict->uniqueID())
|
||||
, fCTM(&SkMatrix::I())
|
||||
, fCurrentClipBounds(SkIRect::MakeXYWH(0, 0, pict->width(), pict->height()))
|
||||
, fSaveLayersInStack(0)
|
||||
, fAccelData(accelData) {
|
||||
|
||||
GrGatherDevice(int width, int height, SkPicturePlayback* playback, GrAccelData* accelData,
|
||||
int saveLayerDepth) {
|
||||
fPlayback = playback;
|
||||
fSaveLayerDepth = saveLayerDepth;
|
||||
fInfo.fValid = true;
|
||||
fInfo.fSize.set(width, height);
|
||||
fInfo.fPaint = NULL;
|
||||
fInfo.fSaveLayerOpID = fPlayback->curOpID();
|
||||
fInfo.fRestoreOpID = 0;
|
||||
fInfo.fHasNestedLayers = false;
|
||||
fInfo.fIsNested = (2 == fSaveLayerDepth);
|
||||
|
||||
fEmptyBitmap.setInfo(SkImageInfo::MakeUnknown(fInfo.fSize.fWidth, fInfo.fSize.fHeight));
|
||||
fAccelData = accelData;
|
||||
fAlreadyDrawn = false;
|
||||
}
|
||||
|
||||
virtual ~GrGatherDevice() { }
|
||||
|
||||
virtual SkImageInfo imageInfo() const SK_OVERRIDE {
|
||||
return fEmptyBitmap.info();
|
||||
}
|
||||
|
||||
#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
|
||||
virtual void writePixels(const SkBitmap& bitmap, int x, int y,
|
||||
SkCanvas::Config8888 config8888) SK_OVERRIDE {
|
||||
NotSupported();
|
||||
}
|
||||
#endif
|
||||
virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }
|
||||
|
||||
protected:
|
||||
virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
|
||||
return false;
|
||||
}
|
||||
virtual void clear(SkColor color) SK_OVERRIDE {
|
||||
NothingToDo();
|
||||
}
|
||||
virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
|
||||
}
|
||||
virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
|
||||
const SkPoint points[], const SkPaint& paint) SK_OVERRIDE {
|
||||
}
|
||||
virtual void drawRect(const SkDraw& draw, const SkRect& rect,
|
||||
const SkPaint& paint) SK_OVERRIDE {
|
||||
}
|
||||
virtual void drawOval(const SkDraw& draw, const SkRect& rect,
|
||||
const SkPaint& paint) SK_OVERRIDE {
|
||||
}
|
||||
virtual void drawRRect(const SkDraw& draw, const SkRRect& rrect,
|
||||
const SkPaint& paint) SK_OVERRIDE {
|
||||
}
|
||||
virtual void drawPath(const SkDraw& draw, const SkPath& path,
|
||||
const SkPaint& paint, const SkMatrix* prePathMatrix,
|
||||
bool pathIsMutable) SK_OVERRIDE {
|
||||
}
|
||||
virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
|
||||
const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE {
|
||||
}
|
||||
virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
|
||||
int x, int y, const SkPaint& paint) SK_OVERRIDE {
|
||||
}
|
||||
virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
|
||||
const SkRect* srcOrNull, const SkRect& dst,
|
||||
const SkPaint& paint,
|
||||
SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
|
||||
}
|
||||
virtual void drawText(const SkDraw& draw, const void* text, size_t len,
|
||||
SkScalar x, SkScalar y,
|
||||
const SkPaint& paint) SK_OVERRIDE {
|
||||
}
|
||||
virtual void drawPosText(const SkDraw& draw, const void* text, size_t len,
|
||||
const SkScalar pos[], SkScalar constY,
|
||||
int scalarsPerPos, const SkPaint& paint) SK_OVERRIDE {
|
||||
}
|
||||
virtual void drawTextOnPath(const SkDraw& draw, const void* text, size_t len,
|
||||
const SkPath& path, const SkMatrix* matrix,
|
||||
const SkPaint& paint) SK_OVERRIDE {
|
||||
}
|
||||
virtual void drawVertices(const SkDraw& draw, SkCanvas::VertexMode, int vertexCount,
|
||||
const SkPoint verts[], const SkPoint texs[],
|
||||
const SkColor colors[], SkXfermode* xmode,
|
||||
const uint16_t indices[], int indexCount,
|
||||
const SkPaint& paint) SK_OVERRIDE {
|
||||
}
|
||||
virtual void drawDevice(const SkDraw& draw, SkBaseDevice* deviceIn, int x, int y,
|
||||
const SkPaint& paint) SK_OVERRIDE {
|
||||
// deviceIn is the one that is being "restored" back to its parent
|
||||
GrGatherDevice* device = static_cast<GrGatherDevice*>(deviceIn);
|
||||
|
||||
if (device->fAlreadyDrawn) {
|
||||
if (NULL == pict->fRecord.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
device->fInfo.fRestoreOpID = fPlayback->curOpID();
|
||||
device->fInfo.fCTM = *draw.fMatrix;
|
||||
device->fInfo.fCTM.postTranslate(SkIntToScalar(-device->getOrigin().fX),
|
||||
SkIntToScalar(-device->getOrigin().fY));
|
||||
|
||||
device->fInfo.fOffset = device->getOrigin();
|
||||
|
||||
if (NeedsDeepCopy(paint)) {
|
||||
// This NULL acts as a signal that the paint was uncopyable (for now)
|
||||
device->fInfo.fPaint = NULL;
|
||||
device->fInfo.fValid = false;
|
||||
} else {
|
||||
device->fInfo.fPaint = SkNEW_ARGS(SkPaint, (paint));
|
||||
for (fCurrentOp = 0; fCurrentOp < pict->fRecord->count(); ++fCurrentOp) {
|
||||
pict->fRecord->visit<void>(fCurrentOp, *this);
|
||||
}
|
||||
|
||||
fAccelData->addSaveLayerInfo(device->fInfo);
|
||||
device->fAlreadyDrawn = true;
|
||||
}
|
||||
// TODO: allow this call to return failure, or move to SkBitmapDevice only.
|
||||
virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
|
||||
return fEmptyBitmap;
|
||||
}
|
||||
#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
|
||||
virtual bool onReadPixels(const SkBitmap& bitmap,
|
||||
int x, int y,
|
||||
SkCanvas::Config8888 config8888) SK_OVERRIDE {
|
||||
NotSupported();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
virtual void lockPixels() SK_OVERRIDE { NothingToDo(); }
|
||||
virtual void unlockPixels() SK_OVERRIDE { NothingToDo(); }
|
||||
virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
|
||||
virtual bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
|
||||
virtual bool filterImage(const SkImageFilter*, const SkBitmap&, const SkImageFilter::Context&,
|
||||
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
// The playback object driving this rendering
|
||||
SkPicturePlayback *fPlayback;
|
||||
|
||||
SkBitmap fEmptyBitmap; // legacy -- need to remove
|
||||
|
||||
// All information gathered during the gather process is stored here
|
||||
GrAccelData* fAccelData;
|
||||
|
||||
// true if this device has already been drawn back to its parent(s) at least
|
||||
// once.
|
||||
bool fAlreadyDrawn;
|
||||
|
||||
// The information regarding the saveLayer call this device represents.
|
||||
GrAccelData::SaveLayerInfo fInfo;
|
||||
|
||||
// The depth of this device in the saveLayer stack
|
||||
int fSaveLayerDepth;
|
||||
|
||||
virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
|
||||
NotSupported();
|
||||
}
|
||||
|
||||
virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) SK_OVERRIDE {
|
||||
// we expect to only get called via savelayer, in which case it is fine.
|
||||
SkASSERT(kSaveLayer_Usage == usage);
|
||||
|
||||
fInfo.fHasNestedLayers = true;
|
||||
return SkNEW_ARGS(GrGatherDevice, (info.width(), info.height(), fPlayback,
|
||||
fAccelData, fSaveLayerDepth+1));
|
||||
}
|
||||
|
||||
virtual void flush() SK_OVERRIDE {}
|
||||
|
||||
static void NotSupported() {
|
||||
SkDEBUGFAIL("this method should never be called");
|
||||
}
|
||||
|
||||
static void NothingToDo() {}
|
||||
|
||||
typedef SkBaseDevice INHERITED;
|
||||
};
|
||||
|
||||
// The GrGatherCanvas allows saveLayers but simplifies clipping. It is really
|
||||
// only intended to be used as:
|
||||
//
|
||||
// GrGatherDevice dev(w, h, picture, accelData);
|
||||
// GrGatherCanvas canvas(..., picture);
|
||||
// canvas.gather();
|
||||
//
|
||||
// which is all just to fill in 'accelData'
|
||||
class SK_API GrGatherCanvas : public SkCanvas {
|
||||
public:
|
||||
GrGatherCanvas(GrGatherDevice* device) : INHERITED(device) {}
|
||||
|
||||
protected:
|
||||
// disable aa for speed
|
||||
virtual void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
|
||||
this->INHERITED::onClipRect(rect, op, kHard_ClipEdgeStyle);
|
||||
}
|
||||
|
||||
// for speed, just respect the bounds, and disable AA. May give us a few
|
||||
// false positives and negatives.
|
||||
virtual void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
|
||||
this->updateClipConservativelyUsingBounds(path.getBounds(), op,
|
||||
path.isInverseFillType());
|
||||
}
|
||||
virtual void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
|
||||
this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
|
||||
}
|
||||
|
||||
virtual void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
|
||||
const SkPaint* paint) SK_OVERRIDE {
|
||||
SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->width(), picture->height());
|
||||
|
||||
if (NULL != picture->fData.get()) {
|
||||
// Disable the BBH for the old path so all the draw calls
|
||||
// will be seen. The stock SkPicture::draw method can't be
|
||||
// invoked since it just uses a vanilla SkPicturePlayback.
|
||||
SkPicturePlayback playback(picture);
|
||||
playback.setUseBBH(false);
|
||||
playback.draw(this, NULL);
|
||||
} else {
|
||||
// Since we know this is the SkRecord path we can just call
|
||||
// SkPicture::draw.
|
||||
picture->draw(this);
|
||||
while (!fSaveStack.isEmpty()) {
|
||||
this->popSaveBlock();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> void operator()(const T& op) {
|
||||
this->updateCTM(op);
|
||||
this->updateClipBounds(op);
|
||||
this->trackSaveLayers(op);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef SkCanvas INHERITED;
|
||||
|
||||
class SaveInfo {
|
||||
public:
|
||||
SaveInfo() { }
|
||||
SaveInfo(int opIndex, bool isSaveLayer, const SkPaint* paint, const SkIRect& bounds)
|
||||
: fStartIndex(opIndex)
|
||||
, fIsSaveLayer(isSaveLayer)
|
||||
, fHasNestedSaveLayer(false)
|
||||
, fPaint(paint)
|
||||
, fBounds(bounds) {
|
||||
|
||||
}
|
||||
|
||||
int fStartIndex;
|
||||
bool fIsSaveLayer;
|
||||
bool fHasNestedSaveLayer;
|
||||
const SkPaint* fPaint;
|
||||
SkIRect fBounds;
|
||||
};
|
||||
|
||||
uint32_t fPictureID;
|
||||
unsigned int fCurrentOp;
|
||||
const SkMatrix* fCTM;
|
||||
SkIRect fCurrentClipBounds;
|
||||
int fSaveLayersInStack;
|
||||
SkTDArray<SaveInfo> fSaveStack;
|
||||
GrAccelData* fAccelData;
|
||||
|
||||
template <typename T> void updateCTM(const T&) { /* most ops don't change the CTM */ }
|
||||
void updateCTM(const SkRecords::Restore& op) { fCTM = &op.matrix; }
|
||||
void updateCTM(const SkRecords::SetMatrix& op) { fCTM = &op.matrix; }
|
||||
|
||||
template <typename T> void updateClipBounds(const T&) { /* most ops don't change the clip */ }
|
||||
// Each of these devBounds fields is the state of the device bounds after the op.
|
||||
// So Restore's devBounds are those bounds saved by its paired Save or SaveLayer.
|
||||
void updateClipBounds(const SkRecords::Restore& op) { fCurrentClipBounds = op.devBounds; }
|
||||
void updateClipBounds(const SkRecords::ClipPath& op) { fCurrentClipBounds = op.devBounds; }
|
||||
void updateClipBounds(const SkRecords::ClipRRect& op) { fCurrentClipBounds = op.devBounds; }
|
||||
void updateClipBounds(const SkRecords::ClipRect& op) { fCurrentClipBounds = op.devBounds; }
|
||||
void updateClipBounds(const SkRecords::ClipRegion& op) { fCurrentClipBounds = op.devBounds; }
|
||||
void updateClipBounds(const SkRecords::SaveLayer& op) {
|
||||
if (NULL != op.bounds) {
|
||||
fCurrentClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> void trackSaveLayers(const T& op) {
|
||||
/* most ops aren't involved in saveLayers */
|
||||
}
|
||||
void trackSaveLayers(const SkRecords::Save& s) { this->pushSaveBlock(); }
|
||||
void trackSaveLayers(const SkRecords::SaveLayer& sl) { this->pushSaveLayerBlock(sl.paint); }
|
||||
void trackSaveLayers(const SkRecords::Restore& r) { this->popSaveBlock(); }
|
||||
void trackSaveLayers(const SkRecords::DrawPicture& dp) {
|
||||
// For sub-pictures, we wrap their layer information within the parent
|
||||
// picture's rendering hierarchy
|
||||
const GrAccelData* childData = GPUOptimize(dp.picture);
|
||||
|
||||
for (int i = 0; i < childData->numSaveLayers(); ++i) {
|
||||
const GrAccelData::SaveLayerInfo& src = childData->saveLayerInfo(i);
|
||||
|
||||
this->updateStackForSaveLayer();
|
||||
|
||||
GrAccelData::SaveLayerInfo dst;
|
||||
|
||||
// TODO: need to store an SkRect in GrAccelData::SaveLayerInfo?
|
||||
SkRect srcRect = SkRect::MakeXYWH(SkIntToScalar(src.fOffset.fX),
|
||||
SkIntToScalar(src.fOffset.fY),
|
||||
SkIntToScalar(src.fSize.width()),
|
||||
SkIntToScalar(src.fSize.height()));
|
||||
SkIRect newClip(fCurrentClipBounds);
|
||||
newClip.intersect(this->adjustAndMap(srcRect, dp.paint));
|
||||
|
||||
dst.fValid = true;
|
||||
dst.fPictureID = dp.picture->uniqueID();
|
||||
dst.fSize = SkISize::Make(newClip.width(), newClip.height());
|
||||
dst.fOffset = SkIPoint::Make(newClip.fLeft, newClip.fTop);
|
||||
dst.fOriginXform = *fCTM;
|
||||
dst.fOriginXform.postConcat(src.fOriginXform);
|
||||
dst.fOriginXform.postTranslate(SkIntToScalar(-newClip.fLeft),
|
||||
SkIntToScalar(-newClip.fTop));
|
||||
|
||||
if (NULL == src.fPaint) {
|
||||
dst.fPaint = NULL;
|
||||
} else {
|
||||
dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint));
|
||||
}
|
||||
|
||||
dst.fSaveLayerOpID = src.fSaveLayerOpID;
|
||||
dst.fRestoreOpID = src.fRestoreOpID;
|
||||
dst.fHasNestedLayers = src.fHasNestedLayers;
|
||||
dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested;
|
||||
|
||||
fAccelData->addSaveLayerInfo(dst);
|
||||
}
|
||||
}
|
||||
|
||||
void pushSaveBlock() {
|
||||
fSaveStack.push(SaveInfo(fCurrentOp, false, NULL, SkIRect::MakeEmpty()));
|
||||
}
|
||||
|
||||
// Inform all the saveLayers already on the stack that they now have a
|
||||
// nested saveLayer inside them
|
||||
void updateStackForSaveLayer() {
|
||||
for (int index = fSaveStack.count() - 1; index >= 0; --index) {
|
||||
if (fSaveStack[index].fHasNestedSaveLayer) {
|
||||
break;
|
||||
}
|
||||
fSaveStack[index].fHasNestedSaveLayer = true;
|
||||
if (fSaveStack[index].fIsSaveLayer) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pushSaveLayerBlock(const SkPaint* paint) {
|
||||
this->updateStackForSaveLayer();
|
||||
|
||||
fSaveStack.push(SaveInfo(fCurrentOp, true, paint, fCurrentClipBounds));
|
||||
++fSaveLayersInStack;
|
||||
}
|
||||
|
||||
void popSaveBlock() {
|
||||
if (fSaveStack.count() <= 0) {
|
||||
SkASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
SaveInfo si;
|
||||
fSaveStack.pop(&si);
|
||||
|
||||
if (!si.fIsSaveLayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
--fSaveLayersInStack;
|
||||
|
||||
GrAccelData::SaveLayerInfo slInfo;
|
||||
|
||||
slInfo.fValid = true;
|
||||
slInfo.fPictureID = fPictureID;
|
||||
slInfo.fSize = SkISize::Make(si.fBounds.width(), si.fBounds.height());
|
||||
slInfo.fOffset = SkIPoint::Make(si.fBounds.fLeft, si.fBounds.fTop);
|
||||
slInfo.fOriginXform = *fCTM;
|
||||
slInfo.fOriginXform.postTranslate(SkIntToScalar(-si.fBounds.fLeft),
|
||||
SkIntToScalar(-si.fBounds.fTop));
|
||||
|
||||
if (NULL == si.fPaint) {
|
||||
slInfo.fPaint = NULL;
|
||||
} else {
|
||||
slInfo.fPaint = SkNEW_ARGS(SkPaint, (*si.fPaint));
|
||||
}
|
||||
|
||||
slInfo.fSaveLayerOpID = si.fStartIndex;
|
||||
slInfo.fRestoreOpID = fCurrentOp;
|
||||
slInfo.fHasNestedLayers = si.fHasNestedSaveLayer;
|
||||
slInfo.fIsNested = fSaveLayersInStack > 0;
|
||||
|
||||
fAccelData->addSaveLayerInfo(slInfo);
|
||||
}
|
||||
|
||||
// Returns true if rect was meaningfully adjusted for the effects of paint,
|
||||
// false if the paint could affect the rect in unknown ways.
|
||||
static bool AdjustForPaint(const SkPaint* paint, SkRect* rect) {
|
||||
if (paint) {
|
||||
if (paint->canComputeFastBounds()) {
|
||||
*rect = paint->computeFastBounds(*rect, rect);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Adjust rect for all paints that may affect its geometry, then map it to device space.
|
||||
SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) const {
|
||||
// Inverted rectangles really confuse our BBHs.
|
||||
rect.sort();
|
||||
|
||||
// Adjust the rect for its own paint.
|
||||
if (!AdjustForPaint(paint, &rect)) {
|
||||
// The paint could do anything to our bounds. The only safe answer is the current clip.
|
||||
return fCurrentClipBounds;
|
||||
}
|
||||
|
||||
// Adjust rect for all the paints from the SaveLayers we're inside.
|
||||
for (int i = fSaveStack.count() - 1; i >= 0; i--) {
|
||||
if (!AdjustForPaint(fSaveStack[i].fPaint, &rect)) {
|
||||
// Same deal as above.
|
||||
return fCurrentClipBounds;
|
||||
}
|
||||
}
|
||||
|
||||
// Map the rect back to device space.
|
||||
fCTM->mapRect(&rect);
|
||||
SkIRect devRect;
|
||||
rect.roundOut(&devRect);
|
||||
|
||||
// Nothing can draw outside the current clip.
|
||||
// (Only bounded ops call into this method, so oddballs like Clear don't matter here.)
|
||||
devRect.intersect(fCurrentClipBounds);
|
||||
return devRect;
|
||||
}
|
||||
};
|
||||
|
||||
// GatherGPUInfo is only intended to be called within the context of SkGpuDevice's
|
||||
|
||||
// GPUOptimize is only intended to be called within the context of SkGpuDevice's
|
||||
// EXPERIMENTAL_optimize method.
|
||||
void GatherGPUInfo(const SkPicture* pict, GrAccelData* accelData) {
|
||||
const GrAccelData* GPUOptimize(const SkPicture* pict) {
|
||||
if (NULL == pict || 0 == pict->width() || 0 == pict->height()) {
|
||||
return ;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// BBH-based rendering doesn't re-issue many of the operations the gather
|
||||
// process cares about (e.g., saves and restores) so it must be disabled.
|
||||
SkPicturePlayback playback(pict);
|
||||
playback.setUseBBH(false);
|
||||
SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
|
||||
|
||||
GrGatherDevice device(pict->width(), pict->height(), &playback, accelData, 0);
|
||||
GrGatherCanvas canvas(&device);
|
||||
const GrAccelData* existing =
|
||||
static_cast<const GrAccelData*>(pict->EXPERIMENTAL_getAccelData(key));
|
||||
if (NULL != existing) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
canvas.clipRect(SkRect::MakeWH(SkIntToScalar(pict->width()),
|
||||
SkIntToScalar(pict->height())),
|
||||
SkRegion::kIntersect_Op, false);
|
||||
playback.draw(&canvas, NULL);
|
||||
SkAutoTUnref<GrAccelData> data(SkNEW_ARGS(GrAccelData, (key)));
|
||||
|
||||
pict->EXPERIMENTAL_addAccelData(data);
|
||||
|
||||
CollectLayers collector(pict, data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -21,11 +21,14 @@ public:
|
||||
// invalid (due to a non-invertible CTM) or 'fPaint' is NULL (due
|
||||
// to a non-copyable paint).
|
||||
bool fValid;
|
||||
// ID of the picture containing the layer. This can be the ID of
|
||||
// a sub-picture embedded within the picture owning the GrAccelData
|
||||
uint32_t fPictureID;
|
||||
// The size of the saveLayer
|
||||
SkISize fSize;
|
||||
// The CTM in which this layer's draws must occur. It already incorporates
|
||||
// The matrix state in which this layer's draws must occur. It already incorporates
|
||||
// the translation needed to map the layer's top-left point to the origin.
|
||||
SkMatrix fCTM;
|
||||
SkMatrix fOriginXform;
|
||||
// The offset that needs to be passed to drawBitmap to correctly
|
||||
// position the pre-rendered layer. It is in device space.
|
||||
SkIPoint fOffset;
|
||||
@ -74,6 +77,6 @@ private:
|
||||
typedef SkPicture::AccelData INHERITED;
|
||||
};
|
||||
|
||||
void GatherGPUInfo(const SkPicture* pict, GrAccelData* accelData);
|
||||
const GrAccelData* GPUOptimize(const SkPicture* pict);
|
||||
|
||||
#endif // GrPictureUtils_DEFINED
|
||||
|
@ -1861,11 +1861,7 @@ void SkGpuDevice::EXPERIMENTAL_optimize(const SkPicture* picture) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkAutoTUnref<GrAccelData> data(SkNEW_ARGS(GrAccelData, (key)));
|
||||
|
||||
picture->EXPERIMENTAL_addAccelData(data);
|
||||
|
||||
GatherGPUInfo(picture, data);
|
||||
GPUOptimize(picture);
|
||||
|
||||
fContext->getLayerCache()->trackPicture(picture);
|
||||
}
|
||||
@ -2004,10 +2000,10 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
|
||||
if (pullForward[i]) {
|
||||
const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
|
||||
|
||||
GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture->uniqueID(),
|
||||
info.fSaveLayerOpID,
|
||||
info.fRestoreOpID,
|
||||
info.fCTM);
|
||||
GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture->uniqueID(),
|
||||
info.fSaveLayerOpID,
|
||||
info.fRestoreOpID,
|
||||
info.fOriginXform);
|
||||
|
||||
SkPictureReplacementPlayback::PlaybackReplacements::ReplacementInfo* layerInfo =
|
||||
replacements.push();
|
||||
@ -2165,7 +2161,7 @@ void SkGpuDevice::unlockLayers(const SkPicture* picture) {
|
||||
GrCachedLayer* layer = fContext->getLayerCache()->findLayer(picture->uniqueID(),
|
||||
info.fSaveLayerOpID,
|
||||
info.fRestoreOpID,
|
||||
info.fCTM);
|
||||
info.fOriginXform);
|
||||
fContext->getLayerCache()->unlock(layer);
|
||||
}
|
||||
|
||||
|
@ -876,7 +876,18 @@ static void test_gpu_picture_optimization(skiatest::Reporter* reporter,
|
||||
static const int kWidth = 100;
|
||||
static const int kHeight = 100;
|
||||
|
||||
SkAutoTUnref<SkPicture> pict;
|
||||
SkAutoTUnref<SkPicture> pict, child;
|
||||
|
||||
{
|
||||
SkPictureRecorder recorder;
|
||||
|
||||
SkCanvas* c = recorder.beginRecording(kWidth, kHeight);
|
||||
|
||||
c->saveLayer(NULL, NULL);
|
||||
c->restore();
|
||||
|
||||
child.reset(recorder.endRecording());
|
||||
}
|
||||
|
||||
// create a picture with the structure:
|
||||
// 1)
|
||||
@ -892,21 +903,26 @@ static void test_gpu_picture_optimization(skiatest::Reporter* reporter,
|
||||
// SaveLayer w/ copyable paint
|
||||
// Restore
|
||||
// 4)
|
||||
// SaveLayer w/ non-copyable paint
|
||||
// SaveLayer
|
||||
// DrawPicture (which has a SaveLayer/Restore pair)
|
||||
// Restore
|
||||
// 5)
|
||||
// SaveLayer
|
||||
// DrawPicture with Matrix & Paint (with SaveLayer/Restore pair)
|
||||
// Restore
|
||||
{
|
||||
SkPictureRecorder recorder;
|
||||
|
||||
SkCanvas* c = recorder.DEPRECATED_beginRecording(kWidth, kHeight);
|
||||
SkCanvas* c = recorder.beginRecording(kWidth, kHeight);
|
||||
// 1)
|
||||
c->saveLayer(NULL, NULL);
|
||||
c->saveLayer(NULL, NULL); // layer #0
|
||||
c->restore();
|
||||
|
||||
// 2)
|
||||
c->saveLayer(NULL, NULL);
|
||||
c->translate(kWidth/2, kHeight/2);
|
||||
c->saveLayer(NULL, NULL); // layer #1
|
||||
c->translate(kWidth/2.0f, kHeight/2.0f);
|
||||
SkRect r = SkRect::MakeXYWH(0, 0, kWidth/2, kHeight/2);
|
||||
c->saveLayer(&r, NULL);
|
||||
c->saveLayer(&r, NULL); // layer #2
|
||||
c->restore();
|
||||
c->restore();
|
||||
|
||||
@ -914,16 +930,23 @@ static void test_gpu_picture_optimization(skiatest::Reporter* reporter,
|
||||
{
|
||||
SkPaint p;
|
||||
p.setColor(SK_ColorRED);
|
||||
c->saveLayer(NULL, &p);
|
||||
c->saveLayer(NULL, &p); // layer #3
|
||||
c->restore();
|
||||
}
|
||||
// 4)
|
||||
// TODO: this case will need to be removed once the paint's are immutable
|
||||
{
|
||||
c->saveLayer(NULL, NULL); // layer #4
|
||||
c->drawPicture(child); // layer #5 inside picture
|
||||
c->restore();
|
||||
}
|
||||
// 5
|
||||
{
|
||||
SkPaint p;
|
||||
SkAutoTUnref<SkColorFilter> cf(SkLumaColorFilter::Create());
|
||||
p.setImageFilter(SkColorFilterImageFilter::Create(cf.get()))->unref();
|
||||
c->saveLayer(NULL, &p);
|
||||
SkMatrix trans;
|
||||
trans.setTranslate(10, 10);
|
||||
|
||||
c->saveLayer(NULL, NULL); // layer #6
|
||||
c->drawPicture(child, &trans, &p); // layer #7 inside picture
|
||||
c->restore();
|
||||
}
|
||||
|
||||
@ -946,53 +969,98 @@ static void test_gpu_picture_optimization(skiatest::Reporter* reporter,
|
||||
REPORTER_ASSERT(reporter, NULL != data);
|
||||
|
||||
const GrAccelData *gpuData = static_cast<const GrAccelData*>(data);
|
||||
REPORTER_ASSERT(reporter, 5 == gpuData->numSaveLayers());
|
||||
REPORTER_ASSERT(reporter, 8 == gpuData->numSaveLayers());
|
||||
|
||||
const GrAccelData::SaveLayerInfo& info0 = gpuData->saveLayerInfo(0);
|
||||
// The parent/child layer appear in reverse order
|
||||
// The parent/child layers appear in reverse order
|
||||
const GrAccelData::SaveLayerInfo& info1 = gpuData->saveLayerInfo(2);
|
||||
const GrAccelData::SaveLayerInfo& info2 = gpuData->saveLayerInfo(1);
|
||||
|
||||
const GrAccelData::SaveLayerInfo& info3 = gpuData->saveLayerInfo(3);
|
||||
// const GrAccelData::SaveLayerInfo& info4 = gpuData->saveLayerInfo(4);
|
||||
|
||||
// The parent/child layers appear in reverse order
|
||||
const GrAccelData::SaveLayerInfo& info4 = gpuData->saveLayerInfo(5);
|
||||
const GrAccelData::SaveLayerInfo& info5 = gpuData->saveLayerInfo(4);
|
||||
|
||||
// The parent/child layers appear in reverse order
|
||||
const GrAccelData::SaveLayerInfo& info6 = gpuData->saveLayerInfo(7);
|
||||
const GrAccelData::SaveLayerInfo& info7 = gpuData->saveLayerInfo(6);
|
||||
|
||||
REPORTER_ASSERT(reporter, info0.fValid);
|
||||
REPORTER_ASSERT(reporter, kWidth == info0.fSize.fWidth && kHeight == info0.fSize.fHeight);
|
||||
REPORTER_ASSERT(reporter, info0.fCTM.isIdentity());
|
||||
REPORTER_ASSERT(reporter, pict->uniqueID() == info0.fPictureID);
|
||||
REPORTER_ASSERT(reporter, kWidth == info0.fSize.fWidth &&
|
||||
kHeight == info0.fSize.fHeight);
|
||||
REPORTER_ASSERT(reporter, info0.fOriginXform.isIdentity());
|
||||
REPORTER_ASSERT(reporter, 0 == info0.fOffset.fX && 0 == info0.fOffset.fY);
|
||||
REPORTER_ASSERT(reporter, NULL != info0.fPaint);
|
||||
REPORTER_ASSERT(reporter, NULL == info0.fPaint);
|
||||
REPORTER_ASSERT(reporter, !info0.fIsNested && !info0.fHasNestedLayers);
|
||||
|
||||
REPORTER_ASSERT(reporter, info1.fValid);
|
||||
REPORTER_ASSERT(reporter, kWidth == info1.fSize.fWidth && kHeight == info1.fSize.fHeight);
|
||||
REPORTER_ASSERT(reporter, info1.fCTM.isIdentity());
|
||||
REPORTER_ASSERT(reporter, pict->uniqueID() == info1.fPictureID);
|
||||
REPORTER_ASSERT(reporter, kWidth == info1.fSize.fWidth &&
|
||||
kHeight == info1.fSize.fHeight);
|
||||
REPORTER_ASSERT(reporter, info1.fOriginXform.isIdentity());
|
||||
REPORTER_ASSERT(reporter, 0 == info1.fOffset.fX && 0 == info1.fOffset.fY);
|
||||
REPORTER_ASSERT(reporter, NULL != info1.fPaint);
|
||||
REPORTER_ASSERT(reporter, !info1.fIsNested && info1.fHasNestedLayers); // has a nested SL
|
||||
REPORTER_ASSERT(reporter, NULL == info1.fPaint);
|
||||
REPORTER_ASSERT(reporter, !info1.fIsNested &&
|
||||
info1.fHasNestedLayers); // has a nested SL
|
||||
|
||||
REPORTER_ASSERT(reporter, info2.fValid);
|
||||
REPORTER_ASSERT(reporter, kWidth/2 == info2.fSize.fWidth &&
|
||||
REPORTER_ASSERT(reporter, pict->uniqueID() == info2.fPictureID);
|
||||
REPORTER_ASSERT(reporter, kWidth / 2 == info2.fSize.fWidth &&
|
||||
kHeight/2 == info2.fSize.fHeight); // bound reduces size
|
||||
REPORTER_ASSERT(reporter, info2.fCTM.isIdentity()); // translated
|
||||
REPORTER_ASSERT(reporter, kWidth/2 == info2.fOffset.fX &&
|
||||
kHeight/2 == info2.fOffset.fY);
|
||||
REPORTER_ASSERT(reporter, NULL != info1.fPaint);
|
||||
REPORTER_ASSERT(reporter, info2.fOriginXform.isIdentity());
|
||||
REPORTER_ASSERT(reporter, kWidth/2 == info2.fOffset.fX && // translated
|
||||
kHeight/2 == info2.fOffset.fY);
|
||||
REPORTER_ASSERT(reporter, NULL == info1.fPaint);
|
||||
REPORTER_ASSERT(reporter, info2.fIsNested && !info2.fHasNestedLayers); // is nested
|
||||
|
||||
REPORTER_ASSERT(reporter, info3.fValid);
|
||||
REPORTER_ASSERT(reporter, kWidth == info3.fSize.fWidth && kHeight == info3.fSize.fHeight);
|
||||
REPORTER_ASSERT(reporter, info3.fCTM.isIdentity());
|
||||
REPORTER_ASSERT(reporter, pict->uniqueID() == info3.fPictureID);
|
||||
REPORTER_ASSERT(reporter, kWidth == info3.fSize.fWidth &&
|
||||
kHeight == info3.fSize.fHeight);
|
||||
REPORTER_ASSERT(reporter, info3.fOriginXform.isIdentity());
|
||||
REPORTER_ASSERT(reporter, 0 == info3.fOffset.fX && 0 == info3.fOffset.fY);
|
||||
REPORTER_ASSERT(reporter, NULL != info3.fPaint);
|
||||
REPORTER_ASSERT(reporter, !info3.fIsNested && !info3.fHasNestedLayers);
|
||||
|
||||
#if 0 // needs more though for GrGatherCanvas
|
||||
REPORTER_ASSERT(reporter, !info4.fValid); // paint is/was uncopyable
|
||||
REPORTER_ASSERT(reporter, kWidth == info4.fSize.fWidth && kHeight == info4.fSize.fHeight);
|
||||
REPORTER_ASSERT(reporter, info4.fValid);
|
||||
REPORTER_ASSERT(reporter, pict->uniqueID() == info4.fPictureID);
|
||||
REPORTER_ASSERT(reporter, kWidth == info4.fSize.fWidth &&
|
||||
kHeight == info4.fSize.fHeight);
|
||||
REPORTER_ASSERT(reporter, 0 == info4.fOffset.fX && 0 == info4.fOffset.fY);
|
||||
REPORTER_ASSERT(reporter, info4.fCTM.isIdentity());
|
||||
REPORTER_ASSERT(reporter, NULL == info4.fPaint); // paint is/was uncopyable
|
||||
REPORTER_ASSERT(reporter, !info4.fIsNested && !info4.fHasNestedLayers);
|
||||
#endif
|
||||
REPORTER_ASSERT(reporter, info4.fOriginXform.isIdentity());
|
||||
REPORTER_ASSERT(reporter, NULL == info4.fPaint);
|
||||
REPORTER_ASSERT(reporter, !info4.fIsNested &&
|
||||
info4.fHasNestedLayers); // has a nested SL
|
||||
|
||||
REPORTER_ASSERT(reporter, info5.fValid);
|
||||
REPORTER_ASSERT(reporter, child->uniqueID() == info5.fPictureID); // in a child picture
|
||||
REPORTER_ASSERT(reporter, kWidth == info5.fSize.fWidth &&
|
||||
kHeight == info5.fSize.fHeight);
|
||||
REPORTER_ASSERT(reporter, 0 == info5.fOffset.fX && 0 == info5.fOffset.fY);
|
||||
REPORTER_ASSERT(reporter, info5.fOriginXform.isIdentity());
|
||||
REPORTER_ASSERT(reporter, NULL == info5.fPaint);
|
||||
REPORTER_ASSERT(reporter, info5.fIsNested && !info5.fHasNestedLayers); // is nested
|
||||
|
||||
REPORTER_ASSERT(reporter, info6.fValid);
|
||||
REPORTER_ASSERT(reporter, pict->uniqueID() == info6.fPictureID);
|
||||
REPORTER_ASSERT(reporter, kWidth == info6.fSize.fWidth &&
|
||||
kHeight == info6.fSize.fHeight);
|
||||
REPORTER_ASSERT(reporter, 0 == info6.fOffset.fX && 0 == info6.fOffset.fY);
|
||||
REPORTER_ASSERT(reporter, info6.fOriginXform.isIdentity());
|
||||
REPORTER_ASSERT(reporter, NULL == info6.fPaint);
|
||||
REPORTER_ASSERT(reporter, !info6.fIsNested &&
|
||||
info6.fHasNestedLayers); // has a nested SL
|
||||
|
||||
REPORTER_ASSERT(reporter, info7.fValid);
|
||||
REPORTER_ASSERT(reporter, child->uniqueID() == info7.fPictureID); // in a child picture
|
||||
REPORTER_ASSERT(reporter, kWidth == info7.fSize.fWidth &&
|
||||
kHeight == info7.fSize.fHeight);
|
||||
REPORTER_ASSERT(reporter, 0 == info7.fOffset.fX && 0 == info7.fOffset.fY);
|
||||
REPORTER_ASSERT(reporter, info7.fOriginXform.isIdentity());
|
||||
REPORTER_ASSERT(reporter, NULL == info7.fPaint);
|
||||
REPORTER_ASSERT(reporter, info7.fIsNested && !info7.fHasNestedLayers); // is nested
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user