blob: 9c1784a670e1db3131d30b5d0b00b2796105b7a9 [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
Brian Salomon7f296c42021-01-13 14:56:55 +0000136// 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
139// 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
Brian Salomon982127b2021-01-21 10:43:35 -0500188 sk_sp<GrSurfaceProxy> srcProxy = this->asSurfaceProxyRef();
Greg Daniel6eb8c242019-06-05 10:22:24 -0400189
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) {
Brian Salomon982127b2021-01-21 10:43:35 -0500277 copy = GrSurfaceProxy::Copy(fContext,
278 std::move(srcProxy),
279 this->origin(),
280 kMipMapped,
281 kFit,
Brian Salomon72c7b982020-10-06 10:07:38 -0400282 kBudgeted);
283 } else {
Brian Salomondd4087d2020-12-23 20:36:44 -0500284 auto srcRect = SkIRect::MakePtSize(pt, dst.dimensions());
Brian Salomon982127b2021-01-21 10:43:35 -0500285 copy = GrSurfaceProxy::Copy(fContext,
286 std::move(srcProxy),
287 this->origin(),
288 kMipMapped,
289 srcRect,
290 kFit,
291 kBudgeted,
292 restrictions.fRectsMustMatch);
Brian Salomon72c7b982020-10-06 10:07:38 -0400293 pt = {0, 0};
294 }
295 if (!copy) {
296 return false;
297 }
298 GrSurfaceProxyView view{std::move(copy), this->origin(), this->readSwizzle()};
Brian Salomon14f99fc2020-12-07 12:19:47 -0500299 tempCtx = GrSurfaceContext::Make(dContext, std::move(view), this->colorInfo());
Brian Salomon72c7b982020-10-06 10:07:38 -0400300 SkASSERT(tempCtx);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400301 }
Brian Salomondd4087d2020-12-23 20:36:44 -0500302 return tempCtx->readPixels(dContext, dst, pt);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400303 }
304
Greg Danielb8d84f82020-02-13 14:25:00 -0500305 bool flip = this->origin() == kBottomLeft_GrSurfaceOrigin;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400306
Brian Salomon1d435302019-07-01 13:05:28 -0400307 auto supportedRead = caps->supportedReadPixelsColorType(
Brian Salomondd4087d2020-12-23 20:36:44 -0500308 this->colorInfo().colorType(), srcProxy->backendFormat(), dst.colorType());
Brian Salomon1d435302019-07-01 13:05:28 -0400309
Brian Salomondd4087d2020-12-23 20:36:44 -0500310 bool makeTight =
311 !caps->readPixelsRowBytesSupport() && dst.rowBytes() != dst.info().minRowBytes();
Brian Salomon1047a492019-07-02 12:25:21 -0400312
313 bool convert = unpremul || premul || needColorConversion || flip || makeTight ||
Brian Salomondd4087d2020-12-23 20:36:44 -0500314 (dst.colorType() != supportedRead.fColorType);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400315
Brian Salomonf30b1c12019-06-20 12:25:02 -0400316 std::unique_ptr<char[]> tmpPixels;
Brian Salomondd4087d2020-12-23 20:36:44 -0500317 GrPixmap tmp;
318 void* readDst = dst.addr();
319 size_t readRB = dst.rowBytes();
Greg Daniel6eb8c242019-06-05 10:22:24 -0400320 if (convert) {
Brian Salomondd4087d2020-12-23 20:36:44 -0500321 GrImageInfo tmpInfo(supportedRead.fColorType,
322 this->colorInfo().alphaType(),
323 this->colorInfo().refColorSpace(),
324 dst.dimensions());
Brian Salomon1d435302019-07-01 13:05:28 -0400325 size_t tmpRB = tmpInfo.minRowBytes();
326 size_t size = tmpRB * tmpInfo.height();
327 // Chrome MSAN bots require the data to be initialized (hence the ()).
John Stilesfbd050b2020-08-03 13:21:46 -0400328 tmpPixels = std::make_unique<char[]>(size);
Brian Salomondd4087d2020-12-23 20:36:44 -0500329 tmp = {tmpInfo, tmpPixels.get(), tmpRB};
Brian Salomonf30b1c12019-06-20 12:25:02 -0400330
Brian Salomonf30b1c12019-06-20 12:25:02 -0400331 readDst = tmpPixels.get();
Brian Salomon1d435302019-07-01 13:05:28 -0400332 readRB = tmpRB;
Brian Salomondd4087d2020-12-23 20:36:44 -0500333 pt.fY = flip ? srcSurface->height() - pt.fY - dst.height() : pt.fY;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400334 }
335
Brian Salomon982127b2021-01-21 10:43:35 -0500336 dContext->priv().flushSurface(srcProxy.get());
Adlai Hollerc95b5892020-08-11 12:02:22 -0400337 dContext->submit();
Brian Salomondd4087d2020-12-23 20:36:44 -0500338 if (!dContext->priv().getGpu()->readPixels(srcSurface, pt.fX, pt.fY, dst.width(), dst.height(),
339 this->colorInfo().colorType(),
Adlai Hollerc95b5892020-08-11 12:02:22 -0400340 supportedRead.fColorType, readDst, readRB)) {
Greg Daniel6eb8c242019-06-05 10:22:24 -0400341 return false;
342 }
343
Brian Salomondd4087d2020-12-23 20:36:44 -0500344 if (tmp.hasPixels()) {
345 return GrConvertPixels(dst, tmp, flip);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400346 }
347 return true;
348}
Robert Phillips0d075de2019-03-04 11:08:13 -0500349
Brian Salomondd4087d2020-12-23 20:36:44 -0500350bool GrSurfaceContext::writePixels(GrDirectContext* dContext, GrPixmap src, SkIPoint pt) {
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400351 ASSERT_SINGLE_OWNER
352 RETURN_FALSE_IF_ABANDONED
353 SkDEBUGCODE(this->validate();)
Brian Salomon1d435302019-07-01 13:05:28 -0400354 GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrSurfaceContext::writePixels");
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400355
Adlai Hollerc95b5892020-08-11 12:02:22 -0400356 if (!dContext) {
Brian Salomonc320b152018-02-20 14:05:36 -0500357 return false;
358 }
Robert Phillips6a6de562019-02-15 15:19:15 -0500359
Brian Salomon1d435302019-07-01 13:05:28 -0400360 if (this->asSurfaceProxy()->readOnly()) {
Robert Phillips6a6de562019-02-15 15:19:15 -0500361 return false;
362 }
363
Brian Salomondd4087d2020-12-23 20:36:44 -0500364 src = src.clip(this->dimensions(), &pt);
365 if (!src.hasPixels()) {
Brian Salomon1d435302019-07-01 13:05:28 -0400366 return false;
367 }
Brian Salomondd4087d2020-12-23 20:36:44 -0500368 if (!alpha_types_compatible(src.alphaType(), this->colorInfo().alphaType())) {
Greg Daniel6eb8c242019-06-05 10:22:24 -0400369 return false;
370 }
371
372 GrSurfaceProxy* dstProxy = this->asSurfaceProxy();
Stephen White3c0a50f2020-01-16 18:19:54 -0500373
374 if (dstProxy->framebufferOnly()) {
375 return false;
376 }
377
Adlai Hollerc95b5892020-08-11 12:02:22 -0400378 if (!dstProxy->instantiate(dContext->priv().resourceProvider())) {
Greg Daniel6eb8c242019-06-05 10:22:24 -0400379 return false;
380 }
381
382 GrSurface* dstSurface = dstProxy->peekSurface();
383
Brian Salomondd4087d2020-12-23 20:36:44 -0500384 SkColorSpaceXformSteps::Flags flags =
385 SkColorSpaceXformSteps{src.info(), this->colorInfo()}.flags;
Mike Klein7321e6a2019-12-03 11:08:40 -0600386 bool unpremul = flags.unpremul,
387 needColorConversion = flags.linearize || flags.gamut_transform || flags.encode,
388 premul = flags.premul;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400389
Adlai Hollerc95b5892020-08-11 12:02:22 -0400390 const GrCaps* caps = dContext->priv().caps();
Greg Daniel7bfc9132019-08-14 14:23:53 -0400391
392 auto rgbaDefaultFormat = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
393 GrRenderable::kNo);
394
Greg Danielc71c7962020-01-14 16:44:18 -0500395 GrColorType dstColorType = this->colorInfo().colorType();
Greg Daniel6eb8c242019-06-05 10:22:24 -0400396 // For canvas2D putImageData performance we have a special code path for unpremul RGBA_8888 srcs
397 // that are premultiplied on the GPU. This is kept as narrow as possible for now.
Brian Salomon1d435302019-07-01 13:05:28 -0400398 bool canvas2DFastPath = !caps->avoidWritePixelsFastPath() && premul && !needColorConversion &&
Brian Salomondd4087d2020-12-23 20:36:44 -0500399 (src.colorType() == GrColorType::kRGBA_8888 ||
400 src.colorType() == GrColorType::kBGRA_8888) &&
Brian Salomon590f5672020-12-16 11:44:47 -0500401 this->asFillContext() &&
Greg Danielc71c7962020-01-14 16:44:18 -0500402 (dstColorType == GrColorType::kRGBA_8888 ||
403 dstColorType == GrColorType::kBGRA_8888) &&
Greg Daniel7bfc9132019-08-14 14:23:53 -0400404 rgbaDefaultFormat.isValid() &&
Adlai Hollerc95b5892020-08-11 12:02:22 -0400405 dContext->priv().validPMUPMConversionExists();
Greg Daniel6eb8c242019-06-05 10:22:24 -0400406
407 if (!caps->surfaceSupportsWritePixels(dstSurface) || canvas2DFastPath) {
Brian Salomon14f99fc2020-12-07 12:19:47 -0500408 GrColorInfo tempColorInfo;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400409 GrBackendFormat format;
Greg Danielbfa19c42019-12-19 16:41:40 -0500410 GrSwizzle tempReadSwizzle;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400411 if (canvas2DFastPath) {
Brian Salomon14f99fc2020-12-07 12:19:47 -0500412 tempColorInfo = {GrColorType::kRGBA_8888,
413 kUnpremul_SkAlphaType,
414 this->colorInfo().refColorSpace()};
Greg Daniel7bfc9132019-08-14 14:23:53 -0400415 format = rgbaDefaultFormat;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400416 } else {
Brian Salomon14f99fc2020-12-07 12:19:47 -0500417 tempColorInfo = this->colorInfo();
Greg Daniel6eb8c242019-06-05 10:22:24 -0400418 format = dstProxy->backendFormat().makeTexture2D();
419 if (!format.isValid()) {
420 return false;
421 }
Greg Danielbfa19c42019-12-19 16:41:40 -0500422 tempReadSwizzle = this->readSwizzle();
Greg Daniel6eb8c242019-06-05 10:22:24 -0400423 }
424
Greg Daniel2e52ad12019-06-13 10:04:16 -0400425 // It is more efficient for us to write pixels into a top left origin so we prefer that.
426 // However, if the final proxy isn't a render target then we must use a copy to move the
427 // data into it which requires the origins to match. If the final proxy is a render target
428 // we can use a draw instead which doesn't have this origin restriction. Thus for render
429 // targets we will use top left and otherwise we will make the origins match.
Brian Salomonf30b1c12019-06-20 12:25:02 -0400430 GrSurfaceOrigin tempOrigin =
Brian Salomon590f5672020-12-16 11:44:47 -0500431 this->asFillContext() ? kTopLeft_GrSurfaceOrigin : this->origin();
Adlai Hollerc95b5892020-08-11 12:02:22 -0400432 auto tempProxy = dContext->priv().proxyProvider()->createProxy(
Brian Salomondd4087d2020-12-23 20:36:44 -0500433 format, src.dimensions(), GrRenderable::kNo, 1, GrMipmapped::kNo,
Brian Salomondf1bd6d2020-03-26 20:37:01 -0400434 SkBackingFit::kApprox, SkBudgeted::kYes, GrProtected::kNo);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400435 if (!tempProxy) {
436 return false;
437 }
Greg Daniel3912a4b2020-01-14 09:56:04 -0500438 GrSurfaceProxyView tempView(tempProxy, tempOrigin, tempReadSwizzle);
Brian Salomon14f99fc2020-12-07 12:19:47 -0500439 GrSurfaceContext tempCtx(dContext, tempView, tempColorInfo);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400440
441 // In the fast path we always write the srcData to the temp context as though it were RGBA.
442 // When the data is really BGRA the write will cause the R and B channels to be swapped in
443 // the intermediate surface which gets corrected by a swizzle effect when drawing to the
444 // dst.
Brian Salomondd4087d2020-12-23 20:36:44 -0500445 GrColorType origSrcColorType = src.colorType();
Brian Salomon1d435302019-07-01 13:05:28 -0400446 if (canvas2DFastPath) {
Brian Salomondd4087d2020-12-23 20:36:44 -0500447 src = {src.info().makeColorType(GrColorType::kRGBA_8888), src.addr(), src.rowBytes()};
Brian Salomon1d435302019-07-01 13:05:28 -0400448 }
Brian Salomondd4087d2020-12-23 20:36:44 -0500449 if (!tempCtx.writePixels(dContext, src, {0, 0})) {
Greg Daniel6eb8c242019-06-05 10:22:24 -0400450 return false;
451 }
452
Brian Salomon590f5672020-12-16 11:44:47 -0500453 if (this->asFillContext()) {
Greg Daniel46cfbc62019-06-07 11:43:30 -0400454 std::unique_ptr<GrFragmentProcessor> fp;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400455 if (canvas2DFastPath) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400456 fp = dContext->priv().createUPMToPMEffect(
Brian Salomon14f99fc2020-12-07 12:19:47 -0500457 GrTextureEffect::Make(std::move(tempView), tempColorInfo.alphaType()));
Brian Salomon1d435302019-07-01 13:05:28 -0400458 // Important: check the original src color type here!
Brian Salomondd4087d2020-12-23 20:36:44 -0500459 if (origSrcColorType == GrColorType::kBGRA_8888) {
Greg Daniel6eb8c242019-06-05 10:22:24 -0400460 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
461 }
462 } else {
Brian Salomon14f99fc2020-12-07 12:19:47 -0500463 fp = GrTextureEffect::Make(std::move(tempView), tempColorInfo.alphaType());
Greg Daniel6eb8c242019-06-05 10:22:24 -0400464 }
465 if (!fp) {
466 return false;
467 }
Brian Salomondd4087d2020-12-23 20:36:44 -0500468 this->asFillContext()->fillRectToRectWithFP(SkIRect::MakeSize(src.dimensions()),
469 SkIRect::MakePtSize(pt, src.dimensions()),
470 std::move(fp));
Greg Daniel6eb8c242019-06-05 10:22:24 -0400471 } else {
Brian Salomondd4087d2020-12-23 20:36:44 -0500472 SkIRect srcRect = SkIRect::MakeSize(src.dimensions());
Brian Salomon1d435302019-07-01 13:05:28 -0400473 SkIPoint dstPoint = SkIPoint::Make(pt.fX, pt.fY);
Brian Salomon982127b2021-01-21 10:43:35 -0500474 if (!this->copy(std::move(tempProxy), srcRect, dstPoint)) {
Greg Daniel6eb8c242019-06-05 10:22:24 -0400475 return false;
476 }
Greg Daniel6eb8c242019-06-05 10:22:24 -0400477 }
478 return true;
479 }
480
Brian Salomon1d435302019-07-01 13:05:28 -0400481 GrColorType allowedColorType =
Brian Salomon4bc0c1f2019-09-30 15:12:27 -0400482 caps->supportedWritePixelsColorType(this->colorInfo().colorType(),
Brian Salomon01915c02019-08-02 09:57:21 -0400483 dstProxy->backendFormat(),
Brian Salomondd4087d2020-12-23 20:36:44 -0500484 src.colorType()).fColorType;
Greg Danielb8d84f82020-02-13 14:25:00 -0500485 bool flip = this->origin() == kBottomLeft_GrSurfaceOrigin;
Brian Salomondd4087d2020-12-23 20:36:44 -0500486 bool makeTight = !caps->writePixelsRowBytesSupport() &&
487 src.rowBytes() != src.info().minRowBytes();
Brian Salomon1047a492019-07-02 12:25:21 -0400488 bool convert = premul || unpremul || needColorConversion || makeTight ||
Brian Salomondd4087d2020-12-23 20:36:44 -0500489 (src.colorType() != allowedColorType) || flip;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400490
Brian Salomonf30b1c12019-06-20 12:25:02 -0400491 std::unique_ptr<char[]> tmpPixels;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400492 if (convert) {
Brian Salomondd4087d2020-12-23 20:36:44 -0500493 GrImageInfo tmpInfo(allowedColorType,
494 this->colorInfo().alphaType(),
495 this->colorInfo().refColorSpace(),
496 src.dimensions());
Brian Salomon1d435302019-07-01 13:05:28 -0400497 auto tmpRB = tmpInfo.minRowBytes();
498 tmpPixels.reset(new char[tmpRB * tmpInfo.height()]);
Brian Salomondd4087d2020-12-23 20:36:44 -0500499 GrPixmap tmp(tmpInfo, tmpPixels.get(), tmpRB);
Brian Salomonf30b1c12019-06-20 12:25:02 -0400500
Brian Salomondd4087d2020-12-23 20:36:44 -0500501 SkAssertResult(GrConvertPixels(tmp, src, flip));
Brian Salomonf30b1c12019-06-20 12:25:02 -0400502
Brian Salomondd4087d2020-12-23 20:36:44 -0500503 src = tmp;
Brian Salomon1d435302019-07-01 13:05:28 -0400504 pt.fY = flip ? dstSurface->height() - pt.fY - tmpInfo.height() : pt.fY;
Greg Daniel6eb8c242019-06-05 10:22:24 -0400505 }
506
507 // On platforms that prefer flushes over VRAM use (i.e., ANGLE) we're better off forcing a
508 // complete flush here. On platforms that prefer VRAM use over flushes we're better off
509 // giving the drawing manager the chance of skipping the flush (i.e., by passing in the
510 // destination proxy)
511 // TODO: should this policy decision just be moved into the drawing manager?
Adlai Hollerc95b5892020-08-11 12:02:22 -0400512 dContext->priv().flushSurface(caps->preferVRAMUseOverFlushes() ? dstProxy : nullptr);
Greg Daniel6eb8c242019-06-05 10:22:24 -0400513
Brian Salomondd4087d2020-12-23 20:36:44 -0500514 return dContext->priv().getGpu()->writePixels(dstSurface, pt.fX, pt.fY, src.width(),
515 src.height(), this->colorInfo().colorType(),
516 src.colorType(), src.addr(), src.rowBytes());
Brian Osman45580d32016-11-23 09:37:01 -0500517}
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400518
Adlai Hollerc95b5892020-08-11 12:02:22 -0400519void GrSurfaceContext::asyncRescaleAndReadPixels(GrDirectContext* dContext,
520 const SkImageInfo& info,
Brian Salomon63a0a752020-06-26 13:32:09 -0400521 const SkIRect& srcRect,
522 RescaleGamma rescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -0500523 RescaleMode rescaleMode,
Brian Salomon63a0a752020-06-26 13:32:09 -0400524 ReadPixelsCallback callback,
Adlai Hollerc95b5892020-08-11 12:02:22 -0400525 ReadPixelsContext callbackContext) {
Brian Salomon7f296c42021-01-13 14:56:55 +0000526 // We implement this by rendering and we don't currently support rendering kUnpremul.
527 if (info.alphaType() == kUnpremul_SkAlphaType) {
528 callback(callbackContext, nullptr);
529 return;
530 }
Adlai Hollerc95b5892020-08-11 12:02:22 -0400531 if (!dContext) {
532 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400533 return;
534 }
535 auto rt = this->asRenderTargetProxy();
536 if (rt && rt->wrapsVkSecondaryCB()) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400537 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400538 return;
539 }
540 if (rt && rt->framebufferOnly()) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400541 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400542 return;
543 }
544 auto dstCT = SkColorTypeToGrColorType(info.colorType());
545 if (dstCT == GrColorType::kUnknown) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400546 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400547 return;
548 }
Brian Salomon7f296c42021-01-13 14:56:55 +0000549 bool needsRescale = srcRect.width() != info.width() || srcRect.height() != info.height();
Brian Salomon63a0a752020-06-26 13:32:09 -0400550 auto colorTypeOfFinalContext = this->colorInfo().colorType();
551 auto backendFormatOfFinalContext = this->asSurfaceProxy()->backendFormat();
552 if (needsRescale) {
553 colorTypeOfFinalContext = dstCT;
554 backendFormatOfFinalContext =
555 this->caps()->getDefaultBackendFormat(dstCT, GrRenderable::kYes);
556 }
557 auto readInfo = this->caps()->supportedReadPixelsColorType(colorTypeOfFinalContext,
Brian Salomon7f296c42021-01-13 14:56:55 +0000558 backendFormatOfFinalContext, dstCT);
Brian Salomon63a0a752020-06-26 13:32:09 -0400559 // Fail if we can't read from the source surface's color type.
560 if (readInfo.fColorType == GrColorType::kUnknown) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400561 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400562 return;
563 }
564 // Fail if read color type does not have all of dstCT's color channels and those missing color
565 // channels are in the src.
566 uint32_t dstChannels = GrColorTypeChannelFlags(dstCT);
567 uint32_t legalReadChannels = GrColorTypeChannelFlags(readInfo.fColorType);
568 uint32_t srcChannels = GrColorTypeChannelFlags(this->colorInfo().colorType());
569 if ((~legalReadChannels & dstChannels) & srcChannels) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400570 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400571 return;
572 }
573
Brian Salomon7f296c42021-01-13 14:56:55 +0000574 std::unique_ptr<GrSurfaceDrawContext> tempRTC;
Brian Salomon63a0a752020-06-26 13:32:09 -0400575 int x = srcRect.fLeft;
576 int y = srcRect.fTop;
577 if (needsRescale) {
Brian Salomon7f296c42021-01-13 14:56:55 +0000578 tempRTC = this->rescale(info, kTopLeft_GrSurfaceOrigin, srcRect, rescaleGamma, rescaleMode);
579 if (!tempRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400580 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400581 return;
582 }
Brian Salomon7f296c42021-01-13 14:56:55 +0000583 SkASSERT(SkColorSpace::Equals(tempRTC->colorInfo().colorSpace(), info.colorSpace()));
584 SkASSERT(tempRTC->origin() == kTopLeft_GrSurfaceOrigin);
Brian Salomon63a0a752020-06-26 13:32:09 -0400585 x = y = 0;
586 } else {
Brian Salomon7f296c42021-01-13 14:56:55 +0000587 sk_sp<GrColorSpaceXform> xform = GrColorSpaceXform::Make(this->colorInfo().colorSpace(),
588 this->colorInfo().alphaType(),
589 info.colorSpace(),
590 info.alphaType());
Brian Salomon63a0a752020-06-26 13:32:09 -0400591 // Insert a draw to a temporary surface if we need to do a y-flip or color space conversion.
592 if (this->origin() == kBottomLeft_GrSurfaceOrigin || xform) {
593 GrSurfaceProxyView texProxyView = this->readSurfaceView();
Brian Salomon7f296c42021-01-13 14:56:55 +0000594 SkRect srcRectToDraw = SkRect::Make(srcRect);
Brian Salomon63a0a752020-06-26 13:32:09 -0400595 // If the src is not texturable first try to make a copy to a texture.
596 if (!texProxyView.asTextureProxy()) {
Brian Salomon7f296c42021-01-13 14:56:55 +0000597 texProxyView =
598 GrSurfaceProxyView::Copy(fContext, texProxyView, GrMipmapped::kNo, srcRect,
599 SkBackingFit::kApprox, SkBudgeted::kNo);
Brian Salomon63a0a752020-06-26 13:32:09 -0400600 if (!texProxyView) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400601 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400602 return;
603 }
604 SkASSERT(texProxyView.asTextureProxy());
Brian Salomon7f296c42021-01-13 14:56:55 +0000605 srcRectToDraw = SkRect::MakeWH(srcRect.width(), srcRect.height());
Brian Salomon63a0a752020-06-26 13:32:09 -0400606 }
Brian Salomon7f296c42021-01-13 14:56:55 +0000607 tempRTC = GrSurfaceDrawContext::Make(dContext, this->colorInfo().colorType(),
608 info.refColorSpace(), SkBackingFit::kApprox,
609 srcRect.size(), 1, GrMipmapped::kNo,
610 GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
611 if (!tempRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400612 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400613 return;
614 }
Brian Salomon7f296c42021-01-13 14:56:55 +0000615 tempRTC->drawTexture(nullptr,
616 std::move(texProxyView),
617 this->colorInfo().alphaType(),
618 GrSamplerState::Filter::kNearest,
619 GrSamplerState::MipmapMode::kNone,
620 SkBlendMode::kSrc,
621 SK_PMColor4fWHITE,
622 srcRectToDraw,
623 SkRect::MakeWH(srcRect.width(), srcRect.height()),
624 GrAA::kNo,
625 GrQuadAAFlags::kNone,
626 SkCanvas::kFast_SrcRectConstraint,
627 SkMatrix::I(),
628 std::move(xform));
Brian Salomon63a0a752020-06-26 13:32:09 -0400629 x = y = 0;
630 }
631 }
Brian Salomon7f296c42021-01-13 14:56:55 +0000632 auto rtc = tempRTC ? tempRTC.get() : this;
633 return rtc->asyncReadPixels(dContext, SkIRect::MakeXYWH(x, y, info.width(), info.height()),
634 info.colorType(), callback, callbackContext);
Brian Salomon63a0a752020-06-26 13:32:09 -0400635}
636
637class GrSurfaceContext::AsyncReadResult : public SkImage::AsyncReadResult {
638public:
639 AsyncReadResult(uint32_t inboxID) : fInboxID(inboxID) {}
640 ~AsyncReadResult() override {
641 for (int i = 0; i < fPlanes.count(); ++i) {
642 if (!fPlanes[i].fMappedBuffer) {
643 delete[] static_cast<const char*>(fPlanes[i].fData);
644 } else {
645 GrClientMappedBufferManager::BufferFinishedMessageBus::Post(
646 {std::move(fPlanes[i].fMappedBuffer), fInboxID});
647 }
648 }
649 }
650
651 int count() const override { return fPlanes.count(); }
652 const void* data(int i) const override { return fPlanes[i].fData; }
653 size_t rowBytes(int i) const override { return fPlanes[i].fRowBytes; }
654
655 bool addTransferResult(const PixelTransferResult& result,
656 SkISize dimensions,
657 size_t rowBytes,
658 GrClientMappedBufferManager* manager) {
659 SkASSERT(!result.fTransferBuffer->isMapped());
660 const void* mappedData = result.fTransferBuffer->map();
661 if (!mappedData) {
662 return false;
663 }
664 if (result.fPixelConverter) {
665 std::unique_ptr<char[]> convertedData(new char[rowBytes * dimensions.height()]);
666 result.fPixelConverter(convertedData.get(), mappedData);
667 this->addCpuPlane(std::move(convertedData), rowBytes);
668 result.fTransferBuffer->unmap();
669 } else {
670 manager->insert(result.fTransferBuffer);
671 this->addMappedPlane(mappedData, rowBytes, std::move(result.fTransferBuffer));
672 }
673 return true;
674 }
675
676 void addCpuPlane(std::unique_ptr<const char[]> data, size_t rowBytes) {
677 SkASSERT(data);
678 SkASSERT(rowBytes > 0);
679 fPlanes.emplace_back(data.release(), rowBytes, nullptr);
680 }
681
682private:
683 void addMappedPlane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> mappedBuffer) {
684 SkASSERT(data);
685 SkASSERT(rowBytes > 0);
686 SkASSERT(mappedBuffer);
687 SkASSERT(mappedBuffer->isMapped());
688 fPlanes.emplace_back(data, rowBytes, std::move(mappedBuffer));
689 }
690
691 struct Plane {
692 Plane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> buffer)
693 : fData(data), fRowBytes(rowBytes), fMappedBuffer(std::move(buffer)) {}
694 const void* fData;
695 size_t fRowBytes;
696 // If this is null then fData is heap alloc and must be delete[]ed as const char[].
697 sk_sp<GrGpuBuffer> fMappedBuffer;
698 };
699 SkSTArray<3, Plane> fPlanes;
700 uint32_t fInboxID;
701};
702
Adlai Hollerc95b5892020-08-11 12:02:22 -0400703void GrSurfaceContext::asyncReadPixels(GrDirectContext* dContext,
704 const SkIRect& rect,
Brian Salomon63a0a752020-06-26 13:32:09 -0400705 SkColorType colorType,
706 ReadPixelsCallback callback,
Adlai Hollerc95b5892020-08-11 12:02:22 -0400707 ReadPixelsContext callbackContext) {
Brian Salomon63a0a752020-06-26 13:32:09 -0400708 SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
709 SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
710
Adlai Hollerc95b5892020-08-11 12:02:22 -0400711 if (!dContext || this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
712 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400713 return;
714 }
715
Adlai Hollerc95b5892020-08-11 12:02:22 -0400716 auto mappedBufferManager = dContext->priv().clientMappedBufferManager();
Brian Salomon63a0a752020-06-26 13:32:09 -0400717
718 auto transferResult = this->transferPixels(SkColorTypeToGrColorType(colorType), rect);
719
720 if (!transferResult.fTransferBuffer) {
721 auto ii = SkImageInfo::Make(rect.size(), colorType, this->colorInfo().alphaType(),
722 this->colorInfo().refColorSpace());
723 auto result = std::make_unique<AsyncReadResult>(0);
724 std::unique_ptr<char[]> data(new char[ii.computeMinByteSize()]);
725 SkPixmap pm(ii, data.get(), ii.minRowBytes());
726 result->addCpuPlane(std::move(data), pm.rowBytes());
727
Adlai Hollerc95b5892020-08-11 12:02:22 -0400728 SkIPoint pt{rect.fLeft, rect.fTop};
Brian Salomondd4087d2020-12-23 20:36:44 -0500729 if (!this->readPixels(dContext, pm, pt)) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400730 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400731 return;
732 }
Adlai Hollerc95b5892020-08-11 12:02:22 -0400733 callback(callbackContext, std::move(result));
Brian Salomon63a0a752020-06-26 13:32:09 -0400734 return;
735 }
736
737 struct FinishContext {
738 ReadPixelsCallback* fClientCallback;
739 ReadPixelsContext fClientContext;
740 SkISize fSize;
741 SkColorType fColorType;
742 GrClientMappedBufferManager* fMappedBufferManager;
743 PixelTransferResult fTransferResult;
744 };
745 // Assumption is that the caller would like to flush. We could take a parameter or require an
746 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
747 // callback to GrGpu until after the next flush that flushes our op list, though.
748 auto* finishContext = new FinishContext{callback,
Adlai Hollerc95b5892020-08-11 12:02:22 -0400749 callbackContext,
Brian Salomon63a0a752020-06-26 13:32:09 -0400750 rect.size(),
751 colorType,
752 mappedBufferManager,
753 std::move(transferResult)};
754 auto finishCallback = [](GrGpuFinishedContext c) {
755 const auto* context = reinterpret_cast<const FinishContext*>(c);
756 auto result = std::make_unique<AsyncReadResult>(context->fMappedBufferManager->inboxID());
757 size_t rowBytes = context->fSize.width() * SkColorTypeBytesPerPixel(context->fColorType);
758 if (!result->addTransferResult(context->fTransferResult, context->fSize, rowBytes,
759 context->fMappedBufferManager)) {
760 result.reset();
761 }
762 (*context->fClientCallback)(context->fClientContext, std::move(result));
763 delete context;
764 };
765 GrFlushInfo flushInfo;
766 flushInfo.fFinishedContext = finishContext;
767 flushInfo.fFinishedProc = finishCallback;
Robert Phillips80bfda82020-11-12 09:23:36 -0500768
769 dContext->priv().flushSurface(this->asSurfaceProxy(),
770 SkSurface::BackendSurfaceAccess::kNoAccess,
771 flushInfo);
Brian Salomon63a0a752020-06-26 13:32:09 -0400772}
773
Adlai Hollerc95b5892020-08-11 12:02:22 -0400774void GrSurfaceContext::asyncRescaleAndReadPixelsYUV420(GrDirectContext* dContext,
775 SkYUVColorSpace yuvColorSpace,
Brian Salomon63a0a752020-06-26 13:32:09 -0400776 sk_sp<SkColorSpace> dstColorSpace,
777 const SkIRect& srcRect,
778 SkISize dstSize,
779 RescaleGamma rescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -0500780 RescaleMode rescaleMode,
Brian Salomon63a0a752020-06-26 13:32:09 -0400781 ReadPixelsCallback callback,
Adlai Hollerc95b5892020-08-11 12:02:22 -0400782 ReadPixelsContext callbackContext) {
Brian Salomon63a0a752020-06-26 13:32:09 -0400783 SkASSERT(srcRect.fLeft >= 0 && srcRect.fRight <= this->width());
784 SkASSERT(srcRect.fTop >= 0 && srcRect.fBottom <= this->height());
785 SkASSERT(!dstSize.isZero());
786 SkASSERT((dstSize.width() % 2 == 0) && (dstSize.height() % 2 == 0));
787
Adlai Hollerc95b5892020-08-11 12:02:22 -0400788 if (!dContext) {
789 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400790 return;
791 }
792 auto rt = this->asRenderTargetProxy();
793 if (rt && rt->wrapsVkSecondaryCB()) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400794 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400795 return;
796 }
797 if (rt && rt->framebufferOnly()) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400798 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400799 return;
800 }
801 if (this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400802 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400803 return;
804 }
805 int x = srcRect.fLeft;
806 int y = srcRect.fTop;
807 bool needsRescale = srcRect.size() != dstSize;
808 GrSurfaceProxyView srcView;
809 if (needsRescale) {
Brian Salomon7f296c42021-01-13 14:56:55 +0000810 // We assume the caller wants kPremul. There is no way to indicate a preference.
811 auto info = SkImageInfo::Make(dstSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
812 dstColorSpace);
Brian Salomon63a0a752020-06-26 13:32:09 -0400813 // TODO: Incorporate the YUV conversion into last pass of rescaling.
Brian Salomon7f296c42021-01-13 14:56:55 +0000814 auto tempRTC = this->rescale(info, kTopLeft_GrSurfaceOrigin, srcRect, rescaleGamma,
815 rescaleMode);
816 if (!tempRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400817 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400818 return;
819 }
Brian Salomon7f296c42021-01-13 14:56:55 +0000820 SkASSERT(SkColorSpace::Equals(tempRTC->colorInfo().colorSpace(), info.colorSpace()));
821 SkASSERT(tempRTC->origin() == kTopLeft_GrSurfaceOrigin);
Brian Salomon63a0a752020-06-26 13:32:09 -0400822 x = y = 0;
Brian Salomon7f296c42021-01-13 14:56:55 +0000823 srcView = tempRTC->readSurfaceView();
Brian Salomon63a0a752020-06-26 13:32:09 -0400824 } else {
825 srcView = this->readSurfaceView();
826 if (!srcView.asTextureProxy()) {
Brian Salomon7f296c42021-01-13 14:56:55 +0000827 srcView = GrSurfaceProxyView::Copy(fContext, std::move(srcView), GrMipmapped::kNo,
828 srcRect, SkBackingFit::kApprox, SkBudgeted::kYes);
Brian Salomon63a0a752020-06-26 13:32:09 -0400829 if (!srcView) {
830 // If we can't get a texture copy of the contents then give up.
Adlai Hollerc95b5892020-08-11 12:02:22 -0400831 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400832 return;
833 }
834 SkASSERT(srcView.asTextureProxy());
835 x = y = 0;
836 }
837 // We assume the caller wants kPremul. There is no way to indicate a preference.
Brian Salomon7f296c42021-01-13 14:56:55 +0000838 sk_sp<GrColorSpaceXform> xform = GrColorSpaceXform::Make(
839 this->colorInfo().colorSpace(), this->colorInfo().alphaType(), dstColorSpace.get(),
840 kPremul_SkAlphaType);
Brian Salomon63a0a752020-06-26 13:32:09 -0400841 if (xform) {
842 SkRect srcRectToDraw = SkRect::MakeXYWH(x, y, srcRect.width(), srcRect.height());
Brian Salomon7f296c42021-01-13 14:56:55 +0000843 auto tempRTC = GrSurfaceDrawContext::Make(
844 dContext, this->colorInfo().colorType(), dstColorSpace, SkBackingFit::kApprox,
845 dstSize, 1, GrMipmapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
846 if (!tempRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400847 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400848 return;
849 }
Brian Salomon7f296c42021-01-13 14:56:55 +0000850 tempRTC->drawTexture(nullptr,
851 std::move(srcView),
852 this->colorInfo().alphaType(),
853 GrSamplerState::Filter::kNearest,
854 GrSamplerState::MipmapMode::kNone,
855 SkBlendMode::kSrc,
856 SK_PMColor4fWHITE,
857 srcRectToDraw,
858 SkRect::Make(srcRect.size()),
859 GrAA::kNo,
860 GrQuadAAFlags::kNone,
861 SkCanvas::kFast_SrcRectConstraint,
862 SkMatrix::I(),
863 std::move(xform));
864 srcView = tempRTC->readSurfaceView();
Brian Salomon63a0a752020-06-26 13:32:09 -0400865 SkASSERT(srcView.asTextureProxy());
866 x = y = 0;
867 }
868 }
869
Brian Salomon7f296c42021-01-13 14:56:55 +0000870 auto yRTC = GrSurfaceDrawContext::MakeWithFallback(
871 dContext, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, dstSize, 1,
872 GrMipmapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
873 int halfW = dstSize.width() /2;
874 int halfH = dstSize.height()/2;
875 auto uRTC = GrSurfaceDrawContext::MakeWithFallback(
876 dContext, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, {halfW, halfH},
877 1, GrMipmapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
878 auto vRTC = GrSurfaceDrawContext::MakeWithFallback(
879 dContext, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, {halfW, halfH},
880 1, GrMipmapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
881 if (!yRTC || !uRTC || !vRTC) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400882 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400883 return;
884 }
885
886 float baseM[20];
887 SkColorMatrix_RGB2YUV(yuvColorSpace, baseM);
888
889 // TODO: Use one transfer buffer for all three planes to reduce map/unmap cost?
890
891 auto texMatrix = SkMatrix::Translate(x, y);
892
Brian Salomon7f296c42021-01-13 14:56:55 +0000893 SkRect dstRectY = SkRect::Make(dstSize);
894 SkRect dstRectUV = SkRect::MakeWH(halfW, halfH);
895
Brian Salomon63a0a752020-06-26 13:32:09 -0400896 bool doSynchronousRead = !this->caps()->transferFromSurfaceToBufferSupport();
897 PixelTransferResult yTransfer, uTransfer, vTransfer;
898
899 // This matrix generates (r,g,b,a) = (0, 0, 0, y)
900 float yM[20];
901 std::fill_n(yM, 15, 0.f);
902 std::copy_n(baseM + 0, 5, yM + 15);
Brian Salomon7f296c42021-01-13 14:56:55 +0000903 GrPaint yPaint;
904 auto yTexFP = GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix);
905 auto yColFP = GrColorMatrixFragmentProcessor::Make(std::move(yTexFP), yM,
906 /*unpremulInput=*/false,
907 /*clampRGBOutput=*/true,
908 /*premulOutput=*/false);
909 yPaint.setColorFragmentProcessor(std::move(yColFP));
910 yPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
911 yRTC->fillRectToRect(nullptr, std::move(yPaint), GrAA::kNo, SkMatrix::I(), dstRectY, dstRectY);
Brian Salomon63a0a752020-06-26 13:32:09 -0400912 if (!doSynchronousRead) {
Brian Salomon7f296c42021-01-13 14:56:55 +0000913 yTransfer = yRTC->transferPixels(GrColorType::kAlpha_8,
914 SkIRect::MakeWH(yRTC->width(), yRTC->height()));
Brian Salomon63a0a752020-06-26 13:32:09 -0400915 if (!yTransfer.fTransferBuffer) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400916 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400917 return;
918 }
919 }
920
921 texMatrix.preScale(2.f, 2.f);
922 // This matrix generates (r,g,b,a) = (0, 0, 0, u)
923 float uM[20];
924 std::fill_n(uM, 15, 0.f);
925 std::copy_n(baseM + 5, 5, uM + 15);
Brian Salomon7f296c42021-01-13 14:56:55 +0000926 GrPaint uPaint;
927 auto uTexFP = GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix,
928 GrSamplerState::Filter::kLinear);
929 auto uColFP = GrColorMatrixFragmentProcessor::Make(std::move(uTexFP), uM,
930 /*unpremulInput=*/false,
931 /*clampRGBOutput=*/true,
932 /*premulOutput=*/false);
933 uPaint.setColorFragmentProcessor(std::move(uColFP));
934 uPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
935 uRTC->fillRectToRect(nullptr, std::move(uPaint), GrAA::kNo, SkMatrix::I(), dstRectUV,
936 dstRectUV);
Brian Salomon63a0a752020-06-26 13:32:09 -0400937 if (!doSynchronousRead) {
Brian Salomon7f296c42021-01-13 14:56:55 +0000938 uTransfer = uRTC->transferPixels(GrColorType::kAlpha_8,
939 SkIRect::MakeWH(uRTC->width(), uRTC->height()));
Brian Salomon63a0a752020-06-26 13:32:09 -0400940 if (!uTransfer.fTransferBuffer) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400941 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400942 return;
943 }
944 }
945
946 // This matrix generates (r,g,b,a) = (0, 0, 0, v)
947 float vM[20];
948 std::fill_n(vM, 15, 0.f);
949 std::copy_n(baseM + 10, 5, vM + 15);
Brian Salomon7f296c42021-01-13 14:56:55 +0000950 GrPaint vPaint;
951 auto vTexFP = GrTextureEffect::Make(std::move(srcView), this->colorInfo().alphaType(),
952 texMatrix, GrSamplerState::Filter::kLinear);
953 auto vColFP = GrColorMatrixFragmentProcessor::Make(std::move(vTexFP), vM,
954 /*unpremulInput=*/false,
955 /*clampRGBOutput=*/true,
956 /*premulOutput=*/false);
957 vPaint.setColorFragmentProcessor(std::move(vColFP));
958 vPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
959 vRTC->fillRectToRect(nullptr, std::move(vPaint), GrAA::kNo, SkMatrix::I(), dstRectUV,
960 dstRectUV);
Brian Salomon63a0a752020-06-26 13:32:09 -0400961 if (!doSynchronousRead) {
Brian Salomon7f296c42021-01-13 14:56:55 +0000962 vTransfer = vRTC->transferPixels(GrColorType::kAlpha_8,
963 SkIRect::MakeWH(vRTC->width(), vRTC->height()));
Brian Salomon63a0a752020-06-26 13:32:09 -0400964 if (!vTransfer.fTransferBuffer) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400965 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400966 return;
967 }
968 }
969
970 if (doSynchronousRead) {
Brian Salomon7f296c42021-01-13 14:56:55 +0000971 GrImageInfo yInfo(GrColorType::kAlpha_8, kPremul_SkAlphaType, nullptr, dstSize);
972 GrImageInfo uvInfo = yInfo.makeWH(halfW, halfH);
Brian Salomondd4087d2020-12-23 20:36:44 -0500973 auto [yPmp, yStorage] = GrPixmap::Allocate(yInfo);
974 auto [uPmp, uStorage] = GrPixmap::Allocate(uvInfo);
975 auto [vPmp, vStorage] = GrPixmap::Allocate(uvInfo);
Brian Salomon7f296c42021-01-13 14:56:55 +0000976 if (!yRTC->readPixels(dContext, yPmp, {0, 0}) ||
977 !uRTC->readPixels(dContext, uPmp, {0, 0}) ||
978 !vRTC->readPixels(dContext, vPmp, {0, 0})) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400979 callback(callbackContext, nullptr);
Brian Salomon63a0a752020-06-26 13:32:09 -0400980 return;
981 }
Adlai Hollerc95b5892020-08-11 12:02:22 -0400982 auto result = std::make_unique<AsyncReadResult>(dContext->priv().contextID());
Brian Salomondd4087d2020-12-23 20:36:44 -0500983 result->addCpuPlane(std::move(yStorage), yPmp.rowBytes());
984 result->addCpuPlane(std::move(uStorage), uPmp.rowBytes());
985 result->addCpuPlane(std::move(vStorage), vPmp.rowBytes());
Adlai Hollerc95b5892020-08-11 12:02:22 -0400986 callback(callbackContext, std::move(result));
Brian Salomon63a0a752020-06-26 13:32:09 -0400987 return;
988 }
989
990 struct FinishContext {
991 ReadPixelsCallback* fClientCallback;
992 ReadPixelsContext fClientContext;
993 GrClientMappedBufferManager* fMappedBufferManager;
994 SkISize fSize;
995 PixelTransferResult fYTransfer;
996 PixelTransferResult fUTransfer;
997 PixelTransferResult fVTransfer;
998 };
999 // Assumption is that the caller would like to flush. We could take a parameter or require an
1000 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
1001 // callback to GrGpu until after the next flush that flushes our op list, though.
1002 auto* finishContext = new FinishContext{callback,
Adlai Hollerc95b5892020-08-11 12:02:22 -04001003 callbackContext,
1004 dContext->priv().clientMappedBufferManager(),
Brian Salomon63a0a752020-06-26 13:32:09 -04001005 dstSize,
1006 std::move(yTransfer),
1007 std::move(uTransfer),
1008 std::move(vTransfer)};
1009 auto finishCallback = [](GrGpuFinishedContext c) {
1010 const auto* context = reinterpret_cast<const FinishContext*>(c);
1011 auto result = std::make_unique<AsyncReadResult>(context->fMappedBufferManager->inboxID());
1012 auto manager = context->fMappedBufferManager;
1013 size_t rowBytes = SkToSizeT(context->fSize.width());
1014 if (!result->addTransferResult(context->fYTransfer, context->fSize, rowBytes, manager)) {
1015 (*context->fClientCallback)(context->fClientContext, nullptr);
1016 delete context;
1017 return;
1018 }
1019 rowBytes /= 2;
1020 SkISize uvSize = {context->fSize.width() / 2, context->fSize.height() / 2};
1021 if (!result->addTransferResult(context->fUTransfer, uvSize, rowBytes, manager)) {
1022 (*context->fClientCallback)(context->fClientContext, nullptr);
1023 delete context;
1024 return;
1025 }
1026 if (!result->addTransferResult(context->fVTransfer, uvSize, rowBytes, manager)) {
1027 (*context->fClientCallback)(context->fClientContext, nullptr);
1028 delete context;
1029 return;
1030 }
1031 (*context->fClientCallback)(context->fClientContext, std::move(result));
1032 delete context;
1033 };
1034 GrFlushInfo flushInfo;
1035 flushInfo.fFinishedContext = finishContext;
1036 flushInfo.fFinishedProc = finishCallback;
Robert Phillips80bfda82020-11-12 09:23:36 -05001037 dContext->priv().flushSurface(this->asSurfaceProxy(),
1038 SkSurface::BackendSurfaceAccess::kNoAccess,
1039 flushInfo);
Brian Salomon63a0a752020-06-26 13:32:09 -04001040}
1041
Brian Salomon982127b2021-01-21 10:43:35 -05001042bool GrSurfaceContext::copy(sk_sp<GrSurfaceProxy> src, SkIRect srcRect, SkIPoint dstPoint) {
Robert Phillips2de8cfa2017-06-28 10:33:41 -04001043 ASSERT_SINGLE_OWNER
1044 RETURN_FALSE_IF_ABANDONED
1045 SkDEBUGCODE(this->validate();)
Greg Daniel46cfbc62019-06-07 11:43:30 -04001046 GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrSurfaceContextPriv::copy");
Greg Daniel25af6712018-04-25 10:44:38 -04001047
Brian Salomon947efe22019-07-16 15:36:11 -04001048 const GrCaps* caps = fContext->priv().caps();
1049
Greg Daniel46cfbc62019-06-07 11:43:30 -04001050 SkASSERT(src->backendFormat().textureType() != GrTextureType::kExternal);
Greg Danielc71c7962020-01-14 16:44:18 -05001051 SkASSERT(src->backendFormat() == this->asSurfaceProxy()->backendFormat());
Greg Daniel46cfbc62019-06-07 11:43:30 -04001052
Stephen White3c0a50f2020-01-16 18:19:54 -05001053 if (this->asSurfaceProxy()->framebufferOnly()) {
1054 return false;
1055 }
1056
Brian Salomon982127b2021-01-21 10:43:35 -05001057 if (!caps->canCopySurface(this->asSurfaceProxy(), src.get(), srcRect, dstPoint)) {
Greg Daniel25af6712018-04-25 10:44:38 -04001058 return false;
1059 }
Robert Phillips2de8cfa2017-06-28 10:33:41 -04001060
Brian Salomon982127b2021-01-21 10:43:35 -05001061 if (!GrClipSrcRectAndDstPoint(this->dimensions(), src->dimensions(), srcRect, dstPoint,
1062 &srcRect, &dstPoint)) {
1063 return false;
1064 }
1065
1066 if (this->origin() == kBottomLeft_GrSurfaceOrigin) {
1067 int rectHeight = srcRect.height();
1068 srcRect.fTop = src->backingStoreDimensions().height() - srcRect.fBottom;
1069 srcRect.fBottom = srcRect.fTop + rectHeight;
1070 dstPoint.fY = this->asSurfaceProxy()->backingStoreDimensions().height() -
1071 (dstPoint.fY + rectHeight);
1072 }
1073 return this->drawingManager()->newCopyRenderTask(std::move(src),
1074 srcRect,
1075 this->asSurfaceProxyRef(),
1076 dstPoint);
Robert Phillips2de8cfa2017-06-28 10:33:41 -04001077}
Greg Daniel46cfbc62019-06-07 11:43:30 -04001078
Brian Salomon7f296c42021-01-13 14:56:55 +00001079std::unique_ptr<GrSurfaceDrawContext> GrSurfaceContext::rescale(const GrImageInfo& info,
Brian Salomoneebe7352020-12-09 16:37:04 -05001080 GrSurfaceOrigin origin,
1081 SkIRect srcRect,
1082 RescaleGamma rescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -05001083 RescaleMode rescaleMode) {
Brian Salomon7f296c42021-01-13 14:56:55 +00001084 // We rescale by drawing and currently only support drawing to premul.
1085 if (info.alphaType() != kPremul_SkAlphaType) {
1086 return nullptr;
1087 }
1088 auto sdc = GrSurfaceDrawContext::MakeWithFallback(fContext,
1089 info.colorType(),
1090 info.refColorSpace(),
Brian Salomon1c86b632020-12-11 12:36:01 -05001091 SkBackingFit::kExact,
Brian Salomon7f296c42021-01-13 14:56:55 +00001092 info.dimensions(),
Brian Salomon1c86b632020-12-11 12:36:01 -05001093 1,
1094 GrMipmapped::kNo,
1095 this->asSurfaceProxy()->isProtected(),
1096 origin);
Brian Salomon7f296c42021-01-13 14:56:55 +00001097 if (!sdc || !this->rescaleInto(sdc.get(),
1098 SkIRect::MakeSize(sdc->dimensions()),
Brian Salomon1c86b632020-12-11 12:36:01 -05001099 srcRect,
1100 rescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -05001101 rescaleMode)) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001102 return nullptr;
1103 }
Brian Salomon7f296c42021-01-13 14:56:55 +00001104 return sdc;
Brian Salomon1c86b632020-12-11 12:36:01 -05001105}
1106
Brian Salomon7f296c42021-01-13 14:56:55 +00001107bool GrSurfaceContext::rescaleInto(GrSurfaceDrawContext* dst,
Brian Salomon1c86b632020-12-11 12:36:01 -05001108 SkIRect dstRect,
1109 SkIRect srcRect,
1110 RescaleGamma rescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -05001111 RescaleMode rescaleMode) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001112 SkASSERT(dst);
1113 if (!SkIRect::MakeSize(dst->dimensions()).contains((dstRect))) {
1114 return false;
1115 }
1116
Brian Salomone9ad9982019-07-22 16:17:41 -04001117 auto rtProxy = this->asRenderTargetProxy();
1118 if (rtProxy && rtProxy->wrapsVkSecondaryCB()) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001119 return false;
Brian Salomone9ad9982019-07-22 16:17:41 -04001120 }
1121
Stephen White3c0a50f2020-01-16 18:19:54 -05001122 if (this->asSurfaceProxy()->framebufferOnly()) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001123 return false;
Brian Salomone9ad9982019-07-22 16:17:41 -04001124 }
1125
Greg Daniel40903af2020-01-30 14:55:05 -05001126 GrSurfaceProxyView texView = this->readSurfaceView();
Brian Salomon7f296c42021-01-13 14:56:55 +00001127 SkAlphaType srcAlphaType = this->colorInfo().alphaType();
Greg Daniel40903af2020-01-30 14:55:05 -05001128 if (!texView.asTextureProxy()) {
Brian Salomon7e67dca2020-07-21 09:27:25 -04001129 texView = GrSurfaceProxyView::Copy(fContext, std::move(texView), GrMipmapped::kNo, srcRect,
Brian Salomonc5243782020-04-02 12:50:34 -04001130 SkBackingFit::kApprox, SkBudgeted::kNo);
1131 if (!texView) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001132 return false;
Brian Salomone9ad9982019-07-22 16:17:41 -04001133 }
Greg Daniel40903af2020-01-30 14:55:05 -05001134 SkASSERT(texView.asTextureProxy());
Brian Salomonafd8a6c2020-05-21 12:10:54 -04001135 srcRect = SkIRect::MakeSize(srcRect.size());
Brian Salomone9ad9982019-07-22 16:17:41 -04001136 }
1137
Brian Salomon1c86b632020-12-11 12:36:01 -05001138 SkISize finalSize = dstRect.size();
1139
Brian Salomonbf6b9792019-08-21 09:38:10 -04001140 // Within a rescaling pass A is the input (if not null) and B is the output. At the end of the
1141 // pass B is moved to A. If 'this' is the input on the first pass then tempA is null.
Brian Salomon7f296c42021-01-13 14:56:55 +00001142 std::unique_ptr<GrSurfaceDrawContext> tempA;
1143 std::unique_ptr<GrSurfaceDrawContext> tempB;
Brian Salomonbf6b9792019-08-21 09:38:10 -04001144
Brian Salomone9ad9982019-07-22 16:17:41 -04001145 // Assume we should ignore the rescale linear request if the surface has no color space since
1146 // it's unclear how we'd linearize from an unknown color space.
Brian Salomon63a0a752020-06-26 13:32:09 -04001147 if (rescaleGamma == RescaleGamma::kLinear && this->colorInfo().colorSpace() &&
Brian Salomon4bc0c1f2019-09-30 15:12:27 -04001148 !this->colorInfo().colorSpace()->gammaIsLinear()) {
1149 auto cs = this->colorInfo().colorSpace()->makeLinearGamma();
Brian Salomon7f296c42021-01-13 14:56:55 +00001150 auto xform = GrColorSpaceXform::Make(this->colorInfo().colorSpace(), srcAlphaType, cs.get(),
1151 kPremul_SkAlphaType);
Brian Salomone9ad9982019-07-22 16:17:41 -04001152 // We'll fall back to kRGBA_8888 if half float not supported.
Brian Salomon7f296c42021-01-13 14:56:55 +00001153 auto linearRTC = GrSurfaceDrawContext::MakeWithFallback(
1154 fContext, GrColorType::kRGBA_F16, cs, SkBackingFit::kApprox, srcRect.size(), 1,
1155 GrMipmapped::kNo, GrProtected::kNo, dst->origin());
Brian Salomone9ad9982019-07-22 16:17:41 -04001156 if (!linearRTC) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001157 return false;
Brian Salomone9ad9982019-07-22 16:17:41 -04001158 }
Brian Salomon7f296c42021-01-13 14:56:55 +00001159 // 1-to-1 draw can always be kFast.
1160 linearRTC->drawTexture(nullptr,
1161 std::move(texView),
1162 srcAlphaType,
1163 GrSamplerState::Filter::kNearest,
1164 GrSamplerState::MipmapMode::kNone,
1165 SkBlendMode::kSrc,
1166 SK_PMColor4fWHITE,
1167 SkRect::Make(srcRect),
1168 SkRect::Make(srcRect.size()),
1169 GrAA::kNo,
1170 GrQuadAAFlags::kNone,
1171 SkCanvas::kFast_SrcRectConstraint,
1172 SkMatrix::I(),
1173 std::move(xform));
Greg Daniel40903af2020-01-30 14:55:05 -05001174 texView = linearRTC->readSurfaceView();
1175 SkASSERT(texView.asTextureProxy());
Brian Salomonbf6b9792019-08-21 09:38:10 -04001176 tempA = std::move(linearRTC);
Brian Salomonafd8a6c2020-05-21 12:10:54 -04001177 srcRect = SkIRect::MakeSize(srcRect.size());
Brian Salomone9ad9982019-07-22 16:17:41 -04001178 }
Brian Salomonafd8a6c2020-05-21 12:10:54 -04001179
Brian Salomon1c86b632020-12-11 12:36:01 -05001180 while (srcRect.size() != finalSize) {
1181 SkISize nextDims = finalSize;
Mike Reed1efa14d2021-01-02 21:44:59 -05001182 if (rescaleMode != RescaleMode::kNearest) {
Brian Salomon1c86b632020-12-11 12:36:01 -05001183 if (srcRect.width() > finalSize.width()) {
1184 nextDims.fWidth = std::max((srcRect.width() + 1)/2, finalSize.width());
1185 } else if (srcRect.width() < finalSize.width()) {
1186 nextDims.fWidth = std::min(srcRect.width()*2, finalSize.width());
Brian Salomon59f31b12020-06-04 17:27:15 -04001187 }
Brian Salomon1c86b632020-12-11 12:36:01 -05001188 if (srcRect.height() > finalSize.height()) {
1189 nextDims.fHeight = std::max((srcRect.height() + 1)/2, finalSize.height());
1190 } else if (srcRect.height() < finalSize.height()) {
1191 nextDims.fHeight = std::min(srcRect.height()*2, finalSize.height());
Brian Salomon59f31b12020-06-04 17:27:15 -04001192 }
1193 }
Brian Salomonbf6b9792019-08-21 09:38:10 -04001194 auto input = tempA ? tempA.get() : this;
Brian Salomone9ad9982019-07-22 16:17:41 -04001195 sk_sp<GrColorSpaceXform> xform;
Brian Salomon7f296c42021-01-13 14:56:55 +00001196 GrSurfaceDrawContext* stepDst;
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001197 SkIRect stepDstRect;
Brian Salomon1c86b632020-12-11 12:36:01 -05001198 if (nextDims == finalSize) {
Brian Salomon7f296c42021-01-13 14:56:55 +00001199 // Might as well fold conversion to final info in the last step.
1200 xform = GrColorSpaceXform::Make(input->colorInfo().colorSpace(),
1201 input->colorInfo().alphaType(),
1202 dst->colorInfo().colorSpace(),
1203 dst->colorInfo().alphaType());
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001204 stepDst = dst;
1205 stepDstRect = dstRect;
Brian Salomon1c86b632020-12-11 12:36:01 -05001206 } else {
Brian Salomon7f296c42021-01-13 14:56:55 +00001207 tempB = GrSurfaceDrawContext::MakeWithFallback(fContext,
1208 input->colorInfo().colorType(),
1209 input->colorInfo().refColorSpace(),
1210 SkBackingFit::kApprox,
1211 nextDims,
1212 1,
1213 GrMipmapped::kNo,
1214 GrProtected::kNo,
1215 dst->origin());
Brian Salomon1c86b632020-12-11 12:36:01 -05001216 if (!tempB) {
1217 return false;
1218 }
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001219 stepDst = tempB.get();
1220 stepDstRect = SkIRect::MakeSize(tempB->dimensions());
Brian Salomone9ad9982019-07-22 16:17:41 -04001221 }
Mike Reed1efa14d2021-01-02 21:44:59 -05001222 if (rescaleMode == RescaleMode::kRepeatedCubic) {
Brian Salomon7f296c42021-01-13 14:56:55 +00001223 SkMatrix matrix;
1224 matrix.setScaleTranslate((float)srcRect.width()/nextDims.width(),
1225 (float)srcRect.height()/nextDims.height(),
1226 srcRect.x(),
1227 srcRect.y());
1228 std::unique_ptr<GrFragmentProcessor> fp;
Brian Salomon59f31b12020-06-04 17:27:15 -04001229 auto dir = GrBicubicEffect::Direction::kXY;
1230 if (nextDims.width() == srcRect.width()) {
1231 dir = GrBicubicEffect::Direction::kY;
1232 } else if (nextDims.height() == srcRect.height()) {
1233 dir = GrBicubicEffect::Direction::kX;
Brian Salomone9ad9982019-07-22 16:17:41 -04001234 }
Brian Salomon1af72d12020-06-25 10:47:26 -04001235 static constexpr auto kWM = GrSamplerState::WrapMode::kClamp;
Mike Reed3867c702020-09-01 13:28:10 -04001236 static constexpr auto kKernel = GrBicubicEffect::gCatmullRom;
Brian Salomon1c86b632020-12-11 12:36:01 -05001237 fp = GrBicubicEffect::MakeSubset(std::move(texView),
1238 input->colorInfo().alphaType(),
Brian Salomon7f296c42021-01-13 14:56:55 +00001239 matrix,
Brian Salomon1c86b632020-12-11 12:36:01 -05001240 kWM,
1241 kWM,
1242 SkRect::Make(srcRect),
1243 kKernel,
1244 dir,
1245 *this->caps());
Brian Salomon7f296c42021-01-13 14:56:55 +00001246 if (xform) {
1247 fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(xform));
1248 }
1249 GrPaint paint;
1250 paint.setColorFragmentProcessor(std::move(fp));
1251 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
1252 stepDst->fillRectToRect(nullptr,
1253 std::move(paint),
1254 GrAA::kNo,
1255 SkMatrix::I(),
1256 SkRect::Make(stepDstRect),
1257 SkRect::Make(stepDstRect));
Brian Salomon59f31b12020-06-04 17:27:15 -04001258 } else {
Mike Reed1efa14d2021-01-02 21:44:59 -05001259 auto filter = rescaleMode == RescaleMode::kNearest ? GrSamplerState::Filter::kNearest
1260 : GrSamplerState::Filter::kLinear;
Brian Salomon7f296c42021-01-13 14:56:55 +00001261 // Minimizing draw with integer coord src and dev rects can always be kFast.
1262 auto constraint = SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint;
1263 if (nextDims.width() <= srcRect.width() && nextDims.height() <= srcRect.height()) {
1264 constraint = SkCanvas::SrcRectConstraint::kFast_SrcRectConstraint;
1265 }
1266 stepDst->drawTexture(nullptr,
1267 std::move(texView),
1268 srcAlphaType,
1269 filter,
1270 GrSamplerState::MipmapMode::kNone,
1271 SkBlendMode::kSrc,
1272 SK_PMColor4fWHITE,
1273 SkRect::Make(srcRect),
1274 SkRect::Make(stepDstRect),
1275 GrAA::kNo,
1276 GrQuadAAFlags::kNone,
1277 constraint,
1278 SkMatrix::I(),
1279 std::move(xform));
Brian Salomone9ad9982019-07-22 16:17:41 -04001280 }
Brian Salomon4bd9fcc2020-12-11 13:52:03 -05001281 texView = stepDst->readSurfaceView();
Brian Salomonbf6b9792019-08-21 09:38:10 -04001282 tempA = std::move(tempB);
Brian Salomonafd8a6c2020-05-21 12:10:54 -04001283 srcRect = SkIRect::MakeSize(nextDims);
Brian Salomone9ad9982019-07-22 16:17:41 -04001284 }
Brian Salomon1c86b632020-12-11 12:36:01 -05001285 return true;
Brian Salomone9ad9982019-07-22 16:17:41 -04001286}
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001287
1288GrSurfaceContext::PixelTransferResult GrSurfaceContext::transferPixels(GrColorType dstCT,
1289 const SkIRect& rect) {
1290 SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
1291 SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
Robert Phillipsf8f45d92020-07-01 11:11:18 -04001292 auto direct = fContext->asDirectContext();
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001293 if (!direct) {
1294 return {};
1295 }
1296 auto rtProxy = this->asRenderTargetProxy();
1297 if (rtProxy && rtProxy->wrapsVkSecondaryCB()) {
1298 return {};
1299 }
1300
1301 auto proxy = this->asSurfaceProxy();
Brian Salomon4bc0c1f2019-09-30 15:12:27 -04001302 auto supportedRead = this->caps()->supportedReadPixelsColorType(this->colorInfo().colorType(),
1303 proxy->backendFormat(), dstCT);
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001304 // Fail if read color type does not have all of dstCT's color channels and those missing color
1305 // channels are in the src.
Brian Salomon2f23ae62020-03-26 16:17:56 -04001306 uint32_t dstChannels = GrColorTypeChannelFlags(dstCT);
1307 uint32_t legalReadChannels = GrColorTypeChannelFlags(supportedRead.fColorType);
1308 uint32_t srcChannels = GrColorTypeChannelFlags(this->colorInfo().colorType());
1309 if ((~legalReadChannels & dstChannels) & srcChannels) {
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001310 return {};
1311 }
1312
Brian Salomonfb28c6f2020-01-10 13:04:45 -05001313 if (!this->caps()->transferFromSurfaceToBufferSupport() ||
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001314 !supportedRead.fOffsetAlignmentForTransferBuffer) {
1315 return {};
1316 }
1317
1318 size_t rowBytes = GrColorTypeBytesPerPixel(supportedRead.fColorType) * rect.width();
1319 size_t size = rowBytes * rect.height();
1320 auto buffer = direct->priv().resourceProvider()->createBuffer(
1321 size, GrGpuBufferType::kXferGpuToCpu, GrAccessPattern::kStream_GrAccessPattern);
1322 if (!buffer) {
1323 return {};
1324 }
1325 auto srcRect = rect;
Greg Danielb8d84f82020-02-13 14:25:00 -05001326 bool flip = this->origin() == kBottomLeft_GrSurfaceOrigin;
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001327 if (flip) {
1328 srcRect = SkIRect::MakeLTRB(rect.fLeft, this->height() - rect.fBottom, rect.fRight,
1329 this->height() - rect.fTop);
1330 }
Greg Danielbbfec9d2019-08-20 10:56:51 -04001331 this->drawingManager()->newTransferFromRenderTask(this->asSurfaceProxyRef(), srcRect,
Brian Salomon4bc0c1f2019-09-30 15:12:27 -04001332 this->colorInfo().colorType(),
Greg Danielbbfec9d2019-08-20 10:56:51 -04001333 supportedRead.fColorType, buffer, 0);
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001334 PixelTransferResult result;
1335 result.fTransferBuffer = std::move(buffer);
Brian Salomon4bc0c1f2019-09-30 15:12:27 -04001336 auto at = this->colorInfo().alphaType();
Brian Salomon8f8354a2019-07-31 20:12:02 -04001337 if (supportedRead.fColorType != dstCT || flip) {
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001338 result.fPixelConverter = [w = rect.width(), h = rect.height(), dstCT, supportedRead, at](
1339 void* dst, const void* src) {
Brian Salomonf2ebdd92019-09-30 12:15:30 -04001340 GrImageInfo srcInfo(supportedRead.fColorType, at, nullptr, w, h);
1341 GrImageInfo dstInfo(dstCT, at, nullptr, w, h);
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001342 GrConvertPixels(dstInfo, dst, dstInfo.minRowBytes(),
1343 srcInfo, src, srcInfo.minRowBytes(),
Brian Salomon8f8354a2019-07-31 20:12:02 -04001344 /* flipY = */ false);
Brian Salomon4d2d6f42019-07-26 14:15:11 -04001345 };
1346 }
1347 return result;
1348}
Greg Daniel46e366a2019-12-16 14:38:36 -05001349
1350#ifdef SK_DEBUG
1351void GrSurfaceContext::validate() const {
Greg Daniel3912a4b2020-01-14 09:56:04 -05001352 SkASSERT(fReadView.proxy());
1353 fReadView.proxy()->validate(fContext);
Brian Salomonc5243782020-04-02 12:50:34 -04001354 if (this->colorInfo().colorType() != GrColorType::kUnknown) {
1355 SkASSERT(fContext->priv().caps()->areColorTypeAndFormatCompatible(
1356 this->colorInfo().colorType(), fReadView.proxy()->backendFormat()));
1357 }
Greg Daniel46e366a2019-12-16 14:38:36 -05001358 this->onValidate();
1359}
1360#endif