Switch Layer Hoisting over to SkRecord backend

R=bsalomon@google.com
TBR=bsalomon@google.com

Author: robertphillips@google.com

Review URL: https://codereview.chromium.org/540543002
This commit is contained in:
robertphillips 2014-09-04 07:24:18 -07:00 committed by Commit bot
parent 5353bae113
commit 274b4ba6bd
9 changed files with 18 additions and 382 deletions

View File

@ -136,13 +136,9 @@
'<(skia_src_path)/core/SkPictureFlat.h',
'<(skia_src_path)/core/SkPicturePlayback.cpp',
'<(skia_src_path)/core/SkPicturePlayback.h',
'<(skia_src_path)/core/SkPictureRangePlayback.cpp',
'<(skia_src_path)/core/SkPictureRangePlayback.h',
'<(skia_src_path)/core/SkPictureRecord.cpp',
'<(skia_src_path)/core/SkPictureRecord.h',
'<(skia_src_path)/core/SkPictureRecorder.cpp',
'<(skia_src_path)/core/SkPictureReplacementPlayback.cpp',
'<(skia_src_path)/core/SkPictureReplacementPlayback.h',
'<(skia_src_path)/core/SkPictureShader.cpp',
'<(skia_src_path)/core/SkPictureShader.h',
'<(skia_src_path)/core/SkPictureStateTree.cpp',

View File

@ -286,6 +286,7 @@ private:
friend class SkPictureData; // to access OperationList
friend class SkPictureRecorder; // just for SkPicture-based constructor
friend class SkGpuDevice; // for fData access
friend class GrLayerHoister; // access to fRecord
friend class CollectLayers; // access to fRecord
friend class SkPicturePlayback; // to get fData & OperationList
friend class SkPictureReplacementPlayback; // to access OperationList

View File

@ -1,57 +0,0 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkCanvas.h"
#include "SkPictureData.h"
#include "SkPictureRangePlayback.h"
void SkPictureRangePlayback::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) {
AutoResetOpID aroi(this);
SkASSERT(0 == fCurOffset);
SkReader32 reader(fPictureData->opData()->bytes(), fPictureData->opData()->size());
if (0 != fStart || 0 != fStop) {
reader.setOffset(fStart);
uint32_t size;
SkDEBUGCODE(DrawType op = ) ReadOpAndSize(&reader, &size);
SkASSERT(SAVE_LAYER == op);
reader.setOffset(fStart + size);
}
// Record this, so we can concat w/ it if we encounter a setMatrix()
SkMatrix initialMatrix = canvas->getTotalMatrix();
SkAutoCanvasRestore acr(canvas, false);
while (!reader.eof()) {
if (NULL != callback && callback->abortDrawing()) {
return;
}
if (0 != fStart || 0 != fStop) {
size_t offset = reader.offset();
if (offset >= fStop) {
SkDEBUGCODE(uint32_t size;)
SkDEBUGCODE(DrawType op = ReadOpAndSize(&reader, &size);)
SkASSERT(RESTORE == op);
return;
}
}
fCurOffset = reader.offset();
uint32_t size;
DrawType op = ReadOpAndSize(&reader, &size);
if (NOOP == op) {
// NOOPs are to be ignored - do not propagate them any further
reader.setOffset(fCurOffset + size);
continue;
}
this->handleOp(&reader, op, size, canvas, initialMatrix);
}
}

View File

@ -1,41 +0,0 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPictureRangePlayback_DEFINED
#define SkPictureRangePlayback_DEFINED
#include "SkPicturePlayback.h"
// This version of picture playback plays all the operations between
// a pair of start and stop values.
// The opcode at 'start' should be a saveLayer while the opcode at
// 'stop' should be a restore. Neither of those commands will be issued.
// Since this class never uses the bounding box hierarchy, the base class'
// useBBH setting is ignored.
class SkPictureRangePlayback : public SkPicturePlayback {
public:
// Set both start & stop to 0 to disable draw limiting. Note that disabling
// draw limiting isn't the same as using the base SkPicturePlayback object
// since this class never uses the bounding box hierarchy information.
SkPictureRangePlayback(const SkPicture* picture, size_t start, size_t stop)
: INHERITED(picture)
, fStart(start)
, fStop(stop) {
}
virtual void draw(SkCanvas* canvas, SkDrawPictureCallback*) SK_OVERRIDE;
private:
size_t fStart;
size_t fStop;
typedef SkPicturePlayback INHERITED;
};
#endif

