Collapse matrix & clip stack in PictureRecord

https://codereview.chromium.org/137093004/



git-svn-id: http://skia.googlecode.com/svn/trunk@13402 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
robertphillips@google.com 2014-02-11 15:10:40 +00:00
Родитель 93d5ffda58
Коммит 105a4a584c
6 изменённых файлов: 832 добавлений и 16 удалений

Просмотреть файл

@ -110,6 +110,8 @@
'<(skia_src_path)/core/SkMaskGamma.h', '<(skia_src_path)/core/SkMaskGamma.h',
'<(skia_src_path)/core/SkMath.cpp', '<(skia_src_path)/core/SkMath.cpp',
'<(skia_src_path)/core/SkMatrix.cpp', '<(skia_src_path)/core/SkMatrix.cpp',
'<(skia_src_path)/core/SkMatrixClipStateMgr.cpp',
'<(skia_src_path)/core/SkMatrixClipStateMgr.h',
'<(skia_src_path)/core/SkMessageBus.h', '<(skia_src_path)/core/SkMessageBus.h',
'<(skia_src_path)/core/SkMetaData.cpp', '<(skia_src_path)/core/SkMetaData.cpp',
'<(skia_src_path)/core/SkMipMap.cpp', '<(skia_src_path)/core/SkMipMap.cpp',

Просмотреть файл

