зеркало из https://github.com/mozilla/moz-skia.git
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:
Родитель
ad0c5d248c
Коммит
8515e79a76
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче