Update old tools to allow MultiPictureDraw rendering

I'll post a separate patch for nanobench and dm

Review URL: https://codereview.chromium.org/639013003
This commit is contained in:
robertphillips 2014-10-09 04:59:19 -07:00 committed by Commit bot
parent 17bfe0d670
commit 78c71272fb
10 changed files with 137 additions and 95 deletions

View File

@ -356,7 +356,7 @@ void SkDebuggerGUI::run(const SkPicture* pict,
return;
}
renderer->init(pict, NULL, NULL, NULL, false);
renderer->init(pict, NULL, NULL, NULL, false, false);
renderer->setup();
renderer->render();

View File

@ -10,6 +10,7 @@
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkImageEncoder.h"
#include "SkMultiPictureDraw.h"
#include "SkPicture.h"
#include "SkPixelRef.h"
#include "SkRect.h"
@ -28,7 +29,7 @@ namespace sk_tools {
#endif
void CopyTilesRenderer::init(const SkPicture* pict, const SkString* writePath,
const SkString* mismatchPath, const SkString* inputFilename,
bool useChecksumBasedFilenames) {
bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
// Do not call INHERITED::init(), which would create a (potentially large) canvas which is
// not used by bench_pictures.
SkASSERT(pict != NULL);
@ -39,6 +40,7 @@ namespace sk_tools {
this->CopyString(&fMismatchPath, mismatchPath);
this->CopyString(&fInputFilename, inputFilename);
fUseChecksumBasedFilenames = useChecksumBasedFilenames;
fUseMultiPictureDraw = useMultiPictureDraw;
this->buildBBoxHierarchy();
// In order to avoid allocating a large canvas (particularly important for GPU), create one
// canvas that is a multiple of the tile size, and draw portions of the picture.
@ -61,7 +63,15 @@ namespace sk_tools {
mat.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
fCanvas->setMatrix(mat);
// Draw the picture
fCanvas->drawPicture(fPicture);
if (fUseMultiPictureDraw) {
SkMultiPictureDraw mpd;
mpd.add(fCanvas, fPicture);
mpd.draw();
} else {
fCanvas->drawPicture(fPicture);
}
// Now extract the picture into tiles
SkBitmap baseBitmap;
fCanvas->readPixels(SkIRect::MakeSize(fCanvas->getBaseLayerSize()), &baseBitmap);

View File

@ -31,7 +31,8 @@ namespace sk_tools {
const SkString* writePath,
const SkString* mismatchPath,
const SkString* inputFilename,
bool useChecksumBasedFilenames) SK_OVERRIDE;
bool useChecksumBasedFilenames,
bool useMultiPictureDraw) SK_OVERRIDE;
/**
* Similar to TiledPictureRenderer, this will draw a PNG for each tile. However, the

View File

@ -15,15 +15,14 @@
namespace sk_tools {
PictureBenchmark::PictureBenchmark()
: fRepeats(1)
, fRenderer(NULL)
, fTimerResult(TimerData::kAvg_Result)
, fTimerTypes(0)
, fTimeIndividualTiles(false)
, fPurgeDecodedTex(false)
, fPreprocess(false)
, fWriter(NULL)
{}
: fRepeats(1)
, fRenderer(NULL)
, fTimerResult(TimerData::kAvg_Result)
, fTimerTypes(0)
, fTimeIndividualTiles(false)
, fPurgeDecodedTex(false)
, fWriter(NULL) {
}
PictureBenchmark::~PictureBenchmark() {
SkSafeUnref(fRenderer);
@ -56,7 +55,7 @@ PictureRenderer* PictureBenchmark::setRenderer(sk_tools::PictureRenderer* render
return renderer;
}
void PictureBenchmark::run(SkPicture* pict) {
void PictureBenchmark::run(SkPicture* pict, bool useMultiPictureDraw) {
SkASSERT(pict);
if (NULL == pict) {
return;
@ -67,17 +66,11 @@ void PictureBenchmark::run(SkPicture* pict) {
return;
}
fRenderer->init(pict, NULL, NULL, NULL, false);
fRenderer->init(pict, NULL, NULL, NULL, false, useMultiPictureDraw);
// We throw this away to remove first time effects (such as paging in this program)
fRenderer->setup();
if (fPreprocess) {
if (fRenderer->getCanvas()) {
fRenderer->getCanvas()->EXPERIMENTAL_optimize(fRenderer->getPicture());
}
}
fRenderer->render(NULL);
fRenderer->resetState(true); // flush, swapBuffers and Finish

View File

@ -28,7 +28,7 @@ public:
* Draw the provided SkPicture fRepeats times while collecting timing data, and log the output
* via fWriter.
*/
void run(SkPicture* pict);
void run(SkPicture* pict, bool useMultiPictureDraw);
void setRepeats(int repeats) {
fRepeats = repeats;
@ -45,9 +45,6 @@ public:
void setPurgeDecodedTex(bool purgeDecodedTex) { fPurgeDecodedTex = purgeDecodedTex; }
bool purgeDecodedText() const { return fPurgeDecodedTex; }
void setPreprocess(bool preprocess) { fPreprocess = preprocess; }
bool preprocess() const { return fPreprocess; }
PictureRenderer* setRenderer(PictureRenderer*);
PictureRenderer* renderer() { return fRenderer; }
@ -64,7 +61,6 @@ private:
uint32_t fTimerTypes; // bitfield of TimerData::TimerFlags values
bool fTimeIndividualTiles;
bool fPurgeDecodedTex;
bool fPreprocess;
PictureResultsWriter* fWriter;

View File

@ -22,6 +22,7 @@
#include "SkImageEncoder.h"
#include "SkMaskFilter.h"
#include "SkMatrix.h"
#include "SkMultiPictureDraw.h"
#include "SkOSFile.h"
#include "SkPicture.h"
#include "SkPictureRecorder.h"
@ -30,6 +31,7 @@
#include "SkScalar.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkSurface.h"
#include "SkTemplates.h"
#include "SkTDArray.h"
#include "SkThreadUtils.h"
@ -52,11 +54,13 @@ void PictureRenderer::init(const SkPicture* pict,
const SkString* writePath,
const SkString* mismatchPath,
const SkString* inputFilename,
bool useChecksumBasedFilenames) {
bool useChecksumBasedFilenames,
bool useMultiPictureDraw) {
this->CopyString(&fWritePath, writePath);
this->CopyString(&fMismatchPath, mismatchPath);
this->CopyString(&fInputFilename, inputFilename);
fUseChecksumBasedFilenames = useChecksumBasedFilenames;
fUseMultiPictureDraw = useMultiPictureDraw;
SkASSERT(NULL == fPicture);
SkASSERT(NULL == fCanvas.get());
@ -415,8 +419,9 @@ SkString PipePictureRenderer::getConfigNameInternal() {
void SimplePictureRenderer::init(const SkPicture* picture, const SkString* writePath,
const SkString* mismatchPath, const SkString* inputFilename,
bool useChecksumBasedFilenames) {
INHERITED::init(picture, writePath, mismatchPath, inputFilename, useChecksumBasedFilenames);
bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
INHERITED::init(picture, writePath, mismatchPath, inputFilename,
useChecksumBasedFilenames, useMultiPictureDraw);
this->buildBBoxHierarchy();
}
@ -427,7 +432,15 @@ bool SimplePictureRenderer::render(SkBitmap** out) {
return false;
}
fCanvas->drawPicture(fPicture);
if (fUseMultiPictureDraw) {
SkMultiPictureDraw mpd;
mpd.add(fCanvas, fPicture);
mpd.draw();
} else {
fCanvas->drawPicture(fPicture);
}
fCanvas->flush();
if (out) {
*out = SkNEW(SkBitmap);
@ -467,7 +480,7 @@ TiledPictureRenderer::TiledPictureRenderer()
void TiledPictureRenderer::init(const SkPicture* pict, const SkString* writePath,
const SkString* mismatchPath, const SkString* inputFilename,
bool useChecksumBasedFilenames) {
bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
SkASSERT(pict);
SkASSERT(0 == fTileRects.count());
if (NULL == pict || fTileRects.count() != 0) {
@ -481,6 +494,7 @@ void TiledPictureRenderer::init(const SkPicture* pict, const SkString* writePath
this->CopyString(&fMismatchPath, mismatchPath);
this->CopyString(&fInputFilename, inputFilename);
fUseChecksumBasedFilenames = useChecksumBasedFilenames;
fUseMultiPictureDraw = useMultiPictureDraw;
this->buildBBoxHierarchy();
if (fTileWidthPercentage > 0) {
@ -519,10 +533,8 @@ void TiledPictureRenderer::setupTiles() {
// Only count tiles in the X direction on the first pass.
fTilesX++;
}
*fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
SkIntToScalar(tile_y_start),
SkIntToScalar(fTileWidth),
SkIntToScalar(fTileHeight));
*fTileRects.append() = SkIRect::MakeXYWH(tile_x_start, tile_y_start,
fTileWidth, fTileHeight);
}
}
}
@ -575,10 +587,8 @@ void TiledPictureRenderer::setupPowerOf2Tiles() {
// Only count tiles in the X direction on the first pass.
fTilesX++;
}
*fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
SkIntToScalar(tile_y_start),
SkIntToScalar(current_width),
SkIntToScalar(fTileHeight));
*fTileRects.append() = SkIRect::MakeXYWH(tile_x_start, tile_y_start,
current_width, fTileHeight);
tile_x_start += current_width;
}
@ -594,13 +604,13 @@ void TiledPictureRenderer::setupPowerOf2Tiles() {
* is called.
*/
static void draw_tile_to_canvas(SkCanvas* canvas,
const SkRect& tileRect,
const SkIRect& tileRect,
const SkPicture* picture) {
int saveCount = canvas->save();
// Translate so that we draw the correct portion of the picture.
// Perform a postTranslate so that the scaleFactor does not interfere with the positioning.
SkMatrix mat(canvas->getTotalMatrix());
mat.postTranslate(-tileRect.fLeft, -tileRect.fTop);
mat.postTranslate(-SkIntToScalar(tileRect.fLeft), -SkIntToScalar(tileRect.fTop));
canvas->setMatrix(mat);
canvas->drawPicture(picture);
canvas->restoreToCount(saveCount);
@ -643,6 +653,27 @@ void TiledPictureRenderer::drawCurrentTile() {
draw_tile_to_canvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture);
}
bool TiledPictureRenderer::postRender(SkCanvas* canvas, const SkIRect& tileRect,
SkBitmap* tempBM, SkBitmap** out,
int tileNumber) {
bool success = true;
if (fEnableWrites) {
success &= write(canvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
fUseChecksumBasedFilenames, &tileNumber);
}
if (out) {
if (canvas->readPixels(tempBM, 0, 0)) {
// Add this tile to the entire bitmap.
bitmapCopyAtOffset(*tempBM, *out, tileRect.left(), tileRect.top());
} else {
success = false;
}
}
return success;
}
bool TiledPictureRenderer::render(SkBitmap** out) {
SkASSERT(fPicture != NULL);
if (NULL == fPicture) {
@ -650,29 +681,59 @@ bool TiledPictureRenderer::render(SkBitmap** out) {
}
SkBitmap bitmap;
if (out){
if (out) {
*out = SkNEW(SkBitmap);
setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
SkScalarCeilToInt(fPicture->cullRect().height()));
setup_bitmap(&bitmap, fTileWidth, fTileHeight);
}
bool success = true;
for (int i = 0; i < fTileRects.count(); ++i) {
draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture);
if (fEnableWrites) {
success &= write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
fUseChecksumBasedFilenames, &i);
if (fUseMultiPictureDraw) {
SkMultiPictureDraw mpd;
SkTDArray<SkSurface*> surfaces;
surfaces.setReserve(fTileRects.count());
// Create a separate SkSurface/SkCanvas for each tile along with a
// translated version of the skp (to mimic Chrome's behavior) and
// feed all such pairs to the MultiPictureDraw.
for (int i = 0; i < fTileRects.count(); ++i) {
SkImageInfo ii = fCanvas->imageInfo().makeWH(fTileRects[i].width(),
fTileRects[i].height());
*surfaces.append() = fCanvas->newSurface(ii);
surfaces[i]->getCanvas()->setMatrix(fCanvas->getTotalMatrix());
SkPictureRecorder recorder;
SkCanvas* c = recorder.beginRecording(SkIntToScalar(fTileRects[i].width()),
SkIntToScalar(fTileRects[i].height()));
c->save();
SkMatrix mat;
mat.setTranslate(-SkIntToScalar(fTileRects[i].fLeft),
-SkIntToScalar(fTileRects[i].fTop));
c->setMatrix(mat);
c->drawPicture(fPicture);
c->restore();
SkAutoTUnref<SkPicture> xlatedPicture(recorder.endRecording());
mpd.add(surfaces[i]->getCanvas(), xlatedPicture);
}
if (out) {
if (fCanvas->readPixels(&bitmap, 0, 0)) {
// Add this tile to the entire bitmap.
bitmapCopyAtOffset(bitmap, *out, SkScalarFloorToInt(fTileRects[i].left()),
SkScalarFloorToInt(fTileRects[i].top()));
} else {
success = false;
}
// Render all the buffered SkCanvases/SkPictures
mpd.draw();
// Sort out the results and cleanup the allocated surfaces
for (int i = 0; i < fTileRects.count(); ++i) {
success &= this->postRender(surfaces[i]->getCanvas(), fTileRects[i], &bitmap, out, i);
surfaces[i]->unref();
}
} else {
for (int i = 0; i < fTileRects.count(); ++i) {
draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture);
success &= this->postRender(fCanvas, fTileRects[i], &bitmap, out, i);
}
}
return success;
}

View File

@ -88,12 +88,14 @@ public:
* @param inputFilename The name of the input file we are rendering.
* @param useChecksumBasedFilenames Whether to use checksum-based filenames when writing
* bitmap images to disk.
* @param useMultiPictureDraw true if MultiPictureDraw should be used for rendering
*/
virtual void init(const SkPicture* pict,
const SkString* writePath,
const SkString* mismatchPath,
const SkString* inputFilename,
bool useChecksumBasedFilenames);
bool useChecksumBasedFilenames,
bool useMultiPictureDraw);
/**
* TODO(epoger): Temporary hack, while we work on http://skbug.com/2584 ('bench_pictures is
@ -445,6 +447,7 @@ protected:
SkAutoTUnref<SkCanvas> fCanvas;
SkAutoTUnref<const SkPicture> fPicture;
bool fUseChecksumBasedFilenames;
bool fUseMultiPictureDraw;
ImageResultsAndExpectations* fJsonSummaryPtr;
SkDeviceTypes fDeviceType;
bool fEnableWrites;
@ -548,7 +551,8 @@ public:
const SkString* writePath,
const SkString* mismatchPath,
const SkString* inputFilename,
bool useChecksumBasedFilenames) SK_OVERRIDE;
bool useChecksumBasedFilenames,
bool useMultiPictureDraw) SK_OVERRIDE;
virtual bool render(SkBitmap** out = NULL) SK_OVERRIDE;
@ -570,7 +574,8 @@ public:
const SkString* writePath,
const SkString* mismatchPath,
const SkString* inputFilename,
bool useChecksumBasedFilenames) SK_OVERRIDE;
bool useChecksumBasedFilenames,
bool useMultiPictureDraw) SK_OVERRIDE;
/**
* Renders to tiles, rather than a single canvas.
@ -659,7 +664,7 @@ public:
void drawCurrentTile();
protected:
SkTDArray<SkRect> fTileRects;
SkTDArray<SkIRect> fTileRects;
virtual SkCanvas* setupCanvas(int width, int height) SK_OVERRIDE;
virtual SkString getConfigNameInternal() SK_OVERRIDE;
@ -681,6 +686,9 @@ private:
void setupTiles();
void setupPowerOf2Tiles();
bool postRender(SkCanvas*, const SkIRect& tileRect,
SkBitmap* tempBM, SkBitmap** out,
int tileNumber);
typedef PictureRenderer INHERITED;
};

View File

@ -60,13 +60,13 @@ static SkPicture* pic_from_path(const char path[]) {
* @param timer The timer used to benchmark the work.
*/
static void do_benchmark_work(sk_tools::PictureRenderer* renderer,
BBoxType bBoxType,
SkPicture* pic,
const int numRepeats,
Timer* timer) {
BBoxType bBoxType,
SkPicture* pic,
const int numRepeats,
Timer* timer) {
renderer->setBBoxHierarchyType(bBoxType);
renderer->setGridSize(FLAGS_tilesize, FLAGS_tilesize);
renderer->init(pic, NULL, NULL, NULL, false);
renderer->init(pic, NULL, NULL, NULL, false, false);
SkDebugf("%s %d times...\n", renderer->getConfigName().c_str(), numRepeats);
for (int i = 0; i < numRepeats; ++i) {

View File

@ -59,7 +59,7 @@ DEFINE_bool(gpuStats, false, "Only meaningful with gpu configurations. "
"Report some GPU call statistics.");
#endif
DEFINE_bool(preprocess, false, "If true, perform device specific preprocessing before timing.");
DEFINE_bool(mpd, false, "If true, use MultiPictureDraw to render.");
// Buildbot-specific parameters
DEFINE_string(builderName, "", "Name of the builder this is running on.");
@ -202,23 +202,13 @@ static bool run_single_benchmark(const SkString& inputPath,
return false;
}
if (FLAGS_preprocess) {
// Because the GPU preprocessing step relies on the in-memory picture
// statistics we need to rerecord the picture here
SkPictureRecorder recorder;
picture->playback(recorder.beginRecording(picture->cullRect().width(),
picture->cullRect().height(),
NULL, 0));
picture.reset(recorder.endRecording());
}
SkString filename = SkOSPath::Basename(inputPath.c_str());
gWriter.bench(filename.c_str(),
SkScalarCeilToInt(picture->cullRect().width()),
SkScalarCeilToInt(picture->cullRect().height()));
benchmark.run(picture);
benchmark.run(picture, FLAGS_mpd);
#if SK_LAZY_CACHE_STATS
if (FLAGS_trackDeferredCaching) {
@ -365,7 +355,6 @@ static void setup_benchmark(sk_tools::PictureBenchmark* benchmark) {
}
benchmark->setPurgeDecodedTex(FLAGS_purgeDecodedTex);
benchmark->setPreprocess(FLAGS_preprocess);
if (FLAGS_readPath.count() < 1) {
gLogger.logError(".skp files or directories are required.\n");

View File

@ -40,7 +40,7 @@ DEFINE_string(mismatchPath, "", "Write images for tests that failed due to "
DEFINE_bool(gpuStats, false, "Only meaningful with gpu configurations. "
"Report some GPU call statistics.");
#endif
DEFINE_bool(preprocess, false, "If true, perform device specific preprocessing before rendering.");
DEFINE_bool(mpd, false, "If true, use MultiPictureDraw for rendering.");
DEFINE_string(readJsonSummaryPath, "", "JSON file to read image expectations from.");
DECLARE_string(readPath);
DEFINE_bool(writeChecksumBasedFilenames, false,
@ -184,16 +184,6 @@ static bool render_picture_internal(const SkString& inputPath, const SkString* w
return false;
}
if (FLAGS_preprocess) {
// Because the GPU preprocessing step relies on the in-memory picture
// statistics we need to rerecord the picture here
SkPictureRecorder recorder;
picture->playback(recorder.beginRecording(picture->cullRect().width(),
picture->cullRect().height(),
NULL, 0));
picture.reset(recorder.endRecording());
}
while (FLAGS_bench_record) {
SkPictureRecorder recorder;
picture->playback(recorder.beginRecording(picture->cullRect().width(),
@ -208,13 +198,7 @@ static bool render_picture_internal(const SkString& inputPath, const SkString* w
inputPath.c_str());
renderer.init(picture, &writePathString, &mismatchPathString, &inputFilename,
FLAGS_writeChecksumBasedFilenames);
if (FLAGS_preprocess) {
if (renderer.getCanvas()) {
renderer.getCanvas()->EXPERIMENTAL_optimize(renderer.getPicture());
}
}
FLAGS_writeChecksumBasedFilenames, FLAGS_mpd);
renderer.setup();
renderer.enableWrites();