2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #ifndef PictureRenderer_DEFINED
9 #define PictureRenderer_DEFINED
12 #include "SkDrawFilter.h"
13 #include "SkJSONCPP.h"
16 #include "SkPicture.h"
17 #include "SkPictureRecorder.h"
21 #include "SkTDArray.h"
25 #include "GrContextFactory.h"
26 #include "GrContext.h"
29 #include "image_expectations.h"
38 class TiledPictureRenderer;
40 class PictureRenderer : public SkRefCnt {
57 enum BBoxHierarchyType {
58 kNone_BBoxHierarchyType = 0,
59 kRTree_BBoxHierarchyType,
61 kLast_BBoxHierarchyType = kRTree_BBoxHierarchyType,
64 // this uses SkPaint::Flags as a base and adds additional flags
65 enum DrawFilterFlags {
66 kNone_DrawFilterFlag = 0,
67 kHinting_DrawFilterFlag = 0x10000, // toggles between no hinting and normal hinting
68 kSlightHinting_DrawFilterFlag = 0x20000, // toggles between slight and normal hinting
69 kAAClip_DrawFilterFlag = 0x40000, // toggles between soft and hard clip
70 kMaskFilter_DrawFilterFlag = 0x80000, // toggles on/off mask filters (e.g., blurs)
73 SK_COMPILE_ASSERT(!(kMaskFilter_DrawFilterFlag & SkPaint::kAllFlags), maskfilter_flag_must_be_greater);
74 SK_COMPILE_ASSERT(!(kHinting_DrawFilterFlag & SkPaint::kAllFlags),
75 hinting_flag_must_be_greater);
76 SK_COMPILE_ASSERT(!(kSlightHinting_DrawFilterFlag & SkPaint::kAllFlags),
77 slight_hinting_flag_must_be_greater);
80 * Called with each new SkPicture to render.
82 * @param pict The SkPicture to render.
83 * @param writePath The output directory within which this renderer should write all images,
84 * or NULL if this renderer should not write all images.
85 * @param mismatchPath The output directory within which this renderer should write any images
86 * which do not match expectations, or NULL if this renderer should not write mismatches.
87 * @param inputFilename The name of the input file we are rendering.
88 * @param useChecksumBasedFilenames Whether to use checksum-based filenames when writing
89 * bitmap images to disk.
90 * @param useMultiPictureDraw true if MultiPictureDraw should be used for rendering
92 virtual void init(const SkPicture* pict,
93 const SkString* writePath,
94 const SkString* mismatchPath,
95 const SkString* inputFilename,
96 bool useChecksumBasedFilenames,
97 bool useMultiPictureDraw);
100 * TODO(epoger): Temporary hack, while we work on http://skbug.com/2584 ('bench_pictures is
101 * timing reading pixels and writing json files'), such that:
102 * - render_pictures can call this method and continue to work
103 * - any other callers (bench_pictures) will skip calls to write() by default
105 void enableWrites() { fEnableWrites = true; }
108 * Set the viewport so that only the portion listed gets drawn.
110 void setViewport(SkISize size) { fViewport = size; }
113 * Set the scale factor at which draw the picture.
115 void setScaleFactor(SkScalar scale) { fScaleFactor = scale; }
118 * Perform any setup that should done prior to each iteration of render() which should not be
121 virtual void setup() {}
124 * Perform the work. If this is being called within the context of bench_pictures,
125 * this is the step that will be timed.
127 * Typically "the work" is rendering an SkPicture into a bitmap, but in some subclasses
128 * it is recording the source SkPicture into another SkPicture.
130 * If fWritePath has been specified, the result of the work will be written to that dir.
131 * If fMismatchPath has been specified, and the actual image result differs from its
132 * expectation, the result of the work will be written to that dir.
134 * @param out If non-null, the implementing subclass MAY allocate an SkBitmap, copy the
135 * output image into it, and return it here. (Some subclasses ignore this parameter)
136 * @return bool True if rendering succeeded and, if fWritePath had been specified, the output
137 * was successfully written to a file.
139 virtual bool render(SkBitmap** out = NULL) = 0;
142 * Called once finished with a particular SkPicture, before calling init again, and before
143 * being done with this Renderer.
148 * If this PictureRenderer is actually a TiledPictureRender, return a pointer to this as a
149 * TiledPictureRender so its methods can be called.
151 virtual TiledPictureRenderer* getTiledRenderer() { return NULL; }
154 * Resets the GPU's state. Does nothing if the backing is raster. For a GPU renderer, calls
155 * flush, swapBuffers and, if callFinish is true, finish.
156 * @param callFinish Whether to call finish.
158 void resetState(bool callFinish);
161 * Remove all decoded textures from the CPU caches and all uploaded textures
164 void purgeTextures();
167 * Set the backend type. Returns true on success and false on failure.
170 bool setDeviceType(SkDeviceTypes deviceType, GrGLStandard gpuAPI = kNone_GrGLStandard) {
172 bool setDeviceType(SkDeviceTypes deviceType) {
174 fDeviceType = deviceType;
176 // In case this function is called more than once
177 SkSafeUnref(fGrContext);
179 // Set to Native so it will have an initial value.
180 GrContextFactory::GLContextType glContextType = GrContextFactory::kNative_GLContextType;
183 case kBitmap_DeviceType:
186 case kGPU_DeviceType:
187 // Already set to GrContextFactory::kNative_GLContextType, above.
189 case kNVPR_DeviceType:
190 glContextType = GrContextFactory::kNVPR_GLContextType;
193 case kAngle_DeviceType:
194 glContextType = GrContextFactory::kANGLE_GLContextType;
198 case kMesa_DeviceType:
199 glContextType = GrContextFactory::kMESA_GLContextType;
204 // Invalid device type.
208 fGrContext = fGrContextFactory.get(glContextType, gpuAPI);
209 if (NULL == fGrContext) {
219 void setSampleCount(int sampleCount) {
220 fSampleCount = sampleCount;
223 void setUseDFText(bool useDFText) {
224 fUseDFText = useDFText;
228 void setDrawFilters(DrawFilterFlags const * const filters, const SkString& configName) {
229 memcpy(fDrawFilters, filters, sizeof(fDrawFilters));
230 fDrawFiltersConfig = configName;
233 void setBBoxHierarchyType(BBoxHierarchyType bbhType) {
234 fBBoxHierarchyType = bbhType;
237 BBoxHierarchyType getBBoxHierarchyType() { return fBBoxHierarchyType; }
239 void setJsonSummaryPtr(ImageResultsAndExpectations* jsonSummaryPtr) {
240 fJsonSummaryPtr = jsonSummaryPtr;
243 bool isUsingBitmapDevice() {
244 return kBitmap_DeviceType == fDeviceType;
247 virtual SkString getPerIterTimeFormat() { return SkString("%.2f"); }
249 virtual SkString getNormalTimeFormat() { return SkString("%6.2f"); }
252 * Reports the configuration of this PictureRenderer.
254 SkString getConfigName() {
255 SkString config = this->getConfigNameInternal();
256 if (!fViewport.isEmpty()) {
257 config.appendf("_viewport_%ix%i", fViewport.width(), fViewport.height());
259 if (fScaleFactor != SK_Scalar1) {
260 config.appendf("_scalar_%f", SkScalarToFloat(fScaleFactor));
262 if (kRTree_BBoxHierarchyType == fBBoxHierarchyType) {
263 config.append("_rtree");
266 switch (fDeviceType) {
267 case kGPU_DeviceType:
269 config.appendf("_msaa%d", fSampleCount);
270 } else if (fUseDFText) {
271 config.append("_gpudft");
273 config.append("_gpu");
276 case kNVPR_DeviceType:
277 config.appendf("_nvprmsaa%d", fSampleCount);
280 case kAngle_DeviceType:
281 config.append("_angle");
285 case kMesa_DeviceType:
286 config.append("_mesa");
290 // Assume that no extra info means bitmap.
294 config.append(fDrawFiltersConfig.c_str());
298 Json::Value getJSONConfig() {
301 result["mode"] = this->getConfigNameInternal().c_str();
302 result["scale"] = 1.0f;
303 if (SK_Scalar1 != fScaleFactor) {
304 result["scale"] = SkScalarToFloat(fScaleFactor);
306 if (kRTree_BBoxHierarchyType == fBBoxHierarchyType) {
307 result["bbh"] = "rtree";
311 switch (fDeviceType) {
312 case kGPU_DeviceType:
313 if (0 != fSampleCount) {
315 tmp.appendS32(fSampleCount);
316 result["config"] = tmp.c_str();
317 } else if (fUseDFText) {
318 result["config"] = "gpudft";
320 result["config"] = "gpu";
323 case kNVPR_DeviceType:
325 tmp.appendS32(fSampleCount);
326 result["config"] = tmp.c_str();
329 case kAngle_DeviceType:
330 result["config"] = "angle";
334 case kMesa_DeviceType:
335 result["config"] = "mesa";
339 // Assume that no extra info means bitmap.
347 bool isUsingGpuDevice() {
348 switch (fDeviceType) {
349 case kGPU_DeviceType:
350 case kNVPR_DeviceType:
353 case kAngle_DeviceType:
357 case kMesa_DeviceType:
365 SkGLContext* getGLContext() {
366 GrContextFactory::GLContextType glContextType
367 = GrContextFactory::kNull_GLContextType;
368 switch(fDeviceType) {
369 case kGPU_DeviceType:
370 glContextType = GrContextFactory::kNative_GLContextType;
372 case kNVPR_DeviceType:
373 glContextType = GrContextFactory::kNVPR_GLContextType;
376 case kAngle_DeviceType:
377 glContextType = GrContextFactory::kANGLE_GLContextType;
381 case kMesa_DeviceType:
382 glContextType = GrContextFactory::kMESA_GLContextType;
388 return fGrContextFactory.getGLContext(glContextType);
391 GrContext* getGrContext() {
395 const GrContext::Options& getGrContextOptions() {
396 return fGrContextFactory.getGlobalOptions();
400 SkCanvas* getCanvas() {
404 const SkPicture* getPicture() {
409 explicit PictureRenderer(const GrContext::Options &opts)
413 : fJsonSummaryPtr(NULL)
414 , fDeviceType(kBitmap_DeviceType)
415 , fEnableWrites(false)
416 , fBBoxHierarchyType(kNone_BBoxHierarchyType)
417 , fScaleFactor(SK_Scalar1)
419 , fGrContextFactory(opts)
425 sk_bzero(fDrawFilters, sizeof(fDrawFilters));
430 virtual ~PictureRenderer() {
431 SkSafeUnref(fGrContext);
436 SkAutoTUnref<SkCanvas> fCanvas;
437 SkAutoTUnref<const SkPicture> fPicture;
438 bool fUseChecksumBasedFilenames;
439 bool fUseMultiPictureDraw;
440 ImageResultsAndExpectations* fJsonSummaryPtr;
441 SkDeviceTypes fDeviceType;
443 BBoxHierarchyType fBBoxHierarchyType;
444 DrawFilterFlags fDrawFilters[SkDrawFilter::kTypeCount];
445 SkString fDrawFiltersConfig;
447 SkString fMismatchPath;
448 SkString fInputFilename;
450 void buildBBoxHierarchy();
453 * Return the total width that should be drawn. If the viewport width has been set greater than
454 * 0, this will be the minimum of the current SkPicture's width and the viewport's width.
459 * Return the total height that should be drawn. If the viewport height has been set greater
460 * than 0, this will be the minimum of the current SkPicture's height and the viewport's height.
465 * Scales the provided canvas to the scale factor set by setScaleFactor.
467 void scaleToScaleFactor(SkCanvas*);
469 SkBBHFactory* getFactory();
470 uint32_t recordFlags() const { return 0; }
471 SkCanvas* setupCanvas();
472 virtual SkCanvas* setupCanvas(int width, int height);
475 * Copy src to dest; if src==NULL, set dest to empty string.
477 static void CopyString(SkString* dest, const SkString* src);
481 SkScalar fScaleFactor;
483 GrContextFactory fGrContextFactory;
484 GrContext* fGrContext;
489 virtual SkString getConfigNameInternal() = 0;
491 typedef SkRefCnt INHERITED;
495 * This class does not do any rendering, but its render function executes recording, which we want
498 class RecordPictureRenderer : public PictureRenderer {
501 RecordPictureRenderer(const GrContext::Options &opts) : INHERITED(opts) { }
504 bool render(SkBitmap** out = NULL) SK_OVERRIDE;
506 SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
508 SkString getNormalTimeFormat() SK_OVERRIDE { return SkString("%6.4f"); }
511 SkCanvas* setupCanvas(int width, int height) SK_OVERRIDE;
514 SkString getConfigNameInternal() SK_OVERRIDE;
516 typedef PictureRenderer INHERITED;
519 class PipePictureRenderer : public PictureRenderer {
522 PipePictureRenderer(const GrContext::Options &opts) : INHERITED(opts) { }
525 bool render(SkBitmap** out = NULL) SK_OVERRIDE;
528 SkString getConfigNameInternal() SK_OVERRIDE;
530 typedef PictureRenderer INHERITED;
533 class SimplePictureRenderer : public PictureRenderer {
536 SimplePictureRenderer(const GrContext::Options &opts) : INHERITED(opts) { }
539 virtual void init(const SkPicture* pict,
540 const SkString* writePath,
541 const SkString* mismatchPath,
542 const SkString* inputFilename,
543 bool useChecksumBasedFilenames,
544 bool useMultiPictureDraw) SK_OVERRIDE;
546 bool render(SkBitmap** out = NULL) SK_OVERRIDE;
549 SkString getConfigNameInternal() SK_OVERRIDE;
551 typedef PictureRenderer INHERITED;
554 class TiledPictureRenderer : public PictureRenderer {
557 TiledPictureRenderer(const GrContext::Options &opts);
559 TiledPictureRenderer();
562 virtual void init(const SkPicture* pict,
563 const SkString* writePath,
564 const SkString* mismatchPath,
565 const SkString* inputFilename,
566 bool useChecksumBasedFilenames,
567 bool useMultiPictureDraw) SK_OVERRIDE;
570 * Renders to tiles, rather than a single canvas.
571 * If fWritePath was provided, a separate file is
572 * created for each tile, named "path0.png", "path1.png", etc.
574 bool render(SkBitmap** out = NULL) SK_OVERRIDE;
576 void end() SK_OVERRIDE;
578 void setTileWidth(int width) {
582 int getTileWidth() const {
586 void setTileHeight(int height) {
587 fTileHeight = height;
590 int getTileHeight() const {
594 void setTileWidthPercentage(double percentage) {
595 fTileWidthPercentage = percentage;
598 double getTileWidthPercentage() const {
599 return fTileWidthPercentage;
602 void setTileHeightPercentage(double percentage) {
603 fTileHeightPercentage = percentage;
606 double getTileHeightPercentage() const {
607 return fTileHeightPercentage;
610 void setTileMinPowerOf2Width(int width) {
611 SkASSERT(SkIsPow2(width) && width > 0);
612 if (!SkIsPow2(width) || width <= 0) {
616 fTileMinPowerOf2Width = width;
619 int getTileMinPowerOf2Width() const {
620 return fTileMinPowerOf2Width;
623 TiledPictureRenderer* getTiledRenderer() SK_OVERRIDE { return this; }
625 virtual bool supportsTimingIndividualTiles() { return true; }
628 * Report the number of tiles in the x and y directions. Must not be called before init.
629 * @param x Output parameter identifying the number of tiles in the x direction.
630 * @param y Output parameter identifying the number of tiles in the y direction.
631 * @return True if the tiles have been set up, and x and y are meaningful. If false, x and y are
634 bool tileDimensions(int& x, int&y);
637 * Move to the next tile and return its indices. Must be called before calling drawCurrentTile
638 * for the first time.
639 * @param i Output parameter identifying the column of the next tile to be drawn on the next
640 * call to drawNextTile.
641 * @param j Output parameter identifying the row of the next tile to be drawn on the next call
643 * @param True if the tiles have been created and the next tile to be drawn by drawCurrentTile
644 * is within the range of tiles. If false, i and j are unmodified.
646 bool nextTile(int& i, int& j);
649 * Render one tile. This will draw the same tile each time it is called until nextTile is
650 * called. The tile rendered will depend on how many calls have been made to nextTile.
651 * It is an error to call this without first calling nextTile, or if nextTile returns false.
653 void drawCurrentTile();
656 SkTDArray<SkIRect> fTileRects;
658 SkCanvas* setupCanvas(int width, int height) SK_OVERRIDE;
659 SkString getConfigNameInternal() SK_OVERRIDE;
664 double fTileWidthPercentage;
665 double fTileHeightPercentage;
666 int fTileMinPowerOf2Width;
668 // These variables are only used for timing individual tiles.
669 // Next tile to draw in fTileRects.
670 int fCurrentTileOffset;
671 // Number of tiles in the x direction.
673 // Number of tiles in the y direction.
677 void setupPowerOf2Tiles();
678 bool postRender(SkCanvas*, const SkIRect& tileRect,
679 SkBitmap* tempBM, SkBitmap** out,
682 typedef PictureRenderer INHERITED;
686 * This class does not do any rendering, but its render function executes turning an SkPictureRecord
687 * into an SkPicturePlayback, which we want to time.
689 class PlaybackCreationRenderer : public PictureRenderer {
692 PlaybackCreationRenderer(const GrContext::Options &opts) : INHERITED(opts) { }
695 void setup() SK_OVERRIDE;
697 bool render(SkBitmap** out = NULL) SK_OVERRIDE;
699 SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
701 SkString getNormalTimeFormat() SK_OVERRIDE { return SkString("%6.4f"); }
704 SkAutoTDelete<SkPictureRecorder> fRecorder;
706 SkString getConfigNameInternal() SK_OVERRIDE;
708 typedef PictureRenderer INHERITED;
712 extern PictureRenderer* CreateGatherPixelRefsRenderer(const GrContext::Options& opts);
714 extern PictureRenderer* CreateGatherPixelRefsRenderer();
719 #endif // PictureRenderer_DEFINED