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