blob: dfb2c0b12e854a98fce2ea904e933c6d6a97c4a8 [file] [log] [blame]
Robert Phillipsdbaf3172019-02-06 15:12:53 -05001/*
2 * Copyright 2019 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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/GrContextPriv.h"
Robert Phillipsdbaf3172019-02-06 15:12:53 -05009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/gpu/GrContextThreadSafeProxy.h"
11#include "include/gpu/GrTexture.h"
12#include "include/private/GrSkSLFPFactoryCache.h"
13#include "src/core/SkAutoPixmapStorage.h"
14#include "src/gpu/GrClip.h"
15#include "src/gpu/GrContextThreadSafeProxyPriv.h"
16#include "src/gpu/GrDrawingManager.h"
17#include "src/gpu/GrGpu.h"
18#include "src/gpu/GrMemoryPool.h"
19#include "src/gpu/GrRenderTargetContext.h"
20#include "src/gpu/GrSurfacePriv.h"
21#include "src/gpu/GrTextureContext.h"
22#include "src/gpu/SkGr.h"
23#include "src/gpu/text/GrTextBlobCache.h"
24#include "src/image/SkImage_Base.h"
25#include "src/image/SkImage_Gpu.h"
Robert Phillipsdbaf3172019-02-06 15:12:53 -050026
Brian Salomon693bc2b2019-05-09 13:48:00 +000027#define ASSERT_OWNED_PROXY_PRIV(P) \
Robert Phillipsdbaf3172019-02-06 15:12:53 -050028 SkASSERT(!(P) || !((P)->peekTexture()) || (P)->peekTexture()->getContext() == fContext)
Brian Salomon693bc2b2019-05-09 13:48:00 +000029#define ASSERT_SINGLE_OWNER_PRIV \
Robert Phillipsa41c6852019-02-07 10:44:10 -050030 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fContext->singleOwner());)
Brian Salomon693bc2b2019-05-09 13:48:00 +000031#define RETURN_IF_ABANDONED_PRIV if (fContext->abandoned()) { return; }
32#define RETURN_FALSE_IF_ABANDONED_PRIV if (fContext->abandoned()) { return false; }
Robert Phillipsdbaf3172019-02-06 15:12:53 -050033
Robert Phillipsa41c6852019-02-07 10:44:10 -050034sk_sp<const GrCaps> GrContextPriv::refCaps() const {
35 return fContext->refCaps();
36}
37
Robert Phillipsdbaf3172019-02-06 15:12:53 -050038sk_sp<GrSkSLFPFactoryCache> GrContextPriv::fpFactoryCache() {
39 return fContext->fpFactoryCache();
40}
41
42sk_sp<GrOpMemoryPool> GrContextPriv::refOpMemoryPool() {
Robert Phillipsd6841482019-02-08 10:29:20 -050043 return fContext->refOpMemoryPool();
Robert Phillipsdbaf3172019-02-06 15:12:53 -050044}
45
Robert Phillipsc5058a62019-02-15 12:52:59 -050046void GrContextPriv::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) {
47 fContext->addOnFlushCallbackObject(onFlushCBObject);
48}
49
Robert Phillips292a6b22019-02-14 14:49:02 -050050sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(
51 sk_sp<GrSurfaceProxy> proxy,
52 sk_sp<SkColorSpace> colorSpace,
53 const SkSurfaceProps* props) {
54 return fContext->makeWrappedSurfaceContext(std::move(proxy), std::move(colorSpace), props);
55}
56
57sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(
58 const GrBackendFormat& format,
59 const GrSurfaceDesc& dstDesc,
60 GrSurfaceOrigin origin,
61 GrMipMapped mipMapped,
62 SkBackingFit fit,
63 SkBudgeted isDstBudgeted,
64 sk_sp<SkColorSpace> colorSpace,
65 const SkSurfaceProps* props) {
66 return fContext->makeDeferredSurfaceContext(format, dstDesc, origin, mipMapped, fit,
67 isDstBudgeted, std::move(colorSpace), props);
68}
69
Robert Phillipsb97da532019-02-12 15:24:12 -050070sk_sp<GrRenderTargetContext> GrContextPriv::makeDeferredRenderTargetContext(
Robert Phillips6f0e02f2019-02-13 11:02:28 -050071 const GrBackendFormat& format,
72 SkBackingFit fit,
73 int width, int height,
74 GrPixelConfig config,
75 sk_sp<SkColorSpace> colorSpace,
76 int sampleCnt,
77 GrMipMapped mipMapped,
78 GrSurfaceOrigin origin,
79 const SkSurfaceProps* surfaceProps,
80 SkBudgeted budgeted) {
Robert Phillipsb97da532019-02-12 15:24:12 -050081 return fContext->makeDeferredRenderTargetContext(format, fit, width, height, config,
82 std::move(colorSpace), sampleCnt, mipMapped,
83 origin, surfaceProps, budgeted);
84}
85
Robert Phillips6f0e02f2019-02-13 11:02:28 -050086sk_sp<GrRenderTargetContext> GrContextPriv::makeDeferredRenderTargetContextWithFallback(
87 const GrBackendFormat& format,
88 SkBackingFit fit,
89 int width, int height,
90 GrPixelConfig config,
91 sk_sp<SkColorSpace> colorSpace,
92 int sampleCnt,
93 GrMipMapped mipMapped,
94 GrSurfaceOrigin origin,
95 const SkSurfaceProps* surfaceProps,
96 SkBudgeted budgeted) {
97 return fContext->makeDeferredRenderTargetContextWithFallback(format, fit, width, height, config,
98 std::move(colorSpace), sampleCnt,
99 mipMapped, origin, surfaceProps,
100 budgeted);
101}
102
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500103sk_sp<GrTextureContext> GrContextPriv::makeBackendTextureContext(const GrBackendTexture& tex,
104 GrSurfaceOrigin origin,
105 sk_sp<SkColorSpace> colorSpace) {
Brian Salomon693bc2b2019-05-09 13:48:00 +0000106 ASSERT_SINGLE_OWNER_PRIV
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500107
108 sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->wrapBackendTexture(
109 tex, origin, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType);
110 if (!proxy) {
111 return nullptr;
112 }
113
114 return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
115}
116
117sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext(
118 const GrBackendTexture& tex,
119 GrSurfaceOrigin origin,
120 int sampleCnt,
121 sk_sp<SkColorSpace> colorSpace,
122 const SkSurfaceProps* props,
123 ReleaseProc releaseProc,
124 ReleaseContext releaseCtx) {
Brian Salomon693bc2b2019-05-09 13:48:00 +0000125 ASSERT_SINGLE_OWNER_PRIV
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500126 SkASSERT(sampleCnt > 0);
127
128 sk_sp<GrTextureProxy> proxy(this->proxyProvider()->wrapRenderableBackendTexture(
129 tex, origin, sampleCnt, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, releaseProc,
130 releaseCtx));
131 if (!proxy) {
132 return nullptr;
133 }
134
135 return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
136 std::move(colorSpace), props);
137}
138
139sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext(
140 const GrBackendRenderTarget& backendRT,
141 GrSurfaceOrigin origin,
142 sk_sp<SkColorSpace> colorSpace,
143 const SkSurfaceProps* surfaceProps,
144 ReleaseProc releaseProc,
145 ReleaseContext releaseCtx) {
Brian Salomon693bc2b2019-05-09 13:48:00 +0000146 ASSERT_SINGLE_OWNER_PRIV
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500147
148 sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->wrapBackendRenderTarget(
149 backendRT, origin, releaseProc, releaseCtx);
150 if (!proxy) {
151 return nullptr;
152 }
153
154 return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
155 std::move(colorSpace),
156 surfaceProps);
157}
158
159sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext(
160 const GrBackendTexture& tex,
161 GrSurfaceOrigin origin,
162 int sampleCnt,
163 sk_sp<SkColorSpace> colorSpace,
164 const SkSurfaceProps* props) {
Brian Salomon693bc2b2019-05-09 13:48:00 +0000165 ASSERT_SINGLE_OWNER_PRIV
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500166 SkASSERT(sampleCnt > 0);
167 sk_sp<GrSurfaceProxy> proxy(
168 this->proxyProvider()->wrapBackendTextureAsRenderTarget(tex, origin, sampleCnt));
169 if (!proxy) {
170 return nullptr;
171 }
172
173 return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
174 std::move(colorSpace),
175 props);
176}
177
178sk_sp<GrRenderTargetContext> GrContextPriv::makeVulkanSecondaryCBRenderTargetContext(
179 const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo, const SkSurfaceProps* props) {
Brian Salomon693bc2b2019-05-09 13:48:00 +0000180 ASSERT_SINGLE_OWNER_PRIV
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500181 sk_sp<GrSurfaceProxy> proxy(
182 this->proxyProvider()->wrapVulkanSecondaryCBAsRenderTarget(imageInfo, vkInfo));
183 if (!proxy) {
184 return nullptr;
185 }
186
187 return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
188 imageInfo.refColorSpace(),
189 props);
190}
191
Brian Salomon693bc2b2019-05-09 13:48:00 +0000192void GrContextPriv::flush(GrSurfaceProxy* proxy) {
193 ASSERT_SINGLE_OWNER_PRIV
194 RETURN_IF_ABANDONED_PRIV
195 ASSERT_OWNED_PROXY_PRIV(proxy);
196
197 fContext->drawingManager()->flush(proxy, SkSurface::BackendSurfaceAccess::kNoAccess,
198 GrFlushInfo());
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500199}
200
Brian Salomon693bc2b2019-05-09 13:48:00 +0000201void GrContextPriv::flushSurface(GrSurfaceProxy* proxy) {
202 ASSERT_SINGLE_OWNER_PRIV
203 RETURN_IF_ABANDONED_PRIV
204 SkASSERT(proxy);
205 ASSERT_OWNED_PROXY_PRIV(proxy);
206 fContext->drawingManager()->flushSurface(proxy,
207 SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo());
208}
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500209
210static bool valid_premul_color_type(GrColorType ct) {
211 switch (ct) {
Brian Osmand0626aa2019-03-11 15:28:06 -0400212 case GrColorType::kUnknown: return false;
213 case GrColorType::kAlpha_8: return false;
214 case GrColorType::kRGB_565: return false;
215 case GrColorType::kABGR_4444: return true;
216 case GrColorType::kRGBA_8888: return true;
217 case GrColorType::kRGB_888x: return false;
218 case GrColorType::kRG_88: return false;
219 case GrColorType::kBGRA_8888: return true;
220 case GrColorType::kRGBA_1010102: return true;
221 case GrColorType::kGray_8: return false;
222 case GrColorType::kAlpha_F16: return false;
223 case GrColorType::kRGBA_F16: return true;
224 case GrColorType::kRGBA_F16_Clamped: return true;
225 case GrColorType::kRG_F32: return false;
226 case GrColorType::kRGBA_F32: return true;
227 case GrColorType::kRGB_ETC1: return false;
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500228 }
229 SK_ABORT("Invalid GrColorType");
230 return false;
231}
232
233// TODO: This will be removed when GrSurfaceContexts are aware of their color types.
234// (skbug.com/6718)
235static bool valid_premul_config(GrPixelConfig config) {
236 switch (config) {
237 case kUnknown_GrPixelConfig: return false;
238 case kAlpha_8_GrPixelConfig: return false;
239 case kGray_8_GrPixelConfig: return false;
240 case kRGB_565_GrPixelConfig: return false;
241 case kRGBA_4444_GrPixelConfig: return true;
242 case kRGBA_8888_GrPixelConfig: return true;
243 case kRGB_888_GrPixelConfig: return false;
Greg Danielf259b8b2019-02-14 09:03:43 -0500244 case kRGB_888X_GrPixelConfig: return false;
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500245 case kRG_88_GrPixelConfig: return false;
246 case kBGRA_8888_GrPixelConfig: return true;
247 case kSRGBA_8888_GrPixelConfig: return true;
248 case kSBGRA_8888_GrPixelConfig: return true;
249 case kRGBA_1010102_GrPixelConfig: return true;
250 case kRGBA_float_GrPixelConfig: return true;
251 case kRG_float_GrPixelConfig: return false;
252 case kAlpha_half_GrPixelConfig: return false;
253 case kRGBA_half_GrPixelConfig: return true;
Brian Osmand0626aa2019-03-11 15:28:06 -0400254 case kRGBA_half_Clamped_GrPixelConfig: return true;
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500255 case kRGB_ETC1_GrPixelConfig: return false;
256 case kAlpha_8_as_Alpha_GrPixelConfig: return false;
257 case kAlpha_8_as_Red_GrPixelConfig: return false;
258 case kAlpha_half_as_Red_GrPixelConfig: return false;
259 case kGray_8_as_Lum_GrPixelConfig: return false;
260 case kGray_8_as_Red_GrPixelConfig: return false;
261 }
262 SK_ABORT("Invalid GrPixelConfig");
263 return false;
264}
265
266static bool valid_pixel_conversion(GrColorType cpuColorType, GrPixelConfig gpuConfig,
267 bool premulConversion) {
268 // We only allow premul <-> unpremul conversions for some formats
269 if (premulConversion &&
270 (!valid_premul_color_type(cpuColorType) || !valid_premul_config(gpuConfig))) {
271 return false;
272 }
273 return true;
274}
275
276bool GrContextPriv::readSurfacePixels(GrSurfaceContext* src, int left, int top, int width,
277 int height, GrColorType dstColorType,
278 SkColorSpace* dstColorSpace, void* buffer, size_t rowBytes,
279 uint32_t pixelOpsFlags) {
Brian Salomon693bc2b2019-05-09 13:48:00 +0000280 ASSERT_SINGLE_OWNER_PRIV
281 RETURN_FALSE_IF_ABANDONED_PRIV
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500282 SkASSERT(src);
283 SkASSERT(buffer);
Brian Salomon693bc2b2019-05-09 13:48:00 +0000284 ASSERT_OWNED_PROXY_PRIV(src->asSurfaceProxy());
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500285 GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "readSurfacePixels", fContext);
286
Robert Phillips8e1529c2019-04-05 08:17:25 -0400287 GrSurfaceProxy* srcProxy = src->asSurfaceProxy();
288
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500289 // MDB TODO: delay this instantiation until later in the method
Robert Phillips8e1529c2019-04-05 08:17:25 -0400290 if (!srcProxy->instantiate(this->resourceProvider())) {
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500291 return false;
292 }
293
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500294 GrSurface* srcSurface = srcProxy->peekSurface();
295
296 if (!GrSurfacePriv::AdjustReadPixelParams(srcSurface->width(), srcSurface->height(),
297 GrColorTypeBytesPerPixel(dstColorType), &left, &top,
298 &width, &height, &buffer, &rowBytes)) {
299 return false;
300 }
301
302 // TODO: Make GrSurfaceContext know its alpha type and pass dst buffer's alpha type.
303 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
304
305 if (!valid_pixel_conversion(dstColorType, srcProxy->config(), unpremul)) {
306 return false;
307 }
308
Brian Osman4f98dbe2019-03-28 11:49:01 -0400309 bool needColorConversion =
310 SkColorSpaceXformSteps::Required(src->colorSpaceInfo().colorSpace(), dstColorSpace);
311
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500312 // This is the getImageData equivalent to the canvas2D putImageData fast path. We probably don't
313 // care so much about getImageData performance. However, in order to ensure putImageData/
314 // getImageData in "legacy" mode are round-trippable we use the GPU to do the complementary
315 // unpremul step to writeSurfacePixels's premul step (which is determined empirically in
316 // fContext->vaildaPMUPMConversionExists()).
317 bool canvas2DFastPath =
318 unpremul &&
Brian Osman4f98dbe2019-03-28 11:49:01 -0400319 !needColorConversion &&
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500320 (GrColorType::kRGBA_8888 == dstColorType || GrColorType::kBGRA_8888 == dstColorType) &&
321 SkToBool(srcProxy->asTextureProxy()) &&
322 (srcProxy->config() == kRGBA_8888_GrPixelConfig ||
323 srcProxy->config() == kBGRA_8888_GrPixelConfig) &&
324 fContext->priv().caps()->isConfigRenderable(kRGBA_8888_GrPixelConfig) &&
325 fContext->validPMUPMConversionExists();
326
327 if (!fContext->priv().caps()->surfaceSupportsReadPixels(srcSurface) ||
328 canvas2DFastPath) {
329 GrSurfaceDesc desc;
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500330 desc.fWidth = width;
331 desc.fHeight = height;
332 desc.fSampleCnt = 1;
333
334 GrBackendFormat format;
335 if (canvas2DFastPath) {
336 desc.fFlags = kRenderTarget_GrSurfaceFlag;
337 desc.fConfig = kRGBA_8888_GrPixelConfig;
338 format = this->caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
339 } else {
340 desc.fFlags = kNone_GrSurfaceFlags;
341 desc.fConfig = srcProxy->config();
342 format = srcProxy->backendFormat().makeTexture2D();
343 if (!format.isValid()) {
344 return false;
345 }
346 }
347
348 auto tempProxy = this->proxyProvider()->createProxy(
349 format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kApprox, SkBudgeted::kYes);
350 if (!tempProxy) {
351 return false;
352 }
353 sk_sp<GrSurfaceContext> tempCtx;
354 if (canvas2DFastPath) {
355 tempCtx = this->drawingManager()->makeRenderTargetContext(std::move(tempProxy), nullptr,
356 nullptr);
357 SkASSERT(tempCtx->asRenderTargetContext());
358 tempCtx->asRenderTargetContext()->discard();
359 } else {
360 tempCtx = this->drawingManager()->makeTextureContext(
361 std::move(tempProxy), src->colorSpaceInfo().refColorSpace());
362 }
363 if (!tempCtx) {
364 return false;
365 }
366 if (canvas2DFastPath) {
367 GrPaint paint;
368 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
369 auto fp = fContext->createPMToUPMEffect(
370 GrSimpleTextureEffect::Make(sk_ref_sp(srcProxy->asTextureProxy()),
371 SkMatrix::I()));
372 if (dstColorType == GrColorType::kBGRA_8888) {
373 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
374 dstColorType = GrColorType::kRGBA_8888;
375 }
376 if (!fp) {
377 return false;
378 }
379 paint.addColorFragmentProcessor(std::move(fp));
380 tempCtx->asRenderTargetContext()->fillRectToRect(
381 GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
382 SkRect::MakeWH(width, height), SkRect::MakeXYWH(left, top, width, height));
383 } else if (!tempCtx->copy(srcProxy, SkIRect::MakeXYWH(left, top, width, height), {0, 0})) {
384 return false;
385 }
386 uint32_t flags = canvas2DFastPath ? 0 : pixelOpsFlags;
387 return this->readSurfacePixels(tempCtx.get(), 0, 0, width, height, dstColorType,
388 dstColorSpace, buffer, rowBytes, flags);
389 }
390
Brian Osman4f98dbe2019-03-28 11:49:01 -0400391 bool convert = unpremul || needColorConversion;
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500392
393 bool flip = srcProxy->origin() == kBottomLeft_GrSurfaceOrigin;
394 if (flip) {
395 top = srcSurface->height() - top - height;
396 }
397
398 GrColorType allowedColorType = fContext->priv().caps()->supportedReadPixelsColorType(
399 srcProxy->config(), dstColorType);
400 convert = convert || (dstColorType != allowedColorType);
401
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500402 SkAutoPixmapStorage tempPixmap;
403 SkPixmap finalPixmap;
404 if (convert) {
405 SkColorType srcSkColorType = GrColorTypeToSkColorType(allowedColorType);
406 SkColorType dstSkColorType = GrColorTypeToSkColorType(dstColorType);
407 bool srcAlwaysOpaque = SkColorTypeIsAlwaysOpaque(srcSkColorType);
408 bool dstAlwaysOpaque = SkColorTypeIsAlwaysOpaque(dstSkColorType);
409 if (kUnknown_SkColorType == srcSkColorType || kUnknown_SkColorType == dstSkColorType) {
410 return false;
411 }
412 auto tempAT = srcAlwaysOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
413 auto tempII = SkImageInfo::Make(width, height, srcSkColorType, tempAT,
414 src->colorSpaceInfo().refColorSpace());
415 SkASSERT(!unpremul || !dstAlwaysOpaque);
416 auto finalAT = (srcAlwaysOpaque || dstAlwaysOpaque)
417 ? kOpaque_SkAlphaType
418 : unpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
419 auto finalII =
420 SkImageInfo::Make(width, height, dstSkColorType, finalAT, sk_ref_sp(dstColorSpace));
421 if (!SkImageInfoValidConversion(finalII, tempII)) {
422 return false;
423 }
424 if (!tempPixmap.tryAlloc(tempII)) {
425 return false;
426 }
427 finalPixmap.reset(finalII, buffer, rowBytes);
428 buffer = tempPixmap.writable_addr();
429 rowBytes = tempPixmap.rowBytes();
430 // Chrome msan bots require this.
431 sk_bzero(buffer, tempPixmap.computeByteSize());
432 }
433
Brian Salomon693bc2b2019-05-09 13:48:00 +0000434 this->flush(srcProxy);
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500435
436 if (!fContext->fGpu->readPixels(srcSurface, left, top, width, height, allowedColorType, buffer,
437 rowBytes)) {
438 return false;
439 }
440
441 if (flip) {
442 size_t trimRowBytes = GrColorTypeBytesPerPixel(allowedColorType) * width;
443 std::unique_ptr<char[]> row(new char[trimRowBytes]);
444 char* upper = reinterpret_cast<char*>(buffer);
445 char* lower = reinterpret_cast<char*>(buffer) + (height - 1) * rowBytes;
446 for (int y = 0; y < height / 2; ++y, upper += rowBytes, lower -= rowBytes) {
447 memcpy(row.get(), upper, trimRowBytes);
448 memcpy(upper, lower, trimRowBytes);
449 memcpy(lower, row.get(), trimRowBytes);
450 }
451 }
452 if (convert) {
453 if (!tempPixmap.readPixels(finalPixmap)) {
454 return false;
455 }
456 }
457 return true;
458}
459
460bool GrContextPriv::writeSurfacePixels(GrSurfaceContext* dst, int left, int top, int width,
461 int height, GrColorType srcColorType,
462 SkColorSpace* srcColorSpace, const void* buffer,
463 size_t rowBytes, uint32_t pixelOpsFlags) {
Brian Salomon693bc2b2019-05-09 13:48:00 +0000464 ASSERT_SINGLE_OWNER_PRIV
465 RETURN_FALSE_IF_ABANDONED_PRIV
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500466 SkASSERT(dst);
467 SkASSERT(buffer);
Brian Salomon693bc2b2019-05-09 13:48:00 +0000468 ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy());
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500469 GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels", fContext);
470
471 if (GrColorType::kUnknown == srcColorType) {
472 return false;
473 }
474
Robert Phillips8e1529c2019-04-05 08:17:25 -0400475 GrSurfaceProxy* dstProxy = dst->asSurfaceProxy();
476 if (!dstProxy->instantiate(this->resourceProvider())) {
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500477 return false;
478 }
479
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500480 GrSurface* dstSurface = dstProxy->peekSurface();
481
482 if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(),
483 GrColorTypeBytesPerPixel(srcColorType), &left, &top,
484 &width, &height, &buffer, &rowBytes)) {
485 return false;
486 }
487
488 // TODO: Make GrSurfaceContext know its alpha type and pass src buffer's alpha type.
489 bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
490
Brian Osman4f98dbe2019-03-28 11:49:01 -0400491 bool needColorConversion =
492 SkColorSpaceXformSteps::Required(srcColorSpace, dst->colorSpaceInfo().colorSpace());
493
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500494 // For canvas2D putImageData performance we have a special code path for unpremul RGBA_8888 srcs
495 // that are premultiplied on the GPU. This is kept as narrow as possible for now.
496 bool canvas2DFastPath =
497 !fContext->priv().caps()->avoidWritePixelsFastPath() &&
498 premul &&
Brian Osman4f98dbe2019-03-28 11:49:01 -0400499 !needColorConversion &&
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500500 (srcColorType == GrColorType::kRGBA_8888 || srcColorType == GrColorType::kBGRA_8888) &&
501 SkToBool(dst->asRenderTargetContext()) &&
502 (dstProxy->config() == kRGBA_8888_GrPixelConfig ||
503 dstProxy->config() == kBGRA_8888_GrPixelConfig) &&
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500504 fContext->priv().caps()->isConfigTexturable(kRGBA_8888_GrPixelConfig) &&
505 fContext->validPMUPMConversionExists();
506
507 const GrCaps* caps = this->caps();
Robert Phillipsba4178e2019-03-28 14:53:27 -0400508 if (!caps->surfaceSupportsWritePixels(dstSurface) || canvas2DFastPath) {
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500509 GrSurfaceDesc desc;
510 desc.fWidth = width;
511 desc.fHeight = height;
512 desc.fSampleCnt = 1;
513
514 GrBackendFormat format;
515 if (canvas2DFastPath) {
516 desc.fConfig = kRGBA_8888_GrPixelConfig;
517 format =
518 fContext->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
519 } else {
520 desc.fConfig = dstProxy->config();
521 format = dstProxy->backendFormat().makeTexture2D();
522 if (!format.isValid()) {
523 return false;
524 }
525 }
526
527 auto tempProxy = this->proxyProvider()->createProxy(
528 format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kApprox, SkBudgeted::kYes);
529 if (!tempProxy) {
530 return false;
531 }
532 auto tempCtx = this->drawingManager()->makeTextureContext(
533 tempProxy, dst->colorSpaceInfo().refColorSpace());
534 if (!tempCtx) {
535 return false;
536 }
537 uint32_t flags = canvas2DFastPath ? 0 : pixelOpsFlags;
538 // In the fast path we always write the srcData to the temp context as though it were RGBA.
539 // When the data is really BGRA the write will cause the R and B channels to be swapped in
540 // the intermediate surface which gets corrected by a swizzle effect when drawing to the
541 // dst.
542 auto tmpColorType = canvas2DFastPath ? GrColorType::kRGBA_8888 : srcColorType;
543 if (!this->writeSurfacePixels(tempCtx.get(), 0, 0, width, height, tmpColorType,
544 srcColorSpace, buffer, rowBytes, flags)) {
545 return false;
546 }
547 if (canvas2DFastPath) {
548 GrPaint paint;
549 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
550 auto fp = fContext->createUPMToPMEffect(
551 GrSimpleTextureEffect::Make(std::move(tempProxy), SkMatrix::I()));
552 if (srcColorType == GrColorType::kBGRA_8888) {
553 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
554 }
555 if (!fp) {
556 return false;
557 }
558 paint.addColorFragmentProcessor(std::move(fp));
559 dst->asRenderTargetContext()->fillRectToRect(
560 GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
561 SkRect::MakeXYWH(left, top, width, height), SkRect::MakeWH(width, height));
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500562 } else {
Robert Phillips8e1529c2019-04-05 08:17:25 -0400563 if (!dst->copy(tempProxy.get(), SkIRect::MakeWH(width, height), {left, top})) {
564 return false;
565 }
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500566 }
Robert Phillips8e1529c2019-04-05 08:17:25 -0400567
568 return true;
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500569 }
570
Brian Osman4f98dbe2019-03-28 11:49:01 -0400571 bool convert = premul || needColorConversion;
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500572
573 if (!valid_pixel_conversion(srcColorType, dstProxy->config(), premul)) {
574 return false;
575 }
576
577 GrColorType allowedColorType = fContext->priv().caps()->supportedWritePixelsColorType(
578 dstProxy->config(), srcColorType);
579 convert = convert || (srcColorType != allowedColorType);
580
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500581 std::unique_ptr<char[]> tempBuffer;
582 if (convert) {
583 auto srcSkColorType = GrColorTypeToSkColorType(srcColorType);
584 auto dstSkColorType = GrColorTypeToSkColorType(allowedColorType);
585 if (kUnknown_SkColorType == srcSkColorType || kUnknown_SkColorType == dstSkColorType) {
586 return false;
587 }
588 auto srcAlphaType = SkColorTypeIsAlwaysOpaque(srcSkColorType)
589 ? kOpaque_SkAlphaType
590 : (premul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType);
591 SkPixmap src(SkImageInfo::Make(width, height, srcSkColorType, srcAlphaType,
592 sk_ref_sp(srcColorSpace)),
593 buffer, rowBytes);
594 auto tempSrcII = SkImageInfo::Make(width, height, dstSkColorType, kPremul_SkAlphaType,
595 dst->colorSpaceInfo().refColorSpace());
596 auto size = tempSrcII.computeMinByteSize();
597 if (!size) {
598 return false;
599 }
600 tempBuffer.reset(new char[size]);
601 SkPixmap tempSrc(tempSrcII, tempBuffer.get(), tempSrcII.minRowBytes());
602 if (!src.readPixels(tempSrc)) {
603 return false;
604 }
605 srcColorType = allowedColorType;
606 buffer = tempSrc.addr();
607 rowBytes = tempSrc.rowBytes();
608 if (dstProxy->origin() == kBottomLeft_GrSurfaceOrigin) {
609 std::unique_ptr<char[]> row(new char[rowBytes]);
610 for (int y = 0; y < height / 2; ++y) {
611 memcpy(row.get(), tempSrc.addr(0, y), rowBytes);
612 memcpy(tempSrc.writable_addr(0, y), tempSrc.addr(0, height - 1 - y), rowBytes);
613 memcpy(tempSrc.writable_addr(0, height - 1 - y), row.get(), rowBytes);
614 }
615 top = dstSurface->height() - top - height;
616 }
617 } else if (dstProxy->origin() == kBottomLeft_GrSurfaceOrigin) {
618 size_t trimRowBytes = GrColorTypeBytesPerPixel(srcColorType) * width;
619 tempBuffer.reset(new char[trimRowBytes * height]);
620 char* dst = reinterpret_cast<char*>(tempBuffer.get()) + trimRowBytes * (height - 1);
621 const char* src = reinterpret_cast<const char*>(buffer);
622 for (int i = 0; i < height; ++i, src += rowBytes, dst -= trimRowBytes) {
623 memcpy(dst, src, trimRowBytes);
624 }
625 buffer = tempBuffer.get();
626 rowBytes = trimRowBytes;
627 top = dstSurface->height() - top - height;
628 }
629
Robert Phillips7ecb8d12019-04-24 11:17:06 -0400630 // On platforms that prefer flushes over VRAM use (i.e., ANGLE) we're better off forcing a
631 // complete flush here. On platforms that prefer VRAM use over flushes we're better off
632 // giving the drawing manager the chance of skipping the flush (i.e., by passing in the
633 // destination proxy)
634 // TODO: should this policy decision just be moved into the drawing manager?
Brian Salomon693bc2b2019-05-09 13:48:00 +0000635 this->flush(caps->preferVRAMUseOverFlushes() ? dstProxy : nullptr);
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500636
637 return this->getGpu()->writePixels(dstSurface, left, top, width, height, srcColorType, buffer,
638 rowBytes);
639}
640
641void GrContextPriv::moveOpListsToDDL(SkDeferredDisplayList* ddl) {
Robert Phillips292a6b22019-02-14 14:49:02 -0500642 fContext->drawingManager()->moveOpListsToDDL(ddl);
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500643}
644
645void GrContextPriv::copyOpListsFromDDL(const SkDeferredDisplayList* ddl,
646 GrRenderTargetProxy* newDest) {
Robert Phillips6a6de562019-02-15 15:19:15 -0500647 fContext->drawingManager()->copyOpListsFromDDL(ddl, newDest);
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500648}
649
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500650//////////////////////////////////////////////////////////////////////////////
651#ifdef SK_ENABLE_DUMP_GPU
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500652#include "src/utils/SkJSONWriter.h"
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500653SkString GrContextPriv::dump() const {
654 SkDynamicMemoryWStream stream;
655 SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty);
656 writer.beginObject();
657
658 static const char* kBackendStr[] = {
659 "Metal",
660 "OpenGL",
661 "Vulkan",
662 "Mock",
663 };
664 GR_STATIC_ASSERT(0 == (unsigned)GrBackendApi::kMetal);
665 GR_STATIC_ASSERT(1 == (unsigned)GrBackendApi::kOpenGL);
666 GR_STATIC_ASSERT(2 == (unsigned)GrBackendApi::kVulkan);
667 GR_STATIC_ASSERT(3 == (unsigned)GrBackendApi::kMock);
668 writer.appendString("backend", kBackendStr[(unsigned)fContext->backend()]);
669
670 writer.appendName("caps");
671 fContext->caps()->dumpJSON(&writer);
672
673 writer.appendName("gpu");
674 fContext->fGpu->dumpJSON(&writer);
675
676 // Flush JSON to the memory stream
677 writer.endObject();
678 writer.flush();
679
680 // Null terminate the JSON data in the memory stream
681 stream.write8(0);
682
683 // Allocate a string big enough to hold all the data, then copy out of the stream
684 SkString result(stream.bytesWritten());
685 stream.copyToAndReset(result.writable_str());
686 return result;
687}
688#endif
689
690#if GR_TEST_UTILS
691void GrContextPriv::resetGpuStats() const {
692#if GR_GPU_STATS
693 fContext->fGpu->stats()->reset();
694#endif
695}
696
697void GrContextPriv::dumpCacheStats(SkString* out) const {
698#if GR_CACHE_STATS
699 fContext->fResourceCache->dumpStats(out);
700#endif
701}
702
703void GrContextPriv::dumpCacheStatsKeyValuePairs(SkTArray<SkString>* keys,
704 SkTArray<double>* values) const {
705#if GR_CACHE_STATS
706 fContext->fResourceCache->dumpStatsKeyValuePairs(keys, values);
707#endif
708}
709
710void GrContextPriv::printCacheStats() const {
711 SkString out;
712 this->dumpCacheStats(&out);
713 SkDebugf("%s", out.c_str());
714}
715
716void GrContextPriv::dumpGpuStats(SkString* out) const {
717#if GR_GPU_STATS
718 return fContext->fGpu->stats()->dump(out);
719#endif
720}
721
722void GrContextPriv::dumpGpuStatsKeyValuePairs(SkTArray<SkString>* keys,
723 SkTArray<double>* values) const {
724#if GR_GPU_STATS
725 return fContext->fGpu->stats()->dumpKeyValuePairs(keys, values);
726#endif
727}
728
729void GrContextPriv::printGpuStats() const {
730 SkString out;
731 this->dumpGpuStats(&out);
732 SkDebugf("%s", out.c_str());
733}
734
735void GrContextPriv::testingOnly_setTextBlobCacheLimit(size_t bytes) {
Robert Phillips2184fb72019-02-21 16:11:41 -0500736 fContext->priv().getTextBlobCache()->setBudget(bytes);
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500737}
738
739sk_sp<SkImage> GrContextPriv::testingOnly_getFontAtlasImage(GrMaskFormat format, unsigned int index) {
740 auto atlasManager = this->getAtlasManager();
741 if (!atlasManager) {
742 return nullptr;
743 }
744
745 unsigned int numActiveProxies;
746 const sk_sp<GrTextureProxy>* proxies = atlasManager->getProxies(format, &numActiveProxies);
747 if (index >= numActiveProxies || !proxies || !proxies[index]) {
748 return nullptr;
749 }
750
751 SkASSERT(proxies[index]->priv().isExact());
752 sk_sp<SkImage> image(new SkImage_Gpu(sk_ref_sp(fContext), kNeedNewImageUniqueID,
753 kPremul_SkAlphaType, proxies[index], nullptr));
754 return image;
755}
756
757void GrContextPriv::testingOnly_purgeAllUnlockedResources() {
758 fContext->fResourceCache->purgeAllUnlocked();
759}
760
761void GrContextPriv::testingOnly_flushAndRemoveOnFlushCallbackObject(GrOnFlushCallbackObject* cb) {
762 fContext->flush();
Robert Phillips292a6b22019-02-14 14:49:02 -0500763 fContext->drawingManager()->testingOnly_removeOnFlushCallbackObject(cb);
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500764}
765#endif