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