Convert BBH APIs to use SkRect.

Still TODO: convert internals of SkTileGrid.cpp and SkRTree.cpp to work in floats too.

NOTREECHECKS=true

BUG=skia:1021
R=robertphillips@google.com, reed@google.com, mtklein@google.com

Author: mtklein@chromium.org

Review URL: https://codereview.chromium.org/511613002
This commit is contained in:
mtklein 2014-08-27 10:39:42 -07:00 committed by Commit bot
parent 3031350e05
commit 533eb782ed
20 changed files with 207 additions and 196 deletions

View File

@ -13,12 +13,12 @@
#include "SkString.h"
// confine rectangles to a smallish area, so queries generally hit something, and overlap occurs:
static const int GENERATE_EXTENTS = 1000;
static const SkScalar GENERATE_EXTENTS = 1000.0f;
static const int NUM_BUILD_RECTS = 500;
static const int NUM_QUERY_RECTS = 5000;
static const int GRID_WIDTH = 100;
typedef SkIRect (*MakeRectProc)(SkRandom&, int, int);
typedef SkRect (*MakeRectProc)(SkRandom&, int, int);
// Time how long it takes to build an R-Tree either bulk-loaded or not
class RTreeBuildBench : public Benchmark {
@ -115,32 +115,32 @@ protected:
SkRandom rand;
for (int i = 0; i < loops; ++i) {
SkTDArray<void*> hits;
SkIRect query;
SkRect query;
switch(fQuery) {
case kSmall_QueryType:
query.fLeft = rand.nextU() % GENERATE_EXTENTS;
query.fTop = rand.nextU() % GENERATE_EXTENTS;
query.fRight = query.fLeft + (GENERATE_EXTENTS / 20);
query.fBottom = query.fTop + (GENERATE_EXTENTS / 20);
query.fLeft = rand.nextRangeF(0, GENERATE_EXTENTS);
query.fTop = rand.nextRangeF(0, GENERATE_EXTENTS);
query.fRight = query.fLeft + (GENERATE_EXTENTS / 20);
query.fBottom = query.fTop + (GENERATE_EXTENTS / 20);
break;
case kLarge_QueryType:
query.fLeft = rand.nextU() % GENERATE_EXTENTS;
query.fTop = rand.nextU() % GENERATE_EXTENTS;
query.fRight = query.fLeft + (GENERATE_EXTENTS / 2);
query.fBottom = query.fTop + (GENERATE_EXTENTS / 2);
query.fLeft = rand.nextRangeF(0, GENERATE_EXTENTS);
query.fTop = rand.nextRangeF(0, GENERATE_EXTENTS);
query.fRight = query.fLeft + (GENERATE_EXTENTS / 2);
query.fBottom = query.fTop + (GENERATE_EXTENTS / 2);
break;
case kFull_QueryType:
query.fLeft = -GENERATE_EXTENTS;
query.fTop = -GENERATE_EXTENTS;
query.fRight = 2 * GENERATE_EXTENTS;
query.fLeft = -GENERATE_EXTENTS;
query.fTop = -GENERATE_EXTENTS;
query.fRight = 2 * GENERATE_EXTENTS;
query.fBottom = 2 * GENERATE_EXTENTS;
break;
default: // fallthrough
case kRandom_QueryType:
query.fLeft = rand.nextU() % GENERATE_EXTENTS;
query.fTop = rand.nextU() % GENERATE_EXTENTS;
query.fRight = query.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 2);
query.fBottom = query.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 2);
query.fLeft = rand.nextRangeF(0, GENERATE_EXTENTS);
query.fTop = rand.nextRangeF(0, GENERATE_EXTENTS);
query.fRight = query.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/2);
query.fBottom = query.fTop + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/2);
break;
};
fTree->search(query, &hits);
@ -155,34 +155,34 @@ private:
typedef Benchmark INHERITED;
};
static inline SkIRect make_concentric_rects_increasing(SkRandom&, int index, int numRects) {
SkIRect out = {0, 0, index + 1, index + 1};
static inline SkRect make_concentric_rects_increasing(SkRandom&, int index, int numRects) {
SkRect out = SkRect::MakeWH(SkIntToScalar(index+1), SkIntToScalar(index+1));
return out;
}
static inline SkIRect make_XYordered_rects(SkRandom& rand, int index, int numRects) {
SkIRect out;
out.fLeft = index % GRID_WIDTH;
out.fTop = index / GRID_WIDTH;
out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 3);
out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 3);
static inline SkRect make_XYordered_rects(SkRandom& rand, int index, int numRects) {
SkRect out;
out.fLeft = SkIntToScalar(index % GRID_WIDTH);
out.fTop = SkIntToScalar(index / GRID_WIDTH);
out.fRight = out.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3);
out.fBottom = out.fTop + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3);
return out;
}
static inline SkIRect make_YXordered_rects(SkRandom& rand, int index, int numRects) {
SkIRect out;
out.fLeft = index / GRID_WIDTH;
out.fTop = index % GRID_WIDTH;
out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 3);
out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 3);
static inline SkRect make_YXordered_rects(SkRandom& rand, int index, int numRects) {
SkRect out;
out.fLeft = SkIntToScalar(index / GRID_WIDTH);
out.fTop = SkIntToScalar(index % GRID_WIDTH);
out.fRight = out.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3);
out.fBottom = out.fTop + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3);
return out;
}
static inline SkIRect make_random_rects(SkRandom& rand, int index, int numRects) {
SkIRect out;
out.fLeft = rand.nextS() % GENERATE_EXTENTS;
out.fTop = rand.nextS() % GENERATE_EXTENTS;
out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 5);
out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 5);
static inline SkRect make_random_rects(SkRandom& rand, int index, int numRects) {
SkRect out;
out.fLeft = rand.nextRangeF(0, GENERATE_EXTENTS);
out.fTop = rand.nextRangeF(0, GENERATE_EXTENTS);
out.fRight = out.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/5);
out.fBottom = out.fTop + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/5);
return out;
}