View File

@ -1,171 +0,0 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkCanvas.h"
#include "SkPicture.h"
#include "SkPictureData.h"
#include "SkPictureReplacementPlayback.h"
SkPictureReplacementPlayback::PlaybackReplacements::ReplacementInfo*
SkPictureReplacementPlayback::PlaybackReplacements::push() {
SkDEBUGCODE(this->validate());
return fReplacements.push();
}
void SkPictureReplacementPlayback::PlaybackReplacements::freeAll() {
for (int i = 0; i < fReplacements.count(); ++i) {
SkDELETE(fReplacements[i].fBM);
}
fReplacements.reset();
}
#ifdef SK_DEBUG
void SkPictureReplacementPlayback::PlaybackReplacements::validate() const {
// Check that the ranges are monotonically increasing and non-overlapping
if (fReplacements.count() > 0) {
SkASSERT(fReplacements[0].fStart < fReplacements[0].fStop);
for (int i = 1; i < fReplacements.count(); ++i) {
SkASSERT(fReplacements[i].fStart < fReplacements[i].fStop);
SkASSERT(fReplacements[i - 1].fStop < fReplacements[i].fStart);
}
}
}
#endif
// TODO: Replace with hash or pass in "lastLookedUp" hint
SkPictureReplacementPlayback::PlaybackReplacements::ReplacementInfo*
SkPictureReplacementPlayback::PlaybackReplacements::lookupByStart(size_t start) {
SkDEBUGCODE(this->validate());
for (int i = 0; i < fReplacements.count(); ++i) {
if (start == fReplacements[i].fStart) {
return &fReplacements[i];
} else if (start < fReplacements[i].fStart) {
return NULL; // the ranges are monotonically increasing and non-overlapping
}
}
return NULL;
}
bool SkPictureReplacementPlayback::replaceOps(SkPictureStateTree::Iterator* iter,
SkReader32* reader,
SkCanvas* canvas,
const SkMatrix& initialMatrix) {
if (NULL != fReplacements) {
// Potentially replace a block of operations with a single drawBitmap call
PlaybackReplacements::ReplacementInfo* temp =
fReplacements->lookupByStart(reader->offset());
if (NULL != temp) {
SkASSERT(NULL != temp->fBM);
SkASSERT(NULL != temp->fPaint);
canvas->save();
canvas->setMatrix(initialMatrix);
SkRect src = SkRect::Make(temp->fSrcRect);
SkRect dst = SkRect::MakeXYWH(temp->fPos.fX, temp->fPos.fY,
temp->fSrcRect.width(),
temp->fSrcRect.height());
canvas->drawBitmapRectToRect(*temp->fBM, &src, dst, temp->fPaint);
canvas->restore();
if (iter->isValid()) {
// This save is needed since the BBH will automatically issue
// a restore to balanced the saveLayer we're skipping
canvas->save();
// At this point we know that the PictureStateTree was aiming
// for some draw op within temp's saveLayer (although potentially
// in a separate saveLayer nested inside it).
// We need to skip all the operations inside temp's range
// along with all the associated state changes but update
// the state tree to the first operation outside temp's range.
uint32_t skipTo;
do {
skipTo = iter->nextDraw();
if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) {
break;
}
if (skipTo <= temp->fStop) {
reader->setOffset(skipTo);
uint32_t size;
DrawType op = ReadOpAndSize(reader, &size);
// Since we are relying on the normal SkPictureStateTree
// playback we need to convert any nested saveLayer calls
// it may issue into saves (so that all its internal
// restores will be balanced).
if (SAVE_LAYER == op) {
canvas->save();
}
}
} while (skipTo <= temp->fStop);
if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) {
reader->setOffset(reader->size()); // skip to end
return true;
}
reader->setOffset(skipTo);
} else {
reader->setOffset(temp->fStop);
uint32_t size;
SkDEBUGCODE(DrawType op = ) ReadOpAndSize(reader, &size);
SkASSERT(RESTORE == op);
}
return true;
}
}
return false;
}
void SkPictureReplacementPlayback::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) {
AutoResetOpID aroi(this);
SkASSERT(0 == fCurOffset);
SkPictureStateTree::Iterator it;
if (!this->initIterator(&it, canvas, fActiveOpsList)) {
return; // nothing to draw
}
SkReader32 reader(fPictureData->opData()->bytes(), fPictureData->opData()->size());
StepIterator(&it, &reader);
// Record this, so we can concat w/ it if we encounter a setMatrix()
SkMatrix initialMatrix = canvas->getTotalMatrix();
SkAutoCanvasRestore acr(canvas, false);
while (!reader.eof()) {
if (NULL != callback && callback->abortDrawing()) {
return;
}
if (this->replaceOps(&it, &reader, canvas, initialMatrix)) {
continue;
}
fCurOffset = reader.offset();
uint32_t size;
DrawType op = ReadOpAndSize(&reader, &size);
if (NOOP == op) {
// NOOPs are to be ignored - do not propagate them any further
SkipIterTo(&it, &reader, fCurOffset + size);
continue;
}
this->handleOp(&reader, op, size, canvas, initialMatrix);
StepIterator(&it, &reader);
}
}

