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