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 "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      */
    107     void setViewport(SkISize size) { fViewport = size; }
    108 
    109     /**
    110      *  Set the scale factor at which draw the picture.
    111      */
    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      */
    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      */
    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      */
    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
    191     void setSampleCount(int sampleCount) {
    192         fSampleCount = sampleCount;
    193     }
    194 #endif
    195 
    196     void setDrawFilters(DrawFilterFlags const * const filters, const SkString& configName) {
    197         memcpy(fDrawFilters, filters, sizeof(fDrawFilters));
    198         fDrawFiltersConfig = configName;
    199     }
    200 
    201     void setBBoxHierarchyType(BBoxHierarchyType bbhType) {
    202         fBBoxHierarchyType = bbhType;
    203     }
    204 
    205     BBoxHierarchyType getBBoxHierarchyType() { return fBBoxHierarchyType; }
    206 
    207     void setGridSize(int width, int height) {
    208         fGridInfo.fTileInterval.set(width, height);
    209     }
    210 
    211     void setJsonSummaryPtr(ImageResultsSummary* jsonSummaryPtr) {
    212         fJsonSummaryPtr = jsonSummaryPtr;
    213     }
    214 
    215     bool isUsingBitmapDevice() {
    216         return kBitmap_DeviceType == fDeviceType;
    217     }
    218 
    219     virtual SkString getPerIterTimeFormat() { return SkString("%.2f"); }
    220 
    221     virtual SkString getNormalTimeFormat() { return SkString("%6.2f"); }
    222 
    223     /**
    224      * Reports the configuration of this PictureRenderer.
    225      */
    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
    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 
    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 
    291     GrContext* getGrContext() {
    292         return fGrContext;
    293     }
    294 #endif
    295 
    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
    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 
    375     virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
    376 
    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 
    423     void setTileWidth(int width) {
    424         fTileWidth = width;
    425     }
    426 
    427     int getTileWidth() const {
    428         return fTileWidth;
    429     }
    430 
    431     void setTileHeight(int height) {
    432         fTileHeight = height;
    433     }
    434 
    435     int getTileHeight() const {
    436         return fTileHeight;
    437     }
    438 
    439     void setTileWidthPercentage(double percentage) {
    440         fTileWidthPercentage = percentage;
    441     }
    442 
    443     double getTileWidthPercentage() const {
    444         return fTileWidthPercentage;
    445     }
    446 
    447     void setTileHeightPercentage(double percentage) {
    448         fTileHeightPercentage = percentage;
    449     }
    450 
    451     double getTileHeightPercentage() const {
    452         return fTileHeightPercentage;
    453     }
    454 
    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 
    464     int getTileMinPowerOf2Width() const {
    465         return fTileMinPowerOf2Width;
    466     }
    467 
    468     virtual TiledPictureRenderer* getTiledRenderer() SK_OVERRIDE { return this; }
    469 
    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 
    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 
    569     virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
    570 
    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