summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/skia/tools/PictureRenderer.h
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/skia/tools/PictureRenderer.h')
-rw-r--r--chromium/third_party/skia/tools/PictureRenderer.h661
1 files changed, 661 insertions, 0 deletions
diff --git a/chromium/third_party/skia/tools/PictureRenderer.h b/chromium/third_party/skia/tools/PictureRenderer.h
new file mode 100644
index 00000000000..efe118ff08f
--- /dev/null
+++ b/chromium/third_party/skia/tools/PictureRenderer.h
@@ -0,0 +1,661 @@
+/*
+ * 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 PictureRenderer_DEFINED
+#define PictureRenderer_DEFINED
+
+#include "SkCanvas.h"
+#include "SkCountdown.h"
+#include "SkDrawFilter.h"
+#include "SkMath.h"
+#include "SkPaint.h"
+#include "SkPicture.h"
+#include "SkPictureRecorder.h"
+#include "SkRect.h"
+#include "SkRefCnt.h"
+#include "SkRunnable.h"
+#include "SkString.h"
+#include "SkTDArray.h"
+#include "SkThreadPool.h"
+#include "SkTypes.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContextFactory.h"
+#include "GrContext.h"
+#endif
+
+#include "image_expectations.h"
+
+class SkBitmap;
+class SkCanvas;
+class SkGLContextHelper;
+class SkThread;
+
+namespace sk_tools {
+
+class TiledPictureRenderer;
+
+class PictureRenderer : public SkRefCnt {
+
+public:
+ enum SkDeviceTypes {
+#if SK_ANGLE
+ kAngle_DeviceType,
+#endif
+#if SK_MESA
+ kMesa_DeviceType,
+#endif
+ kBitmap_DeviceType,
+#if SK_SUPPORT_GPU
+ kGPU_DeviceType,
+ kNVPR_DeviceType,
+#endif
+ };
+
+ enum BBoxHierarchyType {
+ kNone_BBoxHierarchyType = 0,
+ kQuadTree_BBoxHierarchyType,
+ kRTree_BBoxHierarchyType,
+ kTileGrid_BBoxHierarchyType,
+
+ kLast_BBoxHierarchyType = kTileGrid_BBoxHierarchyType,
+ };
+
+ // this uses SkPaint::Flags as a base and adds additional flags
+ enum DrawFilterFlags {
+ kNone_DrawFilterFlag = 0,
+ kHinting_DrawFilterFlag = 0x10000, // toggles between no hinting and normal hinting
+ kSlightHinting_DrawFilterFlag = 0x20000, // toggles between slight and normal hinting
+ kAAClip_DrawFilterFlag = 0x40000, // toggles between soft and hard clip
+ kMaskFilter_DrawFilterFlag = 0x80000, // toggles on/off mask filters (e.g., blurs)
+ };
+
+ SK_COMPILE_ASSERT(!(kMaskFilter_DrawFilterFlag & SkPaint::kAllFlags), maskfilter_flag_must_be_greater);
+ SK_COMPILE_ASSERT(!(kHinting_DrawFilterFlag & SkPaint::kAllFlags),
+ hinting_flag_must_be_greater);
+ SK_COMPILE_ASSERT(!(kSlightHinting_DrawFilterFlag & SkPaint::kAllFlags),
+ slight_hinting_flag_must_be_greater);
+
+ /**
+ * Called with each new SkPicture to render.
+ *
+ * @param pict The SkPicture to render.
+ * @param writePath The output directory within which this renderer should write all images,
+ * or NULL if this renderer should not write all images.
+ * @param mismatchPath The output directory within which this renderer should write any images
+ * which do not match expectations, or NULL if this renderer should not write mismatches.
+ * @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.
+ */
+ virtual void init(SkPicture* pict, const SkString* writePath, const SkString* mismatchPath,
+ const SkString* inputFilename, bool useChecksumBasedFilenames);
+
+ /**
+ * TODO(epoger): Temporary hack, while we work on http://skbug.com/2584 ('bench_pictures is
+ * timing reading pixels and writing json files'), such that:
+ * - render_pictures can call this method and continue to work
+ * - any other callers (bench_pictures) will skip calls to write() by default
+ */
+ void enableWrites() { fEnableWrites = true; }
+
+ /**
+ * Set the viewport so that only the portion listed gets drawn.
+ */
+ void setViewport(SkISize size) { fViewport = size; }
+
+ /**
+ * Set the scale factor at which draw the picture.
+ */
+ void setScaleFactor(SkScalar scale) { fScaleFactor = scale; }
+
+ /**
+ * Perform any setup that should done prior to each iteration of render() which should not be
+ * timed.
+ */
+ virtual void setup() {}
+
+ /**
+ * Perform the work. If this is being called within the context of bench_pictures,
+ * this is the step that will be timed.
+ *
+ * Typically "the work" is rendering an SkPicture into a bitmap, but in some subclasses
+ * it is recording the source SkPicture into another SkPicture.
+ *
+ * If fWritePath has been specified, the result of the work will be written to that dir.
+ * If fMismatchPath has been specified, and the actual image result differs from its
+ * expectation, the result of the work will be written to that dir.
+ *
+ * @param out If non-null, the implementing subclass MAY allocate an SkBitmap, copy the
+ * output image into it, and return it here. (Some subclasses ignore this parameter)
+ * @return bool True if rendering succeeded and, if fWritePath had been specified, the output
+ * was successfully written to a file.
+ */
+ virtual bool render(SkBitmap** out = NULL) = 0;
+
+ /**
+ * Called once finished with a particular SkPicture, before calling init again, and before
+ * being done with this Renderer.
+ */
+ virtual void end();
+
+ /**
+ * If this PictureRenderer is actually a TiledPictureRender, return a pointer to this as a
+ * TiledPictureRender so its methods can be called.
+ */
+ virtual TiledPictureRenderer* getTiledRenderer() { return NULL; }
+
+ /**
+ * Resets the GPU's state. Does nothing if the backing is raster. For a GPU renderer, calls
+ * flush, swapBuffers and, if callFinish is true, finish.
+ * @param callFinish Whether to call finish.
+ */
+ void resetState(bool callFinish);
+
+ /**
+ * Remove all decoded textures from the CPU caches and all uploaded textures
+ * from the GPU.
+ */
+ void purgeTextures();
+
+ /**
+ * Set the backend type. Returns true on success and false on failure.
+ */
+ bool setDeviceType(SkDeviceTypes deviceType) {
+ fDeviceType = deviceType;
+#if SK_SUPPORT_GPU
+ // In case this function is called more than once
+ SkSafeUnref(fGrContext);
+ fGrContext = NULL;
+ // Set to Native so it will have an initial value.
+ GrContextFactory::GLContextType glContextType = GrContextFactory::kNative_GLContextType;
+#endif
+ switch(deviceType) {
+ case kBitmap_DeviceType:
+ return true;
+#if SK_SUPPORT_GPU
+ case kGPU_DeviceType:
+ // Already set to GrContextFactory::kNative_GLContextType, above.
+ break;
+ case kNVPR_DeviceType:
+ glContextType = GrContextFactory::kNVPR_GLContextType;
+ break;
+#if SK_ANGLE
+ case kAngle_DeviceType:
+ glContextType = GrContextFactory::kANGLE_GLContextType;
+ break;
+#endif
+#if SK_MESA
+ case kMesa_DeviceType:
+ glContextType = GrContextFactory::kMESA_GLContextType;
+ break;
+#endif
+#endif
+ default:
+ // Invalid device type.
+ return false;
+ }
+#if SK_SUPPORT_GPU
+ fGrContext = fGrContextFactory.get(glContextType);
+ if (NULL == fGrContext) {
+ return false;
+ } else {
+ fGrContext->ref();
+ return true;
+ }
+#endif
+ }
+
+#if SK_SUPPORT_GPU
+ void setSampleCount(int sampleCount) {
+ fSampleCount = sampleCount;
+ }
+#endif
+
+ void setDrawFilters(DrawFilterFlags const * const filters, const SkString& configName) {
+ memcpy(fDrawFilters, filters, sizeof(fDrawFilters));
+ fDrawFiltersConfig = configName;
+ }
+
+ void setBBoxHierarchyType(BBoxHierarchyType bbhType) {
+ fBBoxHierarchyType = bbhType;
+ }
+
+ BBoxHierarchyType getBBoxHierarchyType() { return fBBoxHierarchyType; }
+
+ void setGridSize(int width, int height) {
+ fGridInfo.fTileInterval.set(width, height);
+ }
+
+ void setJsonSummaryPtr(ImageResultsAndExpectations* jsonSummaryPtr) {
+ fJsonSummaryPtr = jsonSummaryPtr;
+ }
+
+ bool isUsingBitmapDevice() {
+ return kBitmap_DeviceType == fDeviceType;
+ }
+
+ virtual SkString getPerIterTimeFormat() { return SkString("%.2f"); }
+
+ virtual SkString getNormalTimeFormat() { return SkString("%6.2f"); }
+
+ /**
+ * Reports the configuration of this PictureRenderer.
+ */
+ SkString getConfigName() {
+ SkString config = this->getConfigNameInternal();
+ if (!fViewport.isEmpty()) {
+ config.appendf("_viewport_%ix%i", fViewport.width(), fViewport.height());
+ }
+ if (fScaleFactor != SK_Scalar1) {
+ config.appendf("_scalar_%f", SkScalarToFloat(fScaleFactor));
+ }
+ if (kRTree_BBoxHierarchyType == fBBoxHierarchyType) {
+ config.append("_rtree");
+ } else if (kQuadTree_BBoxHierarchyType == fBBoxHierarchyType) {
+ config.append("_quadtree");
+ } 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) {
+ case kGPU_DeviceType:
+ if (fSampleCount) {
+ config.appendf("_msaa%d", fSampleCount);
+ } else {
+ config.append("_gpu");
+ }
+ break;
+ case kNVPR_DeviceType:
+ config.appendf("_nvprmsaa%d", fSampleCount);
+ break;
+#if SK_ANGLE
+ case kAngle_DeviceType:
+ config.append("_angle");
+ break;
+#endif
+#if SK_MESA
+ case kMesa_DeviceType:
+ config.append("_mesa");
+ break;
+#endif
+ default:
+ // Assume that no extra info means bitmap.
+ break;
+ }
+#endif
+ config.append(fDrawFiltersConfig.c_str());
+ return config;
+ }
+
+#if SK_SUPPORT_GPU
+ bool isUsingGpuDevice() {
+ switch (fDeviceType) {
+ case kGPU_DeviceType:
+ case kNVPR_DeviceType:
+ // fall through
+#if SK_ANGLE
+ case kAngle_DeviceType:
+ // fall through
+#endif
+#if SK_MESA
+ case kMesa_DeviceType:
+#endif
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ SkGLContextHelper* getGLContext() {
+ GrContextFactory::GLContextType glContextType
+ = GrContextFactory::kNull_GLContextType;
+ switch(fDeviceType) {
+ case kGPU_DeviceType:
+ glContextType = GrContextFactory::kNative_GLContextType;
+ break;
+ case kNVPR_DeviceType:
+ glContextType = GrContextFactory::kNVPR_GLContextType;
+ break;
+#if SK_ANGLE
+ case kAngle_DeviceType:
+ glContextType = GrContextFactory::kANGLE_GLContextType;
+ break;
+#endif
+#if SK_MESA
+ case kMesa_DeviceType:
+ glContextType = GrContextFactory::kMESA_GLContextType;
+ break;
+#endif
+ default:
+ return NULL;
+ }
+ return fGrContextFactory.getGLContext(glContextType);
+ }
+
+ GrContext* getGrContext() {
+ return fGrContext;
+ }
+#endif
+
+ SkCanvas* getCanvas() {
+ return fCanvas;
+ }
+
+ SkPicture* getPicture() {
+ return fPicture;
+ }
+
+ PictureRenderer()
+ : fJsonSummaryPtr(NULL)
+ , fDeviceType(kBitmap_DeviceType)
+ , fEnableWrites(false)
+ , fBBoxHierarchyType(kNone_BBoxHierarchyType)
+ , fScaleFactor(SK_Scalar1)
+#if SK_SUPPORT_GPU
+ , fGrContext(NULL)
+ , fSampleCount(0)
+#endif
+ {
+ fGridInfo.fMargin.setEmpty();
+ fGridInfo.fOffset.setZero();
+ fGridInfo.fTileInterval.set(1, 1);
+ sk_bzero(fDrawFilters, sizeof(fDrawFilters));
+ fViewport.set(0, 0);
+ }
+
+#if SK_SUPPORT_GPU
+ virtual ~PictureRenderer() {
+ SkSafeUnref(fGrContext);
+ }
+#endif
+
+protected:
+ SkAutoTUnref<SkCanvas> fCanvas;
+ SkAutoTUnref<SkPicture> fPicture;
+ bool fUseChecksumBasedFilenames;
+ ImageResultsAndExpectations* fJsonSummaryPtr;
+ SkDeviceTypes fDeviceType;
+ bool fEnableWrites;
+ BBoxHierarchyType fBBoxHierarchyType;
+ DrawFilterFlags fDrawFilters[SkDrawFilter::kTypeCount];
+ SkString fDrawFiltersConfig;
+ SkString fWritePath;
+ SkString fMismatchPath;
+ SkString fInputFilename;
+ SkTileGridFactory::TileGridInfo fGridInfo; // used when fBBoxHierarchyType is TileGrid
+
+ void buildBBoxHierarchy();
+
+ /**
+ * Return the total width that should be drawn. If the viewport width has been set greater than
+ * 0, this will be the minimum of the current SkPicture's width and the viewport's width.
+ */
+ int getViewWidth();
+
+ /**
+ * Return the total height that should be drawn. If the viewport height has been set greater
+ * than 0, this will be the minimum of the current SkPicture's height and the viewport's height.
+ */
+ int getViewHeight();
+
+ /**
+ * Scales the provided canvas to the scale factor set by setScaleFactor.
+ */
+ void scaleToScaleFactor(SkCanvas*);
+
+ SkBBHFactory* getFactory();
+ uint32_t recordFlags() const { return 0; }
+ SkCanvas* setupCanvas();
+ virtual SkCanvas* setupCanvas(int width, int height);
+
+ /**
+ * Copy src to dest; if src==NULL, set dest to empty string.
+ */
+ static void CopyString(SkString* dest, const SkString* src);
+
+private:
+ SkISize fViewport;
+ SkScalar fScaleFactor;
+#if SK_SUPPORT_GPU
+ GrContextFactory fGrContextFactory;
+ GrContext* fGrContext;
+ int fSampleCount;
+#endif
+
+ virtual SkString getConfigNameInternal() = 0;
+
+ typedef SkRefCnt INHERITED;
+};
+
+/**
+ * This class does not do any rendering, but its render function executes recording, which we want
+ * to time.
+ */
+class RecordPictureRenderer : public PictureRenderer {
+ virtual bool render(SkBitmap** out = NULL) SK_OVERRIDE;
+
+ virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
+
+ virtual SkString getNormalTimeFormat() SK_OVERRIDE { return SkString("%6.4f"); }
+
+protected:
+ virtual SkCanvas* setupCanvas(int width, int height) SK_OVERRIDE;
+
+private:
+ virtual SkString getConfigNameInternal() SK_OVERRIDE;
+};
+
+class PipePictureRenderer : public PictureRenderer {
+public:
+ virtual bool render(SkBitmap** out = NULL) SK_OVERRIDE;
+
+private:
+ virtual SkString getConfigNameInternal() SK_OVERRIDE;
+
+ typedef PictureRenderer INHERITED;
+};
+
+class SimplePictureRenderer : public PictureRenderer {
+public:
+ virtual void init(SkPicture* pict, const SkString* writePath, const SkString* mismatchPath,
+ const SkString* inputFilename, bool useChecksumBasedFilenames) SK_OVERRIDE;
+
+ virtual bool render(SkBitmap** out = NULL) SK_OVERRIDE;
+
+private:
+ virtual SkString getConfigNameInternal() SK_OVERRIDE;
+
+ typedef PictureRenderer INHERITED;
+};
+
+class TiledPictureRenderer : public PictureRenderer {
+public:
+ TiledPictureRenderer();
+
+ virtual void init(SkPicture* pict, const SkString* writePath, const SkString* mismatchPath,
+ const SkString* inputFilename, bool useChecksumBasedFilenames) SK_OVERRIDE;
+
+ /**
+ * Renders to tiles, rather than a single canvas.
+ * If fWritePath was 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(SkBitmap** out = NULL) SK_OVERRIDE;
+
+ virtual void end() SK_OVERRIDE;
+
+ void setTileWidth(int width) {
+ fTileWidth = width;
+ }
+
+ int getTileWidth() const {
+ return fTileWidth;
+ }
+
+ void setTileHeight(int height) {
+ fTileHeight = height;
+ }
+
+ int getTileHeight() const {
+ return fTileHeight;
+ }
+
+ void setTileWidthPercentage(double percentage) {
+ fTileWidthPercentage = percentage;
+ }
+
+ double getTileWidthPercentage() const {
+ return fTileWidthPercentage;
+ }
+
+ void setTileHeightPercentage(double percentage) {
+ fTileHeightPercentage = percentage;
+ }
+
+ double getTileHeightPercentage() const {
+ return fTileHeightPercentage;
+ }
+
+ void setTileMinPowerOf2Width(int width) {
+ SkASSERT(SkIsPow2(width) && width > 0);
+ if (!SkIsPow2(width) || width <= 0) {
+ return;
+ }
+
+ fTileMinPowerOf2Width = width;
+ }
+
+ int getTileMinPowerOf2Width() const {
+ return fTileMinPowerOf2Width;
+ }
+
+ virtual TiledPictureRenderer* getTiledRenderer() SK_OVERRIDE { return this; }
+
+ virtual bool supportsTimingIndividualTiles() { return true; }
+
+ /**
+ * Report the number of tiles in the x and y directions. Must not be called before init.
+ * @param x Output parameter identifying the number of tiles in the x direction.
+ * @param y Output parameter identifying the number of tiles in the y direction.
+ * @return True if the tiles have been set up, and x and y are meaningful. If false, x and y are
+ * unmodified.
+ */
+ bool tileDimensions(int& x, int&y);
+
+ /**
+ * Move to the next tile and return its indices. Must be called before calling drawCurrentTile
+ * for the first time.
+ * @param i Output parameter identifying the column of the next tile to be drawn on the next
+ * call to drawNextTile.
+ * @param j Output parameter identifying the row of the next tile to be drawn on the next call
+ * to drawNextTile.
+ * @param True if the tiles have been created and the next tile to be drawn by drawCurrentTile
+ * is within the range of tiles. If false, i and j are unmodified.
+ */
+ bool nextTile(int& i, int& j);
+
+ /**
+ * Render one tile. This will draw the same tile each time it is called until nextTile is
+ * called. The tile rendered will depend on how many calls have been made to nextTile.
+ * It is an error to call this without first calling nextTile, or if nextTile returns false.
+ */
+ void drawCurrentTile();
+
+protected:
+ SkTDArray<SkRect> fTileRects;
+
+ virtual SkCanvas* setupCanvas(int width, int height) SK_OVERRIDE;
+ virtual SkString getConfigNameInternal() SK_OVERRIDE;
+
+private:
+ int fTileWidth;
+ int fTileHeight;
+ double fTileWidthPercentage;
+ double fTileHeightPercentage;
+ int fTileMinPowerOf2Width;
+
+ // These variables are only used for timing individual tiles.
+ // Next tile to draw in fTileRects.
+ int fCurrentTileOffset;
+ // Number of tiles in the x direction.
+ int fTilesX;
+ // Number of tiles in the y direction.
+ int fTilesY;
+
+ void setupTiles();
+ void setupPowerOf2Tiles();
+
+ typedef PictureRenderer INHERITED;
+};
+
+class CloneData;
+
+class MultiCorePictureRenderer : public TiledPictureRenderer {
+public:
+ explicit MultiCorePictureRenderer(int threadCount);
+
+ ~MultiCorePictureRenderer();
+
+ virtual void init(SkPicture* pict, const SkString* writePath, const SkString* mismatchPath,
+ const SkString* inputFilename, bool useChecksumBasedFilenames) SK_OVERRIDE;
+
+ /**
+ * Behaves like TiledPictureRenderer::render(), only using multiple threads.
+ */
+ virtual bool render(SkBitmap** out = NULL) SK_OVERRIDE;
+
+ virtual void end() SK_OVERRIDE;
+
+ virtual bool supportsTimingIndividualTiles() SK_OVERRIDE { return false; }
+
+private:
+ virtual SkString getConfigNameInternal() SK_OVERRIDE;
+
+ const int fNumThreads;
+ SkTDArray<SkCanvas*> fCanvasPool;
+ SkThreadPool fThreadPool;
+ SkPicture* fPictureClones;
+ CloneData** fCloneData;
+ SkCountdown fCountdown;
+
+ typedef TiledPictureRenderer INHERITED;
+};
+
+/**
+ * This class does not do any rendering, but its render function executes turning an SkPictureRecord
+ * into an SkPicturePlayback, which we want to time.
+ */
+class PlaybackCreationRenderer : public PictureRenderer {
+public:
+ virtual void setup() SK_OVERRIDE;
+
+ virtual bool render(SkBitmap** out = NULL) SK_OVERRIDE;
+
+ virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
+
+ virtual SkString getNormalTimeFormat() SK_OVERRIDE { return SkString("%6.4f"); }
+
+private:
+ SkAutoTDelete<SkPictureRecorder> fRecorder;
+
+ virtual SkString getConfigNameInternal() SK_OVERRIDE;
+
+ typedef PictureRenderer INHERITED;
+};
+
+extern PictureRenderer* CreateGatherPixelRefsRenderer();
+extern PictureRenderer* CreatePictureCloneRenderer();
+
+}
+
+#endif // PictureRenderer_DEFINED