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:
parent
5353bae113
commit
274b4ba6bd
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
@ -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();
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user