xref: /aosp_15_r20/external/skia/src/gpu/graphite/DrawContext.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2021 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawContext.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPixmap.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkColorData.h"
13*c8dee2aaSAndroid Build Coastguard Worker 
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Context.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Recorder.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTraceEvent.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/AtlasProvider.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Buffer.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Caps.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/CommandBuffer.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ComputePathAtlas.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ContextPriv.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawList.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawPass.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Log.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RasterPathAtlas.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RecorderPriv.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RenderPassDesc.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ResourceTypes.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/SharedContext.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/TextureProxy.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/TextureProxyView.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/compute/DispatchGroup.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/BoundsManager.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/geom/Geometry.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/task/ComputeTask.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/task/CopyTask.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/task/DrawTask.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/task/RenderPassTask.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/task/UploadTask.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/text/TextAtlasManager.h"
42*c8dee2aaSAndroid Build Coastguard Worker 
43*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker namespace {
46*c8dee2aaSAndroid Build Coastguard Worker 
47*c8dee2aaSAndroid Build Coastguard Worker // Discarding content on floating point textures can leave nans as the prior color for a pixel,
48*c8dee2aaSAndroid Build Coastguard Worker // in which case hardware blending (when enabled) will fail even if the src, dst coefficients
49*c8dee2aaSAndroid Build Coastguard Worker // and coverage would produce the unmodified src value.
discard_op_should_use_clear(SkColorType ct)50*c8dee2aaSAndroid Build Coastguard Worker bool discard_op_should_use_clear(SkColorType ct) {
51*c8dee2aaSAndroid Build Coastguard Worker     switch(ct) {
52*c8dee2aaSAndroid Build Coastguard Worker         case kRGBA_F16Norm_SkColorType:
53*c8dee2aaSAndroid Build Coastguard Worker         case kRGBA_F16_SkColorType:
54*c8dee2aaSAndroid Build Coastguard Worker         case kRGBA_F32_SkColorType:
55*c8dee2aaSAndroid Build Coastguard Worker         case kA16_float_SkColorType:
56*c8dee2aaSAndroid Build Coastguard Worker         case kR16G16_float_SkColorType:
57*c8dee2aaSAndroid Build Coastguard Worker             return true;
58*c8dee2aaSAndroid Build Coastguard Worker         default:
59*c8dee2aaSAndroid Build Coastguard Worker             return false;
60*c8dee2aaSAndroid Build Coastguard Worker     }
61*c8dee2aaSAndroid Build Coastguard Worker }
62*c8dee2aaSAndroid Build Coastguard Worker 
63*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
64*c8dee2aaSAndroid Build Coastguard Worker 
Make(const Caps * caps,sk_sp<TextureProxy> target,SkISize deviceSize,const SkColorInfo & colorInfo,const SkSurfaceProps & props)65*c8dee2aaSAndroid Build Coastguard Worker sk_sp<DrawContext> DrawContext::Make(const Caps* caps,
66*c8dee2aaSAndroid Build Coastguard Worker                                      sk_sp<TextureProxy> target,
67*c8dee2aaSAndroid Build Coastguard Worker                                      SkISize deviceSize,
68*c8dee2aaSAndroid Build Coastguard Worker                                      const SkColorInfo& colorInfo,
69*c8dee2aaSAndroid Build Coastguard Worker                                      const SkSurfaceProps& props) {
70*c8dee2aaSAndroid Build Coastguard Worker     if (!target) {
71*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
72*c8dee2aaSAndroid Build Coastguard Worker     }
73*c8dee2aaSAndroid Build Coastguard Worker     // We don't render to unknown or unpremul alphatypes
74*c8dee2aaSAndroid Build Coastguard Worker     if (colorInfo.alphaType() == kUnknown_SkAlphaType ||
75*c8dee2aaSAndroid Build Coastguard Worker         colorInfo.alphaType() == kUnpremul_SkAlphaType) {
76*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
77*c8dee2aaSAndroid Build Coastguard Worker     }
78*c8dee2aaSAndroid Build Coastguard Worker     if (!caps->isRenderable(target->textureInfo())) {
79*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
80*c8dee2aaSAndroid Build Coastguard Worker     }
81*c8dee2aaSAndroid Build Coastguard Worker 
82*c8dee2aaSAndroid Build Coastguard Worker     // Accept an approximate-fit texture, but make sure it's at least as large as the device's
83*c8dee2aaSAndroid Build Coastguard Worker     // logical size.
84*c8dee2aaSAndroid Build Coastguard Worker     // TODO: validate that the color type and alpha type are compatible with the target's info
85*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(target->isFullyLazy() || (target->dimensions().width() >= deviceSize.width() &&
86*c8dee2aaSAndroid Build Coastguard Worker                                        target->dimensions().height() >= deviceSize.height()));
87*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo imageInfo = SkImageInfo::Make(deviceSize, colorInfo);
88*c8dee2aaSAndroid Build Coastguard Worker     return sk_sp<DrawContext>(new DrawContext(caps, std::move(target), imageInfo, props));
89*c8dee2aaSAndroid Build Coastguard Worker }
90*c8dee2aaSAndroid Build Coastguard Worker 
DrawContext(const Caps * caps,sk_sp<TextureProxy> target,const SkImageInfo & ii,const SkSurfaceProps & props)91*c8dee2aaSAndroid Build Coastguard Worker DrawContext::DrawContext(const Caps* caps,
92*c8dee2aaSAndroid Build Coastguard Worker                          sk_sp<TextureProxy> target,
93*c8dee2aaSAndroid Build Coastguard Worker                          const SkImageInfo& ii,
94*c8dee2aaSAndroid Build Coastguard Worker                          const SkSurfaceProps& props)
95*c8dee2aaSAndroid Build Coastguard Worker         : fTarget(std::move(target))
96*c8dee2aaSAndroid Build Coastguard Worker         , fImageInfo(ii)
97*c8dee2aaSAndroid Build Coastguard Worker         , fSurfaceProps(props)
98*c8dee2aaSAndroid Build Coastguard Worker         , fCurrentDrawTask(sk_make_sp<DrawTask>(fTarget))
99*c8dee2aaSAndroid Build Coastguard Worker         , fPendingDraws(std::make_unique<DrawList>())
100*c8dee2aaSAndroid Build Coastguard Worker         , fPendingUploads(std::make_unique<UploadList>()) {
101*c8dee2aaSAndroid Build Coastguard Worker     if (!caps->isTexturable(fTarget->textureInfo())) {
102*c8dee2aaSAndroid Build Coastguard Worker         fReadView = {}; // Presumably this DrawContext is rendering into a swap chain
103*c8dee2aaSAndroid Build Coastguard Worker     } else {
104*c8dee2aaSAndroid Build Coastguard Worker         Swizzle swizzle = caps->getReadSwizzle(ii.colorType(), fTarget->textureInfo());
105*c8dee2aaSAndroid Build Coastguard Worker         fReadView = {fTarget, swizzle};
106*c8dee2aaSAndroid Build Coastguard Worker     }
107*c8dee2aaSAndroid Build Coastguard Worker     // TBD - Will probably want DrawLists (and its internal commands) to come from an arena
108*c8dee2aaSAndroid Build Coastguard Worker     // that the DC manages.
109*c8dee2aaSAndroid Build Coastguard Worker }
110*c8dee2aaSAndroid Build Coastguard Worker 
111*c8dee2aaSAndroid Build Coastguard Worker DrawContext::~DrawContext() = default;
112*c8dee2aaSAndroid Build Coastguard Worker 
clear(const SkColor4f & clearColor)113*c8dee2aaSAndroid Build Coastguard Worker void DrawContext::clear(const SkColor4f& clearColor) {
114*c8dee2aaSAndroid Build Coastguard Worker     this->discard();
115*c8dee2aaSAndroid Build Coastguard Worker 
116*c8dee2aaSAndroid Build Coastguard Worker     fPendingLoadOp = LoadOp::kClear;
117*c8dee2aaSAndroid Build Coastguard Worker     SkPMColor4f pmColor = clearColor.premul();
118*c8dee2aaSAndroid Build Coastguard Worker     fPendingClearColor = pmColor.array();
119*c8dee2aaSAndroid Build Coastguard Worker }
120*c8dee2aaSAndroid Build Coastguard Worker 
discard()121*c8dee2aaSAndroid Build Coastguard Worker void DrawContext::discard() {
122*c8dee2aaSAndroid Build Coastguard Worker     // Non-loading operations on a fully lazy target can corrupt data beyond the DrawContext's
123*c8dee2aaSAndroid Build Coastguard Worker     // region so should be avoided.
124*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!fTarget->isFullyLazy());
125*c8dee2aaSAndroid Build Coastguard Worker 
126*c8dee2aaSAndroid Build Coastguard Worker     // A fullscreen clear or discard will overwrite anything that came before, so clear the DrawList
127*c8dee2aaSAndroid Build Coastguard Worker     // NOTE: Eventually the current DrawTask should be reset, once there are no longer implicit
128*c8dee2aaSAndroid Build Coastguard Worker     // dependencies on atlas tasks between DrawContexts. When that's resolved, the only tasks in the
129*c8dee2aaSAndroid Build Coastguard Worker     // current DrawTask are those that directly impact the target, which becomes irrelevant with the
130*c8dee2aaSAndroid Build Coastguard Worker     // clear op overwriting it. For now, preserve the previous tasks that might include atlas
131*c8dee2aaSAndroid Build Coastguard Worker     // uploads that are not explicitly shared between DrawContexts.
132*c8dee2aaSAndroid Build Coastguard Worker     if (fPendingDraws->renderStepCount() > 0) {
133*c8dee2aaSAndroid Build Coastguard Worker         fPendingDraws = std::make_unique<DrawList>();
134*c8dee2aaSAndroid Build Coastguard Worker     }
135*c8dee2aaSAndroid Build Coastguard Worker     if (fComputePathAtlas) {
136*c8dee2aaSAndroid Build Coastguard Worker         fComputePathAtlas->reset();
137*c8dee2aaSAndroid Build Coastguard Worker     }
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker     if (discard_op_should_use_clear(fImageInfo.colorType())) {
140*c8dee2aaSAndroid Build Coastguard Worker         // In theory the clear color shouldn't matter since a discardable state should be fully
141*c8dee2aaSAndroid Build Coastguard Worker         // overwritten by later draws, but if a previous call to clear() had injected bad data,
142*c8dee2aaSAndroid Build Coastguard Worker         // the discard should not inherit it.
143*c8dee2aaSAndroid Build Coastguard Worker         fPendingClearColor = {0.f, 0.f, 0.f, 0.f};
144*c8dee2aaSAndroid Build Coastguard Worker         fPendingLoadOp = LoadOp::kClear;
145*c8dee2aaSAndroid Build Coastguard Worker     } else {
146*c8dee2aaSAndroid Build Coastguard Worker         fPendingLoadOp = LoadOp::kDiscard;
147*c8dee2aaSAndroid Build Coastguard Worker     }
148*c8dee2aaSAndroid Build Coastguard Worker }
149*c8dee2aaSAndroid Build Coastguard Worker 
recordDraw(const Renderer * renderer,const Transform & localToDevice,const Geometry & geometry,const Clip & clip,DrawOrder ordering,const PaintParams * paint,const StrokeStyle * stroke)150*c8dee2aaSAndroid Build Coastguard Worker void DrawContext::recordDraw(const Renderer* renderer,
151*c8dee2aaSAndroid Build Coastguard Worker                              const Transform& localToDevice,
152*c8dee2aaSAndroid Build Coastguard Worker                              const Geometry& geometry,
153*c8dee2aaSAndroid Build Coastguard Worker                              const Clip& clip,
154*c8dee2aaSAndroid Build Coastguard Worker                              DrawOrder ordering,
155*c8dee2aaSAndroid Build Coastguard Worker                              const PaintParams* paint,
156*c8dee2aaSAndroid Build Coastguard Worker                              const StrokeStyle* stroke) {
157*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(SkIRect::MakeSize(this->imageInfo().dimensions()).contains(clip.scissor()));
158*c8dee2aaSAndroid Build Coastguard Worker     fPendingDraws->recordDraw(renderer, localToDevice, geometry, clip, ordering, paint, stroke);
159*c8dee2aaSAndroid Build Coastguard Worker }
160*c8dee2aaSAndroid Build Coastguard Worker 
recordUpload(Recorder * recorder,sk_sp<TextureProxy> targetProxy,const SkColorInfo & srcColorInfo,const SkColorInfo & dstColorInfo,const std::vector<MipLevel> & levels,const SkIRect & dstRect,std::unique_ptr<ConditionalUploadContext> condContext)161*c8dee2aaSAndroid Build Coastguard Worker bool DrawContext::recordUpload(Recorder* recorder,
162*c8dee2aaSAndroid Build Coastguard Worker                                sk_sp<TextureProxy> targetProxy,
163*c8dee2aaSAndroid Build Coastguard Worker                                const SkColorInfo& srcColorInfo,
164*c8dee2aaSAndroid Build Coastguard Worker                                const SkColorInfo& dstColorInfo,
165*c8dee2aaSAndroid Build Coastguard Worker                                const std::vector<MipLevel>& levels,
166*c8dee2aaSAndroid Build Coastguard Worker                                const SkIRect& dstRect,
167*c8dee2aaSAndroid Build Coastguard Worker                                std::unique_ptr<ConditionalUploadContext> condContext) {
168*c8dee2aaSAndroid Build Coastguard Worker     // Our caller should have clipped to the bounds of the surface already.
169*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(targetProxy->isFullyLazy() ||
170*c8dee2aaSAndroid Build Coastguard Worker              SkIRect::MakeSize(targetProxy->dimensions()).contains(dstRect));
171*c8dee2aaSAndroid Build Coastguard Worker     return fPendingUploads->recordUpload(recorder,
172*c8dee2aaSAndroid Build Coastguard Worker                                          std::move(targetProxy),
173*c8dee2aaSAndroid Build Coastguard Worker                                          srcColorInfo,
174*c8dee2aaSAndroid Build Coastguard Worker                                          dstColorInfo,
175*c8dee2aaSAndroid Build Coastguard Worker                                          levels,
176*c8dee2aaSAndroid Build Coastguard Worker                                          dstRect,
177*c8dee2aaSAndroid Build Coastguard Worker                                          std::move(condContext));
178*c8dee2aaSAndroid Build Coastguard Worker }
179*c8dee2aaSAndroid Build Coastguard Worker 
recordDependency(sk_sp<Task> task)180*c8dee2aaSAndroid Build Coastguard Worker void DrawContext::recordDependency(sk_sp<Task> task) {
181*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(task);
182*c8dee2aaSAndroid Build Coastguard Worker     // Adding `task` to the current DrawTask directly means that it will execute after any previous
183*c8dee2aaSAndroid Build Coastguard Worker     // dependent tasks and after any previous calls to flush(), but everything else that's being
184*c8dee2aaSAndroid Build Coastguard Worker     // collected on the DrawContext will execute after `task` once the next flush() is performed.
185*c8dee2aaSAndroid Build Coastguard Worker     fCurrentDrawTask->addTask(std::move(task));
186*c8dee2aaSAndroid Build Coastguard Worker }
187*c8dee2aaSAndroid Build Coastguard Worker 
getComputePathAtlas(Recorder * recorder)188*c8dee2aaSAndroid Build Coastguard Worker PathAtlas* DrawContext::getComputePathAtlas(Recorder* recorder) {
189*c8dee2aaSAndroid Build Coastguard Worker     if (!fComputePathAtlas) {
190*c8dee2aaSAndroid Build Coastguard Worker         fComputePathAtlas = recorder->priv().atlasProvider()->createComputePathAtlas(recorder);
191*c8dee2aaSAndroid Build Coastguard Worker     }
192*c8dee2aaSAndroid Build Coastguard Worker     return fComputePathAtlas.get();
193*c8dee2aaSAndroid Build Coastguard Worker }
194*c8dee2aaSAndroid Build Coastguard Worker 
flush(Recorder * recorder)195*c8dee2aaSAndroid Build Coastguard Worker void DrawContext::flush(Recorder* recorder) {
196*c8dee2aaSAndroid Build Coastguard Worker     if (fPendingUploads->size() > 0) {
197*c8dee2aaSAndroid Build Coastguard Worker         TRACE_EVENT_INSTANT1("skia.gpu", TRACE_FUNC, TRACE_EVENT_SCOPE_THREAD,
198*c8dee2aaSAndroid Build Coastguard Worker                              "# uploads", fPendingUploads->size());
199*c8dee2aaSAndroid Build Coastguard Worker         fCurrentDrawTask->addTask(UploadTask::Make(fPendingUploads.get()));
200*c8dee2aaSAndroid Build Coastguard Worker         // The UploadTask steals the collected upload instances, automatically resetting this list
201*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fPendingUploads->size() == 0);
202*c8dee2aaSAndroid Build Coastguard Worker     }
203*c8dee2aaSAndroid Build Coastguard Worker 
204*c8dee2aaSAndroid Build Coastguard Worker     // Generate compute dispatches that render into the atlas texture used by pending draws.
205*c8dee2aaSAndroid Build Coastguard Worker     // TODO: Once compute atlas caching is implemented, DrawContext might not hold onto to this
206*c8dee2aaSAndroid Build Coastguard Worker     // at which point a recordDispatch() could be added and it stores a pending dispatches list that
207*c8dee2aaSAndroid Build Coastguard Worker     // much like how uploads are handled. In that case, Device would be responsible for triggering
208*c8dee2aaSAndroid Build Coastguard Worker     // the recording of dispatches, but that may happen naturally in AtlasProvider::recordUploads().
209*c8dee2aaSAndroid Build Coastguard Worker     if (fComputePathAtlas) {
210*c8dee2aaSAndroid Build Coastguard Worker         ComputeTask::DispatchGroupList dispatches;
211*c8dee2aaSAndroid Build Coastguard Worker         if (fComputePathAtlas->recordDispatches(recorder, &dispatches)) {
212*c8dee2aaSAndroid Build Coastguard Worker             // For now this check is valid as all coverage mask draws involve dispatches
213*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fPendingDraws->hasCoverageMaskDraws());
214*c8dee2aaSAndroid Build Coastguard Worker 
215*c8dee2aaSAndroid Build Coastguard Worker             fCurrentDrawTask->addTask(ComputeTask::Make(std::move(dispatches)));
216*c8dee2aaSAndroid Build Coastguard Worker         } // else no pending compute work needed to be recorded
217*c8dee2aaSAndroid Build Coastguard Worker 
218*c8dee2aaSAndroid Build Coastguard Worker         fComputePathAtlas->reset();
219*c8dee2aaSAndroid Build Coastguard Worker     } // else platform doesn't support compute or atlas was never initialized.
220*c8dee2aaSAndroid Build Coastguard Worker 
221*c8dee2aaSAndroid Build Coastguard Worker     if (fPendingDraws->renderStepCount() == 0 && fPendingLoadOp != LoadOp::kClear) {
222*c8dee2aaSAndroid Build Coastguard Worker         // Nothing will be rasterized to the target that warrants a RenderPassTask, but we preserve
223*c8dee2aaSAndroid Build Coastguard Worker         // any added uploads or compute tasks since those could also affect the target w/o
224*c8dee2aaSAndroid Build Coastguard Worker         // rasterizing anything directly.
225*c8dee2aaSAndroid Build Coastguard Worker         return;
226*c8dee2aaSAndroid Build Coastguard Worker     }
227*c8dee2aaSAndroid Build Coastguard Worker 
228*c8dee2aaSAndroid Build Coastguard Worker     // Convert the pending draws and load/store ops into a DrawPass that will be executed after
229*c8dee2aaSAndroid Build Coastguard Worker     // the collected uploads and compute dispatches. Save the bounds required for a dst copy to
230*c8dee2aaSAndroid Build Coastguard Worker     // insert a copy task of sufficient size.
231*c8dee2aaSAndroid Build Coastguard Worker     // TODO: At this point, there's only ever one DrawPass in a RenderPassTask to a target. When
232*c8dee2aaSAndroid Build Coastguard Worker     // subpasses are implemented, they will either be collected alongside fPendingDraws or added
233*c8dee2aaSAndroid Build Coastguard Worker     // to the RenderPassTask separately.
234*c8dee2aaSAndroid Build Coastguard Worker     SkIRect dstCopyPixelBounds = fPendingDraws->dstCopyBounds().makeRoundOut().asSkIRect();
235*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<DrawPass> pass = DrawPass::Make(recorder,
236*c8dee2aaSAndroid Build Coastguard Worker                                                     std::move(fPendingDraws),
237*c8dee2aaSAndroid Build Coastguard Worker                                                     fTarget,
238*c8dee2aaSAndroid Build Coastguard Worker                                                     this->imageInfo(),
239*c8dee2aaSAndroid Build Coastguard Worker                                                     std::make_pair(fPendingLoadOp, fPendingStoreOp),
240*c8dee2aaSAndroid Build Coastguard Worker                                                     fPendingClearColor);
241*c8dee2aaSAndroid Build Coastguard Worker     fPendingDraws = std::make_unique<DrawList>();
242*c8dee2aaSAndroid Build Coastguard Worker     // Now that there is content drawn to the target, that content must be loaded on any subsequent
243*c8dee2aaSAndroid Build Coastguard Worker     // render pass.
244*c8dee2aaSAndroid Build Coastguard Worker     fPendingLoadOp = LoadOp::kLoad;
245*c8dee2aaSAndroid Build Coastguard Worker     fPendingStoreOp = StoreOp::kStore;
246*c8dee2aaSAndroid Build Coastguard Worker 
247*c8dee2aaSAndroid Build Coastguard Worker     if (pass) {
248*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fTarget.get() == pass->target());
249*c8dee2aaSAndroid Build Coastguard Worker 
250*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<TextureProxy> dstCopy;
251*c8dee2aaSAndroid Build Coastguard Worker         if (!dstCopyPixelBounds.isEmpty()) {
252*c8dee2aaSAndroid Build Coastguard Worker             TRACE_EVENT_INSTANT0("skia.gpu", "DrawPass requires dst copy",
253*c8dee2aaSAndroid Build Coastguard Worker                                  TRACE_EVENT_SCOPE_THREAD);
254*c8dee2aaSAndroid Build Coastguard Worker 
255*c8dee2aaSAndroid Build Coastguard Worker             // TODO: Right now this assert is ensuring that the dstCopy will be texturable since it
256*c8dee2aaSAndroid Build Coastguard Worker             // uses the same texture info as fTarget. Ideally, if fTarget were not texturable but
257*c8dee2aaSAndroid Build Coastguard Worker             // still readable, we would perform a fallback to a compatible texturable info. We also
258*c8dee2aaSAndroid Build Coastguard Worker             // should decide whether or not a copy-as-draw fallback is necessary here too. All of
259*c8dee2aaSAndroid Build Coastguard Worker             // this is handled inside Image::Copy() except we would need it to expose the task in
260*c8dee2aaSAndroid Build Coastguard Worker             // order to link it correctly.
261*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(recorder->priv().caps()->isTexturable(fTarget->textureInfo()));
262*c8dee2aaSAndroid Build Coastguard Worker             dstCopy = TextureProxy::Make(recorder->priv().caps(),
263*c8dee2aaSAndroid Build Coastguard Worker                                          recorder->priv().resourceProvider(),
264*c8dee2aaSAndroid Build Coastguard Worker                                          dstCopyPixelBounds.size(),
265*c8dee2aaSAndroid Build Coastguard Worker                                          fTarget->textureInfo(),
266*c8dee2aaSAndroid Build Coastguard Worker                                          "DstCopyTexture",
267*c8dee2aaSAndroid Build Coastguard Worker                                          skgpu::Budgeted::kYes);
268*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(dstCopy);
269*c8dee2aaSAndroid Build Coastguard Worker 
270*c8dee2aaSAndroid Build Coastguard Worker             // Add the copy task to initialize dstCopy before the render pass task.
271*c8dee2aaSAndroid Build Coastguard Worker             fCurrentDrawTask->addTask(CopyTextureToTextureTask::Make(
272*c8dee2aaSAndroid Build Coastguard Worker                     fTarget, dstCopyPixelBounds, dstCopy, /*dstPoint=*/{0, 0}));
273*c8dee2aaSAndroid Build Coastguard Worker         }
274*c8dee2aaSAndroid Build Coastguard Worker 
275*c8dee2aaSAndroid Build Coastguard Worker         const Caps* caps = recorder->priv().caps();
276*c8dee2aaSAndroid Build Coastguard Worker         auto [loadOp, storeOp] = pass->ops();
277*c8dee2aaSAndroid Build Coastguard Worker         auto writeSwizzle = caps->getWriteSwizzle(this->colorInfo().colorType(),
278*c8dee2aaSAndroid Build Coastguard Worker                                                   fTarget->textureInfo());
279*c8dee2aaSAndroid Build Coastguard Worker 
280*c8dee2aaSAndroid Build Coastguard Worker         RenderPassDesc desc = RenderPassDesc::Make(caps, fTarget->textureInfo(), loadOp, storeOp,
281*c8dee2aaSAndroid Build Coastguard Worker                                                    pass->depthStencilFlags(),
282*c8dee2aaSAndroid Build Coastguard Worker                                                    pass->clearColor(),
283*c8dee2aaSAndroid Build Coastguard Worker                                                    pass->requiresMSAA(),
284*c8dee2aaSAndroid Build Coastguard Worker                                                    writeSwizzle);
285*c8dee2aaSAndroid Build Coastguard Worker 
286*c8dee2aaSAndroid Build Coastguard Worker         RenderPassTask::DrawPassList passes;
287*c8dee2aaSAndroid Build Coastguard Worker         passes.emplace_back(std::move(pass));
288*c8dee2aaSAndroid Build Coastguard Worker         fCurrentDrawTask->addTask(RenderPassTask::Make(std::move(passes), desc, fTarget,
289*c8dee2aaSAndroid Build Coastguard Worker                                                        std::move(dstCopy), dstCopyPixelBounds));
290*c8dee2aaSAndroid Build Coastguard Worker     }
291*c8dee2aaSAndroid Build Coastguard Worker     // else pass creation failed, DrawPass will have logged why. Don't discard the previously
292*c8dee2aaSAndroid Build Coastguard Worker     // accumulated tasks, however, since they may represent operations on an atlas that other
293*c8dee2aaSAndroid Build Coastguard Worker     // DrawContexts now implicitly depend on.
294*c8dee2aaSAndroid Build Coastguard Worker }
295*c8dee2aaSAndroid Build Coastguard Worker 
snapDrawTask(Recorder * recorder)296*c8dee2aaSAndroid Build Coastguard Worker sk_sp<Task> DrawContext::snapDrawTask(Recorder* recorder) {
297*c8dee2aaSAndroid Build Coastguard Worker     // If flush() was explicitly called earlier and no new work was recorded, this call to flush()
298*c8dee2aaSAndroid Build Coastguard Worker     // is a no-op and shouldn't hurt performance.
299*c8dee2aaSAndroid Build Coastguard Worker     this->flush(recorder);
300*c8dee2aaSAndroid Build Coastguard Worker 
301*c8dee2aaSAndroid Build Coastguard Worker     if (!fCurrentDrawTask->hasTasks()) {
302*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
303*c8dee2aaSAndroid Build Coastguard Worker     }
304*c8dee2aaSAndroid Build Coastguard Worker 
305*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<Task> snappedTask = std::move(fCurrentDrawTask);
306*c8dee2aaSAndroid Build Coastguard Worker     fCurrentDrawTask = sk_make_sp<DrawTask>(fTarget);
307*c8dee2aaSAndroid Build Coastguard Worker     return snappedTask;
308*c8dee2aaSAndroid Build Coastguard Worker }
309*c8dee2aaSAndroid Build Coastguard Worker 
310*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
311