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