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