1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
/*
* 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/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSurfaceCharacterization.h"
class DDLPromiseImageHelper;
class PromiseImageCallbackContext;
class SkCanvas;
class SkData;
class SkDeferredDisplayList;
class SkDeferredDisplayListRecorder;
class SkPicture;
class SkSurface;
class SkSurfaceCharacterization;
class DDLTileHelper {
public:
// The TileData class encapsulates the information and behavior of a single tile when
// rendering with DDLs.
class TileData {
public:
TileData() {}
~TileData();
void init(int id,
GrContext* context,
const SkSurfaceCharacterization& dstChar,
const SkIRect& clip);
// Convert the compressedPictureData into an SkPicture replacing each image-index
// with a promise image.
void createTileSpecificSKP(SkData* compressedPictureData,
const DDLPromiseImageHelper& helper);
// Create the DDL for this tile (i.e., fill in 'fDisplayList').
void createDDL();
void dropDDL() { fDisplayList.reset(); }
// Precompile all the programs required to draw this tile's DDL
void precompile(GrContext*);
// 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(GrContext*);
// Replay the recorded DDL into the tile surface - filling in 'fBackendTexture'.
void draw(GrContext*);
void reset();
int id() const { return fID; }
SkIRect clipRect() const { return fClip; }
SkDeferredDisplayList* ddl() { return fDisplayList.get(); }
sk_sp<SkImage> makePromiseImage(SkDeferredDisplayListRecorder*);
void dropCallbackContext() { fCallbackContext.reset(); }
static void CreateBackendTexture(GrContext*, TileData*);
static void DeleteBackendTexture(GrContext*, TileData*);
private:
sk_sp<SkSurface> makeWrappedTileDest(GrContext* context);
sk_sp<PromiseImageCallbackContext> refCallbackContext() { return fCallbackContext; }
int fID = -1;
SkIRect fClip; // in the device space of the final SkSurface
SkSurfaceCharacterization fCharacterization; // characterization for the tile's 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<SkPicture> fReconstitutedPicture;
SkTArray<sk_sp<SkImage>> fPromiseImages; // All the promise images in the
// reconstituted picture
std::unique_ptr<SkDeferredDisplayList> fDisplayList;
};
DDLTileHelper(GrContext* context,
const SkSurfaceCharacterization& dstChar,
const SkIRect& viewport,
int numDivisions);
void createSKPPerTile(SkData* compressedPictureData, const DDLPromiseImageHelper&);
void kickOffThreadedWork(SkTaskGroup* recordingTaskGroup,
SkTaskGroup* gpuTaskGroup,
GrContext*);
void createDDLsInParallel();
// Create the DDL that will compose all the tile images into a final result.
void createComposeDDL();
SkDeferredDisplayList* composeDDL() const { return fComposeDDL.get(); }
void precompileAndDrawAllTiles(GrContext*);
// 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(GrContext*);
// 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(GrContext*);
void dropCallbackContexts();
void resetAllTiles();
int numTiles() const { return fNumDivisions * fNumDivisions; }
void createBackendTextures(SkTaskGroup*, GrContext*);
void deleteBackendTextures(SkTaskGroup*, GrContext*);
private:
int fNumDivisions; // number of tiles along a side
SkAutoTArray<TileData> fTiles; // 'fNumDivisions' x 'fNumDivisions'
std::unique_ptr<SkDeferredDisplayList> fComposeDDL;
const SkSurfaceCharacterization fDstCharacterization;
};
#endif
|