• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
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/GrSurfaceContext.h"
9 
10 #include <memory>
11 
12 #include "include/gpu/GrDirectContext.h"
13 #include "include/gpu/GrRecordingContext.h"
14 #include "src/core/SkAutoPixmapStorage.h"
15 #include "src/core/SkMipmap.h"
16 #include "src/core/SkYUVMath.h"
17 #include "src/gpu/GrAuditTrail.h"
18 #include "src/gpu/GrColorSpaceXform.h"
19 #include "src/gpu/GrDataUtils.h"
20 #include "src/gpu/GrDirectContextPriv.h"
21 #include "src/gpu/GrDrawingManager.h"
22 #include "src/gpu/GrGpu.h"
23 #include "src/gpu/GrImageInfo.h"
24 #include "src/gpu/GrProxyProvider.h"
25 #include "src/gpu/GrRecordingContextPriv.h"
26 #include "src/gpu/GrSurfaceDrawContext.h"
27 #include "src/gpu/GrSurfaceFillContext.h"
28 #include "src/gpu/SkGr.h"
29 #include "src/gpu/effects/GrBicubicEffect.h"
30 #include "src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h"
31 
32 #define ASSERT_SINGLE_OWNER         GR_ASSERT_SINGLE_OWNER(this->singleOwner())
33 #define RETURN_FALSE_IF_ABANDONED   if (this->fContext->abandoned()) { return false;   }
34 #define RETURN_NULLPTR_IF_ABANDONED if (this->fContext->abandoned()) { return nullptr; }
35 
Make(GrRecordingContext * context,GrSurfaceProxyView readView,const GrColorInfo & info)36 std::unique_ptr<GrSurfaceContext> GrSurfaceContext::Make(GrRecordingContext* context,
37                                                          GrSurfaceProxyView readView,
38                                                          const GrColorInfo& info) {
39     // It is probably not necessary to check if the context is abandoned here since uses of the
40     // GrSurfaceContext which need the context will mostly likely fail later on without an issue.
41     // However having this hear adds some reassurance in case there is a path doesn't handle an
42     // abandoned context correctly. It also lets us early out of some extra work.
43     if (context->abandoned()) {
44         return nullptr;
45     }
46     GrSurfaceProxy* proxy = readView.proxy();
47     SkASSERT(proxy && proxy->asTextureProxy());
48 
49     std::unique_ptr<GrSurfaceContext> surfaceContext;
50     if (proxy->asRenderTargetProxy()) {
51         // Will we ever want a swizzle that is not the default write swizzle for the format and
52         // colorType here? If so we will need to manually pass that in.
53         GrSwizzle writeSwizzle;
54         if (info.colorType() != GrColorType::kUnknown) {
55             writeSwizzle = context->priv().caps()->getWriteSwizzle(proxy->backendFormat(),
56                                                                    info.colorType());
57         }
58         GrSurfaceProxyView writeView(readView.refProxy(), readView.origin(), writeSwizzle);
59         if (info.alphaType() == kPremul_SkAlphaType || info.alphaType() == kOpaque_SkAlphaType) {
60             surfaceContext = std::make_unique<GrSurfaceDrawContext>(context,
61                                                                     std::move(readView),
62                                                                     std::move(writeView),
63                                                                     info.colorType(),
64                                                                     info.refColorSpace(),
65                                                                     SkSurfaceProps());
66         } else {
67             surfaceContext = std::make_unique<GrSurfaceFillContext>(context,
68                                                                     std::move(readView),
69                                                                     std::move(writeView),
70                                                                     info);
71         }
72     } else {
73         surfaceContext = std::make_unique<GrSurfaceContext>(context, std::move(readView), info);
74     }
75     SkDEBUGCODE(surfaceContext->validate();)
76     return surfaceContext;
77 }
78 
Make(GrRecordingContext * context,const GrImageInfo & info,const GrBackendFormat & format,SkBackingFit fit,GrSurfaceOrigin origin,GrRenderable renderable,int sampleCount,GrMipmapped mipmapped,GrProtected isProtected,SkBudgeted budgeted)79 std::unique_ptr<GrSurfaceContext> GrSurfaceContext::Make(GrRecordingContext* context,
80                                                          const GrImageInfo& info,
81                                                          const GrBackendFormat& format,
82                                                          SkBackingFit fit,
83                                                          GrSurfaceOrigin origin,
84                                                          GrRenderable renderable,
85                                                          int sampleCount,
86                                                          GrMipmapped mipmapped,
87                                                          GrProtected isProtected,
88                                                          SkBudgeted budgeted) {
89     SkASSERT(context);
90     SkASSERT(renderable == GrRenderable::kYes || sampleCount == 1);
91     if (context->abandoned()) {
92         return nullptr;
93     }
94     sk_sp<GrTextureProxy> proxy = context->priv().proxyProvider()->createProxy(format,
95                                                                                info.dimensions(),
96                                                                                renderable,
97                                                                                sampleCount,
98                                                                                mipmapped,
99                                                                                fit,
100                                                                                budgeted,
101                                                                                isProtected);
102     if (!proxy) {
103         return nullptr;
104     }
105 
106     GrSwizzle swizzle;
107     if (info.colorType() != GrColorType::kUnknown &&
108         !context->priv().caps()->isFormatCompressed(format)) {
109         swizzle = context->priv().caps()->getReadSwizzle(format, info.colorType());
110     }
111 
112     GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
113     return GrSurfaceContext::Make(context, std::move(view), info.colorInfo());
114 }
115 
Make(GrRecordingContext * context,const GrImageInfo & info,SkBackingFit fit,GrSurfaceOrigin origin,GrRenderable renderable,int sampleCount,GrMipmapped mipmapped,GrProtected isProtected,SkBudgeted budgeted)116 std::unique_ptr<GrSurfaceContext> GrSurfaceContext::Make(GrRecordingContext* context,
117                                                          const GrImageInfo& info,
118                                                          SkBackingFit fit,
119                                                          GrSurfaceOrigin origin,
120                                                          GrRenderable renderable,
121                                                          int sampleCount,
122                                                          GrMipmapped mipmapped,
123                                                          GrProtected isProtected,
124                                                          SkBudgeted budgeted) {
125     GrBackendFormat format = context->priv().caps()->getDefaultBackendFormat(info.colorType(),
126                                                                              renderable);
127     return Make(context,
128                 info,
129                 format,
130                 fit,
131                 origin,
132                 renderable,
133                 sampleCount,
134                 mipmapped,
135                 isProtected,
136                 budgeted);
137 }
138 
GrSurfaceContext(GrRecordingContext * context,GrSurfaceProxyView readView,const GrColorInfo & info)139 GrSurfaceContext::GrSurfaceContext(GrRecordingContext* context,
140                                    GrSurfaceProxyView readView,
141                                    const GrColorInfo& info)
142         : fContext(context), fReadView(std::move(readView)), fColorInfo(info) {
143     SkASSERT(!context->abandoned());
144 }
145 
caps() const146 const GrCaps* GrSurfaceContext::caps() const { return fContext->priv().caps(); }
147 
auditTrail()148 GrAuditTrail* GrSurfaceContext::auditTrail() {
149     return fContext->priv().auditTrail();
150 }
151 
drawingManager()152 GrDrawingManager* GrSurfaceContext::drawingManager() {
153     return fContext->priv().drawingManager();
154 }
155 
drawingManager() const156 const GrDrawingManager* GrSurfaceContext::drawingManager() const {
157     return fContext->priv().drawingManager();
158 }
159 
160 #ifdef SK_DEBUG
singleOwner() const161 GrSingleOwner* GrSurfaceContext::singleOwner() const { return fContext->priv().singleOwner(); }
162 #endif
163 
alpha_types_compatible(SkAlphaType srcAlphaType,SkAlphaType dstAlphaType)164 static bool alpha_types_compatible(SkAlphaType srcAlphaType, SkAlphaType dstAlphaType) {
165     // If both alpha types are kUnknown things make sense. If not, it's too underspecified.
166     return (srcAlphaType == kUnknown_SkAlphaType) == (dstAlphaType == kUnknown_SkAlphaType);
167 }
168 
readPixels(GrDirectContext * dContext,GrPixmap dst,SkIPoint pt)169 bool GrSurfaceContext::readPixels(GrDirectContext* dContext, GrPixmap dst, SkIPoint pt) {
170     ASSERT_SINGLE_OWNER
171     RETURN_FALSE_IF_ABANDONED
172     SkDEBUGCODE(this->validate();)
173     GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrSurfaceContext::readPixels");
174     if (!fContext->priv().matches(dContext)) {
175         return false;
176     }
177 
178     if (dst.colorType() == GrColorType::kUnknown) {
179         return false;
180     }
181 
182     if (dst.rowBytes() % dst.info().bpp()) {
183         return false;
184     }
185 
186     dst = dst.clip(this->dimensions(), &pt);
187     if (!dst.hasPixels()) {
188         return false;
189     }
190     if (!alpha_types_compatible(this->colorInfo().alphaType(), dst.alphaType())) {
191         return false;
192     }
193     // We allow unknown alpha types but only if both src and dst are unknown. Otherwise, it's too
194     // weird to reason about what should be expected.
195 
196     sk_sp<GrSurfaceProxy> srcProxy = this->asSurfaceProxyRef();
197 
198     if (srcProxy->framebufferOnly()) {
199         return false;
200     }
201 
202     // MDB TODO: delay this instantiation until later in the method
203     if (!srcProxy->instantiate(dContext->priv().resourceProvider())) {
204         return false;
205     }
206 
207     GrSurface* srcSurface = srcProxy->peekSurface();
208 
209     SkColorSpaceXformSteps::Flags flags =
210             SkColorSpaceXformSteps{this->colorInfo(), dst.info()}.flags;
211     bool unpremul            = flags.unpremul,
212          needColorConversion = flags.linearize || flags.gamut_transform || flags.encode,
213          premul              = flags.premul;
214 
215     const GrCaps* caps = dContext->priv().caps();
216     bool srcIsCompressed = caps->isFormatCompressed(srcSurface->backendFormat());
217     // This is the getImageData equivalent to the canvas2D putImageData fast path. We probably don't
218     // care so much about getImageData performance. However, in order to ensure putImageData/
219     // getImageData in "legacy" mode are round-trippable we use the GPU to do the complementary
220     // unpremul step to writeSurfacePixels's premul step (which is determined empirically in
221     // fContext->vaildaPMUPMConversionExists()).
222     GrBackendFormat defaultRGBAFormat = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
223                                                                       GrRenderable::kYes);
224     GrColorType srcColorType = this->colorInfo().colorType();
225     bool canvas2DFastPath = unpremul && !needColorConversion &&
226                             (GrColorType::kRGBA_8888 == dst.colorType() ||
227                              GrColorType::kBGRA_8888 == dst.colorType()) &&
228                             SkToBool(srcProxy->asTextureProxy()) &&
229                             (srcColorType == GrColorType::kRGBA_8888 ||
230                              srcColorType == GrColorType::kBGRA_8888) &&
231                             defaultRGBAFormat.isValid() &&
232                             dContext->priv().validPMUPMConversionExists();
233 
234     auto readFlag = caps->surfaceSupportsReadPixels(srcSurface);
235     if (readFlag == GrCaps::SurfaceReadPixelsSupport::kUnsupported) {
236         return false;
237     }
238 
239     if (readFlag == GrCaps::SurfaceReadPixelsSupport::kCopyToTexture2D || canvas2DFastPath) {
240         std::unique_ptr<GrSurfaceContext> tempCtx;
241         if (this->asTextureProxy()) {
242             GrColorType colorType = (canvas2DFastPath || srcIsCompressed)
243                                             ? GrColorType::kRGBA_8888
244                                             : this->colorInfo().colorType();
245             SkAlphaType alphaType = canvas2DFastPath ? dst.alphaType()
246                                                      : this->colorInfo().alphaType();
247             GrImageInfo tempInfo(colorType,
248                                  alphaType,
249                                  this->colorInfo().refColorSpace(),
250                                  dst.dimensions());
251             auto sfc = GrSurfaceFillContext::Make(dContext, tempInfo, SkBackingFit::kApprox);
252             if (!sfc) {
253                 return false;
254             }
255 
256             std::unique_ptr<GrFragmentProcessor> fp;
257             if (canvas2DFastPath) {
258                 fp = dContext->priv().createPMToUPMEffect(GrTextureEffect::Make(
259                         this->readSurfaceView(), this->colorInfo().alphaType()));
260                 if (dst.colorType() == GrColorType::kBGRA_8888) {
261                     fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
262                     dst = GrPixmap(dst.info().makeColorType(GrColorType::kRGBA_8888),
263                                    dst.addr(),
264                                    dst.rowBytes());
265                 }
266             } else {
267                 fp = GrTextureEffect::Make(this->readSurfaceView(), this->colorInfo().alphaType());
268             }
269             if (!fp) {
270                 return false;
271             }
272             sfc->fillRectToRectWithFP(SkIRect::MakePtSize(pt, dst.dimensions()),
273                                       SkIRect::MakeSize(dst.dimensions()),
274                                       std::move(fp));
275             pt = {0, 0};
276             tempCtx = std::move(sfc);
277         } else {
278             auto restrictions = this->caps()->getDstCopyRestrictions(this->asRenderTargetProxy(),
279                                                                      this->colorInfo().colorType());
280             sk_sp<GrSurfaceProxy> copy;
281             static constexpr auto kFit = SkBackingFit::kExact;
282             static constexpr auto kBudgeted = SkBudgeted::kYes;
283             static constexpr auto kMipMapped = GrMipMapped::kNo;
284             if (restrictions.fMustCopyWholeSrc) {
285                 copy = GrSurfaceProxy::Copy(fContext,
286                                             std::move(srcProxy),
287                                             this->origin(),
288                                             kMipMapped,
289                                             kFit,
290                                             kBudgeted);
291             } else {
292                 auto srcRect = SkIRect::MakePtSize(pt, dst.dimensions());
293                 copy = GrSurfaceProxy::Copy(fContext,
294                                             std::move(srcProxy),
295                                             this->origin(),
296                                             kMipMapped,
297                                             srcRect,
298                                             kFit,
299                                             kBudgeted,
300                                             restrictions.fRectsMustMatch);
301                 pt = {0, 0};
302             }
303             if (!copy) {
304                 return false;
305             }
306             GrSurfaceProxyView view{std::move(copy), this->origin(), this->readSwizzle()};
307             tempCtx = GrSurfaceContext::Make(dContext, std::move(view), this->colorInfo());
308             SkASSERT(tempCtx);
309         }
310         return tempCtx->readPixels(dContext, dst, pt);
311     }
312 
313     bool flip = this->origin() == kBottomLeft_GrSurfaceOrigin;
314 
315     auto supportedRead = caps->supportedReadPixelsColorType(
316             this->colorInfo().colorType(), srcProxy->backendFormat(), dst.colorType());
317 
318     bool makeTight =
319             !caps->readPixelsRowBytesSupport() && dst.rowBytes() != dst.info().minRowBytes();
320 
321     bool convert = unpremul || premul || needColorConversion || flip || makeTight ||
322                    (dst.colorType() != supportedRead.fColorType);
323 
324     std::unique_ptr<char[]> tmpPixels;
325     GrPixmap tmp;
326     void* readDst = dst.addr();
327     size_t readRB = dst.rowBytes();
328     if (convert) {
329         GrImageInfo tmpInfo(supportedRead.fColorType,
330                             this->colorInfo().alphaType(),
331                             this->colorInfo().refColorSpace(),
332                             dst.dimensions());
333         size_t tmpRB = tmpInfo.minRowBytes();
334         size_t size = tmpRB * tmpInfo.height();
335         // Chrome MSAN bots require the data to be initialized (hence the ()).
336         tmpPixels = std::make_unique<char[]>(size);
337         tmp = {tmpInfo, tmpPixels.get(), tmpRB};
338 
339         readDst = tmpPixels.get();
340         readRB = tmpRB;
341         pt.fY = flip ? srcSurface->height() - pt.fY - dst.height() : pt.fY;
342     }
343 
344     dContext->priv().flushSurface(srcProxy.get());
345     dContext->submit();
346     if (!dContext->priv().getGpu()->readPixels(srcSurface, pt.fX, pt.fY, dst.width(), dst.height(),
347                                                this->colorInfo().colorType(),
348                                                supportedRead.fColorType, readDst, readRB)) {
349         return false;
350     }
351 
352     if (tmp.hasPixels()) {
353         return GrConvertPixels(dst, tmp, flip);
354     }
355     return true;
356 }
357 
writePixels(GrDirectContext * dContext,GrCPixmap src,SkIPoint dstPt)358 bool GrSurfaceContext::writePixels(GrDirectContext* dContext,
359                                    GrCPixmap src,
360                                    SkIPoint dstPt) {
361     ASSERT_SINGLE_OWNER
362     RETURN_FALSE_IF_ABANDONED
363     SkDEBUGCODE(this->validate();)
364 
365     src = src.clip(this->dimensions(), &dstPt);
366     if (!src.hasPixels()) {
367         return false;
368     }
369     if (!src.info().bpp() || src.rowBytes() % src.info().bpp()) {
370         return false;
371     }
372     return this->internalWritePixels(dContext, &src, 1, dstPt);
373 }
374 
writePixels(GrDirectContext * dContext,const GrCPixmap src[],int numLevels)375 bool GrSurfaceContext::writePixels(GrDirectContext* dContext,
376                                    const GrCPixmap src[],
377                                    int numLevels) {
378     ASSERT_SINGLE_OWNER
379     RETURN_FALSE_IF_ABANDONED
380     SkDEBUGCODE(this->validate();)
381 
382     SkASSERT(dContext);
383     SkASSERT(numLevels >= 1);
384     SkASSERT(src);
385 
386     if (numLevels == 1) {
387         if (src->dimensions() != this->dimensions()) {
388             return false;
389         }
390         return this->writePixels(dContext, src[0], {0, 0});
391     }
392     if (!this->asTextureProxy() || this->asTextureProxy()->proxyMipmapped() == GrMipmapped::kNo) {
393         return false;
394     }
395 
396     SkISize dims = this->dimensions();
397     if (numLevels != SkMipmap::ComputeLevelCount(dims) + 1) {
398         return false;
399     }
400     for (int i = 0; i < numLevels; ++i) {
401         if (src[i].colorInfo() != src[0].colorInfo()) {
402             return false;
403         }
404         if (dims != src[i].dimensions()) {
405             return false;
406         }
407         if (!src[i].info().bpp() || src[i].rowBytes() % src[i].info().bpp()) {
408             return false;
409         }
410         dims = {std::max(1, dims.width()/2), std::max(1, dims.height()/2)};
411     }
412     return this->internalWritePixels(dContext, src, numLevels, {0, 0});
413 }
414 
internalWritePixels(GrDirectContext * dContext,const GrCPixmap src[],int numLevels,SkIPoint pt)415 bool GrSurfaceContext::internalWritePixels(GrDirectContext* dContext,
416                                            const GrCPixmap src[],
417                                            int numLevels,
418                                            SkIPoint pt) {
419     GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrSurfaceContext::internalWritePixels");
420 
421     SkASSERT(numLevels >= 1);
422     SkASSERT(src);
423 
424     // We can either write to a subset or write MIP levels, but not both.
425     SkASSERT((src[0].dimensions() == this->dimensions() && pt.isZero()) || numLevels == 1);
426     SkASSERT(numLevels == 1 ||
427              (this->asTextureProxy() && this->asTextureProxy()->mipmapped() == GrMipmapped::kYes));
428     // Our public caller should have clipped to the bounds of the surface already.
429     SkASSERT(SkIRect::MakeSize(this->dimensions()).contains(
430             SkIRect::MakePtSize(pt, src[0].dimensions())));
431 
432     if (!dContext) {
433         return false;
434     }
435 
436     if (this->asSurfaceProxy()->readOnly()) {
437         return false;
438     }
439 
440     if (src[0].colorType() == GrColorType::kUnknown) {
441         return false;
442     }
443 
444     if (!alpha_types_compatible(src[0].alphaType(), this->colorInfo().alphaType())) {
445         return false;
446     }
447 
448     GrSurfaceProxy* dstProxy = this->asSurfaceProxy();
449 
450     if (dstProxy->framebufferOnly()) {
451         return false;
452     }
453 
454     if (!dstProxy->instantiate(dContext->priv().resourceProvider())) {
455         return false;
456     }
457 
458     GrSurface* dstSurface = dstProxy->peekSurface();
459 
460     SkColorSpaceXformSteps::Flags flags =
461             SkColorSpaceXformSteps{src[0].colorInfo(), this->colorInfo()}.flags;
462     bool unpremul            = flags.unpremul,
463          needColorConversion = flags.linearize || flags.gamut_transform || flags.encode,
464          premul              = flags.premul;
465 
466     const GrCaps* caps = dContext->priv().caps();
467 
468     auto rgbaDefaultFormat = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
469                                                            GrRenderable::kNo);
470 
471     GrColorType dstColorType = this->colorInfo().colorType();
472     // For canvas2D putImageData performance we have a special code path for unpremul RGBA_8888 srcs
473     // that are premultiplied on the GPU. This is kept as narrow as possible for now.
474     bool canvas2DFastPath = !caps->avoidWritePixelsFastPath() && premul && !needColorConversion &&
475                             (src[0].colorType() == GrColorType::kRGBA_8888 ||
476                              src[0].colorType() == GrColorType::kBGRA_8888) &&
477                             this->asFillContext() &&
478                             (dstColorType == GrColorType::kRGBA_8888 ||
479                              dstColorType == GrColorType::kBGRA_8888) &&
480                             rgbaDefaultFormat.isValid() &&
481                             dContext->priv().validPMUPMConversionExists();
482     // Drawing code path doesn't support writing to levels and doesn't support inserting layout
483     // transitions.
484     if ((!caps->surfaceSupportsWritePixels(dstSurface) || canvas2DFastPath) && numLevels == 1) {
485         GrColorInfo tempColorInfo;
486         GrBackendFormat format;
487         GrSwizzle tempReadSwizzle;
488         if (canvas2DFastPath) {
489             tempColorInfo = {GrColorType::kRGBA_8888,
490                              kUnpremul_SkAlphaType,
491                              this->colorInfo().refColorSpace()};
492             format = rgbaDefaultFormat;
493         } else {
494             tempColorInfo = this->colorInfo();
495             format = dstProxy->backendFormat().makeTexture2D();
496             if (!format.isValid()) {
497                 return false;
498             }
499             tempReadSwizzle = this->readSwizzle();
500         }
501 
502         // It is more efficient for us to write pixels into a top left origin so we prefer that.
503         // However, if the final proxy isn't a render target then we must use a copy to move the
504         // data into it which requires the origins to match. If the final proxy is a render target
505         // we can use a draw instead which doesn't have this origin restriction. Thus for render
506         // targets we will use top left and otherwise we will make the origins match.
507         GrSurfaceOrigin tempOrigin =
508                 this->asFillContext() ? kTopLeft_GrSurfaceOrigin : this->origin();
509         auto tempProxy = dContext->priv().proxyProvider()->createProxy(format,
510                                                                        src[0].dimensions(),
511                                                                        GrRenderable::kNo,
512                                                                        1,
513                                                                        GrMipmapped::kNo,
514                                                                        SkBackingFit::kApprox,
515                                                                        SkBudgeted::kYes,
516                                                                        GrProtected::kNo);
517         if (!tempProxy) {
518             return false;
519         }
520         GrSurfaceProxyView tempView(tempProxy, tempOrigin, tempReadSwizzle);
521         GrSurfaceContext tempCtx(dContext, tempView, tempColorInfo);
522 
523         // In the fast path we always write the srcData to the temp context as though it were RGBA.
524         // When the data is really BGRA the write will cause the R and B channels to be swapped in
525         // the intermediate surface which gets corrected by a swizzle effect when drawing to the
526         // dst.
527         GrCPixmap origSrcBase = src[0];
528         GrCPixmap srcBase = origSrcBase;
529         if (canvas2DFastPath) {
530             srcBase = GrCPixmap(origSrcBase.info().makeColorType(GrColorType::kRGBA_8888),
531                                 origSrcBase.addr(),
532                                 origSrcBase.rowBytes());
533         }
534         if (!tempCtx.writePixels(dContext, srcBase, {0, 0})) {
535             return false;
536         }
537 
538         if (this->asFillContext()) {
539             std::unique_ptr<GrFragmentProcessor> fp;
540             if (canvas2DFastPath) {
541                 fp = dContext->priv().createUPMToPMEffect(
542                         GrTextureEffect::Make(std::move(tempView), tempColorInfo.alphaType()));
543                 // Important: check the original src color type here!
544                 if (origSrcBase.colorType() == GrColorType::kBGRA_8888) {
545                     fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
546                 }
547             } else {
548                 fp = GrTextureEffect::Make(std::move(tempView), tempColorInfo.alphaType());
549             }
550             if (!fp) {
551                 return false;
552             }
553             this->asFillContext()->fillRectToRectWithFP(
554                     SkIRect::MakeSize(srcBase.dimensions()),
555                     SkIRect::MakePtSize(pt, srcBase.dimensions()),
556                     std::move(fp));
557         } else {
558             SkIRect srcRect = SkIRect::MakeSize(srcBase.dimensions());
559             SkIPoint dstPoint = SkIPoint::Make(pt.fX, pt.fY);
560             if (!this->copy(std::move(tempProxy), srcRect, dstPoint)) {
561                 return false;
562             }
563         }
564         return true;
565     }
566 
567     GrColorType srcColorType = src[0].colorType();
568     auto [allowedColorType, _] =
569             caps->supportedWritePixelsColorType(this->colorInfo().colorType(),
570                                                 dstProxy->backendFormat(),
571                                                 srcColorType);
572     bool flip = this->origin() == kBottomLeft_GrSurfaceOrigin;
573 
574     bool convertAll = premul              ||
575                       unpremul            ||
576                       needColorConversion ||
577                       flip                ||
578                       (srcColorType != allowedColorType);
579     bool mustBeTight = !caps->writePixelsRowBytesSupport();
580     size_t tmpSize = 0;
581     if (mustBeTight || convertAll) {
582         for (int i = 0; i < numLevels; ++i) {
583             if (convertAll || (mustBeTight && src[i].rowBytes() != src[i].info().minRowBytes())) {
584                 tmpSize += src[i].info().makeColorType(allowedColorType).minRowBytes()*
585                            src[i].height();
586             }
587         }
588     }
589 
590     auto tmpData = tmpSize ? SkData::MakeUninitialized(tmpSize) : nullptr;
591     void*    tmp = tmpSize ? tmpData->writable_data()           : nullptr;
592     SkAutoSTArray<15, GrMipLevel> srcLevels(numLevels);
593     bool ownAllStorage = true;
594     for (int i = 0; i < numLevels; ++i) {
595         if (convertAll || (mustBeTight && src[i].rowBytes() != src[i].info().minRowBytes())) {
596             GrImageInfo tmpInfo(allowedColorType,
597                                 this->colorInfo().alphaType(),
598                                 this->colorInfo().refColorSpace(),
599                                 src[i].dimensions());
600             auto tmpRB = tmpInfo.minRowBytes();
601             GrPixmap tmpPM(tmpInfo, tmp, tmpRB);
602             SkAssertResult(GrConvertPixels(tmpPM, src[i], flip));
603             srcLevels[i] = {tmpPM.addr(), tmpPM.rowBytes(), tmpData};
604             tmp = SkTAddOffset<void>(tmp, tmpRB*tmpPM.height());
605         } else {
606             srcLevels[i] = {src[i].addr(), src[i].rowBytes(), src[i].pixelStorage()};
607             ownAllStorage &= src[i].ownsPixels();
608         }
609     }
610     pt.fY = flip ? dstSurface->height() - pt.fY - src[0].height() : pt.fY;
611 
612     if (!dContext->priv().drawingManager()->newWritePixelsTask(
613                 sk_ref_sp(dstProxy),
614                 SkIRect::MakePtSize(pt, src[0].dimensions()),
615                 allowedColorType,
616                 this->colorInfo().colorType(),
617                 srcLevels.begin(),
618                 numLevels)) {
619         return false;
620     }
621     if (numLevels > 1) {
622         dstProxy->asTextureProxy()->markMipmapsClean();
623     }
624     if (!ownAllStorage) {
625         // If any pixmap doesn't own its pixels then we must flush so that the pixels are pushed to
626         // the GPU before we return.
627         dContext->priv().flushSurface(dstProxy);
628     }
629     return true;
630 }
631 
asyncRescaleAndReadPixels(GrDirectContext * dContext,const SkImageInfo & info,const SkIRect & srcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext callbackContext)632 void GrSurfaceContext::asyncRescaleAndReadPixels(GrDirectContext* dContext,
633                                                  const SkImageInfo& info,
634                                                  const SkIRect& srcRect,
635                                                  RescaleGamma rescaleGamma,
636                                                  RescaleMode rescaleMode,
637                                                  ReadPixelsCallback callback,
638                                                  ReadPixelsContext callbackContext) {
639     if (!dContext) {
640         callback(callbackContext, nullptr);
641         return;
642     }
643     auto rt = this->asRenderTargetProxy();
644     if (rt && rt->wrapsVkSecondaryCB()) {
645         callback(callbackContext, nullptr);
646         return;
647     }
648     if (rt && rt->framebufferOnly()) {
649         callback(callbackContext, nullptr);
650         return;
651     }
652     auto dstCT = SkColorTypeToGrColorType(info.colorType());
653     if (dstCT == GrColorType::kUnknown) {
654         callback(callbackContext, nullptr);
655         return;
656     }
657     bool needsRescale = srcRect.size() != info.dimensions()               ||
658                         this->origin() == kBottomLeft_GrSurfaceOrigin     ||
659                         this->colorInfo().alphaType() != info.alphaType() ||
660                         !SkColorSpace::Equals(this->colorInfo().colorSpace(), info.colorSpace());
661     auto colorTypeOfFinalContext = this->colorInfo().colorType();
662     auto backendFormatOfFinalContext = this->asSurfaceProxy()->backendFormat();
663     if (needsRescale) {
664         colorTypeOfFinalContext = dstCT;
665         backendFormatOfFinalContext =
666                 this->caps()->getDefaultBackendFormat(dstCT, GrRenderable::kYes);
667     }
668     auto readInfo = this->caps()->supportedReadPixelsColorType(colorTypeOfFinalContext,
669                                                                backendFormatOfFinalContext,
670                                                                dstCT);
671     // Fail if we can't read from the source surface's color type.
672     if (readInfo.fColorType == GrColorType::kUnknown) {
673         callback(callbackContext, nullptr);
674         return;
675     }
676     // Fail if read color type does not have all of dstCT's color channels and those missing color
677     // channels are in the src.
678     uint32_t dstChannels = GrColorTypeChannelFlags(dstCT);
679     uint32_t legalReadChannels = GrColorTypeChannelFlags(readInfo.fColorType);
680     uint32_t srcChannels = GrColorTypeChannelFlags(this->colorInfo().colorType());
681     if ((~legalReadChannels & dstChannels) & srcChannels) {
682         callback(callbackContext, nullptr);
683         return;
684     }
685 
686     std::unique_ptr<GrSurfaceFillContext> tempFC;
687     int x = srcRect.fLeft;
688     int y = srcRect.fTop;
689     if (needsRescale) {
690         tempFC = this->rescale(info, kTopLeft_GrSurfaceOrigin, srcRect, rescaleGamma, rescaleMode);
691         if (!tempFC) {
692             callback(callbackContext, nullptr);
693             return;
694         }
695         SkASSERT(SkColorSpace::Equals(tempFC->colorInfo().colorSpace(), info.colorSpace()));
696         SkASSERT(tempFC->origin() == kTopLeft_GrSurfaceOrigin);
697         x = y = 0;
698     }
699     auto srcCtx = tempFC ? tempFC.get() : this;
700     return srcCtx->asyncReadPixels(dContext,
701                                    SkIRect::MakePtSize({x, y}, info.dimensions()),
702                                    info.colorType(),
703                                    callback,
704                                    callbackContext);
705 }
706 
707 class GrSurfaceContext::AsyncReadResult : public SkImage::AsyncReadResult {
708 public:
AsyncReadResult(GrDirectContext::DirectContextID intendedRecipient)709     AsyncReadResult(GrDirectContext::DirectContextID intendedRecipient)
710         : fIntendedRecipient(intendedRecipient) {
711     }
712 
~AsyncReadResult()713     ~AsyncReadResult() override {
714         for (int i = 0; i < fPlanes.count(); ++i) {
715             fPlanes[i].releaseMappedBuffer(fIntendedRecipient);
716         }
717     }
718 
count() const719     int count() const override { return fPlanes.count(); }
data(int i) const720     const void* data(int i) const override { return fPlanes[i].data(); }
rowBytes(int i) const721     size_t rowBytes(int i) const override { return fPlanes[i].rowBytes(); }
722 
addTransferResult(const PixelTransferResult & result,SkISize dimensions,size_t rowBytes,GrClientMappedBufferManager * manager)723     bool addTransferResult(const PixelTransferResult& result,
724                            SkISize dimensions,
725                            size_t rowBytes,
726                            GrClientMappedBufferManager* manager) {
727         SkASSERT(!result.fTransferBuffer->isMapped());
728         const void* mappedData = result.fTransferBuffer->map();
729         if (!mappedData) {
730             return false;
731         }
732         if (result.fPixelConverter) {
733             size_t size = rowBytes*dimensions.height();
734             sk_sp<SkData> data = SkData::MakeUninitialized(size);
735             result.fPixelConverter(data->writable_data(), mappedData);
736             this->addCpuPlane(std::move(data), rowBytes);
737             result.fTransferBuffer->unmap();
738         } else {
739             manager->insert(result.fTransferBuffer);
740             this->addMappedPlane(mappedData, rowBytes, std::move(result.fTransferBuffer));
741         }
742         return true;
743     }
744 
addCpuPlane(sk_sp<SkData> data,size_t rowBytes)745     void addCpuPlane(sk_sp<SkData> data, size_t rowBytes) {
746         SkASSERT(data);
747         SkASSERT(rowBytes > 0);
748         fPlanes.emplace_back(std::move(data), rowBytes);
749     }
750 
751 private:
addMappedPlane(const void * data,size_t rowBytes,sk_sp<GrGpuBuffer> mappedBuffer)752     void addMappedPlane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> mappedBuffer) {
753         SkASSERT(data);
754         SkASSERT(rowBytes > 0);
755         SkASSERT(mappedBuffer);
756         SkASSERT(mappedBuffer->isMapped());
757         fPlanes.emplace_back(std::move(mappedBuffer), rowBytes);
758     }
759 
760     class Plane {
761     public:
Plane(sk_sp<GrGpuBuffer> buffer,size_t rowBytes)762         Plane(sk_sp<GrGpuBuffer> buffer, size_t rowBytes)
763                 : fMappedBuffer(std::move(buffer)), fRowBytes(rowBytes) {}
Plane(sk_sp<SkData> data,size_t rowBytes)764         Plane(sk_sp<SkData> data, size_t rowBytes) : fData(std::move(data)), fRowBytes(rowBytes) {}
765 
766         Plane(const Plane&) = delete;
767         Plane(Plane&&) = default;
768 
~Plane()769         ~Plane() { SkASSERT(!fMappedBuffer); }
770 
771         Plane& operator=(const Plane&) = delete;
772         Plane& operator=(Plane&&) = default;
773 
releaseMappedBuffer(GrDirectContext::DirectContextID intendedRecipient)774         void releaseMappedBuffer(GrDirectContext::DirectContextID intendedRecipient) {
775             if (fMappedBuffer) {
776                 GrClientMappedBufferManager::BufferFinishedMessageBus::Post(
777                         {std::move(fMappedBuffer), intendedRecipient});
778             }
779         }
780 
data() const781         const void* data() const {
782             if (fMappedBuffer) {
783                 SkASSERT(!fData);
784                 SkASSERT(fMappedBuffer->isMapped());
785                 return fMappedBuffer->map();
786             }
787             SkASSERT(fData);
788             return fData->data();
789         }
790 
rowBytes() const791         size_t rowBytes() const { return fRowBytes; }
792 
793     private:
794         sk_sp<SkData> fData;
795         sk_sp<GrGpuBuffer> fMappedBuffer;
796         size_t fRowBytes;
797     };
798     SkSTArray<3, Plane> fPlanes;
799     GrDirectContext::DirectContextID fIntendedRecipient;
800 };
801 
asyncReadPixels(GrDirectContext * dContext,const SkIRect & rect,SkColorType colorType,ReadPixelsCallback callback,ReadPixelsContext callbackContext)802 void GrSurfaceContext::asyncReadPixels(GrDirectContext* dContext,
803                                        const SkIRect& rect,
804                                        SkColorType colorType,
805                                        ReadPixelsCallback callback,
806                                        ReadPixelsContext callbackContext) {
807     SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
808     SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
809 
810     if (!dContext || this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
811         callback(callbackContext, nullptr);
812         return;
813     }
814 
815     auto mappedBufferManager = dContext->priv().clientMappedBufferManager();
816 
817     auto transferResult = this->transferPixels(SkColorTypeToGrColorType(colorType), rect);
818 
819     if (!transferResult.fTransferBuffer) {
820         auto ii = SkImageInfo::Make(rect.size(), colorType, this->colorInfo().alphaType(),
821                                     this->colorInfo().refColorSpace());
822         static const GrDirectContext::DirectContextID kInvalid;
823         auto result = std::make_unique<AsyncReadResult>(kInvalid);
824         GrPixmap pm = GrPixmap::Allocate(ii);
825         result->addCpuPlane(pm.pixelStorage(), pm.rowBytes());
826 
827         SkIPoint pt{rect.fLeft, rect.fTop};
828         if (!this->readPixels(dContext, pm, pt)) {
829             callback(callbackContext, nullptr);
830             return;
831         }
832         callback(callbackContext, std::move(result));
833         return;
834     }
835 
836     struct FinishContext {
837         ReadPixelsCallback* fClientCallback;
838         ReadPixelsContext fClientContext;
839         SkISize fSize;
840         SkColorType fColorType;
841         GrClientMappedBufferManager* fMappedBufferManager;
842         PixelTransferResult fTransferResult;
843     };
844     // Assumption is that the caller would like to flush. We could take a parameter or require an
845     // explicit flush from the caller. We'd have to have a way to defer attaching the finish
846     // callback to GrGpu until after the next flush that flushes our op list, though.
847     auto* finishContext = new FinishContext{callback,
848                                             callbackContext,
849                                             rect.size(),
850                                             colorType,
851                                             mappedBufferManager,
852                                             std::move(transferResult)};
853     auto finishCallback = [](GrGpuFinishedContext c) {
854         const auto* context = reinterpret_cast<const FinishContext*>(c);
855         auto manager = context->fMappedBufferManager;
856         auto result = std::make_unique<AsyncReadResult>(manager->owningDirectContext());
857         size_t rowBytes = context->fSize.width() * SkColorTypeBytesPerPixel(context->fColorType);
858         if (!result->addTransferResult(context->fTransferResult, context->fSize, rowBytes,
859                                        manager)) {
860             result.reset();
861         }
862         (*context->fClientCallback)(context->fClientContext, std::move(result));
863         delete context;
864     };
865     GrFlushInfo flushInfo;
866     flushInfo.fFinishedContext = finishContext;
867     flushInfo.fFinishedProc = finishCallback;
868 
869     dContext->priv().flushSurface(this->asSurfaceProxy(),
870                                   SkSurface::BackendSurfaceAccess::kNoAccess,
871                                   flushInfo);
872 }
873 
asyncRescaleAndReadPixelsYUV420(GrDirectContext * dContext,SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,SkISize dstSize,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext callbackContext)874 void GrSurfaceContext::asyncRescaleAndReadPixelsYUV420(GrDirectContext* dContext,
875                                                        SkYUVColorSpace yuvColorSpace,
876                                                        sk_sp<SkColorSpace> dstColorSpace,
877                                                        const SkIRect& srcRect,
878                                                        SkISize dstSize,
879                                                        RescaleGamma rescaleGamma,
880                                                        RescaleMode rescaleMode,
881                                                        ReadPixelsCallback callback,
882                                                        ReadPixelsContext callbackContext) {
883     SkASSERT(srcRect.fLeft >= 0 && srcRect.fRight <= this->width());
884     SkASSERT(srcRect.fTop >= 0 && srcRect.fBottom <= this->height());
885     SkASSERT(!dstSize.isZero());
886     SkASSERT((dstSize.width() % 2 == 0) && (dstSize.height() % 2 == 0));
887 
888     if (!dContext) {
889         callback(callbackContext, nullptr);
890         return;
891     }
892     auto rt = this->asRenderTargetProxy();
893     if (rt && rt->wrapsVkSecondaryCB()) {
894         callback(callbackContext, nullptr);
895         return;
896     }
897     if (rt && rt->framebufferOnly()) {
898         callback(callbackContext, nullptr);
899         return;
900     }
901     if (this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
902         callback(callbackContext, nullptr);
903         return;
904     }
905     int x = srcRect.fLeft;
906     int y = srcRect.fTop;
907     bool needsRescale = srcRect.size() != dstSize ||
908                         !SkColorSpace::Equals(this->colorInfo().colorSpace(), dstColorSpace.get());
909     GrSurfaceProxyView srcView = this->readSurfaceView();
910     if (needsRescale) {
911         auto info = SkImageInfo::Make(dstSize,
912                                       kRGBA_8888_SkColorType,
913                                       this->colorInfo().alphaType(),
914                                       dstColorSpace);
915         // TODO: Incorporate the YUV conversion into last pass of rescaling.
916         auto tempFC = this->rescale(info,
917                                     kTopLeft_GrSurfaceOrigin,
918                                     srcRect,
919                                     rescaleGamma,
920                                     rescaleMode);
921         if (!tempFC) {
922             callback(callbackContext, nullptr);
923             return;
924         }
925         SkASSERT(SkColorSpace::Equals(tempFC->colorInfo().colorSpace(), info.colorSpace()));
926         SkASSERT(tempFC->origin() == kTopLeft_GrSurfaceOrigin);
927         x = y = 0;
928         srcView = tempFC->readSurfaceView();
929     } else if (!srcView.asTextureProxy()) {
930         srcView = GrSurfaceProxyView::Copy(fContext,
931                                            std::move(srcView),
932                                            GrMipmapped::kNo,
933                                            srcRect,
934                                            SkBackingFit::kApprox,
935                                            SkBudgeted::kYes);
936         if (!srcView) {
937             // If we can't get a texture copy of the contents then give up.
938             callback(callbackContext, nullptr);
939             return;
940         }
941         SkASSERT(srcView.asTextureProxy());
942         x = y = 0;
943     }
944 
945     auto yInfo = SkImageInfo::MakeA8(dstSize);
946     auto yFC = GrSurfaceFillContext::MakeWithFallback(dContext, yInfo, SkBackingFit::kApprox);
947 
948     auto uvInfo = yInfo.makeWH(yInfo.width()/2, yInfo.height()/2);
949     auto uFC = GrSurfaceFillContext::MakeWithFallback(dContext, uvInfo, SkBackingFit::kApprox);
950     auto vFC = GrSurfaceFillContext::MakeWithFallback(dContext, uvInfo, SkBackingFit::kApprox);
951 
952     if (!yFC || !uFC || !vFC) {
953         callback(callbackContext, nullptr);
954         return;
955     }
956 
957     float baseM[20];
958     SkColorMatrix_RGB2YUV(yuvColorSpace, baseM);
959 
960     // TODO: Use one transfer buffer for all three planes to reduce map/unmap cost?
961 
962     auto texMatrix = SkMatrix::Translate(x, y);
963 
964     bool doSynchronousRead = !this->caps()->transferFromSurfaceToBufferSupport();
965     PixelTransferResult yTransfer, uTransfer, vTransfer;
966 
967     // This matrix generates (r,g,b,a) = (0, 0, 0, y)
968     float yM[20];
969     std::fill_n(yM, 15, 0.f);
970     std::copy_n(baseM + 0, 5, yM + 15);
971 
972     auto yFP = GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix);
973     yFP = GrColorMatrixFragmentProcessor::Make(std::move(yFP),
974                                                yM,
975                                                /*unpremulInput=*/false,
976                                                /*clampRGBOutput=*/true,
977                                                /*premulOutput=*/false);
978     yFC->fillWithFP(std::move(yFP));
979     if (!doSynchronousRead) {
980         yTransfer = yFC->transferPixels(GrColorType::kAlpha_8,
981                                         SkIRect::MakeSize(yFC->dimensions()));
982         if (!yTransfer.fTransferBuffer) {
983             callback(callbackContext, nullptr);
984             return;
985         }
986     }
987 
988     texMatrix.preScale(2.f, 2.f);
989     // This matrix generates (r,g,b,a) = (0, 0, 0, u)
990     float uM[20];
991     std::fill_n(uM, 15, 0.f);
992     std::copy_n(baseM + 5, 5, uM + 15);
993 
994     auto uFP = GrTextureEffect::Make(srcView,
995                                      this->colorInfo().alphaType(),
996                                      texMatrix,
997                                      GrSamplerState::Filter::kLinear);
998     uFP = GrColorMatrixFragmentProcessor::Make(std::move(uFP),
999                                                uM,
1000                                                /*unpremulInput=*/false,
1001                                                /*clampRGBOutput=*/true,
1002                                                /*premulOutput=*/false);
1003     uFC->fillWithFP(std::move(uFP));
1004     if (!doSynchronousRead) {
1005         uTransfer = uFC->transferPixels(GrColorType::kAlpha_8,
1006                                         SkIRect::MakeSize(uFC->dimensions()));
1007         if (!uTransfer.fTransferBuffer) {
1008             callback(callbackContext, nullptr);
1009             return;
1010         }
1011     }
1012 
1013     // This matrix generates (r,g,b,a) = (0, 0, 0, v)
1014     float vM[20];
1015     std::fill_n(vM, 15, 0.f);
1016     std::copy_n(baseM + 10, 5, vM + 15);
1017     auto vFP = GrTextureEffect::Make(std::move(srcView),
1018                                      this->colorInfo().alphaType(),
1019                                      texMatrix,
1020                                      GrSamplerState::Filter::kLinear);
1021     vFP = GrColorMatrixFragmentProcessor::Make(std::move(vFP),
1022                                                vM,
1023                                                /*unpremulInput=*/false,
1024                                                /*clampRGBOutput=*/true,
1025                                                /*premulOutput=*/false);
1026     vFC->fillWithFP(std::move(vFP));
1027 
1028     if (!doSynchronousRead) {
1029         vTransfer = vFC->transferPixels(GrColorType::kAlpha_8,
1030                                          SkIRect::MakeSize(vFC->dimensions()));
1031         if (!vTransfer.fTransferBuffer) {
1032             callback(callbackContext, nullptr);
1033             return;
1034         }
1035     }
1036 
1037     if (doSynchronousRead) {
1038         GrPixmap yPmp = GrPixmap::Allocate(yInfo);
1039         GrPixmap uPmp = GrPixmap::Allocate(uvInfo);
1040         GrPixmap vPmp = GrPixmap::Allocate(uvInfo);
1041         if (!yFC->readPixels(dContext, yPmp, {0, 0}) ||
1042             !uFC->readPixels(dContext, uPmp, {0, 0}) ||
1043             !vFC->readPixels(dContext, vPmp, {0, 0})) {
1044             callback(callbackContext, nullptr);
1045             return;
1046         }
1047         auto result = std::make_unique<AsyncReadResult>(dContext->directContextID());
1048         result->addCpuPlane(yPmp.pixelStorage(), yPmp.rowBytes());
1049         result->addCpuPlane(uPmp.pixelStorage(), uPmp.rowBytes());
1050         result->addCpuPlane(vPmp.pixelStorage(), vPmp.rowBytes());
1051         callback(callbackContext, std::move(result));
1052         return;
1053     }
1054 
1055     struct FinishContext {
1056         ReadPixelsCallback* fClientCallback;
1057         ReadPixelsContext fClientContext;
1058         GrClientMappedBufferManager* fMappedBufferManager;
1059         SkISize fSize;
1060         PixelTransferResult fYTransfer;
1061         PixelTransferResult fUTransfer;
1062         PixelTransferResult fVTransfer;
1063     };
1064     // Assumption is that the caller would like to flush. We could take a parameter or require an
1065     // explicit flush from the caller. We'd have to have a way to defer attaching the finish
1066     // callback to GrGpu until after the next flush that flushes our op list, though.
1067     auto* finishContext = new FinishContext{callback,
1068                                             callbackContext,
1069                                             dContext->priv().clientMappedBufferManager(),
1070                                             dstSize,
1071                                             std::move(yTransfer),
1072                                             std::move(uTransfer),
1073                                             std::move(vTransfer)};
1074     auto finishCallback = [](GrGpuFinishedContext c) {
1075         const auto* context = reinterpret_cast<const FinishContext*>(c);
1076         auto manager = context->fMappedBufferManager;
1077         auto result = std::make_unique<AsyncReadResult>(manager->owningDirectContext());
1078         size_t rowBytes = SkToSizeT(context->fSize.width());
1079         if (!result->addTransferResult(context->fYTransfer, context->fSize, rowBytes, manager)) {
1080             (*context->fClientCallback)(context->fClientContext, nullptr);
1081             delete context;
1082             return;
1083         }
1084         rowBytes /= 2;
1085         SkISize uvSize = {context->fSize.width() / 2, context->fSize.height() / 2};
1086         if (!result->addTransferResult(context->fUTransfer, uvSize, rowBytes, manager)) {
1087             (*context->fClientCallback)(context->fClientContext, nullptr);
1088             delete context;
1089             return;
1090         }
1091         if (!result->addTransferResult(context->fVTransfer, uvSize, rowBytes, manager)) {
1092             (*context->fClientCallback)(context->fClientContext, nullptr);
1093             delete context;
1094             return;
1095         }
1096         (*context->fClientCallback)(context->fClientContext, std::move(result));
1097         delete context;
1098     };
1099     GrFlushInfo flushInfo;
1100     flushInfo.fFinishedContext = finishContext;
1101     flushInfo.fFinishedProc = finishCallback;
1102     dContext->priv().flushSurface(this->asSurfaceProxy(),
1103                                   SkSurface::BackendSurfaceAccess::kNoAccess,
1104                                   flushInfo);
1105 }
1106 
copy(sk_sp<GrSurfaceProxy> src,SkIRect srcRect,SkIPoint dstPoint)1107 sk_sp<GrRenderTask> GrSurfaceContext::copy(sk_sp<GrSurfaceProxy> src,
1108                                            SkIRect srcRect,
1109                                            SkIPoint dstPoint) {
1110     ASSERT_SINGLE_OWNER
1111     RETURN_NULLPTR_IF_ABANDONED
1112     SkDEBUGCODE(this->validate();)
1113     GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrSurfaceContextPriv::copy");
1114 
1115     const GrCaps* caps = fContext->priv().caps();
1116 
1117     SkASSERT(src->backendFormat().textureType() != GrTextureType::kExternal);
1118     SkASSERT(src->backendFormat() == this->asSurfaceProxy()->backendFormat());
1119 
1120     if (this->asSurfaceProxy()->framebufferOnly()) {
1121         return nullptr;
1122     }
1123 
1124     if (!caps->canCopySurface(this->asSurfaceProxy(), src.get(), srcRect, dstPoint)) {
1125         return nullptr;
1126     }
1127 
1128     return this->drawingManager()->newCopyRenderTask(std::move(src),
1129                                                      srcRect,
1130                                                      this->asSurfaceProxyRef(),
1131                                                      dstPoint,
1132                                                      this->origin());
1133 }
1134 
rescale(const GrImageInfo & info,GrSurfaceOrigin origin,SkIRect srcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode)1135 std::unique_ptr<GrSurfaceFillContext> GrSurfaceContext::rescale(const GrImageInfo& info,
1136                                                                 GrSurfaceOrigin origin,
1137                                                                 SkIRect srcRect,
1138                                                                 RescaleGamma rescaleGamma,
1139                                                                 RescaleMode rescaleMode) {
1140     auto sfc = GrSurfaceFillContext::MakeWithFallback(fContext,
1141                                                       info,
1142                                                       SkBackingFit::kExact,
1143                                                       1,
1144                                                       GrMipmapped::kNo,
1145                                                       this->asSurfaceProxy()->isProtected(),
1146                                                       origin);
1147     if (!sfc || !this->rescaleInto(sfc.get(),
1148                                    SkIRect::MakeSize(sfc->dimensions()),
1149                                    srcRect,
1150                                    rescaleGamma,
1151                                    rescaleMode)) {
1152         return nullptr;
1153     }
1154     return sfc;
1155 }
1156 
rescaleInto(GrSurfaceFillContext * dst,SkIRect dstRect,SkIRect srcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode)1157 bool GrSurfaceContext::rescaleInto(GrSurfaceFillContext* dst,
1158                                    SkIRect dstRect,
1159                                    SkIRect srcRect,
1160                                    RescaleGamma rescaleGamma,
1161                                    RescaleMode rescaleMode) {
1162     SkASSERT(dst);
1163     if (!SkIRect::MakeSize(dst->dimensions()).contains((dstRect))) {
1164         return false;
1165     }
1166 
1167     auto rtProxy = this->asRenderTargetProxy();
1168     if (rtProxy && rtProxy->wrapsVkSecondaryCB()) {
1169         return false;
1170     }
1171 
1172     if (this->asSurfaceProxy()->framebufferOnly()) {
1173         return false;
1174     }
1175 
1176     GrSurfaceProxyView texView = this->readSurfaceView();
1177     if (!texView.asTextureProxy()) {
1178         // TODO: If copying supported specifying a renderable copy then we could return the copy
1179         // when there are no other conversions.
1180         texView = GrSurfaceProxyView::Copy(fContext, std::move(texView), GrMipmapped::kNo, srcRect,
1181                                            SkBackingFit::kApprox, SkBudgeted::kNo);
1182         if (!texView) {
1183             return false;
1184         }
1185         SkASSERT(texView.asTextureProxy());
1186         srcRect = SkIRect::MakeSize(srcRect.size());
1187     }
1188 
1189     SkISize finalSize = dstRect.size();
1190     if (finalSize == srcRect.size()) {
1191         rescaleGamma = RescaleGamma::kSrc;
1192         rescaleMode = RescaleMode::kNearest;
1193     }
1194 
1195     // Within a rescaling pass A is the input (if not null) and B is the output. At the end of the
1196     // pass B is moved to A. If 'this' is the input on the first pass then tempA is null.
1197     std::unique_ptr<GrSurfaceFillContext> tempA;
1198     std::unique_ptr<GrSurfaceFillContext> tempB;
1199 
1200     // Assume we should ignore the rescale linear request if the surface has no color space since
1201     // it's unclear how we'd linearize from an unknown color space.
1202     if (rescaleGamma == RescaleGamma::kLinear && this->colorInfo().colorSpace() &&
1203         !this->colorInfo().colorSpace()->gammaIsLinear()) {
1204         auto cs = this->colorInfo().colorSpace()->makeLinearGamma();
1205         // We'll fall back to kRGBA_8888 if half float not supported.
1206         GrImageInfo ii(GrColorType::kRGBA_F16,
1207                        dst->colorInfo().alphaType(),
1208                        std::move(cs),
1209                        srcRect.size());
1210         auto linearRTC = GrSurfaceFillContext::MakeWithFallback(fContext,
1211                                                                 std::move(ii),
1212                                                                 SkBackingFit::kApprox,
1213                                                                 1,
1214                                                                 GrMipmapped::kNo,
1215                                                                 GrProtected::kNo,
1216                                                                 dst->origin());
1217         if (!linearRTC) {
1218             return false;
1219         }
1220         auto fp = GrTextureEffect::Make(std::move(texView),
1221                                         this->colorInfo().alphaType(),
1222                                         SkMatrix::Translate(srcRect.topLeft()),
1223                                         GrSamplerState::Filter::kNearest,
1224                                         GrSamplerState::MipmapMode::kNone);
1225         fp = GrColorSpaceXformEffect::Make(std::move(fp),
1226                                            this->colorInfo(),
1227                                            linearRTC->colorInfo());
1228         linearRTC->fillWithFP(std::move(fp));
1229         texView = linearRTC->readSurfaceView();
1230         SkASSERT(texView.asTextureProxy());
1231         tempA = std::move(linearRTC);
1232         srcRect = SkIRect::MakeSize(srcRect.size());
1233     }
1234 
1235     do {
1236         SkISize nextDims = finalSize;
1237         if (rescaleMode != RescaleMode::kNearest) {
1238             if (srcRect.width() > finalSize.width()) {
1239                 nextDims.fWidth = std::max((srcRect.width() + 1)/2, finalSize.width());
1240             } else if (srcRect.width() < finalSize.width()) {
1241                 nextDims.fWidth = std::min(srcRect.width()*2, finalSize.width());
1242             }
1243             if (srcRect.height() > finalSize.height()) {
1244                 nextDims.fHeight = std::max((srcRect.height() + 1)/2, finalSize.height());
1245             } else if (srcRect.height() < finalSize.height()) {
1246                 nextDims.fHeight = std::min(srcRect.height()*2, finalSize.height());
1247             }
1248         }
1249         auto input = tempA ? tempA.get() : this;
1250         sk_sp<GrColorSpaceXform> xform;
1251         GrSurfaceFillContext* stepDst;
1252         SkIRect stepDstRect;
1253         if (nextDims == finalSize) {
1254             stepDst = dst;
1255             stepDstRect = dstRect;
1256             xform = GrColorSpaceXform::Make(input->colorInfo(), dst->colorInfo());
1257         } else {
1258             GrImageInfo nextInfo(input->colorInfo(), nextDims);
1259             tempB = GrSurfaceFillContext::MakeWithFallback(fContext,
1260                                                            nextInfo,
1261                                                            SkBackingFit::kApprox);
1262             if (!tempB) {
1263                 return false;
1264             }
1265             stepDst = tempB.get();
1266             stepDstRect = SkIRect::MakeSize(tempB->dimensions());
1267         }
1268         std::unique_ptr<GrFragmentProcessor> fp;
1269         if (rescaleMode == RescaleMode::kRepeatedCubic) {
1270             auto dir = GrBicubicEffect::Direction::kXY;
1271             if (nextDims.width() == srcRect.width()) {
1272                 dir = GrBicubicEffect::Direction::kY;
1273             } else if (nextDims.height() == srcRect.height()) {
1274                 dir = GrBicubicEffect::Direction::kX;
1275             }
1276             static constexpr auto kWM     = GrSamplerState::WrapMode::kClamp;
1277             static constexpr auto kKernel = GrBicubicEffect::gCatmullRom;
1278             fp = GrBicubicEffect::MakeSubset(std::move(texView),
1279                                              input->colorInfo().alphaType(),
1280                                              SkMatrix::I(),
1281                                              kWM,
1282                                              kWM,
1283                                              SkRect::Make(srcRect),
1284                                              kKernel,
1285                                              dir,
1286                                              *this->caps());
1287         } else {
1288             auto filter = rescaleMode == RescaleMode::kNearest ? GrSamplerState::Filter::kNearest
1289                                                                : GrSamplerState::Filter::kLinear;
1290             auto srcRectF = SkRect::Make(srcRect);
1291             fp = GrTextureEffect::MakeSubset(std::move(texView),
1292                                              this->colorInfo().alphaType(),
1293                                              SkMatrix::I(),
1294                                              {filter, GrSamplerState::MipmapMode::kNone},
1295                                              srcRectF,
1296                                              srcRectF,
1297                                              *this->caps());
1298         }
1299         if (xform) {
1300             fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(xform));
1301         }
1302         stepDst->fillRectToRectWithFP(srcRect, stepDstRect, std::move(fp));
1303         texView = stepDst->readSurfaceView();
1304         tempA = std::move(tempB);
1305         srcRect = SkIRect::MakeSize(nextDims);
1306     } while (srcRect.size() != finalSize);
1307     return true;
1308 }
1309 
transferPixels(GrColorType dstCT,const SkIRect & rect)1310 GrSurfaceContext::PixelTransferResult GrSurfaceContext::transferPixels(GrColorType dstCT,
1311                                                                        const SkIRect& rect) {
1312     SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
1313     SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
1314     auto direct = fContext->asDirectContext();
1315     if (!direct) {
1316         return {};
1317     }
1318     auto rtProxy = this->asRenderTargetProxy();
1319     if (rtProxy && rtProxy->wrapsVkSecondaryCB()) {
1320         return {};
1321     }
1322 
1323     auto proxy = this->asSurfaceProxy();
1324     auto supportedRead = this->caps()->supportedReadPixelsColorType(this->colorInfo().colorType(),
1325                                                                     proxy->backendFormat(), dstCT);
1326     // Fail if read color type does not have all of dstCT's color channels and those missing color
1327     // channels are in the src.
1328     uint32_t dstChannels = GrColorTypeChannelFlags(dstCT);
1329     uint32_t legalReadChannels = GrColorTypeChannelFlags(supportedRead.fColorType);
1330     uint32_t srcChannels = GrColorTypeChannelFlags(this->colorInfo().colorType());
1331     if ((~legalReadChannels & dstChannels) & srcChannels) {
1332         return {};
1333     }
1334 
1335     if (!this->caps()->transferFromSurfaceToBufferSupport() ||
1336         !supportedRead.fOffsetAlignmentForTransferBuffer) {
1337         return {};
1338     }
1339 
1340     size_t rowBytes = GrColorTypeBytesPerPixel(supportedRead.fColorType) * rect.width();
1341     size_t size = rowBytes * rect.height();
1342     // By using kStream_GrAccessPattern here, we are not able to cache and reuse the buffer for
1343     // multiple reads. Switching to kDynamic_GrAccessPattern would allow for this, however doing
1344     // so causes a crash in a chromium test. See skbug.com/11297
1345     auto buffer = direct->priv().resourceProvider()->createBuffer(
1346             size, GrGpuBufferType::kXferGpuToCpu, GrAccessPattern::kStream_GrAccessPattern);
1347     if (!buffer) {
1348         return {};
1349     }
1350     auto srcRect = rect;
1351     bool flip = this->origin() == kBottomLeft_GrSurfaceOrigin;
1352     if (flip) {
1353         srcRect = SkIRect::MakeLTRB(rect.fLeft, this->height() - rect.fBottom, rect.fRight,
1354                                     this->height() - rect.fTop);
1355     }
1356     this->drawingManager()->newTransferFromRenderTask(this->asSurfaceProxyRef(), srcRect,
1357                                                       this->colorInfo().colorType(),
1358                                                       supportedRead.fColorType, buffer, 0);
1359     PixelTransferResult result;
1360     result.fTransferBuffer = std::move(buffer);
1361     auto at = this->colorInfo().alphaType();
1362     if (supportedRead.fColorType != dstCT || flip) {
1363         result.fPixelConverter = [w = rect.width(), h = rect.height(), dstCT, supportedRead, at](
1364                 void* dst, const void* src) {
1365             GrImageInfo srcInfo(supportedRead.fColorType, at, nullptr, w, h);
1366             GrImageInfo dstInfo(dstCT,                    at, nullptr, w, h);
1367             GrConvertPixels( GrPixmap(dstInfo, dst, dstInfo.minRowBytes()),
1368                             GrCPixmap(srcInfo, src, srcInfo.minRowBytes()));
1369         };
1370     }
1371     return result;
1372 }
1373 
1374 #ifdef SK_DEBUG
validate() const1375 void GrSurfaceContext::validate() const {
1376     SkASSERT(fReadView.proxy());
1377     fReadView.proxy()->validate(fContext);
1378     if (this->colorInfo().colorType() != GrColorType::kUnknown) {
1379         SkASSERT(fContext->priv().caps()->areColorTypeAndFormatCompatible(
1380                 this->colorInfo().colorType(), fReadView.proxy()->backendFormat()));
1381     }
1382     this->onValidate();
1383 }
1384 #endif
1385