1 /* 2 * Copyright 2018 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 DDLTileHelper_DEFINED 9 #define DDLTileHelper_DEFINED 10 11 #include "include/core/SkDeferredDisplayList.h" 12 #include "include/core/SkRect.h" 13 #include "include/core/SkRefCnt.h" 14 #include "include/core/SkSpan.h" 15 #include "include/core/SkSurfaceCharacterization.h" 16 17 class DDLPromiseImageHelper; 18 class PromiseImageCallbackContext; 19 class SkCanvas; 20 class SkData; 21 class SkDeferredDisplayListRecorder; 22 class SkPicture; 23 class SkSurface; 24 class SkSurfaceCharacterization; 25 class SkTaskGroup; 26 27 class DDLTileHelper { 28 public: 29 // The TileData class encapsulates the information and behavior of a single tile when 30 // rendering with DDLs. 31 class TileData { 32 public: 33 TileData(); 34 ~TileData(); 35 initialized()36 bool initialized() const { return fID != -1; } 37 38 void init(int id, 39 GrDirectContext*, 40 const SkSurfaceCharacterization& dstChar, 41 const SkIRect& clip, 42 const SkIRect& paddingOutsets); 43 44 // Create the DDL for this tile (i.e., fill in 'fDisplayList'). 45 void createDDL(const SkPicture*); 46 dropDDL()47 void dropDDL() { fDisplayList.reset(); } 48 49 // Precompile all the programs required to draw this tile's DDL 50 void precompile(GrDirectContext*); 51 52 // Just draw the re-inflated per-tile SKP directly into this tile w/o going through a DDL 53 // first. This is used for determining the overhead of using DDLs (i.e., it replaces 54 // a 'createDDL' and 'draw' pair. 55 void drawSKPDirectly(GrDirectContext*, const SkPicture*); 56 57 // Replay the recorded DDL into the tile surface - filling in 'fBackendTexture'. 58 void draw(GrDirectContext*); 59 60 void reset(); 61 id()62 int id() const { return fID; } clipRect()63 SkIRect clipRect() const { return fClip; } paddedRectSize()64 SkISize paddedRectSize() const { 65 return { fClip.width() + fPaddingOutsets.fLeft + fPaddingOutsets.fRight, 66 fClip.height() + fPaddingOutsets.fTop + fPaddingOutsets.fBottom }; 67 } padOffset()68 SkIVector padOffset() const { return { fPaddingOutsets.fLeft, fPaddingOutsets.fTop }; } 69 ddl()70 SkDeferredDisplayList* ddl() { return fDisplayList.get(); } 71 72 sk_sp<SkImage> makePromiseImageForDst(sk_sp<GrContextThreadSafeProxy>); dropCallbackContext()73 void dropCallbackContext() { fCallbackContext.reset(); } 74 75 static void CreateBackendTexture(GrDirectContext*, TileData*); 76 static void DeleteBackendTexture(GrDirectContext*, TileData*); 77 78 private: 79 sk_sp<SkSurface> makeWrappedTileDest(GrRecordingContext* context); 80 refCallbackContext()81 sk_sp<PromiseImageCallbackContext> refCallbackContext() { return fCallbackContext; } 82 83 int fID = -1; 84 SkIRect fClip; // in the device space of the final SkSurface 85 SkIRect fPaddingOutsets; // random padding for the output surface 86 SkSurfaceCharacterization fPlaybackChar; // characterization for the tile's dst surface 87 88 // The callback context holds (via its SkPromiseImageTexture) the backend texture 89 // that is both wrapped in 'fTileSurface' and backs this tile's promise image 90 // (i.e., the one returned by 'makePromiseImage'). 91 sk_sp<PromiseImageCallbackContext> fCallbackContext; 92 // 'fTileSurface' wraps the backend texture in 'fCallbackContext' and must exist until 93 // after 'fDisplayList' has been flushed (bc it owns the proxy the DDL's destination 94 // trampoline points at). 95 // TODO: fix the ref-order so we don't need 'fTileSurface' here 96 sk_sp<SkSurface> fTileSurface; 97 98 sk_sp<SkDeferredDisplayList> fDisplayList; 99 }; 100 101 DDLTileHelper(GrDirectContext*, 102 const SkSurfaceCharacterization& dstChar, 103 const SkIRect& viewport, 104 int numXDivisions, int numYDivisions, 105 bool addRandomPaddingToDst); 106 107 void kickOffThreadedWork(SkTaskGroup* recordingTaskGroup, 108 SkTaskGroup* gpuTaskGroup, 109 GrDirectContext*, 110 SkPicture*); 111 112 void createDDLsInParallel(SkPicture*); 113 114 // Create the DDL that will compose all the tile images into a final result. 115 void createComposeDDL(); composeDDL()116 const sk_sp<SkDeferredDisplayList>& composeDDL() const { return fComposeDDL; } 117 118 // For each tile, create its DDL and then draw it - all on a single thread. This is to allow 119 // comparison w/ just drawing the SKP directly (i.e., drawAllTilesDirectly). The 120 // DDL creations and draws are interleaved to prevent starvation of the GPU. 121 // Note: this is somewhat of a misuse/pessimistic-use of DDLs since they are supposed to 122 // be created on a separate thread. 123 void interleaveDDLCreationAndDraw(GrDirectContext*, SkPicture*); 124 125 // This draws all the per-tile SKPs directly into all of the tiles w/o converting them to 126 // DDLs first - all on a single thread. 127 void drawAllTilesDirectly(GrDirectContext*, SkPicture*); 128 129 void dropCallbackContexts(); 130 void resetAllTiles(); 131 numTiles()132 int numTiles() const { return fNumXDivisions * fNumYDivisions; } 133 134 void createBackendTextures(SkTaskGroup*, GrDirectContext*); 135 void deleteBackendTextures(SkTaskGroup*, GrDirectContext*); 136 137 private: 138 int fNumXDivisions; // number of tiles horizontally 139 int fNumYDivisions; // number of tiles vertically 140 SkAutoTArray<TileData> fTiles; // 'fNumXDivisions' x 'fNumYDivisions' 141 142 sk_sp<SkDeferredDisplayList> fComposeDDL; 143 144 const SkSurfaceCharacterization fDstCharacterization; 145 }; 146 147 #endif 148