Home | History | Annotate | Download | only in tools
      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      */
     77     void setViewport(SkISize size) { fViewport = size; }
     78 
     79     /**
     80      *  Set the scale factor at which draw the picture.
     81      */
     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      */
     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      */
    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 
    120     void setDeviceType(SkDeviceTypes deviceType) {
    121         fDeviceType = deviceType;
    122     }
    123 
    124     void setDrawFilters(DrawFilterFlags const * const filters, const SkString& configName) {
    125         memcpy(fDrawFilters, filters, sizeof(fDrawFilters));
    126         fDrawFiltersConfig = configName;
    127     }
    128 
    129     void setBBoxHierarchyType(BBoxHierarchyType bbhType) {
    130         fBBoxHierarchyType = bbhType;
    131     }
    132 
    133     void setGridSize(int width, int height) {
    134         fGridWidth = width;
    135         fGridHeight = height;
    136     }
    137 
    138     bool isUsingBitmapDevice() {
    139         return kBitmap_DeviceType == fDeviceType;
    140     }
    141 
    142     virtual SkString getPerIterTimeFormat() { return SkString("%.2f"); }
    143 
    144     virtual SkString getNormalTimeFormat() { return SkString("%6.2f"); }
    145 
    146     /**
    147      * Reports the configuration of this PictureRenderer.
    148      */
    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
    169     bool isUsingGpuDevice() {
    170         return kGPU_DeviceType == fDeviceType;
    171     }
    172 
    173     SkGLContext* getGLContext() {
    174         if (this->isUsingGpuDevice()) {
    175             return fGrContextFactory.getGLContext(GrContextFactory::kNative_GLContextType);
    176         } else {
    177             return NULL;
    178         }
    179     }
    180 
    181     GrContext* getGrContext() {
    182         return fGrContext;
    183     }
    184 #endif
    185 
    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 
    255     virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
    256 
    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 
    303     void setTileWidth(int width) {
    304         fTileWidth = width;
    305     }
    306 
    307     int getTileWidth() const {
    308         return fTileWidth;
    309     }
    310 
    311     void setTileHeight(int height) {
    312         fTileHeight = height;
    313     }
    314 
    315     int getTileHeight() const {
    316         return fTileHeight;
    317     }
    318 
    319     void setTileWidthPercentage(double percentage) {
    320         fTileWidthPercentage = percentage;
    321     }
    322 
    323     double getTileWidthPercentage() const {
    324         return fTileWidthPercentage;
    325     }
    326 
    327     void setTileHeightPercentage(double percentage) {
    328         fTileHeightPercentage = percentage;
    329     }
    330 
    331     double getTileHeightPercentage() const {
    332         return fTileHeightPercentage;
    333     }
    334 
    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 
    344     int getTileMinPowerOf2Width() const {
    345         return fTileMinPowerOf2Width;
    346     }
    347 
    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 
    445     virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
    446 
    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