1 /*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "GrContext.h"
9 #include "GrClip.h"
10 #include "GrContextOptions.h"
11 #include "GrContextPriv.h"
12 #include "GrDrawingManager.h"
13 #include "GrGpu.h"
14 #include "GrRenderTargetContext.h"
15 #include "GrRenderTargetProxy.h"
16 #include "GrResourceCache.h"
17 #include "GrResourceProvider.h"
18 #include "GrSemaphore.h"
19 #include "GrSoftwarePathRenderer.h"
20 #include "GrSurfaceContext.h"
21 #include "GrSurfacePriv.h"
22 #include "GrSurfaceProxyPriv.h"
23 #include "GrTexture.h"
24 #include "GrTextureContext.h"
25 #include "GrTracing.h"
26 #include "SkConvertPixels.h"
27 #include "SkGr.h"
28 #include "SkUnPreMultiplyPriv.h"
29 #include "effects/GrConfigConversionEffect.h"
30 #include "text/GrTextBlobCache.h"
31
32 #ifdef SK_METAL
33 #include "mtl/GrMtlTrampoline.h"
34 #endif
35
36 #define ASSERT_OWNED_PROXY(P) \
37 SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == this)
38 #define ASSERT_OWNED_PROXY_PRIV(P) \
39 SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == fContext)
40
41 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
42 #define ASSERT_SINGLE_OWNER \
43 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);)
44 #define ASSERT_SINGLE_OWNER_PRIV \
45 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fContext->fSingleOwner);)
46 #define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; }
47 #define RETURN_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return; }
48 #define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; }
49 #define RETURN_FALSE_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return false; }
50 #define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; }
51
52 ////////////////////////////////////////////////////////////////////////////////
53
Create(GrBackend backend,GrBackendContext backendContext)54 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
55 GrContextOptions defaultOptions;
56 return Create(backend, backendContext, defaultOptions);
57 }
58
Create(GrBackend backend,GrBackendContext backendContext,const GrContextOptions & options)59 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
60 const GrContextOptions& options) {
61 sk_sp<GrContext> context(new GrContext);
62
63 if (!context->init(backend, backendContext, options)) {
64 return nullptr;
65 }
66 return context.release();
67 }
68
69 #ifdef SK_METAL
MakeMetal(void * device,void * queue,const GrContextOptions & options)70 sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue, const GrContextOptions& options) {
71 sk_sp<GrContext> context(new GrContext);
72 context->fGpu = GrMtlTrampoline::CreateGpu(context.get(), options, device, queue);
73 if (!context->fGpu) {
74 return nullptr;
75 }
76 context->fBackend = kMetal_GrBackend;
77 if (!context->init(options)) {
78 return nullptr;
79 }
80 return context;
81 }
82 #endif
83
84 static int32_t gNextID = 1;
next_id()85 static int32_t next_id() {
86 int32_t id;
87 do {
88 id = sk_atomic_inc(&gNextID);
89 } while (id == SK_InvalidGenID);
90 return id;
91 }
92
GrContext()93 GrContext::GrContext() : fUniqueID(next_id()) {
94 fGpu = nullptr;
95 fCaps = nullptr;
96 fResourceCache = nullptr;
97 fResourceProvider = nullptr;
98 fAtlasGlyphCache = nullptr;
99 }
100
init(GrBackend backend,GrBackendContext backendContext,const GrContextOptions & options)101 bool GrContext::init(GrBackend backend, GrBackendContext backendContext,
102 const GrContextOptions& options) {
103 ASSERT_SINGLE_OWNER
104 SkASSERT(!fGpu);
105
106 fBackend = backend;
107
108 fGpu = GrGpu::Create(backend, backendContext, options, this);
109 if (!fGpu) {
110 return false;
111 }
112 return this->init(options);
113 }
114
init(const GrContextOptions & options)115 bool GrContext::init(const GrContextOptions& options) {
116 ASSERT_SINGLE_OWNER
117 fCaps = SkRef(fGpu->caps());
118 fResourceCache = new GrResourceCache(fCaps, fUniqueID);
119 fResourceProvider = new GrResourceProvider(fGpu, fResourceCache, &fSingleOwner);
120
121 fDisableGpuYUVConversion = options.fDisableGpuYUVConversion;
122 fDidTestPMConversions = false;
123
124 GrPathRendererChain::Options prcOptions;
125 prcOptions.fAllowPathMaskCaching = options.fAllowPathMaskCaching;
126 prcOptions.fGpuPathRenderers = options.fGpuPathRenderers;
127 fDrawingManager.reset(new GrDrawingManager(this, prcOptions, &fSingleOwner));
128
129 fAtlasGlyphCache = new GrAtlasGlyphCache(this, options.fGlyphCacheTextureMaximumBytes);
130
131 fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this));
132
133 return true;
134 }
135
~GrContext()136 GrContext::~GrContext() {
137 ASSERT_SINGLE_OWNER
138
139 if (!fGpu) {
140 SkASSERT(!fCaps);
141 return;
142 }
143
144 this->flush();
145
146 fDrawingManager->cleanup();
147
148 for (int i = 0; i < fCleanUpData.count(); ++i) {
149 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
150 }
151
152 delete fResourceProvider;
153 delete fResourceCache;
154 delete fAtlasGlyphCache;
155
156 fGpu->unref();
157 fCaps->unref();
158 }
159
threadSafeProxy()160 sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() {
161 if (!fThreadSafeProxy) {
162 fThreadSafeProxy.reset(new GrContextThreadSafeProxy(sk_ref_sp(fCaps), this->uniqueID()));
163 }
164 return fThreadSafeProxy;
165 }
166
abandonContext()167 void GrContext::abandonContext() {
168 ASSERT_SINGLE_OWNER
169
170 fResourceProvider->abandon();
171
172 // Need to abandon the drawing manager first so all the render targets
173 // will be released/forgotten before they too are abandoned.
174 fDrawingManager->abandon();
175
176 // abandon first to so destructors
177 // don't try to free the resources in the API.
178 fResourceCache->abandonAll();
179
180 fGpu->disconnect(GrGpu::DisconnectType::kAbandon);
181
182 fAtlasGlyphCache->freeAll();
183 fTextBlobCache->freeAll();
184 }
185
releaseResourcesAndAbandonContext()186 void GrContext::releaseResourcesAndAbandonContext() {
187 ASSERT_SINGLE_OWNER
188
189 fResourceProvider->abandon();
190
191 // Need to abandon the drawing manager first so all the render targets
192 // will be released/forgotten before they too are abandoned.
193 fDrawingManager->abandon();
194
195 // Release all resources in the backend 3D API.
196 fResourceCache->releaseAll();
197
198 fGpu->disconnect(GrGpu::DisconnectType::kCleanup);
199
200 fAtlasGlyphCache->freeAll();
201 fTextBlobCache->freeAll();
202 }
203
resetContext(uint32_t state)204 void GrContext::resetContext(uint32_t state) {
205 ASSERT_SINGLE_OWNER
206 fGpu->markContextDirty(state);
207 }
208
freeGpuResources()209 void GrContext::freeGpuResources() {
210 ASSERT_SINGLE_OWNER
211
212 this->flush();
213
214 fAtlasGlyphCache->freeAll();
215
216 fDrawingManager->freeGpuResources();
217
218 fResourceCache->purgeAllUnlocked();
219 }
220
purgeResourcesNotUsedInMs(std::chrono::milliseconds ms)221 void GrContext::purgeResourcesNotUsedInMs(std::chrono::milliseconds ms) {
222 ASSERT_SINGLE_OWNER
223 fResourceCache->purgeResourcesNotUsedSince(GrStdSteadyClock::now() - ms);
224 }
225
purgeUnlockedResources(size_t bytesToPurge,bool preferScratchResources)226 void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
227 ASSERT_SINGLE_OWNER
228 fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources);
229 }
230
getResourceCacheUsage(int * resourceCount,size_t * resourceBytes) const231 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
232 ASSERT_SINGLE_OWNER
233
234 if (resourceCount) {
235 *resourceCount = fResourceCache->getBudgetedResourceCount();
236 }
237 if (resourceBytes) {
238 *resourceBytes = fResourceCache->getBudgetedResourceBytes();
239 }
240 }
241
getResourceCachePurgeableBytes() const242 size_t GrContext::getResourceCachePurgeableBytes() const {
243 ASSERT_SINGLE_OWNER
244 return fResourceCache->getPurgeableBytes();
245 }
246
247 ////////////////////////////////////////////////////////////////////////////////
248
TextBlobCacheOverBudgetCB(void * data)249 void GrContext::TextBlobCacheOverBudgetCB(void* data) {
250 SkASSERT(data);
251 // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on
252 // GrRenderTargetContext to perform a necessary flush. The solution is to move drawText calls
253 // to below the GrContext level, but this is not trivial because they call drawPath on
254 // SkGpuDevice.
255 GrContext* context = reinterpret_cast<GrContext*>(data);
256 context->flush();
257 }
258
259 ////////////////////////////////////////////////////////////////////////////////
260
flush()261 void GrContext::flush() {
262 ASSERT_SINGLE_OWNER
263 RETURN_IF_ABANDONED
264
265 fDrawingManager->flush(nullptr);
266 }
267
flush(GrSurfaceProxy * proxy)268 void GrContextPriv::flush(GrSurfaceProxy* proxy) {
269 ASSERT_SINGLE_OWNER_PRIV
270 RETURN_IF_ABANDONED_PRIV
271 ASSERT_OWNED_PROXY_PRIV(proxy);
272
273 fContext->fDrawingManager->flush(proxy);
274 }
275
sw_convert_to_premul(GrPixelConfig srcConfig,int width,int height,size_t inRowBytes,const void * inPixels,size_t outRowBytes,void * outPixels)276 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
277 const void* inPixels, size_t outRowBytes, void* outPixels) {
278 SkColorType colorType;
279 if (!GrPixelConfigToColorType(srcConfig, &colorType) ||
280 4 != SkColorTypeBytesPerPixel(colorType))
281 {
282 return false;
283 }
284
285 for (int y = 0; y < height; y++) {
286 SkOpts::RGBA_to_rgbA((uint32_t*) outPixels, inPixels, width);
287 outPixels = SkTAddOffset<void>(outPixels, outRowBytes);
288 inPixels = SkTAddOffset<const void>(inPixels, inRowBytes);
289 }
290
291 return true;
292 }
293
valid_premul_config(GrPixelConfig config)294 static bool valid_premul_config(GrPixelConfig config) {
295 return GrPixelConfigIs8888Unorm(config) || kRGBA_half_GrPixelConfig == config;
296 }
297
valid_pixel_conversion(GrPixelConfig srcConfig,GrPixelConfig dstConfig,bool premulConversion)298 static bool valid_pixel_conversion(GrPixelConfig srcConfig, GrPixelConfig dstConfig,
299 bool premulConversion) {
300 // We don't allow conversion between integer configs and float/fixed configs.
301 if (GrPixelConfigIsSint(srcConfig) != GrPixelConfigIsSint(dstConfig)) {
302 return false;
303 }
304
305 // We only allow premul <-> unpremul conversions for some formats
306 if (premulConversion && (!valid_premul_config(srcConfig) || !valid_premul_config(dstConfig))) {
307 return false;
308 }
309
310 return true;
311 }
312
pm_upm_must_round_trip(GrPixelConfig config,SkColorSpace * colorSpace)313 static bool pm_upm_must_round_trip(GrPixelConfig config, SkColorSpace* colorSpace) {
314 return !colorSpace &&
315 (kRGBA_8888_GrPixelConfig == config || kBGRA_8888_GrPixelConfig == config);
316 }
317
writeSurfacePixels(GrSurfaceContext * dst,int left,int top,int width,int height,GrPixelConfig srcConfig,SkColorSpace * srcColorSpace,const void * buffer,size_t rowBytes,uint32_t pixelOpsFlags)318 bool GrContextPriv::writeSurfacePixels(GrSurfaceContext* dst,
319 int left, int top, int width, int height,
320 GrPixelConfig srcConfig, SkColorSpace* srcColorSpace,
321 const void* buffer, size_t rowBytes,
322 uint32_t pixelOpsFlags) {
323 // TODO: Color space conversion
324
325 ASSERT_SINGLE_OWNER_PRIV
326 RETURN_FALSE_IF_ABANDONED_PRIV
327 SkASSERT(dst);
328 ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy());
329 GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels", fContext);
330
331 if (!dst->asSurfaceProxy()->instantiate(fContext->resourceProvider())) {
332 return false;
333 }
334
335 GrSurface* dstSurface = dst->asSurfaceProxy()->priv().peekSurface();
336
337 // The src is unpremul but the dst is premul -> premul the src before or as part of the write
338 const bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
339 if (!valid_pixel_conversion(srcConfig, dstSurface->config(), premul)) {
340 return false;
341 }
342
343 // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data,
344 // without any color spaces attached, and the caller wants us to premul.
345 bool useConfigConversionEffect =
346 premul &&
347 pm_upm_must_round_trip(srcConfig, srcColorSpace) &&
348 pm_upm_must_round_trip(dstSurface->config(), dst->getColorSpace());
349
350 // Are we going to try to premul as part of a draw? For the non-legacy case, we always allow
351 // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly.
352 bool premulOnGpu = premul &&
353 (!useConfigConversionEffect || fContext->validPMUPMConversionExists());
354
355 // Trim the params here so that if we wind up making a temporary surface it can be as small as
356 // necessary and because GrGpu::getWritePixelsInfo requires it.
357 if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(),
358 GrBytesPerPixel(srcConfig), &left, &top, &width,
359 &height, &buffer, &rowBytes)) {
360 return false;
361 }
362
363 GrGpu::DrawPreference drawPreference = premulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference
364 : GrGpu::kNoDraw_DrawPreference;
365 GrGpu::WritePixelTempDrawInfo tempDrawInfo;
366 if (!fContext->fGpu->getWritePixelsInfo(dstSurface, width, height, srcConfig,
367 &drawPreference, &tempDrawInfo)) {
368 return false;
369 }
370
371 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && dstSurface->surfacePriv().hasPendingIO()) {
372 this->flush(nullptr); // MDB TODO: tighten this
373 }
374
375 sk_sp<GrTextureProxy> tempProxy;
376 if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
377 tempProxy = GrSurfaceProxy::MakeDeferred(fContext->resourceProvider(),
378 tempDrawInfo.fTempSurfaceDesc,
379 SkBackingFit::kApprox,
380 SkBudgeted::kYes);
381 if (!tempProxy && GrGpu::kRequireDraw_DrawPreference == drawPreference) {
382 return false;
383 }
384 }
385
386 // temp buffer for doing sw premul conversion, if needed.
387 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
388 // We need to do sw premul if we were unable to create a RT for drawing, or if we can't do the
389 // premul on the GPU
390 if (premul && (!tempProxy || !premulOnGpu)) {
391 size_t tmpRowBytes = 4 * width;
392 tmpPixels.reset(width * height);
393 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
394 tmpPixels.get())) {
395 return false;
396 }
397 rowBytes = tmpRowBytes;
398 buffer = tmpPixels.get();
399 }
400
401 if (tempProxy) {
402 sk_sp<GrFragmentProcessor> fp = GrSimpleTextureEffect::Make(
403 tempProxy, nullptr, SkMatrix::I());
404 if (premulOnGpu) {
405 fp = fContext->createUPMToPMEffect(std::move(fp), useConfigConversionEffect);
406 }
407 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle);
408 if (!fp) {
409 return false;
410 }
411
412 if (tempProxy->priv().hasPendingIO()) {
413 this->flush(tempProxy.get());
414 }
415 if (!tempProxy->instantiate(fContext->resourceProvider())) {
416 return false;
417 }
418 GrTexture* texture = tempProxy->priv().peekTexture();
419 if (!fContext->fGpu->writePixels(texture, 0, 0, width, height, tempDrawInfo.fWriteConfig,
420 buffer, rowBytes)) {
421 return false;
422 }
423 SkMatrix matrix;
424 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
425 GrRenderTargetContext* renderTargetContext = dst->asRenderTargetContext();
426 if (!renderTargetContext) {
427 return false;
428 }
429 GrPaint paint;
430 paint.addColorFragmentProcessor(std::move(fp));
431 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
432 paint.setAllowSRGBInputs(SkToBool(dst->getColorSpace()) ||
433 GrPixelConfigIsSRGB(renderTargetContext->config()));
434 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
435 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, rect,
436 nullptr);
437
438 if (kFlushWrites_PixelOp & pixelOpsFlags) {
439 this->flushSurfaceWrites(renderTargetContext->asRenderTargetProxy());
440 }
441 } else {
442 return fContext->fGpu->writePixels(dstSurface, left, top, width, height, srcConfig,
443 buffer, rowBytes);
444 }
445 return true;
446 }
447
readSurfacePixels(GrSurfaceContext * src,int left,int top,int width,int height,GrPixelConfig dstConfig,SkColorSpace * dstColorSpace,void * buffer,size_t rowBytes,uint32_t flags)448 bool GrContextPriv::readSurfacePixels(GrSurfaceContext* src,
449 int left, int top, int width, int height,
450 GrPixelConfig dstConfig, SkColorSpace* dstColorSpace,
451 void* buffer, size_t rowBytes, uint32_t flags) {
452 // TODO: Color space conversion
453
454 ASSERT_SINGLE_OWNER_PRIV
455 RETURN_FALSE_IF_ABANDONED_PRIV
456 SkASSERT(src);
457 ASSERT_OWNED_PROXY_PRIV(src->asSurfaceProxy());
458 GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "readSurfacePixels", fContext);
459
460 // MDB TODO: delay this instantiation until later in the method
461 if (!src->asSurfaceProxy()->instantiate(fContext->resourceProvider())) {
462 return false;
463 }
464
465 GrSurface* srcSurface = src->asSurfaceProxy()->priv().peekSurface();
466
467 // The src is premul but the dst is unpremul -> unpremul the src after or as part of the read
468 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
469 if (!valid_pixel_conversion(srcSurface->config(), dstConfig, unpremul)) {
470 return false;
471 }
472
473 // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data,
474 // without any color spaces attached, and the caller wants us to unpremul.
475 bool useConfigConversionEffect =
476 unpremul &&
477 pm_upm_must_round_trip(srcSurface->config(), src->getColorSpace()) &&
478 pm_upm_must_round_trip(dstConfig, dstColorSpace);
479
480 // Are we going to try to unpremul as part of a draw? For the non-legacy case, we always allow
481 // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly.
482 bool unpremulOnGpu = unpremul &&
483 (!useConfigConversionEffect || fContext->validPMUPMConversionExists());
484
485 // Adjust the params so that if we wind up using an intermediate surface we've already done
486 // all the trimming and the temporary can be the min size required.
487 if (!GrSurfacePriv::AdjustReadPixelParams(srcSurface->width(), srcSurface->height(),
488 GrBytesPerPixel(dstConfig), &left,
489 &top, &width, &height, &buffer, &rowBytes)) {
490 return false;
491 }
492
493 GrGpu::DrawPreference drawPreference = unpremulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference
494 : GrGpu::kNoDraw_DrawPreference;
495 GrGpu::ReadPixelTempDrawInfo tempDrawInfo;
496 if (!fContext->fGpu->getReadPixelsInfo(srcSurface, width, height, rowBytes, dstConfig,
497 &drawPreference, &tempDrawInfo)) {
498 return false;
499 }
500
501 if (!(kDontFlush_PixelOpsFlag & flags) && srcSurface->surfacePriv().hasPendingWrite()) {
502 this->flush(nullptr); // MDB TODO: tighten this
503 }
504
505 sk_sp<GrSurfaceProxy> proxyToRead = src->asSurfaceProxyRef();
506 bool didTempDraw = false;
507 if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
508 if (SkBackingFit::kExact == tempDrawInfo.fTempSurfaceFit) {
509 // We only respect this when the entire src is being read. Otherwise we can trigger too
510 // many odd ball texture sizes and trash the cache.
511 if (width != srcSurface->width() || height != srcSurface->height()) {
512 tempDrawInfo.fTempSurfaceFit= SkBackingFit::kApprox;
513 }
514 }
515 // TODO: Need to decide the semantics of this function for color spaces. Do we support
516 // conversion to a passed-in color space? For now, specifying nullptr means that this
517 // path will do no conversion, so it will match the behavior of the non-draw path.
518 sk_sp<GrRenderTargetContext> tempRTC = fContext->makeDeferredRenderTargetContext(
519 tempDrawInfo.fTempSurfaceFit,
520 tempDrawInfo.fTempSurfaceDesc.fWidth,
521 tempDrawInfo.fTempSurfaceDesc.fHeight,
522 tempDrawInfo.fTempSurfaceDesc.fConfig,
523 nullptr,
524 tempDrawInfo.fTempSurfaceDesc.fSampleCnt,
525 tempDrawInfo.fTempSurfaceDesc.fOrigin);
526 if (tempRTC) {
527 SkMatrix textureMatrix = SkMatrix::MakeTrans(SkIntToScalar(left), SkIntToScalar(top));
528 sk_sp<GrTextureProxy> proxy = src->asTextureProxyRef();
529 sk_sp<GrFragmentProcessor> fp = GrSimpleTextureEffect::Make(
530 std::move(proxy), nullptr, textureMatrix);
531 if (unpremulOnGpu) {
532 fp = fContext->createPMToUPMEffect(std::move(fp), useConfigConversionEffect);
533 // We no longer need to do this on CPU after the read back.
534 unpremul = false;
535 }
536 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle);
537 if (!fp) {
538 return false;
539 }
540
541 GrPaint paint;
542 paint.addColorFragmentProcessor(std::move(fp));
543 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
544 paint.setAllowSRGBInputs(true);
545 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
546 tempRTC->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect,
547 nullptr);
548 proxyToRead = tempRTC->asTextureProxyRef();
549 left = 0;
550 top = 0;
551 didTempDraw = true;
552 }
553 }
554
555 if (!proxyToRead) {
556 return false;
557 }
558
559 if (!proxyToRead->instantiate(fContext->resourceProvider())) {
560 return false;
561 }
562
563 GrSurface* surfaceToRead = proxyToRead->priv().peekSurface();
564
565 if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) {
566 return false;
567 }
568 GrPixelConfig configToRead = dstConfig;
569 if (didTempDraw) {
570 this->flushSurfaceWrites(proxyToRead.get());
571 configToRead = tempDrawInfo.fReadConfig;
572 }
573 if (!fContext->fGpu->readPixels(surfaceToRead, left, top, width, height, configToRead,
574 buffer, rowBytes)) {
575 return false;
576 }
577
578 // Perform umpremul conversion if we weren't able to perform it as a draw.
579 if (unpremul) {
580 SkColorType colorType;
581 if (!GrPixelConfigToColorType(dstConfig, &colorType) ||
582 4 != SkColorTypeBytesPerPixel(colorType))
583 {
584 return false;
585 }
586
587 for (int y = 0; y < height; y++) {
588 SkUnpremultiplyRow<false>((uint32_t*) buffer, (const uint32_t*) buffer, width);
589 buffer = SkTAddOffset<void>(buffer, rowBytes);
590 }
591 }
592 return true;
593 }
594
prepareSurfaceForExternalIO(GrSurfaceProxy * proxy)595 void GrContextPriv::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) {
596 ASSERT_SINGLE_OWNER_PRIV
597 RETURN_IF_ABANDONED_PRIV
598 SkASSERT(proxy);
599 ASSERT_OWNED_PROXY_PRIV(proxy);
600 fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy);
601 }
602
flushSurfaceWrites(GrSurfaceProxy * proxy)603 void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) {
604 ASSERT_SINGLE_OWNER_PRIV
605 RETURN_IF_ABANDONED_PRIV
606 SkASSERT(proxy);
607 ASSERT_OWNED_PROXY_PRIV(proxy);
608 if (proxy->priv().hasPendingWrite()) {
609 this->flush(proxy);
610 }
611 }
612
flushSurfaceIO(GrSurfaceProxy * proxy)613 void GrContextPriv::flushSurfaceIO(GrSurfaceProxy* proxy) {
614 ASSERT_SINGLE_OWNER_PRIV
615 RETURN_IF_ABANDONED_PRIV
616 SkASSERT(proxy);
617 ASSERT_OWNED_PROXY_PRIV(proxy);
618 if (proxy->priv().hasPendingIO()) {
619 this->flush(proxy);
620 }
621 }
622
623 ////////////////////////////////////////////////////////////////////////////////
getRecommendedSampleCount(GrPixelConfig config,SkScalar dpi) const624 int GrContext::getRecommendedSampleCount(GrPixelConfig config,
625 SkScalar dpi) const {
626 ASSERT_SINGLE_OWNER
627
628 if (!this->caps()->isConfigRenderable(config, true)) {
629 return 0;
630 }
631 int chosenSampleCount = 0;
632 if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) {
633 if (dpi >= 250.0f) {
634 chosenSampleCount = 4;
635 } else {
636 chosenSampleCount = 16;
637 }
638 }
639 int supportedSampleCount = fGpu->caps()->getSampleCount(chosenSampleCount, config);
640 return chosenSampleCount <= supportedSampleCount ? supportedSampleCount : 0;
641 }
642
makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy,sk_sp<SkColorSpace> colorSpace)643 sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy,
644 sk_sp<SkColorSpace> colorSpace) {
645 ASSERT_SINGLE_OWNER_PRIV
646
647 if (proxy->asRenderTargetProxy()) {
648 return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
649 std::move(colorSpace), nullptr);
650 } else {
651 SkASSERT(proxy->asTextureProxy());
652 return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
653 }
654 }
655
makeDeferredSurfaceContext(const GrSurfaceDesc & dstDesc,SkBackingFit fit,SkBudgeted isDstBudgeted)656 sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrSurfaceDesc& dstDesc,
657 SkBackingFit fit,
658 SkBudgeted isDstBudgeted) {
659
660 sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeDeferred(fContext->resourceProvider(),
661 dstDesc, fit, isDstBudgeted);
662 if (!proxy) {
663 return nullptr;
664 }
665
666 return this->makeWrappedSurfaceContext(std::move(proxy), nullptr);
667 }
668
makeBackendSurfaceContext(const GrBackendTexture & tex,GrSurfaceOrigin origin,GrBackendTextureFlags flags,int sampleCnt,sk_sp<SkColorSpace> colorSpace)669 sk_sp<GrSurfaceContext> GrContextPriv::makeBackendSurfaceContext(const GrBackendTexture& tex,
670 GrSurfaceOrigin origin,
671 GrBackendTextureFlags flags,
672 int sampleCnt,
673 sk_sp<SkColorSpace> colorSpace) {
674 ASSERT_SINGLE_OWNER_PRIV
675
676 sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTexture(tex, origin,
677 flags, sampleCnt));
678 if (!surface) {
679 return nullptr;
680 }
681
682 sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
683 if (!proxy) {
684 return nullptr;
685 }
686
687 return this->makeWrappedSurfaceContext(std::move(proxy), std::move(colorSpace));
688 }
689
makeBackendTextureRenderTargetContext(const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)690 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext(
691 const GrBackendTexture& tex,
692 GrSurfaceOrigin origin,
693 int sampleCnt,
694 sk_sp<SkColorSpace> colorSpace,
695 const SkSurfaceProps* props) {
696 ASSERT_SINGLE_OWNER_PRIV
697
698 static const GrBackendTextureFlags kForceRT = kRenderTarget_GrBackendTextureFlag;
699 sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTexture(tex, origin, kForceRT,
700 sampleCnt));
701 if (!surface) {
702 return nullptr;
703 }
704
705 sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
706 if (!proxy) {
707 return nullptr;
708 }
709
710 return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
711 std::move(colorSpace), props);
712 }
713
makeBackendRenderTargetRenderTargetContext(const GrBackendRenderTarget & backendRT,GrSurfaceOrigin origin,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps)714 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext(
715 const GrBackendRenderTarget& backendRT,
716 GrSurfaceOrigin origin,
717 sk_sp<SkColorSpace> colorSpace,
718 const SkSurfaceProps* surfaceProps) {
719 ASSERT_SINGLE_OWNER_PRIV
720
721 sk_sp<GrRenderTarget> rt(fContext->resourceProvider()->wrapBackendRenderTarget(backendRT,
722 origin));
723 if (!rt) {
724 return nullptr;
725 }
726
727 sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(rt)));
728 if (!proxy) {
729 return nullptr;
730 }
731
732 return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
733 std::move(colorSpace),
734 surfaceProps);
735 }
736
makeBackendTextureAsRenderTargetRenderTargetContext(const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps)737 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext(
738 const GrBackendTexture& tex,
739 GrSurfaceOrigin origin,
740 int sampleCnt,
741 sk_sp<SkColorSpace> colorSpace,
742 const SkSurfaceProps* surfaceProps) {
743 ASSERT_SINGLE_OWNER_PRIV
744
745 sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTextureAsRenderTarget(
746 tex,
747 origin,
748 sampleCnt));
749 if (!surface) {
750 return nullptr;
751 }
752
753 sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
754 if (!proxy) {
755 return nullptr;
756 }
757
758 return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
759 std::move(colorSpace),
760 surfaceProps);
761 }
762
addOnFlushCallbackObject(GrOnFlushCallbackObject * onFlushCBObject)763 void GrContextPriv::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) {
764 fContext->fDrawingManager->addOnFlushCallbackObject(onFlushCBObject);
765 }
766
767
GrPixelConfigFallback(GrPixelConfig config)768 static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) {
769 switch (config) {
770 case kAlpha_8_GrPixelConfig:
771 case kRGB_565_GrPixelConfig:
772 case kRGBA_4444_GrPixelConfig:
773 case kBGRA_8888_GrPixelConfig:
774 return kRGBA_8888_GrPixelConfig;
775 case kSBGRA_8888_GrPixelConfig:
776 return kSRGBA_8888_GrPixelConfig;
777 case kAlpha_half_GrPixelConfig:
778 return kRGBA_half_GrPixelConfig;
779 default:
780 return kUnknown_GrPixelConfig;
781 }
782 }
783
makeDeferredRenderTargetContextWithFallback(SkBackingFit fit,int width,int height,GrPixelConfig config,sk_sp<SkColorSpace> colorSpace,int sampleCnt,GrSurfaceOrigin origin,const SkSurfaceProps * surfaceProps,SkBudgeted budgeted)784 sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContextWithFallback(
785 SkBackingFit fit,
786 int width, int height,
787 GrPixelConfig config,
788 sk_sp<SkColorSpace> colorSpace,
789 int sampleCnt,
790 GrSurfaceOrigin origin,
791 const SkSurfaceProps* surfaceProps,
792 SkBudgeted budgeted) {
793 if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) {
794 config = GrPixelConfigFallback(config);
795 }
796
797 return this->makeDeferredRenderTargetContext(fit, width, height, config, std::move(colorSpace),
798 sampleCnt, origin, surfaceProps, budgeted);
799 }
800
makeDeferredRenderTargetContext(SkBackingFit fit,int width,int height,GrPixelConfig config,sk_sp<SkColorSpace> colorSpace,int sampleCnt,GrSurfaceOrigin origin,const SkSurfaceProps * surfaceProps,SkBudgeted budgeted)801 sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContext(
802 SkBackingFit fit,
803 int width, int height,
804 GrPixelConfig config,
805 sk_sp<SkColorSpace> colorSpace,
806 int sampleCnt,
807 GrSurfaceOrigin origin,
808 const SkSurfaceProps* surfaceProps,
809 SkBudgeted budgeted) {
810 SkASSERT(kDefault_GrSurfaceOrigin != origin);
811
812 if (this->abandoned()) {
813 return nullptr;
814 }
815
816 GrSurfaceDesc desc;
817 desc.fFlags = kRenderTarget_GrSurfaceFlag;
818 desc.fOrigin = origin;
819 desc.fWidth = width;
820 desc.fHeight = height;
821 desc.fConfig = config;
822 desc.fSampleCnt = sampleCnt;
823
824 sk_sp<GrTextureProxy> rtp = GrSurfaceProxy::MakeDeferred(this->resourceProvider(),
825 desc, fit, budgeted);
826 if (!rtp) {
827 return nullptr;
828 }
829
830 sk_sp<GrRenderTargetContext> renderTargetContext(
831 fDrawingManager->makeRenderTargetContext(std::move(rtp),
832 std::move(colorSpace),
833 surfaceProps));
834 if (!renderTargetContext) {
835 return nullptr;
836 }
837
838 renderTargetContext->discard();
839
840 return renderTargetContext;
841 }
842
abandoned() const843 bool GrContext::abandoned() const {
844 ASSERT_SINGLE_OWNER
845 return fDrawingManager->wasAbandoned();
846 }
847
createPMToUPMEffect(sk_sp<GrFragmentProcessor> fp,bool useConfigConversionEffect)848 sk_sp<GrFragmentProcessor> GrContext::createPMToUPMEffect(sk_sp<GrFragmentProcessor> fp,
849 bool useConfigConversionEffect) {
850 ASSERT_SINGLE_OWNER
851 // We have specialized effects that guarantee round-trip conversion for some formats
852 if (useConfigConversionEffect) {
853 // We should have already called this->validPMUPMConversionExists() in this case
854 SkASSERT(fDidTestPMConversions);
855 // ...and it should have succeeded
856 SkASSERT(this->validPMUPMConversionExists());
857
858 return GrConfigConversionEffect::Make(std::move(fp),
859 GrConfigConversionEffect::kToUnpremul_PMConversion);
860 } else {
861 // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and
862 // explicitly round the results. Just do the obvious, naive thing in the shader.
863 return GrFragmentProcessor::UnpremulOutput(std::move(fp));
864 }
865 }
866
createUPMToPMEffect(sk_sp<GrFragmentProcessor> fp,bool useConfigConversionEffect)867 sk_sp<GrFragmentProcessor> GrContext::createUPMToPMEffect(sk_sp<GrFragmentProcessor> fp,
868 bool useConfigConversionEffect) {
869 ASSERT_SINGLE_OWNER
870 // We have specialized effects that guarantee round-trip conversion for these formats
871 if (useConfigConversionEffect) {
872 // We should have already called this->validPMUPMConversionExists() in this case
873 SkASSERT(fDidTestPMConversions);
874 // ...and it should have succeeded
875 SkASSERT(this->validPMUPMConversionExists());
876
877 return GrConfigConversionEffect::Make(std::move(fp),
878 GrConfigConversionEffect::kToPremul_PMConversion);
879 } else {
880 // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and
881 // explicitly round the results. Just do the obvious, naive thing in the shader.
882 return GrFragmentProcessor::PremulOutput(std::move(fp));
883 }
884 }
885
validPMUPMConversionExists()886 bool GrContext::validPMUPMConversionExists() {
887 ASSERT_SINGLE_OWNER
888 if (!fDidTestPMConversions) {
889 fPMUPMConversionsRoundTrip = GrConfigConversionEffect::TestForPreservingPMConversions(this);
890 fDidTestPMConversions = true;
891 }
892
893 // The PM<->UPM tests fail or succeed together so we only need to check one.
894 return fPMUPMConversionsRoundTrip;
895 }
896
897 //////////////////////////////////////////////////////////////////////////////
898
getResourceCacheLimits(int * maxTextures,size_t * maxTextureBytes) const899 void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
900 ASSERT_SINGLE_OWNER
901 if (maxTextures) {
902 *maxTextures = fResourceCache->getMaxResourceCount();
903 }
904 if (maxTextureBytes) {
905 *maxTextureBytes = fResourceCache->getMaxResourceBytes();
906 }
907 }
908
setResourceCacheLimits(int maxTextures,size_t maxTextureBytes)909 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
910 ASSERT_SINGLE_OWNER
911 fResourceCache->setLimits(maxTextures, maxTextureBytes);
912 }
913
914 //////////////////////////////////////////////////////////////////////////////
915
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const916 void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
917 ASSERT_SINGLE_OWNER
918 fResourceCache->dumpMemoryStatistics(traceMemoryDump);
919 }
920