aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkCanvas.h8
-rw-r--r--include/core/SkDevice.h18
-rw-r--r--include/core/SkPicture.h40
-rw-r--r--include/gpu/SkGpuDevice.h9
-rw-r--r--src/core/SkCanvas.cpp15
-rw-r--r--src/core/SkDevice.cpp9
-rw-r--r--src/core/SkPicture.cpp29
-rw-r--r--src/gpu/SkGpuDevice.cpp42
-rw-r--r--tools/PictureRenderer.cpp13
-rw-r--r--tools/PictureRenderer.h4
-rw-r--r--tools/render_pictures_main.cpp9
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;