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