View File

@ -1,86 +0,0 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPictureReplacementPlayback_DEFINED
#define SkPictureReplacementPlayback_DEFINED
#include "SkPicturePlayback.h"
// This playback class replaces complete "saveLayer ... restore" runs with a
// single drawBitmap call.
class SkPictureReplacementPlayback : public SkPicturePlayback {
public:
// PlaybackReplacements collects op ranges that can be replaced with
// a single drawBitmap call (using a precomputed bitmap).
class PlaybackReplacements {
public:
// All the operations between fStart and fStop (inclusive) will be replaced with
// a single drawBitmap call using fPos, fBM and fPaint.
// fPaint will be NULL if the picture's paint wasn't copyable
struct ReplacementInfo {
size_t fStart;
size_t fStop;
SkIPoint fPos;
SkBitmap* fBM; // fBM is allocated so ReplacementInfo can remain POD
const SkPaint* fPaint; // Note: this object doesn't own the paint
SkIRect fSrcRect;
};
~PlaybackReplacements() { this->freeAll(); }
// Add a new replacement range. The replacement ranges should be
// sorted in increasing order and non-overlapping (esp. no nested
// saveLayers).
ReplacementInfo* push();
// look up a replacement range by its start offset
ReplacementInfo* lookupByStart(size_t start);
private:
SkTDArray<ReplacementInfo> fReplacements;
void freeAll();
#ifdef SK_DEBUG
void validate() const;
#endif
};
// This class doesn't take ownership of either 'replacements' or 'activeOpsList'
// The caller must guarantee they exist across any calls to 'draw'.
// 'activeOpsList' can be NULL but in that case BBH acceleration will not
// be used ('replacements' can be NULL too but that defeats the purpose
// of using this class).
SkPictureReplacementPlayback(const SkPicture* picture,
PlaybackReplacements* replacements,
const SkPicture::OperationList* activeOpsList)
: INHERITED(picture)
, fReplacements(replacements)
, fActiveOpsList(activeOpsList) {
}
virtual void draw(SkCanvas* canvas, SkDrawPictureCallback*) SK_OVERRIDE;
private:
PlaybackReplacements* fReplacements;
const SkPicture::OperationList* fActiveOpsList;
// This method checks if the current op pointed at by 'iter' and 'reader'
// is within a replacement range. If so, it issues the drawBitmap call,
// updates 'iter' and 'reader' to be after the restore operation, and
// returns true. If the operation is not in a replacement range (and thus
// needs to be drawn normally) false is returned.
bool replaceOps(SkPictureStateTree::Iterator* iter,
SkReader32* reader,
SkCanvas* canvas,
const SkMatrix& initialMatrix);
typedef SkPicturePlayback INHERITED;
};
#endif

View File