View File

@ -288,7 +288,7 @@ private:
/** PRIVATE / EXPERIMENTAL -- do not call
Return the operations required to render the content inside 'queryRect'.
*/
const OperationList* EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) const;
const OperationList* EXPERIMENTAL_getActiveOps(const SkRect& queryRect) const;
void createHeader(SkPictInfo* info) const;
static bool IsValidPictInfo(const SkPictInfo& info);

View File

@ -144,7 +144,7 @@ protected:
static bool FindLayersToHoist(const GrAccelData *gpuData,
const SkPicture::OperationList* ops,
const SkIRect& query,
const SkRect& query,
bool* pullForward);
void drawLayers(const SkPicture* picture,
const SkTDArray<GrCachedLayer*>& atlased,

View File

@ -49,7 +49,7 @@ public:
* structures than repeated inserts) until flushDeferredInserts is called or the first
* search.
*/
virtual void insert(void* data, const SkIRect& bounds, bool defer = false) = 0;
virtual void insert(void* data, const SkRect& bounds, bool defer = false) = 0;
/**
* If any insertions have been deferred, this forces them to be inserted
@ -59,7 +59,7 @@ public:
/**
* Populate 'results' with data pointers corresponding to bounding boxes that intersect 'query'
*/
virtual void search(const SkIRect& query, SkTDArray<void*>* results) const = 0;
virtual void search(const SkRect& query, SkTDArray<void*>* results) const = 0;
virtual void clear() = 0;

View File

