In render_pictures tiled rendering, draw a separate PNG for each tile.

Since the passed in picture may represent an image which is too large
to be represented on the GPU, never create such a large canvas. Instead,
after drawing to each tile, create a file showing just that tile.

Review URL: https://codereview.appspot.com/6532056

git-svn-id: http://skia.googlecode.com/svn/trunk@5603 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
scroggo@google.com 2012-09-20 14:54:21 +00:00
Родитель bcdf2ec50d
Коммит 81f9d2e05b
4 изменённых файлов: 66 добавлений и 53 удалений

Просмотреть файл

@ -71,7 +71,7 @@ void PictureBenchmark::run(SkPicture* pict) {
// We throw this away to remove first time effects (such as paging in this program) // We throw this away to remove first time effects (such as paging in this program)
fRenderer->setup(); fRenderer->setup();
fRenderer->render(false); fRenderer->render(NULL);
fRenderer->resetState(); fRenderer->resetState();
BenchTimer* timer = this->setupTimer(); BenchTimer* timer = this->setupTimer();

Просмотреть файл

@ -99,38 +99,43 @@ void PictureRenderer::resetState() {
#endif #endif
} }
bool PictureRenderer::write(const SkString& path) const { bool PictureRenderer::write(SkCanvas* canvas, SkString path) const {
SkASSERT(fCanvas.get() != NULL); SkASSERT(canvas != NULL);
SkASSERT(fPicture != NULL); SkASSERT(fPicture != NULL);
if (NULL == fCanvas.get() || NULL == fPicture) { if (NULL == canvas || NULL == fPicture) {
return false; return false;
} }
SkBitmap bitmap; SkBitmap bitmap;
sk_tools::setup_bitmap(&bitmap, fPicture->width(), fPicture->height()); SkISize size = canvas->getDeviceSize();
sk_tools::setup_bitmap(&bitmap, size.width(), size.height());
fCanvas->readPixels(&bitmap, 0, 0); canvas->readPixels(&bitmap, 0, 0);
sk_tools::force_all_opaque(bitmap); sk_tools::force_all_opaque(bitmap);
// Since path is passed in by value, it is okay to modify it.
path.append(".png");
return SkImageEncoder::EncodeFile(path.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100); return SkImageEncoder::EncodeFile(path.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100);
} }
/////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////
void RecordPictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) { bool RecordPictureRenderer::render(const SkString*) {
SkPicture replayer; SkPicture replayer;
SkCanvas* recorder = replayer.beginRecording(fPicture->width(), fPicture->height()); SkCanvas* recorder = replayer.beginRecording(fPicture->width(), fPicture->height());
fPicture->draw(recorder); fPicture->draw(recorder);
replayer.endRecording(); replayer.endRecording();
// Since this class does not actually render, return false.
return false;
} }
/////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////
void PipePictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) { bool PipePictureRenderer::render(const SkString* path) {
SkASSERT(fCanvas.get() != NULL); SkASSERT(fCanvas.get() != NULL);
SkASSERT(fPicture != NULL); SkASSERT(fPicture != NULL);
if (NULL == fCanvas.get() || NULL == fPicture) { if (NULL == fCanvas.get() || NULL == fPicture) {
return; return false;
} }
PipeController pipeController(fCanvas.get()); PipeController pipeController(fCanvas.get());
@ -139,19 +144,21 @@ void PipePictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
pipeCanvas->drawPicture(*fPicture); pipeCanvas->drawPicture(*fPicture);
writer.endRecording(); writer.endRecording();
fCanvas->flush(); fCanvas->flush();
return path != NULL && this->write(fCanvas, *path);
} }
/////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////
void SimplePictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) { bool SimplePictureRenderer::render(const SkString* path) {
SkASSERT(fCanvas.get() != NULL); SkASSERT(fCanvas.get() != NULL);
SkASSERT(fPicture != NULL); SkASSERT(fPicture != NULL);
if (NULL == fCanvas.get() || NULL == fPicture) { if (NULL == fCanvas.get() || NULL == fPicture) {
return; return false;
} }
fCanvas->drawPicture(*fPicture); fCanvas->drawPicture(*fPicture);
fCanvas->flush(); fCanvas->flush();
return path != NULL && this->write(fCanvas, *path);
} }
/////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////
@ -398,16 +405,10 @@ void TiledPictureRenderer::setup() {
} }
} }
void TiledPictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) { bool TiledPictureRenderer::render(const SkString* path) {
SkASSERT(fPicture != NULL); SkASSERT(fPicture != NULL);
if (NULL == fPicture) { if (NULL == fPicture) {
return; return false;
}
if (doExtraWorkToDrawToBaseCanvas) {
if (NULL == fCanvas.get()) {
fCanvas.reset(this->INHERITED::setupCanvas());
}
} }
if (this->multiThreaded()) { if (this->multiThreaded()) {
@ -437,6 +438,8 @@ void TiledPictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
SkDELETE(thread); SkDELETE(thread);
} }
threads.reset(); threads.reset();
// Currently multithreaded is not an option for render_pictures
return false;
} else { } else {
// For single thread, we really only need one canvas total. // For single thread, we really only need one canvas total.
SkCanvas* canvas = this->setupCanvas(fTileWidth, fTileHeight); SkCanvas* canvas = this->setupCanvas(fTileWidth, fTileHeight);
@ -444,13 +447,15 @@ void TiledPictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
for (int i = 0; i < fTileRects.count(); ++i) { for (int i = 0; i < fTileRects.count(); ++i) {
DrawTileToCanvas(canvas, fTileRects[i], fPicture); DrawTileToCanvas(canvas, fTileRects[i], fPicture);
if (doExtraWorkToDrawToBaseCanvas) { if (path != NULL) {
SkASSERT(fCanvas.get() != NULL); SkString tilePath(*path);
SkBitmap source = canvas->getDevice()->accessBitmap(false); tilePath.appendf("%i", i);
fCanvas->drawBitmap(source, fTileRects[i].fLeft, fTileRects[i].fTop); if (!this->write(canvas, tilePath)) {
fCanvas->flush(); return false;
}
} }
} }
return path != NULL;
} }
} }
@ -474,8 +479,10 @@ void PlaybackCreationRenderer::setup() {
fPicture->draw(recorder); fPicture->draw(recorder);
} }
void PlaybackCreationRenderer::render(bool doExtraWorkToDrawToBaseCanvas) { bool PlaybackCreationRenderer::render(const SkString*) {
fReplayer.endRecording(); fReplayer.endRecording();
// Since this class does not actually render, return false.
return false;
} }
} }

