blob: 5a85e886776362434e930a9037684ab383c80240 [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,
Mike Reed1efa14d2021-01-02 21:44:59 -0500513 RescaleMode rescaleMode,
Brian Salomon63a0a752020-06-26 13:32:09 -0400514 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) {
Mike Reed1efa14d2021-01-02 21:44:59 -0500568 tempRTC = this->rescale(info, kTopLeft_GrSurfaceOrigin, srcRect, rescaleGamma, rescaleMode);
Brian Salomon63a0a752020-06-26 13:32:09 -0400569 if (!tempRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400570 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400571 return;
572 }
573 SkASSERT(SkColorSpace::Equals(tempRTC->colorInfo().colorSpace(), info.colorSpace()));
574 SkASSERT(tempRTC->origin() == kTopLeft_GrSurfaceOrigin);
575 x = y = 0;
576 } else {
577 sk_sp<GrColorSpaceXform> xform = GrColorSpaceXform::Make(this->colorInfo().colorSpace(),
578 this->colorInfo().alphaType(),
579 info.colorSpace(),
580 info.alphaType());
581 // Insert a draw to a temporary surface if we need to do a y-flip or color space conversion.
582 if (this->origin() == kBottomLeft_GrSurfaceOrigin || xform) {
583 GrSurfaceProxyView texProxyView = this->readSurfaceView();
584 SkRect srcRectToDraw = SkRect::Make(srcRect);
585 // If the src is not texturable first try to make a copy to a texture.
586 if (!texProxyView.asTextureProxy()) {
587 texProxyView =
Brian Salomon7e67dca2020-07-21 09:27:25 -0400588 GrSurfaceProxyView::Copy(fContext, texProxyView, GrMipmapped::kNo, srcRect,
Brian Salomon63a0a752020-06-26 13:32:09 -0400589 SkBackingFit::kApprox, SkBudgeted::kNo);
590 if (!texProxyView) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400591 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400592 return;
593 }
594 SkASSERT(texProxyView.asTextureProxy());
595 srcRectToDraw = SkRect::MakeWH(srcRect.width(), srcRect.height());
596 }
Brian Salomoneebe7352020-12-09 16:37:04 -0500597 tempRTC = GrSurfaceDrawContext::Make(dContext, this->colorInfo().colorType(),
598 info.refColorSpace(), SkBackingFit::kApprox,
599 srcRect.size(), 1, GrMipmapped::kNo,
600 GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon63a0a752020-06-26 13:32:09 -0400601 if (!tempRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400602 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400603 return;
604 }
Brian Salomone69b9ef2020-07-22 11:18:06 -0400605 tempRTC->drawTexture(nullptr,
606 std::move(texProxyView),
607 this->colorInfo().alphaType(),
608 GrSamplerState::Filter::kNearest,
609 GrSamplerState::MipmapMode::kNone,
610 SkBlendMode::kSrc,
611 SK_PMColor4fWHITE,
612 srcRectToDraw,
613 SkRect::MakeWH(srcRect.width(), srcRect.height()),
614 GrAA::kNo,
615 GrQuadAAFlags::kNone,
616 SkCanvas::kFast_SrcRectConstraint,
617 SkMatrix::I(),
618 std::move(xform));
Brian Salomon63a0a752020-06-26 13:32:09 -0400619 x = y = 0;
620 }
621 }
622 auto rtc = tempRTC ? tempRTC.get() : this;
Adlai Hollerc95b5892020-08-11 12:02:22 -0400623 return rtc->asyncReadPixels(dContext, SkIRect::MakeXYWH(x, y, info.width(), info.height()),
624 info.colorType(), callback, callbackContext);
Brian Salomon63a0a752020-06-26 13:32:09 -0400625}
626
627class GrSurfaceContext::AsyncReadResult : public SkImage::AsyncReadResult {
628public:
629 AsyncReadResult(uint32_t inboxID) : fInboxID(inboxID) {}
630 ~AsyncReadResult() override {
631 for (int i = 0; i < fPlanes.count(); ++i) {
632 if (!fPlanes[i].fMappedBuffer) {
633 delete[] static_cast<const char*>(fPlanes[i].fData);
634 } else {
635 GrClientMappedBufferManager::BufferFinishedMessageBus::Post(
636 {std::move(fPlanes[i].fMappedBuffer), fInboxID});
637 }
638 }
639 }
640
641 int count() const override { return fPlanes.count(); }
642 const void* data(int i) const override { return fPlanes[i].fData; }
643 size_t rowBytes(int i) const override { return fPlanes[i].fRowBytes; }
644
645 bool addTransferResult(const PixelTransferResult& result,
646 SkISize dimensions,
647 size_t rowBytes,
648 GrClientMappedBufferManager* manager) {
649 SkASSERT(!result.fTransferBuffer->isMapped());
650 const void* mappedData = result.fTransferBuffer->map();
651 if (!mappedData) {
652 return false;
653 }
654 if (result.fPixelConverter) {
655 std::unique_ptr<char[]> convertedData(new char[rowBytes * dimensions.height()]);
656 result.fPixelConverter(convertedData.get(), mappedData);
657 this->addCpuPlane(std::move(convertedData), rowBytes);
658 result.fTransferBuffer->unmap();
659 } else {
660 manager->insert(result.fTransferBuffer);
661 this->addMappedPlane(mappedData, rowBytes, std::move(result.fTransferBuffer));
662 }
663 return true;
664 }
665
666 void addCpuPlane(std::unique_ptr<const char[]> data, size_t rowBytes) {
667 SkASSERT(data);
668 SkASSERT(rowBytes > 0);
669 fPlanes.emplace_back(data.release(), rowBytes, nullptr);
670 }
671
672private:
673 void addMappedPlane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> mappedBuffer) {
674 SkASSERT(data);
675 SkASSERT(rowBytes > 0);
676 SkASSERT(mappedBuffer);
677 SkASSERT(mappedBuffer->isMapped());
678 fPlanes.emplace_back(data, rowBytes, std::move(mappedBuffer));
679 }
680
681 struct Plane {
682 Plane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> buffer)
683 : fData(data), fRowBytes(rowBytes), fMappedBuffer(std::move(buffer)) {}
684 const void* fData;
685 size_t fRowBytes;
686 // If this is null then fData is heap alloc and must be delete[]ed as const char[].
687 sk_sp<GrGpuBuffer> fMappedBuffer;
688 };
689 SkSTArray<3, Plane> fPlanes;
690 uint32_t fInboxID;
691};
692
Adlai Hollerc95b5892020-08-11 12:02:22 -0400693void GrSurfaceContext::asyncReadPixels(GrDirectContext* dContext,
694 const SkIRect& rect,
Brian Salomon63a0a752020-06-26 13:32:09 -0400695 SkColorType colorType,
696 ReadPixelsCallback callback,
Adlai Hollerc95b5892020-08-11 12:02:22 -0400697 ReadPixelsContext callbackContext) {
Brian Salomon63a0a752020-06-26 13:32:09 -0400698 SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
699 SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
700
Adlai Hollerc95b5892020-08-11 12:02:22 -0400701 if (!dContext || this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
702 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400703 return;
704 }
705
Adlai Hollerc95b5892020-08-11 12:02:22 -0400706 auto mappedBufferManager = dContext->priv().clientMappedBufferManager();
Brian Salomon63a0a752020-06-26 13:32:09 -0400707
708 auto transferResult = this->transferPixels(SkColorTypeToGrColorType(colorType), rect);
709
710 if (!transferResult.fTransferBuffer) {
711 auto ii = SkImageInfo::Make(rect.size(), colorType, this->colorInfo().alphaType(),
712 this->colorInfo().refColorSpace());
713 auto result = std::make_unique<AsyncReadResult>(0);
714 std::unique_ptr<char[]> data(new char[ii.computeMinByteSize()]);
715 SkPixmap pm(ii, data.get(), ii.minRowBytes());
716 result->addCpuPlane(std::move(data), pm.rowBytes());
717
Adlai Hollerc95b5892020-08-11 12:02:22 -0400718 SkIPoint pt{rect.fLeft, rect.fTop};
Brian Salomondd4087d2020-12-23 20:36:44 -0500719 if (!this->readPixels(dContext, pm, pt)) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400720 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400721 return;
722 }
Adlai Hollerc95b5892020-08-11 12:02:22 -0400723 callback(callbackContext, std::move(result));
Brian Salomon63a0a752020-06-26 13:32:09 -0400724 return;
725 }
726
727 struct FinishContext {
728 ReadPixelsCallback* fClientCallback;
729 ReadPixelsContext fClientContext;
730 SkISize fSize;
731 SkColorType fColorType;
732 GrClientMappedBufferManager* fMappedBufferManager;
733 PixelTransferResult fTransferResult;
734 };
735 // Assumption is that the caller would like to flush. We could take a parameter or require an
736 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
737 // callback to GrGpu until after the next flush that flushes our op list, though.
738 auto* finishContext = new FinishContext{callback,
Adlai Hollerc95b5892020-08-11 12:02:22 -0400739 callbackContext,
Brian Salomon63a0a752020-06-26 13:32:09 -0400740 rect.size(),
741 colorType,
742 mappedBufferManager,
743 std::move(transferResult)};
744 auto finishCallback = [](GrGpuFinishedContext c) {
745 const auto* context = reinterpret_cast<const FinishContext*>(c);
746 auto result = std::make_unique<AsyncReadResult>(context->fMappedBufferManager->inboxID());
747 size_t rowBytes = context->fSize.width() * SkColorTypeBytesPerPixel(context->fColorType);
748 if (!result->addTransferResult(context->fTransferResult, context->fSize, rowBytes,
749 context->fMappedBufferManager)) {
750 result.reset();
751 }
752 (*context->fClientCallback)(context->fClientContext, std::move(result));
753 delete context;
754 };
755 GrFlushInfo flushInfo;
756 flushInfo.fFinishedContext = finishContext;
757 flushInfo.fFinishedProc = finishCallback;
Robert Phillips80bfda82020-11-12 09:23:36 -0500758
759 dContext->priv().flushSurface(this->asSurfaceProxy(),
760 SkSurface::BackendSurfaceAccess::kNoAccess,
761 flushInfo);
Brian Salomon63a0a752020-06-26 13:32:09 -0400762}
763
Adlai Hollerc95b5892020-08-11 12:02:22 -0400764void GrSurfaceContext::asyncRescaleAndReadPixelsYUV420(GrDirectContext* dContext,
765 SkYUVColorSpace yuvColorSpace,
Brian Salomon63a0a752020-06-26 13:32:09 -0400766 sk_sp<SkColorSpace> dstColorSpace,
767 const SkIRect& srcRect,
768 SkISize dstSize,
769 RescaleGamma rescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -0500770 RescaleMode rescaleMode,
Brian Salomon63a0a752020-06-26 13:32:09 -0400771 ReadPixelsCallback callback,
Adlai Hollerc95b5892020-08-11 12:02:22 -0400772 ReadPixelsContext callbackContext) {
Brian Salomon63a0a752020-06-26 13:32:09 -0400773 SkASSERT(srcRect.fLeft >= 0 && srcRect.fRight <= this->width());
774 SkASSERT(srcRect.fTop >= 0 && srcRect.fBottom <= this->height());
775 SkASSERT(!dstSize.isZero());
776 SkASSERT((dstSize.width() % 2 == 0) && (dstSize.height() % 2 == 0));
777
Adlai Hollerc95b5892020-08-11 12:02:22 -0400778 if (!dContext) {
779 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400780 return;
781 }
782 auto rt = this->asRenderTargetProxy();
783 if (rt && rt->wrapsVkSecondaryCB()) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400784 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400785 return;
786 }
787 if (rt && rt->framebufferOnly()) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400788 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400789 return;
790 }
791 if (this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400792 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400793 return;
794 }
795 int x = srcRect.fLeft;
796 int y = srcRect.fTop;
797 bool needsRescale = srcRect.size() != dstSize;
798 GrSurfaceProxyView srcView;
799 if (needsRescale) {
800 // We assume the caller wants kPremul. There is no way to indicate a preference.
801 auto info = SkImageInfo::Make(dstSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
802 dstColorSpace);
803 // TODO: Incorporate the YUV conversion into last pass of rescaling.
804 auto tempRTC = this->rescale(info, kTopLeft_GrSurfaceOrigin, srcRect, rescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -0500805 rescaleMode);
Brian Salomon63a0a752020-06-26 13:32:09 -0400806 if (!tempRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400807 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400808 return;
809 }
810 SkASSERT(SkColorSpace::Equals(tempRTC->colorInfo().colorSpace(), info.colorSpace()));
811 SkASSERT(tempRTC->origin() == kTopLeft_GrSurfaceOrigin);
812 x = y = 0;
813 srcView = tempRTC->readSurfaceView();
814 } else {
815 srcView = this->readSurfaceView();
816 if (!srcView.asTextureProxy()) {
Brian Salomon7e67dca2020-07-21 09:27:25 -0400817 srcView = GrSurfaceProxyView::Copy(fContext, std::move(srcView), GrMipmapped::kNo,
Brian Salomon63a0a752020-06-26 13:32:09 -0400818 srcRect, SkBackingFit::kApprox, SkBudgeted::kYes);
819 if (!srcView) {
820 // If we can't get a texture copy of the contents then give up.
Adlai Hollerc95b5892020-08-11 12:02:22 -0400821 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400822 return;
823 }
824 SkASSERT(srcView.asTextureProxy());
825 x = y = 0;
826 }
827 // We assume the caller wants kPremul. There is no way to indicate a preference.
828 sk_sp<GrColorSpaceXform> xform = GrColorSpaceXform::Make(
829 this->colorInfo().colorSpace(), this->colorInfo().alphaType(), dstColorSpace.get(),
830 kPremul_SkAlphaType);
831 if (xform) {
832 SkRect srcRectToDraw = SkRect::MakeXYWH(x, y, srcRect.width(), srcRect.height());
Brian Salomoneebe7352020-12-09 16:37:04 -0500833 auto tempRTC = GrSurfaceDrawContext::Make(
Adlai Hollerc95b5892020-08-11 12:02:22 -0400834 dContext, this->colorInfo().colorType(), dstColorSpace, SkBackingFit::kApprox,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400835 dstSize, 1, GrMipmapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon63a0a752020-06-26 13:32:09 -0400836 if (!tempRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400837 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400838 return;
839 }
Brian Salomone69b9ef2020-07-22 11:18:06 -0400840 tempRTC->drawTexture(nullptr,
841 std::move(srcView),
842 this->colorInfo().alphaType(),
843 GrSamplerState::Filter::kNearest,
844 GrSamplerState::MipmapMode::kNone,
845 SkBlendMode::kSrc,
846 SK_PMColor4fWHITE,
847 srcRectToDraw,
848 SkRect::Make(srcRect.size()),
849 GrAA::kNo,
850 GrQuadAAFlags::kNone,
851 SkCanvas::kFast_SrcRectConstraint,
852 SkMatrix::I(),
853 std::move(xform));
Brian Salomon63a0a752020-06-26 13:32:09 -0400854 srcView = tempRTC->readSurfaceView();
855 SkASSERT(srcView.asTextureProxy());
856 x = y = 0;
857 }
858 }
859
Brian Salomoneebe7352020-12-09 16:37:04 -0500860 auto yRTC = GrSurfaceDrawContext::MakeWithFallback(
Adlai Hollerc95b5892020-08-11 12:02:22 -0400861 dContext, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, dstSize, 1,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400862 GrMipmapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon63a0a752020-06-26 13:32:09 -0400863 int halfW = dstSize.width() /2;
864 int halfH = dstSize.height()/2;
Brian Salomoneebe7352020-12-09 16:37:04 -0500865 auto uRTC = GrSurfaceDrawContext::MakeWithFallback(
Adlai Hollerc95b5892020-08-11 12:02:22 -0400866 dContext, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, {halfW, halfH},
867 1, GrMipmapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomoneebe7352020-12-09 16:37:04 -0500868 auto vRTC = GrSurfaceDrawContext::MakeWithFallback(
Adlai Hollerc95b5892020-08-11 12:02:22 -0400869 dContext, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, {halfW, halfH},
870 1, GrMipmapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon63a0a752020-06-26 13:32:09 -0400871 if (!yRTC || !uRTC || !vRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400872 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400873 return;
874 }
875
876 float baseM[20];
877 SkColorMatrix_RGB2YUV(yuvColorSpace, baseM);
878
879 // TODO: Use one transfer buffer for all three planes to reduce map/unmap cost?
880
881 auto texMatrix = SkMatrix::Translate(x, y);
882
883 SkRect dstRectY = SkRect::Make(dstSize);
884 SkRect dstRectUV = SkRect::MakeWH(halfW, halfH);
885
886 bool doSynchronousRead = !this->caps()->transferFromSurfaceToBufferSupport();
887 PixelTransferResult yTransfer, uTransfer, vTransfer;
888
889 // This matrix generates (r,g,b,a) = (0, 0, 0, y)
890 float yM[20];
891 std::fill_n(yM, 15, 0.f);
892 std::copy_n(baseM + 0, 5, yM + 15);
893 GrPaint yPaint;
894 auto yTexFP = GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix);
895 auto yColFP = GrColorMatrixFragmentProcessor::Make(std::move(yTexFP), yM,
896 /*unpremulInput=*/false,
897 /*clampRGBOutput=*/true,
898 /*premulOutput=*/false);
John Stiles5933d7d2020-07-21 12:28:35 -0400899 yPaint.setColorFragmentProcessor(std::move(yColFP));
Brian Salomon63a0a752020-06-26 13:32:09 -0400900 yPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
901 yRTC->fillRectToRect(nullptr, std::move(yPaint), GrAA::kNo, SkMatrix::I(), dstRectY, dstRectY);
902 if (!doSynchronousRead) {
903 yTransfer = yRTC->transferPixels(GrColorType::kAlpha_8,
904 SkIRect::MakeWH(yRTC->width(), yRTC->height()));
905 if (!yTransfer.fTransferBuffer) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400906 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400907 return;
908 }
909 }
910
911 texMatrix.preScale(2.f, 2.f);
912 // This matrix generates (r,g,b,a) = (0, 0, 0, u)
913 float uM[20];
914 std::fill_n(uM, 15, 0.f);
915 std::copy_n(baseM + 5, 5, uM + 15);
916 GrPaint uPaint;
917 auto uTexFP = GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix,
Brian Salomona3b02f52020-07-15 16:02:01 -0400918 GrSamplerState::Filter::kLinear);
Brian Salomon63a0a752020-06-26 13:32:09 -0400919 auto uColFP = GrColorMatrixFragmentProcessor::Make(std::move(uTexFP), uM,
920 /*unpremulInput=*/false,
921 /*clampRGBOutput=*/true,
922 /*premulOutput=*/false);
John Stiles5933d7d2020-07-21 12:28:35 -0400923 uPaint.setColorFragmentProcessor(std::move(uColFP));
Brian Salomon63a0a752020-06-26 13:32:09 -0400924 uPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
925 uRTC->fillRectToRect(nullptr, std::move(uPaint), GrAA::kNo, SkMatrix::I(), dstRectUV,
926 dstRectUV);
927 if (!doSynchronousRead) {
928 uTransfer = uRTC->transferPixels(GrColorType::kAlpha_8,
929 SkIRect::MakeWH(uRTC->width(), uRTC->height()));
930 if (!uTransfer.fTransferBuffer) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400931 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400932 return;
933 }
934 }
935
936 // This matrix generates (r,g,b,a) = (0, 0, 0, v)
937 float vM[20];
938 std::fill_n(vM, 15, 0.f);
939 std::copy_n(baseM + 10, 5, vM + 15);
940 GrPaint vPaint;
941 auto vTexFP = GrTextureEffect::Make(std::move(srcView), this->colorInfo().alphaType(),
Brian Salomona3b02f52020-07-15 16:02:01 -0400942 texMatrix, GrSamplerState::Filter::kLinear);
Brian Salomon63a0a752020-06-26 13:32:09 -0400943 auto vColFP = GrColorMatrixFragmentProcessor::Make(std::move(vTexFP), vM,
944 /*unpremulInput=*/false,
945 /*clampRGBOutput=*/true,
946 /*premulOutput=*/false);
John Stiles5933d7d2020-07-21 12:28:35 -0400947 vPaint.setColorFragmentProcessor(std::move(vColFP));
Brian Salomon63a0a752020-06-26 13:32:09 -0400948 vPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
949 vRTC->fillRectToRect(nullptr, std::move(vPaint), GrAA::kNo, SkMatrix::I(), dstRectUV,
950 dstRectUV);
951 if (!doSynchronousRead) {
952 vTransfer = vRTC->transferPixels(GrColorType::kAlpha_8,
953 SkIRect::MakeWH(vRTC->width(), vRTC->height()));
954 if (!vTransfer.fTransferBuffer) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400955 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400956 return;
957 }
958 }
959
960 if (doSynchronousRead) {
961 GrImageInfo yInfo(GrColorType::kAlpha_8, kPremul_SkAlphaType, nullptr, dstSize);
962 GrImageInfo uvInfo = yInfo.makeWH(halfW, halfH);
Brian Salomondd4087d2020-12-23 20:36:44 -0500963 auto [yPmp, yStorage] = GrPixmap::Allocate(yInfo);
964 auto [uPmp, uStorage] = GrPixmap::Allocate(uvInfo);
965 auto [vPmp, vStorage] = GrPixmap::Allocate(uvInfo);
966 if (!yRTC->readPixels(dContext, yPmp, {0, 0}) ||
967 !uRTC->readPixels(dContext, uPmp, {0, 0}) ||
968 !vRTC->readPixels(dContext, vPmp, {0, 0})) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400969 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400970 return;
971 }
Adlai Hollerc95b5892020-08-11 12:02:22 -0400972 auto result = std::make_unique<AsyncReadResult>(dContext->priv().contextID());
Brian Salomondd4087d2020-12-23 20:36:44 -0500973 result->addCpuPlane(std::move(yStorage), yPmp.rowBytes());
974 result->addCpuPlane(std::move(uStorage), uPmp.rowBytes());
975 result->addCpuPlane(std::move(vStorage), vPmp.rowBytes());
Adlai Hollerc95b5892020-08-11 12:02:22 -0400976 callback(callbackContext, std::move(result));
Brian Salomon63a0a752020-06-26 13:32:09 -0400977 return;
978 }
979
980 struct FinishContext {
981 ReadPixelsCallback* fClientCallback;
982 ReadPixelsContext fClientContext;
983 GrClientMappedBufferManager* fMappedBufferManager;
984 SkISize fSize;
985 PixelTransferResult fYTransfer;
986 PixelTransferResult fUTransfer;
987 PixelTransferResult fVTransfer;
988 };
989 // Assumption is that the caller would like to flush. We could take a parameter or require an
990 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
991 // callback to GrGpu until after the next flush that flushes our op list, though.
992 auto* finishContext = new FinishContext{callback,
Adlai Hollerc95b5892020-08-11 12:02:22 -0400993 callbackContext,
994 dContext->priv().clientMappedBufferManager(),
Brian Salomon63a0a752020-06-26 13:32:09 -0400995 dstSize,
996 std::move(yTransfer),
997 std::move(uTransfer),
998 std::move(vTransfer)};
999 auto finishCallback = [](GrGpuFinishedContext c) {
1000 const auto* context = reinterpret_cast<const FinishContext*>(c);
1001 auto result = std::make_unique<AsyncReadResult>(context->fMappedBufferManager->inboxID());
1002 auto manager = context->fMappedBufferManager;
1003 size_t rowBytes = SkToSizeT(context->fSize.width());
1004 if (!result->addTransferResult(context->fYTransfer, context->fSize, rowBytes, manager)) {
1005 (*context->fClientCallback)(context->fClientContext, nullptr);
1006 delete context;
1007 return;
1008 }
1009 rowBytes /= 2;
1010 SkISize uvSize = {context->fSize.width() / 2, context->fSize.height() / 2};
1011 if (!result->addTransferResult(context->fUTransfer, uvSize, rowBytes, manager)) {
1012 (*context->fClientCallback)(context->fClientContext, nullptr);
1013 delete context;
1014 return;
1015 }
1016 if (!result->addTransferResult(context->fVTransfer, uvSize, rowBytes, manager)) {
1017 (*context->fClientCallback)(context->fClientContext, nullptr);
1018 delete context;
1019 return;
1020 }
1021 (*context->fClientCallback)(context->fClientContext, std::move(result));
1022 delete context;
1023 };
1024 GrFlushInfo flushInfo;
1025 flushInfo.fFinishedContext = finishContext;
1026 flushInfo.fFinishedProc = finishCallback;
Robert Phillips80bfda82020-11-12 09:23:36 -05001027 dContext->priv().flushSurface(this->asSurfaceProxy(),
1028 SkSurface::BackendSurfaceAccess::kNoAccess,
1029 flushInfo);
Brian Salomon63a0a752020-06-26 13:32:09 -04001030}
1031
Brian Salomonc5243782020-04-02 12:50:34 -04001032bool GrSurfaceContext::copy(GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) {
Robert Phillips2de8cfa2017-06-28 10:33:41 -04001033 ASSERT_SINGLE_OWNER
1034 RETURN_FALSE_IF_ABANDONED
1035 SkDEBUGCODE(this->validate();)
Greg Daniel46cfbc62019-06-07 11:43:30 -04001036 GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrSurfaceContextPriv::copy");
Greg Daniel25af6712018-04-25 10:44:38 -04001037
Brian Salomon947efe22019-07-16 15:36:11 -04001038 const GrCaps* caps = fContext->priv().caps();
1039
Greg Daniel46cfbc62019-06-07 11:43:30 -04001040 SkASSERT(src->backendFormat().textureType() != GrTextureType::kExternal);
Greg Danielc71c7962020-01-14 16:44:18 -05001041 SkASSERT(src->backendFormat() == this->asSurfaceProxy()->backendFormat());
Greg Daniel46cfbc62019-06-07 11:43:30 -04001042
Stephen White3c0a50f2020-01-16 18:19:54 -05001043 if (this->asSurfaceProxy()->framebufferOnly()) {
1044 return false;
1045 }
1046
Chris Daltonf8e5aad2019-08-02 12:55:23 -06001047 if (!caps->canCopySurface(this->asSurfaceProxy(), src, srcRect, dstPoint)) {
Greg Daniel25af6712018-04-25 10:44:38 -04001048 return false;
1049 }
Robert Phillips2de8cfa2017-06-28 10:33:41 -04001050
Greg Daniel16f5c652019-10-29 11:26:01 -04001051 // The swizzle doesn't matter for copies and it is not used.
1052 return this->drawingManager()->newCopyRenderTask(
Brian Salomonc5243782020-04-02 12:50:34 -04001053 GrSurfaceProxyView(sk_ref_sp(src), this->origin(), GrSwizzle("rgba")), srcRect,
Greg Daniel46e366a2019-12-16 14:38:36 -05001054 this->readSurfaceView(), dstPoint);
Robert Phillips2de8cfa2017-06-28 10:33:41 -04001055}
Greg Daniel46cfbc62019-06-07 11:43:30 -04001056
Brian Salomoneebe7352020-12-09 16:37:04 -05001057std::unique_ptr<GrSurfaceDrawContext> GrSurfaceContext::rescale(const GrImageInfo& info,
1058 GrSurfaceOrigin origin,
1059 SkIRect srcRect,
1060 RescaleGamma rescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -05001061 RescaleMode rescaleMode) {
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001062 // We rescale by drawing and currently only support drawing to premul.
Brian Salomon1c86b632020-12-11 12:36:01 -05001063 if (info.alphaType() != kPremul_SkAlphaType) {
1064 return nullptr;
1065 }
1066 auto sdc = GrSurfaceDrawContext::MakeWithFallback(fContext,
1067 info.colorType(),
1068 info.refColorSpace(),
1069 SkBackingFit::kExact,
1070 info.dimensions(),
1071 1,
1072 GrMipmapped::kNo,
1073 this->asSurfaceProxy()->isProtected(),
1074 origin);
1075 if (!sdc || !this->rescaleInto(sdc.get(),
1076 SkIRect::MakeSize(sdc->dimensions()),
1077 srcRect,
1078 rescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -05001079 rescaleMode)) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001080 return nullptr;
1081 }
1082 return sdc;
1083}
1084
1085bool GrSurfaceContext::rescaleInto(GrSurfaceDrawContext* dst,
1086 SkIRect dstRect,
1087 SkIRect srcRect,
1088 RescaleGamma rescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -05001089 RescaleMode rescaleMode) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001090 SkASSERT(dst);
1091 if (!SkIRect::MakeSize(dst->dimensions()).contains((dstRect))) {
1092 return false;
1093 }
1094
Brian Salomone9ad9982019-07-22 16:17:41 -04001095 auto rtProxy = this->asRenderTargetProxy();
1096 if (rtProxy && rtProxy->wrapsVkSecondaryCB()) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001097 return false;
Brian Salomone9ad9982019-07-22 16:17:41 -04001098 }
1099
Stephen White3c0a50f2020-01-16 18:19:54 -05001100 if (this->asSurfaceProxy()->framebufferOnly()) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001101 return false;
Brian Salomone9ad9982019-07-22 16:17:41 -04001102 }
1103
Greg Daniel40903af2020-01-30 14:55:05 -05001104 GrSurfaceProxyView texView = this->readSurfaceView();
Brian Salomonfc118442019-11-22 19:09:27 -05001105 SkAlphaType srcAlphaType = this->colorInfo().alphaType();
Greg Daniel40903af2020-01-30 14:55:05 -05001106 if (!texView.asTextureProxy()) {
Brian Salomon7e67dca2020-07-21 09:27:25 -04001107 texView = GrSurfaceProxyView::Copy(fContext, std::move(texView), GrMipmapped::kNo, srcRect,
Brian Salomonc5243782020-04-02 12:50:34 -04001108 SkBackingFit::kApprox, SkBudgeted::kNo);
1109 if (!texView) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001110 return false;
Brian Salomone9ad9982019-07-22 16:17:41 -04001111 }
Greg Daniel40903af2020-01-30 14:55:05 -05001112 SkASSERT(texView.asTextureProxy());
Brian Salomonafd8a6c2020-05-21 12:10:54 -04001113 srcRect = SkIRect::MakeSize(srcRect.size());
Brian Salomone9ad9982019-07-22 16:17:41 -04001114 }
1115
Brian Salomon1c86b632020-12-11 12:36:01 -05001116 SkISize finalSize = dstRect.size();
1117
Brian Salomonbf6b9792019-08-21 09:38:10 -04001118 // Within a rescaling pass A is the input (if not null) and B is the output. At the end of the
1119 // 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 -05001120 std::unique_ptr<GrSurfaceDrawContext> tempA;
1121 std::unique_ptr<GrSurfaceDrawContext> tempB;
Brian Salomonbf6b9792019-08-21 09:38:10 -04001122
Brian Salomone9ad9982019-07-22 16:17:41 -04001123 // Assume we should ignore the rescale linear request if the surface has no color space since
1124 // it's unclear how we'd linearize from an unknown color space.
Brian Salomon63a0a752020-06-26 13:32:09 -04001125 if (rescaleGamma == RescaleGamma::kLinear && this->colorInfo().colorSpace() &&
Brian Salomon4bc0c1f2019-09-30 15:12:27 -04001126 !this->colorInfo().colorSpace()->gammaIsLinear()) {
1127 auto cs = this->colorInfo().colorSpace()->makeLinearGamma();
Brian Salomonfc118442019-11-22 19:09:27 -05001128 auto xform = GrColorSpaceXform::Make(this->colorInfo().colorSpace(), srcAlphaType, cs.get(),
Brian Salomone9ad9982019-07-22 16:17:41 -04001129 kPremul_SkAlphaType);
1130 // We'll fall back to kRGBA_8888 if half float not supported.
Brian Salomoneebe7352020-12-09 16:37:04 -05001131 auto linearRTC = GrSurfaceDrawContext::MakeWithFallback(
Brian Salomonafd8a6c2020-05-21 12:10:54 -04001132 fContext, GrColorType::kRGBA_F16, cs, SkBackingFit::kApprox, srcRect.size(), 1,
Brian Salomon1c86b632020-12-11 12:36:01 -05001133 GrMipmapped::kNo, GrProtected::kNo, dst->origin());
Brian Salomone9ad9982019-07-22 16:17:41 -04001134 if (!linearRTC) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001135 return false;
Brian Salomone9ad9982019-07-22 16:17:41 -04001136 }
Brian Salomon11ad4cc2020-05-15 12:07:59 -04001137 // 1-to-1 draw can always be kFast.
Brian Salomone69b9ef2020-07-22 11:18:06 -04001138 linearRTC->drawTexture(nullptr,
1139 std::move(texView),
1140 srcAlphaType,
1141 GrSamplerState::Filter::kNearest,
1142 GrSamplerState::MipmapMode::kNone,
1143 SkBlendMode::kSrc,
1144 SK_PMColor4fWHITE,
1145 SkRect::Make(srcRect),
1146 SkRect::Make(srcRect.size()),
1147 GrAA::kNo,
1148 GrQuadAAFlags::kNone,
1149 SkCanvas::kFast_SrcRectConstraint,
1150 SkMatrix::I(),
1151 std::move(xform));
Greg Daniel40903af2020-01-30 14:55:05 -05001152 texView = linearRTC->readSurfaceView();
1153 SkASSERT(texView.asTextureProxy());
Brian Salomonbf6b9792019-08-21 09:38:10 -04001154 tempA = std::move(linearRTC);
Brian Salomonafd8a6c2020-05-21 12:10:54 -04001155 srcRect = SkIRect::MakeSize(srcRect.size());
Brian Salomone9ad9982019-07-22 16:17:41 -04001156 }
Brian Salomonafd8a6c2020-05-21 12:10:54 -04001157
Brian Salomon1c86b632020-12-11 12:36:01 -05001158 while (srcRect.size() != finalSize) {
1159 SkISize nextDims = finalSize;
Mike Reed1efa14d2021-01-02 21:44:59 -05001160 if (rescaleMode != RescaleMode::kNearest) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001161 if (srcRect.width() > finalSize.width()) {
1162 nextDims.fWidth = std::max((srcRect.width() + 1)/2, finalSize.width());
1163 } else if (srcRect.width() < finalSize.width()) {
1164 nextDims.fWidth = std::min(srcRect.width()*2, finalSize.width());
Brian Salomon59f31b12020-06-04 17:27:15 -04001165 }
Brian Salomon1c86b632020-12-11 12:36:01 -05001166 if (srcRect.height() > finalSize.height()) {
1167 nextDims.fHeight = std::max((srcRect.height() + 1)/2, finalSize.height());
1168 } else if (srcRect.height() < finalSize.height()) {
1169 nextDims.fHeight = std::min(srcRect.height()*2, finalSize.height());
Brian Salomon59f31b12020-06-04 17:27:15 -04001170 }
1171 }
Brian Salomonbf6b9792019-08-21 09:38:10 -04001172 auto input = tempA ? tempA.get() : this;
Brian Salomone9ad9982019-07-22 16:17:41 -04001173 sk_sp<GrColorSpaceXform> xform;
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001174 GrSurfaceDrawContext* stepDst;
1175 SkIRect stepDstRect;
Brian Salomon1c86b632020-12-11 12:36:01 -05001176 if (nextDims == finalSize) {
Brian Salomone9ad9982019-07-22 16:17:41 -04001177 // Might as well fold conversion to final info in the last step.
Brian Salomon4bc0c1f2019-09-30 15:12:27 -04001178 xform = GrColorSpaceXform::Make(input->colorInfo().colorSpace(),
Brian Salomon1c86b632020-12-11 12:36:01 -05001179 input->colorInfo().alphaType(),
1180 dst->colorInfo().colorSpace(),
1181 dst->colorInfo().alphaType());
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001182 stepDst = dst;
1183 stepDstRect = dstRect;
Brian Salomon1c86b632020-12-11 12:36:01 -05001184 } else {
1185 tempB = GrSurfaceDrawContext::MakeWithFallback(fContext,
1186 input->colorInfo().colorType(),
1187 input->colorInfo().refColorSpace(),
1188 SkBackingFit::kApprox,
1189 nextDims,
1190 1,
1191 GrMipmapped::kNo,
1192 GrProtected::kNo,
1193 dst->origin());
1194 if (!tempB) {
1195 return false;
1196 }
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001197 stepDst = tempB.get();
1198 stepDstRect = SkIRect::MakeSize(tempB->dimensions());
Brian Salomone9ad9982019-07-22 16:17:41 -04001199 }
Mike Reed1efa14d2021-01-02 21:44:59 -05001200 if (rescaleMode == RescaleMode::kRepeatedCubic) {
Brian Salomon59f31b12020-06-04 17:27:15 -04001201 SkMatrix matrix;
1202 matrix.setScaleTranslate((float)srcRect.width()/nextDims.width(),
1203 (float)srcRect.height()/nextDims.height(),
1204 srcRect.x(),
1205 srcRect.y());
1206 std::unique_ptr<GrFragmentProcessor> fp;
1207 auto dir = GrBicubicEffect::Direction::kXY;
1208 if (nextDims.width() == srcRect.width()) {
1209 dir = GrBicubicEffect::Direction::kY;
1210 } else if (nextDims.height() == srcRect.height()) {
1211 dir = GrBicubicEffect::Direction::kX;
Brian Salomone9ad9982019-07-22 16:17:41 -04001212 }
Brian Salomon1af72d12020-06-25 10:47:26 -04001213 static constexpr auto kWM = GrSamplerState::WrapMode::kClamp;
Mike Reed3867c702020-09-01 13:28:10 -04001214 static constexpr auto kKernel = GrBicubicEffect::gCatmullRom;
Brian Salomon1c86b632020-12-11 12:36:01 -05001215 fp = GrBicubicEffect::MakeSubset(std::move(texView),
1216 input->colorInfo().alphaType(),
1217 matrix,
1218 kWM,
1219 kWM,
1220 SkRect::Make(srcRect),
1221 kKernel,
1222 dir,
1223 *this->caps());
Brian Salomon59f31b12020-06-04 17:27:15 -04001224 if (xform) {
1225 fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(xform));
Brian Salomone9ad9982019-07-22 16:17:41 -04001226 }
Brian Salomon59f31b12020-06-04 17:27:15 -04001227 GrPaint paint;
John Stiles5933d7d2020-07-21 12:28:35 -04001228 paint.setColorFragmentProcessor(std::move(fp));
Brian Salomon59f31b12020-06-04 17:27:15 -04001229 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001230 stepDst->fillRectToRect(nullptr,
1231 std::move(paint),
1232 GrAA::kNo,
1233 SkMatrix::I(),
1234 SkRect::Make(stepDstRect),
1235 SkRect::Make(stepDstRect));
Brian Salomon59f31b12020-06-04 17:27:15 -04001236 } else {
Mike Reed1efa14d2021-01-02 21:44:59 -05001237 auto filter = rescaleMode == RescaleMode::kNearest ? GrSamplerState::Filter::kNearest
1238 : GrSamplerState::Filter::kLinear;
Brian Salomon59f31b12020-06-04 17:27:15 -04001239 // Minimizing draw with integer coord src and dev rects can always be kFast.
1240 auto constraint = SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint;
1241 if (nextDims.width() <= srcRect.width() && nextDims.height() <= srcRect.height()) {
1242 constraint = SkCanvas::SrcRectConstraint::kFast_SrcRectConstraint;
1243 }
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001244 stepDst->drawTexture(nullptr,
1245 std::move(texView),
1246 srcAlphaType,
1247 filter,
1248 GrSamplerState::MipmapMode::kNone,
1249 SkBlendMode::kSrc,
1250 SK_PMColor4fWHITE,
1251 SkRect::Make(srcRect),
1252 SkRect::Make(stepDstRect),
1253 GrAA::kNo,
1254 GrQuadAAFlags::kNone,
1255 constraint,
1256 SkMatrix::I(),
1257 std::move(xform));
Brian Salomone9ad9982019-07-22 16:17:41 -04001258 }
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001259 texView = stepDst->readSurfaceView();
Brian Salomonbf6b9792019-08-21 09:38:10 -04001260 tempA = std::move(tempB);
Brian Salomonafd8a6c2020-05-21 12:10:54 -04001261 srcRect = SkIRect::MakeSize(nextDims);
Brian Salomone9ad9982019-07-22 16:17:41 -04001262 }
Brian Salomon1c86b632020-12-11 12:36:01 -05001263 return true;
Brian Salomone9ad9982019-07-22 16:17:41 -04001264}
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001265
1266GrSurfaceContext::PixelTransferResult GrSurfaceContext::transferPixels(GrColorType dstCT,
1267 const SkIRect& rect) {
1268 SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
1269 SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
Robert Phillipsf8f45d92020-07-01 11:11:18 -04001270 auto direct = fContext->asDirectContext();
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001271 if (!direct) {
1272 return {};
1273 }
1274 auto rtProxy = this->asRenderTargetProxy();
1275 if (rtProxy && rtProxy->wrapsVkSecondaryCB()) {
1276 return {};
1277 }
1278
1279 auto proxy = this->asSurfaceProxy();
Brian Salomon4bc0c1f2019-09-30 15:12:27 -04001280 auto supportedRead = this->caps()->supportedReadPixelsColorType(this->colorInfo().colorType(),
1281 proxy->backendFormat(), dstCT);
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001282 // Fail if read color type does not have all of dstCT's color channels and those missing color
1283 // channels are in the src.
Brian Salomon2f23ae62020-03-26 16:17:56 -04001284 uint32_t dstChannels = GrColorTypeChannelFlags(dstCT);
1285 uint32_t legalReadChannels = GrColorTypeChannelFlags(supportedRead.fColorType);
1286 uint32_t srcChannels = GrColorTypeChannelFlags(this->colorInfo().colorType());
1287 if ((~legalReadChannels & dstChannels) & srcChannels) {
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001288 return {};
1289 }
1290
Brian Salomonfb28c6f2020-01-10 13:04:45 -05001291 if (!this->caps()->transferFromSurfaceToBufferSupport() ||
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001292 !supportedRead.fOffsetAlignmentForTransferBuffer) {
1293 return {};
1294 }
1295
1296 size_t rowBytes = GrColorTypeBytesPerPixel(supportedRead.fColorType) * rect.width();
1297 size_t size = rowBytes * rect.height();
1298 auto buffer = direct->priv().resourceProvider()->createBuffer(
1299 size, GrGpuBufferType::kXferGpuToCpu, GrAccessPattern::kStream_GrAccessPattern);
1300 if (!buffer) {
1301 return {};
1302 }
1303 auto srcRect = rect;
Greg Danielb8d84f82020-02-13 14:25:00 -05001304 bool flip = this->origin() == kBottomLeft_GrSurfaceOrigin;
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001305 if (flip) {
1306 srcRect = SkIRect::MakeLTRB(rect.fLeft, this->height() - rect.fBottom, rect.fRight,
1307 this->height() - rect.fTop);
1308 }
Greg Danielbbfec9d2019-08-20 10:56:51 -04001309 this->drawingManager()->newTransferFromRenderTask(this->asSurfaceProxyRef(), srcRect,
Brian Salomon4bc0c1f2019-09-30 15:12:27 -04001310 this->colorInfo().colorType(),
Greg Danielbbfec9d2019-08-20 10:56:51 -04001311 supportedRead.fColorType, buffer, 0);
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001312 PixelTransferResult result;
1313 result.fTransferBuffer = std::move(buffer);
Brian Salomon4bc0c1f2019-09-30 15:12:27 -04001314 auto at = this->colorInfo().alphaType();
Brian Salomon8f8354a2019-07-31 20:12:02 -04001315 if (supportedRead.fColorType != dstCT || flip) {
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001316 result.fPixelConverter = [w = rect.width(), h = rect.height(), dstCT, supportedRead, at](
1317 void* dst, const void* src) {
Brian Salomonf2ebdd92019-09-30 12:15:30 -04001318 GrImageInfo srcInfo(supportedRead.fColorType, at, nullptr, w, h);
1319 GrImageInfo dstInfo(dstCT, at, nullptr, w, h);
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001320 GrConvertPixels(dstInfo, dst, dstInfo.minRowBytes(),
1321 srcInfo, src, srcInfo.minRowBytes(),
Brian Salomon8f8354a2019-07-31 20:12:02 -04001322 /* flipY = */ false);
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001323 };
1324 }
1325 return result;
1326}
Greg Daniel46e366a2019-12-16 14:38:36 -05001327
1328#ifdef SK_DEBUG
1329void GrSurfaceContext::validate() const {
Greg Daniel3912a4b2020-01-14 09:56:04 -05001330 SkASSERT(fReadView.proxy());
1331 fReadView.proxy()->validate(fContext);
Brian Salomonc5243782020-04-02 12:50:34 -04001332 if (this->colorInfo().colorType() != GrColorType::kUnknown) {
1333 SkASSERT(fContext->priv().caps()->areColorTypeAndFormatCompatible(
1334 this->colorInfo().colorType(), fReadView.proxy()->backendFormat()));
1335 }
Greg Daniel46e366a2019-12-16 14:38:36 -05001336 this->onValidate();
1337}
1338#endif