1 /*
2 * Copyright 2020 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
8 #include "src/gpu/GrSurfaceFillContext.h"
9
10 #include "include/private/GrImageContext.h"
11 #include "src/gpu/GrImageContextPriv.h"
12 #include "src/gpu/GrProxyProvider.h"
13 #include "src/gpu/GrSurfaceDrawContext.h"
14 #include "src/gpu/ops/GrClearOp.h"
15 #include "src/gpu/ops/GrFillRectOp.h"
16
17 #define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(this->singleOwner())
18 #define RETURN_IF_ABANDONED if (fContext->abandoned()) { return; }
19
20 class AutoCheckFlush {
21 public:
AutoCheckFlush(GrDrawingManager * drawingManager)22 AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
23 SkASSERT(fDrawingManager);
24 }
~AutoCheckFlush()25 ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
26
27 private:
28 GrDrawingManager* fDrawingManager;
29 };
30
color_type_fallback(GrColorType ct)31 static inline GrColorType color_type_fallback(GrColorType ct) {
32 switch (ct) {
33 // kRGBA_8888 is our default fallback for many color types that may not have renderable
34 // backend formats.
35 case GrColorType::kAlpha_8:
36 case GrColorType::kBGR_565:
37 case GrColorType::kABGR_4444:
38 case GrColorType::kBGRA_8888:
39 case GrColorType::kRGBA_1010102:
40 case GrColorType::kBGRA_1010102:
41 case GrColorType::kRGBA_F16:
42 case GrColorType::kRGBA_F16_Clamped:
43 return GrColorType::kRGBA_8888;
44 case GrColorType::kAlpha_F16:
45 return GrColorType::kRGBA_F16;
46 case GrColorType::kGray_8:
47 return GrColorType::kRGB_888x;
48 default:
49 return GrColorType::kUnknown;
50 }
51 }
52
GetFallbackColorTypeAndFormat(GrImageContext * context,GrColorType colorType,int sampleCnt)53 std::tuple<GrColorType, GrBackendFormat> GrSurfaceFillContext::GetFallbackColorTypeAndFormat(
54 GrImageContext* context, GrColorType colorType, int sampleCnt) {
55 auto caps = context->priv().caps();
56 do {
57 auto format = caps->getDefaultBackendFormat(colorType, GrRenderable::kYes);
58 // We continue to the fallback color type if there no default renderable format or we
59 // requested msaa and the format doesn't support msaa.
60 if (format.isValid() && caps->isFormatRenderable(format, sampleCnt)) {
61 return {colorType, format};
62 }
63 colorType = color_type_fallback(colorType);
64 } while (colorType != GrColorType::kUnknown);
65 return {GrColorType::kUnknown, {}};
66 }
67
Make(GrRecordingContext * context,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,SkISize dimensions,SkBackingFit fit,const GrBackendFormat & format,int sampleCount,GrMipmapped mipmapped,GrProtected isProtected,GrSwizzle readSwizzle,GrSwizzle writeSwizzle,GrSurfaceOrigin origin,SkBudgeted budgeted)68 std::unique_ptr<GrSurfaceFillContext> GrSurfaceFillContext::Make(GrRecordingContext* context,
69 SkAlphaType alphaType,
70 sk_sp<SkColorSpace> colorSpace,
71 SkISize dimensions,
72 SkBackingFit fit,
73 const GrBackendFormat& format,
74 int sampleCount,
75 GrMipmapped mipmapped,
76 GrProtected isProtected,
77 GrSwizzle readSwizzle,
78 GrSwizzle writeSwizzle,
79 GrSurfaceOrigin origin,
80 SkBudgeted budgeted) {
81 SkASSERT(context);
82 SkASSERT(!dimensions.isEmpty());
83 SkASSERT(sampleCount >= 1);
84 SkASSERT(format.isValid() && format.backend() == context->backend());
85 if (alphaType == kPremul_SkAlphaType || alphaType == kOpaque_SkAlphaType) {
86 return GrSurfaceDrawContext::Make(context,
87 std::move(colorSpace),
88 fit,
89 dimensions,
90 format,
91 sampleCount,
92 mipmapped,
93 isProtected,
94 readSwizzle,
95 writeSwizzle,
96 origin,
97 budgeted,
98 SkSurfaceProps());
99 }
100
101 sk_sp<GrTextureProxy> proxy = context->priv().proxyProvider()->createProxy(format,
102 dimensions,
103 GrRenderable::kYes,
104 sampleCount,
105 mipmapped,
106 fit,
107 budgeted,
108 isProtected);
109 if (!proxy) {
110 return nullptr;
111 }
112 GrImageInfo info(GrColorType::kUnknown, alphaType, std::move(colorSpace), dimensions);
113 GrSurfaceProxyView readView( proxy, origin, readSwizzle);
114 GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);
115 auto fillContext = std::make_unique<GrSurfaceFillContext>(context,
116 std::move(readView),
117 std::move(writeView),
118 info.colorInfo());
119 fillContext->discard();
120 return fillContext;
121 }
122
Make(GrRecordingContext * context,GrImageInfo info,SkBackingFit fit,int sampleCount,GrMipmapped mipmapped,GrProtected isProtected,GrSurfaceOrigin origin,SkBudgeted budgeted)123 std::unique_ptr<GrSurfaceFillContext> GrSurfaceFillContext::Make(GrRecordingContext* context,
124 GrImageInfo info,
125 SkBackingFit fit,
126 int sampleCount,
127 GrMipmapped mipmapped,
128 GrProtected isProtected,
129 GrSurfaceOrigin origin,
130 SkBudgeted budgeted) {
131 if (info.alphaType() == kPremul_SkAlphaType || info.alphaType() == kOpaque_SkAlphaType) {
132 return GrSurfaceDrawContext::Make(context,
133 info.colorType(),
134 info.refColorSpace(),
135 fit,
136 info.dimensions(),
137 SkSurfaceProps(),
138 sampleCount,
139 mipmapped,
140 isProtected,
141 origin,
142 budgeted);
143 }
144 GrBackendFormat format = context->priv().caps()->getDefaultBackendFormat(info.colorType(),
145 GrRenderable::kYes);
146 sk_sp<GrTextureProxy> proxy = context->priv().proxyProvider()->createProxy(format,
147 info.dimensions(),
148 GrRenderable::kYes,
149 sampleCount,
150 mipmapped,
151 fit,
152 budgeted,
153 isProtected);
154 if (!proxy) {
155 return nullptr;
156 }
157 GrSwizzle readSwizzle = context->priv().caps()->getReadSwizzle (format, info.colorType());
158 GrSwizzle writeSwizzle = context->priv().caps()->getWriteSwizzle(format, info.colorType());
159
160 GrSurfaceProxyView readView( proxy, origin, readSwizzle);
161 GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);
162 auto fillContext = std::make_unique<GrSurfaceFillContext>(context,
163 std::move(readView),
164 std::move(writeView),
165 info.colorInfo());
166 fillContext->discard();
167 return fillContext;
168 }
169
MakeWithFallback(GrRecordingContext * context,GrImageInfo info,SkBackingFit fit,int sampleCount,GrMipmapped mipmapped,GrProtected isProtected,GrSurfaceOrigin origin,SkBudgeted budgeted)170 std::unique_ptr<GrSurfaceFillContext> GrSurfaceFillContext::MakeWithFallback(
171 GrRecordingContext* context,
172 GrImageInfo info,
173 SkBackingFit fit,
174 int sampleCount,
175 GrMipmapped mipmapped,
176 GrProtected isProtected,
177 GrSurfaceOrigin origin,
178 SkBudgeted budgeted) {
179 if (info.alphaType() == kPremul_SkAlphaType || info.alphaType() == kOpaque_SkAlphaType) {
180 return GrSurfaceDrawContext::MakeWithFallback(context,
181 info.colorType(),
182 info.refColorSpace(),
183 fit,
184 info.dimensions(),
185 SkSurfaceProps(),
186 sampleCount,
187 mipmapped,
188 isProtected,
189 origin,
190 budgeted);
191 }
192 auto [ct, _] = GetFallbackColorTypeAndFormat(context, info.colorType(), sampleCount);
193 if (ct == GrColorType::kUnknown) {
194 return nullptr;
195 }
196 info = info.makeColorType(ct);
197 return GrSurfaceFillContext::Make(context,
198 info,
199 fit,
200 sampleCount,
201 mipmapped,
202 isProtected,
203 origin,
204 budgeted);
205 }
206
MakeFromBackendTexture(GrRecordingContext * context,GrColorInfo info,const GrBackendTexture & tex,int sampleCount,GrSurfaceOrigin origin,sk_sp<GrRefCntedCallback> releaseHelper)207 std::unique_ptr<GrSurfaceFillContext> GrSurfaceFillContext::MakeFromBackendTexture(
208 GrRecordingContext* context,
209 GrColorInfo info,
210 const GrBackendTexture& tex,
211 int sampleCount,
212 GrSurfaceOrigin origin,
213 sk_sp<GrRefCntedCallback> releaseHelper) {
214 SkASSERT(sampleCount > 0);
215
216 if (info.alphaType() == kPremul_SkAlphaType || info.alphaType() == kOpaque_SkAlphaType) {
217 return GrSurfaceDrawContext::MakeFromBackendTexture(context,
218 info.colorType(),
219 info.refColorSpace(),
220 tex,
221 sampleCount,
222 origin,
223 SkSurfaceProps(),
224 std::move(releaseHelper));
225 }
226 const GrBackendFormat& format = tex.getBackendFormat();
227 GrSwizzle readSwizzle, writeSwizzle;
228 if (info.colorType() != GrColorType::kUnknown) {
229 if (!context->priv().caps()->areColorTypeAndFormatCompatible(info.colorType(), format)) {
230 return nullptr;
231 }
232 readSwizzle = context->priv().caps()->getReadSwizzle (format, info.colorType());
233 writeSwizzle = context->priv().caps()->getWriteSwizzle(format, info.colorType());
234 }
235
236 sk_sp<GrTextureProxy> proxy(context->priv().proxyProvider()->wrapRenderableBackendTexture(
237 tex, sampleCount, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
238 std::move(releaseHelper)));
239 if (!proxy) {
240 return nullptr;
241 }
242
243 GrSurfaceProxyView readView( proxy, origin, readSwizzle);
244 GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);
245
246 return std::make_unique<GrSurfaceFillContext>(context,
247 std::move(readView),
248 std::move(writeView),
249 std::move(info));
250
251 }
252
253 // In MDB mode the reffing of the 'getLastOpsTask' call's result allows in-progress
254 // GrOpsTask to be picked up and added to by GrSurfaceFillContext lower in the call
255 // stack. When this occurs with a closed GrOpsTask, a new one will be allocated
256 // when the GrSurfaceFillContext attempts to use it (via getOpsTask).
GrSurfaceFillContext(GrRecordingContext * context,GrSurfaceProxyView readView,GrSurfaceProxyView writeView,const GrColorInfo & colorInfo,bool flushTimeOpsTask)257 GrSurfaceFillContext::GrSurfaceFillContext(GrRecordingContext* context,
258 GrSurfaceProxyView readView,
259 GrSurfaceProxyView writeView,
260 const GrColorInfo& colorInfo,
261 bool flushTimeOpsTask)
262 : GrSurfaceContext(context, std::move(readView), std::move(colorInfo))
263 , fWriteView(std::move(writeView))
264 , fFlushTimeOpsTask(flushTimeOpsTask) {
265 fOpsTask = sk_ref_sp(context->priv().drawingManager()->getLastOpsTask(this->asSurfaceProxy()));
266 SkASSERT(this->asSurfaceProxy() == fWriteView.proxy());
267 SkASSERT(this->origin() == fWriteView.origin());
268
269 SkDEBUGCODE(this->validate();)
270 }
271
fillRectWithFP(const SkIRect & dstRect,std::unique_ptr<GrFragmentProcessor> fp)272 void GrSurfaceFillContext::fillRectWithFP(const SkIRect& dstRect,
273 std::unique_ptr<GrFragmentProcessor> fp) {
274 ASSERT_SINGLE_OWNER
275 RETURN_IF_ABANDONED
276 SkDEBUGCODE(this->validate();)
277 GR_CREATE_TRACE_MARKER_CONTEXT("GrSurfaceFillContext", "fillRectWithFP", fContext);
278
279 AutoCheckFlush acf(this->drawingManager());
280
281 GrPaint paint;
282 paint.setColorFragmentProcessor(std::move(fp));
283 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
284 auto op = GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
285 SkRect::Make(dstRect));
286 this->addDrawOp(std::move(op));
287 }
288
addDrawOp(GrOp::Owner owner)289 void GrSurfaceFillContext::addDrawOp(GrOp::Owner owner) {
290 GrDrawOp* op = static_cast<GrDrawOp*>(owner.get());
291 GrClampType clampType = GrColorTypeClampType(this->colorInfo().colorType());
292 auto clip = GrAppliedClip::Disabled();
293 const GrCaps& caps = *this->caps();
294 GrProcessorSet::Analysis analysis = op->finalize(caps, &clip, clampType);
295 SkASSERT(!(op->fixedFunctionFlags() & GrDrawOp::FixedFunctionFlags::kUsesStencil));
296 SkASSERT(!analysis.requiresDstTexture());
297 SkRect bounds = owner->bounds();
298 // We shouldn't have coverage AA or hairline draws in fill contexts.
299 SkASSERT(!op->hasAABloat() && !op->hasZeroArea());
300 if (!bounds.intersect(this->asSurfaceProxy()->getBoundsRect())) {
301 return;
302 }
303 op->setClippedBounds(op->bounds());
304 SkDEBUGCODE(op->fAddDrawOpCalled = true;)
305
306 GrXferProcessor::DstProxyView dstProxyView;
307 this->getOpsTask()->addDrawOp(fContext->priv().drawingManager(),
308 std::move(owner),
309 op->fixedFunctionFlags(),
310 analysis,
311 std::move(clip),
312 dstProxyView,
313 GrTextureResolveManager(this->drawingManager()),
314 caps);
315 }
316
ClearToGrPaint(std::array<float,4> color,GrPaint * paint)317 void GrSurfaceFillContext::ClearToGrPaint(std::array<float, 4> color, GrPaint* paint) {
318 paint->setColor4f({color[0], color[1], color[2], color[3]});
319 if (color[3] == 1.f) {
320 // Can just rely on the src-over blend mode to do the right thing.
321 // This may improve batching.
322 paint->setPorterDuffXPFactory(SkBlendMode::kSrcOver);
323 } else {
324 // A clear overwrites the prior color, so even if it's transparent, it behaves as if it
325 // were src blended
326 paint->setPorterDuffXPFactory(SkBlendMode::kSrc);
327 }
328 }
329
addOp(GrOp::Owner op)330 void GrSurfaceFillContext::addOp(GrOp::Owner op) {
331 GrDrawingManager* drawingMgr = this->drawingManager();
332 this->getOpsTask()->addOp(drawingMgr,
333 std::move(op),
334 GrTextureResolveManager(drawingMgr),
335 *this->caps());
336 }
337
getOpsTask()338 GrOpsTask* GrSurfaceFillContext::getOpsTask() {
339 ASSERT_SINGLE_OWNER
340 SkDEBUGCODE(this->validate();)
341
342 if (!fOpsTask || fOpsTask->isClosed()) {
343 sk_sp<GrOpsTask> newOpsTask = this->drawingManager()->newOpsTask(
344 this->writeSurfaceView(), this->arenas(), fFlushTimeOpsTask);
345 this->willReplaceOpsTask(fOpsTask.get(), newOpsTask.get());
346 fOpsTask = std::move(newOpsTask);
347 }
348 SkASSERT(!fOpsTask->isClosed());
349 return fOpsTask.get();
350 }
351
352 #ifdef SK_DEBUG
onValidate() const353 void GrSurfaceFillContext::onValidate() const {
354 if (fOpsTask && !fOpsTask->isClosed()) {
355 SkASSERT(this->drawingManager()->getLastRenderTask(fWriteView.proxy()) == fOpsTask.get());
356 }
357 }
358 #endif
359
discard()360 void GrSurfaceFillContext::discard() {
361 ASSERT_SINGLE_OWNER
362 RETURN_IF_ABANDONED
363 SkDEBUGCODE(this->validate();)
364 GR_CREATE_TRACE_MARKER_CONTEXT("GrSurfaceDrawContext", "discard", fContext);
365
366 AutoCheckFlush acf(this->drawingManager());
367
368 this->getOpsTask()->discard();
369 }
370
internalClear(const SkIRect * scissor,std::array<float,4> color,bool upgradePartialToFull)371 void GrSurfaceFillContext::internalClear(const SkIRect* scissor,
372 std::array<float, 4> color,
373 bool upgradePartialToFull) {
374 ASSERT_SINGLE_OWNER
375 RETURN_IF_ABANDONED
376 SkDEBUGCODE(this->validate();)
377 GR_CREATE_TRACE_MARKER_CONTEXT("GrSurfaceDrawContext", "clear", fContext);
378
379 // There are three ways clears are handled: load ops, native clears, and draws. Load ops are
380 // only for fullscreen clears; native clears can be fullscreen or with scissors if the backend
381 // supports then. Drawing an axis-aligned rect is the fallback path.
382 GrScissorState scissorState(this->asSurfaceProxy()->backingStoreDimensions());
383 if (scissor && !scissorState.set(*scissor)) {
384 // The clear is offscreen, so skip it (normally this would be handled by addDrawOp,
385 // except clear ops are not draw ops).
386 return;
387 }
388
389 // If we have a scissor but it's okay to clear beyond it for performance reasons, then disable
390 // the test. We only do this when the clear would be handled by a load op or natively.
391 if (scissorState.enabled() && !this->caps()->performColorClearsAsDraws()) {
392 if (upgradePartialToFull && (this->caps()->preferFullscreenClears() ||
393 this->caps()->shouldInitializeTextures())) {
394 // TODO: wrt the shouldInitializeTextures path, it would be more performant to
395 // only clear the entire target if we knew it had not been cleared before. As
396 // is this could end up doing a lot of redundant clears.
397 scissorState.setDisabled();
398 } else {
399 // Unlike with stencil clears, we also allow clears up to the logical dimensions of the
400 // render target to overflow into any approx-fit padding of the backing store dimensions
401 scissorState.relaxTest(this->dimensions());
402 }
403 }
404
405 if (!scissorState.enabled()) {
406 // This is a fullscreen clear, so could be handled as a load op. Regardless, we can also
407 // discard all prior ops in the current task since the color buffer will be overwritten.
408 GrOpsTask* opsTask = this->getOpsTask();
409 if (opsTask->resetForFullscreenClear(this->canDiscardPreviousOpsOnFullClear()) &&
410 !this->caps()->performColorClearsAsDraws()) {
411 color = this->writeSurfaceView().swizzle().applyTo(color);
412 // The op list was emptied and native clears are allowed, so just use the load op
413 opsTask->setColorLoadOp(GrLoadOp::kClear, color);
414 return;
415 } else {
416 // Will use an op for the clear, reset the load op to discard since the op will
417 // blow away the color buffer contents
418 opsTask->setColorLoadOp(GrLoadOp::kDiscard);
419 }
420 }
421
422 // At this point we are either a partial clear or a fullscreen clear that couldn't be applied
423 // as a load op.
424 bool clearAsDraw = this->caps()->performColorClearsAsDraws() ||
425 (scissorState.enabled() && this->caps()->performPartialClearsAsDraws());
426 if (clearAsDraw) {
427 GrPaint paint;
428 ClearToGrPaint(color, &paint);
429 auto op = GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
430 SkRect::Make(scissorState.rect()));
431 this->addDrawOp(std::move(op));
432 } else {
433 color = this->writeSurfaceView().swizzle().applyTo(color);
434 this->addOp(GrClearOp::MakeColor(fContext, scissorState, color));
435 }
436 }
437
blitTexture(GrSurfaceProxyView view,const SkIRect & srcRect,const SkIPoint & dstPoint)438 bool GrSurfaceFillContext::blitTexture(GrSurfaceProxyView view,
439 const SkIRect& srcRect,
440 const SkIPoint& dstPoint) {
441 SkASSERT(view.asTextureProxy());
442 SkIRect clippedSrcRect;
443 SkIPoint clippedDstPoint;
444 if (!GrClipSrcRectAndDstPoint(this->dimensions(),
445 view.dimensions(),
446 srcRect,
447 dstPoint,
448 &clippedSrcRect,
449 &clippedDstPoint)) {
450 return false;
451 }
452
453 auto fp = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType);
454 auto dstRect = SkIRect::MakePtSize(clippedDstPoint, clippedSrcRect.size());
455 auto srcRectF = SkRect::Make(clippedSrcRect);
456 this->fillRectToRectWithFP(srcRectF, dstRect, std::move(fp));
457 return true;
458 }
459