@ -0,0 +1,257 @@
/*
* 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 "SkMatrixClipStateMgr.h"
#include "SkPictureRecord.h"
bool SkMatrixClipStateMgr::MatrixClipState::ClipInfo::clipPath(SkPictureRecord* picRecord,
const SkPath& path,
SkRegion::Op op,
bool doAA,
const SkMatrix& matrix) {
int pathID = picRecord->addPathToHeap(path);
ClipOp& newClip = fClips.push_back();
newClip.fClipType = kPath_ClipType;
newClip.fGeom.fPathID = pathID;
newClip.fOp = op;
newClip.fDoAA = doAA;
newClip.fMatrix = matrix;
newClip.fOffset = kInvalidJumpOffset;
return false;
}
bool SkMatrixClipStateMgr::MatrixClipState::ClipInfo::clipRegion(SkPictureRecord* picRecord,
const SkRegion& region,
SkRegion::Op op,
const SkMatrix& matrix) {
// TODO: add a region dictionary so we don't have to copy the region in here
ClipOp& newClip = fClips.push_back();
newClip.fClipType = kRegion_ClipType;
newClip.fGeom.fRegion = SkNEW(SkRegion(region));
newClip.fOp = op;
newClip.fDoAA = true; // not necessary but sanity preserving
newClip.fMatrix = matrix;
newClip.fOffset = kInvalidJumpOffset;
return false;
}
void SkMatrixClipStateMgr::WriteDeltaMat(SkPictureRecord* picRecord,
const SkMatrix& current,
const SkMatrix& desired) {
SkMatrix delta;
current.invert(&delta);
delta.preConcat(desired);
picRecord->recordConcat(delta);
}
// Note: this only writes out the clips for the current save state. To get the
// entire clip stack requires iterating of the entire matrix/clip stack.
void SkMatrixClipStateMgr::MatrixClipState::ClipInfo::writeClip(SkMatrix* curMat,
SkPictureRecord* picRecord,
bool* overrideFirstOp) {
for (int i = 0; i < fClips.count(); ++i) {
ClipOp& curClip = fClips[i];
SkRegion::Op op = curClip.fOp;
if (*overrideFirstOp) {
op = SkRegion::kReplace_Op;
*overrideFirstOp = false;
}
// TODO: re-add an internal matrix dictionary to not write out
// redundant matrices.
// TODO: right now we're writing out the delta matrix from the prior
// matrix state. This is a side-effect of writing out the entire
// clip stack and should be resolved when that is fixed.
SkMatrixClipStateMgr::WriteDeltaMat(picRecord, *curMat, curClip.fMatrix);
*curMat = curClip.fMatrix;
switch (curClip.fClipType) {
case kRect_ClipType:
curClip.fOffset = picRecord->recordClipRect(curClip.fGeom.fRRect.rect(),
op, curClip.fDoAA);
break;
case kRRect_ClipType:
curClip.fOffset = picRecord->recordClipRRect(curClip.fGeom.fRRect, op,
curClip.fDoAA);
break;
case kPath_ClipType:
curClip.fOffset = picRecord->recordClipPath(curClip.fGeom.fPathID, op,
curClip.fDoAA);
break;
case kRegion_ClipType:
curClip.fOffset = picRecord->recordClipRegion(*curClip.fGeom.fRegion, op);
break;
default:
SkASSERT(0);
}
}
}
// Fill in the skip offsets for all the clips written in the current block
void SkMatrixClipStateMgr::MatrixClipState::ClipInfo::fillInSkips(SkWriter32* writer,
int32_t restoreOffset) {
for (int i = 0; i < fClips.count(); ++i) {
ClipOp& curClip = fClips[i];
if (-1 == curClip.fOffset) {
continue;
}
SkDEBUGCODE(uint32_t peek = writer->read32At(curClip.fOffset);)
SkASSERT(-1 == peek);
writer->write32At(curClip.fOffset, restoreOffset);
SkDEBUGCODE(curClip.fOffset = -1;)
}
}
SkMatrixClipStateMgr::SkMatrixClipStateMgr()
: fPicRecord(NULL)
, fCurOpenStateID(kIdentityWideOpenStateID)
, fMatrixClipStack(sizeof(MatrixClipState),
fMatrixClipStackStorage,
sizeof(fMatrixClipStackStorage)) {
fCurMCState = (MatrixClipState*)fMatrixClipStack.push_back();
new (fCurMCState) MatrixClipState(NULL, 0); // balanced in restore()
}
int SkMatrixClipStateMgr::save(SkCanvas::SaveFlags flags) {
SkDEBUGCODE(this->validate();)
MatrixClipState* newTop = (MatrixClipState*)fMatrixClipStack.push_back();
new (newTop) MatrixClipState(fCurMCState, flags); // balanced in restore()
fCurMCState = newTop;
SkDEBUGCODE(this->validate();)
return fMatrixClipStack.count();
}
int SkMatrixClipStateMgr::saveLayer(const SkRect* bounds, const SkPaint* paint,
SkCanvas::SaveFlags flags) {
int result = this->save(flags);
++fCurMCState->fLayerID;
fCurMCState->fIsSaveLayer = true;
fCurMCState->fSaveLayerBracketed = this->call(kOther_CallType);
fCurMCState->fSaveLayerBaseStateID = fCurOpenStateID;
fPicRecord->recordSaveLayer(bounds, paint,
(SkCanvas::SaveFlags)(flags| SkCanvas::kMatrixClip_SaveFlag));
return result;
}
void SkMatrixClipStateMgr::restore() {
SkDEBUGCODE(this->validate();)
if (fCurMCState->fIsSaveLayer) {
if (fCurMCState->fSaveLayerBaseStateID != fCurOpenStateID) {
fPicRecord->recordRestore(); // Close the open block
}
// The saveLayer's don't carry any matrix or clip state in the
// new scheme so make sure the saveLayer's recordRestore doesn't
// try to finalize them (i.e., fill in their skip offsets).
fPicRecord->recordRestore(false); // close of saveLayer
// Close the Save that brackets the saveLayer. TODO: this doesn't handle
// the skip offsets correctly
if (fCurMCState->fSaveLayerBracketed) {
fPicRecord->recordRestore(false);
}
// MC states can be allowed to fuse across saveLayer/restore boundaries
fCurOpenStateID = kIdentityWideOpenStateID;
}
fCurMCState->~MatrixClipState(); // balanced in save()
fMatrixClipStack.pop_back();
fCurMCState = (MatrixClipState*)fMatrixClipStack.back();
SkDEBUGCODE(this->validate();)
}
// kIdentityWideOpenStateID (0) is reserved for the identity/wide-open clip state
int32_t SkMatrixClipStateMgr::NewMCStateID() {
// TODO: guard against wrap around
// TODO: make uint32_t
static int32_t gMCStateID = kIdentityWideOpenStateID;
++gMCStateID;
return gMCStateID;
}
bool SkMatrixClipStateMgr::call(CallType callType) {
SkDEBUGCODE(this->validate();)
if (kMatrix_CallType == callType || kClip_CallType == callType) {
fCurMCState->fMCStateID = NewMCStateID();
SkDEBUGCODE(this->validate();)
return false;
}
SkASSERT(kOther_CallType == callType);
if (fCurMCState->fMCStateID == fCurOpenStateID) {
// Required MC state is already active one - nothing to do
SkDEBUGCODE(this->validate();)
return false;
}
if (kIdentityWideOpenStateID != fCurOpenStateID) {
fPicRecord->recordRestore(); // Close the open block
}
// Install the required MC state as the active one
fCurOpenStateID = fCurMCState->fMCStateID;
fPicRecord->recordSave(SkCanvas::kMatrixClip_SaveFlag);
// write out clips
SkDeque::F2BIter iter(fMatrixClipStack);
bool firstClip = true;
SkMatrix curMat = SkMatrix::I();
for (const MatrixClipState* state = (const MatrixClipState*) iter.next();
state != NULL;
state = (const MatrixClipState*) iter.next()) {
state->fClipInfo->writeClip(&curMat, fPicRecord, &firstClip);
}
// write out matrix
if (!fCurMCState->fMatrixInfo->fMatrix.isIdentity()) {
// TODO: writing out the delta matrix here is an artifact of the writing
// out of the entire clip stack (with its matrices). Ultimately we will
// write out the CTM here when the clip state is collapsed to a single path.
WriteDeltaMat(fPicRecord, curMat, fCurMCState->fMatrixInfo->fMatrix);
}
SkDEBUGCODE(this->validate();)
return true;
}
void SkMatrixClipStateMgr::finish() {
if (kIdentityWideOpenStateID != fCurOpenStateID) {
fPicRecord->recordRestore(); // Close the open block
fCurOpenStateID = kIdentityWideOpenStateID;
}
}
#ifdef SK_DEBUG
void SkMatrixClipStateMgr::validate() {
if (fCurOpenStateID == fCurMCState->fMCStateID) {
// The current state is the active one so all its skip offsets should
// still be -1
SkDeque::F2BIter iter(fMatrixClipStack);
for (const MatrixClipState* state = (const MatrixClipState*) iter.next();
state != NULL;
state = (const MatrixClipState*) iter.next()) {
state->fClipInfo->checkOffsetNotEqual(-1);
}
}
}
#endif

Просмотреть файл

@ -0,0 +1,343 @@
/*
* 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 SkMatrixClipStateMgr_DEFINED
#define SkMatrixClipStateMgr_DEFINED
#include "SkCanvas.h"
#include "SkMatrix.h"
#include "SkRegion.h"
#include "SkRRect.h"
#include "SkTypes.h"
#include "SkTArray.h"
class SkPictureRecord;
class SkWriter32;
// The SkMatrixClipStateMgr collapses the matrix/clip state of an SkPicture into
// a series of save/restore blocks of consistent matrix clip state, e.g.:
//
// save
// clip(s)
// concat
// ... draw ops ...
// restore
//
// SaveLayers simply add another level, e.g.:
//
// save
// clip(s)
// concat
// ... draw ops ...
// saveLayer
// save
// clip(s)
// concat
// ... draw ops ...
// restore
// restore
// restore
//
// As a side effect of this process all saves and saveLayers will become
// kMatrixClip_SaveFlag style saves/saveLayers.
// The SkMatrixClipStateMgr works by intercepting all the save*, restore, clip*,
// and matrix calls sent to SkCanvas in order to track the current matrix/clip
// state. All the other canvas calls get funnelled into a generic "call" entry
// point that signals that a state block is required.
class SkMatrixClipStateMgr {
public:
static const int32_t kIdentityWideOpenStateID = 0;
class MatrixClipState {
public:
class MatrixInfo {
public:
SkMatrix fMatrix;
// TODO: add an internal dictionary and an ID here
};
class ClipInfo : public SkNoncopyable {
public:
ClipInfo() {}
bool clipRect(const SkRect& rect,
SkRegion::Op op,
bool doAA,
const SkMatrix& matrix) {
ClipOp& newClip = fClips.push_back();
newClip.fClipType = kRect_ClipType;
newClip.fGeom.fRRect.setRect(rect); // storing the clipRect in the RRect
newClip.fOp = op;
newClip.fDoAA = doAA;
newClip.fMatrix = matrix;
newClip.fOffset = kInvalidJumpOffset;
return false;
}
bool clipRRect(const SkRRect& rrect,
SkRegion::Op op,
bool doAA,
const SkMatrix& matrix) {
ClipOp& newClip = fClips.push_back();
newClip.fClipType = kRRect_ClipType;
newClip.fGeom.fRRect = rrect;
newClip.fOp = op;
newClip.fDoAA = doAA;
newClip.fMatrix = matrix;
newClip.fOffset = kInvalidJumpOffset;
return false;
}
bool clipPath(SkPictureRecord* picRecord,
const SkPath& path,
SkRegion::Op op,
bool doAA,
const SkMatrix& matrix);
bool clipRegion(SkPictureRecord* picRecord,
const SkRegion& region,
SkRegion::Op op,
const SkMatrix& matrix);
void writeClip(SkMatrix* curMat,
SkPictureRecord* picRecord,
bool* overrideFirstOp);
void fillInSkips(SkWriter32* writer, int32_t restoreOffset);
#ifdef SK_DEBUG
void checkOffsetNotEqual(int32_t offset) {
for (int i = 0; i < fClips.count(); ++i) {
ClipOp& curClip = fClips[i];
SkASSERT(offset != curClip.fOffset);
}
}
#endif
private:
enum ClipType {
kRect_ClipType,
kRRect_ClipType,
kPath_ClipType,
kRegion_ClipType
};
static const int kInvalidJumpOffset = -1;
class ClipOp {
public:
ClipOp() {}
~ClipOp() {
if (kRegion_ClipType == fClipType) {
SkDELETE(fGeom.fRegion);
}
}
ClipType fClipType;
union {
SkRRect fRRect; // also stores clipRect
int fPathID;
// TODO: add internal dictionary of regions
// This parameter forces us to have a dtor and thus use
// SkTArray rather then SkTDArray!
const SkRegion* fRegion;
} fGeom;
bool fDoAA;
SkRegion::Op fOp;
// The CTM in effect when this clip call was issued
// TODO: add an internal dictionary and replace with ID
SkMatrix fMatrix;
// The offset of this clipOp's "jump-to-offset" location in the skp.
// -1 means the offset hasn't been written.
int32_t fOffset;
};
SkTArray<ClipOp> fClips;
typedef SkNoncopyable INHERITED;
};
MatrixClipState(MatrixClipState* prev, int flags)
#ifdef SK_DEBUG
: fPrev(prev)
#endif
{
if (NULL == prev) {
fLayerID = 0;
fMatrixInfoStorage.fMatrix.reset();
fMatrixInfo = &fMatrixInfoStorage;
fClipInfo = &fClipInfoStorage; // ctor handles init of fClipInfoStorage
// The identity/wide-open-clip state is current by default
fMCStateID = kIdentityWideOpenStateID;
}
else {
fLayerID = prev->fLayerID;
if (flags & SkCanvas::kMatrix_SaveFlag) {
fMatrixInfoStorage = *prev->fMatrixInfo;
fMatrixInfo = &fMatrixInfoStorage;
} else {
fMatrixInfo = prev->fMatrixInfo;
}
if (flags & SkCanvas::kClip_SaveFlag) {
// We don't copy the ClipOps of the previous clip states
fClipInfo = &fClipInfoStorage;
} else {
fClipInfo = prev->fClipInfo;
}
// Initially a new save/saveLayer represents the same MC state
// as its predecessor.
fMCStateID = prev->fMCStateID;
}
fIsSaveLayer = false;
}
MatrixInfo* fMatrixInfo;
MatrixInfo fMatrixInfoStorage;
ClipInfo* fClipInfo;
ClipInfo fClipInfoStorage;
// Tracks the current depth of saveLayers to support the isDrawingToLayer call
int fLayerID;
// Does this MC state represent a saveLayer call?
bool fIsSaveLayer;
// The next two fields are only valid when fIsSaveLayer is set.
int32_t fSaveLayerBaseStateID;
bool fSaveLayerBracketed;
#ifdef SK_DEBUG
MatrixClipState* fPrev; // debugging aid
#endif
int32_t fMCStateID;
};
enum CallType {
kMatrix_CallType,
kClip_CallType,
kOther_CallType
};
SkMatrixClipStateMgr();
void init(SkPictureRecord* picRecord) {
// Note: we're not taking a ref here. It is expected that the SkMatrixClipStateMgr
// is owned by the SkPictureRecord object
fPicRecord = picRecord;
}
// TODO: need to override canvas' getSaveCount. Right now we pass the
// save* and restore calls on to the base SkCanvas in SkPictureRecord but
// this duplicates effort.
int getSaveCount() const { return fMatrixClipStack.count(); }
int save(SkCanvas::SaveFlags flags);
int saveLayer(const SkRect* bounds, const SkPaint* paint, SkCanvas::SaveFlags flags);
bool isDrawingToLayer() const {
return fCurMCState->fLayerID > 0;
}
void restore();
bool translate(SkScalar dx, SkScalar dy) {
this->call(kMatrix_CallType);
return fCurMCState->fMatrixInfo->fMatrix.preTranslate(dx, dy);
}
bool scale(SkScalar sx, SkScalar sy) {
this->call(kMatrix_CallType);
return fCurMCState->fMatrixInfo->fMatrix.preScale(sx, sy);
}
bool rotate(SkScalar degrees) {
this->call(kMatrix_CallType);
return fCurMCState->fMatrixInfo->fMatrix.preRotate(degrees);
}
bool skew(SkScalar sx, SkScalar sy) {
this->call(kMatrix_CallType);
return fCurMCState->fMatrixInfo->fMatrix.preSkew(sx, sy);
}
bool concat(const SkMatrix& matrix) {
this->call(kMatrix_CallType);
return fCurMCState->fMatrixInfo->fMatrix.preConcat(matrix);
}
void setMatrix(const SkMatrix& matrix) {
this->call(kMatrix_CallType);
fCurMCState->fMatrixInfo->fMatrix = matrix;
}
bool clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
this->call(SkMatrixClipStateMgr::kClip_CallType);
return fCurMCState->fClipInfo->clipRect(rect, op, doAA,
fCurMCState->fMatrixInfo->fMatrix);
}
bool clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
this->call(SkMatrixClipStateMgr::kClip_CallType);
return fCurMCState->fClipInfo->clipRRect(rrect, op, doAA,
fCurMCState->fMatrixInfo->fMatrix);
}
bool clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
this->call(SkMatrixClipStateMgr::kClip_CallType);
return fCurMCState->fClipInfo->clipPath(fPicRecord, path, op, doAA,
fCurMCState->fMatrixInfo->fMatrix);
}
bool clipRegion(const SkRegion& region, SkRegion::Op op) {
this->call(SkMatrixClipStateMgr::kClip_CallType);
return fCurMCState->fClipInfo->clipRegion(fPicRecord, region, op,
fCurMCState->fMatrixInfo->fMatrix);
}
bool call(CallType callType);
void fillInSkips(SkWriter32* writer, int32_t restoreOffset) {
// Since we write out the entire clip stack at each block start we
// need to update the skips for the entire stack each time too.
SkDeque::F2BIter iter(fMatrixClipStack);
for (const MatrixClipState* state = (const MatrixClipState*) iter.next();
state != NULL;
state = (const MatrixClipState*) iter.next()) {
state->fClipInfo->fillInSkips(writer, restoreOffset);
}
}
void finish();
protected:
SkPictureRecord* fPicRecord;
uint32_t fMatrixClipStackStorage[43]; // sized to fit 2 clip states
SkDeque fMatrixClipStack;
MatrixClipState* fCurMCState;
// The MCStateID of the state currently in effect in the byte stream. 0 if none.
int32_t fCurOpenStateID;
SkDEBUGCODE(void validate();)
static void WriteDeltaMat(SkPictureRecord* picRecord,
const SkMatrix& current,
const SkMatrix& desired);
static int32_t NewMCStateID();
};
#endif

Просмотреть файл

@ -43,9 +43,15 @@ SkPictureRecord::SkPictureRecord(uint32_t flags, SkBaseDevice* device)
fBitmapHeap = SkNEW(SkBitmapHeap); fBitmapHeap = SkNEW(SkBitmapHeap);
fFlattenableHeap.setBitmapStorage(fBitmapHeap); fFlattenableHeap.setBitmapStorage(fBitmapHeap);
fPathHeap = NULL; // lazy allocate fPathHeap = NULL; // lazy allocate
#ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
fFirstSavedLayerIndex = kNoSavedLayerIndex; fFirstSavedLayerIndex = kNoSavedLayerIndex;
#endif
fInitialSaveCount = kNoInitialSave; fInitialSaveCount = kNoInitialSave;
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.init(this);
#endif
} }
SkPictureRecord::~SkPictureRecord() { SkPictureRecord::~SkPictureRecord() {
@ -139,10 +145,15 @@ SkBaseDevice* SkPictureRecord::setDevice(SkBaseDevice* device) {
} }
int SkPictureRecord::save(SaveFlags flags) { int SkPictureRecord::save(SaveFlags flags) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.save(flags);
#else
// record the offset to us, making it non-positive to distinguish a save // record the offset to us, making it non-positive to distinguish a save
// from a clip entry. // from a clip entry.
fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten()); fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
this->recordSave(flags); this->recordSave(flags);
#endif
return this->INHERITED::save(flags); return this->INHERITED::save(flags);
} }
@ -157,6 +168,11 @@ void SkPictureRecord::recordSave(SaveFlags flags) {
int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint, int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
SaveFlags flags) { SaveFlags flags) {
int count;
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
count = fMCMgr.saveLayer(bounds, paint, flags);
#else
// record the offset to us, making it non-positive to distinguish a save // record the offset to us, making it non-positive to distinguish a save
// from a clip entry. // from a clip entry.
fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten()); fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
@ -164,6 +180,7 @@ int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
if (kNoSavedLayerIndex == fFirstSavedLayerIndex) { if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
fFirstSavedLayerIndex = fRestoreOffsetStack.count(); fFirstSavedLayerIndex = fRestoreOffsetStack.count();
} }
#endif
/* Don't actually call INHERITED::saveLayer, because that will try to allocate /* Don't actually call INHERITED::saveLayer, because that will try to allocate
an offscreen device (potentially very big) which we don't actually need an offscreen device (potentially very big) which we don't actually need
@ -171,13 +188,13 @@ int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
clip starts out the size of the picture, which is often much larger clip starts out the size of the picture, which is often much larger
than the size of the actual device we'll use during playback). than the size of the actual device we'll use during playback).
*/ */
int count = this->INHERITED::save(flags); count = this->INHERITED::save(flags);
this->clipRectBounds(bounds, flags, NULL); this->clipRectBounds(bounds, flags, NULL);
return count; return count;
} }
void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint, void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
SaveFlags flags) { SaveFlags flags) {
// op + bool for 'bounds' // op + bool for 'bounds'
uint32_t size = 2 * kUInt32Size; uint32_t size = 2 * kUInt32Size;
if (NULL != bounds) { if (NULL != bounds) {
@ -198,7 +215,11 @@ void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint
} }
bool SkPictureRecord::isDrawingToLayer() const { bool SkPictureRecord::isDrawingToLayer() const {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
return fMCMgr.isDrawingToLayer();
#else
return fFirstSavedLayerIndex != kNoSavedLayerIndex; return fFirstSavedLayerIndex != kNoSavedLayerIndex;
#endif
} }
/* /*
@ -577,6 +598,14 @@ void SkPictureRecord::restore() {
SkASSERT(fRestoreOffsetStack.count() > 1); SkASSERT(fRestoreOffsetStack.count() > 1);
#endif #endif
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
if (fMCMgr.getSaveCount() == 1) {
return;
}
// TODO: don't write the restore to the op stream for normal saves
fMCMgr.restore();
#else
// check for underflow // check for underflow
if (fRestoreOffsetStack.count() == 0) { if (fRestoreOffsetStack.count() == 0) {
return; return;
@ -609,59 +638,86 @@ void SkPictureRecord::restore() {
} }
fRestoreOffsetStack.pop(); fRestoreOffsetStack.pop();
#endif
return this->INHERITED::restore(); return this->INHERITED::restore();
} }
void SkPictureRecord::recordRestore() { void SkPictureRecord::recordRestore(bool fillInSkips) {
uint32_t initialOffset, size; uint32_t initialOffset, size;
this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten()); if (fillInSkips) {
this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
}
size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
initialOffset = this->addDraw(RESTORE, &size); initialOffset = this->addDraw(RESTORE, &size);
this->validate(initialOffset, size); this->validate(initialOffset, size);
} }
bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) { bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.translate(dx, dy);
#else
// op + dx + dy // op + dx + dy
uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
size_t initialOffset = this->addDraw(TRANSLATE, &size); size_t initialOffset = this->addDraw(TRANSLATE, &size);
this->addScalar(dx); this->addScalar(dx);
this->addScalar(dy); this->addScalar(dy);
this->validate(initialOffset, size); this->validate(initialOffset, size);
#endif
return this->INHERITED::translate(dx, dy); return this->INHERITED::translate(dx, dy);
} }
bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) { bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.scale(sx, sy);
#else
// op + sx + sy // op + sx + sy
uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
size_t initialOffset = this->addDraw(SCALE, &size); size_t initialOffset = this->addDraw(SCALE, &size);
this->addScalar(sx); this->addScalar(sx);
this->addScalar(sy); this->addScalar(sy);
this->validate(initialOffset, size); this->validate(initialOffset, size);
#endif
return this->INHERITED::scale(sx, sy); return this->INHERITED::scale(sx, sy);
} }
bool SkPictureRecord::rotate(SkScalar degrees) { bool SkPictureRecord::rotate(SkScalar degrees) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.rotate(degrees);
#else
// op + degrees // op + degrees
uint32_t size = 1 * kUInt32Size + sizeof(SkScalar); uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
size_t initialOffset = this->addDraw(ROTATE, &size); size_t initialOffset = this->addDraw(ROTATE, &size);
this->addScalar(degrees); this->addScalar(degrees);
this->validate(initialOffset, size); this->validate(initialOffset, size);
#endif
return this->INHERITED::rotate(degrees); return this->INHERITED::rotate(degrees);
} }
bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) { bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.skew(sx, sy);
#else
// op + sx + sy // op + sx + sy
uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
size_t initialOffset = this->addDraw(SKEW, &size); size_t initialOffset = this->addDraw(SKEW, &size);
this->addScalar(sx); this->addScalar(sx);
this->addScalar(sy); this->addScalar(sy);
this->validate(initialOffset, size); this->validate(initialOffset, size);
#endif
return this->INHERITED::skew(sx, sy); return this->INHERITED::skew(sx, sy);
} }
bool SkPictureRecord::concat(const SkMatrix& matrix) { bool SkPictureRecord::concat(const SkMatrix& matrix) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.concat(matrix);
#else
this->recordConcat(matrix); this->recordConcat(matrix);
#endif
return this->INHERITED::concat(matrix); return this->INHERITED::concat(matrix);
} }
@ -675,12 +731,17 @@ void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
} }
void SkPictureRecord::setMatrix(const SkMatrix& matrix) { void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.setMatrix(matrix);
#else
this->validate(fWriter.bytesWritten(), 0); this->validate(fWriter.bytesWritten(), 0);
// op + matrix // op + matrix
uint32_t size = kUInt32Size + matrix.writeToMemory(NULL); uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
size_t initialOffset = this->addDraw(SET_MATRIX, &size); size_t initialOffset = this->addDraw(SET_MATRIX, &size);
this->addMatrix(matrix); this->addMatrix(matrix);
this->validate(initialOffset, size); this->validate(initialOffset, size);
#endif
this->INHERITED::setMatrix(matrix); this->INHERITED::setMatrix(matrix);
} }
@ -700,6 +761,11 @@ static bool regionOpExpands(SkRegion::Op op) {
} }
} }
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
fMCMgr.fillInSkips(&fWriter, restoreOffset);
}
#else
void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) { void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
int32_t offset = fRestoreOffsetStack.top(); int32_t offset = fRestoreOffsetStack.top();
while (offset > 0) { while (offset > 0) {
@ -715,6 +781,7 @@ void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t
SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp); SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
#endif #endif
} }
#endif
void SkPictureRecord::beginRecording() { void SkPictureRecord::beginRecording() {
// we have to call this *after* our constructor, to ensure that it gets // we have to call this *after* our constructor, to ensure that it gets
@ -726,8 +793,18 @@ void SkPictureRecord::beginRecording() {
void SkPictureRecord::endRecording() { void SkPictureRecord::endRecording() {
SkASSERT(kNoInitialSave != fInitialSaveCount); SkASSERT(kNoInitialSave != fInitialSaveCount);
this->restoreToCount(fInitialSaveCount); this->restoreToCount(fInitialSaveCount);
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.finish();
#endif
} }
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
size_t offset = fWriter.bytesWritten();
this->addInt(-1);
return offset;
}
#else
int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) { int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
if (fRestoreOffsetStack.isEmpty()) { if (fRestoreOffsetStack.isEmpty()) {
return -1; return -1;
@ -757,22 +834,30 @@ int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
fRestoreOffsetStack.top() = offset; fRestoreOffsetStack.top() = offset;
return offset; return offset;
} }
#endif
bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.clipRect(rect, op, doAA);
#else
this->recordClipRect(rect, op, doAA); this->recordClipRect(rect, op, doAA);
#endif
return this->INHERITED::clipRect(rect, op, doAA); return this->INHERITED::clipRect(rect, op, doAA);
} }
int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
// id + rect + clip params // id + rect + clip params
uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size; uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
size += kUInt32Size; // + restore offset
#else
// recordRestoreOffsetPlaceholder doesn't always write an offset // recordRestoreOffsetPlaceholder doesn't always write an offset
if (!fRestoreOffsetStack.isEmpty()) { if (!fRestoreOffsetStack.isEmpty()) {
// + restore offset // + restore offset
size += kUInt32Size; size += kUInt32Size;
} }
#endif
size_t initialOffset = this->addDraw(CLIP_RECT, &size); size_t initialOffset = this->addDraw(CLIP_RECT, &size);
this->addRect(rect); this->addRect(rect);
this->addInt(ClipParams_pack(op, doAA)); this->addInt(ClipParams_pack(op, doAA));
@ -787,7 +872,11 @@ bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA
return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA); return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
} }
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.clipRRect(rrect, op, doAA);
#else
this->recordClipRRect(rrect, op, doAA); this->recordClipRRect(rrect, op, doAA);
#endif
if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) { if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false); return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
} else { } else {
@ -796,19 +885,21 @@ bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA
} }
int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
// op + rrect + clip params // op + rrect + clip params
uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size; uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
size += kUInt32Size; // + restore offset
#else
// recordRestoreOffsetPlaceholder doesn't always write an offset // recordRestoreOffsetPlaceholder doesn't always write an offset
if (!fRestoreOffsetStack.isEmpty()) { if (!fRestoreOffsetStack.isEmpty()) {
// + restore offset // + restore offset
size += kUInt32Size; size += kUInt32Size;
} }
#endif
size_t initialOffset = this->addDraw(CLIP_RRECT, &size); size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
this->addRRect(rrect); this->addRRect(rrect);
this->addInt(ClipParams_pack(op, doAA)); this->addInt(ClipParams_pack(op, doAA));
int offset = recordRestoreOffsetPlaceholder(op); int offset = recordRestoreOffsetPlaceholder(op);
this->validate(initialOffset, size); this->validate(initialOffset, size);
return offset; return offset;
} }
@ -820,8 +911,12 @@ bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
return this->clipRect(r, op, doAA); return this->clipRect(r, op, doAA);
} }
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.clipPath(path, op, doAA);
#else
int pathID = this->addPathToHeap(path); int pathID = this->addPathToHeap(path);
this->recordClipPath(pathID, op, doAA); this->recordClipPath(pathID, op, doAA);
#endif
if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) { if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
return this->updateClipConservativelyUsingBounds(path.getBounds(), op, return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
@ -832,36 +927,47 @@ bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
} }
int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) { int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
// op + path index + clip params // op + path index + clip params
uint32_t size = 3 * kUInt32Size; uint32_t size = 3 * kUInt32Size;
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
size += kUInt32Size; // + restore offset
#else
// recordRestoreOffsetPlaceholder doesn't always write an offset // recordRestoreOffsetPlaceholder doesn't always write an offset
if (!fRestoreOffsetStack.isEmpty()) { if (!fRestoreOffsetStack.isEmpty()) {
// + restore offset // + restore offset
size += kUInt32Size; size += kUInt32Size;
} }
#endif
size_t initialOffset = this->addDraw(CLIP_PATH, &size); size_t initialOffset = this->addDraw(CLIP_PATH, &size);
this->addInt(pathID); this->addInt(pathID);
this->addInt(ClipParams_pack(op, doAA)); this->addInt(ClipParams_pack(op, doAA));
int offset = recordRestoreOffsetPlaceholder(op); int offset = recordRestoreOffsetPlaceholder(op);
this->validate(initialOffset, size); this->validate(initialOffset, size);
return offset; return offset;
} }
bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) { bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.clipRegion(region, op);
#else
this->recordClipRegion(region, op); this->recordClipRegion(region, op);
#endif
return this->INHERITED::clipRegion(region, op); return this->INHERITED::clipRegion(region, op);
} }
int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) { int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
// op + clip params + region // op + clip params + region
uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL); uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
size += kUInt32Size; // + restore offset
#else
// recordRestoreOffsetPlaceholder doesn't always write an offset // recordRestoreOffsetPlaceholder doesn't always write an offset
if (!fRestoreOffsetStack.isEmpty()) { if (!fRestoreOffsetStack.isEmpty()) {
// + restore offset // + restore offset
size += kUInt32Size; size += kUInt32Size;
} }
#endif
size_t initialOffset = this->addDraw(CLIP_REGION, &size); size_t initialOffset = this->addDraw(CLIP_REGION, &size);
this->addRegion(region); this->addRegion(region);
this->addInt(ClipParams_pack(op, false)); this->addInt(ClipParams_pack(op, false));
@ -872,6 +978,11 @@ int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
} }
void SkPictureRecord::clear(SkColor color) { void SkPictureRecord::clear(SkColor color) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
// op + color // op + color
uint32_t size = 2 * kUInt32Size; uint32_t size = 2 * kUInt32Size;
size_t initialOffset = this->addDraw(DRAW_CLEAR, &size); size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
@ -880,6 +991,11 @@ void SkPictureRecord::clear(SkColor color) {
} }
void SkPictureRecord::drawPaint(const SkPaint& paint) { void SkPictureRecord::drawPaint(const SkPaint& paint) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
// op + paint index // op + paint index
uint32_t size = 2 * kUInt32Size; uint32_t size = 2 * kUInt32Size;
size_t initialOffset = this->addDraw(DRAW_PAINT, &size); size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
@ -890,6 +1006,11 @@ void SkPictureRecord::drawPaint(const SkPaint& paint) {
void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[], void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
const SkPaint& paint) { const SkPaint& paint) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
// op + paint index + mode + count + point data // op + paint index + mode + count + point data
uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint); uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
size_t initialOffset = this->addDraw(DRAW_POINTS, &size); size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
@ -902,6 +1023,11 @@ void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts
} }
void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) { void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
// op + paint index + rect // op + paint index + rect
uint32_t size = 2 * kUInt32Size + sizeof(oval); uint32_t size = 2 * kUInt32Size + sizeof(oval);
size_t initialOffset = this->addDraw(DRAW_OVAL, &size); size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
@ -912,6 +1038,11 @@ void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
} }
void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) { void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
// op + paint index + rect // op + paint index + rect
uint32_t size = 2 * kUInt32Size + sizeof(rect); uint32_t size = 2 * kUInt32Size + sizeof(rect);
size_t initialOffset = this->addDraw(DRAW_RECT, &size); size_t initialOffset = this->addDraw(DRAW_RECT, &size);
@ -922,6 +1053,11 @@ void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
} }
void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) { void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
if (rrect.isRect()) { if (rrect.isRect()) {
this->SkPictureRecord::drawRect(rrect.getBounds(), paint); this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
} else if (rrect.isOval()) { } else if (rrect.isOval()) {
@ -939,6 +1075,11 @@ void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
} }
void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
// op + paint index + path index // op + paint index + path index
uint32_t size = 3 * kUInt32Size; uint32_t size = 3 * kUInt32Size;
size_t initialOffset = this->addDraw(DRAW_PATH, &size); size_t initialOffset = this->addDraw(DRAW_PATH, &size);
@ -953,6 +1094,11 @@ void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar
if (bitmap.drawsNothing()) { if (bitmap.drawsNothing()) {
return; return;
} }
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
// op + paint index + bitmap index + left + top // op + paint index + bitmap index + left + top
uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
size_t initialOffset = this->addDraw(DRAW_BITMAP, &size); size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
@ -970,6 +1116,10 @@ void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect*
if (bitmap.drawsNothing()) { if (bitmap.drawsNothing()) {
return; return;
} }
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
// id + paint index + bitmap index + bool for 'src' + flags // id + paint index + bitmap index + bool for 'src' + flags
uint32_t size = 5 * kUInt32Size; uint32_t size = 5 * kUInt32Size;
if (NULL != src) { if (NULL != src) {
@ -993,6 +1143,11 @@ void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m
if (bitmap.drawsNothing()) { if (bitmap.drawsNothing()) {
return; return;
} }
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
// id + paint index + bitmap index + matrix // id + paint index + bitmap index + matrix
uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL); uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size); size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
@ -1008,6 +1163,11 @@ void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& cent
if (bitmap.drawsNothing()) { if (bitmap.drawsNothing()) {
return; return;
} }
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
// op + paint index + bitmap id + center + dst rect // op + paint index + bitmap id + center + dst rect
uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst); uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size); size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
@ -1024,6 +1184,11 @@ void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
if (bitmap.drawsNothing()) { if (bitmap.drawsNothing()) {
return; return;
} }
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
// op + paint index + bitmap index + left + top // op + paint index + bitmap index + left + top
uint32_t size = 5 * kUInt32Size; uint32_t size = 5 * kUInt32Size;
size_t initialOffset = this->addDraw(DRAW_SPRITE, &size); size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
@ -1056,6 +1221,11 @@ void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlat
void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x, void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
SkScalar y, const SkPaint& paint) { SkScalar y, const SkPaint& paint) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
// op + paint index + length + 'length' worth of chars + x + y // op + paint index + length + 'length' worth of chars + x + y
@ -1080,6 +1250,11 @@ void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
void SkPictureRecord::drawPosText(const void* text, size_t byteLength, void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
const SkPoint pos[], const SkPaint& paint) { const SkPoint pos[], const SkPaint& paint) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
size_t points = paint.countText(text, byteLength); size_t points = paint.countText(text, byteLength);
if (0 == points) if (0 == points)
return; return;
@ -1166,6 +1341,10 @@ void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
const SkScalar xpos[], SkScalar constY, const SkScalar xpos[], SkScalar constY,
const SkPaint& paint) { const SkPaint& paint) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
const SkFlatData* flatPaintData = this->getFlatPaintData(paint); const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData); this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
} }
@ -1212,6 +1391,11 @@ void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength, void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
const SkPath& path, const SkMatrix* matrix, const SkPath& path, const SkMatrix* matrix,
const SkPaint& paint) { const SkPaint& paint) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
// op + paint index + length + 'length' worth of data + path index + matrix // op + paint index + length + 'length' worth of data + path index + matrix
const SkMatrix& m = matrix ? *matrix : SkMatrix::I(); const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL); uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
@ -1225,6 +1409,11 @@ void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
} }
void SkPictureRecord::drawPicture(SkPicture& picture) { void SkPictureRecord::drawPicture(SkPicture& picture) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
// op + picture index // op + picture index
uint32_t size = 2 * kUInt32Size; uint32_t size = 2 * kUInt32Size;
size_t initialOffset = this->addDraw(DRAW_PICTURE, &size); size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
@ -1237,6 +1426,11 @@ void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
const SkColor colors[], SkXfermode* xfer, const SkColor colors[], SkXfermode* xfer,
const uint16_t indices[], int indexCount, const uint16_t indices[], int indexCount,
const SkPaint& paint) { const SkPaint& paint) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
uint32_t flags = 0; uint32_t flags = 0;
if (texs) { if (texs) {
flags |= DRAW_VERTICES_HAS_TEXS; flags |= DRAW_VERTICES_HAS_TEXS;
@ -1296,6 +1490,11 @@ void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
} }
void SkPictureRecord::drawData(const void* data, size_t length) { void SkPictureRecord::drawData(const void* data, size_t length) {
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
#endif
// op + length + 'length' worth of data // op + length + 'length' worth of data
uint32_t size = 2 * kUInt32Size + SkAlign4(length); uint32_t size = 2 * kUInt32Size + SkAlign4(length);
size_t initialOffset = this->addDraw(DRAW_DATA, &size); size_t initialOffset = this->addDraw(DRAW_DATA, &size);

Просмотреть файл

@ -10,6 +10,9 @@
#include "SkCanvas.h" #include "SkCanvas.h"
#include "SkFlattenable.h" #include "SkFlattenable.h"
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
#include "SkMatrixClipStateMgr.h"
#endif
#include "SkPathHeap.h" #include "SkPathHeap.h"
#include "SkPicture.h" #include "SkPicture.h"
#include "SkPictureFlat.h" #include "SkPictureFlat.h"
@ -111,11 +114,13 @@ private:
int recordRestoreOffsetPlaceholder(SkRegion::Op); int recordRestoreOffsetPlaceholder(SkRegion::Op);
void fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset); void fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset);
#ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
SkTDArray<int32_t> fRestoreOffsetStack; SkTDArray<int32_t> fRestoreOffsetStack;
int fFirstSavedLayerIndex; int fFirstSavedLayerIndex;
enum { enum {
kNoSavedLayerIndex = -1 kNoSavedLayerIndex = -1
}; };
#endif
/* /*
* Write the 'drawType' operation and chunk size to the skp. 'size' * Write the 'drawType' operation and chunk size to the skp. 'size'
@ -250,7 +255,7 @@ protected:
int recordClipRegion(const SkRegion& region, SkRegion::Op op); int recordClipRegion(const SkRegion& region, SkRegion::Op op);
void recordSave(SaveFlags flags); void recordSave(SaveFlags flags);
void recordSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags); void recordSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags);
void recordRestore(); void recordRestore(bool fillInSkips = true);
// These are set to NULL in our constructor, but may be changed by // These are set to NULL in our constructor, but may be changed by
// subclasses, in which case they will be SkSafeUnref'd in our destructor. // subclasses, in which case they will be SkSafeUnref'd in our destructor.
@ -261,6 +266,9 @@ protected:
SkBitmapHeap* fBitmapHeap; SkBitmapHeap* fBitmapHeap;
private: private:
friend class MatrixClipState; // for access to *Impl methods
friend class SkMatrixClipStateMgr; // for access to *Impl methods
SkChunkFlatController fFlattenableHeap; SkChunkFlatController fFlattenableHeap;
SkPaintDictionary fPaints; SkPaintDictionary fPaints;
@ -277,6 +285,10 @@ private:
friend class SkPicturePlayback; friend class SkPicturePlayback;
friend class SkPictureTester; // for unit testing friend class SkPictureTester; // for unit testing
#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
SkMatrixClipStateMgr fMCMgr;
#endif
typedef SkCanvas INHERITED; typedef SkCanvas INHERITED;
}; };

Просмотреть файл

@ -52,7 +52,10 @@
// system is ready for prime time // system is ready for prime time
// bench the recording times with/without matrix/clip collapsing // bench the recording times with/without matrix/clip collapsing
#ifdef COLLAPSE_MATRIX_CLIP_STATE #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
// Enable/disable debugging helper code
//#define TEST_COLLAPSE_MATRIX_CLIP_STATE 1
// Extract the command ops from the input SkPicture // Extract the command ops from the input SkPicture
static void gets_ops(SkPicture& input, SkTDArray<DrawType>* ops) { static void gets_ops(SkPicture& input, SkTDArray<DrawType>* ops) {
@ -623,7 +626,7 @@ static void emit_struct3(SkCanvas* canvas,
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
#ifdef COLLAPSE_MATRIX_CLIP_STATE #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
static void print(const SkTDArray<DrawType>& expected, const SkTDArray<DrawType>& actual) { static void print(const SkTDArray<DrawType>& expected, const SkTDArray<DrawType>& actual) {
SkDebugf("\n\nexpected %d --- actual %d\n", expected.count(), actual.count()); SkDebugf("\n\nexpected %d --- actual %d\n", expected.count(), actual.count());
int max = SkMax32(expected.count(), actual.count()); int max = SkMax32(expected.count(), actual.count());
@ -658,7 +661,7 @@ static void test_collapse(skiatest::Reporter* reporter) {
for (int l = 0; l < kMatTypeCount; ++l) { for (int l = 0; l < kMatTypeCount; ++l) {
for (int m = 0; m < kClipTypeCount; ++m) { for (int m = 0; m < kClipTypeCount; ++m) {
for (int n = 0; n < kDrawOpTypeCount; ++n) { for (int n = 0; n < kDrawOpTypeCount; ++n) {
#ifdef COLLAPSE_MATRIX_CLIP_STATE #ifdef TEST_COLLAPSE_MATRIX_CLIP_STATE
static int testID = -1; static int testID = -1;
++testID; ++testID;
if (testID < -1) { if (testID < -1) {
@ -686,7 +689,7 @@ static void test_collapse(skiatest::Reporter* reporter) {
REPORTER_ASSERT(reporter, expected.count() == actual.count()); REPORTER_ASSERT(reporter, expected.count() == actual.count());
if (expected.count() != actual.count()) { if (expected.count() != actual.count()) {
#ifdef COLLAPSE_MATRIX_CLIP_STATE #ifdef TEST_COLLAPSE_MATRIX_CLIP_STATE
print(expected, actual); print(expected, actual);
#endif #endif
continue; continue;
@ -694,7 +697,7 @@ static void test_collapse(skiatest::Reporter* reporter) {
for (int i = 0; i < expected.count(); ++i) { for (int i = 0; i < expected.count(); ++i) {
REPORTER_ASSERT(reporter, expected[i] == actual[i]); REPORTER_ASSERT(reporter, expected[i] == actual[i]);
#ifdef COLLAPSE_MATRIX_CLIP_STATE #ifdef TEST_COLLAPSE_MATRIX_CLIP_STATE
if (expected[i] != actual[i]) { if (expected[i] != actual[i]) {
print(expected, actual); print(expected, actual);
} }