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