diff options
-rw-r--r-- | include/core/SkCanvas.h | 8 | ||||
-rw-r--r-- | include/core/SkDevice.h | 18 | ||||
-rw-r--r-- | include/core/SkPicture.h | 40 | ||||
-rw-r--r-- | include/gpu/SkGpuDevice.h | 9 | ||||
-rw-r--r-- | src/core/SkCanvas.cpp | 15 | ||||
-rw-r--r-- | src/core/SkDevice.cpp | 9 | ||||
-rw-r--r-- | src/core/SkPicture.cpp | 29 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 42 | ||||
-rw-r--r-- | tools/PictureRenderer.cpp | 13 | ||||
-rw-r--r-- | tools/PictureRenderer.h | 4 | ||||
-rw-r--r-- | tools/render_pictures_main.cpp | 9 |
11 files changed, 181 insertions, 15 deletions
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index 716720bc3e..7fd21352a4 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -962,6 +962,14 @@ public: const SkPath& path, const SkMatrix* matrix, const SkPaint& paint); + /** PRIVATE / EXPERIMENTAL -- do not call + Perform back-end analysis/optimization of a picture. This may attach + optimization data to the picture which can be used by a later + drawPicture call. + @param picture The recorded drawing commands to analyze/optimize + */ + void EXPERIMENTAL_optimize(SkPicture* picture); + /** Draw the picture into this canvas. This method effective brackets the playback of the picture's draw calls with save/restore, so the state of this canvas will be unchanged after this call. diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h index 2d9b0fc43b..7161bb141d 100644 --- a/include/core/SkDevice.h +++ b/include/core/SkDevice.h @@ -423,6 +423,24 @@ protected: */ SkDeviceProperties fLeakyProperties; + /** + * PRIVATE / EXPERIMENTAL -- do not call + * Construct an acceleration object and attach it to 'picture' + */ + virtual void EXPERIMENTAL_optimize(SkPicture* picture); + + /** + * PRIVATE / EXPERIMENTAL -- do not call + * This entry point gives the backend an opportunity to take over the rendering + * of 'picture'. If optimization data is available (due to an earlier + * 'optimize' call) this entry point should make use of it and return true + * if all rendering has been done. If false is returned, SkCanvas will + * perform its own rendering pass. It is acceptable for the backend + * to perform some device-specific warm up tasks and then let SkCanvas + * perform the main rendering loop (by return false from here). + */ + virtual bool EXPERIMENTAL_drawPicture(const SkPicture& picture); + private: friend class SkCanvas; friend struct DeviceCM; //for setMatrixClip diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index ef6f4a2063..8fa777792f 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -34,6 +34,27 @@ class SK_API SkPicture : public SkRefCnt { public: SK_DECLARE_INST_COUNT(SkPicture) + // AccelData provides a base class for device-specific acceleration + // data. It is added to the picture via a call to a device's optimize + // method. + class AccelData : public SkRefCnt { + public: + typedef uint8_t Domain; + typedef uint32_t Key; + + AccelData(Key key) : fKey(key) { } + + const Key& getKey() const { return fKey; } + + // This entry point allows user's to get a unique domain prefix + // for their keys + static Domain GenerateDomain(); + private: + Key fKey; + + typedef SkRefCnt INHERITED; + }; + /** The constructor prepares the picture to record. @param width the width of the virtual device the picture records. @param height the height of the virtual device the picture records. @@ -44,6 +65,18 @@ public: */ SkPicture(const SkPicture& src); + /** PRIVATE / EXPERIMENTAL -- do not call */ + void EXPERIMENTAL_addAccelData(const AccelData* data) { + SkRefCnt_SafeAssign(fAccelData, data); + } + /** PRIVATE / EXPERIMENTAL -- do not call */ + const AccelData* EXPERIMENTAL_getAccelData(AccelData::Key key) const { + if (NULL != fAccelData && fAccelData->getKey() == key) { + return fAccelData; + } + return NULL; + } + /** * Function signature defining a function that sets up an SkBitmap from encoded data. On * success, the SkBitmap should have its Config, width, height, rowBytes and pixelref set. @@ -262,9 +295,10 @@ protected: // fPlayback, fRecord, fWidth & fHeight are protected to allow derived classes to // install their own SkPicturePlayback-derived players,SkPictureRecord-derived // recorders and set the picture size - SkPicturePlayback* fPlayback; - SkPictureRecord* fRecord; - int fWidth, fHeight; + SkPicturePlayback* fPlayback; + SkPictureRecord* fRecord; + int fWidth, fHeight; + const AccelData* fAccelData; // Create a new SkPicture from an existing SkPicturePlayback. Ref count of // playback is unchanged. diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h index f8ee7817bc..7394361ff1 100644 --- a/include/gpu/SkGpuDevice.h +++ b/include/gpu/SkGpuDevice.h @@ -14,6 +14,7 @@ #include "SkGr.h" #include "SkBitmap.h" #include "SkBitmapDevice.h" +#include "SkPicture.h" #include "SkRegion.h" #include "GrContext.h" @@ -146,10 +147,16 @@ public: class SkAutoCachedTexture; // used internally + protected: virtual bool onReadPixels(const SkBitmap&, int x, int y, SkCanvas::Config8888) SK_OVERRIDE; virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int, int) SK_OVERRIDE; + /** PRIVATE / EXPERIMENTAL -- do not call */ + virtual void EXPERIMENTAL_optimize(SkPicture* picture) SK_OVERRIDE; + /** PRIVATE / EXPERIMENTAL -- do not call */ + virtual bool EXPERIMENTAL_drawPicture(const SkPicture& picture) SK_OVERRIDE; + private: GrContext* fContext; @@ -215,6 +222,8 @@ private: int tileSize, bool bicubic); + static SkPicture::AccelData::Key ComputeAccelDataKey(); + typedef SkBitmapDevice INHERITED; }; diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 4ac7b29826..f2200a6d8d 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -2461,8 +2461,23 @@ void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, } /////////////////////////////////////////////////////////////////////////////// +void SkCanvas::EXPERIMENTAL_optimize(SkPicture* picture) { + SkBaseDevice* device = this->getDevice(); + if (NULL != device) { + device->EXPERIMENTAL_optimize(picture); + } +} void SkCanvas::drawPicture(SkPicture& picture) { + SkBaseDevice* device = this->getTopDevice(); + if (NULL != device) { + // Canvas has to first give the device the opportunity to render + // the picture itself. + if (device->EXPERIMENTAL_drawPicture(picture)) { + return; // the device has rendered the entire picture + } + } + picture.draw(this); } diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 587181302d..3cfe89cfec 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -213,3 +213,12 @@ void* SkBaseDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) { #ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG void SkBaseDevice::writePixels(const SkBitmap&, int x, int y, SkCanvas::Config8888) {} #endif + +void SkBaseDevice::EXPERIMENTAL_optimize(SkPicture* picture) { + // The base class doesn't perform any analysis but derived classes may +} + +bool SkBaseDevice::EXPERIMENTAL_drawPicture(const SkPicture& picture) { + // The base class doesn't perform any accelerated picture rendering + return false; +} diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp index 9270236572..92311f3a3a 100644 --- a/src/core/SkPicture.cpp +++ b/src/core/SkPicture.cpp @@ -117,9 +117,12 @@ SkPicture::SkPicture() { fRecord = NULL; fPlayback = NULL; fWidth = fHeight = 0; + fAccelData = NULL; } -SkPicture::SkPicture(const SkPicture& src) : INHERITED() { +SkPicture::SkPicture(const SkPicture& src) + : INHERITED() + , fAccelData(NULL) { fWidth = src.fWidth; fHeight = src.fHeight; fRecord = NULL; @@ -141,6 +144,7 @@ SkPicture::SkPicture(const SkPicture& src) : INHERITED() { SkPicture::~SkPicture() { SkSafeUnref(fRecord); SkDELETE(fPlayback); + SkSafeUnref(fAccelData); } void SkPicture::internalOnly_EnableOpts(bool enableOpts) { @@ -152,6 +156,7 @@ void SkPicture::internalOnly_EnableOpts(bool enableOpts) { void SkPicture::swap(SkPicture& other) { SkTSwap(fRecord, other.fRecord); SkTSwap(fPlayback, other.fPlayback); + SkTSwap(fAccelData, other.fAccelData); SkTSwap(fWidth, other.fWidth); SkTSwap(fHeight, other.fHeight); } @@ -188,6 +193,17 @@ void SkPicture::clone(SkPicture* pictures, int count) const { } } +SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() { + static int32_t gNextID = 0; + + int32_t id = sk_atomic_inc(&gNextID); + if (id >= 1 << (8 * sizeof(Domain))) { + SK_CRASH(); + } + + return static_cast<Domain>(id); +} + /////////////////////////////////////////////////////////////////////////////// SkCanvas* SkPicture::beginRecording(int width, int height, @@ -196,7 +212,7 @@ SkCanvas* SkPicture::beginRecording(int width, int height, SkDELETE(fPlayback); fPlayback = NULL; } - + SkSafeUnref(fAccelData); SkSafeSetNull(fRecord); // Must be set before calling createBBoxHierarchy @@ -250,7 +266,7 @@ void SkPicture::endRecording() { void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) { this->endRecording(); - if (fPlayback) { + if (NULL != fPlayback) { fPlayback->draw(*surface, callback); } } @@ -310,7 +326,8 @@ SkPicture::SkPicture(SkPicturePlayback* playback, int width, int height) : fPlayback(playback) , fRecord(NULL) , fWidth(width) - , fHeight(height) {} + , fHeight(height) + , fAccelData(NULL) {} SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) { SkPictInfo info; @@ -418,7 +435,9 @@ void SkPicture::flatten(SkWriteBuffer& buffer) const { } bool SkPicture::willPlayBackBitmaps() const { - if (!fPlayback) return false; + if (!fPlayback) { + return false; + } return fPlayback->containsBitmaps(); } diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index e872f1ac97..a86170b75e 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -25,6 +25,7 @@ #include "SkImageFilter.h" #include "SkMaskFilter.h" #include "SkPathEffect.h" +#include "SkPicture.h" #include "SkRRect.h" #include "SkStroke.h" #include "SkSurface.h" @@ -2003,3 +2004,44 @@ SkGpuDevice::SkGpuDevice(GrContext* context, this->initFromRenderTarget(context, texture->asRenderTarget(), true); fNeedClear = needClear; } + +class GPUAccelData : public SkPicture::AccelData { +public: + GPUAccelData(Key key) : INHERITED(key) { } + +protected: + +private: + typedef SkPicture::AccelData INHERITED; +}; + +// In the future this may not be a static method if we need to incorporate the +// clip and matrix state into the key +SkPicture::AccelData::Key SkGpuDevice::ComputeAccelDataKey() { + static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain(); + + return gGPUID; +} + +void SkGpuDevice::EXPERIMENTAL_optimize(SkPicture* picture) { + SkPicture::AccelData::Key key = ComputeAccelDataKey(); + + GPUAccelData* data = SkNEW_ARGS(GPUAccelData, (key)); + + picture->EXPERIMENTAL_addAccelData(data); +} + +bool SkGpuDevice::EXPERIMENTAL_drawPicture(const SkPicture& picture) { + SkPicture::AccelData::Key key = ComputeAccelDataKey(); + + const SkPicture::AccelData* data = picture.EXPERIMENTAL_getAccelData(key); + if (NULL == data) { + return false; + } + +#if 0 + const GPUAccelData *gpuData = static_cast<const GPUAccelData*>(data); +#endif + + return false; +} diff --git a/tools/PictureRenderer.cpp b/tools/PictureRenderer.cpp index ebac9ca46d..466e31d28e 100644 --- a/tools/PictureRenderer.cpp +++ b/tools/PictureRenderer.cpp @@ -570,20 +570,19 @@ void TiledPictureRenderer::setupPowerOf2Tiles() { } /** - * Draw the specified playback to the canvas translated to rectangle provided, so that this mini + * Draw the specified picture to the canvas translated to rectangle provided, so that this mini * canvas represents the rectangle's portion of the overall picture. * Saves and restores so that the initial clip and matrix return to their state before this function * is called. */ -template<class T> -static void DrawTileToCanvas(SkCanvas* canvas, const SkRect& tileRect, T* playback) { +static void draw_tile_to_canvas(SkCanvas* canvas, const SkRect& tileRect, 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); canvas->setMatrix(mat); - playback->draw(canvas); + canvas->drawPicture(*picture); canvas->restoreToCount(saveCount); canvas->flush(); } @@ -621,7 +620,7 @@ bool TiledPictureRenderer::nextTile(int &i, int &j) { void TiledPictureRenderer::drawCurrentTile() { SkASSERT(fCurrentTileOffset >= 0 && fCurrentTileOffset < fTileRects.count()); - DrawTileToCanvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture); + draw_tile_to_canvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture); } bool TiledPictureRenderer::render(const SkString* path, SkBitmap** out) { @@ -638,7 +637,7 @@ bool TiledPictureRenderer::render(const SkString* path, SkBitmap** out) { } bool success = true; for (int i = 0; i < fTileRects.count(); ++i) { - DrawTileToCanvas(fCanvas, fTileRects[i], fPicture); + draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture); if (NULL != path) { success &= writeAppendNumber(fCanvas, path, i, fJsonSummaryPtr); } @@ -722,7 +721,7 @@ public: } for (int i = fStart; i < fEnd; i++) { - DrawTileToCanvas(fCanvas, fRects[i], fClone); + draw_tile_to_canvas(fCanvas, fRects[i], fClone); if ((fPath != NULL) && !writeAppendNumber(fCanvas, fPath, i, fJsonSummaryPtr) && fSuccess != NULL) { *fSuccess = false; diff --git a/tools/PictureRenderer.h b/tools/PictureRenderer.h index c3438c912f..010aadf05f 100644 --- a/tools/PictureRenderer.h +++ b/tools/PictureRenderer.h @@ -309,6 +309,10 @@ public: } } + SkCanvas* getCanvas() { + return fCanvas; + } + SkGLContextHelper* getGLContext() { GrContextFactory::GLContextType glContextType = GrContextFactory::kNull_GLContextType; diff --git a/tools/render_pictures_main.cpp b/tools/render_pictures_main.cpp index f0609c94fa..245f995382 100644 --- a/tools/render_pictures_main.cpp +++ b/tools/render_pictures_main.cpp @@ -44,6 +44,8 @@ DEFINE_bool(validate, false, "Verify that the rendered image contains the same p DEFINE_bool(bench_record, false, "If true, drop into an infinite loop of recording the picture."); +DEFINE_bool(preprocess, false, "If true, perform device specific preprocessing before rendering."); + static void make_output_filepath(SkString* path, const SkString& dir, const SkString& name) { sk_tools::make_filepath(path, dir, name); @@ -188,6 +190,13 @@ static bool render_picture_internal(const SkString& inputPath, const SkString* o inputPath.c_str()); renderer.init(picture); + + if (FLAGS_preprocess) { + if (NULL != renderer.getCanvas()) { + renderer.getCanvas()->EXPERIMENTAL_optimize(picture); + } + } + renderer.setup(); SkString* outputPath = NULL; |