• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef PictureRenderer_DEFINED
9 #define PictureRenderer_DEFINED
10 
11 #include "SkCanvas.h"
12 #include "SkCountdown.h"
13 #include "SkDrawFilter.h"
14 #include "SkJSONCPP.h"
15 #include "SkMath.h"
16 #include "SkPaint.h"
17 #include "SkPicture.h"
18 #include "SkRect.h"
19 #include "SkRefCnt.h"
20 #include "SkRunnable.h"
21 #include "SkString.h"
22 #include "SkTDArray.h"
23 #include "SkThreadPool.h"
24 #include "SkTileGridPicture.h"
25 #include "SkTypes.h"
26 
27 #if SK_SUPPORT_GPU
28 #include "GrContextFactory.h"
29 #include "GrContext.h"
30 #endif
31 
32 class SkBitmap;
33 class SkCanvas;
34 class SkGLContextHelper;
35 class SkThread;
36 
37 namespace sk_tools {
38 
39 class TiledPictureRenderer;
40 
41 /**
42  * Class for collecting image results (checksums) as we go.
43  */
44 class ImageResultsSummary {
45 public:
46     /**
47      * Adds this bitmap's hash to the summary of results.
48      *
49      * @param testName name of the test
50      * @param bitmap bitmap to store the hash of
51      */
52     void add(const char *testName, const SkBitmap& bitmap);
53 
54     /**
55      * Writes the summary (as constructed so far) to a file.
56      *
57      * @param filename path to write the summary to
58      */
59     void writeToFile(const char *filename);
60 
61 private:
62     Json::Value fActualResultsNoComparison;
63 };
64 
65 class PictureRenderer : public SkRefCnt {
66 
67 public:
68     enum SkDeviceTypes {
69 #if SK_ANGLE
70         kAngle_DeviceType,
71 #endif
72         kBitmap_DeviceType,
73 #if SK_SUPPORT_GPU
74         kGPU_DeviceType,
75 #endif
76     };
77 
78     enum BBoxHierarchyType {
79         kNone_BBoxHierarchyType = 0,
80         kRTree_BBoxHierarchyType,
81         kTileGrid_BBoxHierarchyType,
82     };
83 
84     // this uses SkPaint::Flags as a base and adds additional flags
85     enum DrawFilterFlags {
86         kNone_DrawFilterFlag = 0,
87         kHinting_DrawFilterFlag = 0x10000, // toggles between no hinting and normal hinting
88         kSlightHinting_DrawFilterFlag = 0x20000, // toggles between slight and normal hinting
89         kAAClip_DrawFilterFlag = 0x40000, // toggles between soft and hard clip
90         kMaskFilter_DrawFilterFlag = 0x80000, // toggles on/off mask filters (e.g., blurs)
91     };
92 
93     SK_COMPILE_ASSERT(!(kMaskFilter_DrawFilterFlag & SkPaint::kAllFlags), maskfilter_flag_must_be_greater);
94     SK_COMPILE_ASSERT(!(kHinting_DrawFilterFlag & SkPaint::kAllFlags),
95             hinting_flag_must_be_greater);
96     SK_COMPILE_ASSERT(!(kSlightHinting_DrawFilterFlag & SkPaint::kAllFlags),
97             slight_hinting_flag_must_be_greater);
98 
99     /**
100      * Called with each new SkPicture to render.
101      */
102     virtual void init(SkPicture* pict);
103 
104     /**
105      *  Set the viewport so that only the portion listed gets drawn.
106      */
setViewport(SkISize size)107     void setViewport(SkISize size) { fViewport = size; }
108 
109     /**
110      *  Set the scale factor at which draw the picture.
111      */
setScaleFactor(SkScalar scale)112     void setScaleFactor(SkScalar scale) { fScaleFactor = scale; }
113 
114     /**
115      * Perform any setup that should done prior to each iteration of render() which should not be
116      * timed.
117      */
setup()118     virtual void setup() {}
119 
120     /**
121      * Perform work that is to be timed. Typically this is rendering, but is also used for recording
122      * and preparing picture for playback by the subclasses which do those.
123      * If path is non-null, subclass implementations should call write().
124      * @param path If non-null, also write the output to the file specified by path. path should
125      *             have no extension; it will be added by write().
126      * @return bool True if rendering succeeded and, if path is non-null, the output was
127      *             successfully written to a file.
128      */
129     virtual bool render(const SkString* path, SkBitmap** out = NULL) = 0;
130 
131     /**
132      * Called once finished with a particular SkPicture, before calling init again, and before
133      * being done with this Renderer.
134      */
135     virtual void end();
136 
137     /**
138      * If this PictureRenderer is actually a TiledPictureRender, return a pointer to this as a
139      * TiledPictureRender so its methods can be called.
140      */
getTiledRenderer()141     virtual TiledPictureRenderer* getTiledRenderer() { return NULL; }
142 
143     /**
144      * Resets the GPU's state. Does nothing if the backing is raster. For a GPU renderer, calls
145      * flush, and calls finish if callFinish is true.
146      * @param callFinish Whether to call finish.
147      */
148     void resetState(bool callFinish);
149 
150     /**
151      * Set the backend type. Returns true on success and false on failure.
152      */
setDeviceType(SkDeviceTypes deviceType)153     bool setDeviceType(SkDeviceTypes deviceType) {
154         fDeviceType = deviceType;
155 #if SK_SUPPORT_GPU
156         // In case this function is called more than once
157         SkSafeUnref(fGrContext);
158         fGrContext = NULL;
159         // Set to Native so it will have an initial value.
160         GrContextFactory::GLContextType glContextType = GrContextFactory::kNative_GLContextType;
161 #endif
162         switch(deviceType) {
163             case kBitmap_DeviceType:
164                 return true;
165 #if SK_SUPPORT_GPU
166             case kGPU_DeviceType:
167                 // Already set to GrContextFactory::kNative_GLContextType, above.
168                 break;
169 #if SK_ANGLE
170             case kAngle_DeviceType:
171                 glContextType = GrContextFactory::kANGLE_GLContextType;
172                 break;
173 #endif
174 #endif
175             default:
176                 // Invalid device type.
177                 return false;
178         }
179 #if SK_SUPPORT_GPU
180         fGrContext = fGrContextFactory.get(glContextType);
181         if (NULL == fGrContext) {
182             return false;
183         } else {
184             fGrContext->ref();
185             return true;
186         }
187 #endif
188     }
189 
190 #if SK_SUPPORT_GPU
setSampleCount(int sampleCount)191     void setSampleCount(int sampleCount) {
192         fSampleCount = sampleCount;
193     }
194 #endif
195 
setDrawFilters(DrawFilterFlags const * const filters,const SkString & configName)196     void setDrawFilters(DrawFilterFlags const * const filters, const SkString& configName) {
197         memcpy(fDrawFilters, filters, sizeof(fDrawFilters));
198         fDrawFiltersConfig = configName;
199     }
200 
setBBoxHierarchyType(BBoxHierarchyType bbhType)201     void setBBoxHierarchyType(BBoxHierarchyType bbhType) {
202         fBBoxHierarchyType = bbhType;
203     }
204 
getBBoxHierarchyType()205     BBoxHierarchyType getBBoxHierarchyType() { return fBBoxHierarchyType; }
206 
setGridSize(int width,int height)207     void setGridSize(int width, int height) {
208         fGridInfo.fTileInterval.set(width, height);
209     }
210 
setJsonSummaryPtr(ImageResultsSummary * jsonSummaryPtr)211     void setJsonSummaryPtr(ImageResultsSummary* jsonSummaryPtr) {
212         fJsonSummaryPtr = jsonSummaryPtr;
213     }
214 
isUsingBitmapDevice()215     bool isUsingBitmapDevice() {
216         return kBitmap_DeviceType == fDeviceType;
217     }
218 
getPerIterTimeFormat()219     virtual SkString getPerIterTimeFormat() { return SkString("%.2f"); }
220 
getNormalTimeFormat()221     virtual SkString getNormalTimeFormat() { return SkString("%6.2f"); }
222 
223     /**
224      * Reports the configuration of this PictureRenderer.
225      */
getConfigName()226     SkString getConfigName() {
227         SkString config = this->getConfigNameInternal();
228         if (!fViewport.isEmpty()) {
229             config.appendf("_viewport_%ix%i", fViewport.width(), fViewport.height());
230         }
231         if (kRTree_BBoxHierarchyType == fBBoxHierarchyType) {
232             config.append("_rtree");
233         } else if (kTileGrid_BBoxHierarchyType == fBBoxHierarchyType) {
234             config.append("_grid");
235         }
236 #if SK_SUPPORT_GPU
237         switch (fDeviceType) {
238             case kGPU_DeviceType:
239                 if (fSampleCount) {
240                     config.appendf("_msaa%d", fSampleCount);
241                 } else {
242                     config.append("_gpu");
243                 }
244                 break;
245 #if SK_ANGLE
246             case kAngle_DeviceType:
247                 config.append("_angle");
248                 break;
249 #endif
250             default:
251                 // Assume that no extra info means bitmap.
252                 break;
253         }
254 #endif
255         config.append(fDrawFiltersConfig.c_str());
256         return config;
257     }
258 
259 #if SK_SUPPORT_GPU
isUsingGpuDevice()260     bool isUsingGpuDevice() {
261         switch (fDeviceType) {
262             case kGPU_DeviceType:
263                 // fall through
264 #if SK_ANGLE
265             case kAngle_DeviceType:
266 #endif
267                 return true;
268             default:
269                 return false;
270         }
271     }
272 
getGLContext()273     SkGLContextHelper* getGLContext() {
274         GrContextFactory::GLContextType glContextType
275                 = GrContextFactory::kNull_GLContextType;
276         switch(fDeviceType) {
277             case kGPU_DeviceType:
278                 glContextType = GrContextFactory::kNative_GLContextType;
279                 break;
280 #if SK_ANGLE
281             case kAngle_DeviceType:
282                 glContextType = GrContextFactory::kANGLE_GLContextType;
283                 break;
284 #endif
285             default:
286                 return NULL;
287         }
288         return fGrContextFactory.getGLContext(glContextType);
289     }
290 
getGrContext()291     GrContext* getGrContext() {
292         return fGrContext;
293     }
294 #endif
295 
PictureRenderer()296     PictureRenderer()
297         : fPicture(NULL)
298         , fJsonSummaryPtr(NULL)
299         , fDeviceType(kBitmap_DeviceType)
300         , fBBoxHierarchyType(kNone_BBoxHierarchyType)
301         , fScaleFactor(SK_Scalar1)
302 #if SK_SUPPORT_GPU
303         , fGrContext(NULL)
304         , fSampleCount(0)
305 #endif
306         {
307             fGridInfo.fMargin.setEmpty();
308             fGridInfo.fOffset.setZero();
309             fGridInfo.fTileInterval.set(1, 1);
310             sk_bzero(fDrawFilters, sizeof(fDrawFilters));
311             fViewport.set(0, 0);
312         }
313 
314 #if SK_SUPPORT_GPU
~PictureRenderer()315     virtual ~PictureRenderer() {
316         SkSafeUnref(fGrContext);
317     }
318 #endif
319 
320 protected:
321     SkAutoTUnref<SkCanvas> fCanvas;
322     SkPicture*             fPicture;
323     ImageResultsSummary*   fJsonSummaryPtr;
324     SkDeviceTypes          fDeviceType;
325     BBoxHierarchyType      fBBoxHierarchyType;
326     DrawFilterFlags        fDrawFilters[SkDrawFilter::kTypeCount];
327     SkString               fDrawFiltersConfig;
328     SkTileGridPicture::TileGridInfo fGridInfo; // used when fBBoxHierarchyType is TileGrid
329 
330     void buildBBoxHierarchy();
331 
332     /**
333      * Return the total width that should be drawn. If the viewport width has been set greater than
334      * 0, this will be the minimum of the current SkPicture's width and the viewport's width.
335      */
336     int getViewWidth();
337 
338     /**
339      * Return the total height that should be drawn. If the viewport height has been set greater
340      * than 0, this will be the minimum of the current SkPicture's height and the viewport's height.
341      */
342     int getViewHeight();
343 
344     /**
345      * Scales the provided canvas to the scale factor set by setScaleFactor.
346      */
347     void scaleToScaleFactor(SkCanvas*);
348 
349     SkPicture* createPicture();
350     uint32_t recordFlags();
351     SkCanvas* setupCanvas();
352     virtual SkCanvas* setupCanvas(int width, int height);
353 
354 private:
355     SkISize                fViewport;
356     SkScalar               fScaleFactor;
357 #if SK_SUPPORT_GPU
358     GrContextFactory       fGrContextFactory;
359     GrContext*             fGrContext;
360     int                    fSampleCount;
361 #endif
362 
363     virtual SkString getConfigNameInternal() = 0;
364 
365     typedef SkRefCnt INHERITED;
366 };
367 
368 /**
369  * This class does not do any rendering, but its render function executes recording, which we want
370  * to time.
371  */
372 class RecordPictureRenderer : public PictureRenderer {
373     virtual bool render(const SkString*, SkBitmap** out = NULL) SK_OVERRIDE;
374 
getPerIterTimeFormat()375     virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
376 
getNormalTimeFormat()377     virtual SkString getNormalTimeFormat() SK_OVERRIDE { return SkString("%6.4f"); }
378 
379 protected:
380     virtual SkCanvas* setupCanvas(int width, int height) SK_OVERRIDE;
381 
382 private:
383     virtual SkString getConfigNameInternal() SK_OVERRIDE;
384 };
385 
386 class PipePictureRenderer : public PictureRenderer {
387 public:
388     virtual bool render(const SkString*, SkBitmap** out = NULL) SK_OVERRIDE;
389 
390 private:
391     virtual SkString getConfigNameInternal() SK_OVERRIDE;
392 
393     typedef PictureRenderer INHERITED;
394 };
395 
396 class SimplePictureRenderer : public PictureRenderer {
397 public:
398     virtual void init(SkPicture* pict) SK_OVERRIDE;
399 
400     virtual bool render(const SkString*, SkBitmap** out = NULL) SK_OVERRIDE;
401 
402 private:
403     virtual SkString getConfigNameInternal() SK_OVERRIDE;
404 
405     typedef PictureRenderer INHERITED;
406 };
407 
408 class TiledPictureRenderer : public PictureRenderer {
409 public:
410     TiledPictureRenderer();
411 
412     virtual void init(SkPicture* pict) SK_OVERRIDE;
413 
414     /**
415      * Renders to tiles, rather than a single canvas. If a path is provided, a separate file is
416      * created for each tile, named "path0.png", "path1.png", etc.
417      * Multithreaded mode currently does not support writing to a file.
418      */
419     virtual bool render(const SkString* path, SkBitmap** out = NULL) SK_OVERRIDE;
420 
421     virtual void end() SK_OVERRIDE;
422 
setTileWidth(int width)423     void setTileWidth(int width) {
424         fTileWidth = width;
425     }
426 
getTileWidth()427     int getTileWidth() const {
428         return fTileWidth;
429     }
430 
setTileHeight(int height)431     void setTileHeight(int height) {
432         fTileHeight = height;
433     }
434 
getTileHeight()435     int getTileHeight() const {
436         return fTileHeight;
437     }
438 
setTileWidthPercentage(double percentage)439     void setTileWidthPercentage(double percentage) {
440         fTileWidthPercentage = percentage;
441     }
442 
getTileWidthPercentage()443     double getTileWidthPercentage() const {
444         return fTileWidthPercentage;
445     }
446 
setTileHeightPercentage(double percentage)447     void setTileHeightPercentage(double percentage) {
448         fTileHeightPercentage = percentage;
449     }
450 
getTileHeightPercentage()451     double getTileHeightPercentage() const {
452         return fTileHeightPercentage;
453     }
454 
setTileMinPowerOf2Width(int width)455     void setTileMinPowerOf2Width(int width) {
456         SkASSERT(SkIsPow2(width) && width > 0);
457         if (!SkIsPow2(width) || width <= 0) {
458             return;
459         }
460 
461         fTileMinPowerOf2Width = width;
462     }
463 
getTileMinPowerOf2Width()464     int getTileMinPowerOf2Width() const {
465         return fTileMinPowerOf2Width;
466     }
467 
getTiledRenderer()468     virtual TiledPictureRenderer* getTiledRenderer() SK_OVERRIDE { return this; }
469 
supportsTimingIndividualTiles()470     virtual bool supportsTimingIndividualTiles() { return true; }
471 
472     /**
473      * Report the number of tiles in the x and y directions. Must not be called before init.
474      * @param x Output parameter identifying the number of tiles in the x direction.
475      * @param y Output parameter identifying the number of tiles in the y direction.
476      * @return True if the tiles have been set up, and x and y are meaningful. If false, x and y are
477      *         unmodified.
478      */
479     bool tileDimensions(int& x, int&y);
480 
481     /**
482      * Move to the next tile and return its indices. Must be called before calling drawCurrentTile
483      * for the first time.
484      * @param i Output parameter identifying the column of the next tile to be drawn on the next
485      *          call to drawNextTile.
486      * @param j Output parameter identifying the row  of the next tile to be drawn on the next call
487      *          to drawNextTile.
488      * @param True if the tiles have been created and the next tile to be drawn by drawCurrentTile
489      *        is within the range of tiles. If false, i and j are unmodified.
490      */
491     bool nextTile(int& i, int& j);
492 
493     /**
494      * Render one tile. This will draw the same tile each time it is called until nextTile is
495      * called. The tile rendered will depend on how many calls have been made to nextTile.
496      * It is an error to call this without first calling nextTile, or if nextTile returns false.
497      */
498     void drawCurrentTile();
499 
500 protected:
501     SkTDArray<SkRect> fTileRects;
502 
503     virtual SkCanvas* setupCanvas(int width, int height) SK_OVERRIDE;
504     virtual SkString getConfigNameInternal() SK_OVERRIDE;
505 
506 private:
507     int    fTileWidth;
508     int    fTileHeight;
509     double fTileWidthPercentage;
510     double fTileHeightPercentage;
511     int    fTileMinPowerOf2Width;
512 
513     // These variables are only used for timing individual tiles.
514     // Next tile to draw in fTileRects.
515     int    fCurrentTileOffset;
516     // Number of tiles in the x direction.
517     int    fTilesX;
518     // Number of tiles in the y direction.
519     int    fTilesY;
520 
521     void setupTiles();
522     void setupPowerOf2Tiles();
523 
524     typedef PictureRenderer INHERITED;
525 };
526 
527 class CloneData;
528 
529 class MultiCorePictureRenderer : public TiledPictureRenderer {
530 public:
531     explicit MultiCorePictureRenderer(int threadCount);
532 
533     ~MultiCorePictureRenderer();
534 
535     virtual void init(SkPicture* pict) SK_OVERRIDE;
536 
537     /**
538      * Behaves like TiledPictureRenderer::render(), only using multiple threads.
539      */
540     virtual bool render(const SkString* path, SkBitmap** out = NULL) SK_OVERRIDE;
541 
542     virtual void end() SK_OVERRIDE;
543 
supportsTimingIndividualTiles()544     virtual bool supportsTimingIndividualTiles() SK_OVERRIDE { return false; }
545 
546 private:
547     virtual SkString getConfigNameInternal() SK_OVERRIDE;
548 
549     const int            fNumThreads;
550     SkTDArray<SkCanvas*> fCanvasPool;
551     SkThreadPool         fThreadPool;
552     SkPicture*           fPictureClones;
553     CloneData**          fCloneData;
554     SkCountdown          fCountdown;
555 
556     typedef TiledPictureRenderer INHERITED;
557 };
558 
559 /**
560  * This class does not do any rendering, but its render function executes turning an SkPictureRecord
561  * into an SkPicturePlayback, which we want to time.
562  */
563 class PlaybackCreationRenderer : public PictureRenderer {
564 public:
565     virtual void setup() SK_OVERRIDE;
566 
567     virtual bool render(const SkString*, SkBitmap** out = NULL) SK_OVERRIDE;
568 
getPerIterTimeFormat()569     virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
570 
getNormalTimeFormat()571     virtual SkString getNormalTimeFormat() SK_OVERRIDE { return SkString("%6.4f"); }
572 
573 private:
574     SkAutoTUnref<SkPicture> fReplayer;
575 
576     virtual SkString getConfigNameInternal() SK_OVERRIDE;
577 
578     typedef PictureRenderer INHERITED;
579 };
580 
581 extern PictureRenderer* CreateGatherPixelRefsRenderer();
582 extern PictureRenderer* CreatePictureCloneRenderer();
583 
584 }
585 
586 #endif  // PictureRenderer_DEFINED
587