• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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