blob: 41563f943bf0b4e40e30bc8213ab31c854e5ec10 [file] [log] [blame]
Robert Phillips96601082018-05-29 16:13:26 -04001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "tools/DDLTileHelper.h"
Robert Phillips96601082018-05-29 16:13:26 -04009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkCanvas.h"
11#include "include/core/SkDeferredDisplayListRecorder.h"
12#include "include/core/SkPicture.h"
13#include "include/core/SkSurface.h"
14#include "include/core/SkSurfaceCharacterization.h"
15#include "src/core/SkDeferredDisplayListPriv.h"
16#include "src/core/SkTaskGroup.h"
Robert Phillips7b0ed552020-02-20 12:45:19 -050017#include "src/gpu/GrContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/image/SkImage_Gpu.h"
19#include "tools/DDLPromiseImageHelper.h"
Robert Phillips96601082018-05-29 16:13:26 -040020
Robert Phillipsa865a3a2020-02-14 10:49:39 -050021void DDLTileHelper::TileData::init(int id, sk_sp<SkSurface> dstSurface, const SkIRect& clip) {
22 fID = id;
23 fDstSurface = dstSurface;
24 fClip = clip;
25
26 SkSurfaceCharacterization tmp;
27 SkAssertResult(fDstSurface->characterize(&tmp));
28 fCharacterization = tmp.createResized(clip.width(), clip.height());
29 SkASSERT(fCharacterization.isValid());
Robert Phillips96601082018-05-29 16:13:26 -040030}
31
Robert Phillipsa865a3a2020-02-14 10:49:39 -050032DDLTileHelper::TileData::~TileData() {}
33
Robert Phillips96601082018-05-29 16:13:26 -040034void DDLTileHelper::TileData::createTileSpecificSKP(SkData* compressedPictureData,
35 const DDLPromiseImageHelper& helper) {
Robert Phillips7a3197b2018-09-26 21:18:23 +000036 SkASSERT(!fReconstitutedPicture);
Robert Phillips96601082018-05-29 16:13:26 -040037
Robert Phillips7a3197b2018-09-26 21:18:23 +000038 // This is bending the DDLRecorder contract! The promise images in the SKP should be
39 // created by the same recorder used to create the matching DDL.
40 SkDeferredDisplayListRecorder recorder(fCharacterization);
Robert Phillips96601082018-05-29 16:13:26 -040041
Robert Phillips7a3197b2018-09-26 21:18:23 +000042 fReconstitutedPicture = helper.reinflateSKP(&recorder, compressedPictureData, &fPromiseImages);
Robert Phillipse8e2bb12018-09-27 14:26:47 -040043
44 std::unique_ptr<SkDeferredDisplayList> ddl = recorder.detach();
Chris Dalton6b498102019-08-01 14:14:52 -060045 if (ddl->priv().numRenderTasks()) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -040046 // TODO: remove this once skbug.com/8424 is fixed. If the DDL resulting from the
Greg Danielf41b2bd2019-08-22 16:19:24 -040047 // reinflation of the SKPs contains opsTasks that means some image subset operation
Robert Phillipse8e2bb12018-09-27 14:26:47 -040048 // created a draw.
49 fReconstitutedPicture.reset();
50 }
Robert Phillips96601082018-05-29 16:13:26 -040051}
52
53void DDLTileHelper::TileData::createDDL() {
Robert Phillips96601082018-05-29 16:13:26 -040054 SkASSERT(!fDisplayList);
55
Robert Phillips7a3197b2018-09-26 21:18:23 +000056 SkDeferredDisplayListRecorder recorder(fCharacterization);
57
58 // DDL TODO: the DDLRecorder's GrContext isn't initialized until getCanvas is called.
59 // Maybe set it up in the ctor?
60 SkCanvas* subCanvas = recorder.getCanvas();
61
62 // Because we cheated in createTileSpecificSKP and used the wrong DDLRecorder, the GrContext's
63 // stored in fReconstitutedPicture's promise images are incorrect. Patch them with the correct
64 // one now.
65 for (int i = 0; i < fPromiseImages.count(); ++i) {
66 GrContext* newContext = subCanvas->getGrContext();
67
68 if (fPromiseImages[i]->isTextureBacked()) {
Jim Van Verth21bd60d2018-10-12 15:00:20 -040069 SkImage_GpuBase* gpuImage = (SkImage_GpuBase*) fPromiseImages[i].get();
Robert Phillips7a3197b2018-09-26 21:18:23 +000070 gpuImage->resetContext(sk_ref_sp(newContext));
71 }
72 }
Robert Phillips96601082018-05-29 16:13:26 -040073
74 subCanvas->clipRect(SkRect::MakeWH(fClip.width(), fClip.height()));
75 subCanvas->translate(-fClip.fLeft, -fClip.fTop);
76
77 // Note: in this use case we only render a picture to the deferred canvas
78 // but, more generally, clients will use arbitrary draw calls.
Robert Phillipse8e2bb12018-09-27 14:26:47 -040079 if (fReconstitutedPicture) {
80 subCanvas->drawPicture(fReconstitutedPicture);
81 }
Robert Phillips96601082018-05-29 16:13:26 -040082
Robert Phillips7a3197b2018-09-26 21:18:23 +000083 fDisplayList = recorder.detach();
Robert Phillips96601082018-05-29 16:13:26 -040084}
85
Robert Phillipsa865a3a2020-02-14 10:49:39 -050086void DDLTileHelper::TileData::draw(GrContext* context) {
87 SkASSERT(fDisplayList && !fImage);
Robert Phillips96601082018-05-29 16:13:26 -040088
Robert Phillipsa865a3a2020-02-14 10:49:39 -050089 sk_sp<SkSurface> tileSurface = SkSurface::MakeRenderTarget(context, fCharacterization,
90 SkBudgeted::kYes);
91 if (tileSurface) {
92 tileSurface->draw(fDisplayList.get());
93
94 fImage = tileSurface->makeImageSnapshot();
95 }
Robert Phillips96601082018-05-29 16:13:26 -040096}
97
Robert Phillipsa865a3a2020-02-14 10:49:39 -050098// TODO: We should create a single DDL for the composition step and just add replaying it
99// as the last GPU task
100void DDLTileHelper::TileData::compose() {
101 SkASSERT(fDstSurface && fImage);
102
103 SkCanvas* canvas = fDstSurface->getCanvas();
104 canvas->save();
105 canvas->clipRect(SkRect::Make(fClip));
Mike Reed3eaed8d2020-02-15 11:07:37 -0500106 canvas->drawImage(fImage, fClip.fLeft, fClip.fTop);
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500107 canvas->restore();
Robert Phillips96601082018-05-29 16:13:26 -0400108}
109
110void DDLTileHelper::TileData::reset() {
111 // TODO: when DDLs are re-renderable we don't need to do this
112 fDisplayList = nullptr;
113}
114
115///////////////////////////////////////////////////////////////////////////////////////////////////
116
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500117DDLTileHelper::DDLTileHelper(sk_sp<SkSurface> dstSurface,
118 const SkIRect& viewport,
119 int numDivisions)
Robert Phillips96601082018-05-29 16:13:26 -0400120 : fNumDivisions(numDivisions) {
121 SkASSERT(fNumDivisions > 0);
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500122 fTiles = new TileData[this->numTiles()];
Robert Phillips96601082018-05-29 16:13:26 -0400123
124 int xTileSize = viewport.width()/fNumDivisions;
125 int yTileSize = viewport.height()/fNumDivisions;
126
127 // Create the destination tiles
128 for (int y = 0, yOff = 0; y < fNumDivisions; ++y, yOff += yTileSize) {
129 int ySize = (y < fNumDivisions-1) ? yTileSize : viewport.height()-yOff;
130
131 for (int x = 0, xOff = 0; x < fNumDivisions; ++x, xOff += xTileSize) {
132 int xSize = (x < fNumDivisions-1) ? xTileSize : viewport.width()-xOff;
133
134 SkIRect clip = SkIRect::MakeXYWH(xOff, yOff, xSize, ySize);
135
136 SkASSERT(viewport.contains(clip));
137
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500138 fTiles[y*fNumDivisions+x].init(y*fNumDivisions+x, dstSurface, clip);
Robert Phillips96601082018-05-29 16:13:26 -0400139 }
140 }
141}
142
143void DDLTileHelper::createSKPPerTile(SkData* compressedPictureData,
144 const DDLPromiseImageHelper& helper) {
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500145 for (int i = 0; i < this->numTiles(); ++i) {
Robert Phillips96601082018-05-29 16:13:26 -0400146 fTiles[i].createTileSpecificSKP(compressedPictureData, helper);
147 }
148}
149
150void DDLTileHelper::createDDLsInParallel() {
151#if 1
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500152 SkTaskGroup().batch(this->numTiles(), [&](int i) { fTiles[i].createDDL(); });
Robert Phillipsf18c7562018-06-13 09:01:36 -0400153 SkTaskGroup().wait();
Robert Phillips96601082018-05-29 16:13:26 -0400154#else
155 // Use this code path to debug w/o threads
156 for (int i = 0; i < fTiles.count(); ++i) {
157 fTiles[i].createDDL();
158 }
159#endif
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500160}
Robert Phillips96601082018-05-29 16:13:26 -0400161
Robert Phillips7b0ed552020-02-20 12:45:19 -0500162// On the gpu thread:
163// precompile any programs
164// replay the DDL into a surface to make the tile image
165// compose the tile image into the main canvas
166static void do_gpu_stuff(GrContext* context, DDLTileHelper::TileData* tile) {
167 auto& programData = tile->ddl()->priv().programData();
168
169 // TODO: schedule program compilation as their own tasks
170 for (auto& programDatum : programData) {
171 context->priv().compile(programDatum.desc(), programDatum.info());
172 }
173
174 tile->draw(context);
175
176 // TODO: we should actually have a separate DDL that does
177 // the final composition draw
178 tile->compose();
179}
180
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500181// We expect to have more than one recording thread but just one gpu thread
182void DDLTileHelper::kickOffThreadedWork(SkTaskGroup* recordingTaskGroup,
183 SkTaskGroup* gpuTaskGroup,
184 GrContext* gpuThreadContext) {
185 SkASSERT(recordingTaskGroup && gpuTaskGroup && gpuThreadContext);
186
187 for (int i = 0; i < this->numTiles(); ++i) {
188 TileData* tile = &fTiles[i];
189
190 // On a recording thread:
191 // generate the tile's DDL
192 // schedule gpu-thread processing of the DDL
193 // Note: a finer grained approach would be add a scheduling task which would evaluate
194 // which DDLs were ready to be rendered based on their prerequisites
195 recordingTaskGroup->add([tile, gpuTaskGroup, gpuThreadContext]() {
196 tile->createDDL();
197
198 gpuTaskGroup->add([gpuThreadContext, tile]() {
Robert Phillips7b0ed552020-02-20 12:45:19 -0500199 do_gpu_stuff(gpuThreadContext, tile);
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500200 });
201 });
202 }
Robert Phillips96601082018-05-29 16:13:26 -0400203}
204
205void DDLTileHelper::drawAllTilesAndFlush(GrContext* context, bool flush) {
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500206 for (int i = 0; i < this->numTiles(); ++i) {
207 fTiles[i].draw(context);
Robert Phillips96601082018-05-29 16:13:26 -0400208 }
209 if (flush) {
210 context->flush();
211 }
212}
213
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500214void DDLTileHelper::composeAllTiles() {
215 for (int i = 0; i < this->numTiles(); ++i) {
216 fTiles[i].compose();
Robert Phillips96601082018-05-29 16:13:26 -0400217 }
218}
219
220void DDLTileHelper::resetAllTiles() {
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500221 for (int i = 0; i < this->numTiles(); ++i) {
Robert Phillips96601082018-05-29 16:13:26 -0400222 fTiles[i].reset();
223 }
224}