• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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