GrContext.cpp revision 96be9df1300b2281641b038ef11064157f6e0b41
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) \
37SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == this)
38#define ASSERT_OWNED_PROXY_PRIV(P) \
39SkASSERT(!(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
54GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
55    GrContextOptions defaultOptions;
56    return Create(backend, backendContext, defaultOptions);
57}
58
59GrContext* 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
70sk_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
84static int32_t gNextID = 1;
85static 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
93GrContext::GrContext() : fUniqueID(next_id()) {
94    fGpu = nullptr;
95    fCaps = nullptr;
96    fResourceCache = nullptr;
97    fResourceProvider = nullptr;
98    fAtlasGlyphCache = nullptr;
99}
100
101bool 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
115bool 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
136GrContext::~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
160sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() {
161    if (!fThreadSafeProxy) {
162        fThreadSafeProxy.reset(new GrContextThreadSafeProxy(sk_ref_sp(fCaps), this->uniqueID()));
163    }
164    return fThreadSafeProxy;
165}
166
167void 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
186void 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
204void GrContext::resetContext(uint32_t state) {
205    ASSERT_SINGLE_OWNER
206    fGpu->markContextDirty(state);
207}
208
209void GrContext::freeGpuResources() {
210    ASSERT_SINGLE_OWNER
211
212    this->flush();
213
214    fAtlasGlyphCache->freeAll();
215
216    fDrawingManager->freeGpuResources();
217
218    fResourceCache->purgeAllUnlocked();
219}
220
221void GrContext::purgeResourcesNotUsedInMs(std::chrono::milliseconds ms) {
222    ASSERT_SINGLE_OWNER
223    fResourceCache->purgeResourcesNotUsedSince(GrStdSteadyClock::now() - ms);
224}
225
226void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
227    ASSERT_SINGLE_OWNER
228    fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources);
229}
230
231void 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
242size_t GrContext::getResourceCachePurgeableBytes() const {
243    ASSERT_SINGLE_OWNER
244    return fResourceCache->getPurgeableBytes();
245}
246
247////////////////////////////////////////////////////////////////////////////////
248
249void 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
261void GrContext::flush() {
262    ASSERT_SINGLE_OWNER
263    RETURN_IF_ABANDONED
264
265    fDrawingManager->flush(nullptr);
266}
267
268void 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
276bool 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
294static bool valid_premul_config(GrPixelConfig config) {
295    return GrPixelConfigIs8888Unorm(config) || kRGBA_half_GrPixelConfig == config;
296}
297
298static 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
313static bool pm_upm_must_round_trip(GrPixelConfig config, SkColorSpace* colorSpace) {
314    return !colorSpace &&
315           (kRGBA_8888_GrPixelConfig == config || kBGRA_8888_GrPixelConfig == config);
316}
317
318bool 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
448bool 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
595void 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
603void 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
613void 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////////////////////////////////////////////////////////////////////////////////
624int 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
643sk_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
656sk_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
669sk_sp<GrTextureContext> GrContextPriv::makeBackendTextureContext(const GrBackendTexture& tex,
670                                                                 GrSurfaceOrigin origin,
671                                                                 sk_sp<SkColorSpace> colorSpace) {
672    ASSERT_SINGLE_OWNER_PRIV
673
674    sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTexture(tex, origin));
675    if (!surface) {
676        return nullptr;
677    }
678
679    sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
680    if (!proxy) {
681        return nullptr;
682    }
683
684    return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
685}
686
687sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext(
688                                                                   const GrBackendTexture& tex,
689                                                                   GrSurfaceOrigin origin,
690                                                                   int sampleCnt,
691                                                                   sk_sp<SkColorSpace> colorSpace,
692                                                                   const SkSurfaceProps* props) {
693    ASSERT_SINGLE_OWNER_PRIV
694
695    sk_sp<GrSurface> surface(
696            fContext->resourceProvider()->wrapRenderableBackendTexture(tex, origin, sampleCnt));
697    if (!surface) {
698        return nullptr;
699    }
700
701    sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
702    if (!proxy) {
703        return nullptr;
704    }
705
706    return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
707                                                           std::move(colorSpace), props);
708}
709
710sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext(
711                                                const GrBackendRenderTarget& backendRT,
712                                                GrSurfaceOrigin origin,
713                                                sk_sp<SkColorSpace> colorSpace,
714                                                const SkSurfaceProps* surfaceProps) {
715    ASSERT_SINGLE_OWNER_PRIV
716
717    sk_sp<GrRenderTarget> rt(fContext->resourceProvider()->wrapBackendRenderTarget(backendRT,
718                                                                                   origin));
719    if (!rt) {
720        return nullptr;
721    }
722
723    sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(rt)));
724    if (!proxy) {
725        return nullptr;
726    }
727
728    return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
729                                                           std::move(colorSpace),
730                                                           surfaceProps);
731}
732
733sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext(
734                                                     const GrBackendTexture& tex,
735                                                     GrSurfaceOrigin origin,
736                                                     int sampleCnt,
737                                                     sk_sp<SkColorSpace> colorSpace,
738                                                     const SkSurfaceProps* surfaceProps) {
739    ASSERT_SINGLE_OWNER_PRIV
740
741    sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTextureAsRenderTarget(
742                                                                                        tex,
743                                                                                        origin,
744                                                                                        sampleCnt));
745    if (!surface) {
746        return nullptr;
747    }
748
749    sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
750    if (!proxy) {
751        return nullptr;
752    }
753
754    return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
755                                                           std::move(colorSpace),
756                                                           surfaceProps);
757}
758
759void GrContextPriv::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) {
760    fContext->fDrawingManager->addOnFlushCallbackObject(onFlushCBObject);
761}
762
763
764static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) {
765    switch (config) {
766        case kAlpha_8_GrPixelConfig:
767        case kRGB_565_GrPixelConfig:
768        case kRGBA_4444_GrPixelConfig:
769        case kBGRA_8888_GrPixelConfig:
770            return kRGBA_8888_GrPixelConfig;
771        case kSBGRA_8888_GrPixelConfig:
772            return kSRGBA_8888_GrPixelConfig;
773        case kAlpha_half_GrPixelConfig:
774            return kRGBA_half_GrPixelConfig;
775        default:
776            return kUnknown_GrPixelConfig;
777    }
778}
779
780sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContextWithFallback(
781                                                                 SkBackingFit fit,
782                                                                 int width, int height,
783                                                                 GrPixelConfig config,
784                                                                 sk_sp<SkColorSpace> colorSpace,
785                                                                 int sampleCnt,
786                                                                 GrSurfaceOrigin origin,
787                                                                 const SkSurfaceProps* surfaceProps,
788                                                                 SkBudgeted budgeted) {
789    if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) {
790        config = GrPixelConfigFallback(config);
791    }
792
793    return this->makeDeferredRenderTargetContext(fit, width, height, config, std::move(colorSpace),
794                                                 sampleCnt, origin, surfaceProps, budgeted);
795}
796
797sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContext(
798                                                        SkBackingFit fit,
799                                                        int width, int height,
800                                                        GrPixelConfig config,
801                                                        sk_sp<SkColorSpace> colorSpace,
802                                                        int sampleCnt,
803                                                        GrSurfaceOrigin origin,
804                                                        const SkSurfaceProps* surfaceProps,
805                                                        SkBudgeted budgeted) {
806    SkASSERT(kDefault_GrSurfaceOrigin != origin);
807
808    if (this->abandoned()) {
809        return nullptr;
810    }
811
812    GrSurfaceDesc desc;
813    desc.fFlags = kRenderTarget_GrSurfaceFlag;
814    desc.fOrigin = origin;
815    desc.fWidth = width;
816    desc.fHeight = height;
817    desc.fConfig = config;
818    desc.fSampleCnt = sampleCnt;
819
820    sk_sp<GrTextureProxy> rtp = GrSurfaceProxy::MakeDeferred(this->resourceProvider(),
821                                                             desc, fit, budgeted);
822    if (!rtp) {
823        return nullptr;
824    }
825
826    sk_sp<GrRenderTargetContext> renderTargetContext(
827        fDrawingManager->makeRenderTargetContext(std::move(rtp),
828                                                 std::move(colorSpace),
829                                                 surfaceProps));
830    if (!renderTargetContext) {
831        return nullptr;
832    }
833
834    renderTargetContext->discard();
835
836    return renderTargetContext;
837}
838
839bool GrContext::abandoned() const {
840    ASSERT_SINGLE_OWNER
841    return fDrawingManager->wasAbandoned();
842}
843
844sk_sp<GrFragmentProcessor> GrContext::createPMToUPMEffect(sk_sp<GrFragmentProcessor> fp,
845                                                          bool useConfigConversionEffect) {
846    ASSERT_SINGLE_OWNER
847    // We have specialized effects that guarantee round-trip conversion for some formats
848    if (useConfigConversionEffect) {
849        // We should have already called this->validPMUPMConversionExists() in this case
850        SkASSERT(fDidTestPMConversions);
851        // ...and it should have succeeded
852        SkASSERT(this->validPMUPMConversionExists());
853
854        return GrConfigConversionEffect::Make(std::move(fp),
855                                              GrConfigConversionEffect::kToUnpremul_PMConversion);
856    } else {
857        // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and
858        // explicitly round the results. Just do the obvious, naive thing in the shader.
859        return GrFragmentProcessor::UnpremulOutput(std::move(fp));
860    }
861}
862
863sk_sp<GrFragmentProcessor> GrContext::createUPMToPMEffect(sk_sp<GrFragmentProcessor> fp,
864                                                          bool useConfigConversionEffect) {
865    ASSERT_SINGLE_OWNER
866    // We have specialized effects that guarantee round-trip conversion for these formats
867    if (useConfigConversionEffect) {
868        // We should have already called this->validPMUPMConversionExists() in this case
869        SkASSERT(fDidTestPMConversions);
870        // ...and it should have succeeded
871        SkASSERT(this->validPMUPMConversionExists());
872
873        return GrConfigConversionEffect::Make(std::move(fp),
874                                              GrConfigConversionEffect::kToPremul_PMConversion);
875    } else {
876        // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and
877        // explicitly round the results. Just do the obvious, naive thing in the shader.
878        return GrFragmentProcessor::PremulOutput(std::move(fp));
879    }
880}
881
882bool GrContext::validPMUPMConversionExists() {
883    ASSERT_SINGLE_OWNER
884    if (!fDidTestPMConversions) {
885        fPMUPMConversionsRoundTrip = GrConfigConversionEffect::TestForPreservingPMConversions(this);
886        fDidTestPMConversions = true;
887    }
888
889    // The PM<->UPM tests fail or succeed together so we only need to check one.
890    return fPMUPMConversionsRoundTrip;
891}
892
893//////////////////////////////////////////////////////////////////////////////
894
895void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
896    ASSERT_SINGLE_OWNER
897    if (maxTextures) {
898        *maxTextures = fResourceCache->getMaxResourceCount();
899    }
900    if (maxTextureBytes) {
901        *maxTextureBytes = fResourceCache->getMaxResourceBytes();
902    }
903}
904
905void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
906    ASSERT_SINGLE_OWNER
907    fResourceCache->setLimits(maxTextures, maxTextureBytes);
908}
909
910//////////////////////////////////////////////////////////////////////////////
911
912void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
913    ASSERT_SINGLE_OWNER
914    fResourceCache->dumpMemoryStatistics(traceMemoryDump);
915}
916