Просмотреть файл

@ -47,12 +47,12 @@ public:
/** /**
* Perform work that is to be timed. Typically this is rendering, but is also used for recording * Perform work that is to be timed. Typically this is rendering, but is also used for recording
* and preparing picture for playback by the subclasses which do those. * and preparing picture for playback by the subclasses which do those.
* @param doExtraWorkToDrawToBaseCanvas Perform extra work to draw to fCanvas. Some subclasses * If path is non-null, subclass implementations should call write().
* will automatically draw to fCanvas, but in the tiled * @param path If non-null, also write the output to the file specified by path. path should
* case, for example, true needs to be passed so that * have no extension; it will be added by write().
* the tiles will be stitched together on fCanvas. * @return bool True if path is non-null and the output is successfully written to a file.
*/ */
virtual void render(bool doExtraWorkToDrawToBaseCanvas) = 0; virtual bool render(const SkString* path) = 0;
virtual void end(); virtual void end();
void resetState(); void resetState();
@ -95,9 +95,14 @@ public:
#endif #endif
{} {}
bool write(const SkString& path) const;
protected: protected:
/**
* Write the canvas to the specified path.
* @param canvas Must be non-null. Canvas to be written to a file.
* @param path Path for the file to be written. Should have no extension; write() will append
* an appropriate one.
*/
bool write(SkCanvas* canvas, SkString path) const;
SkCanvas* setupCanvas(); SkCanvas* setupCanvas();
virtual SkCanvas* setupCanvas(int width, int height); virtual SkCanvas* setupCanvas(int width, int height);
@ -119,7 +124,7 @@ private:
* to time. * to time.
*/ */
class RecordPictureRenderer : public PictureRenderer { class RecordPictureRenderer : public PictureRenderer {
virtual void render(bool doExtraWorkToDrawToBaseCanvas) SK_OVERRIDE; virtual bool render(const SkString*) SK_OVERRIDE;
virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); } virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
@ -128,7 +133,7 @@ class RecordPictureRenderer : public PictureRenderer {
class PipePictureRenderer : public PictureRenderer { class PipePictureRenderer : public PictureRenderer {
public: public:
virtual void render(bool doExtraWorkToDrawToBaseCanvas) SK_OVERRIDE; virtual bool render(const SkString*) SK_OVERRIDE;
private: private:
typedef PictureRenderer INHERITED; typedef PictureRenderer INHERITED;
@ -136,7 +141,7 @@ private:
class SimplePictureRenderer : public PictureRenderer { class SimplePictureRenderer : public PictureRenderer {
public: public:
virtual void render(bool doExtraWorkToDrawToBaseCanvas) SK_OVERRIDE; virtual bool render(const SkString*) SK_OVERRIDE;
private: private:
typedef PictureRenderer INHERITED; typedef PictureRenderer INHERITED;
@ -147,8 +152,16 @@ public:
TiledPictureRenderer(); TiledPictureRenderer();
virtual void init(SkPicture* pict) SK_OVERRIDE; virtual void init(SkPicture* pict) SK_OVERRIDE;
virtual void setup() SK_OVERRIDE; virtual void setup() SK_OVERRIDE;
virtual void render(bool doExtraWorkToDrawToBaseCanvas) SK_OVERRIDE;
/**
* Renders to tiles, rather than a single canvas. If a path is provided, a separate file is
* created for each tile, named "path0.png", "path1.png", etc.
* Multithreaded mode currently does not support writing to a file.
*/
virtual bool render(const SkString* path) SK_OVERRIDE;
virtual void end() SK_OVERRIDE; virtual void end() SK_OVERRIDE;
void setTileWidth(int width) { void setTileWidth(int width) {
@ -241,7 +254,7 @@ class PlaybackCreationRenderer : public PictureRenderer {
public: public:
virtual void setup() SK_OVERRIDE; virtual void setup() SK_OVERRIDE;
virtual void render(bool doExtraWorkToDrawToBaseCanvas) SK_OVERRIDE; virtual bool render(const SkString*) SK_OVERRIDE;
virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); } virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }

Просмотреть файл

@ -75,19 +75,8 @@ static void usage(const char* argv0) {
static void make_output_filepath(SkString* path, const SkString& dir, static void make_output_filepath(SkString* path, const SkString& dir,
const SkString& name) { const SkString& name) {
sk_tools::make_filepath(path, dir, name); sk_tools::make_filepath(path, dir, name);
path->remove(path->size() - 3, 3); // Remove ".skp"
path->append("png"); path->remove(path->size() - 4, 4);
}
static bool write_output(const SkString& outputDir, const SkString& inputFilename,
const sk_tools::PictureRenderer& renderer) {
SkString outputPath;
make_output_filepath(&outputPath, outputDir, inputFilename);
bool isWritten = renderer.write(outputPath);
if (!isWritten) {
SkDebugf("Could not write to file %s\n", outputPath.c_str());
}
return isWritten;
} }
static bool render_picture(const SkString& inputPath, const SkString& outputDir, static bool render_picture(const SkString& inputPath, const SkString& outputDir,
@ -118,12 +107,16 @@ static bool render_picture(const SkString& inputPath, const SkString& outputDir,
renderer.init(aur); renderer.init(aur);
renderer.render(true); SkString outputPath;
make_output_filepath(&outputPath, outputDir, inputFilename);
success = renderer.render(&outputPath);
if (!success) {
SkDebugf("Could not write to file %s\n", outputPath.c_str());
}
renderer.resetState(); renderer.resetState();
success = write_output(outputDir, inputFilename, renderer);
renderer.end(); renderer.end();
return success; return success;
} }