blob: 45ca86d2e01c06b0ce6fb2aec964855923681ef9 [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 Phillips19f466d2020-02-26 10:27:07 -050021void DDLTileHelper::TileData::init(int id,
22 sk_sp<SkSurface> dstSurface,
23 const SkSurfaceCharacterization& dstSurfaceCharacterization,
24 const SkIRect& clip) {
Robert Phillipsa865a3a2020-02-14 10:49:39 -050025 fID = id;
26 fDstSurface = dstSurface;
27 fClip = clip;
28
Robert Phillips19f466d2020-02-26 10:27:07 -050029 fCharacterization = dstSurfaceCharacterization.createResized(clip.width(), clip.height());
Robert Phillipsa865a3a2020-02-14 10:49:39 -050030 SkASSERT(fCharacterization.isValid());
Robert Phillips96601082018-05-29 16:13:26 -040031}
32
Robert Phillipsa865a3a2020-02-14 10:49:39 -050033DDLTileHelper::TileData::~TileData() {}
34
Robert Phillips96601082018-05-29 16:13:26 -040035void DDLTileHelper::TileData::createTileSpecificSKP(SkData* compressedPictureData,
36 const DDLPromiseImageHelper& helper) {
Robert Phillips7a3197b2018-09-26 21:18:23 +000037 SkASSERT(!fReconstitutedPicture);
Robert Phillips96601082018-05-29 16:13:26 -040038
Robert Phillips7a3197b2018-09-26 21:18:23 +000039 // This is bending the DDLRecorder contract! The promise images in the SKP should be
40 // created by the same recorder used to create the matching DDL.
41 SkDeferredDisplayListRecorder recorder(fCharacterization);
Robert Phillips96601082018-05-29 16:13:26 -040042
Robert Phillips7a3197b2018-09-26 21:18:23 +000043 fReconstitutedPicture = helper.reinflateSKP(&recorder, compressedPictureData, &fPromiseImages);
Robert Phillipse8e2bb12018-09-27 14:26:47 -040044
45 std::unique_ptr<SkDeferredDisplayList> ddl = recorder.detach();
Chris Dalton6b498102019-08-01 14:14:52 -060046 if (ddl->priv().numRenderTasks()) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -040047 // TODO: remove this once skbug.com/8424 is fixed. If the DDL resulting from the
Greg Danielf41b2bd2019-08-22 16:19:24 -040048 // reinflation of the SKPs contains opsTasks that means some image subset operation
Robert Phillipse8e2bb12018-09-27 14:26:47 -040049 // created a draw.
50 fReconstitutedPicture.reset();
51 }
Robert Phillips96601082018-05-29 16:13:26 -040052}
53
54void DDLTileHelper::TileData::createDDL() {
Robert Phillips96601082018-05-29 16:13:26 -040055 SkASSERT(!fDisplayList);
56
Robert Phillips7a3197b2018-09-26 21:18:23 +000057 SkDeferredDisplayListRecorder recorder(fCharacterization);
58
59 // DDL TODO: the DDLRecorder's GrContext isn't initialized until getCanvas is called.
60 // Maybe set it up in the ctor?
61 SkCanvas* subCanvas = recorder.getCanvas();
62
63 // Because we cheated in createTileSpecificSKP and used the wrong DDLRecorder, the GrContext's
64 // stored in fReconstitutedPicture's promise images are incorrect. Patch them with the correct
65 // one now.
66 for (int i = 0; i < fPromiseImages.count(); ++i) {
67 GrContext* newContext = subCanvas->getGrContext();
68
69 if (fPromiseImages[i]->isTextureBacked()) {
Jim Van Verth21bd60d2018-10-12 15:00:20 -040070 SkImage_GpuBase* gpuImage = (SkImage_GpuBase*) fPromiseImages[i].get();
Robert Phillips7a3197b2018-09-26 21:18:23 +000071 gpuImage->resetContext(sk_ref_sp(newContext));
72 }
73 }
Robert Phillips96601082018-05-29 16:13:26 -040074
75 subCanvas->clipRect(SkRect::MakeWH(fClip.width(), fClip.height()));
76 subCanvas->translate(-fClip.fLeft, -fClip.fTop);
77
78 // Note: in this use case we only render a picture to the deferred canvas
79 // but, more generally, clients will use arbitrary draw calls.
Robert Phillipse8e2bb12018-09-27 14:26:47 -040080 if (fReconstitutedPicture) {
81 subCanvas->drawPicture(fReconstitutedPicture);
82 }
Robert Phillips96601082018-05-29 16:13:26 -040083
Robert Phillips7a3197b2018-09-26 21:18:23 +000084 fDisplayList = recorder.detach();
Robert Phillips96601082018-05-29 16:13:26 -040085}
86
Robert Phillipsa865a3a2020-02-14 10:49:39 -050087void DDLTileHelper::TileData::draw(GrContext* context) {
88 SkASSERT(fDisplayList && !fImage);
Robert Phillips96601082018-05-29 16:13:26 -040089
Robert Phillipsa865a3a2020-02-14 10:49:39 -050090 sk_sp<SkSurface> tileSurface = SkSurface::MakeRenderTarget(context, fCharacterization,
91 SkBudgeted::kYes);
92 if (tileSurface) {
93 tileSurface->draw(fDisplayList.get());
94
95 fImage = tileSurface->makeImageSnapshot();
96 }
Robert Phillips96601082018-05-29 16:13:26 -040097}
98
Robert Phillipsa865a3a2020-02-14 10:49:39 -050099// TODO: We should create a single DDL for the composition step and just add replaying it
100// as the last GPU task
101void DDLTileHelper::TileData::compose() {
102 SkASSERT(fDstSurface && fImage);
103
104 SkCanvas* canvas = fDstSurface->getCanvas();
105 canvas->save();
106 canvas->clipRect(SkRect::Make(fClip));
Mike Reed3eaed8d2020-02-15 11:07:37 -0500107 canvas->drawImage(fImage, fClip.fLeft, fClip.fTop);
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500108 canvas->restore();
Robert Phillips96601082018-05-29 16:13:26 -0400109}
110
111void DDLTileHelper::TileData::reset() {
112 // TODO: when DDLs are re-renderable we don't need to do this
113 fDisplayList = nullptr;
114}
115
116///////////////////////////////////////////////////////////////////////////////////////////////////
117
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500118DDLTileHelper::DDLTileHelper(sk_sp<SkSurface> dstSurface,
Robert Phillips19f466d2020-02-26 10:27:07 -0500119 const SkSurfaceCharacterization& dstChar,
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500120 const SkIRect& viewport,
121 int numDivisions)
Robert Phillips96601082018-05-29 16:13:26 -0400122 : fNumDivisions(numDivisions) {
123 SkASSERT(fNumDivisions > 0);
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500124 fTiles = new TileData[this->numTiles()];
Robert Phillips96601082018-05-29 16:13:26 -0400125
126 int xTileSize = viewport.width()/fNumDivisions;
127 int yTileSize = viewport.height()/fNumDivisions;
128
129 // Create the destination tiles
130 for (int y = 0, yOff = 0; y < fNumDivisions; ++y, yOff += yTileSize) {
131 int ySize = (y < fNumDivisions-1) ? yTileSize : viewport.height()-yOff;
132
133 for (int x = 0, xOff = 0; x < fNumDivisions; ++x, xOff += xTileSize) {
134 int xSize = (x < fNumDivisions-1) ? xTileSize : viewport.width()-xOff;
135
136 SkIRect clip = SkIRect::MakeXYWH(xOff, yOff, xSize, ySize);
137
138 SkASSERT(viewport.contains(clip));
139
Robert Phillips19f466d2020-02-26 10:27:07 -0500140 fTiles[y*fNumDivisions+x].init(y*fNumDivisions+x, dstSurface, dstChar, clip);
Robert Phillips96601082018-05-29 16:13:26 -0400141 }
142 }
143}
144
145void DDLTileHelper::createSKPPerTile(SkData* compressedPictureData,
146 const DDLPromiseImageHelper& helper) {
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500147 for (int i = 0; i < this->numTiles(); ++i) {
Robert Phillips96601082018-05-29 16:13:26 -0400148 fTiles[i].createTileSpecificSKP(compressedPictureData, helper);
149 }
150}
151
152void DDLTileHelper::createDDLsInParallel() {
153#if 1
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500154 SkTaskGroup().batch(this->numTiles(), [&](int i) { fTiles[i].createDDL(); });
Robert Phillipsf18c7562018-06-13 09:01:36 -0400155 SkTaskGroup().wait();
Robert Phillips96601082018-05-29 16:13:26 -0400156#else
157 // Use this code path to debug w/o threads
158 for (int i = 0; i < fTiles.count(); ++i) {
159 fTiles[i].createDDL();
160 }
161#endif
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500162}
Robert Phillips96601082018-05-29 16:13:26 -0400163
Robert Phillips7b0ed552020-02-20 12:45:19 -0500164// On the gpu thread:
165// precompile any programs
166// replay the DDL into a surface to make the tile image
167// compose the tile image into the main canvas
168static void do_gpu_stuff(GrContext* context, DDLTileHelper::TileData* tile) {
Robert Phillips7b0ed552020-02-20 12:45:19 -0500169
170 // TODO: schedule program compilation as their own tasks
Robert Phillips1cec4d52020-02-24 08:38:34 -0500171 SkDeferredDisplayList::ProgramIterator iter(context, tile->ddl());
172 for (; !iter.done(); iter.next()) {
173 iter.compile();
Robert Phillips7b0ed552020-02-20 12:45:19 -0500174 }
175
176 tile->draw(context);
177
178 // TODO: we should actually have a separate DDL that does
179 // the final composition draw
180 tile->compose();
181}
182
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500183// We expect to have more than one recording thread but just one gpu thread
184void DDLTileHelper::kickOffThreadedWork(SkTaskGroup* recordingTaskGroup,
185 SkTaskGroup* gpuTaskGroup,
186 GrContext* gpuThreadContext) {
187 SkASSERT(recordingTaskGroup && gpuTaskGroup && gpuThreadContext);
188
189 for (int i = 0; i < this->numTiles(); ++i) {
190 TileData* tile = &fTiles[i];
191
192 // On a recording thread:
193 // generate the tile's DDL
194 // schedule gpu-thread processing of the DDL
195 // Note: a finer grained approach would be add a scheduling task which would evaluate
196 // which DDLs were ready to be rendered based on their prerequisites
197 recordingTaskGroup->add([tile, gpuTaskGroup, gpuThreadContext]() {
198 tile->createDDL();
199
200 gpuTaskGroup->add([gpuThreadContext, tile]() {
Robert Phillips7b0ed552020-02-20 12:45:19 -0500201 do_gpu_stuff(gpuThreadContext, tile);
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500202 });
203 });
204 }
Robert Phillips96601082018-05-29 16:13:26 -0400205}
206
Greg Daniel02497d42020-02-21 15:46:27 -0500207void DDLTileHelper::drawAllTiles(GrContext* context) {
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500208 for (int i = 0; i < this->numTiles(); ++i) {
209 fTiles[i].draw(context);
Robert Phillips96601082018-05-29 16:13:26 -0400210 }
Robert Phillips96601082018-05-29 16:13:26 -0400211}
212
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500213void DDLTileHelper::composeAllTiles() {
214 for (int i = 0; i < this->numTiles(); ++i) {
215 fTiles[i].compose();
Robert Phillips96601082018-05-29 16:13:26 -0400216 }
217}
218
219void DDLTileHelper::resetAllTiles() {
Robert Phillipsa865a3a2020-02-14 10:49:39 -0500220 for (int i = 0; i < this->numTiles(); ++i) {
Robert Phillips96601082018-05-29 16:13:26 -0400221 fTiles[i].reset();
222 }
223}