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