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