Add R-Tree record flag to SkPicture, plus some cleanup/fixes in associated classes.

Review URL: https://codereview.appspot.com/6506103

git-svn-id: http://skia.googlecode.com/svn/trunk@5537 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
rileya@google.com 2012-09-13 21:41:51 +00:00
Родитель ad0c5d248c
Коммит 8515e79a76
7 изменённых файлов: 106 добавлений и 12 удалений

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

@ -70,7 +70,25 @@ public:
clip-query calls will reflect the path's bounds, not the actual clip-query calls will reflect the path's bounds, not the actual
path. path.
*/ */
kUsePathBoundsForClip_RecordingFlag = 0x01 kUsePathBoundsForClip_RecordingFlag = 0x01,
/* This flag causes the picture to compute bounding boxes and build
up a spatial hierarchy (currently an R-Tree), plus a tree of Canvas'
usually stack-based clip/etc state. This requires an increase in
recording time (often ~2x; likely more for very complex pictures),
but allows us to perform much faster culling at playback time, and
completely avoid some unnecessary clips and other operations. This
is ideal for tiled rendering, or any other situation where you're
drawing a fraction of a large scene into a smaller viewport.
In most cases the record cost is offset by the playback improvement
after a frame or two of tiled rendering (and complex pictures that
induce the worst record times will generally get the largest
speedups at playback time).
Note: Currently this is not serializable, the bounding data will be
discarded if you serialize into a stream and then deserialize.
*/
kOptimizeForClippedPlayback_RecordingFlag = 0x02
}; };
/** Returns the canvas that records the drawing commands. /** Returns the canvas that records the drawing commands.

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

@ -163,8 +163,8 @@ void SkBBoxRecord::drawPosTextH(const void* text, size_t byteLength, const SkSca
SkPaint::FontMetrics metrics; SkPaint::FontMetrics metrics;
paint.getFontMetrics(&metrics); paint.getFontMetrics(&metrics);
// pad horizontally by half max glyph height // pad horizontally by max glyph height
SkScalar pad = (metrics.fTop - metrics.fBottom) / 2; SkScalar pad = (metrics.fTop - metrics.fBottom);
bbox.fLeft += pad; bbox.fLeft += pad;
bbox.fRight -= pad; bbox.fRight -= pad;
@ -217,8 +217,8 @@ void SkBBoxRecord::drawVertices(VertexMode mode, int vertexCount,
} }
void SkBBoxRecord::drawPicture(SkPicture& picture) { void SkBBoxRecord::drawPicture(SkPicture& picture) {
SkRect bbox = {0, 0, picture.width(), picture.height()}; if (picture.width() > 0 && picture.height() > 0 &&
if (this->transformBounds(bbox, NULL)) { this->transformBounds(SkRect::MakeWH(picture.width(), picture.height()), NULL)) {
INHERITED::drawPicture(picture); INHERITED::drawPicture(picture);
} }
} }

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

@ -22,6 +22,8 @@
#include "SkReader32.h" #include "SkReader32.h"
#include "SkWriter32.h" #include "SkWriter32.h"
#include "SkRTree.h"
#include "SkBBoxHierarchyRecord.h"
SK_DEFINE_INST_COUNT(SkPicture) SK_DEFINE_INST_COUNT(SkPicture)
@ -183,7 +185,16 @@ SkCanvas* SkPicture::beginRecording(int width, int height,
fRecord = NULL; fRecord = NULL;
} }
fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags)); if (recordingFlags & kOptimizeForClippedPlayback_RecordingFlag) {
SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(width),
SkIntToScalar(height));
SkRTree* tree = SkRTree::Create(6, 11, aspectRatio);
SkASSERT(NULL != tree);
fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (recordingFlags, tree));
tree->unref();
} else {
fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags));
}
fWidth = width; fWidth = width;
fHeight = height; fHeight = height;

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

@ -11,6 +11,9 @@
#include "SkOrderedReadBuffer.h" #include "SkOrderedReadBuffer.h"
#include "SkOrderedWriteBuffer.h" #include "SkOrderedWriteBuffer.h"
#include <new> #include <new>
#include "SkBBoxHierarchy.h"
#include "SkPictureStateTree.h"
#include "SkTSort.h"
template <typename T> int SafeCount(const T* obj) { template <typename T> int SafeCount(const T* obj) {
return obj ? obj->count() : 0; return obj ? obj->count() : 0;
@ -69,6 +72,16 @@ SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record, bool deepCop
if (writer.size() == 0) if (writer.size() == 0)
return; return;
fBoundingHierarchy = record.fBoundingHierarchy;
fStateTree = record.fStateTree;
SkSafeRef(fBoundingHierarchy);
SkSafeRef(fStateTree);
if (NULL != fBoundingHierarchy) {
fBoundingHierarchy->flushDeferredInserts();
}
{ {
size_t size = writer.size(); size_t size = writer.size();
void* buffer = sk_malloc_throw(size); void* buffer = sk_malloc_throw(size);
@ -140,6 +153,12 @@ SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInf
fMatrices = SkSafeRef(src.fMatrices); fMatrices = SkSafeRef(src.fMatrices);
fRegions = SkSafeRef(src.fRegions); fRegions = SkSafeRef(src.fRegions);
fOpData = SkSafeRef(src.fOpData); fOpData = SkSafeRef(src.fOpData);
fBoundingHierarchy = src.fBoundingHierarchy;
fStateTree = src.fStateTree;
SkSafeRef(fBoundingHierarchy);
SkSafeRef(fStateTree);
if (deepCopyInfo) { if (deepCopyInfo) {
@ -203,6 +222,8 @@ void SkPicturePlayback::init() {
fPictureCount = 0; fPictureCount = 0;
fOpData = NULL; fOpData = NULL;
fFactoryPlayback = NULL; fFactoryPlayback = NULL;
fBoundingHierarchy = NULL;
fStateTree = NULL;
} }
SkPicturePlayback::~SkPicturePlayback() { SkPicturePlayback::~SkPicturePlayback() {
@ -212,6 +233,8 @@ SkPicturePlayback::~SkPicturePlayback() {
SkSafeUnref(fMatrices); SkSafeUnref(fMatrices);
SkSafeUnref(fPaints); SkSafeUnref(fPaints);
SkSafeUnref(fRegions); SkSafeUnref(fRegions);
SkSafeUnref(fBoundingHierarchy);
SkSafeUnref(fStateTree);
for (int i = 0; i < fPictureCount; i++) { for (int i = 0; i < fPictureCount; i++) {
fPictureRefs[i]->unref(); fPictureRefs[i]->unref();
@ -560,6 +583,30 @@ void SkPicturePlayback::draw(SkCanvas& canvas) {
SkReader32 reader(fOpData->bytes(), fOpData->size()); SkReader32 reader(fOpData->bytes(), fOpData->size());
TextContainer text; TextContainer text;
SkTDArray<void*> results;
if (fStateTree && fBoundingHierarchy) {
SkRect clipBounds;
if (canvas.getClipBounds(&clipBounds)) {
SkIRect query;
clipBounds.roundOut(&query);
fBoundingHierarchy->search(query, &results);
if (results.count() == 0) { return; }
SkTQSort<SkPictureStateTree::Draw>(
reinterpret_cast<SkPictureStateTree::Draw**>(results.begin()),
reinterpret_cast<SkPictureStateTree::Draw**>(results.end()-1));
}
}
SkPictureStateTree::Iterator it = (NULL == fStateTree) ?
SkPictureStateTree::Iterator() :
fStateTree->getIterator(results, &canvas);
if (it.isValid()) {
uint32_t off = it.draw();
if (off == SK_MaxU32) { return; }
reader.setOffset(off);
}
// Record this, so we can concat w/ it if we encounter a setMatrix() // Record this, so we can concat w/ it if we encounter a setMatrix()
SkMatrix initialMatrix = canvas.getTotalMatrix(); SkMatrix initialMatrix = canvas.getTotalMatrix();
@ -807,6 +854,12 @@ void SkPicturePlayback::draw(SkCanvas& canvas) {
default: default:
SkASSERT(0); SkASSERT(0);
} }
if (it.isValid()) {
uint32_t off = it.draw();
if (off == SK_MaxU32) { break; }
reader.setOffset(off);
}
} }
#ifdef SPEW_CLIP_SKIPPING #ifdef SPEW_CLIP_SKIPPING

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

@ -28,6 +28,8 @@
class SkPictureRecord; class SkPictureRecord;
class SkStream; class SkStream;
class SkWStream; class SkWStream;
class SkBBoxHierarchy;
class SkPictureStateTree;
struct SkPictInfo { struct SkPictInfo {
enum Flags { enum Flags {
@ -192,6 +194,9 @@ private:
SkPicture** fPictureRefs; SkPicture** fPictureRefs;
int fPictureCount; int fPictureCount;
SkBBoxHierarchy* fBoundingHierarchy;
SkPictureStateTree* fStateTree;
SkTypefacePlayback fTFPlayback; SkTypefacePlayback fTFPlayback;
SkFactoryPlayback* fFactoryPlayback; SkFactoryPlayback* fFactoryPlayback;
#ifdef SK_BUILD_FOR_ANDROID #ifdef SK_BUILD_FOR_ANDROID

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

@ -80,21 +80,23 @@ void SkPictureStateTree::appendNode(uint32_t offset) {
} }
SkPictureStateTree::Iterator::Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root) SkPictureStateTree::Iterator::Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root)
: fDraws(draws) : fDraws(&draws)
, fCanvas(canvas) , fCanvas(canvas)
, fCurrentNode(root) , fCurrentNode(root)
, fPlaybackMatrix(canvas->getTotalMatrix()) , fPlaybackMatrix(canvas->getTotalMatrix())
, fCurrentMatrix(NULL) , fCurrentMatrix(NULL)
, fPlaybackIndex(0) , fPlaybackIndex(0)
, fSave(false) { , fSave(false)
, fValid(true) {
} }
uint32_t SkPictureStateTree::Iterator::draw() { uint32_t SkPictureStateTree::Iterator::draw() {
if (fPlaybackIndex >= fDraws.count()) { SkASSERT(this->isValid());
if (fPlaybackIndex >= fDraws->count()) {
// restore back to where we started // restore back to where we started
if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); } if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
fCurrentNode = fCurrentNode->fParent; fCurrentNode = fCurrentNode->fParent;
while (NULL != fCurrentNode->fParent) { while (NULL != fCurrentNode) {
if (fCurrentNode->fFlags & Node::kSave_Flag) { fCanvas->restore(); } if (fCurrentNode->fFlags & Node::kSave_Flag) { fCanvas->restore(); }
if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); } if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
fCurrentNode = fCurrentNode->fParent; fCurrentNode = fCurrentNode->fParent;
@ -103,7 +105,7 @@ uint32_t SkPictureStateTree::Iterator::draw() {
return kDrawComplete; return kDrawComplete;
} }
Draw* draw = static_cast<Draw*>(fDraws[fPlaybackIndex]); Draw* draw = static_cast<Draw*>((*fDraws)[fPlaybackIndex]);
Node* targetNode = draw->fNode; Node* targetNode = draw->fNode;
if (fSave) { if (fSave) {

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

@ -70,10 +70,12 @@ public:
/** Returns the next offset into the picture stream, or kDrawComplete if complete. */ /** Returns the next offset into the picture stream, or kDrawComplete if complete. */
uint32_t draw(); uint32_t draw();
static const uint32_t kDrawComplete = SK_MaxU32; static const uint32_t kDrawComplete = SK_MaxU32;
Iterator() : fValid(false) { }
bool isValid() { return fValid; }
private: private:
Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root); Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root);
// The draws this iterator is associated with // The draws this iterator is associated with
const SkTDArray<void*>& fDraws; const SkTDArray<void*>* fDraws;
// canvas this is playing into (so we can insert saves/restores as necessary) // canvas this is playing into (so we can insert saves/restores as necessary)
SkCanvas* fCanvas; SkCanvas* fCanvas;
@ -95,6 +97,9 @@ public:
// Whether or not we need to do a save next iteration // Whether or not we need to do a save next iteration
bool fSave; bool fSave;
// Whether or not this is a valid iterator (the default public constructor sets this false)
bool fValid;
friend class SkPictureStateTree; friend class SkPictureStateTree;
}; };