@ -7,8 +7,8 @@
#include "GrLayerCache.h"
#include "GrLayerHoister.h"
#include "SkPictureRangePlayback.h"
#include "SkCanvas.h"
#include "SkRecordDraw.h"
#include "SkSurface.h"
// Return true if any layers are suitable for hoisting
@ -94,10 +94,8 @@ void GrLayerHoister::DrawLayers(const SkPicture* picture,
atlasCanvas->translate(bound.fLeft, bound.fTop);
atlasCanvas->concat(layer->ctm());
SkPictureRangePlayback rangePlayback(picture,
layer->start(),
layer->stop());
rangePlayback.draw(atlasCanvas, NULL);
SkRecordPartialDraw(*picture->fRecord.get(), atlasCanvas, bound,
layer->start(), layer->stop());
atlasCanvas->restore();
}
@ -111,9 +109,9 @@ void GrLayerHoister::DrawLayers(const SkPicture* picture,
// Each non-atlased layer has its own GrTexture
SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(
layer->texture()->asRenderTarget(),
SkSurface::kStandard_TextRenderMode,
SkSurface::kDontClear_RenderTargetFlag));
layer->texture()->asRenderTarget(),
SkSurface::kStandard_TextRenderMode,
SkSurface::kDontClear_RenderTargetFlag));
SkCanvas* layerCanvas = surface->getCanvas();
@ -130,10 +128,8 @@ void GrLayerHoister::DrawLayers(const SkPicture* picture,
layerCanvas->concat(layer->ctm());
SkPictureRangePlayback rangePlayback(picture,
layer->start(),
layer->stop());
rangePlayback.draw(layerCanvas, NULL);
SkRecordPartialDraw(*picture->fRecord.get(), layerCanvas, bound,
layer->start(), layer->stop());
layerCanvas->flush();
}

View File

@ -87,7 +87,7 @@ void GrRecordReplaceDraw(const SkRecord& record,
if (NULL != callback && callback->abortDrawing()) {
return;
}
ri = replacements->lookupByStart(i, &searchStart);
ri = replacements->lookupByStart((uintptr_t)ops[i], &searchStart);
if (NULL != ri) {
draw_replacement_bitmap(ri, canvas);

View File

@ -18,6 +18,7 @@
#include "GrLayerCache.h"
#include "GrLayerHoister.h"
#include "GrPictureUtils.h"
#include "GrRecordReplaceDraw.h"
#include "GrStrokeInfo.h"
#include "GrTracing.h"
@ -31,8 +32,7 @@
#include "SkPathEffect.h"
#include "SkPicture.h"
#include "SkPictureData.h"
#include "SkPictureRangePlayback.h"
#include "SkPictureReplacementPlayback.h"
#include "SkRecord.h"
#include "SkRRect.h"
#include "SkStroke.h"
#include "SkSurface.h"
@ -1875,7 +1875,7 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
return false;
}
SkPictureReplacementPlayback::PlaybackReplacements replacements;
GrReplacements replacements;
SkTDArray<GrCachedLayer*> atlased, nonAtlased;
atlased.setReserve(gpuData->numSaveLayers());
@ -1890,8 +1890,7 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
info.fRestoreOpID,
info.fOriginXform);
SkPictureReplacementPlayback::PlaybackReplacements::ReplacementInfo* layerInfo =
replacements.push();
GrReplacements::ReplacementInfo* layerInfo = replacements.push();
layerInfo->fStart = info.fSaveLayerOpID;
layerInfo->fStop = info.fRestoreOpID;
layerInfo->fPos = info.fOffset;
@ -1909,11 +1908,12 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
continue;
}
layerInfo->fBM = SkNEW(SkBitmap); // fBM is allocated so ReplacementInfo can be POD
SkBitmap bm;
wrap_texture(layer->texture(),
!layer->isAtlased() ? desc.fWidth : layer->texture()->width(),
!layer->isAtlased() ? desc.fHeight : layer->texture()->height(),
layerInfo->fBM);
&bm);
layerInfo->fImage = SkImage::NewTexture(bm);
SkASSERT(info.fPaint);
layerInfo->fPaint = info.fPaint;
@ -1936,9 +1936,7 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
GrLayerHoister::DrawLayers(picture, atlased, nonAtlased);
// Render the entire picture using new layers
SkPictureReplacementPlayback playback(picture, &replacements, NULL);
playback.draw(mainCanvas, NULL);
GrRecordReplaceDraw(*picture->fRecord, mainCanvas, picture->fBBH.get(), &replacements, NULL);
GrLayerHoister::UnlockLayers(fContext->getLayerCache(), picture);