Remove SkTileGrid (except for TileGridInfo).

TBR=reed@google.com

BUG=skia:3085

Review URL: https://codereview.chromium.org/845623002
This commit is contained in:
mtklein 2015-01-09 06:41:48 -08:00 committed by Commit bot
parent 9250543c55
commit 703dd2ed18
20 changed files with 22 additions and 677 deletions

View File

@ -144,7 +144,7 @@ DEF_BENCH( return new PosTextPlaybackBench(false); )
// Chrome draws into small tiles with impl-side painting.
// This benchmark measures the relative performance of our bounding-box hierarchies,
// both when querying tiles perfectly and when not.
enum BBH { kNone, kRTree, kTileGrid };
enum BBH { kNone, kRTree };
enum Mode { kTiled, kRandom };
class TiledPlaybackBench : public Benchmark {
public:
@ -152,7 +152,6 @@ public:
switch (fBBH) {
case kNone: fName.append("_none" ); break;
case kRTree: fName.append("_rtree" ); break;
case kTileGrid: fName.append("_tilegrid"); break;
}
switch (fMode) {
case kTiled: fName.append("_tiled" ); break;
@ -164,12 +163,10 @@ public:
virtual SkIPoint onGetSize() SK_OVERRIDE { return SkIPoint::Make(1024,1024); }
virtual void onPreDraw() SK_OVERRIDE {
SkTileGridFactory::TileGridInfo info = { { 256, 256 }, {0,0}, {0,0} };
SkAutoTDelete<SkBBHFactory> factory;
switch (fBBH) {
case kNone: break;
case kRTree: factory.reset(new SkRTreeFactory); break;
case kTileGrid: factory.reset(new SkTileGridFactory(info)); break;
}
SkPictureRecorder recorder;
@ -220,5 +217,3 @@ DEF_BENCH( return new TiledPlaybackBench(kNone, kRandom); )
DEF_BENCH( return new TiledPlaybackBench(kNone, kTiled ); )
DEF_BENCH( return new TiledPlaybackBench(kRTree, kRandom); )
DEF_BENCH( return new TiledPlaybackBench(kRTree, kTiled ); )
DEF_BENCH( return new TiledPlaybackBench(kTileGrid, kRandom); )
DEF_BENCH( return new TiledPlaybackBench(kTileGrid, kTiled ); )

View File

@ -36,7 +36,6 @@ void CpuGMTask::draw() {
SPAWN(QuiltTask, fGMFactory(NULL), bm, QuiltTask::kNone_BBH);
SPAWN(QuiltTask, fGMFactory(NULL), bm, QuiltTask::kRTree_BBH);
SPAWN(QuiltTask, fGMFactory(NULL), bm, QuiltTask::kTileGrid_BBH);
SPAWN(SerializeTask, fGMFactory(NULL), bm);

View File

@ -48,15 +48,6 @@ void QuiltTask::draw() {
case kRTree_BBH:
factory.reset(SkNEW(SkRTreeFactory));
break;
case kTileGrid_BBH: {
const SkTileGridFactory::TileGridInfo tiles = {
{ FLAGS_quiltTile, FLAGS_quiltTile },
/*overlap: */{0, 0},
/*offset: */{0, 0},
};
factory.reset(SkNEW_ARGS(SkTileGridFactory, (tiles)));
break;
}
}
// A couple GMs draw wrong when using a bounding box hierarchy.

View File

@ -16,7 +16,6 @@ public:
enum BBH {
kNone_BBH,
kRTree_BBH,
kTileGrid_BBH,
};
QuiltTask(const Task& parent, // QuiltTask must be a child task. Pass its parent here.

View File

@ -142,7 +142,6 @@ enum Backend {
enum BbhType {
kNone_BbhType,
kRTree_BbhType,
kTileGrid_BbhType,
};
enum ConfigFlags {
@ -1039,13 +1038,7 @@ public:
SkScalar height = SkScalarMul(SkIntToScalar(gm->getISize().height()), scale);
SkAutoTDelete<SkBBHFactory> factory;
if (kTileGrid_BbhType == bbhType) {
SkTileGridFactory::TileGridInfo info;
info.fMargin.setEmpty();
info.fOffset.setZero();
info.fTileInterval.set(16, 16);
factory.reset(SkNEW_ARGS(SkTileGridFactory, (info)));
} else if (kRTree_BbhType == bbhType) {
if (kRTree_BbhType == bbhType) {
factory.reset(SkNEW(SkRTreeFactory));
}
SkPictureRecorder recorder;
@ -1175,7 +1168,7 @@ public:
const SkISize& size,
GrSurface* gpuTarget) {
if (config.fBackend == kRaster_Backend) {
SkImageInfo ii = SkImageInfo::Make(size.width(), size.height(),
SkImageInfo ii = SkImageInfo::Make(size.width(), size.height(),
config.fColorType, kPremul_SkAlphaType);
return SkSurface::NewRaster(ii);
@ -1725,41 +1718,6 @@ ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm,
}
}
if (FLAGS_tileGrid) {
for(int scaleIndex = 0; scaleIndex < tileGridReplayScales.count(); ++scaleIndex) {
SkScalar replayScale = tileGridReplayScales[scaleIndex];
SkString renderModeDescriptor("-tilegrid");
if (SK_Scalar1 != replayScale) {
renderModeDescriptor += "-scale-";
renderModeDescriptor.appendScalar(replayScale);
}
if ((gmFlags & GM::kSkipPicture_Flag) ||
(gmFlags & GM::kSkipTiled_Flag) ||
((gmFlags & GM::kSkipScaledReplay_Flag) && replayScale != 1)) {
gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
renderModeDescriptor.c_str());
errorsForAllModes.add(kIntentionallySkipped_ErrorType);
} else {
// We record with the reciprocal scale to obtain a replay
// result that can be validated against comparisonBitmap.
SkScalar recordScale = SkScalarInvert(replayScale);
SkPicture* pict = gmmain.generate_new_picture(
gm, kTileGrid_BbhType, 0, recordScale);
SkAutoTUnref<SkPicture> aur(pict);
SkBitmap bitmap;
// We cannot yet pass 'true' to generate_image_from_picture to
// perform actual tiled rendering (see Issue 1198 -
// https://code.google.com/p/skia/issues/detail?id=1198)
gmmain.generate_image_from_picture(gm, compareConfig, gpuTarget, pict, &bitmap,
replayScale /*, true */);
errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
gm->getName(), compareConfig.fName, renderModeDescriptor.c_str(), bitmap,
&comparisonBitmap));
}
}
}
// run the pipe centric GM steps
if (FLAGS_pipe) {
errorsForAllModes.add(gmmain.test_pipe_playback(gm, compareConfig, comparisonBitmap,
@ -1909,7 +1867,7 @@ ErrorCombination run_multiple_configs(GMMain &gmmain, GM *gm,
config.fBackend);
errorsForThisConfig.add(kIntentionallySkipped_ErrorType);
} else if (!(gmFlags & GM::kGPUOnly_Flag)) {
errorsForThisConfig.add(gmmain.testMPDDrawing(gm, config,
errorsForThisConfig.add(gmmain.testMPDDrawing(gm, config,
writePath, gpuTarget,
comparisonBitmap));
}

View File

@ -201,8 +201,6 @@
'<(skia_src_path)/core/SkTextFormatParams.h',
'<(skia_src_path)/core/SkTextMapStateProc.h',
'<(skia_src_path)/core/SkTHashCache.h',
'<(skia_src_path)/core/SkTileGrid.cpp',
'<(skia_src_path)/core/SkTileGrid.h',
'<(skia_src_path)/core/SkTLList.h',
'<(skia_src_path)/core/SkTLS.cpp',
'<(skia_src_path)/core/SkTraceEvent.h',

View File

@ -207,7 +207,6 @@
'../tests/TSetTest.cpp',
'../tests/TextBlobTest.cpp',
'../tests/TextureCompressionTest.cpp',
'../tests/TileGridTest.cpp',
'../tests/ToUnicodeTest.cpp',
'../tests/TracingTest.cpp',
'../tests/TypefaceTest.cpp',

View File

@ -29,7 +29,8 @@ private:
typedef SkBBHFactory INHERITED;
};
class SK_API SkTileGridFactory : public SkBBHFactory {
// TODO(mtklein): delete entirely when Chromium's clean for TileGridInfo
class SK_API SkTileGridFactory {
public:
struct TileGridInfo {
/** Tile placement interval */
@ -47,15 +48,6 @@ public:
*/
SkIPoint fOffset;
};
SkTileGridFactory(const TileGridInfo& info) : fInfo(info) { }
virtual SkBBoxHierarchy* operator()(const SkRect& bounds) const SK_OVERRIDE;
private:
TileGridInfo fInfo;
typedef SkBBHFactory INHERITED;
};
#endif

View File

@ -50,7 +50,6 @@ public:
virtual void onTileSizeChanged(const SkSize &tileSize) SK_OVERRIDE {
if (tileSize != fTileSize) {
fTileSize = tileSize;
SkSafeSetNull(fPictures[kTileGrid_BBoxType]);
}
}
@ -68,9 +67,6 @@ protected:
case kRTree_BBoxType:
name.append(" <bbox: R>");
break;
case kTileGrid_BBoxType:
name.append(" <bbox: T>");
break;
default:
SkASSERT(false);
break;
@ -105,9 +101,8 @@ private:
enum BBoxType {
kNo_BBoxType,
kRTree_BBoxType,
kTileGrid_BBoxType,
kLast_BBoxType = kTileGrid_BBoxType
kLast_BBoxType = kRTree_BBoxType,
};
static const int kBBoxTypeCount = kLast_BBoxType + 1;
@ -123,8 +118,8 @@ private:
if (SkImageDecoder::DecodeFile(path, &bm)) {
bm.setImmutable();
SkPictureRecorder recorder;
SkCanvas* can = recorder.beginRecording(SkIntToScalar(bm.width()),
SkIntToScalar(bm.height()),
SkCanvas* can = recorder.beginRecording(SkIntToScalar(bm.width()),
SkIntToScalar(bm.height()),
NULL, 0);
can->drawBitmap(bm, 0, 0, NULL);
pic.reset(recorder.endRecording());
@ -139,7 +134,7 @@ private:
if (false) { // re-record
SkPictureRecorder recorder;
pic->playback(recorder.beginRecording(pic->cullRect().width(),
pic->cullRect().height(),
pic->cullRect().height(),
NULL, 0));
SkAutoTUnref<SkPicture> p2(recorder.endRecording());
@ -162,22 +157,13 @@ private:
case kRTree_BBoxType:
factory.reset(SkNEW(SkRTreeFactory));
break;
case kTileGrid_BBoxType: {
SkASSERT(!fTileSize.isEmpty());
SkTileGridFactory::TileGridInfo gridInfo;
gridInfo.fMargin = SkISize::Make(0, 0);
gridInfo.fOffset = SkIPoint::Make(0, 0);
gridInfo.fTileInterval = fTileSize.toRound();
factory.reset(SkNEW_ARGS(SkTileGridFactory, (gridInfo)));
break;
}
default:
SkASSERT(false);
}
SkPictureRecorder recorder;
pic->playback(recorder.beginRecording(pic->cullRect().width(),
pic->cullRect().height(),
pic->cullRect().height(),
factory.get(), 0));
return recorder.endRecording();
}

View File

@ -7,27 +7,8 @@
#include "SkBBHFactory.h"
#include "SkRTree.h"
#include "SkTileGrid.h"
SkBBoxHierarchy* SkRTreeFactory::operator()(const SkRect& bounds) const {
SkScalar aspectRatio = bounds.width() / bounds.height();
return SkNEW_ARGS(SkRTree, (aspectRatio));
}
SkBBoxHierarchy* SkTileGridFactory::operator()(const SkRect& bounds) const {
SkASSERT(fInfo.fMargin.width() >= 0);
SkASSERT(fInfo.fMargin.height() >= 0);
// We want a conservative answer for the size...
const SkIRect ibounds = bounds.roundOut();
const int width = ibounds.width();
const int height = ibounds.height();
// Note: SkIRects are non-inclusive of the right() column and bottom() row.
// For example, an SkIRect at 0,0 with a size of (1,1) will only have
// content at pixel (0,0) and will report left=0 and right=1, hence the
// "-1"s below.
int xTileCount = (width + fInfo.fTileInterval.width() - 1) / fInfo.fTileInterval.width();
int yTileCount = (height + fInfo.fTileInterval.height() - 1) / fInfo.fTileInterval.height();
return SkNEW_ARGS(SkTileGrid, (xTileCount, yTileCount, fInfo));
}

View File

@ -1,188 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkTileGrid.h"
SkTileGrid::SkTileGrid(int xTiles, int yTiles, const SkTileGridFactory::TileGridInfo& info)
: fXTiles(xTiles)
, fYTiles(yTiles)
, fInvWidth( SkScalarInvert(info.fTileInterval.width()))
, fInvHeight(SkScalarInvert(info.fTileInterval.height()))
, fMarginWidth (info.fMargin.fWidth +1) // Margin is offset by 1 as a provision for AA and
, fMarginHeight(info.fMargin.fHeight+1) // to cancel the outset applied by getClipDeviceBounds.
, fOffset(SkPoint::Make(info.fOffset.fX, info.fOffset.fY))
, fGridBounds(SkRect::MakeWH(xTiles * info.fTileInterval.width(),
yTiles * info.fTileInterval.height()))
, fTiles(SkNEW_ARRAY(SkTDArray<unsigned>, xTiles * yTiles)) {}
SkTileGrid::~SkTileGrid() {
SkDELETE_ARRAY(fTiles);
}
void SkTileGrid::reserve(int opCount) {
if (fXTiles * fYTiles == 0) {
return; // A tileless tile grid is nonsensical, but happens in at least cc_unittests.
}
// If we assume every op we're about to try to insert() falls within our grid bounds,
// then every op has to hit at least one tile. In fact, a quick scan over our small
// SKP set shows that in the average SKP, each op hits two 256x256 tiles.
// If we take those observations and further assume the ops are distributed evenly
// across the picture, we get this guess for number of ops per tile:
const int opsPerTileGuess = (2 * opCount) / (fXTiles * fYTiles);
for (SkTDArray<unsigned>* tile = fTiles; tile != fTiles + (fXTiles * fYTiles); tile++) {
tile->setReserve(opsPerTileGuess);
}
// In practice, this heuristic means we'll temporarily allocate about 30% more bytes
// than if we made no setReserve() calls, but time spent in insert() drops by about 50%.
}
void SkTileGrid::shrinkToFit() {
for (SkTDArray<unsigned>* tile = fTiles; tile != fTiles + (fXTiles * fYTiles); tile++) {
tile->shrinkToFit();
}
}
// Adjustments to user-provided bounds common to both insert() and search().
// Call this after making insert- or search- specific adjustments.
void SkTileGrid::commonAdjust(SkRect* rect) const {
// Apply our offset.
rect->offset(fOffset);
// Scrunch the bounds in just a little to make the right and bottom edges
// exclusive. We want bounds of exactly one tile to hit exactly one tile.
rect->fRight -= SK_ScalarNearlyZero;
rect->fBottom -= SK_ScalarNearlyZero;
}
// Convert user-space bounds to grid tiles they cover (LT and RB both inclusive).
void SkTileGrid::userToGrid(const SkRect& user, SkIRect* grid) const {
grid->fLeft = SkPin32(user.left() * fInvWidth , 0, fXTiles - 1);
grid->fTop = SkPin32(user.top() * fInvHeight, 0, fYTiles - 1);
grid->fRight = SkPin32(user.right() * fInvWidth , 0, fXTiles - 1);
grid->fBottom = SkPin32(user.bottom() * fInvHeight, 0, fYTiles - 1);
}
void SkTileGrid::insert(SkAutoTMalloc<SkRect>* boundsArray, int N) {
this->reserve(N);
for (int i = 0; i < N; i++) {
SkRect bounds = (*boundsArray)[i];
bounds.outset(fMarginWidth, fMarginHeight);
this->commonAdjust(&bounds);
// TODO(mtklein): can we assert this instead to save an intersection in Release mode,
// or just allow out-of-bound insertions to insert anyway (clamped to nearest tile)?
if (!SkRect::Intersects(bounds, fGridBounds)) {
continue;
}
SkIRect grid;
this->userToGrid(bounds, &grid);
// This is just a loop over y then x. This compiles to a slightly faster and
// more compact loop than if we just did fTiles[y * fXTiles + x].push(i).
SkTDArray<unsigned>* row = &fTiles[grid.fTop * fXTiles + grid.fLeft];
for (int y = 0; y <= grid.fBottom - grid.fTop; y++) {
SkTDArray<unsigned>* tile = row;
for (int x = 0; x <= grid.fRight - grid.fLeft; x++) {
(tile++)->push(i);
}
row += fXTiles;
}
}
this->shrinkToFit();
}
// Number of tiles for which data is allocated on the stack in
// SkTileGrid::search. If malloc becomes a bottleneck, we may consider
// increasing this number. Typical large web page, say 2k x 16k, would
// require 512 tiles of size 256 x 256 pixels.
static const int kStackAllocationTileCount = 1024;
void SkTileGrid::search(const SkRect& originalQuery, SkTDArray<unsigned>* results) const {
// The inset counteracts the outset that applied in 'insert', which optimizes
// for lookups of size 'tileInterval + 2 * margin' (aligned with the tile grid).
SkRect query = originalQuery;
query.inset(fMarginWidth, fMarginHeight);
this->commonAdjust(&query);
// The inset may have inverted the rectangle, so sort().
// TODO(mtklein): It looks like we only end up with inverted bounds in unit tests
// that make explicitly inverted queries, not from insetting. If we can drop support for
// unsorted bounds (i.e. we don't see them outside unit tests), I think we can drop this.
query.sort();
// No intersection check. We optimize for queries that are in bounds.
// We're safe anyway: userToGrid() will clamp out-of-bounds queries to nearest tile.
SkIRect grid;
this->userToGrid(query, &grid);
const int tilesHit = (grid.fRight - grid.fLeft + 1) * (grid.fBottom - grid.fTop + 1);
SkASSERT(tilesHit > 0);
if (tilesHit == 1) {
// A performance shortcut. The merging code below would work fine here too.
*results = fTiles[grid.fTop * fXTiles + grid.fLeft];
return;
}
// We've got to merge the data in many tiles into a single sorted and deduplicated stream.
// We do a simple k-way merge based on the value of opIndex.
// Gather pointers to the starts and ends of the tiles to merge.
SkAutoSTArray<kStackAllocationTileCount, const unsigned*> starts(tilesHit), ends(tilesHit);
int i = 0;
for (int y = grid.fTop; y <= grid.fBottom; y++) {
for (int x = grid.fLeft; x <= grid.fRight; x++) {
starts[i] = fTiles[y * fXTiles + x].begin();
ends[i] = fTiles[y * fXTiles + x].end();
i++;
}
}
// Merge tiles into results until they're fully consumed.
results->reset();
while (true) {
// The tiles themselves are already ordered, so the earliest op is at the front of some
// tile. It may be at the front of several, even all, tiles.
unsigned earliest = SK_MaxU32;
for (int i = 0; i < starts.count(); i++) {
if (starts[i] < ends[i]) {
earliest = SkTMin(earliest, *starts[i]);
}
}
// If we didn't find an earliest op, there isn't anything left to merge.
if (SK_MaxU32 == earliest) {
return;
}
// We did find an earliest op. Output it, and step forward every tile that contains it.
results->push(earliest);
for (int i = 0; i < starts.count(); i++) {
if (starts[i] < ends[i] && *starts[i] == earliest) {
starts[i]++;
}
}
}
}
size_t SkTileGrid::bytesUsed() const {
size_t byteCount = sizeof(SkTileGrid);
size_t opCount = 0;
for (int i = 0; i < fXTiles * fYTiles; i++) {
opCount += fTiles[i].reserved();
}
byteCount += opCount * sizeof(unsigned);
return byteCount;
}

View File

@ -1,51 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkTileGrid_DEFINED
#define SkTileGrid_DEFINED
#include "SkBBHFactory.h"
#include "SkBBoxHierarchy.h"
/**
* Subclass of SkBBoxHierarchy that stores elements in buckets that correspond
* to tile regions, disposed in a regular grid. This is useful when the tile
* structure that will be use in search() calls is known prior to insertion.
*/
class SkTileGrid : public SkBBoxHierarchy {
public:
SkTileGrid(int xTiles, int yTiles, const SkTileGridFactory::TileGridInfo& info);
virtual ~SkTileGrid();
virtual void insert(SkAutoTMalloc<SkRect>* boundsArray, int N) SK_OVERRIDE;
virtual void search(const SkRect& query, SkTDArray<unsigned>* results) const SK_OVERRIDE;
// For testing.
int tileCount(int x, int y) { return fTiles[y * fXTiles + x].count(); }
virtual size_t bytesUsed() const SK_OVERRIDE;
private:
void reserve(int);
void shrinkToFit();
void commonAdjust(SkRect*) const;
void userToGrid(const SkRect&, SkIRect* grid) const;
const int fXTiles, fYTiles;
const SkScalar fInvWidth, fInvHeight;
const SkScalar fMarginWidth, fMarginHeight;
const SkPoint fOffset;
const SkRect fGridBounds;
// (fXTiles * fYTiles) SkTDArrays, each listing ops overlapping that tile in order.
SkTDArray<unsigned>* fTiles;
typedef SkBBoxHierarchy INHERITED;
};
#endif

View File

@ -31,14 +31,6 @@ public:
// No BBH
this->run(NULL, reporter);
// With a Tile Grid
SkTileGridFactory::TileGridInfo gridInfo;
gridInfo.fMargin.setEmpty();
gridInfo.fOffset.setZero();
gridInfo.fTileInterval.set(1, 1);
SkTileGridFactory gridFactory(gridInfo);
this->run(&gridFactory, reporter);
// With an R-Tree
SkRTreeFactory RTreeFactory;
this->run(&RTreeFactory, reporter);

View File

@ -107,8 +107,7 @@ class PictureStrategy : public RecordingStrategy {
virtual const SkBitmap& recordAndReplay(const Drawer& drawer,
const SkRect& intoClip,
SkXfermode::Mode mode) {
SkTileGridFactory::TileGridInfo tileGridInfo = { {100,100}, {0,0}, {0,0} };
SkTileGridFactory factory(tileGridInfo);
SkRTreeFactory factory;
SkPictureRecorder recorder;
SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fWidth),SkIntToScalar(fHeight)));
SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(fWidth),

View File

@ -1,254 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkCanvas.h"
#include "SkPictureRecorder.h"
#include "SkTileGrid.h"
#include "Test.h"
enum Tile {
kTopLeft_Tile = 0x1,
kTopRight_Tile = 0x2,
kBottomLeft_Tile = 0x4,
kBottomRight_Tile = 0x8,
kAll_Tile = kTopLeft_Tile | kTopRight_Tile | kBottomLeft_Tile | kBottomRight_Tile,
};
class MockCanvas : public SkCanvas {
public:
MockCanvas(const SkBitmap& bm) : SkCanvas(bm) {}
void onDrawRect(const SkRect& rect, const SkPaint&) SK_OVERRIDE {
// This capture occurs before quick reject.
fRects.push(rect);
}
SkTDArray<SkRect> fRects;
};
static void verify_tile_hits(skiatest::Reporter* reporter, SkRect rect,
uint32_t tileMask, int borderPixels = 0) {
SkTileGridFactory::TileGridInfo info;
info.fMargin.set(borderPixels, borderPixels);
info.fOffset.setZero();
info.fTileInterval.set(10 - 2 * borderPixels, 10 - 2 * borderPixels);
SkAutoTMalloc<SkRect> rects(1);
rects[0] = rect;
SkTileGrid grid(2, 2, info);
grid.insert(&rects, 1);
REPORTER_ASSERT(reporter, grid.tileCount(0, 0) ==
((tileMask & kTopLeft_Tile)? 1 : 0));
REPORTER_ASSERT(reporter, grid.tileCount(1, 0) ==
((tileMask & kTopRight_Tile)? 1 : 0));
REPORTER_ASSERT(reporter, grid.tileCount(0, 1) ==
((tileMask & kBottomLeft_Tile)? 1 : 0));
REPORTER_ASSERT(reporter, grid.tileCount(1, 1) ==
((tileMask & kBottomRight_Tile)? 1 : 0));
}
DEF_TEST(TileGrid_UnalignedQuery, reporter) {
// Use SkTileGridPicture to generate a SkTileGrid with a helper
SkTileGridFactory::TileGridInfo info;
info.fMargin.setEmpty();
info.fOffset.setZero();
info.fTileInterval.set(10, 10);
SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
SkIntToScalar(8), SkIntToScalar(8));
SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(11), SkIntToScalar(11),
SkIntToScalar(1), SkIntToScalar(1));
SkTileGridFactory factory(info);
SkPictureRecorder recorder;
SkCanvas* canvas = recorder.beginRecording(20, 20, &factory, 0);
SkPaint paint;
canvas->drawRect(rect1, paint);
canvas->drawRect(rect2, paint);
SkAutoTUnref<SkPicture> picture(recorder.endRecording());
SkBitmap store;
store.allocN32Pixels(1, 1);
// Test parts of top-left tile
{
MockCanvas mockCanvas(store);
picture->playback(&mockCanvas);
REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
}
{
MockCanvas mockCanvas(store);
mockCanvas.translate(-7.99f, -7.99f);
picture->playback(&mockCanvas);
REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
}
// Corner overlap
{
MockCanvas mockCanvas(store);
mockCanvas.translate(-9.5f, -9.5f);
picture->playback(&mockCanvas);
REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[1]);
}
// Intersect bottom right tile, but does not overlap rect 2
{
MockCanvas mockCanvas(store);
mockCanvas.translate(-16.0f, -16.0f);
picture->playback(&mockCanvas);
REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
}
// Out of bounds queries, snap to border tiles
{
MockCanvas mockCanvas(store);
mockCanvas.translate(2.0f, 0.0f);
picture->playback(&mockCanvas);
REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
}
{
MockCanvas mockCanvas(store);
mockCanvas.translate(0.0f, 2.0f);
picture->playback(&mockCanvas);
REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
}
{
MockCanvas mockCanvas(store);
mockCanvas.translate(-22.0f, -16.0f);
picture->playback(&mockCanvas);
REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
}
{
MockCanvas mockCanvas(store);
mockCanvas.translate(-16.0f, -22.0f);
picture->playback(&mockCanvas);
REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
}
}
DEF_TEST(TileGrid_OverlapOffsetQueryAlignment, reporter) {
// Use SkTileGridPicture to generate a SkTileGrid with a helper
SkTileGridFactory::TileGridInfo info;
info.fMargin.set(1, 1);
info.fOffset.set(-1, -1);
info.fTileInterval.set(8, 8);
// rect landing entirely in top left tile
SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
SkIntToScalar(1), SkIntToScalar(1));
// rect landing entirely in center tile
SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(12), SkIntToScalar(12),
SkIntToScalar(1), SkIntToScalar(1));
// rect landing entirely in bottomright tile
SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(19), SkIntToScalar(19),
SkIntToScalar(1), SkIntToScalar(1));
SkTileGridFactory factory(info);
SkPictureRecorder recorder;
SkCanvas* canvas = recorder.beginRecording(20, 20, &factory, 0);
SkPaint paint;
canvas->drawRect(rect1, paint);
canvas->drawRect(rect2, paint);
canvas->drawRect(rect3, paint);
SkAutoTUnref<SkPicture> picture(recorder.endRecording());
SkBitmap tileBitmap;
tileBitmap.allocN32Pixels(10, 10);
SkBitmap moreThanATileBitmap;
moreThanATileBitmap.allocN32Pixels(11, 11);
SkBitmap tinyBitmap;
tinyBitmap.allocN32Pixels(2, 2);
// Test parts of top-left tile
{
// The offset should cancel the top and left borders of the top left tile
// So a look-up at interval 0-10 should be grid aligned,
MockCanvas mockCanvas(tileBitmap);
picture->playback(&mockCanvas);
REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
}
{
// Encroaching border by one pixel
MockCanvas mockCanvas(moreThanATileBitmap);
picture->playback(&mockCanvas);
REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[1]);
}
{
// Tile stride is 8 (tileWidth - 2 * border pixels
// so translating by 8, should make query grid-aligned
// with middle tile.
MockCanvas mockCanvas(tileBitmap);
mockCanvas.translate(SkIntToScalar(-8), SkIntToScalar(-8));
picture->playback(&mockCanvas);
REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
}
{
MockCanvas mockCanvas(tileBitmap);
mockCanvas.translate(-7.9f, -7.9f);
picture->playback(&mockCanvas);
REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[1]);
}
{
MockCanvas mockCanvas(tileBitmap);
mockCanvas.translate(-8.1f, -8.1f);
picture->playback(&mockCanvas);
REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
REPORTER_ASSERT(reporter, rect3 == mockCanvas.fRects[1]);
}
{
// Regression test for crbug.com/234688
// Once the 2x2 device region is inset by margin, it yields an empty
// adjusted region, sitting right on top of the tile boundary.
MockCanvas mockCanvas(tinyBitmap);
mockCanvas.translate(-8.0f, -8.0f);
picture->playback(&mockCanvas);
// This test passes by not asserting. We do not validate the rects recorded
// because the result is numerically unstable (floating point equality).
// The content of any one of the four tiles of the tilegrid would be a valid
// result since any bbox that covers the center point of the canvas will be
// recorded in all four tiles.
}
}
DEF_TEST(TileGrid, reporter) {
// Out of bounds
verify_tile_hits(reporter, SkRect::MakeXYWH(30, 0, 1, 1), 0);
verify_tile_hits(reporter, SkRect::MakeXYWH(0, 30, 1, 1), 0);
verify_tile_hits(reporter, SkRect::MakeXYWH(-10, 0, 1, 1), 0);
verify_tile_hits(reporter, SkRect::MakeXYWH(0, -10, 1, 1), 0);
// Dilation for AA consideration
verify_tile_hits(reporter, SkRect::MakeXYWH(0, 0, 9, 9), kTopLeft_Tile);
verify_tile_hits(reporter, SkRect::MakeXYWH(0, 0, 10, 10), kAll_Tile);
verify_tile_hits(reporter, SkRect::MakeXYWH(9, 9, 1, 1), kAll_Tile);
verify_tile_hits(reporter, SkRect::MakeXYWH(10, 10, 1, 1), kAll_Tile);
verify_tile_hits(reporter, SkRect::MakeXYWH(11, 11, 1, 1), kBottomRight_Tile);
// BorderPixels
verify_tile_hits(reporter, SkRect::MakeXYWH(0, 0, 6, 6), kTopLeft_Tile, 1);
verify_tile_hits(reporter, SkRect::MakeXYWH(0, 0, 7, 7), kAll_Tile, 1);
verify_tile_hits(reporter, SkRect::MakeXYWH(9, 9, 1, 1), kAll_Tile, 1);
verify_tile_hits(reporter, SkRect::MakeXYWH(10, 10, 1, 1), kBottomRight_Tile, 1);
verify_tile_hits(reporter, SkRect::MakeXYWH(17, 17, 1, 1), kBottomRight_Tile, 1);
// BBoxes that overlap tiles
verify_tile_hits(reporter, SkRect::MakeXYWH(5, 5, 10, 1), kTopLeft_Tile | kTopRight_Tile);
verify_tile_hits(reporter, SkRect::MakeXYWH(5, 5, 1, 10), kTopLeft_Tile | kBottomLeft_Tile);
verify_tile_hits(reporter, SkRect::MakeXYWH(5, 5, 10, 10), kAll_Tile);
verify_tile_hits(reporter, SkRect::MakeXYWH(-10, -10, 40, 40),kAll_Tile);
}

View File

@ -228,7 +228,7 @@ void PictureRenderer::buildBBoxHierarchy() {
if (fUseMultiPictureDraw) {
flags |= SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag;
}
SkCanvas* canvas = recorder.beginRecording(fPicture->cullRect().width(),
SkCanvas* canvas = recorder.beginRecording(fPicture->cullRect().width(),
fPicture->cullRect().height(),
factory.get(),
flags);
@ -376,7 +376,7 @@ public:
bool RecordPictureRenderer::render(SkBitmap** out) {
SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
SkPictureRecorder recorder;
SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(this->getViewWidth()),
SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(this->getViewWidth()),
SkIntToScalar(this->getViewHeight()),
factory.get(),
this->recordFlags());
@ -415,7 +415,7 @@ bool PipePictureRenderer::render(SkBitmap** out) {
fCanvas->flush();
if (out) {
*out = SkNEW(SkBitmap);
setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
SkScalarCeilToInt(fPicture->cullRect().height()));
fCanvas->readPixels(*out, 0, 0);
}
@ -436,7 +436,7 @@ SkString PipePictureRenderer::getConfigNameInternal() {
void SimplePictureRenderer::init(const SkPicture* picture, const SkString* writePath,
const SkString* mismatchPath, const SkString* inputFilename,
bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
INHERITED::init(picture, writePath, mismatchPath, inputFilename,
INHERITED::init(picture, writePath, mismatchPath, inputFilename,
useChecksumBasedFilenames, useMultiPictureDraw);
this->buildBBoxHierarchy();
}
@ -460,7 +460,7 @@ bool SimplePictureRenderer::render(SkBitmap** out) {
fCanvas->flush();
if (out) {
*out = SkNEW(SkBitmap);
setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
SkScalarCeilToInt(fPicture->cullRect().height()));
fCanvas->readPixels(*out, 0, 0);
}
@ -671,7 +671,7 @@ void TiledPictureRenderer::drawCurrentTile() {
draw_tile_to_canvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture);
}
bool TiledPictureRenderer::postRender(SkCanvas* canvas, const SkIRect& tileRect,
bool TiledPictureRenderer::postRender(SkCanvas* canvas, const SkIRect& tileRect,
SkBitmap* tempBM, SkBitmap** out,
int tileNumber) {
bool success = true;
@ -701,7 +701,7 @@ bool TiledPictureRenderer::render(SkBitmap** out) {
SkBitmap bitmap;
if (out) {
*out = SkNEW(SkBitmap);
setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
SkScalarCeilToInt(fPicture->cullRect().height()));
setup_bitmap(&bitmap, fTileWidth, fTileHeight);
}
@ -801,7 +801,7 @@ SkString TiledPictureRenderer::getConfigNameInternal() {
void PlaybackCreationRenderer::setup() {
SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
fRecorder.reset(SkNEW(SkPictureRecorder));
SkCanvas* canvas = fRecorder->beginRecording(SkIntToScalar(this->getViewWidth()),
SkCanvas* canvas = fRecorder->beginRecording(SkIntToScalar(this->getViewWidth()),
SkIntToScalar(this->getViewHeight()),
factory.get(),
this->recordFlags());
@ -828,8 +828,6 @@ SkBBHFactory* PictureRenderer::getFactory() {
return NULL;
case kRTree_BBoxHierarchyType:
return SkNEW(SkRTreeFactory);
case kTileGrid_BBoxHierarchyType:
return SkNEW_ARGS(SkTileGridFactory, (fGridInfo));
}
SkASSERT(0); // invalid bbhType
return NULL;

View File

@ -57,9 +57,8 @@ public:
enum BBoxHierarchyType {
kNone_BBoxHierarchyType = 0,
kRTree_BBoxHierarchyType,
kTileGrid_BBoxHierarchyType,
kLast_BBoxHierarchyType = kTileGrid_BBoxHierarchyType,
kLast_BBoxHierarchyType = kRTree_BBoxHierarchyType,
};
// this uses SkPaint::Flags as a base and adds additional flags
@ -237,10 +236,6 @@ public:
BBoxHierarchyType getBBoxHierarchyType() { return fBBoxHierarchyType; }
void setGridSize(int width, int height) {
fGridInfo.fTileInterval.set(width, height);
}
void setJsonSummaryPtr(ImageResultsAndExpectations* jsonSummaryPtr) {
fJsonSummaryPtr = jsonSummaryPtr;
}
@ -266,12 +261,6 @@ public:
}
if (kRTree_BBoxHierarchyType == fBBoxHierarchyType) {
config.append("_rtree");
} else if (kTileGrid_BBoxHierarchyType == fBBoxHierarchyType) {
config.append("_grid");
config.append("_");
config.appendS32(fGridInfo.fTileInterval.width());
config.append("x");
config.appendS32(fGridInfo.fTileInterval.height());
}
#if SK_SUPPORT_GPU
switch (fDeviceType) {
@ -316,12 +305,6 @@ public:
}
if (kRTree_BBoxHierarchyType == fBBoxHierarchyType) {
result["bbh"] = "rtree";
} else if (kTileGrid_BBoxHierarchyType == fBBoxHierarchyType) {
SkString tmp("grid_");
tmp.appendS32(fGridInfo.fTileInterval.width());
tmp.append("x");
tmp.appendS32(fGridInfo.fTileInterval.height());
result["bbh"] = tmp.c_str();
}
#if SK_SUPPORT_GPU
SkString tmp;
@ -439,9 +422,6 @@ public:
, fUseDFText(false)
#endif
{
fGridInfo.fMargin.setEmpty();
fGridInfo.fOffset.setZero();
fGridInfo.fTileInterval.set(1, 1);
sk_bzero(fDrawFilters, sizeof(fDrawFilters));
fViewport.set(0, 0);
}
@ -466,7 +446,6 @@ protected:
SkString fWritePath;
SkString fMismatchPath;
SkString fInputFilename;
SkTileGridFactory::TileGridInfo fGridInfo; // used when fBBoxHierarchyType is TileGrid
void buildBBoxHierarchy();
@ -696,7 +675,7 @@ private:
void setupTiles();
void setupPowerOf2Tiles();
bool postRender(SkCanvas*, const SkIRect& tileRect,
bool postRender(SkCanvas*, const SkIRect& tileRect,
SkBitmap* tempBM, SkBitmap** out,
int tileNumber);

View File

@ -92,7 +92,6 @@ sk_tools::PictureRenderer* parseRenderer(SkString& error, PictureTool tool) {
bool isPowerOf2Mode = false;
bool isCopyMode = false;
const char* mode = NULL;
bool gridSupported = false;
#if SK_SUPPORT_GPU
GrContext::Options grContextOpts;
@ -107,7 +106,6 @@ sk_tools::PictureRenderer* parseRenderer(SkString& error, PictureTool tool) {
mode = FLAGS_mode[0];
if (0 == strcmp(mode, "record")) {
renderer.reset(SkNEW_ARGS(sk_tools::RecordPictureRenderer, RENDERER_ARGS));
gridSupported = true;
} else if (0 == strcmp(mode, "tile") || 0 == strcmp(mode, "pow2tile")
|| 0 == strcmp(mode, "copyTile")) {
useTiles = true;
@ -116,8 +114,6 @@ sk_tools::PictureRenderer* parseRenderer(SkString& error, PictureTool tool) {
isPowerOf2Mode = true;
} else if (0 == strcmp(mode, "copyTile")) {
isCopyMode = true;
} else {
gridSupported = true;
}
if (FLAGS_mode.count() < 2) {
@ -134,7 +130,6 @@ sk_tools::PictureRenderer* parseRenderer(SkString& error, PictureTool tool) {
heightString = FLAGS_mode[2];
} else if (0 == strcmp(mode, "playbackCreation") && kBench_PictureTool == tool) {
renderer.reset(SkNEW_ARGS(sk_tools::PlaybackCreationRenderer, RENDERER_ARGS));
gridSupported = true;
// undocumented
} else if (0 == strcmp(mode, "gatherPixelRefs") && kBench_PictureTool == tool) {
#if SK_SUPPORT_GPU
@ -147,8 +142,6 @@ sk_tools::PictureRenderer* parseRenderer(SkString& error, PictureTool tool) {
// Allow 'mode' to be set to 'simple', but do not create a renderer, so we can
// ensure that pipe does not override a mode besides simple. The renderer will
// be created below.
} else if (0 == strcmp(mode, "simple")) {
gridSupported = true;
} else {
error.printf("%s is not a valid mode for --mode\n", mode);
return NULL;
@ -354,20 +347,6 @@ sk_tools::PictureRenderer* parseRenderer(SkString& error, PictureTool tool) {
bbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
} else if (0 == strcmp(type, "rtree")) {
bbhType = sk_tools::PictureRenderer::kRTree_BBoxHierarchyType;
} else if (0 == strcmp(type, "grid")) {
if (!gridSupported) {
error.printf("'--bbh grid' is not compatible with --mode=%s.\n", mode);
return NULL;
}
bbhType = sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType;
if (FLAGS_bbh.count() != 3) {
error.printf("--bbh grid requires a width and a height.\n");
return NULL;
}
int gridWidth = atoi(FLAGS_bbh[1]);
int gridHeight = atoi(FLAGS_bbh[2]);
renderer->setGridSize(gridWidth, gridHeight);
} else {
error.printf("%s is not a valid value for --bbhType\n", type);
return NULL;

View File

@ -37,7 +37,6 @@ struct Measurement {
const char* kBBoxHierarchyTypeNames[kBBoxTypeCount] = {
"none", // kNone_BBoxHierarchyType
"rtree", // kRTree_BBoxHierarchyType
"tilegrid", // kTileGrid_BBoxHierarchyType
};
static SkPicture* pic_from_path(const char path[]) {
@ -65,7 +64,6 @@ static void do_benchmark_work(sk_tools::PictureRenderer* renderer,
const int numRepeats,
Timer* timer) {
renderer->setBBoxHierarchyType(bBoxType);
renderer->setGridSize(FLAGS_tilesize, FLAGS_tilesize);
renderer->init(pic, NULL, NULL, NULL, false, false);
SkDebugf("%s %d times...\n", renderer->getConfigName().c_str(), numRepeats);

View File

@ -105,8 +105,3 @@ def RecordGridConfig(tile_x, tile_y, **kwargs):
def PlaybackCreationGridConfig(tile_x, tile_y, **kwargs):
return GridConfig(tile_x, tile_y, mode='playbackCreation')
def TileGridConfig(tile_x, tile_y, **kwargs):
return GridConfig(tile_x, tile_y,
**dict(TileArgs(tile_x, tile_y).items() + kwargs.items()))