Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
DrawContext.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 Google LLC
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
9
13
41
42namespace skgpu::graphite {
43
44namespace {
45
46// Discarding content on floating point textures can leave nans as the prior color for a pixel,
47// in which case hardware blending (when enabled) will fail even if the src, dst coefficients
48// and coverage would produce the unmodified src value.
49bool discard_op_should_use_clear(SkColorType ct) {
50 switch(ct) {
56 return true;
57 default:
58 return false;
59 }
60}
61
62} // anonymous namespace
63
66 SkISize deviceSize,
67 const SkColorInfo& colorInfo,
68 const SkSurfaceProps& props) {
69 if (!target) {
70 return nullptr;
71 }
72 // We don't render to unknown or unpremul alphatypes
75 return nullptr;
76 }
77 if (!caps->isRenderable(target->textureInfo())) {
78 return nullptr;
79 }
80
81 // Accept an approximate-fit texture, but make sure it's at least as large as the device's
82 // logical size.
83 // TODO: validate that the color type and alpha type are compatible with the target's info
84 SkASSERT(target->isFullyLazy() || (target->dimensions().width() >= deviceSize.width() &&
85 target->dimensions().height() >= deviceSize.height()));
87 return sk_sp<DrawContext>(new DrawContext(caps, std::move(target), imageInfo, props));
88}
89
90DrawContext::DrawContext(const Caps* caps,
92 const SkImageInfo& ii,
93 const SkSurfaceProps& props)
94 : fTarget(std::move(target))
95 , fImageInfo(ii)
96 , fSurfaceProps(props)
97 , fCurrentDrawTask(sk_make_sp<DrawTask>(fTarget))
98 , fPendingDraws(std::make_unique<DrawList>())
99 , fPendingUploads(std::make_unique<UploadList>()) {
100 if (!caps->isTexturable(fTarget->textureInfo())) {
101 fReadView = {}; // Presumably this DrawContext is rendering into a swap chain
102 } else {
103 Swizzle swizzle = caps->getReadSwizzle(ii.colorType(), fTarget->textureInfo());
104 fReadView = {fTarget, swizzle};
105 }
106 // TBD - Will probably want DrawLists (and its internal commands) to come from an arena
107 // that the DC manages.
108}
109
110DrawContext::~DrawContext() = default;
111
112void DrawContext::clear(const SkColor4f& clearColor) {
113 this->discard();
114
115 fPendingLoadOp = LoadOp::kClear;
116 SkPMColor4f pmColor = clearColor.premul();
117 fPendingClearColor = pmColor.array();
118}
119
121 // Non-loading operations on a fully lazy target can corrupt data beyond the DrawContext's
122 // region so should be avoided.
123 SkASSERT(!fTarget->isFullyLazy());
124
125 // A fullscreen clear or discard will overwrite anything that came before, so clear the DrawList
126 // NOTE: Eventually the current DrawTask should be reset, once there are no longer implicit
127 // dependencies on atlas tasks between DrawContexts. When that's resolved, the only tasks in the
128 // current DrawTask are those that directly impact the target, which becomes irrelevant with the
129 // clear op overwriting it. For now, preserve the previous tasks that might include atlas
130 // uploads that are not explicitly shared between DrawContexts.
131 if (fPendingDraws->renderStepCount() > 0) {
132 fPendingDraws = std::make_unique<DrawList>();
133 }
134 if (fComputePathAtlas) {
135 fComputePathAtlas->reset();
136 }
137
138 if (discard_op_should_use_clear(fImageInfo.colorType())) {
139 // In theory the clear color shouldn't matter since a discardable state should be fully
140 // overwritten by later draws, but if a previous call to clear() had injected bad data,
141 // the discard should not inherit it.
142 fPendingClearColor = {0.f, 0.f, 0.f, 0.f};
143 fPendingLoadOp = LoadOp::kClear;
144 } else {
145 fPendingLoadOp = LoadOp::kDiscard;
146 }
147}
148
150 const Transform& localToDevice,
151 const Geometry& geometry,
152 const Clip& clip,
153 DrawOrder ordering,
154 const PaintParams* paint,
155 const StrokeStyle* stroke) {
156 SkASSERT(SkIRect::MakeSize(this->imageInfo().dimensions()).contains(clip.scissor()));
157 fPendingDraws->recordDraw(renderer, localToDevice, geometry, clip, ordering, paint, stroke);
158}
159
161 sk_sp<TextureProxy> targetProxy,
162 const SkColorInfo& srcColorInfo,
163 const SkColorInfo& dstColorInfo,
164 const std::vector<MipLevel>& levels,
165 const SkIRect& dstRect,
166 std::unique_ptr<ConditionalUploadContext> condContext) {
167 // Our caller should have clipped to the bounds of the surface already.
168 SkASSERT(targetProxy->isFullyLazy() ||
169 SkIRect::MakeSize(targetProxy->dimensions()).contains(dstRect));
170 return fPendingUploads->recordUpload(recorder,
171 std::move(targetProxy),
172 srcColorInfo,
173 dstColorInfo,
174 levels,
175 dstRect,
176 std::move(condContext));
177}
178
180 if (!fComputePathAtlas) {
181 fComputePathAtlas = recorder->priv().atlasProvider()->createComputePathAtlas(recorder);
182 }
183 return fComputePathAtlas.get();
184}
185
187 if (fPendingUploads->size() > 0) {
189 "# uploads", fPendingUploads->size());
190 fCurrentDrawTask->addTask(UploadTask::Make(fPendingUploads.get()));
191 // The UploadTask steals the collected upload instances, automatically resetting this list
192 SkASSERT(fPendingUploads->size() == 0);
193 }
194
195 // Generate compute dispatches that render into the atlas texture used by pending draws.
196 // TODO: Once compute atlas caching is implemented, DrawContext might not hold onto to this
197 // at which point a recordDispatch() could be added and it stores a pending dispatches list that
198 // much like how uploads are handled. In that case, Device would be responsible for triggering
199 // the recording of dispatches, but that may happen naturally in AtlasProvider::recordUploads().
200 if (fComputePathAtlas) {
201 auto dispatchGroup = fComputePathAtlas->recordDispatches(recorder);
202 fComputePathAtlas->reset();
203
204 if (dispatchGroup) {
205 // For now this check is valid as all coverage mask draws involve dispatches
206 SkASSERT(fPendingDraws->hasCoverageMaskDraws());
207
209 "# dispatches", dispatchGroup->dispatches().size());
211 dispatches.emplace_back(std::move(dispatchGroup));
212 fCurrentDrawTask->addTask(ComputeTask::Make(std::move(dispatches)));
213 } // else no pending compute work needed to be recorded
214 } // else platform doesn't support compute or atlas was never initialized.
215
216 if (fPendingDraws->renderStepCount() == 0 && fPendingLoadOp != LoadOp::kClear) {
217 // Nothing will be rasterized to the target that warrants a RenderPassTask, but we preserve
218 // any added uploads or compute tasks since those could also affect the target w/o
219 // rasterizing anything directly.
220 return;
221 }
222
223 // Convert the pending draws and load/store ops into a DrawPass that will be executed after
224 // the collected uploads and compute dispatches.
225 // TODO: At this point, there's only ever one DrawPass in a RenderPassTask to a target. When
226 // subpasses are implemented, they will either be collected alongside fPendingDraws or added
227 // to the RenderPassTask separately.
228 std::unique_ptr<DrawPass> pass = DrawPass::Make(recorder,
229 std::move(fPendingDraws),
230 fTarget,
231 this->imageInfo(),
232 std::make_pair(fPendingLoadOp, fPendingStoreOp),
233 fPendingClearColor);
234 fPendingDraws = std::make_unique<DrawList>();
235 // Now that there is content drawn to the target, that content must be loaded on any subsequent
236 // render pass.
237 fPendingLoadOp = LoadOp::kLoad;
238 fPendingStoreOp = StoreOp::kStore;
239
240 if (pass) {
241 SkASSERT(fTarget.get() == pass->target());
242
243 const Caps* caps = recorder->priv().caps();
244 auto [loadOp, storeOp] = pass->ops();
245 auto writeSwizzle = caps->getWriteSwizzle(this->colorInfo().colorType(),
246 fTarget->textureInfo());
247
248 RenderPassDesc desc = RenderPassDesc::Make(caps, fTarget->textureInfo(), loadOp, storeOp,
249 pass->depthStencilFlags(),
250 pass->clearColor(),
251 pass->requiresMSAA(),
252 writeSwizzle);
253
255 passes.emplace_back(std::move(pass));
256 fCurrentDrawTask->addTask(RenderPassTask::Make(std::move(passes), desc, fTarget));
257 }
258 // else pass creation failed, DrawPass will have logged why. Don't discard the previously
259 // accumulated tasks, however, since they may represent operations on an atlas that other
260 // DrawContexts now implicitly depend on.
261}
262
264 // If flush() was explicitly called earlier and no new work was recorded, this call to flush()
265 // is a no-op and shouldn't hurt performance.
266 this->flush(recorder);
267
268 if (!fCurrentDrawTask->hasTasks()) {
269 return nullptr;
270 }
271
272 sk_sp<Task> snappedTask = std::move(fCurrentDrawTask);
273 fCurrentDrawTask = sk_make_sp<DrawTask>(fTarget);
274 return snappedTask;
275}
276
277} // namespace skgpu::graphite
kUnpremul_SkAlphaType
@ kUnknown_SkAlphaType
uninitialized
Definition SkAlphaType.h:27
#define SkASSERT(cond)
Definition SkAssert.h:116
SkColorType
Definition SkColorType.h:19
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition SkColorType.h:38
@ kA16_float_SkColorType
pixel with a half float for alpha
Definition SkColorType.h:45
@ kRGBA_F32_SkColorType
pixel using C float for red, green, blue, alpha; in 128-bit word
Definition SkColorType.h:40
@ kRGBA_F16Norm_SkColorType
pixel with half floats in [0,1] for red, green, blue, alpha;
Definition SkColorType.h:36
@ kR16G16_float_SkColorType
pixel with a half float for red and green
Definition SkColorType.h:46
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static bool contains(const SkRect &r, SkPoint p)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
sk_sp< T > sk_make_sp(Args &&... args)
Definition SkRefCnt.h:371
#define TRACE_EVENT_SCOPE_THREAD
#define TRACE_FUNC
SkAlphaType alphaType() const
std::unique_ptr< ComputePathAtlas > createComputePathAtlas(Recorder *recorder) const
skgpu::Swizzle getReadSwizzle(SkColorType, const TextureInfo &) const
Definition Caps.cpp:128
bool isTexturable(const TextureInfo &) const
Definition Caps.cpp:65
skgpu::Swizzle getWriteSwizzle(SkColorType, const TextureInfo &) const
Definition Caps.cpp:141
virtual bool isRenderable(const TextureInfo &) const =0
static sk_sp< ComputeTask > Make(DispatchGroupList dispatchGroups)
const SkImageInfo & imageInfo() const
Definition DrawContext.h:54
void recordDraw(const Renderer *renderer, const Transform &localToDevice, const Geometry &geometry, const Clip &clip, DrawOrder ordering, const PaintParams *paint, const StrokeStyle *stroke)
const SkColorInfo & colorInfo() const
Definition DrawContext.h:55
static sk_sp< DrawContext > Make(const Caps *caps, sk_sp< TextureProxy > target, SkISize deviceSize, const SkColorInfo &, const SkSurfaceProps &)
PathAtlas * getComputePathAtlas(Recorder *)
void clear(const SkColor4f &clearColor)
sk_sp< Task > snapDrawTask(Recorder *)
bool 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 >)
static std::unique_ptr< DrawPass > Make(Recorder *, std::unique_ptr< DrawList >, sk_sp< TextureProxy > target, const SkImageInfo &targetInfo, std::pair< LoadOp, StoreOp >, std::array< float, 4 > clearColor)
Definition DrawPass.cpp:452
AtlasProvider * atlasProvider()
const Caps * caps() const
static sk_sp< RenderPassTask > Make(DrawPassList, const RenderPassDesc &, sk_sp< TextureProxy > target)
const TextureInfo & textureInfo() const
static sk_sp< UploadTask > Make(UploadList *)
T & emplace_back(Args &&... args)
Definition SkTArray.h:243
const Paint & paint
uint32_t * target
Definition ref_ptr.h:256
static constexpr SkIRect MakeSize(const SkISize &size)
Definition SkRect.h:66
bool contains(int32_t x, int32_t y) const
Definition SkRect.h:463
constexpr int32_t width() const
Definition SkSize.h:36
constexpr int32_t height() const
Definition SkSize.h:37
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
SkColorType colorType() const
std::array< float, 4 > array() const
Definition SkColor.h:317
static RenderPassDesc Make(const Caps *caps, const TextureInfo &targetInfo, LoadOp loadOp, StoreOp storeOp, SkEnumBitMask< DepthStencilFlags > depthStencilFlags, const std::array< float, 4 > &clearColor, bool requiresMSAA, Swizzle writeSwizzle)
#define TRACE_EVENT_INSTANT1(category_group, name, arg1_name, arg1_val)