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