// 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:
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;
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;
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 ); )
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);
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.
enum BBH {
kNone_BBH,
kRTree_BBH,
- kTileGrid_BBH,
};
QuiltTask(const Task& parent, // QuiltTask must be a child task. Pass its parent here.
enum BbhType {
kNone_BbhType,
kRTree_BbhType,
- kTileGrid_BbhType,
};
enum ConfigFlags {
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;
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);
}
}
- 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,
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));
}
'<(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',
'../tests/TSetTest.cpp',
'../tests/TextBlobTest.cpp',
'../tests/TextureCompressionTest.cpp',
- '../tests/TileGridTest.cpp',
'../tests/ToUnicodeTest.cpp',
'../tests/TracingTest.cpp',
'../tests/TypefaceTest.cpp',
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 */
*/
SkIPoint fOffset;
};
-
- SkTileGridFactory(const TileGridInfo& info) : fInfo(info) { }
-
- virtual SkBBoxHierarchy* operator()(const SkRect& bounds) const SK_OVERRIDE;
-
-private:
- TileGridInfo fInfo;
-
- typedef SkBBHFactory INHERITED;
};
#endif
virtual void onTileSizeChanged(const SkSize &tileSize) SK_OVERRIDE {
if (tileSize != fTileSize) {
fTileSize = tileSize;
- SkSafeSetNull(fPictures[kTileGrid_BBoxType]);
}
}
case kRTree_BBoxType:
name.append(" <bbox: R>");
break;
- case kTileGrid_BBoxType:
- name.append(" <bbox: T>");
- break;
default:
SkASSERT(false);
break;
enum BBoxType {
kNo_BBoxType,
kRTree_BBoxType,
- kTileGrid_BBoxType,
- kLast_BBoxType = kTileGrid_BBoxType
+ kLast_BBoxType = kRTree_BBoxType,
};
static const int kBBoxTypeCount = kLast_BBoxType + 1;
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());
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());
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();
}
#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));
-}
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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
// 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);
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),
+++ /dev/null
-/*
- * 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);
-}
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);
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());
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);
}
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();
}
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);
}
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;
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);
}
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());
return NULL;
case kRTree_BBoxHierarchyType:
return SkNEW(SkRTreeFactory);
- case kTileGrid_BBoxHierarchyType:
- return SkNEW_ARGS(SkTileGridFactory, (fGridInfo));
}
SkASSERT(0); // invalid bbhType
return NULL;
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
BBoxHierarchyType getBBoxHierarchyType() { return fBBoxHierarchyType; }
- void setGridSize(int width, int height) {
- fGridInfo.fTileInterval.set(width, height);
- }
-
void setJsonSummaryPtr(ImageResultsAndExpectations* jsonSummaryPtr) {
fJsonSummaryPtr = jsonSummaryPtr;
}
}
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) {
}
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;
, fUseDFText(false)
#endif
{
- fGridInfo.fMargin.setEmpty();
- fGridInfo.fOffset.setZero();
- fGridInfo.fTileInterval.set(1, 1);
sk_bzero(fDrawFilters, sizeof(fDrawFilters));
fViewport.set(0, 0);
}
SkString fWritePath;
SkString fMismatchPath;
SkString fInputFilename;
- SkTileGridFactory::TileGridInfo fGridInfo; // used when fBBoxHierarchyType is TileGrid
void buildBBoxHierarchy();
void setupTiles();
void setupPowerOf2Tiles();
- bool postRender(SkCanvas*, const SkIRect& tileRect,
+ bool postRender(SkCanvas*, const SkIRect& tileRect,
SkBitmap* tempBM, SkBitmap** out,
int tileNumber);
bool isPowerOf2Mode = false;
bool isCopyMode = false;
const char* mode = NULL;
- bool gridSupported = false;
#if SK_SUPPORT_GPU
GrContext::Options grContextOpts;
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;
isPowerOf2Mode = true;
} else if (0 == strcmp(mode, "copyTile")) {
isCopyMode = true;
- } else {
- gridSupported = true;
}
if (FLAGS_mode.count() < 2) {
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
// 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;
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;
const char* kBBoxHierarchyTypeNames[kBBoxTypeCount] = {
"none", // kNone_BBoxHierarchyType
"rtree", // kRTree_BBoxHierarchyType
- "tilegrid", // kTileGrid_BBoxHierarchyType
};
static SkPicture* pic_from_path(const char path[]) {
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);
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()))