@ -20,10 +20,8 @@ SkBBoxHierarchyRecord::SkBBoxHierarchyRecord(const SkISize& size,
}
void SkBBoxHierarchyRecord::handleBBox(const SkRect& bounds) {
SkIRect r;
bounds.roundOut(&r);
SkPictureStateTree::Draw* draw = fStateTree->appendDraw(this->writeStream().bytesWritten());
fBoundingHierarchy->insert(draw, r, true);
fBoundingHierarchy->insert(draw, bounds, true);
}
void SkBBoxHierarchyRecord::willSave() {

View File

@ -335,7 +335,7 @@ const SkMatrix& SkPicture::OperationList::matrix(int index) const {
}
// fRecord TODO(robert) / kind of OK in a non-optimal sense
const SkPicture::OperationList* SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) const {
const SkPicture::OperationList* SkPicture::EXPERIMENTAL_getActiveOps(const SkRect& queryRect) const {
SkASSERT(NULL != fData.get());
if (NULL != fData.get()) {
return fData->getActiveOps(queryRect);

View File

@ -635,7 +635,7 @@ bool SkPictureData::parseBuffer(SkReadBuffer& buffer) {
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
const SkPicture::OperationList* SkPictureData::getActiveOps(const SkIRect& query) const {
const SkPicture::OperationList* SkPictureData::getActiveOps(const SkRect& query) const {
if (NULL == fStateTree || NULL == fBoundingHierarchy) {
return NULL;
}

View File

@ -84,7 +84,7 @@ public:
virtual ~SkPictureData();
const SkPicture::OperationList* getActiveOps(const SkIRect& queryRect) const;
const SkPicture::OperationList* getActiveOps(const SkRect& queryRect) const;
void serialize(SkWStream*, SkPicture::EncodeBitmap) const;
void flatten(SkWriteBuffer&) const;

View File

@ -71,18 +71,15 @@ const SkPicture::OperationList* SkPicturePlayback::getActiveOps(const SkCanvas*
if (fUseBBH) {
SkRect clipBounds;
if (canvas->getClipBounds(&clipBounds)) {
SkIRect query;
clipBounds.roundOut(&query);
return fPictureData->getActiveOps(query);
return fPictureData->getActiveOps(clipBounds);
}
}
}
return NULL;
}
// Initialize the state tree iterator. Return false if there is nothing left to draw.
bool SkPicturePlayback::initIterator(SkPictureStateTree::Iterator* iter,
bool SkPicturePlayback::initIterator(SkPictureStateTree::Iterator* iter,
SkCanvas* canvas,
const SkPicture::OperationList *activeOpsList) {
@ -172,9 +169,9 @@ void SkPicturePlayback::draw(SkCanvas* canvas, SkDrawPictureCallback* callback)
}
}
void SkPicturePlayback::handleOp(SkReader32* reader,
DrawType op,
uint32_t size,
void SkPicturePlayback::handleOp(SkReader32* reader,
DrawType op,
uint32_t size,
SkCanvas* canvas,
const SkMatrix& initialMatrix) {
switch (op) {
@ -310,7 +307,7 @@ void SkPicturePlayback::handleOp(SkReader32* reader,
break;
case DRAW_PATCH: {
const SkPaint& paint = *fPictureData->getPaint(reader);
const SkPoint* cubics = (const SkPoint*)reader->skip(SkPatchUtils::kNumCtrlPts *
sizeof(SkPoint));
uint32_t flag = reader->readInt();

View File

@ -44,7 +44,14 @@ SkRTree::~SkRTree() {
this->clear();
}
void SkRTree::insert(void* data, const SkIRect& bounds, bool defer) {
void SkRTree::insert(void* data, const SkRect& fbounds, bool defer) {
SkIRect bounds;
if (fbounds.isLargest()) {
bounds.setLargest();
} else {
fbounds.roundOut(&bounds);
}
this->validate();
if (bounds.isEmpty()) {
SkASSERT(false);
@ -102,7 +109,9 @@ void SkRTree::flushDeferredInserts() {
this->validate();
}
void SkRTree::search(const SkIRect& query, SkTDArray<void*>* results) const {
void SkRTree::search(const SkRect& fquery, SkTDArray<void*>* results) const {
SkIRect query;
fquery.roundOut(&query);
this->validate();
SkASSERT(0 == fDeferredInserts.count()); // If this fails, you should have flushed.
if (!this->isEmpty() && SkIRect::IntersectsNoEmptyCheck(fRoot.fBounds, query)) {

View File

@ -67,7 +67,7 @@ public:
* @param bounds The corresponding bounding box
* @param defer Can this insert be deferred? (this may be ignored)
*/
virtual void insert(void* data, const SkIRect& bounds, bool defer = false) SK_OVERRIDE;
virtual void insert(void* data, const SkRect& bounds, bool defer = false) SK_OVERRIDE;
/**
* If any inserts have been deferred, this will add them into the tree
@ -77,7 +77,7 @@ public:
/**
* Given a query rectangle, populates the passed-in array with the elements it intersects
*/
virtual void search(const SkIRect& query, SkTDArray<void*>* results) const SK_OVERRIDE;
virtual void search(const SkRect& query, SkTDArray<void*>* results) const SK_OVERRIDE;
virtual void clear() SK_OVERRIDE;
bool isEmpty() const { return 0 == fCount; }

View File

@ -16,15 +16,12 @@ void SkRecordDraw(const SkRecord& record,
if (NULL != bbh) {
// Draw only ops that affect pixels in the canvas's current clip.
SkIRect query;
// The SkRecord and BBH were recorded in identity space. This canvas
// is not necessarily in that same space. getClipBounds() returns us
// this canvas' clip bounds transformed back into identity space, which
// lets us query the BBH.
SkRect clipBounds = { 0, 0, 0, 0 };
(void)canvas->getClipBounds(&clipBounds);
clipBounds.roundOut(&query);
SkRect query = { 0, 0, 0, 0 };
(void)canvas->getClipBounds(&query);
SkTDArray<void*> ops;
bbh->search(query, &ops);
@ -123,7 +120,7 @@ public:
FillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) : fBounds(record.count()) {
// Calculate bounds for all ops. This won't go quite in order, so we'll need
// to store the bounds separately then feed them in to the BBH later in order.
const SkIRect largest = SkIRect::MakeLargest();
const Bounds largest = Bounds::MakeLargest();
fCTM = &SkMatrix::I();
fCurrentClipBounds = largest;
for (fCurrentOp = 0; fCurrentOp < record.count(); fCurrentOp++) {
@ -158,9 +155,12 @@ public:
}
private:
// In this file, SkRect are in local coordinates, Bounds are translated back to identity space.
typedef SkRect Bounds;
struct SaveBounds {
int controlOps; // Number of control ops in this Save block, including the Save.
SkIRect bounds; // Bounds of everything in the block.
Bounds bounds; // Bounds of everything in the block.
const SkPaint* paint; // Unowned. If set, adjusts the bounds of all ops in this block.
};
@ -171,11 +171,11 @@ private:
template <typename T> void updateClipBounds(const T&) { /* most ops don't change the clip */ }
// Each of these devBounds fields is the state of the device bounds after the op.
// So Restore's devBounds are those bounds saved by its paired Save or SaveLayer.
void updateClipBounds(const Restore& op) { fCurrentClipBounds = op.devBounds; }
void updateClipBounds(const ClipPath& op) { fCurrentClipBounds = op.devBounds; }
void updateClipBounds(const ClipRRect& op) { fCurrentClipBounds = op.devBounds; }
void updateClipBounds(const ClipRect& op) { fCurrentClipBounds = op.devBounds; }
void updateClipBounds(const ClipRegion& op) { fCurrentClipBounds = op.devBounds; }
void updateClipBounds(const Restore& op) { fCurrentClipBounds = Bounds::Make(op.devBounds); }
void updateClipBounds(const ClipPath& op) { fCurrentClipBounds = Bounds::Make(op.devBounds); }
void updateClipBounds(const ClipRRect& op) { fCurrentClipBounds = Bounds::Make(op.devBounds); }
void updateClipBounds(const ClipRect& op) { fCurrentClipBounds = Bounds::Make(op.devBounds); }
void updateClipBounds(const ClipRegion& op) { fCurrentClipBounds = Bounds::Make(op.devBounds); }
void updateClipBounds(const SaveLayer& op) {
if (op.bounds) {
fCurrentClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint));
@ -207,7 +207,7 @@ private:
void pushSaveBlock(const SkPaint* paint) {
// Starting a new Save block. Push a new entry to represent that.
SaveBounds sb = { 0, SkIRect::MakeEmpty(), paint };
SaveBounds sb = { 0, Bounds::MakeEmpty(), paint };
fSaveStack.push(sb);
this->pushControl();
}
@ -217,13 +217,13 @@ private:
return paint && (paint->getImageFilter() || paint->getColorFilter());
}
SkIRect popSaveBlock() {
Bounds popSaveBlock() {
// We're done the Save block. Apply the block's bounds to all control ops inside it.
SaveBounds sb;
fSaveStack.pop(&sb);
// If the paint affects transparent black, we can't trust any of our calculated bounds.
const SkIRect& bounds =
const Bounds& bounds =
PaintMayAffectTransparentBlack(sb.paint) ? fCurrentClipBounds : sb.bounds;
while (sb.controlOps --> 0) {
@ -244,12 +244,12 @@ private:
}
}
void popControl(const SkIRect& bounds) {
void popControl(const Bounds& bounds) {
fBounds[fControlIndices.top()] = bounds;
fControlIndices.pop();
}
void updateSaveBounds(const SkIRect& bounds) {
void updateSaveBounds(const Bounds& bounds) {
// If we're in a Save block, expand its bounds to cover these bounds too.
if (!fSaveStack.isEmpty()) {
fSaveStack.top().bounds.join(bounds);
@ -257,49 +257,49 @@ private:
}
// FIXME: this method could use better bounds
SkIRect bounds(const DrawText&) const { return fCurrentClipBounds; }
Bounds bounds(const DrawText&) const { return fCurrentClipBounds; }
SkIRect bounds(const Clear&) const { return SkIRect::MakeLargest(); } // Ignores the clip.
SkIRect bounds(const DrawPaint&) const { return fCurrentClipBounds; }
SkIRect bounds(const NoOp&) const { return SkIRect::MakeEmpty(); } // NoOps don't draw.
Bounds bounds(const Clear&) const { return Bounds::MakeLargest(); } // Ignores the clip.
Bounds bounds(const DrawPaint&) const { return fCurrentClipBounds; }
Bounds bounds(const NoOp&) const { return Bounds::MakeEmpty(); } // NoOps don't draw.
SkIRect bounds(const DrawSprite& op) const {
Bounds bounds(const DrawSprite& op) const {
const SkBitmap& bm = op.bitmap;
return SkIRect::MakeXYWH(op.left, op.top, bm.width(), bm.height()); // Ignores the matrix.
return Bounds::MakeXYWH(op.left, op.top, bm.width(), bm.height()); // Ignores the matrix.
}
SkIRect bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect, &op.paint); }
SkIRect bounds(const DrawOval& op) const { return this->adjustAndMap(op.oval, &op.paint); }
SkIRect bounds(const DrawRRect& op) const {
Bounds bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect, &op.paint); }
Bounds bounds(const DrawOval& op) const { return this->adjustAndMap(op.oval, &op.paint); }
Bounds bounds(const DrawRRect& op) const {
return this->adjustAndMap(op.rrect.rect(), &op.paint);
}
SkIRect bounds(const DrawDRRect& op) const {
Bounds bounds(const DrawDRRect& op) const {
return this->adjustAndMap(op.outer.rect(), &op.paint);
}
SkIRect bounds(const DrawBitmapRectToRect& op) const {
Bounds bounds(const DrawBitmapRectToRect& op) const {
return this->adjustAndMap(op.dst, op.paint);
}
SkIRect bounds(const DrawBitmapNine& op) const {
Bounds bounds(const DrawBitmapNine& op) const {
return this->adjustAndMap(op.dst, op.paint);
}
SkIRect bounds(const DrawBitmap& op) const {
Bounds bounds(const DrawBitmap& op) const {
const SkBitmap& bm = op.bitmap;
return this->adjustAndMap(SkRect::MakeXYWH(op.left, op.top, bm.width(), bm.height()),
op.paint);
}
SkIRect bounds(const DrawBitmapMatrix& op) const {
Bounds bounds(const DrawBitmapMatrix& op) const {
const SkBitmap& bm = op.bitmap;
SkRect dst = SkRect::MakeWH(bm.width(), bm.height());
op.matrix.mapRect(&dst);
return this->adjustAndMap(dst, op.paint);
}
SkIRect bounds(const DrawPath& op) const {
Bounds bounds(const DrawPath& op) const {
return op.path.isInverseFillType() ? fCurrentClipBounds
: this->adjustAndMap(op.path.getBounds(), &op.paint);
}
SkIRect bounds(const DrawPoints& op) const {
Bounds bounds(const DrawPoints& op) const {
SkRect dst;
dst.set(op.pts, op.count);
@ -309,18 +309,18 @@ private:
return this->adjustAndMap(dst, &op.paint);
}
SkIRect bounds(const DrawPatch& op) const {
Bounds bounds(const DrawPatch& op) const {
SkRect dst;
dst.set(op.cubics, SkPatchUtils::kNumCtrlPts);
return this->adjustAndMap(dst, &op.paint);
}
SkIRect bounds(const DrawVertices& op) const {
Bounds bounds(const DrawVertices& op) const {
SkRect dst;
dst.set(op.vertices, op.vertexCount);
return this->adjustAndMap(dst, &op.paint);
}
SkIRect bounds(const DrawPicture& op) const {
Bounds bounds(const DrawPicture& op) const {
SkRect dst = SkRect::MakeWH(op.picture->width(), op.picture->height());
if (op.matrix) {
op.matrix->mapRect(&dst);
@ -328,10 +328,10 @@ private:
return this->adjustAndMap(dst, op.paint);
}
SkIRect bounds(const DrawPosText& op) const {
Bounds bounds(const DrawPosText& op) const {
const int N = op.paint.countText(op.text, op.byteLength);
if (N == 0) {
return SkIRect::MakeEmpty();
return Bounds::MakeEmpty();
}
SkRect dst;
@ -339,10 +339,10 @@ private:
AdjustTextForFontMetrics(&dst, op.paint);
return this->adjustAndMap(dst, &op.paint);
}
SkIRect bounds(const DrawPosTextH& op) const {
Bounds bounds(const DrawPosTextH& op) const {
const int N = op.paint.countText(op.text, op.byteLength);
if (N == 0) {
return SkIRect::MakeEmpty();
return Bounds::MakeEmpty();
}
SkScalar left = op.xpos[0], right = op.xpos[0];
@ -354,7 +354,7 @@ private:
AdjustTextForFontMetrics(&dst, op.paint);
return this->adjustAndMap(dst, &op.paint);
}
SkIRect bounds(const DrawTextOnPath& op) const {
Bounds bounds(const DrawTextOnPath& op) const {
SkRect dst = op.path.getBounds();
// Pad all sides by the maximum padding in any direction we'd normally apply.
@ -370,7 +370,7 @@ private:
return this->adjustAndMap(dst, &op.paint);
}
SkIRect bounds(const DrawTextBlob& op) const {
Bounds bounds(const DrawTextBlob& op) const {
SkRect dst = op.blob->bounds();
dst.offset(op.x, op.y);
// TODO: remove when implicit bounds are plumbed through
@ -415,8 +415,8 @@ private:
return true;
}
// Adjust rect for all paints that may affect its geometry, then map it to device space.
SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) const {
// Adjust rect for all paints that may affect its geometry, then map it to identity space.
Bounds adjustAndMap(SkRect rect, const SkPaint* paint) const {
// Inverted rectangles really confuse our BBHs.
rect.sort();
@ -434,26 +434,24 @@ private:
}
}
// Map the rect back to device space.
// Map the rect back to identity space.
fCTM->mapRect(&rect);
SkIRect devRect;
rect.roundOut(&devRect);
// Nothing can draw outside the current clip.
// (Only bounded ops call into this method, so oddballs like Clear don't matter here.)
devRect.intersect(fCurrentClipBounds);
return devRect;
rect.intersect(fCurrentClipBounds);
return rect;
}
// Conservative device bounds for each op in the SkRecord.
SkAutoTMalloc<SkIRect> fBounds;
// Conservative identity-space bounds for each op in the SkRecord.
SkAutoTMalloc<Bounds> fBounds;
// We walk fCurrentOp through the SkRecord, as we go using updateCTM()
// and updateClipBounds() to maintain the exact CTM (fCTM) and conservative
// device bounds of the current clip (fCurrentClipBounds).
// identity-space bounds of the current clip (fCurrentClipBounds).
unsigned fCurrentOp;
const SkMatrix* fCTM;
SkIRect fCurrentClipBounds;
Bounds fCurrentClipBounds;
// Used to track the bounds of Save/Restore blocks and the control ops inside them.
SkTDArray<SaveBounds> fSaveStack;

View File

@ -23,13 +23,15 @@ SkTileGrid::~SkTileGrid() {
SkDELETE_ARRAY(fTiles);
}
void SkTileGrid::insert(void* data, const SkIRect& bounds, bool) {
SkASSERT(!bounds.isEmpty());
SkIRect dilatedBounds = bounds;
// Dilating the largest SkIRect will overflow. Other nearly-largest rects may overflow too,
// but we don't make active use of them like we do the largest.
if (!bounds.isLargest()) {
void SkTileGrid::insert(void* data, const SkRect& fbounds, bool) {
SkASSERT(!fbounds.isEmpty());
SkIRect dilatedBounds;
if (fbounds.isLargest()) {
// Dilating the largest SkIRect will overflow. Other nearly-largest rects may overflow too,
// but we don't make active use of them like we do the largest.
dilatedBounds.setLargest();
} else {
fbounds.roundOut(&dilatedBounds);
dilatedBounds.outset(fInfo.fMargin.width(), fInfo.fMargin.height());
dilatedBounds.offset(fInfo.fOffset);
}
@ -67,8 +69,9 @@ static int divide_ceil(int x, int y) {
// require 512 tiles of size 256 x 256 pixels.
static const int kStackAllocationTileCount = 1024;
void SkTileGrid::search(const SkIRect& query, SkTDArray<void*>* results) const {
SkIRect adjusted = query;
void SkTileGrid::search(const SkRect& query, SkTDArray<void*>* results) const {
SkIRect adjusted;
query.roundOut(&adjusted);
// The inset is to counteract the outset that was applied in 'insert'
// The outset/inset is to optimize for lookups of size

View File

@ -28,7 +28,7 @@ public:
* @param bounds The bounding box, should not be empty.
* @param defer Ignored; SkTileGrid does not defer insertions.
*/
virtual void insert(void* data, const SkIRect& bounds, bool) SK_OVERRIDE;
virtual void insert(void* data, const SkRect& bounds, bool) SK_OVERRIDE;
virtual void flushDeferredInserts() SK_OVERRIDE {};
@ -36,7 +36,7 @@ public:
* Populate 'results' with data pointers corresponding to bounding boxes that intersect 'query'.
* This will be fastest if the query is an exact match to a single grid tile.
*/
virtual void search(const SkIRect& query, SkTDArray<void*>* results) const SK_OVERRIDE;
virtual void search(const SkRect& query, SkTDArray<void*>* results) const SK_OVERRIDE;
virtual void clear() SK_OVERRIDE;

View File

@ -1617,7 +1617,7 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
CHECK_SHOULD_DRAW(draw, false);
GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawVertices", fContext);
const uint16_t* outIndices;
SkAutoTDeleteArray<uint16_t> outAlloc(NULL);
GrPrimitiveType primType;
@ -1625,13 +1625,13 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
// If both textures and vertex-colors are NULL, strokes hairlines with the paint's color.
if ((NULL == texs || NULL == paint.getShader()) && NULL == colors) {
texs = NULL;
SkPaint copy(paint);
copy.setStyle(SkPaint::kStroke_Style);
copy.setStrokeWidth(0);
// we ignore the shader if texs is null.
SkPaint2GrPaintNoShader(this->context(), copy, SkColor2GrColor(copy.getColor()),
NULL == colors, &grPaint);
@ -1648,13 +1648,13 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
triangleCount = n - 2;
break;
}
VertState state(vertexCount, indices, indexCount);
VertState::Proc vertProc = state.chooseProc(vmode);
//number of indices for lines per triangle with kLines
indexCount = triangleCount * 6;
outAlloc.reset(SkNEW_ARRAY(uint16_t, indexCount));
outIndices = outAlloc.get();
uint16_t* auxIndices = outAlloc.get();
@ -1671,7 +1671,7 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
} else {
outIndices = indices;
primType = gVertexMode2PrimitiveType[vmode];
if (NULL == texs || NULL == paint.getShader()) {
SkPaint2GrPaintNoShader(this->context(), paint, SkColor2GrColor(paint.getColor()),
NULL == colors, &grPaint);
@ -1879,7 +1879,7 @@ static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* re
// Return true if any layers are suitable for hoisting
bool SkGpuDevice::FindLayersToHoist(const GrAccelData *gpuData,
const SkPicture::OperationList* ops,
const SkIRect& query,
const SkRect& query,
bool* pullForward) {
bool anyHoisted = false;
@ -1929,12 +1929,12 @@ bool SkGpuDevice::FindLayersToHoist(const GrAccelData *gpuData,
for (int j = 0; j < gpuData->numSaveLayers(); ++j) {
const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(j);
SkIRect layerRect = SkIRect::MakeXYWH(info.fOffset.fX,
info.fOffset.fY,
info.fSize.fWidth,
info.fSize.fHeight);
SkRect layerRect = SkRect::MakeXYWH(SkIntToScalar(info.fOffset.fX),
SkIntToScalar(info.fOffset.fY),
SkIntToScalar(info.fSize.fWidth),
SkIntToScalar(info.fSize.fHeight));
if (!SkIRect::Intersects(query, layerRect)) {
if (!SkRect::Intersects(query, layerRect)) {
continue;
}
@ -1986,12 +1986,11 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
if (!mainCanvas->getClipBounds(&clipBounds)) {
return true;
}
SkIRect query;
clipBounds.roundOut(&query);
SkAutoTDelete<const SkPicture::OperationList> ops(picture->EXPERIMENTAL_getActiveOps(query));
SkAutoTDelete<const SkPicture::OperationList> ops(
picture->EXPERIMENTAL_getActiveOps(clipBounds));
if (!FindLayersToHoist(gpuData, ops.get(), query, pullForward.get())) {
if (!FindLayersToHoist(gpuData, ops.get(), clipBounds, pullForward.get())) {
return false;
}
@ -2005,9 +2004,9 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
if (pullForward[i]) {
const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture->uniqueID(),
info.fSaveLayerOpID,
info.fRestoreOpID,
GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture->uniqueID(),
info.fSaveLayerOpID,
info.fRestoreOpID,
info.fCTM);
SkPictureReplacementPlayback::PlaybackReplacements::ReplacementInfo* layerInfo =
@ -2030,7 +2029,7 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
}
layerInfo->fBM = SkNEW(SkBitmap); // fBM is allocated so ReplacementInfo can be POD
wrap_texture(layer->texture(),
wrap_texture(layer->texture(),
!layer->isAtlased() ? desc.fWidth : layer->texture()->width(),
!layer->isAtlased() ? desc.fHeight : layer->texture()->height(),
layerInfo->fBM);
@ -2066,7 +2065,7 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
}
void SkGpuDevice::drawLayers(const SkPicture* picture,
const SkTDArray<GrCachedLayer*>& atlased,
const SkTDArray<GrCachedLayer*>& atlased,
const SkTDArray<GrCachedLayer*>& nonAtlased) {
// Render the atlased layers that require it
if (atlased.count() > 0) {
@ -2171,7 +2170,7 @@ void SkGpuDevice::unlockLayers(const SkPicture* picture) {
}
#if DISABLE_CACHING
// This code completely clears out the atlas. It is required when
// This code completely clears out the atlas. It is required when
// caching is disabled so the atlas doesn't fill up and force more
// free floating layers
fContext->getLayerCache()->purge(picture->uniqueID());

View File

@ -17,20 +17,20 @@ static const int NUM_RECTS = 200;
static const size_t NUM_ITERATIONS = 100;
static const size_t NUM_QUERIES = 50;
static const int MAX_SIZE = 1000;
static const SkScalar MAX_SIZE = 1000.0f;
struct DataRect {
SkIRect rect;
SkRect rect;
void* data;
};
static SkIRect random_rect(SkRandom& rand) {
SkIRect rect = {0,0,0,0};
static SkRect random_rect(SkRandom& rand) {
SkRect rect = {0,0,0,0};
while (rect.isEmpty()) {
rect.fLeft = rand.nextS() % MAX_SIZE;
rect.fRight = rand.nextS() % MAX_SIZE;
rect.fTop = rand.nextS() % MAX_SIZE;
rect.fBottom = rand.nextS() % MAX_SIZE;
rect.fLeft = rand.nextRangeF(0, MAX_SIZE);
rect.fRight = rand.nextRangeF(0, MAX_SIZE);
rect.fTop = rand.nextRangeF(0, MAX_SIZE);
rect.fBottom = rand.nextRangeF(0, MAX_SIZE);
rect.sort();
}
return rect;
@ -43,12 +43,15 @@ static void random_data_rects(SkRandom& rand, DataRect out[], int n) {
}
}
static bool verify_query(SkIRect query, DataRect rects[],
static bool verify_query(SkRect query, DataRect rects[],
SkTDArray<void*>& found) {
// TODO(mtklein): no need to do this after everything's SkRects
query.roundOut();
SkTDArray<void*> expected;
// manually intersect with every rectangle
for (int i = 0; i < NUM_RECTS; ++i) {
if (SkIRect::IntersectsNoEmptyCheck(query, rects[i].rect)) {
if (SkRect::Intersects(query, rects[i].rect)) {
expected.push(rects[i].data);
}
}
@ -73,7 +76,7 @@ static void run_queries(skiatest::Reporter* reporter, SkRandom& rand, DataRect r
SkBBoxHierarchy& tree) {
for (size_t i = 0; i < NUM_QUERIES; ++i) {
SkTDArray<void*> hits;
SkIRect query = random_rect(rand);
SkRect query = random_rect(rand);
tree.search(query, &hits);
REPORTER_ASSERT(reporter, verify_query(query, rects, hits));
}

View File

@ -1808,12 +1808,12 @@ struct CountingBBH : public SkBBoxHierarchy {
CountingBBH() : searchCalls(0) {}
virtual void search(const SkIRect& query, SkTDArray<void*>* results) const {
virtual void search(const SkRect& query, SkTDArray<void*>* results) const {
this->searchCalls++;
}
// All other methods unimplemented.
virtual void insert(void* data, const SkIRect& bounds, bool defer) {}
virtual void insert(void* data, const SkRect& bounds, bool defer) {}
virtual void flushDeferredInserts() {}
virtual void clear() {}
virtual int getCount() const { return 0; }

View File

@ -18,17 +18,17 @@ static const size_t NUM_ITERATIONS = 100;
static const size_t NUM_QUERIES = 50;
struct DataRect {
SkIRect rect;
SkRect rect;
void* data;
};
static SkIRect random_rect(SkRandom& rand) {
SkIRect rect = {0,0,0,0};
static SkRect random_rect(SkRandom& rand) {
SkRect rect = {0,0,0,0};
while (rect.isEmpty()) {
rect.fLeft = rand.nextS() % 1000;
rect.fRight = rand.nextS() % 1000;
rect.fTop = rand.nextS() % 1000;
rect.fBottom = rand.nextS() % 1000;
rect.fLeft = rand.nextRangeF(0, 1000);
rect.fRight = rand.nextRangeF(0, 1000);
rect.fTop = rand.nextRangeF(0, 1000);
rect.fBottom = rand.nextRangeF(0, 1000);
rect.sort();
}
return rect;
@ -41,12 +41,16 @@ static void random_data_rects(SkRandom& rand, DataRect out[], int n) {
}
}
static bool verify_query(SkIRect query, DataRect rects[],
static bool verify_query(SkRect query, DataRect rects[],
SkTDArray<void*>& found) {
// TODO(mtklein): no need to do this after everything's SkRects
query.roundOut();
SkTDArray<void*> expected;
// manually intersect with every rectangle
for (int i = 0; i < NUM_RECTS; ++i) {
if (SkIRect::IntersectsNoEmptyCheck(query, rects[i].rect)) {
if (SkRect::Intersects(query, rects[i].rect)) {
expected.push(rects[i].data);
}
}
@ -71,7 +75,7 @@ static void run_queries(skiatest::Reporter* reporter, SkRandom& rand, DataRect r
SkRTree& tree) {
for (size_t i = 0; i < NUM_QUERIES; ++i) {
SkTDArray<void*> hits;
SkIRect query = random_rect(rand);
SkRect query = random_rect(rand);
tree.search(query, &hits);
REPORTER_ASSERT(reporter, verify_query(query, rects, hits));
}

View File

@ -97,7 +97,7 @@ DEF_TEST(RecordDraw_SetMatrixClobber, r) {
}
struct TestBBH : public SkBBoxHierarchy {
virtual void insert(void* data, const SkIRect& bounds, bool defer) SK_OVERRIDE {
virtual void insert(void* data, const SkRect& bounds, bool defer) SK_OVERRIDE {
Entry e = { (uintptr_t)data, bounds };
entries.push(e);
}
@ -105,14 +105,14 @@ struct TestBBH : public SkBBoxHierarchy {
virtual void flushDeferredInserts() SK_OVERRIDE {}
virtual void search(const SkIRect& query, SkTDArray<void*>* results) const SK_OVERRIDE {}
virtual void search(const SkRect& query, SkTDArray<void*>* results) const SK_OVERRIDE {}
virtual void clear() SK_OVERRIDE {}
virtual void rewindInserts() SK_OVERRIDE {}
virtual int getDepth() const SK_OVERRIDE { return -1; }
struct Entry {
uintptr_t data;
SkIRect bounds;
SkRect bounds;
};
SkTDArray<Entry> entries;
};
@ -137,6 +137,6 @@ DEF_TEST(RecordDraw_BBH, r) {
for (int i = 0; i < bbh.entries.count(); i++) {
REPORTER_ASSERT(r, bbh.entries[i].data == (uintptr_t)i);
REPORTER_ASSERT(r, bbh.entries[i].bounds == SkIRect::MakeWH(400, 480));
REPORTER_ASSERT(r, bbh.entries[i].bounds == SkRect::MakeWH(400, 480));
}
}

View File

@ -31,7 +31,7 @@ public:
SkTDArray<SkRect> fRects;
};
static void verifyTileHits(skiatest::Reporter* reporter, SkIRect rect,
static void verifyTileHits(skiatest::Reporter* reporter, SkRect rect,
uint32_t tileMask, int borderPixels = 0) {
SkTileGridFactory::TileGridInfo info;
info.fMargin.set(borderPixels, borderPixels);
@ -223,29 +223,29 @@ DEF_TEST(TileGrid_OverlapOffsetQueryAlignment, reporter) {
DEF_TEST(TileGrid, reporter) {
// Out of bounds
verifyTileHits(reporter, SkIRect::MakeXYWH(30, 0, 1, 1), 0);
verifyTileHits(reporter, SkIRect::MakeXYWH(0, 30, 1, 1), 0);
verifyTileHits(reporter, SkIRect::MakeXYWH(-10, 0, 1, 1), 0);
verifyTileHits(reporter, SkIRect::MakeXYWH(0, -10, 1, 1), 0);
verifyTileHits(reporter, SkRect::MakeXYWH(30, 0, 1, 1), 0);
verifyTileHits(reporter, SkRect::MakeXYWH(0, 30, 1, 1), 0);
verifyTileHits(reporter, SkRect::MakeXYWH(-10, 0, 1, 1), 0);
verifyTileHits(reporter, SkRect::MakeXYWH(0, -10, 1, 1), 0);
// Dilation for AA consideration
verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 9, 9), kTopLeft_Tile);
verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 10, 10), kAll_Tile);
verifyTileHits(reporter, SkIRect::MakeXYWH(9, 9, 1, 1), kAll_Tile);
verifyTileHits(reporter, SkIRect::MakeXYWH(10, 10, 1, 1), kAll_Tile);
verifyTileHits(reporter, SkIRect::MakeXYWH(11, 11, 1, 1), kBottomRight_Tile);
verifyTileHits(reporter, SkRect::MakeXYWH(0, 0, 9, 9), kTopLeft_Tile);
verifyTileHits(reporter, SkRect::MakeXYWH(0, 0, 10, 10), kAll_Tile);
verifyTileHits(reporter, SkRect::MakeXYWH(9, 9, 1, 1), kAll_Tile);
verifyTileHits(reporter, SkRect::MakeXYWH(10, 10, 1, 1), kAll_Tile);
verifyTileHits(reporter, SkRect::MakeXYWH(11, 11, 1, 1), kBottomRight_Tile);
// BorderPixels
verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 6, 6), kTopLeft_Tile, 1);
verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 7, 7), kAll_Tile, 1);
verifyTileHits(reporter, SkIRect::MakeXYWH(9, 9, 1, 1), kAll_Tile, 1);
verifyTileHits(reporter, SkIRect::MakeXYWH(10, 10, 1, 1), kBottomRight_Tile, 1);
verifyTileHits(reporter, SkIRect::MakeXYWH(17, 17, 1, 1), kBottomRight_Tile, 1);
verifyTileHits(reporter, SkRect::MakeXYWH(0, 0, 6, 6), kTopLeft_Tile, 1);
verifyTileHits(reporter, SkRect::MakeXYWH(0, 0, 7, 7), kAll_Tile, 1);
verifyTileHits(reporter, SkRect::MakeXYWH(9, 9, 1, 1), kAll_Tile, 1);
verifyTileHits(reporter, SkRect::MakeXYWH(10, 10, 1, 1), kBottomRight_Tile, 1);
verifyTileHits(reporter, SkRect::MakeXYWH(17, 17, 1, 1), kBottomRight_Tile, 1);
// BBoxes that overlap tiles
verifyTileHits(reporter, SkIRect::MakeXYWH(5, 5, 10, 1), kTopLeft_Tile | kTopRight_Tile);
verifyTileHits(reporter, SkIRect::MakeXYWH(5, 5, 1, 10), kTopLeft_Tile |
verifyTileHits(reporter, SkRect::MakeXYWH(5, 5, 10, 1), kTopLeft_Tile | kTopRight_Tile);
verifyTileHits(reporter, SkRect::MakeXYWH(5, 5, 1, 10), kTopLeft_Tile |
kBottomLeft_Tile);
verifyTileHits(reporter, SkIRect::MakeXYWH(5, 5, 10, 10), kAll_Tile);
verifyTileHits(reporter, SkIRect::MakeXYWH(-10, -10, 40, 40), kAll_Tile);
verifyTileHits(reporter, SkRect::MakeXYWH(5, 5, 10, 10), kAll_Tile);
verifyTileHits(reporter, SkRect::MakeXYWH(-10, -10, 40, 40), kAll_Tile);
}