| /* |
| * Copyright 2018 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef DDLTileHelper_DEFINED |
| #define DDLTileHelper_DEFINED |
| |
| #include "include/core/SkDeferredDisplayList.h" |
| #include "include/core/SkRect.h" |
| #include "include/core/SkRefCnt.h" |
| #include "include/core/SkSpan.h" |
| #include "include/core/SkSurfaceCharacterization.h" |
| #include "include/private/base/SkTemplates.h" |
| |
| class DDLPromiseImageHelper; |
| class PromiseImageCallbackContext; |
| class SkCanvas; |
| class SkData; |
| class SkDeferredDisplayListRecorder; |
| class SkPicture; |
| class SkSurface; |
| class SkSurfaceCharacterization; |
| class SkTaskGroup; |
| |
| class DDLTileHelper { |
| public: |
| // The TileData class encapsulates the information and behavior of a single tile when |
| // rendering with DDLs. |
| class TileData { |
| public: |
| TileData(); |
| ~TileData(); |
| |
| bool initialized() const { return fID != -1; } |
| |
| void init(int id, |
| GrDirectContext*, |
| const SkSurfaceCharacterization& dstChar, |
| const SkIRect& clip, |
| const SkIRect& paddingOutsets); |
| |
| // Create the DDL for this tile (i.e., fill in 'fDisplayList'). |
| void createDDL(const SkPicture*); |
| |
| void dropDDL() { fDisplayList.reset(); } |
| |
| // Precompile all the programs required to draw this tile's DDL |
| void precompile(GrDirectContext*); |
| |
| // Just draw the re-inflated per-tile SKP directly into this tile w/o going through a DDL |
| // first. This is used for determining the overhead of using DDLs (i.e., it replaces |
| // a 'createDDL' and 'draw' pair. |
| void drawSKPDirectly(GrDirectContext*, const SkPicture*); |
| |
| // Replay the recorded DDL into the tile surface - filling in 'fBackendTexture'. |
| void draw(GrDirectContext*); |
| |
| void reset(); |
| |
| int id() const { return fID; } |
| SkIRect clipRect() const { return fClip; } |
| SkISize paddedRectSize() const { |
| return { fClip.width() + fPaddingOutsets.fLeft + fPaddingOutsets.fRight, |
| fClip.height() + fPaddingOutsets.fTop + fPaddingOutsets.fBottom }; |
| } |
| SkIVector padOffset() const { return { fPaddingOutsets.fLeft, fPaddingOutsets.fTop }; } |
| |
| SkDeferredDisplayList* ddl() { return fDisplayList.get(); } |
| |
| sk_sp<SkImage> makePromiseImageForDst(sk_sp<GrContextThreadSafeProxy>); |
| void dropCallbackContext() { fCallbackContext.reset(); } |
| |
| static void CreateBackendTexture(GrDirectContext*, TileData*); |
| static void DeleteBackendTexture(GrDirectContext*, TileData*); |
| |
| private: |
| sk_sp<SkSurface> makeWrappedTileDest(GrRecordingContext* context); |
| |
| sk_sp<PromiseImageCallbackContext> refCallbackContext() { return fCallbackContext; } |
| |
| int fID = -1; |
| SkIRect fClip; // in the device space of the final SkSurface |
| SkIRect fPaddingOutsets; // random padding for the output surface |
| SkSurfaceCharacterization fPlaybackChar; // characterization for the tile's dst surface |
| |
| // The callback context holds (via its SkPromiseImageTexture) the backend texture |
| // that is both wrapped in 'fTileSurface' and backs this tile's promise image |
| // (i.e., the one returned by 'makePromiseImage'). |
| sk_sp<PromiseImageCallbackContext> fCallbackContext; |
| // 'fTileSurface' wraps the backend texture in 'fCallbackContext' and must exist until |
| // after 'fDisplayList' has been flushed (bc it owns the proxy the DDL's destination |
| // trampoline points at). |
| // TODO: fix the ref-order so we don't need 'fTileSurface' here |
| sk_sp<SkSurface> fTileSurface; |
| |
| sk_sp<SkDeferredDisplayList> fDisplayList; |
| }; |
| |
| DDLTileHelper(GrDirectContext*, |
| const SkSurfaceCharacterization& dstChar, |
| const SkIRect& viewport, |
| int numXDivisions, int numYDivisions, |
| bool addRandomPaddingToDst); |
| |
| void kickOffThreadedWork(SkTaskGroup* recordingTaskGroup, |
| SkTaskGroup* gpuTaskGroup, |
| GrDirectContext*, |
| SkPicture*); |
| |
| void createDDLsInParallel(SkPicture*); |
| |
| // Create the DDL that will compose all the tile images into a final result. |
| void createComposeDDL(); |
| const sk_sp<SkDeferredDisplayList>& composeDDL() const { return fComposeDDL; } |
| |
| // For each tile, create its DDL and then draw it - all on a single thread. This is to allow |
| // comparison w/ just drawing the SKP directly (i.e., drawAllTilesDirectly). The |
| // DDL creations and draws are interleaved to prevent starvation of the GPU. |
| // Note: this is somewhat of a misuse/pessimistic-use of DDLs since they are supposed to |
| // be created on a separate thread. |
| void interleaveDDLCreationAndDraw(GrDirectContext*, SkPicture*); |
| |
| // This draws all the per-tile SKPs directly into all of the tiles w/o converting them to |
| // DDLs first - all on a single thread. |
| void drawAllTilesDirectly(GrDirectContext*, SkPicture*); |
| |
| void dropCallbackContexts(); |
| void resetAllTiles(); |
| |
| int numTiles() const { return fNumXDivisions * fNumYDivisions; } |
| |
| void createBackendTextures(SkTaskGroup*, GrDirectContext*); |
| void deleteBackendTextures(SkTaskGroup*, GrDirectContext*); |
| |
| private: |
| int fNumXDivisions; // number of tiles horizontally |
| int fNumYDivisions; // number of tiles vertically |
| skia_private::AutoTArray<TileData> fTiles; // 'fNumXDivisions' x |
| // 'fNumYDivisions' |
| |
| sk_sp<SkDeferredDisplayList> fComposeDDL; |
| |
| const SkSurfaceCharacterization fDstCharacterization; |
| }; |
| |
| #endif |