• 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 "SkCountdown.h"
12 #include "SkDrawFilter.h"
13 #include "SkMath.h"
14 #include "SkPaint.h"
15 #include "SkPicture.h"
16 #include "SkRect.h"
17 #include "SkRefCnt.h"
18 #include "SkRunnable.h"
19 #include "SkString.h"
20 #include "SkTDArray.h"
21 #include "SkThreadPool.h"
22 #include "SkTypes.h"
23 
24 #if SK_SUPPORT_GPU
25 #include "GrContextFactory.h"
26 #include "GrContext.h"
27 #endif
28 
29 class SkBitmap;
30 class SkCanvas;
31 class SkGLContext;
32 class SkThread;
33 
34 namespace sk_tools {
35 
36 class TiledPictureRenderer;
37 
38 class PictureRenderer : public SkRefCnt {
39 
40 public:
41     enum SkDeviceTypes {
42         kBitmap_DeviceType,
43 #if SK_SUPPORT_GPU
44         kGPU_DeviceType
45 #endif
46     };
47 
48     enum BBoxHierarchyType {
49         kNone_BBoxHierarchyType = 0,
50         kRTree_BBoxHierarchyType,
51         kTileGrid_BBoxHierarchyType,
52     };
53 
54     // this uses SkPaint::Flags as a base and adds additional flags
55     enum DrawFilterFlags {
56         kNone_DrawFilterFlag = 0,
57         kBlur_DrawFilterFlag = 0x4000, // toggles between blur and no blur
58         kHinting_DrawFilterFlag = 0x8000, // toggles between no hinting and normal hinting
59         kSlightHinting_DrawFilterFlag = 0x10000, // toggles between slight and normal hinting
60         kAAClip_DrawFilterFlag = 0x20000, // toggles between soft and hard clip
61     };
62 
63     SK_COMPILE_ASSERT(!(kBlur_DrawFilterFlag & SkPaint::kAllFlags), blur_flag_must_be_greater);
64     SK_COMPILE_ASSERT(!(kHinting_DrawFilterFlag & SkPaint::kAllFlags),
65             hinting_flag_must_be_greater);
66     SK_COMPILE_ASSERT(!(kSlightHinting_DrawFilterFlag & SkPaint::kAllFlags),
67             slight_hinting_flag_must_be_greater);
68 
69     /**
70      * Called with each new SkPicture to render.
71      */
72     virtual void init(SkPicture* pict);
73 
74     /**
75      *  Set the viewport so that only the portion listed gets drawn.
76      */
setViewport(SkISize size)77     void setViewport(SkISize size) { fViewport = size; }
78 
79     /**
80      *  Set the scale factor at which draw the picture.
81      */
setScaleFactor(SkScalar scale)82     void setScaleFactor(SkScalar scale) { fScaleFactor = scale; }
83 
84     /**
85      * Perform any setup that should done prior to each iteration of render() which should not be
86      * timed.
87      */
setup()88     virtual void setup() {}
89 
90     /**
91      * Perform work that is to be timed. Typically this is rendering, but is also used for recording
92      * and preparing picture for playback by the subclasses which do those.
93      * If path is non-null, subclass implementations should call write().
94      * @param path If non-null, also write the output to the file specified by path. path should
95      *             have no extension; it will be added by write().
96      * @return bool True if rendering succeeded and, if path is non-null, the output was
97      *             successfully written to a file.
98      */
99     virtual bool render(const SkString* path, SkBitmap** out = NULL) = 0;
100 
101     /**
102      * Called once finished with a particular SkPicture, before calling init again, and before
103      * being done with this Renderer.
104      */
105     virtual void end();
106 
107     /**
108      * If this PictureRenderer is actually a TiledPictureRender, return a pointer to this as a
109      * TiledPictureRender so its methods can be called.
110      */
getTiledRenderer()111     virtual TiledPictureRenderer* getTiledRenderer() { return NULL; }
112 
113     /**
114      * Resets the GPU's state. Does nothing if the backing is raster. For a GPU renderer, calls
115      * flush, and calls finish if callFinish is true.
116      * @param callFinish Whether to call finish.
117      */
118     void resetState(bool callFinish);
119 
setDeviceType(SkDeviceTypes deviceType)120     void setDeviceType(SkDeviceTypes deviceType) {
121         fDeviceType = deviceType;
122     }
123 
setDrawFilters(DrawFilterFlags const * const filters,const SkString & configName)124     void setDrawFilters(DrawFilterFlags const * const filters, const SkString& configName) {
125         memcpy(fDrawFilters, filters, sizeof(fDrawFilters));
126         fDrawFiltersConfig = configName;
127     }
128 
setBBoxHierarchyType(BBoxHierarchyType bbhType)129     void setBBoxHierarchyType(BBoxHierarchyType bbhType) {
130         fBBoxHierarchyType = bbhType;
131     }
132 
setGridSize(int width,int height)133     void setGridSize(int width, int height) {
134         fGridWidth = width;
135         fGridHeight = height;
136     }
137 
isUsingBitmapDevice()138     bool isUsingBitmapDevice() {
139         return kBitmap_DeviceType == fDeviceType;
140     }
141 
getPerIterTimeFormat()142     virtual SkString getPerIterTimeFormat() { return SkString("%.2f"); }
143 
getNormalTimeFormat()144     virtual SkString getNormalTimeFormat() { return SkString("%6.2f"); }
145 
146     /**
147      * Reports the configuration of this PictureRenderer.
148      */
getConfigName()149     SkString getConfigName() {
150         SkString config = this->getConfigNameInternal();
151         if (!fViewport.isEmpty()) {
152             config.appendf("_viewport_%ix%i", fViewport.width(), fViewport.height());
153         }
154         if (kRTree_BBoxHierarchyType == fBBoxHierarchyType) {
155             config.append("_rtree");
156         } else if (kTileGrid_BBoxHierarchyType == fBBoxHierarchyType) {
157             config.append("_grid");
158         }
159 #if SK_SUPPORT_GPU
160         if (this->isUsingGpuDevice()) {
161             config.append("_gpu");
162         }
163 #endif
164         config.append(fDrawFiltersConfig.c_str());
165         return config;
166     }
167 
168 #if SK_SUPPORT_GPU
isUsingGpuDevice()169     bool isUsingGpuDevice() {
170         return kGPU_DeviceType == fDeviceType;
171     }
172 
getGLContext()173     SkGLContext* getGLContext() {
174         if (this->isUsingGpuDevice()) {
175             return fGrContextFactory.getGLContext(GrContextFactory::kNative_GLContextType);
176         } else {
177             return NULL;
178         }
179     }
180 
getGrContext()181     GrContext* getGrContext() {
182         return fGrContext;
183     }
184 #endif
185 
PictureRenderer()186     PictureRenderer()
187         : fPicture(NULL)
188         , fDeviceType(kBitmap_DeviceType)
189         , fBBoxHierarchyType(kNone_BBoxHierarchyType)
190         , fGridWidth(0)
191         , fGridHeight(0)
192 #if SK_SUPPORT_GPU
193         , fGrContext(fGrContextFactory.get(GrContextFactory::kNative_GLContextType))
194 #endif
195         , fScaleFactor(SK_Scalar1)
196         {
197             sk_bzero(fDrawFilters, sizeof(fDrawFilters));
198             fViewport.set(0, 0);
199         }
200 
201 protected:
202     SkAutoTUnref<SkCanvas> fCanvas;
203     SkPicture*             fPicture;
204     SkDeviceTypes          fDeviceType;
205     BBoxHierarchyType      fBBoxHierarchyType;
206     DrawFilterFlags        fDrawFilters[SkDrawFilter::kTypeCount];
207     SkString               fDrawFiltersConfig;
208     int                    fGridWidth, fGridHeight; // used when fBBoxHierarchyType is TileGrid
209 
210 #if SK_SUPPORT_GPU
211     GrContextFactory fGrContextFactory;
212     GrContext* fGrContext;
213 #endif
214 
215     void buildBBoxHierarchy();
216 
217     /**
218      * Return the total width that should be drawn. If the viewport width has been set greater than
219      * 0, this will be the minimum of the current SkPicture's width and the viewport's width.
220      */
221     int getViewWidth();
222 
223     /**
224      * Return the total height that should be drawn. If the viewport height has been set greater
225      * than 0, this will be the minimum of the current SkPicture's height and the viewport's height.
226      */
227     int getViewHeight();
228 
229     /**
230      * Scales the provided canvas to the scale factor set by setScaleFactor.
231      */
232     void scaleToScaleFactor(SkCanvas*);
233 
234     SkPicture* createPicture();
235     uint32_t recordFlags();
236     SkCanvas* setupCanvas();
237     virtual SkCanvas* setupCanvas(int width, int height);
238 
239 private:
240     SkISize                fViewport;
241     SkScalar               fScaleFactor;
242 
243     virtual SkString getConfigNameInternal() = 0;
244 
245     typedef SkRefCnt INHERITED;
246 };
247 
248 /**
249  * This class does not do any rendering, but its render function executes recording, which we want
250  * to time.
251  */
252 class RecordPictureRenderer : public PictureRenderer {
253     virtual bool render(const SkString*, SkBitmap** out = NULL) SK_OVERRIDE;
254 
getPerIterTimeFormat()255     virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
256 
getNormalTimeFormat()257     virtual SkString getNormalTimeFormat() SK_OVERRIDE { return SkString("%6.4f"); }
258 
259 protected:
260     virtual SkCanvas* setupCanvas(int width, int height) SK_OVERRIDE;
261 
262 private:
263     virtual SkString getConfigNameInternal() SK_OVERRIDE;
264 };
265 
266 class PipePictureRenderer : public PictureRenderer {
267 public:
268     virtual bool render(const SkString*, SkBitmap** out = NULL) SK_OVERRIDE;
269 
270 private:
271     virtual SkString getConfigNameInternal() SK_OVERRIDE;
272 
273     typedef PictureRenderer INHERITED;
274 };
275 
276 class SimplePictureRenderer : public PictureRenderer {
277 public:
278     virtual void init(SkPicture* pict) SK_OVERRIDE;
279 
280     virtual bool render(const SkString*, SkBitmap** out = NULL) SK_OVERRIDE;
281 
282 private:
283     virtual SkString getConfigNameInternal() SK_OVERRIDE;
284 
285     typedef PictureRenderer INHERITED;
286 };
287 
288 class TiledPictureRenderer : public PictureRenderer {
289 public:
290     TiledPictureRenderer();
291 
292     virtual void init(SkPicture* pict) SK_OVERRIDE;
293 
294     /**
295      * Renders to tiles, rather than a single canvas. If a path is provided, a separate file is
296      * created for each tile, named "path0.png", "path1.png", etc.
297      * Multithreaded mode currently does not support writing to a file.
298      */
299     virtual bool render(const SkString* path, SkBitmap** out = NULL) SK_OVERRIDE;
300 
301     virtual void end() SK_OVERRIDE;
302 
setTileWidth(int width)303     void setTileWidth(int width) {
304         fTileWidth = width;
305     }
306 
getTileWidth()307     int getTileWidth() const {
308         return fTileWidth;
309     }
310 
setTileHeight(int height)311     void setTileHeight(int height) {
312         fTileHeight = height;
313     }
314 
getTileHeight()315     int getTileHeight() const {
316         return fTileHeight;
317     }
318 
setTileWidthPercentage(double percentage)319     void setTileWidthPercentage(double percentage) {
320         fTileWidthPercentage = percentage;
321     }
322 
getTileWidthPercentage()323     double getTileWidthPercentage() const {
324         return fTileWidthPercentage;
325     }
326 
setTileHeightPercentage(double percentage)327     void setTileHeightPercentage(double percentage) {
328         fTileHeightPercentage = percentage;
329     }
330 
getTileHeightPercentage()331     double getTileHeightPercentage() const {
332         return fTileHeightPercentage;
333     }
334 
setTileMinPowerOf2Width(int width)335     void setTileMinPowerOf2Width(int width) {
336         SkASSERT(SkIsPow2(width) && width > 0);
337         if (!SkIsPow2(width) || width <= 0) {
338             return;
339         }
340 
341         fTileMinPowerOf2Width = width;
342     }
343 
getTileMinPowerOf2Width()344     int getTileMinPowerOf2Width() const {
345         return fTileMinPowerOf2Width;
346     }
347 
getTiledRenderer()348     virtual TiledPictureRenderer* getTiledRenderer() SK_OVERRIDE { return this; }
349 
350     /**
351      * Report the number of tiles in the x and y directions. Must not be called before init.
352      * @param x Output parameter identifying the number of tiles in the x direction.
353      * @param y Output parameter identifying the number of tiles in the y direction.
354      * @return True if the tiles have been set up, and x and y are meaningful. If false, x and y are
355      *         unmodified.
356      */
357     bool tileDimensions(int& x, int&y);
358 
359     /**
360      * Move to the next tile and return its indices. Must be called before calling drawCurrentTile
361      * for the first time.
362      * @param i Output parameter identifying the column of the next tile to be drawn on the next
363      *          call to drawNextTile.
364      * @param j Output parameter identifying the row  of the next tile to be drawn on the next call
365      *          to drawNextTile.
366      * @param True if the tiles have been created and the next tile to be drawn by drawCurrentTile
367      *        is within the range of tiles. If false, i and j are unmodified.
368      */
369     bool nextTile(int& i, int& j);
370 
371     /**
372      * Render one tile. This will draw the same tile each time it is called until nextTile is
373      * called. The tile rendered will depend on how many calls have been made to nextTile.
374      * It is an error to call this without first calling nextTile, or if nextTile returns false.
375      */
376     void drawCurrentTile();
377 
378 protected:
379     SkTDArray<SkRect> fTileRects;
380 
381     virtual SkCanvas* setupCanvas(int width, int height) SK_OVERRIDE;
382     virtual SkString getConfigNameInternal() SK_OVERRIDE;
383 
384 private:
385     int    fTileWidth;
386     int    fTileHeight;
387     double fTileWidthPercentage;
388     double fTileHeightPercentage;
389     int    fTileMinPowerOf2Width;
390 
391     // These variables are only used for timing individual tiles.
392     // Next tile to draw in fTileRects.
393     int    fCurrentTileOffset;
394     // Number of tiles in the x direction.
395     int    fTilesX;
396     // Number of tiles in the y direction.
397     int    fTilesY;
398 
399     void setupTiles();
400     void setupPowerOf2Tiles();
401 
402     typedef PictureRenderer INHERITED;
403 };
404 
405 class CloneData;
406 
407 class MultiCorePictureRenderer : public TiledPictureRenderer {
408 public:
409     explicit MultiCorePictureRenderer(int threadCount);
410 
411     ~MultiCorePictureRenderer();
412 
413     virtual void init(SkPicture* pict) SK_OVERRIDE;
414 
415     /**
416      * Behaves like TiledPictureRenderer::render(), only using multiple threads.
417      */
418     virtual bool render(const SkString* path, SkBitmap** out = NULL) SK_OVERRIDE;
419 
420     virtual void end() SK_OVERRIDE;
421 
422 private:
423     virtual SkString getConfigNameInternal() SK_OVERRIDE;
424 
425     const int            fNumThreads;
426     SkTDArray<SkCanvas*> fCanvasPool;
427     SkThreadPool         fThreadPool;
428     SkPicture*           fPictureClones;
429     CloneData**          fCloneData;
430     SkCountdown          fCountdown;
431 
432     typedef TiledPictureRenderer INHERITED;
433 };
434 
435 /**
436  * This class does not do any rendering, but its render function executes turning an SkPictureRecord
437  * into an SkPicturePlayback, which we want to time.
438  */
439 class PlaybackCreationRenderer : public PictureRenderer {
440 public:
441     virtual void setup() SK_OVERRIDE;
442 
443     virtual bool render(const SkString*, SkBitmap** out = NULL) SK_OVERRIDE;
444 
getPerIterTimeFormat()445     virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
446 
getNormalTimeFormat()447     virtual SkString getNormalTimeFormat() SK_OVERRIDE { return SkString("%6.4f"); }
448 
449 private:
450     SkAutoTUnref<SkPicture> fReplayer;
451 
452     virtual SkString getConfigNameInternal() SK_OVERRIDE;
453 
454     typedef PictureRenderer INHERITED;
455 };
456 
457 extern PictureRenderer* CreateGatherPixelRefsRenderer();
458 extern PictureRenderer* CreatePictureCloneRenderer();
459 
460 }
461 
462 #endif  // PictureRenderer_DEFINED
463