blob: 077d88c8bfc7b199766dd10ce883391ffc8ec1b3 [file] [log] [blame]
Brian Osman45580d32016-11-23 09:37:01 -05001/*
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
Greg Daniel46cfbc62019-06-07 11:43:30 -04008#include "src/gpu/GrSurfaceContext.h"
9
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
11
Robert Phillipsb7bfbc22020-07-01 12:55:01 -040012#include "include/gpu/GrDirectContext.h"
13#include "include/gpu/GrRecordingContext.h"
Greg Daniel6eb8c242019-06-05 10:22:24 -040014#include "src/core/SkAutoPixmapStorage.h"
Brian Salomon63a0a752020-06-26 13:32:09 -040015#include "src/core/SkYUVMath.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040016#include "src/gpu/GrAuditTrail.h"
Brian Salomon1c86b632020-12-11 12:36:01 -050017#include "src/gpu/GrColorSpaceXform.h"
Brian Salomonf30b1c12019-06-20 12:25:02 -040018#include "src/gpu/GrDataUtils.h"
Adlai Hollera0693042020-10-14 11:23:11 -040019#include "src/gpu/GrDirectContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/gpu/GrDrawingManager.h"
Greg Daniel6eb8c242019-06-05 10:22:24 -040021#include "src/gpu/GrGpu.h"
Brian Salomonf2ebdd92019-09-30 12:15:30 -040022#include "src/gpu/GrImageInfo.h"
Robert Phillipse19babf2020-04-06 13:57:30 -040023#include "src/gpu/GrProxyProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/gpu/GrRecordingContextPriv.h"
Brian Salomoneebe7352020-12-09 16:37:04 -050025#include "src/gpu/GrSurfaceDrawContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050026#include "src/gpu/SkGr.h"
Brian Salomone9ad9982019-07-22 16:17:41 -040027#include "src/gpu/effects/GrBicubicEffect.h"
Brian Salomon63a0a752020-06-26 13:32:09 -040028#include "src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h"
Brian Osman45580d32016-11-23 09:37:01 -050029
Adlai Holler33dbd652020-06-01 12:35:42 -040030#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(this->singleOwner())
Robert Phillips9eb00022020-06-30 15:30:12 -040031#define RETURN_FALSE_IF_ABANDONED if (this->fContext->abandoned()) { return false; }
Brian Osman45580d32016-11-23 09:37:01 -050032
Greg Danielbfa19c42019-12-19 16:41:40 -050033std::unique_ptr<GrSurfaceContext> GrSurfaceContext::Make(GrRecordingContext* context,
Greg Daniel3912a4b2020-01-14 09:56:04 -050034 GrSurfaceProxyView readView,
Brian Salomon14f99fc2020-12-07 12:19:47 -050035 const GrColorInfo& info) {
Greg Daniele20fcad2020-01-08 11:52:34 -050036 // It is probably not necessary to check if the context is abandoned here since uses of the
37 // GrSurfaceContext which need the context will mostly likely fail later on without an issue.
38 // However having this hear adds some reassurance in case there is a path doesn't handle an
39 // abandoned context correctly. It also lets us early out of some extra work.
Robert Phillips9eb00022020-06-30 15:30:12 -040040 if (context->abandoned()) {
Greg Daniele20fcad2020-01-08 11:52:34 -050041 return nullptr;
42 }
Greg Daniel3912a4b2020-01-14 09:56:04 -050043 GrSurfaceProxy* proxy = readView.proxy();
Greg Danielbfa19c42019-12-19 16:41:40 -050044 SkASSERT(proxy && proxy->asTextureProxy());
45
Greg Danielbfa19c42019-12-19 16:41:40 -050046 std::unique_ptr<GrSurfaceContext> surfaceContext;
Greg Daniel3912a4b2020-01-14 09:56:04 -050047 if (proxy->asRenderTargetProxy()) {
Brian Salomon8afde5f2020-04-01 16:22:00 -040048 // Will we ever want a swizzle that is not the default write swizzle for the format and
Greg Danielbfa19c42019-12-19 16:41:40 -050049 // colorType here? If so we will need to manually pass that in.
Brian Salomonc5243782020-04-02 12:50:34 -040050 GrSwizzle writeSwizzle;
Brian Salomon14f99fc2020-12-07 12:19:47 -050051 if (info.colorType() != GrColorType::kUnknown) {
52 writeSwizzle = context->priv().caps()->getWriteSwizzle(proxy->backendFormat(),
53 info.colorType());
Brian Salomonc5243782020-04-02 12:50:34 -040054 }
Brian Salomon8afde5f2020-04-01 16:22:00 -040055 GrSurfaceProxyView writeView(readView.refProxy(), readView.origin(), writeSwizzle);
Brian Salomon590f5672020-12-16 11:44:47 -050056 if (info.alphaType() == kPremul_SkAlphaType || info.alphaType() == kOpaque_SkAlphaType) {
57 surfaceContext = std::make_unique<GrSurfaceDrawContext>(context,
58 std::move(readView),
59 std::move(writeView),
60 info.colorType(),
61 info.refColorSpace(),
62 /*surface props*/ nullptr);
63 } else {
64 surfaceContext = std::make_unique<GrSurfaceFillContext>(context,
65 std::move(readView),
66 std::move(writeView),
67 info);
68 }
Greg Danielbfa19c42019-12-19 16:41:40 -050069 } else {
Brian Salomon14f99fc2020-12-07 12:19:47 -050070 surfaceContext = std::make_unique<GrSurfaceContext>(context, std::move(readView), info);
Greg Danielbfa19c42019-12-19 16:41:40 -050071 }
Robert Phillips07f0e412020-01-17 15:20:00 -050072 SkDEBUGCODE(surfaceContext->validate();)
Greg Danielbfa19c42019-12-19 16:41:40 -050073 return surfaceContext;
74}
75
Brian Salomona56a7462020-02-07 14:17:25 -050076std::unique_ptr<GrSurfaceContext> GrSurfaceContext::Make(GrRecordingContext* context,
Brian Salomon14f99fc2020-12-07 12:19:47 -050077 const GrImageInfo& info,
Brian Salomona56a7462020-02-07 14:17:25 -050078 const GrBackendFormat& format,
Brian Salomona56a7462020-02-07 14:17:25 -050079 SkBackingFit fit,
Brian Salomon14f99fc2020-12-07 12:19:47 -050080 GrSurfaceOrigin origin,
81 GrRenderable renderable,
82 int sampleCount,
83 GrMipmapped mipmapped,
84 GrProtected isProtected,
Brian Salomona56a7462020-02-07 14:17:25 -050085 SkBudgeted budgeted) {
Brian Salomon14f99fc2020-12-07 12:19:47 -050086 SkASSERT(context);
87 SkASSERT(renderable == GrRenderable::kYes || sampleCount == 1);
88 if (context->abandoned()) {
89 return nullptr;
Brian Salomond005b692020-04-01 15:47:05 -040090 }
Brian Salomon14f99fc2020-12-07 12:19:47 -050091 sk_sp<GrTextureProxy> proxy = context->priv().proxyProvider()->createProxy(format,
92 info.dimensions(),
93 renderable,
94 sampleCount,
95 mipmapped,
96 fit,
97 budgeted,
98 isProtected);
Greg Danielbfa19c42019-12-19 16:41:40 -050099 if (!proxy) {
100 return nullptr;
101 }
102
Brian Salomon14f99fc2020-12-07 12:19:47 -0500103 GrSwizzle swizzle;
104 if (info.colorType() != GrColorType::kUnknown &&
105 !context->priv().caps()->isFormatCompressed(format)) {
106 swizzle = context->priv().caps()->getReadSwizzle(format, info.colorType());
107 }
108
Greg Daniel3912a4b2020-01-14 09:56:04 -0500109 GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
Brian Salomon14f99fc2020-12-07 12:19:47 -0500110 return GrSurfaceContext::Make(context, std::move(view), info.colorInfo());
111}
112
113std::unique_ptr<GrSurfaceContext> GrSurfaceContext::Make(GrRecordingContext* context,
114 const GrImageInfo& info,
115 SkBackingFit fit,
116 GrSurfaceOrigin origin,
117 GrRenderable renderable,
118 int sampleCount,
119 GrMipmapped mipmapped,
120 GrProtected isProtected,
121 SkBudgeted budgeted) {
122 GrBackendFormat format = context->priv().caps()->getDefaultBackendFormat(info.colorType(),
123 renderable);
124 return Make(context,
125 info,
126 format,
127 fit,
128 origin,
129 renderable,
130 sampleCount,
131 mipmapped,
132 isProtected,
133 budgeted);
Greg Danielbfa19c42019-12-19 16:41:40 -0500134}
135
Greg Danielf41b2bd2019-08-22 16:19:24 -0400136// In MDB mode the reffing of the 'getLastOpsTask' call's result allows in-progress
137// GrOpsTasks to be picked up and added to by renderTargetContexts lower in the call
138// stack. When this occurs with a closed GrOpsTask, a new one will be allocated
Brian Salomon1aa1f5f2020-12-11 17:25:17 -0500139// when the surfaceDrawContext attempts to use it (via getOpsTask).
Robert Phillips69893702019-02-22 11:16:30 -0500140GrSurfaceContext::GrSurfaceContext(GrRecordingContext* context,
Greg Daniel3912a4b2020-01-14 09:56:04 -0500141 GrSurfaceProxyView readView,
Brian Salomon14f99fc2020-12-07 12:19:47 -0500142 const GrColorInfo& info)
143 : fContext(context), fReadView(std::move(readView)), fColorInfo(info) {
Robert Phillips9eb00022020-06-30 15:30:12 -0400144 SkASSERT(!context->abandoned());
Greg Daniele20fcad2020-01-08 11:52:34 -0500145}
Robert Phillipsa90aa2b2017-04-10 08:19:26 -0400146
Brian Salomon4d2d6f42019-07-26 14:15:11 -0400147const GrCaps* GrSurfaceContext::caps() const { return fContext->priv().caps(); }
148
Robert Phillips0d075de2019-03-04 11:08:13 -0500149GrAuditTrail* GrSurfaceContext::auditTrail() {
150 return fContext->priv().auditTrail();
151}
152
153GrDrawingManager* GrSurfaceContext::drawingManager() {
154 return fContext->priv().drawingManager();
155}
156
157const GrDrawingManager* GrSurfaceContext::drawingManager() const {
158 return fContext->priv().drawingManager();
159}
160
161#ifdef SK_DEBUG
Brian Salomon70fe17e2020-11-30 14:33:58 -0500162GrSingleOwner* GrSurfaceContext::singleOwner() const { return fContext->priv().singleOwner(); }
Robert Phillips0d075de2019-03-04 11:08:13 -0500163#endif
Greg Daniel6eb8c242019-06-05 10:22:24 -0400164
Brian Salomondd4087d2020-12-23 20:36:44 -0500165static bool alpha_types_compatible(SkAlphaType srcAlphaType, SkAlphaType dstAlphaType) {
166 // If both alpha types are kUnknown things make sense. If not, it's too underspecified.
167 return (srcAlphaType == kUnknown_SkAlphaType) == (dstAlphaType == kUnknown_SkAlphaType);
168}
169
170bool GrSurfaceContext::readPixels(GrDirectContext* dContext, GrPixmap dst, SkIPoint pt) {
Brian Salomon1d435302019-07-01 13:05:28 -0400171 ASSERT_SINGLE_OWNER
172 RETURN_FALSE_IF_ABANDONED
173 SkDEBUGCODE(this->validate();)
174 GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrSurfaceContext::readPixels");
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400175 if (!fContext->priv().matches(dContext)) {
Greg Daniel6eb8c242019-06-05 10:22:24 -0400176 return false;
177 }
Brian Salomondd4087d2020-12-23 20:36:44 -0500178 dst = dst.clip(this->dimensions(), &pt);
179 if (!dst.hasPixels()) {
Brian Salomon1d435302019-07-01 13:05:28 -0400180 return false;
181 }
Brian Salomondd4087d2020-12-23 20:36:44 -0500182 if (!alpha_types_compatible(this->colorInfo().alphaType(), dst.alphaType())) {
Brian Salomon1d435302019-07-01 13:05:28 -0400183 return false;
184 }
Brian Salomondd4087d2020-12-23 20:36:44 -0500185 // We allow unknown alpha types but only if both src and dst are unknown. Otherwise, it's too
186 // weird to reason about what should be expected.
Greg Daniel6eb8c242019-06-05 10:22:24 -0400187
188 GrSurfaceProxy* srcProxy = this->asSurfaceProxy();
189
Stephen White3c0a50f2020-01-16 18:19:54 -0500190 if (srcProxy->framebufferOnly()) {
191 return false;
192 }
193
Greg Daniel6eb8c242019-06-05 10:22:24 -0400194 // MDB TODO: delay this instantiation until later in the method
Adlai Hollerc95b5892020-08-11 12:02:22 -0400195 if (!srcProxy->instantiate(dContext->priv().resourceProvider())) {
Greg Daniel6eb8c242019-06-05 10:22:24 -0400196 return false;
197 }
198
199 GrSurface* srcSurface = srcProxy->peekSurface();
200
Brian Salomondd4087d2020-12-23 20:36:44 -0500201 SkColorSpaceXformSteps::Flags flags =
202 SkColorSpaceXformSteps{this->colorInfo(), dst.info()}.flags;
Mike Klein7321e6a2019-12-03 11:08:40 -0600203 bool unpremul = flags.unpremul,
204 needColorConversion = flags.linearize || flags.gamut_transform || flags.encode,
205 premul = flags.premul;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400206
Adlai Hollerc95b5892020-08-11 12:02:22 -0400207 const GrCaps* caps = dContext->priv().caps();
Robert Phillips07f0e412020-01-17 15:20:00 -0500208 bool srcIsCompressed = caps->isFormatCompressed(srcSurface->backendFormat());
Greg Daniel6eb8c242019-06-05 10:22:24 -0400209 // This is the getImageData equivalent to the canvas2D putImageData fast path. We probably don't
210 // care so much about getImageData performance. However, in order to ensure putImageData/
211 // getImageData in "legacy" mode are round-trippable we use the GPU to do the complementary
212 // unpremul step to writeSurfacePixels's premul step (which is determined empirically in
213 // fContext->vaildaPMUPMConversionExists()).
Greg Daniel0258c902019-08-01 13:08:33 -0400214 GrBackendFormat defaultRGBAFormat = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
215 GrRenderable::kYes);
Greg Danielc71c7962020-01-14 16:44:18 -0500216 GrColorType srcColorType = this->colorInfo().colorType();
Brian Salomon1d435302019-07-01 13:05:28 -0400217 bool canvas2DFastPath = unpremul && !needColorConversion &&
Brian Salomondd4087d2020-12-23 20:36:44 -0500218 (GrColorType::kRGBA_8888 == dst.colorType() ||
219 GrColorType::kBGRA_8888 == dst.colorType()) &&
Brian Salomon1d435302019-07-01 13:05:28 -0400220 SkToBool(srcProxy->asTextureProxy()) &&
Greg Danielc71c7962020-01-14 16:44:18 -0500221 (srcColorType == GrColorType::kRGBA_8888 ||
222 srcColorType == GrColorType::kBGRA_8888) &&
Greg Daniel0258c902019-08-01 13:08:33 -0400223 defaultRGBAFormat.isValid() &&
Adlai Hollerc95b5892020-08-11 12:02:22 -0400224 dContext->priv().validPMUPMConversionExists();
Greg Daniel6eb8c242019-06-05 10:22:24 -0400225
Emircan Uysaler23ca4e72019-06-24 10:53:09 -0400226 auto readFlag = caps->surfaceSupportsReadPixels(srcSurface);
Brian Salomondc0710f2019-07-01 14:59:32 -0400227 if (readFlag == GrCaps::SurfaceReadPixelsSupport::kUnsupported) {
Emircan Uysaler23ca4e72019-06-24 10:53:09 -0400228 return false;
229 }
230
Brian Salomondc0710f2019-07-01 14:59:32 -0400231 if (readFlag == GrCaps::SurfaceReadPixelsSupport::kCopyToTexture2D || canvas2DFastPath) {
Brian Salomon72c7b982020-10-06 10:07:38 -0400232 std::unique_ptr<GrSurfaceContext> tempCtx;
233 if (this->asTextureProxy()) {
234 GrColorType colorType = (canvas2DFastPath || srcIsCompressed)
235 ? GrColorType::kRGBA_8888
236 : this->colorInfo().colorType();
Brian Salomondd4087d2020-12-23 20:36:44 -0500237 SkAlphaType alphaType = canvas2DFastPath ? dst.alphaType()
Brian Salomon590f5672020-12-16 11:44:47 -0500238 : this->colorInfo().alphaType();
239 GrImageInfo tempInfo(colorType,
240 alphaType,
241 this->colorInfo().refColorSpace(),
Brian Salomondd4087d2020-12-23 20:36:44 -0500242 dst.dimensions());
Brian Salomon590f5672020-12-16 11:44:47 -0500243 auto sfc = GrSurfaceFillContext::Make(dContext, tempInfo, SkBackingFit::kApprox);
244 if (!sfc) {
Brian Salomon72c7b982020-10-06 10:07:38 -0400245 return false;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400246 }
Brian Salomon72c7b982020-10-06 10:07:38 -0400247
248 std::unique_ptr<GrFragmentProcessor> fp;
249 if (canvas2DFastPath) {
250 fp = dContext->priv().createPMToUPMEffect(GrTextureEffect::Make(
251 this->readSurfaceView(), this->colorInfo().alphaType()));
Brian Salomondd4087d2020-12-23 20:36:44 -0500252 if (dst.colorType() == GrColorType::kBGRA_8888) {
Brian Salomon72c7b982020-10-06 10:07:38 -0400253 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
Brian Salomondd4087d2020-12-23 20:36:44 -0500254 dst = GrPixmap(dst.info().makeColorType(GrColorType::kRGBA_8888),
255 dst.addr(),
256 dst.rowBytes());
Brian Salomon72c7b982020-10-06 10:07:38 -0400257 }
Brian Salomon72c7b982020-10-06 10:07:38 -0400258 } else {
259 fp = GrTextureEffect::Make(this->readSurfaceView(), this->colorInfo().alphaType());
260 }
261 if (!fp) {
262 return false;
263 }
Brian Salomondd4087d2020-12-23 20:36:44 -0500264 sfc->fillRectToRectWithFP(SkIRect::MakePtSize(pt, dst.dimensions()),
265 SkIRect::MakeSize(dst.dimensions()),
Brian Salomon590f5672020-12-16 11:44:47 -0500266 std::move(fp));
Brian Salomon72c7b982020-10-06 10:07:38 -0400267 pt = {0, 0};
Brian Salomon590f5672020-12-16 11:44:47 -0500268 tempCtx = std::move(sfc);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400269 } else {
Brian Salomon72c7b982020-10-06 10:07:38 -0400270 auto restrictions = this->caps()->getDstCopyRestrictions(this->asRenderTargetProxy(),
271 this->colorInfo().colorType());
272 sk_sp<GrSurfaceProxy> copy;
273 static constexpr auto kFit = SkBackingFit::kExact;
274 static constexpr auto kBudgeted = SkBudgeted::kYes;
275 static constexpr auto kMipMapped = GrMipMapped::kNo;
276 if (restrictions.fMustCopyWholeSrc) {
277 copy = GrSurfaceProxy::Copy(fContext, srcProxy, this->origin(), kMipMapped, kFit,
278 kBudgeted);
279 } else {
Brian Salomondd4087d2020-12-23 20:36:44 -0500280 auto srcRect = SkIRect::MakePtSize(pt, dst.dimensions());
Brian Salomon72c7b982020-10-06 10:07:38 -0400281 copy = GrSurfaceProxy::Copy(fContext, srcProxy, this->origin(), kMipMapped, srcRect,
282 kFit, kBudgeted, restrictions.fRectsMustMatch);
283 pt = {0, 0};
284 }
285 if (!copy) {
286 return false;
287 }
288 GrSurfaceProxyView view{std::move(copy), this->origin(), this->readSwizzle()};
Brian Salomon14f99fc2020-12-07 12:19:47 -0500289 tempCtx = GrSurfaceContext::Make(dContext, std::move(view), this->colorInfo());
Brian Salomon72c7b982020-10-06 10:07:38 -0400290 SkASSERT(tempCtx);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400291 }
Brian Salomondd4087d2020-12-23 20:36:44 -0500292 return tempCtx->readPixels(dContext, dst, pt);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400293 }
294
Greg Danielb8d84f82020-02-13 14:25:00 -0500295 bool flip = this->origin() == kBottomLeft_GrSurfaceOrigin;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400296
Brian Salomon1d435302019-07-01 13:05:28 -0400297 auto supportedRead = caps->supportedReadPixelsColorType(
Brian Salomondd4087d2020-12-23 20:36:44 -0500298 this->colorInfo().colorType(), srcProxy->backendFormat(), dst.colorType());
Brian Salomon1d435302019-07-01 13:05:28 -0400299
Brian Salomondd4087d2020-12-23 20:36:44 -0500300 bool makeTight =
301 !caps->readPixelsRowBytesSupport() && dst.rowBytes() != dst.info().minRowBytes();
Brian Salomon1047a492019-07-02 12:25:21 -0400302
303 bool convert = unpremul || premul || needColorConversion || flip || makeTight ||
Brian Salomondd4087d2020-12-23 20:36:44 -0500304 (dst.colorType() != supportedRead.fColorType);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400305
Brian Salomonf30b1c12019-06-20 12:25:02 -0400306 std::unique_ptr<char[]> tmpPixels;
Brian Salomondd4087d2020-12-23 20:36:44 -0500307 GrPixmap tmp;
308 void* readDst = dst.addr();
309 size_t readRB = dst.rowBytes();
Greg Daniel6eb8c242019-06-05 10:22:24 -0400310 if (convert) {
Brian Salomondd4087d2020-12-23 20:36:44 -0500311 GrImageInfo tmpInfo(supportedRead.fColorType,
312 this->colorInfo().alphaType(),
313 this->colorInfo().refColorSpace(),
314 dst.dimensions());
Brian Salomon1d435302019-07-01 13:05:28 -0400315 size_t tmpRB = tmpInfo.minRowBytes();
316 size_t size = tmpRB * tmpInfo.height();
317 // Chrome MSAN bots require the data to be initialized (hence the ()).
John Stilesfbd050b2020-08-03 13:21:46 -0400318 tmpPixels = std::make_unique<char[]>(size);
Brian Salomondd4087d2020-12-23 20:36:44 -0500319 tmp = {tmpInfo, tmpPixels.get(), tmpRB};
Brian Salomonf30b1c12019-06-20 12:25:02 -0400320
Brian Salomonf30b1c12019-06-20 12:25:02 -0400321 readDst = tmpPixels.get();
Brian Salomon1d435302019-07-01 13:05:28 -0400322 readRB = tmpRB;
Brian Salomondd4087d2020-12-23 20:36:44 -0500323 pt.fY = flip ? srcSurface->height() - pt.fY - dst.height() : pt.fY;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400324 }
325
Adlai Hollerc95b5892020-08-11 12:02:22 -0400326 dContext->priv().flushSurface(srcProxy);
327 dContext->submit();
Brian Salomondd4087d2020-12-23 20:36:44 -0500328 if (!dContext->priv().getGpu()->readPixels(srcSurface, pt.fX, pt.fY, dst.width(), dst.height(),
329 this->colorInfo().colorType(),
Adlai Hollerc95b5892020-08-11 12:02:22 -0400330 supportedRead.fColorType, readDst, readRB)) {
Greg Daniel6eb8c242019-06-05 10:22:24 -0400331 return false;
332 }
333
Brian Salomondd4087d2020-12-23 20:36:44 -0500334 if (tmp.hasPixels()) {
335 return GrConvertPixels(dst, tmp, flip);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400336 }
337 return true;
338}
Robert Phillips0d075de2019-03-04 11:08:13 -0500339
Brian Salomondd4087d2020-12-23 20:36:44 -0500340bool GrSurfaceContext::writePixels(GrDirectContext* dContext, GrPixmap src, SkIPoint pt) {
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400341 ASSERT_SINGLE_OWNER
342 RETURN_FALSE_IF_ABANDONED
343 SkDEBUGCODE(this->validate();)
Brian Salomon1d435302019-07-01 13:05:28 -0400344 GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrSurfaceContext::writePixels");
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400345
Adlai Hollerc95b5892020-08-11 12:02:22 -0400346 if (!dContext) {
Brian Salomonc320b152018-02-20 14:05:36 -0500347 return false;
348 }
Robert Phillips6a6de562019-02-15 15:19:15 -0500349
Brian Salomon1d435302019-07-01 13:05:28 -0400350 if (this->asSurfaceProxy()->readOnly()) {
Robert Phillips6a6de562019-02-15 15:19:15 -0500351 return false;
352 }
353
Brian Salomondd4087d2020-12-23 20:36:44 -0500354 src = src.clip(this->dimensions(), &pt);
355 if (!src.hasPixels()) {
Brian Salomon1d435302019-07-01 13:05:28 -0400356 return false;
357 }
Brian Salomondd4087d2020-12-23 20:36:44 -0500358 if (!alpha_types_compatible(src.alphaType(), this->colorInfo().alphaType())) {
Greg Daniel6eb8c242019-06-05 10:22:24 -0400359 return false;
360 }
361
362 GrSurfaceProxy* dstProxy = this->asSurfaceProxy();
Stephen White3c0a50f2020-01-16 18:19:54 -0500363
364 if (dstProxy->framebufferOnly()) {
365 return false;
366 }
367
Adlai Hollerc95b5892020-08-11 12:02:22 -0400368 if (!dstProxy->instantiate(dContext->priv().resourceProvider())) {
Greg Daniel6eb8c242019-06-05 10:22:24 -0400369 return false;
370 }
371
372 GrSurface* dstSurface = dstProxy->peekSurface();
373
Brian Salomondd4087d2020-12-23 20:36:44 -0500374 SkColorSpaceXformSteps::Flags flags =
375 SkColorSpaceXformSteps{src.info(), this->colorInfo()}.flags;
Mike Klein7321e6a2019-12-03 11:08:40 -0600376 bool unpremul = flags.unpremul,
377 needColorConversion = flags.linearize || flags.gamut_transform || flags.encode,
378 premul = flags.premul;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400379
Adlai Hollerc95b5892020-08-11 12:02:22 -0400380 const GrCaps* caps = dContext->priv().caps();
Greg Daniel7bfc9132019-08-14 14:23:53 -0400381
382 auto rgbaDefaultFormat = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
383 GrRenderable::kNo);
384
Greg Danielc71c7962020-01-14 16:44:18 -0500385 GrColorType dstColorType = this->colorInfo().colorType();
Greg Daniel6eb8c242019-06-05 10:22:24 -0400386 // For canvas2D putImageData performance we have a special code path for unpremul RGBA_8888 srcs
387 // that are premultiplied on the GPU. This is kept as narrow as possible for now.
Brian Salomon1d435302019-07-01 13:05:28 -0400388 bool canvas2DFastPath = !caps->avoidWritePixelsFastPath() && premul && !needColorConversion &&
Brian Salomondd4087d2020-12-23 20:36:44 -0500389 (src.colorType() == GrColorType::kRGBA_8888 ||
390 src.colorType() == GrColorType::kBGRA_8888) &&
Brian Salomon590f5672020-12-16 11:44:47 -0500391 this->asFillContext() &&
Greg Danielc71c7962020-01-14 16:44:18 -0500392 (dstColorType == GrColorType::kRGBA_8888 ||
393 dstColorType == GrColorType::kBGRA_8888) &&
Greg Daniel7bfc9132019-08-14 14:23:53 -0400394 rgbaDefaultFormat.isValid() &&
Adlai Hollerc95b5892020-08-11 12:02:22 -0400395 dContext->priv().validPMUPMConversionExists();
Greg Daniel6eb8c242019-06-05 10:22:24 -0400396
397 if (!caps->surfaceSupportsWritePixels(dstSurface) || canvas2DFastPath) {
Brian Salomon14f99fc2020-12-07 12:19:47 -0500398 GrColorInfo tempColorInfo;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400399 GrBackendFormat format;
Greg Danielbfa19c42019-12-19 16:41:40 -0500400 GrSwizzle tempReadSwizzle;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400401 if (canvas2DFastPath) {
Brian Salomon14f99fc2020-12-07 12:19:47 -0500402 tempColorInfo = {GrColorType::kRGBA_8888,
403 kUnpremul_SkAlphaType,
404 this->colorInfo().refColorSpace()};
Greg Daniel7bfc9132019-08-14 14:23:53 -0400405 format = rgbaDefaultFormat;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400406 } else {
Brian Salomon14f99fc2020-12-07 12:19:47 -0500407 tempColorInfo = this->colorInfo();
Greg Daniel6eb8c242019-06-05 10:22:24 -0400408 format = dstProxy->backendFormat().makeTexture2D();
409 if (!format.isValid()) {
410 return false;
411 }
Greg Danielbfa19c42019-12-19 16:41:40 -0500412 tempReadSwizzle = this->readSwizzle();
Greg Daniel6eb8c242019-06-05 10:22:24 -0400413 }
414
Greg Daniel2e52ad12019-06-13 10:04:16 -0400415 // It is more efficient for us to write pixels into a top left origin so we prefer that.
416 // However, if the final proxy isn't a render target then we must use a copy to move the
417 // data into it which requires the origins to match. If the final proxy is a render target
418 // we can use a draw instead which doesn't have this origin restriction. Thus for render
419 // targets we will use top left and otherwise we will make the origins match.
Brian Salomonf30b1c12019-06-20 12:25:02 -0400420 GrSurfaceOrigin tempOrigin =
Brian Salomon590f5672020-12-16 11:44:47 -0500421 this->asFillContext() ? kTopLeft_GrSurfaceOrigin : this->origin();
Adlai Hollerc95b5892020-08-11 12:02:22 -0400422 auto tempProxy = dContext->priv().proxyProvider()->createProxy(
Brian Salomondd4087d2020-12-23 20:36:44 -0500423 format, src.dimensions(), GrRenderable::kNo, 1, GrMipmapped::kNo,
Brian Salomondf1bd6d2020-03-26 20:37:01 -0400424 SkBackingFit::kApprox, SkBudgeted::kYes, GrProtected::kNo);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400425 if (!tempProxy) {
426 return false;
427 }
Greg Daniel3912a4b2020-01-14 09:56:04 -0500428 GrSurfaceProxyView tempView(tempProxy, tempOrigin, tempReadSwizzle);
Brian Salomon14f99fc2020-12-07 12:19:47 -0500429 GrSurfaceContext tempCtx(dContext, tempView, tempColorInfo);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400430
431 // In the fast path we always write the srcData to the temp context as though it were RGBA.
432 // When the data is really BGRA the write will cause the R and B channels to be swapped in
433 // the intermediate surface which gets corrected by a swizzle effect when drawing to the
434 // dst.
Brian Salomondd4087d2020-12-23 20:36:44 -0500435 GrColorType origSrcColorType = src.colorType();
Brian Salomon1d435302019-07-01 13:05:28 -0400436 if (canvas2DFastPath) {
Brian Salomondd4087d2020-12-23 20:36:44 -0500437 src = {src.info().makeColorType(GrColorType::kRGBA_8888), src.addr(), src.rowBytes()};
Brian Salomon1d435302019-07-01 13:05:28 -0400438 }
Brian Salomondd4087d2020-12-23 20:36:44 -0500439 if (!tempCtx.writePixels(dContext, src, {0, 0})) {
Greg Daniel6eb8c242019-06-05 10:22:24 -0400440 return false;
441 }
442
Brian Salomon590f5672020-12-16 11:44:47 -0500443 if (this->asFillContext()) {
Greg Daniel46cfbc62019-06-07 11:43:30 -0400444 std::unique_ptr<GrFragmentProcessor> fp;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400445 if (canvas2DFastPath) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400446 fp = dContext->priv().createUPMToPMEffect(
Brian Salomon14f99fc2020-12-07 12:19:47 -0500447 GrTextureEffect::Make(std::move(tempView), tempColorInfo.alphaType()));
Brian Salomon1d435302019-07-01 13:05:28 -0400448 // Important: check the original src color type here!
Brian Salomondd4087d2020-12-23 20:36:44 -0500449 if (origSrcColorType == GrColorType::kBGRA_8888) {
Greg Daniel6eb8c242019-06-05 10:22:24 -0400450 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
451 }
452 } else {
Brian Salomon14f99fc2020-12-07 12:19:47 -0500453 fp = GrTextureEffect::Make(std::move(tempView), tempColorInfo.alphaType());
Greg Daniel6eb8c242019-06-05 10:22:24 -0400454 }
455 if (!fp) {
456 return false;
457 }
Brian Salomondd4087d2020-12-23 20:36:44 -0500458 this->asFillContext()->fillRectToRectWithFP(SkIRect::MakeSize(src.dimensions()),
459 SkIRect::MakePtSize(pt, src.dimensions()),
460 std::move(fp));
Greg Daniel6eb8c242019-06-05 10:22:24 -0400461 } else {
Brian Salomondd4087d2020-12-23 20:36:44 -0500462 SkIRect srcRect = SkIRect::MakeSize(src.dimensions());
Brian Salomon1d435302019-07-01 13:05:28 -0400463 SkIPoint dstPoint = SkIPoint::Make(pt.fX, pt.fY);
Brian Salomonc5243782020-04-02 12:50:34 -0400464 if (!this->copy(tempProxy.get(), srcRect, dstPoint)) {
Greg Daniel6eb8c242019-06-05 10:22:24 -0400465 return false;
466 }
Greg Daniel6eb8c242019-06-05 10:22:24 -0400467 }
468 return true;
469 }
470
Brian Salomon1d435302019-07-01 13:05:28 -0400471 GrColorType allowedColorType =
Brian Salomon4bc0c1f2019-09-30 15:12:27 -0400472 caps->supportedWritePixelsColorType(this->colorInfo().colorType(),
Brian Salomon01915c02019-08-02 09:57:21 -0400473 dstProxy->backendFormat(),
Brian Salomondd4087d2020-12-23 20:36:44 -0500474 src.colorType()).fColorType;
Greg Danielb8d84f82020-02-13 14:25:00 -0500475 bool flip = this->origin() == kBottomLeft_GrSurfaceOrigin;
Brian Salomondd4087d2020-12-23 20:36:44 -0500476 bool makeTight = !caps->writePixelsRowBytesSupport() &&
477 src.rowBytes() != src.info().minRowBytes();
Brian Salomon1047a492019-07-02 12:25:21 -0400478 bool convert = premul || unpremul || needColorConversion || makeTight ||
Brian Salomondd4087d2020-12-23 20:36:44 -0500479 (src.colorType() != allowedColorType) || flip;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400480
Brian Salomonf30b1c12019-06-20 12:25:02 -0400481 std::unique_ptr<char[]> tmpPixels;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400482 if (convert) {
Brian Salomondd4087d2020-12-23 20:36:44 -0500483 GrImageInfo tmpInfo(allowedColorType,
484 this->colorInfo().alphaType(),
485 this->colorInfo().refColorSpace(),
486 src.dimensions());
Brian Salomon1d435302019-07-01 13:05:28 -0400487 auto tmpRB = tmpInfo.minRowBytes();
488 tmpPixels.reset(new char[tmpRB * tmpInfo.height()]);
Brian Salomondd4087d2020-12-23 20:36:44 -0500489 GrPixmap tmp(tmpInfo, tmpPixels.get(), tmpRB);
Brian Salomonf30b1c12019-06-20 12:25:02 -0400490
Brian Salomondd4087d2020-12-23 20:36:44 -0500491 SkAssertResult(GrConvertPixels(tmp, src, flip));
Brian Salomonf30b1c12019-06-20 12:25:02 -0400492
Brian Salomondd4087d2020-12-23 20:36:44 -0500493 src = tmp;
Brian Salomon1d435302019-07-01 13:05:28 -0400494 pt.fY = flip ? dstSurface->height() - pt.fY - tmpInfo.height() : pt.fY;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400495 }
496
497 // On platforms that prefer flushes over VRAM use (i.e., ANGLE) we're better off forcing a
498 // complete flush here. On platforms that prefer VRAM use over flushes we're better off
499 // giving the drawing manager the chance of skipping the flush (i.e., by passing in the
500 // destination proxy)
501 // TODO: should this policy decision just be moved into the drawing manager?
Adlai Hollerc95b5892020-08-11 12:02:22 -0400502 dContext->priv().flushSurface(caps->preferVRAMUseOverFlushes() ? dstProxy : nullptr);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400503
Brian Salomondd4087d2020-12-23 20:36:44 -0500504 return dContext->priv().getGpu()->writePixels(dstSurface, pt.fX, pt.fY, src.width(),
505 src.height(), this->colorInfo().colorType(),
506 src.colorType(), src.addr(), src.rowBytes());
Brian Osman45580d32016-11-23 09:37:01 -0500507}
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400508
Adlai Hollerc95b5892020-08-11 12:02:22 -0400509void GrSurfaceContext::asyncRescaleAndReadPixels(GrDirectContext* dContext,
510 const SkImageInfo& info,
Brian Salomon63a0a752020-06-26 13:32:09 -0400511 const SkIRect& srcRect,
512 RescaleGamma rescaleGamma,
513 SkFilterQuality rescaleQuality,
514 ReadPixelsCallback callback,
Adlai Hollerc95b5892020-08-11 12:02:22 -0400515 ReadPixelsContext callbackContext) {
Brian Salomon63a0a752020-06-26 13:32:09 -0400516 // We implement this by rendering and we don't currently support rendering kUnpremul.
517 if (info.alphaType() == kUnpremul_SkAlphaType) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400518 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400519 return;
520 }
Adlai Hollerc95b5892020-08-11 12:02:22 -0400521 if (!dContext) {
522 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400523 return;
524 }
525 auto rt = this->asRenderTargetProxy();
526 if (rt && rt->wrapsVkSecondaryCB()) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400527 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400528 return;
529 }
530 if (rt && rt->framebufferOnly()) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400531 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400532 return;
533 }
534 auto dstCT = SkColorTypeToGrColorType(info.colorType());
535 if (dstCT == GrColorType::kUnknown) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400536 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400537 return;
538 }
539 bool needsRescale = srcRect.width() != info.width() || srcRect.height() != info.height();
540 auto colorTypeOfFinalContext = this->colorInfo().colorType();
541 auto backendFormatOfFinalContext = this->asSurfaceProxy()->backendFormat();
542 if (needsRescale) {
543 colorTypeOfFinalContext = dstCT;
544 backendFormatOfFinalContext =
545 this->caps()->getDefaultBackendFormat(dstCT, GrRenderable::kYes);
546 }
547 auto readInfo = this->caps()->supportedReadPixelsColorType(colorTypeOfFinalContext,
548 backendFormatOfFinalContext, dstCT);
549 // Fail if we can't read from the source surface's color type.
550 if (readInfo.fColorType == GrColorType::kUnknown) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400551 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400552 return;
553 }
554 // Fail if read color type does not have all of dstCT's color channels and those missing color
555 // channels are in the src.
556 uint32_t dstChannels = GrColorTypeChannelFlags(dstCT);
557 uint32_t legalReadChannels = GrColorTypeChannelFlags(readInfo.fColorType);
558 uint32_t srcChannels = GrColorTypeChannelFlags(this->colorInfo().colorType());
559 if ((~legalReadChannels & dstChannels) & srcChannels) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400560 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400561 return;
562 }
563
Brian Salomoneebe7352020-12-09 16:37:04 -0500564 std::unique_ptr<GrSurfaceDrawContext> tempRTC;
Brian Salomon63a0a752020-06-26 13:32:09 -0400565 int x = srcRect.fLeft;
566 int y = srcRect.fTop;
567 if (needsRescale) {
568 tempRTC = this->rescale(info, kTopLeft_GrSurfaceOrigin, srcRect, rescaleGamma,
569 rescaleQuality);
570 if (!tempRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400571 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400572 return;
573 }
574 SkASSERT(SkColorSpace::Equals(tempRTC->colorInfo().colorSpace(), info.colorSpace()));
575 SkASSERT(tempRTC->origin() == kTopLeft_GrSurfaceOrigin);
576 x = y = 0;
577 } else {
578 sk_sp<GrColorSpaceXform> xform = GrColorSpaceXform::Make(this->colorInfo().colorSpace(),
579 this->colorInfo().alphaType(),
580 info.colorSpace(),
581 info.alphaType());
582 // Insert a draw to a temporary surface if we need to do a y-flip or color space conversion.
583 if (this->origin() == kBottomLeft_GrSurfaceOrigin || xform) {
584 GrSurfaceProxyView texProxyView = this->readSurfaceView();
585 SkRect srcRectToDraw = SkRect::Make(srcRect);
586 // If the src is not texturable first try to make a copy to a texture.
587 if (!texProxyView.asTextureProxy()) {
588 texProxyView =
Brian Salomon7e67dca2020-07-21 09:27:25 -0400589 GrSurfaceProxyView::Copy(fContext, texProxyView, GrMipmapped::kNo, srcRect,
Brian Salomon63a0a752020-06-26 13:32:09 -0400590 SkBackingFit::kApprox, SkBudgeted::kNo);
591 if (!texProxyView) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400592 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400593 return;
594 }
595 SkASSERT(texProxyView.asTextureProxy());
596 srcRectToDraw = SkRect::MakeWH(srcRect.width(), srcRect.height());
597 }
Brian Salomoneebe7352020-12-09 16:37:04 -0500598 tempRTC = GrSurfaceDrawContext::Make(dContext, this->colorInfo().colorType(),
599 info.refColorSpace(), SkBackingFit::kApprox,
600 srcRect.size(), 1, GrMipmapped::kNo,
601 GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon63a0a752020-06-26 13:32:09 -0400602 if (!tempRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400603 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400604 return;
605 }
Brian Salomone69b9ef2020-07-22 11:18:06 -0400606 tempRTC->drawTexture(nullptr,
607 std::move(texProxyView),
608 this->colorInfo().alphaType(),
609 GrSamplerState::Filter::kNearest,
610 GrSamplerState::MipmapMode::kNone,
611 SkBlendMode::kSrc,
612 SK_PMColor4fWHITE,
613 srcRectToDraw,
614 SkRect::MakeWH(srcRect.width(), srcRect.height()),
615 GrAA::kNo,
616 GrQuadAAFlags::kNone,
617 SkCanvas::kFast_SrcRectConstraint,
618 SkMatrix::I(),
619 std::move(xform));
Brian Salomon63a0a752020-06-26 13:32:09 -0400620 x = y = 0;
621 }
622 }
623 auto rtc = tempRTC ? tempRTC.get() : this;
Adlai Hollerc95b5892020-08-11 12:02:22 -0400624 return rtc->asyncReadPixels(dContext, SkIRect::MakeXYWH(x, y, info.width(), info.height()),
625 info.colorType(), callback, callbackContext);
Brian Salomon63a0a752020-06-26 13:32:09 -0400626}
627
628class GrSurfaceContext::AsyncReadResult : public SkImage::AsyncReadResult {
629public:
630 AsyncReadResult(uint32_t inboxID) : fInboxID(inboxID) {}
631 ~AsyncReadResult() override {
632 for (int i = 0; i < fPlanes.count(); ++i) {
633 if (!fPlanes[i].fMappedBuffer) {
634 delete[] static_cast<const char*>(fPlanes[i].fData);
635 } else {
636 GrClientMappedBufferManager::BufferFinishedMessageBus::Post(
637 {std::move(fPlanes[i].fMappedBuffer), fInboxID});
638 }
639 }
640 }
641
642 int count() const override { return fPlanes.count(); }
643 const void* data(int i) const override { return fPlanes[i].fData; }
644 size_t rowBytes(int i) const override { return fPlanes[i].fRowBytes; }
645
646 bool addTransferResult(const PixelTransferResult& result,
647 SkISize dimensions,
648 size_t rowBytes,
649 GrClientMappedBufferManager* manager) {
650 SkASSERT(!result.fTransferBuffer->isMapped());
651 const void* mappedData = result.fTransferBuffer->map();
652 if (!mappedData) {
653 return false;
654 }
655 if (result.fPixelConverter) {
656 std::unique_ptr<char[]> convertedData(new char[rowBytes * dimensions.height()]);
657 result.fPixelConverter(convertedData.get(), mappedData);
658 this->addCpuPlane(std::move(convertedData), rowBytes);
659 result.fTransferBuffer->unmap();
660 } else {
661 manager->insert(result.fTransferBuffer);
662 this->addMappedPlane(mappedData, rowBytes, std::move(result.fTransferBuffer));
663 }
664 return true;
665 }
666
667 void addCpuPlane(std::unique_ptr<const char[]> data, size_t rowBytes) {
668 SkASSERT(data);
669 SkASSERT(rowBytes > 0);
670 fPlanes.emplace_back(data.release(), rowBytes, nullptr);
671 }
672
673private:
674 void addMappedPlane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> mappedBuffer) {
675 SkASSERT(data);
676 SkASSERT(rowBytes > 0);
677 SkASSERT(mappedBuffer);
678 SkASSERT(mappedBuffer->isMapped());
679 fPlanes.emplace_back(data, rowBytes, std::move(mappedBuffer));
680 }
681
682 struct Plane {
683 Plane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> buffer)
684 : fData(data), fRowBytes(rowBytes), fMappedBuffer(std::move(buffer)) {}
685 const void* fData;
686 size_t fRowBytes;
687 // If this is null then fData is heap alloc and must be delete[]ed as const char[].
688 sk_sp<GrGpuBuffer> fMappedBuffer;
689 };
690 SkSTArray<3, Plane> fPlanes;
691 uint32_t fInboxID;
692};
693
Adlai Hollerc95b5892020-08-11 12:02:22 -0400694void GrSurfaceContext::asyncReadPixels(GrDirectContext* dContext,
695 const SkIRect& rect,
Brian Salomon63a0a752020-06-26 13:32:09 -0400696 SkColorType colorType,
697 ReadPixelsCallback callback,
Adlai Hollerc95b5892020-08-11 12:02:22 -0400698 ReadPixelsContext callbackContext) {
Brian Salomon63a0a752020-06-26 13:32:09 -0400699 SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
700 SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
701
Adlai Hollerc95b5892020-08-11 12:02:22 -0400702 if (!dContext || this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
703 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400704 return;
705 }
706
Adlai Hollerc95b5892020-08-11 12:02:22 -0400707 auto mappedBufferManager = dContext->priv().clientMappedBufferManager();
Brian Salomon63a0a752020-06-26 13:32:09 -0400708
709 auto transferResult = this->transferPixels(SkColorTypeToGrColorType(colorType), rect);
710
711 if (!transferResult.fTransferBuffer) {
712 auto ii = SkImageInfo::Make(rect.size(), colorType, this->colorInfo().alphaType(),
713 this->colorInfo().refColorSpace());
714 auto result = std::make_unique<AsyncReadResult>(0);
715 std::unique_ptr<char[]> data(new char[ii.computeMinByteSize()]);
716 SkPixmap pm(ii, data.get(), ii.minRowBytes());
717 result->addCpuPlane(std::move(data), pm.rowBytes());
718
Adlai Hollerc95b5892020-08-11 12:02:22 -0400719 SkIPoint pt{rect.fLeft, rect.fTop};
Brian Salomondd4087d2020-12-23 20:36:44 -0500720 if (!this->readPixels(dContext, pm, pt)) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400721 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400722 return;
723 }
Adlai Hollerc95b5892020-08-11 12:02:22 -0400724 callback(callbackContext, std::move(result));
Brian Salomon63a0a752020-06-26 13:32:09 -0400725 return;
726 }
727
728 struct FinishContext {
729 ReadPixelsCallback* fClientCallback;
730 ReadPixelsContext fClientContext;
731 SkISize fSize;
732 SkColorType fColorType;
733 GrClientMappedBufferManager* fMappedBufferManager;
734 PixelTransferResult fTransferResult;
735 };
736 // Assumption is that the caller would like to flush. We could take a parameter or require an
737 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
738 // callback to GrGpu until after the next flush that flushes our op list, though.
739 auto* finishContext = new FinishContext{callback,
Adlai Hollerc95b5892020-08-11 12:02:22 -0400740 callbackContext,
Brian Salomon63a0a752020-06-26 13:32:09 -0400741 rect.size(),
742 colorType,
743 mappedBufferManager,
744 std::move(transferResult)};
745 auto finishCallback = [](GrGpuFinishedContext c) {
746 const auto* context = reinterpret_cast<const FinishContext*>(c);
747 auto result = std::make_unique<AsyncReadResult>(context->fMappedBufferManager->inboxID());
748 size_t rowBytes = context->fSize.width() * SkColorTypeBytesPerPixel(context->fColorType);
749 if (!result->addTransferResult(context->fTransferResult, context->fSize, rowBytes,
750 context->fMappedBufferManager)) {
751 result.reset();
752 }
753 (*context->fClientCallback)(context->fClientContext, std::move(result));
754 delete context;
755 };
756 GrFlushInfo flushInfo;
757 flushInfo.fFinishedContext = finishContext;
758 flushInfo.fFinishedProc = finishCallback;
Robert Phillips80bfda82020-11-12 09:23:36 -0500759
760 dContext->priv().flushSurface(this->asSurfaceProxy(),
761 SkSurface::BackendSurfaceAccess::kNoAccess,
762 flushInfo);
Brian Salomon63a0a752020-06-26 13:32:09 -0400763}
764
Adlai Hollerc95b5892020-08-11 12:02:22 -0400765void GrSurfaceContext::asyncRescaleAndReadPixelsYUV420(GrDirectContext* dContext,
766 SkYUVColorSpace yuvColorSpace,
Brian Salomon63a0a752020-06-26 13:32:09 -0400767 sk_sp<SkColorSpace> dstColorSpace,
768 const SkIRect& srcRect,
769 SkISize dstSize,
770 RescaleGamma rescaleGamma,
771 SkFilterQuality rescaleQuality,
772 ReadPixelsCallback callback,
Adlai Hollerc95b5892020-08-11 12:02:22 -0400773 ReadPixelsContext callbackContext) {
Brian Salomon63a0a752020-06-26 13:32:09 -0400774 SkASSERT(srcRect.fLeft >= 0 && srcRect.fRight <= this->width());
775 SkASSERT(srcRect.fTop >= 0 && srcRect.fBottom <= this->height());
776 SkASSERT(!dstSize.isZero());
777 SkASSERT((dstSize.width() % 2 == 0) && (dstSize.height() % 2 == 0));
778
Adlai Hollerc95b5892020-08-11 12:02:22 -0400779 if (!dContext) {
780 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400781 return;
782 }
783 auto rt = this->asRenderTargetProxy();
784 if (rt && rt->wrapsVkSecondaryCB()) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400785 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400786 return;
787 }
788 if (rt && rt->framebufferOnly()) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400789 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400790 return;
791 }
792 if (this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400793 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400794 return;
795 }
796 int x = srcRect.fLeft;
797 int y = srcRect.fTop;
798 bool needsRescale = srcRect.size() != dstSize;
799 GrSurfaceProxyView srcView;
800 if (needsRescale) {
801 // We assume the caller wants kPremul. There is no way to indicate a preference.
802 auto info = SkImageInfo::Make(dstSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
803 dstColorSpace);
804 // TODO: Incorporate the YUV conversion into last pass of rescaling.
805 auto tempRTC = this->rescale(info, kTopLeft_GrSurfaceOrigin, srcRect, rescaleGamma,
806 rescaleQuality);
807 if (!tempRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400808 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400809 return;
810 }
811 SkASSERT(SkColorSpace::Equals(tempRTC->colorInfo().colorSpace(), info.colorSpace()));
812 SkASSERT(tempRTC->origin() == kTopLeft_GrSurfaceOrigin);
813 x = y = 0;
814 srcView = tempRTC->readSurfaceView();
815 } else {
816 srcView = this->readSurfaceView();
817 if (!srcView.asTextureProxy()) {
Brian Salomon7e67dca2020-07-21 09:27:25 -0400818 srcView = GrSurfaceProxyView::Copy(fContext, std::move(srcView), GrMipmapped::kNo,
Brian Salomon63a0a752020-06-26 13:32:09 -0400819 srcRect, SkBackingFit::kApprox, SkBudgeted::kYes);
820 if (!srcView) {
821 // If we can't get a texture copy of the contents then give up.
Adlai Hollerc95b5892020-08-11 12:02:22 -0400822 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400823 return;
824 }
825 SkASSERT(srcView.asTextureProxy());
826 x = y = 0;
827 }
828 // We assume the caller wants kPremul. There is no way to indicate a preference.
829 sk_sp<GrColorSpaceXform> xform = GrColorSpaceXform::Make(
830 this->colorInfo().colorSpace(), this->colorInfo().alphaType(), dstColorSpace.get(),
831 kPremul_SkAlphaType);
832 if (xform) {
833 SkRect srcRectToDraw = SkRect::MakeXYWH(x, y, srcRect.width(), srcRect.height());
Brian Salomoneebe7352020-12-09 16:37:04 -0500834 auto tempRTC = GrSurfaceDrawContext::Make(
Adlai Hollerc95b5892020-08-11 12:02:22 -0400835 dContext, this->colorInfo().colorType(), dstColorSpace, SkBackingFit::kApprox,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400836 dstSize, 1, GrMipmapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon63a0a752020-06-26 13:32:09 -0400837 if (!tempRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400838 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400839 return;
840 }
Brian Salomone69b9ef2020-07-22 11:18:06 -0400841 tempRTC->drawTexture(nullptr,
842 std::move(srcView),
843 this->colorInfo().alphaType(),
844 GrSamplerState::Filter::kNearest,
845 GrSamplerState::MipmapMode::kNone,
846 SkBlendMode::kSrc,
847 SK_PMColor4fWHITE,
848 srcRectToDraw,
849 SkRect::Make(srcRect.size()),
850 GrAA::kNo,
851 GrQuadAAFlags::kNone,
852 SkCanvas::kFast_SrcRectConstraint,
853 SkMatrix::I(),
854 std::move(xform));
Brian Salomon63a0a752020-06-26 13:32:09 -0400855 srcView = tempRTC->readSurfaceView();
856 SkASSERT(srcView.asTextureProxy());
857 x = y = 0;
858 }
859 }
860
Brian Salomoneebe7352020-12-09 16:37:04 -0500861 auto yRTC = GrSurfaceDrawContext::MakeWithFallback(
Adlai Hollerc95b5892020-08-11 12:02:22 -0400862 dContext, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, dstSize, 1,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400863 GrMipmapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon63a0a752020-06-26 13:32:09 -0400864 int halfW = dstSize.width() /2;
865 int halfH = dstSize.height()/2;
Brian Salomoneebe7352020-12-09 16:37:04 -0500866 auto uRTC = GrSurfaceDrawContext::MakeWithFallback(
Adlai Hollerc95b5892020-08-11 12:02:22 -0400867 dContext, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, {halfW, halfH},
868 1, GrMipmapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomoneebe7352020-12-09 16:37:04 -0500869 auto vRTC = GrSurfaceDrawContext::MakeWithFallback(
Adlai Hollerc95b5892020-08-11 12:02:22 -0400870 dContext, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, {halfW, halfH},
871 1, GrMipmapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon63a0a752020-06-26 13:32:09 -0400872 if (!yRTC || !uRTC || !vRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400873 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400874 return;
875 }
876
877 float baseM[20];
878 SkColorMatrix_RGB2YUV(yuvColorSpace, baseM);
879
880 // TODO: Use one transfer buffer for all three planes to reduce map/unmap cost?
881
882 auto texMatrix = SkMatrix::Translate(x, y);
883
884 SkRect dstRectY = SkRect::Make(dstSize);
885 SkRect dstRectUV = SkRect::MakeWH(halfW, halfH);
886
887 bool doSynchronousRead = !this->caps()->transferFromSurfaceToBufferSupport();
888 PixelTransferResult yTransfer, uTransfer, vTransfer;
889
890 // This matrix generates (r,g,b,a) = (0, 0, 0, y)
891 float yM[20];
892 std::fill_n(yM, 15, 0.f);
893 std::copy_n(baseM + 0, 5, yM + 15);
894 GrPaint yPaint;
895 auto yTexFP = GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix);
896 auto yColFP = GrColorMatrixFragmentProcessor::Make(std::move(yTexFP), yM,
897 /*unpremulInput=*/false,
898 /*clampRGBOutput=*/true,
899 /*premulOutput=*/false);
John Stiles5933d7d2020-07-21 12:28:35 -0400900 yPaint.setColorFragmentProcessor(std::move(yColFP));
Brian Salomon63a0a752020-06-26 13:32:09 -0400901 yPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
902 yRTC->fillRectToRect(nullptr, std::move(yPaint), GrAA::kNo, SkMatrix::I(), dstRectY, dstRectY);
903 if (!doSynchronousRead) {
904 yTransfer = yRTC->transferPixels(GrColorType::kAlpha_8,
905 SkIRect::MakeWH(yRTC->width(), yRTC->height()));
906 if (!yTransfer.fTransferBuffer) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400907 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400908 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 GrPaint uPaint;
918 auto uTexFP = GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix,
Brian Salomona3b02f52020-07-15 16:02:01 -0400919 GrSamplerState::Filter::kLinear);
Brian Salomon63a0a752020-06-26 13:32:09 -0400920 auto uColFP = GrColorMatrixFragmentProcessor::Make(std::move(uTexFP), uM,
921 /*unpremulInput=*/false,
922 /*clampRGBOutput=*/true,
923 /*premulOutput=*/false);
John Stiles5933d7d2020-07-21 12:28:35 -0400924 uPaint.setColorFragmentProcessor(std::move(uColFP));
Brian Salomon63a0a752020-06-26 13:32:09 -0400925 uPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
926 uRTC->fillRectToRect(nullptr, std::move(uPaint), GrAA::kNo, SkMatrix::I(), dstRectUV,
927 dstRectUV);
928 if (!doSynchronousRead) {
929 uTransfer = uRTC->transferPixels(GrColorType::kAlpha_8,
930 SkIRect::MakeWH(uRTC->width(), uRTC->height()));
931 if (!uTransfer.fTransferBuffer) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400932 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400933 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 GrPaint vPaint;
942 auto vTexFP = GrTextureEffect::Make(std::move(srcView), this->colorInfo().alphaType(),
Brian Salomona3b02f52020-07-15 16:02:01 -0400943 texMatrix, GrSamplerState::Filter::kLinear);
Brian Salomon63a0a752020-06-26 13:32:09 -0400944 auto vColFP = GrColorMatrixFragmentProcessor::Make(std::move(vTexFP), vM,
945 /*unpremulInput=*/false,
946 /*clampRGBOutput=*/true,
947 /*premulOutput=*/false);
John Stiles5933d7d2020-07-21 12:28:35 -0400948 vPaint.setColorFragmentProcessor(std::move(vColFP));
Brian Salomon63a0a752020-06-26 13:32:09 -0400949 vPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
950 vRTC->fillRectToRect(nullptr, std::move(vPaint), GrAA::kNo, SkMatrix::I(), dstRectUV,
951 dstRectUV);
952 if (!doSynchronousRead) {
953 vTransfer = vRTC->transferPixels(GrColorType::kAlpha_8,
954 SkIRect::MakeWH(vRTC->width(), vRTC->height()));
955 if (!vTransfer.fTransferBuffer) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400956 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400957 return;
958 }
959 }
960
961 if (doSynchronousRead) {
962 GrImageInfo yInfo(GrColorType::kAlpha_8, kPremul_SkAlphaType, nullptr, dstSize);
963 GrImageInfo uvInfo = yInfo.makeWH(halfW, halfH);
Brian Salomondd4087d2020-12-23 20:36:44 -0500964 auto [yPmp, yStorage] = GrPixmap::Allocate(yInfo);
965 auto [uPmp, uStorage] = GrPixmap::Allocate(uvInfo);
966 auto [vPmp, vStorage] = GrPixmap::Allocate(uvInfo);
967 if (!yRTC->readPixels(dContext, yPmp, {0, 0}) ||
968 !uRTC->readPixels(dContext, uPmp, {0, 0}) ||
969 !vRTC->readPixels(dContext, vPmp, {0, 0})) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400970 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400971 return;
972 }
Adlai Hollerc95b5892020-08-11 12:02:22 -0400973 auto result = std::make_unique<AsyncReadResult>(dContext->priv().contextID());
Brian Salomondd4087d2020-12-23 20:36:44 -0500974 result->addCpuPlane(std::move(yStorage), yPmp.rowBytes());
975 result->addCpuPlane(std::move(uStorage), uPmp.rowBytes());
976 result->addCpuPlane(std::move(vStorage), vPmp.rowBytes());
Adlai Hollerc95b5892020-08-11 12:02:22 -0400977 callback(callbackContext, std::move(result));
Brian Salomon63a0a752020-06-26 13:32:09 -0400978 return;
979 }
980
981 struct FinishContext {
982 ReadPixelsCallback* fClientCallback;
983 ReadPixelsContext fClientContext;
984 GrClientMappedBufferManager* fMappedBufferManager;
985 SkISize fSize;
986 PixelTransferResult fYTransfer;
987 PixelTransferResult fUTransfer;
988 PixelTransferResult fVTransfer;
989 };
990 // Assumption is that the caller would like to flush. We could take a parameter or require an
991 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
992 // callback to GrGpu until after the next flush that flushes our op list, though.
993 auto* finishContext = new FinishContext{callback,
Adlai Hollerc95b5892020-08-11 12:02:22 -0400994 callbackContext,
995 dContext->priv().clientMappedBufferManager(),
Brian Salomon63a0a752020-06-26 13:32:09 -0400996 dstSize,
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 result = std::make_unique<AsyncReadResult>(context->fMappedBufferManager->inboxID());
1003 auto manager = context->fMappedBufferManager;
1004 size_t rowBytes = SkToSizeT(context->fSize.width());
1005 if (!result->addTransferResult(context->fYTransfer, context->fSize, rowBytes, manager)) {
1006 (*context->fClientCallback)(context->fClientContext, nullptr);
1007 delete context;
1008 return;
1009 }
1010 rowBytes /= 2;
1011 SkISize uvSize = {context->fSize.width() / 2, context->fSize.height() / 2};
1012 if (!result->addTransferResult(context->fUTransfer, uvSize, rowBytes, manager)) {
1013 (*context->fClientCallback)(context->fClientContext, nullptr);
1014 delete context;
1015 return;
1016 }
1017 if (!result->addTransferResult(context->fVTransfer, uvSize, rowBytes, manager)) {
1018 (*context->fClientCallback)(context->fClientContext, nullptr);
1019 delete context;
1020 return;
1021 }
1022 (*context->fClientCallback)(context->fClientContext, std::move(result));
1023 delete context;
1024 };
1025 GrFlushInfo flushInfo;
1026 flushInfo.fFinishedContext = finishContext;
1027 flushInfo.fFinishedProc = finishCallback;
Robert Phillips80bfda82020-11-12 09:23:36 -05001028 dContext->priv().flushSurface(this->asSurfaceProxy(),
1029 SkSurface::BackendSurfaceAccess::kNoAccess,
1030 flushInfo);
Brian Salomon63a0a752020-06-26 13:32:09 -04001031}
1032
Brian Salomonc5243782020-04-02 12:50:34 -04001033bool GrSurfaceContext::copy(GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) {
Robert Phillips2de8cfa2017-06-28 10:33:41 -04001034 ASSERT_SINGLE_OWNER
1035 RETURN_FALSE_IF_ABANDONED
1036 SkDEBUGCODE(this->validate();)
Greg Daniel46cfbc62019-06-07 11:43:30 -04001037 GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrSurfaceContextPriv::copy");
Greg Daniel25af6712018-04-25 10:44:38 -04001038
Brian Salomon947efe22019-07-16 15:36:11 -04001039 const GrCaps* caps = fContext->priv().caps();
1040
Greg Daniel46cfbc62019-06-07 11:43:30 -04001041 SkASSERT(src->backendFormat().textureType() != GrTextureType::kExternal);
Greg Danielc71c7962020-01-14 16:44:18 -05001042 SkASSERT(src->backendFormat() == this->asSurfaceProxy()->backendFormat());
Greg Daniel46cfbc62019-06-07 11:43:30 -04001043
Stephen White3c0a50f2020-01-16 18:19:54 -05001044 if (this->asSurfaceProxy()->framebufferOnly()) {
1045 return false;
1046 }
1047
Chris Daltonf8e5aad2019-08-02 12:55:23 -06001048 if (!caps->canCopySurface(this->asSurfaceProxy(), src, srcRect, dstPoint)) {
Greg Daniel25af6712018-04-25 10:44:38 -04001049 return false;
1050 }
Robert Phillips2de8cfa2017-06-28 10:33:41 -04001051
Greg Daniel16f5c652019-10-29 11:26:01 -04001052 // The swizzle doesn't matter for copies and it is not used.
1053 return this->drawingManager()->newCopyRenderTask(
Brian Salomonc5243782020-04-02 12:50:34 -04001054 GrSurfaceProxyView(sk_ref_sp(src), this->origin(), GrSwizzle("rgba")), srcRect,
Greg Daniel46e366a2019-12-16 14:38:36 -05001055 this->readSurfaceView(), dstPoint);
Robert Phillips2de8cfa2017-06-28 10:33:41 -04001056}
Greg Daniel46cfbc62019-06-07 11:43:30 -04001057
Brian Salomoneebe7352020-12-09 16:37:04 -05001058std::unique_ptr<GrSurfaceDrawContext> GrSurfaceContext::rescale(const GrImageInfo& info,
1059 GrSurfaceOrigin origin,
1060 SkIRect srcRect,
1061 RescaleGamma rescaleGamma,
1062 SkFilterQuality rescaleQuality) {
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001063 // We rescale by drawing and currently only support drawing to premul.
Brian Salomon1c86b632020-12-11 12:36:01 -05001064 if (info.alphaType() != kPremul_SkAlphaType) {
1065 return nullptr;
1066 }
1067 auto sdc = GrSurfaceDrawContext::MakeWithFallback(fContext,
1068 info.colorType(),
1069 info.refColorSpace(),
1070 SkBackingFit::kExact,
1071 info.dimensions(),
1072 1,
1073 GrMipmapped::kNo,
1074 this->asSurfaceProxy()->isProtected(),
1075 origin);
1076 if (!sdc || !this->rescaleInto(sdc.get(),
1077 SkIRect::MakeSize(sdc->dimensions()),
1078 srcRect,
1079 rescaleGamma,
1080 rescaleQuality)) {
1081 return nullptr;
1082 }
1083 return sdc;
1084}
1085
1086bool GrSurfaceContext::rescaleInto(GrSurfaceDrawContext* dst,
1087 SkIRect dstRect,
1088 SkIRect srcRect,
1089 RescaleGamma rescaleGamma,
1090 SkFilterQuality rescaleQuality) {
1091 SkASSERT(dst);
1092 if (!SkIRect::MakeSize(dst->dimensions()).contains((dstRect))) {
1093 return false;
1094 }
1095
Brian Salomone9ad9982019-07-22 16:17:41 -04001096 auto rtProxy = this->asRenderTargetProxy();
1097 if (rtProxy && rtProxy->wrapsVkSecondaryCB()) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001098 return false;
Brian Salomone9ad9982019-07-22 16:17:41 -04001099 }
1100
Stephen White3c0a50f2020-01-16 18:19:54 -05001101 if (this->asSurfaceProxy()->framebufferOnly()) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001102 return false;
Brian Salomone9ad9982019-07-22 16:17:41 -04001103 }
1104
Greg Daniel40903af2020-01-30 14:55:05 -05001105 GrSurfaceProxyView texView = this->readSurfaceView();
Brian Salomonfc118442019-11-22 19:09:27 -05001106 SkAlphaType srcAlphaType = this->colorInfo().alphaType();
Greg Daniel40903af2020-01-30 14:55:05 -05001107 if (!texView.asTextureProxy()) {
Brian Salomon7e67dca2020-07-21 09:27:25 -04001108 texView = GrSurfaceProxyView::Copy(fContext, std::move(texView), GrMipmapped::kNo, srcRect,
Brian Salomonc5243782020-04-02 12:50:34 -04001109 SkBackingFit::kApprox, SkBudgeted::kNo);
1110 if (!texView) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001111 return false;
Brian Salomone9ad9982019-07-22 16:17:41 -04001112 }
Greg Daniel40903af2020-01-30 14:55:05 -05001113 SkASSERT(texView.asTextureProxy());
Brian Salomonafd8a6c2020-05-21 12:10:54 -04001114 srcRect = SkIRect::MakeSize(srcRect.size());
Brian Salomone9ad9982019-07-22 16:17:41 -04001115 }
1116
Brian Salomon1c86b632020-12-11 12:36:01 -05001117 SkISize finalSize = dstRect.size();
1118
Brian Salomonbf6b9792019-08-21 09:38:10 -04001119 // Within a rescaling pass A is the input (if not null) and B is the output. At the end of the
1120 // pass B is moved to A. If 'this' is the input on the first pass then tempA is null.
Brian Salomoneebe7352020-12-09 16:37:04 -05001121 std::unique_ptr<GrSurfaceDrawContext> tempA;
1122 std::unique_ptr<GrSurfaceDrawContext> tempB;
Brian Salomonbf6b9792019-08-21 09:38:10 -04001123
Brian Salomone9ad9982019-07-22 16:17:41 -04001124 // Assume we should ignore the rescale linear request if the surface has no color space since
1125 // it's unclear how we'd linearize from an unknown color space.
Brian Salomon63a0a752020-06-26 13:32:09 -04001126 if (rescaleGamma == RescaleGamma::kLinear && this->colorInfo().colorSpace() &&
Brian Salomon4bc0c1f2019-09-30 15:12:27 -04001127 !this->colorInfo().colorSpace()->gammaIsLinear()) {
1128 auto cs = this->colorInfo().colorSpace()->makeLinearGamma();
Brian Salomonfc118442019-11-22 19:09:27 -05001129 auto xform = GrColorSpaceXform::Make(this->colorInfo().colorSpace(), srcAlphaType, cs.get(),
Brian Salomone9ad9982019-07-22 16:17:41 -04001130 kPremul_SkAlphaType);
1131 // We'll fall back to kRGBA_8888 if half float not supported.
Brian Salomoneebe7352020-12-09 16:37:04 -05001132 auto linearRTC = GrSurfaceDrawContext::MakeWithFallback(
Brian Salomonafd8a6c2020-05-21 12:10:54 -04001133 fContext, GrColorType::kRGBA_F16, cs, SkBackingFit::kApprox, srcRect.size(), 1,
Brian Salomon1c86b632020-12-11 12:36:01 -05001134 GrMipmapped::kNo, GrProtected::kNo, dst->origin());
Brian Salomone9ad9982019-07-22 16:17:41 -04001135 if (!linearRTC) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001136 return false;
Brian Salomone9ad9982019-07-22 16:17:41 -04001137 }
Brian Salomon11ad4cc2020-05-15 12:07:59 -04001138 // 1-to-1 draw can always be kFast.
Brian Salomone69b9ef2020-07-22 11:18:06 -04001139 linearRTC->drawTexture(nullptr,
1140 std::move(texView),
1141 srcAlphaType,
1142 GrSamplerState::Filter::kNearest,
1143 GrSamplerState::MipmapMode::kNone,
1144 SkBlendMode::kSrc,
1145 SK_PMColor4fWHITE,
1146 SkRect::Make(srcRect),
1147 SkRect::Make(srcRect.size()),
1148 GrAA::kNo,
1149 GrQuadAAFlags::kNone,
1150 SkCanvas::kFast_SrcRectConstraint,
1151 SkMatrix::I(),
1152 std::move(xform));
Greg Daniel40903af2020-01-30 14:55:05 -05001153 texView = linearRTC->readSurfaceView();
1154 SkASSERT(texView.asTextureProxy());
Brian Salomonbf6b9792019-08-21 09:38:10 -04001155 tempA = std::move(linearRTC);
Brian Salomonafd8a6c2020-05-21 12:10:54 -04001156 srcRect = SkIRect::MakeSize(srcRect.size());
Brian Salomone9ad9982019-07-22 16:17:41 -04001157 }
Brian Salomonafd8a6c2020-05-21 12:10:54 -04001158
Brian Salomon1c86b632020-12-11 12:36:01 -05001159 while (srcRect.size() != finalSize) {
1160 SkISize nextDims = finalSize;
Brian Salomon59f31b12020-06-04 17:27:15 -04001161 if (rescaleQuality != kNone_SkFilterQuality) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001162 if (srcRect.width() > finalSize.width()) {
1163 nextDims.fWidth = std::max((srcRect.width() + 1)/2, finalSize.width());
1164 } else if (srcRect.width() < finalSize.width()) {
1165 nextDims.fWidth = std::min(srcRect.width()*2, finalSize.width());
Brian Salomon59f31b12020-06-04 17:27:15 -04001166 }
Brian Salomon1c86b632020-12-11 12:36:01 -05001167 if (srcRect.height() > finalSize.height()) {
1168 nextDims.fHeight = std::max((srcRect.height() + 1)/2, finalSize.height());
1169 } else if (srcRect.height() < finalSize.height()) {
1170 nextDims.fHeight = std::min(srcRect.height()*2, finalSize.height());
Brian Salomon59f31b12020-06-04 17:27:15 -04001171 }
1172 }
Brian Salomonbf6b9792019-08-21 09:38:10 -04001173 auto input = tempA ? tempA.get() : this;
Brian Salomone9ad9982019-07-22 16:17:41 -04001174 sk_sp<GrColorSpaceXform> xform;
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001175 GrSurfaceDrawContext* stepDst;
1176 SkIRect stepDstRect;
Brian Salomon1c86b632020-12-11 12:36:01 -05001177 if (nextDims == finalSize) {
Brian Salomone9ad9982019-07-22 16:17:41 -04001178 // Might as well fold conversion to final info in the last step.
Brian Salomon4bc0c1f2019-09-30 15:12:27 -04001179 xform = GrColorSpaceXform::Make(input->colorInfo().colorSpace(),
Brian Salomon1c86b632020-12-11 12:36:01 -05001180 input->colorInfo().alphaType(),
1181 dst->colorInfo().colorSpace(),
1182 dst->colorInfo().alphaType());
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001183 stepDst = dst;
1184 stepDstRect = dstRect;
Brian Salomon1c86b632020-12-11 12:36:01 -05001185 } else {
1186 tempB = GrSurfaceDrawContext::MakeWithFallback(fContext,
1187 input->colorInfo().colorType(),
1188 input->colorInfo().refColorSpace(),
1189 SkBackingFit::kApprox,
1190 nextDims,
1191 1,
1192 GrMipmapped::kNo,
1193 GrProtected::kNo,
1194 dst->origin());
1195 if (!tempB) {
1196 return false;
1197 }
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001198 stepDst = tempB.get();
1199 stepDstRect = SkIRect::MakeSize(tempB->dimensions());
Brian Salomone9ad9982019-07-22 16:17:41 -04001200 }
Brian Salomon59f31b12020-06-04 17:27:15 -04001201 if (rescaleQuality == kHigh_SkFilterQuality) {
1202 SkMatrix matrix;
1203 matrix.setScaleTranslate((float)srcRect.width()/nextDims.width(),
1204 (float)srcRect.height()/nextDims.height(),
1205 srcRect.x(),
1206 srcRect.y());
1207 std::unique_ptr<GrFragmentProcessor> fp;
1208 auto dir = GrBicubicEffect::Direction::kXY;
1209 if (nextDims.width() == srcRect.width()) {
1210 dir = GrBicubicEffect::Direction::kY;
1211 } else if (nextDims.height() == srcRect.height()) {
1212 dir = GrBicubicEffect::Direction::kX;
Brian Salomone9ad9982019-07-22 16:17:41 -04001213 }
Brian Salomon1af72d12020-06-25 10:47:26 -04001214 static constexpr auto kWM = GrSamplerState::WrapMode::kClamp;
Mike Reed3867c702020-09-01 13:28:10 -04001215 static constexpr auto kKernel = GrBicubicEffect::gCatmullRom;
Brian Salomon1c86b632020-12-11 12:36:01 -05001216 fp = GrBicubicEffect::MakeSubset(std::move(texView),
1217 input->colorInfo().alphaType(),
1218 matrix,
1219 kWM,
1220 kWM,
1221 SkRect::Make(srcRect),
1222 kKernel,
1223 dir,
1224 *this->caps());
Brian Salomon59f31b12020-06-04 17:27:15 -04001225 if (xform) {
1226 fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(xform));
Brian Salomone9ad9982019-07-22 16:17:41 -04001227 }
Brian Salomon59f31b12020-06-04 17:27:15 -04001228 GrPaint paint;
John Stiles5933d7d2020-07-21 12:28:35 -04001229 paint.setColorFragmentProcessor(std::move(fp));
Brian Salomon59f31b12020-06-04 17:27:15 -04001230 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001231 stepDst->fillRectToRect(nullptr,
1232 std::move(paint),
1233 GrAA::kNo,
1234 SkMatrix::I(),
1235 SkRect::Make(stepDstRect),
1236 SkRect::Make(stepDstRect));
Brian Salomon59f31b12020-06-04 17:27:15 -04001237 } else {
1238 auto filter = rescaleQuality == kNone_SkFilterQuality ? GrSamplerState::Filter::kNearest
Brian Salomona3b02f52020-07-15 16:02:01 -04001239 : GrSamplerState::Filter::kLinear;
Brian Salomon59f31b12020-06-04 17:27:15 -04001240 // Minimizing draw with integer coord src and dev rects can always be kFast.
1241 auto constraint = SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint;
1242 if (nextDims.width() <= srcRect.width() && nextDims.height() <= srcRect.height()) {
1243 constraint = SkCanvas::SrcRectConstraint::kFast_SrcRectConstraint;
1244 }
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001245 stepDst->drawTexture(nullptr,
1246 std::move(texView),
1247 srcAlphaType,
1248 filter,
1249 GrSamplerState::MipmapMode::kNone,
1250 SkBlendMode::kSrc,
1251 SK_PMColor4fWHITE,
1252 SkRect::Make(srcRect),
1253 SkRect::Make(stepDstRect),
1254 GrAA::kNo,
1255 GrQuadAAFlags::kNone,
1256 constraint,
1257 SkMatrix::I(),
1258 std::move(xform));
Brian Salomone9ad9982019-07-22 16:17:41 -04001259 }
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001260 texView = stepDst->readSurfaceView();
Brian Salomonbf6b9792019-08-21 09:38:10 -04001261 tempA = std::move(tempB);
Brian Salomonafd8a6c2020-05-21 12:10:54 -04001262 srcRect = SkIRect::MakeSize(nextDims);
Brian Salomone9ad9982019-07-22 16:17:41 -04001263 }
Brian Salomon1c86b632020-12-11 12:36:01 -05001264 return true;
Brian Salomone9ad9982019-07-22 16:17:41 -04001265}
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001266
1267GrSurfaceContext::PixelTransferResult GrSurfaceContext::transferPixels(GrColorType dstCT,
1268 const SkIRect& rect) {
1269 SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
1270 SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
Robert Phillipsf8f45d92020-07-01 11:11:18 -04001271 auto direct = fContext->asDirectContext();
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001272 if (!direct) {
1273 return {};
1274 }
1275 auto rtProxy = this->asRenderTargetProxy();
1276 if (rtProxy && rtProxy->wrapsVkSecondaryCB()) {
1277 return {};
1278 }
1279
1280 auto proxy = this->asSurfaceProxy();
Brian Salomon4bc0c1f2019-09-30 15:12:27 -04001281 auto supportedRead = this->caps()->supportedReadPixelsColorType(this->colorInfo().colorType(),
1282 proxy->backendFormat(), dstCT);
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001283 // Fail if read color type does not have all of dstCT's color channels and those missing color
1284 // channels are in the src.
Brian Salomon2f23ae62020-03-26 16:17:56 -04001285 uint32_t dstChannels = GrColorTypeChannelFlags(dstCT);
1286 uint32_t legalReadChannels = GrColorTypeChannelFlags(supportedRead.fColorType);
1287 uint32_t srcChannels = GrColorTypeChannelFlags(this->colorInfo().colorType());
1288 if ((~legalReadChannels & dstChannels) & srcChannels) {
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001289 return {};
1290 }
1291
Brian Salomonfb28c6f2020-01-10 13:04:45 -05001292 if (!this->caps()->transferFromSurfaceToBufferSupport() ||
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001293 !supportedRead.fOffsetAlignmentForTransferBuffer) {
1294 return {};
1295 }
1296
1297 size_t rowBytes = GrColorTypeBytesPerPixel(supportedRead.fColorType) * rect.width();
1298 size_t size = rowBytes * rect.height();
1299 auto buffer = direct->priv().resourceProvider()->createBuffer(
1300 size, GrGpuBufferType::kXferGpuToCpu, GrAccessPattern::kStream_GrAccessPattern);
1301 if (!buffer) {
1302 return {};
1303 }
1304 auto srcRect = rect;
Greg Danielb8d84f82020-02-13 14:25:00 -05001305 bool flip = this->origin() == kBottomLeft_GrSurfaceOrigin;
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001306 if (flip) {
1307 srcRect = SkIRect::MakeLTRB(rect.fLeft, this->height() - rect.fBottom, rect.fRight,
1308 this->height() - rect.fTop);
1309 }
Greg Danielbbfec9d2019-08-20 10:56:51 -04001310 this->drawingManager()->newTransferFromRenderTask(this->asSurfaceProxyRef(), srcRect,
Brian Salomon4bc0c1f2019-09-30 15:12:27 -04001311 this->colorInfo().colorType(),
Greg Danielbbfec9d2019-08-20 10:56:51 -04001312 supportedRead.fColorType, buffer, 0);
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001313 PixelTransferResult result;
1314 result.fTransferBuffer = std::move(buffer);
Brian Salomon4bc0c1f2019-09-30 15:12:27 -04001315 auto at = this->colorInfo().alphaType();
Brian Salomon8f8354a2019-07-31 20:12:02 -04001316 if (supportedRead.fColorType != dstCT || flip) {
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001317 result.fPixelConverter = [w = rect.width(), h = rect.height(), dstCT, supportedRead, at](
1318 void* dst, const void* src) {
Brian Salomonf2ebdd92019-09-30 12:15:30 -04001319 GrImageInfo srcInfo(supportedRead.fColorType, at, nullptr, w, h);
1320 GrImageInfo dstInfo(dstCT, at, nullptr, w, h);
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001321 GrConvertPixels(dstInfo, dst, dstInfo.minRowBytes(),
1322 srcInfo, src, srcInfo.minRowBytes(),
Brian Salomon8f8354a2019-07-31 20:12:02 -04001323 /* flipY = */ false);
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001324 };
1325 }
1326 return result;
1327}
Greg Daniel46e366a2019-12-16 14:38:36 -05001328
1329#ifdef SK_DEBUG
1330void GrSurfaceContext::validate() const {
Greg Daniel3912a4b2020-01-14 09:56:04 -05001331 SkASSERT(fReadView.proxy());
1332 fReadView.proxy()->validate(fContext);
Brian Salomonc5243782020-04-02 12:50:34 -04001333 if (this->colorInfo().colorType() != GrColorType::kUnknown) {
1334 SkASSERT(fContext->priv().caps()->areColorTypeAndFormatCompatible(
1335 this->colorInfo().colorType(), fReadView.proxy()->backendFormat()));
1336 }
Greg Daniel46e366a2019-12-16 14:38:36 -05001337 this->onValidate();
1338}
1339#endif