aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrPictureUtils.cpp
diff options
context:
space:
mode:
authorGravatar robertphillips <robertphillips@google.com>2014-08-27 11:53:28 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-08-27 11:53:28 -0700
commitd62833079fc36e28e65692f9a0c7dbdb124519c6 (patch)
tree65fc99645bb92927f39d2e5f35a94c527e55b1ea /src/gpu/GrPictureUtils.cpp
parent9c3d24b9d1ba3d955094ff0cb1ba2d11e1c1adca (diff)
Switch GPU Optimization code to SkRecord
R=mtklein@google.com, bsalomon@google.com Author: robertphillips@google.com Review URL: https://codereview.chromium.org/504393002
Diffstat (limited to 'src/gpu/GrPictureUtils.cpp')
-rw-r--r--src/gpu/GrPictureUtils.cpp436
1 files changed, 217 insertions, 219 deletions
diff --git a/src/gpu/GrPictureUtils.cpp b/src/gpu/GrPictureUtils.cpp
index 7295089e82..521160ac8a 100644
--- a/src/gpu/GrPictureUtils.cpp
+++ b/src/gpu/GrPictureUtils.cpp
@@ -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)
-
- 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() { }
+ 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) {
+
+ if (NULL == pict->fRecord.get()) {
+ return;
+ }
- virtual SkImageInfo imageInfo() const SK_OVERRIDE {
- return fEmptyBitmap.info();
- }
+ for (fCurrentOp = 0; fCurrentOp < pict->fRecord->count(); ++fCurrentOp) {
+ pict->fRecord->visit<void>(fCurrentOp, *this);
+ }
-#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
- virtual void writePixels(const SkBitmap& bitmap, int x, int y,
- SkCanvas::Config8888 config8888) SK_OVERRIDE {
- NotSupported();
+ while (!fSaveStack.isEmpty()) {
+ this->popSaveBlock();
+ }
}
-#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 {
+ template <typename T> void operator()(const T& op) {
+ this->updateCTM(op);
+ this->updateClipBounds(op);
+ this->trackSaveLayers(op);
}
- 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) {
- return;
- }
+private:
- device->fInfo.fRestoreOpID = fPlayback->curOpID();
- device->fInfo.fCTM = *draw.fMatrix;
- device->fInfo.fCTM.postTranslate(SkIntToScalar(-device->getOrigin().fX),
- SkIntToScalar(-device->getOrigin().fY));
+ 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) {
- 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));
+ 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));
}
+ }
- fAccelData->addSaveLayerInfo(device->fInfo);
- device->fAlreadyDrawn = true;
+ template <typename T> void trackSaveLayers(const T& op) {
+ /* most ops aren't involved in saveLayers */
}
- // TODO: allow this call to return failure, or move to SkBitmapDevice only.
- virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
- return fEmptyBitmap;
+ 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);
+ }
}
-#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
- virtual bool onReadPixels(const SkBitmap& bitmap,
- int x, int y,
- SkCanvas::Config8888 config8888) SK_OVERRIDE {
- NotSupported();
- return false;
+
+ void pushSaveBlock() {
+ fSaveStack.push(SaveInfo(fCurrentOp, false, NULL, SkIRect::MakeEmpty()));
}
-#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;
+
+ // 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;
+ }
+ }
}
-private:
- // The playback object driving this rendering
- SkPicturePlayback *fPlayback;
+ void pushSaveLayerBlock(const SkPaint* paint) {
+ this->updateStackForSaveLayer();
- SkBitmap fEmptyBitmap; // legacy -- need to remove
+ fSaveStack.push(SaveInfo(fCurrentOp, true, paint, fCurrentClipBounds));
+ ++fSaveLayersInStack;
+ }
- // All information gathered during the gather process is stored here
- GrAccelData* fAccelData;
+ void popSaveBlock() {
+ if (fSaveStack.count() <= 0) {
+ SkASSERT(false);
+ return;
+ }
- // true if this device has already been drawn back to its parent(s) at least
- // once.
- bool fAlreadyDrawn;
+ SaveInfo si;
+ fSaveStack.pop(&si);
- // The information regarding the saveLayer call this device represents.
- GrAccelData::SaveLayerInfo fInfo;
+ if (!si.fIsSaveLayer) {
+ return;
+ }
- // The depth of this device in the saveLayer stack
- int fSaveLayerDepth;
+ --fSaveLayersInStack;
- virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
- NotSupported();
- }
+ GrAccelData::SaveLayerInfo slInfo;
- 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);
+ 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));
- fInfo.fHasNestedLayers = true;
- return SkNEW_ARGS(GrGatherDevice, (info.width(), info.height(), fPlayback,
- fAccelData, fSaveLayerDepth+1));
- }
+ if (NULL == si.fPaint) {
+ slInfo.fPaint = NULL;
+ } else {
+ slInfo.fPaint = SkNEW_ARGS(SkPaint, (*si.fPaint));
+ }
- virtual void flush() SK_OVERRIDE {}
+ slInfo.fSaveLayerOpID = si.fStartIndex;
+ slInfo.fRestoreOpID = fCurrentOp;
+ slInfo.fHasNestedLayers = si.fHasNestedSaveLayer;
+ slInfo.fIsNested = fSaveLayersInStack > 0;
- static void NotSupported() {
- SkDEBUGFAIL("this method should never be called");
+ fAccelData->addSaveLayerInfo(slInfo);
}
- static void NothingToDo() {}
+ // 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;
+ }
- typedef SkBaseDevice INHERITED;
-};
+ // 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();
-// 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) {}
+ // 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;
+ }
-protected:
- // disable aa for speed
- virtual void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
- this->INHERITED::onClipRect(rect, op, kHard_ClipEdgeStyle);
- }
+ // 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;
+ }
+ }
- // 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);
- }
+ // Map the rect back to device space.
+ fCTM->mapRect(&rect);
+ SkIRect devRect;
+ rect.roundOut(&devRect);
- 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);
- }
+ // 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;
}
-
-private:
- typedef SkCanvas INHERITED;
};
-// 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();
+
+ const GrAccelData* existing =
+ static_cast<const GrAccelData*>(pict->EXPERIMENTAL_getAccelData(key));
+ if (NULL != existing) {
+ return existing;
+ }
+
+ SkAutoTUnref<GrAccelData> data(SkNEW_ARGS(GrAccelData, (key)));
+
+ pict->EXPERIMENTAL_addAccelData(data);
- GrGatherDevice device(pict->width(), pict->height(), &playback, accelData, 0);
- GrGatherCanvas canvas(&device);
+ CollectLayers collector(pict, data);
- canvas.clipRect(SkRect::MakeWH(SkIntToScalar(pict->width()),
- SkIntToScalar(pict->height())),
- SkRegion::kIntersect_Op, false);
- playback.draw(&canvas, NULL);
+ return data;
}