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