GrContext.cpp revision f3569f0f6d312570c7344b345f8b3a03a892f751
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 "GrBackendSemaphore.h"
9#include "GrContext.h"
10#include "GrClip.h"
11#include "GrContextOptions.h"
12#include "GrContextPriv.h"
13#include "GrDrawingManager.h"
14#include "GrGpu.h"
15#include "GrRenderTargetContext.h"
16#include "GrRenderTargetProxy.h"
17#include "GrResourceCache.h"
18#include "GrResourceProvider.h"
19#include "GrSemaphore.h"
20#include "GrSoftwarePathRenderer.h"
21#include "GrSurfaceContext.h"
22#include "GrSurfacePriv.h"
23#include "GrSurfaceProxyPriv.h"
24#include "GrTexture.h"
25#include "GrTextureContext.h"
26#include "GrTracing.h"
27#include "SkConvertPixels.h"
28#include "SkGr.h"
29#include "SkJSONWriter.h"
30#include "SkMakeUnique.h"
31#include "SkTaskGroup.h"
32#include "SkUnPreMultiplyPriv.h"
33#include "effects/GrConfigConversionEffect.h"
34#include "text/GrTextBlobCache.h"
35
36#include "gl/GrGLGpu.h"
37#include "mock/GrMockGpu.h"
38#ifdef SK_METAL
39#include "mtl/GrMtlTrampoline.h"
40#endif
41#ifdef SK_VULKAN
42#include "vk/GrVkGpu.h"
43#endif
44
45#define ASSERT_OWNED_PROXY(P) \
46SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == this)
47#define ASSERT_OWNED_PROXY_PRIV(P) \
48SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == fContext)
49
50#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
51#define ASSERT_SINGLE_OWNER \
52    SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);)
53#define ASSERT_SINGLE_OWNER_PRIV \
54    SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fContext->fSingleOwner);)
55#define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; }
56#define RETURN_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return; }
57#define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; }
58#define RETURN_FALSE_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return false; }
59#define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; }
60
61////////////////////////////////////////////////////////////////////////////////
62
63GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
64    GrContextOptions defaultOptions;
65    return Create(backend, backendContext, defaultOptions);
66}
67
68GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
69                             const GrContextOptions& options) {
70    sk_sp<GrContext> context(new GrContext);
71
72    if (!context->init(backend, backendContext, options)) {
73        return nullptr;
74    }
75    return context.release();
76}
77
78sk_sp<GrContext> GrContext::MakeGL(const GrGLInterface* interface) {
79    GrContextOptions defaultOptions;
80    return MakeGL(interface, defaultOptions);
81}
82
83sk_sp<GrContext> GrContext::MakeGL(const GrGLInterface* interface,
84                                   const GrContextOptions& options) {
85    sk_sp<GrContext> context(new GrContext);
86    context->fGpu = GrGLGpu::Create(interface, options, context.get());
87    if (!context->fGpu) {
88        return nullptr;
89    }
90    context->fBackend = kOpenGL_GrBackend;
91    if (!context->init(options)) {
92        return nullptr;
93    }
94    return context;
95}
96
97sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions) {
98    GrContextOptions defaultOptions;
99    return MakeMock(mockOptions, defaultOptions);
100}
101
102sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions,
103                                     const GrContextOptions& options) {
104    sk_sp<GrContext> context(new GrContext);
105    context->fGpu = GrMockGpu::Create(mockOptions, options, context.get());
106    if (!context->fGpu) {
107        return nullptr;
108    }
109    context->fBackend = kMock_GrBackend;
110    if (!context->init(options)) {
111        return nullptr;
112    }
113    return context;
114}
115
116#ifdef SK_VULKAN
117sk_sp<GrContext> GrContext::MakeVulkan(const GrVkBackendContext* backendContext) {
118    GrContextOptions defaultOptions;
119    return MakeVulkan(backendContext, defaultOptions);
120}
121
122sk_sp<GrContext> GrContext::MakeVulkan(const GrVkBackendContext* backendContext,
123                                       const GrContextOptions& options) {
124    sk_sp<GrContext> context(new GrContext);
125    context->fGpu = GrVkGpu::Create(backendContext, options, context.get());
126    if (!context->fGpu) {
127        return nullptr;
128    }
129    context->fBackend = kVulkan_GrBackend;
130    if (!context->init(options)) {
131        return nullptr;
132    }
133    return context;
134}
135#endif
136
137#ifdef SK_METAL
138sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue) {
139    GrContextOptions defaultOptions;
140    return MakeMetal(device, queue, defaultOptions);
141}
142
143sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue, const GrContextOptions& options) {
144    sk_sp<GrContext> context(new GrContext);
145    context->fGpu = GrMtlTrampoline::CreateGpu(context.get(), options, device, queue);
146    if (!context->fGpu) {
147        return nullptr;
148    }
149    context->fBackend = kMetal_GrBackend;
150    if (!context->init(options)) {
151        return nullptr;
152    }
153    return context;
154}
155#endif
156
157static int32_t gNextID = 1;
158static int32_t next_id() {
159    int32_t id;
160    do {
161        id = sk_atomic_inc(&gNextID);
162    } while (id == SK_InvalidGenID);
163    return id;
164}
165
166GrContext::GrContext() : fUniqueID(next_id()) {
167    fGpu = nullptr;
168    fCaps = nullptr;
169    fResourceCache = nullptr;
170    fResourceProvider = nullptr;
171    fAtlasGlyphCache = nullptr;
172}
173
174bool GrContext::init(GrBackend backend, GrBackendContext backendContext,
175                     const GrContextOptions& options) {
176    ASSERT_SINGLE_OWNER
177    SkASSERT(!fGpu);
178
179    fBackend = backend;
180
181    fGpu = GrGpu::Create(backend, backendContext, options, this);
182    if (!fGpu) {
183        return false;
184    }
185    return this->init(options);
186}
187
188bool GrContext::init(const GrContextOptions& options) {
189    ASSERT_SINGLE_OWNER
190    fCaps = SkRef(fGpu->caps());
191    fResourceCache = new GrResourceCache(fCaps, fUniqueID);
192    fResourceProvider = new GrResourceProvider(fGpu, fResourceCache, &fSingleOwner);
193
194    fDisableGpuYUVConversion = options.fDisableGpuYUVConversion;
195    fDidTestPMConversions = false;
196
197    GrPathRendererChain::Options prcOptions;
198    prcOptions.fAllowPathMaskCaching = options.fAllowPathMaskCaching;
199#if GR_TEST_UTILS
200    prcOptions.fGpuPathRenderers = options.fGpuPathRenderers;
201#endif
202    if (options.fDisableDistanceFieldPaths) {
203        prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall;
204    }
205    fDrawingManager.reset(new GrDrawingManager(this, prcOptions, &fSingleOwner));
206
207    fAtlasGlyphCache = new GrAtlasGlyphCache(this, options.fGlyphCacheTextureMaximumBytes);
208    this->contextPriv().addOnFlushCallbackObject(fAtlasGlyphCache);
209
210    fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this));
211
212    if (options.fExecutor) {
213        fTaskGroup = skstd::make_unique<SkTaskGroup>(*options.fExecutor);
214    }
215
216    return true;
217}
218
219GrContext::~GrContext() {
220    ASSERT_SINGLE_OWNER
221
222    if (!fGpu) {
223        SkASSERT(!fCaps);
224        return;
225    }
226
227    this->flush();
228
229    fDrawingManager->cleanup();
230
231    for (int i = 0; i < fCleanUpData.count(); ++i) {
232        (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
233    }
234
235    delete fResourceProvider;
236    delete fResourceCache;
237    delete fAtlasGlyphCache;
238
239    fGpu->unref();
240    fCaps->unref();
241}
242
243sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() {
244    if (!fThreadSafeProxy) {
245        fThreadSafeProxy.reset(new GrContextThreadSafeProxy(sk_ref_sp(fCaps), this->uniqueID()));
246    }
247    return fThreadSafeProxy;
248}
249
250void GrContext::abandonContext() {
251    ASSERT_SINGLE_OWNER
252
253    fResourceProvider->abandon();
254
255    // Need to abandon the drawing manager first so all the render targets
256    // will be released/forgotten before they too are abandoned.
257    fDrawingManager->abandon();
258
259    // abandon first to so destructors
260    // don't try to free the resources in the API.
261    fResourceCache->abandonAll();
262
263    fGpu->disconnect(GrGpu::DisconnectType::kAbandon);
264
265    fAtlasGlyphCache->freeAll();
266    fTextBlobCache->freeAll();
267}
268
269void GrContext::releaseResourcesAndAbandonContext() {
270    ASSERT_SINGLE_OWNER
271
272    fResourceProvider->abandon();
273
274    // Need to abandon the drawing manager first so all the render targets
275    // will be released/forgotten before they too are abandoned.
276    fDrawingManager->abandon();
277
278    // Release all resources in the backend 3D API.
279    fResourceCache->releaseAll();
280
281    fGpu->disconnect(GrGpu::DisconnectType::kCleanup);
282
283    fAtlasGlyphCache->freeAll();
284    fTextBlobCache->freeAll();
285}
286
287void GrContext::resetContext(uint32_t state) {
288    ASSERT_SINGLE_OWNER
289    fGpu->markContextDirty(state);
290}
291
292void GrContext::freeGpuResources() {
293    ASSERT_SINGLE_OWNER
294
295    this->flush();
296
297    fAtlasGlyphCache->freeAll();
298
299    fDrawingManager->freeGpuResources();
300
301    fResourceCache->purgeAllUnlocked();
302}
303
304void GrContext::purgeResourcesNotUsedInMs(std::chrono::milliseconds ms) {
305    ASSERT_SINGLE_OWNER
306    fResourceCache->purgeResourcesNotUsedSince(GrStdSteadyClock::now() - ms);
307}
308
309void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
310    ASSERT_SINGLE_OWNER
311    fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources);
312}
313
314void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
315    ASSERT_SINGLE_OWNER
316
317    if (resourceCount) {
318        *resourceCount = fResourceCache->getBudgetedResourceCount();
319    }
320    if (resourceBytes) {
321        *resourceBytes = fResourceCache->getBudgetedResourceBytes();
322    }
323}
324
325size_t GrContext::getResourceCachePurgeableBytes() const {
326    ASSERT_SINGLE_OWNER
327    return fResourceCache->getPurgeableBytes();
328}
329
330////////////////////////////////////////////////////////////////////////////////
331
332void GrContext::TextBlobCacheOverBudgetCB(void* data) {
333    SkASSERT(data);
334    // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on
335    // GrRenderTargetContext to perform a necessary flush.  The solution is to move drawText calls
336    // to below the GrContext level, but this is not trivial because they call drawPath on
337    // SkGpuDevice.
338    GrContext* context = reinterpret_cast<GrContext*>(data);
339    context->flush();
340}
341
342////////////////////////////////////////////////////////////////////////////////
343
344void GrContext::flush() {
345    ASSERT_SINGLE_OWNER
346    RETURN_IF_ABANDONED
347
348    fDrawingManager->flush(nullptr);
349}
350
351GrSemaphoresSubmitted GrContext::flushAndSignalSemaphores(int numSemaphores,
352                                                          GrBackendSemaphore signalSemaphores[]) {
353    ASSERT_SINGLE_OWNER
354    if (fDrawingManager->wasAbandoned()) { return GrSemaphoresSubmitted::kNo; }
355
356    return fDrawingManager->flush(nullptr, numSemaphores, signalSemaphores);
357}
358
359void GrContextPriv::flush(GrSurfaceProxy* proxy) {
360    ASSERT_SINGLE_OWNER_PRIV
361    RETURN_IF_ABANDONED_PRIV
362    ASSERT_OWNED_PROXY_PRIV(proxy);
363
364    fContext->fDrawingManager->flush(proxy);
365}
366
367bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
368                          const void* inPixels, size_t outRowBytes, void* outPixels) {
369    SkColorType colorType;
370    if (!GrPixelConfigToColorType(srcConfig, &colorType) ||
371        4 != SkColorTypeBytesPerPixel(colorType))
372    {
373        return false;
374    }
375
376    for (int y = 0; y < height; y++) {
377        SkOpts::RGBA_to_rgbA((uint32_t*) outPixels, inPixels, width);
378        outPixels = SkTAddOffset<void>(outPixels, outRowBytes);
379        inPixels = SkTAddOffset<const void>(inPixels, inRowBytes);
380    }
381
382    return true;
383}
384
385static bool valid_premul_config(GrPixelConfig config) {
386    return GrPixelConfigIs8888Unorm(config) || kRGBA_half_GrPixelConfig == config;
387}
388
389static bool valid_pixel_conversion(GrPixelConfig srcConfig, GrPixelConfig dstConfig,
390                                   bool premulConversion) {
391    // We don't allow conversion between integer configs and float/fixed configs.
392    if (GrPixelConfigIsSint(srcConfig) != GrPixelConfigIsSint(dstConfig)) {
393        return false;
394    }
395
396    // We only allow premul <-> unpremul conversions for some formats
397    if (premulConversion && (!valid_premul_config(srcConfig) || !valid_premul_config(dstConfig))) {
398        return false;
399    }
400
401    return true;
402}
403
404static bool pm_upm_must_round_trip(GrPixelConfig config, SkColorSpace* colorSpace) {
405    return !colorSpace &&
406           (kRGBA_8888_GrPixelConfig == config || kBGRA_8888_GrPixelConfig == config);
407}
408
409bool GrContextPriv::writeSurfacePixels(GrSurfaceContext* dst,
410                                       int left, int top, int width, int height,
411                                       GrPixelConfig srcConfig, SkColorSpace* srcColorSpace,
412                                       const void* buffer, size_t rowBytes,
413                                       uint32_t pixelOpsFlags) {
414    // TODO: Color space conversion
415
416    ASSERT_SINGLE_OWNER_PRIV
417    RETURN_FALSE_IF_ABANDONED_PRIV
418    SkASSERT(dst);
419    ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy());
420    GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels", fContext);
421
422    if (!dst->asSurfaceProxy()->instantiate(fContext->resourceProvider())) {
423        return false;
424    }
425
426    GrSurfaceProxy* dstProxy = dst->asSurfaceProxy();
427    GrSurface* dstSurface = dstProxy->priv().peekSurface();
428
429    // The src is unpremul but the dst is premul -> premul the src before or as part of the write
430    const bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
431    if (!valid_pixel_conversion(srcConfig, dstProxy->config(), premul)) {
432        return false;
433    }
434
435    // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data,
436    // without any color spaces attached, and the caller wants us to premul.
437    bool useConfigConversionEffect =
438            premul && pm_upm_must_round_trip(srcConfig, srcColorSpace) &&
439            pm_upm_must_round_trip(dstProxy->config(), dst->colorSpaceInfo().colorSpace());
440
441    // Are we going to try to premul as part of a draw? For the non-legacy case, we always allow
442    // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly.
443    bool premulOnGpu = premul &&
444                       (!useConfigConversionEffect || fContext->validPMUPMConversionExists());
445
446    // Trim the params here so that if we wind up making a temporary surface it can be as small as
447    // necessary and because GrGpu::getWritePixelsInfo requires it.
448    if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(),
449                                               GrBytesPerPixel(srcConfig), &left, &top, &width,
450                                               &height, &buffer, &rowBytes)) {
451        return false;
452    }
453
454    GrGpu::DrawPreference drawPreference = premulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference
455                                                       : GrGpu::kNoDraw_DrawPreference;
456    GrGpu::WritePixelTempDrawInfo tempDrawInfo;
457    if (!fContext->fGpu->getWritePixelsInfo(dstSurface, dstProxy->origin(), width, height,
458                                            srcConfig, &drawPreference, &tempDrawInfo)) {
459        return false;
460    }
461
462    if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && dstSurface->surfacePriv().hasPendingIO()) {
463        this->flush(nullptr); // MDB TODO: tighten this
464    }
465
466    sk_sp<GrTextureProxy> tempProxy;
467    if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
468        tempProxy = GrSurfaceProxy::MakeDeferred(fContext->resourceProvider(),
469                                                 tempDrawInfo.fTempSurfaceDesc,
470                                                 SkBackingFit::kApprox,
471                                                 SkBudgeted::kYes);
472        if (!tempProxy && GrGpu::kRequireDraw_DrawPreference == drawPreference) {
473            return false;
474        }
475    }
476
477    // temp buffer for doing sw premul conversion, if needed.
478    SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
479    // We need to do sw premul if we were unable to create a RT for drawing, or if we can't do the
480    // premul on the GPU
481    if (premul && (!tempProxy || !premulOnGpu)) {
482        size_t tmpRowBytes = 4 * width;
483        tmpPixels.reset(width * height);
484        if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
485                                  tmpPixels.get())) {
486            return false;
487        }
488        rowBytes = tmpRowBytes;
489        buffer = tmpPixels.get();
490    }
491
492    if (tempProxy) {
493        auto fp = GrSimpleTextureEffect::Make(tempProxy, SkMatrix::I());
494        if (premulOnGpu) {
495            fp = fContext->createUPMToPMEffect(std::move(fp), useConfigConversionEffect);
496        }
497        fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle);
498        if (!fp) {
499            return false;
500        }
501
502        if (!tempProxy->instantiate(fContext->resourceProvider())) {
503            return false;
504        }
505        GrTexture* texture = tempProxy->priv().peekTexture();
506
507        if (tempProxy->priv().hasPendingIO()) {
508            this->flush(tempProxy.get());
509        }
510
511        if (!fContext->fGpu->writePixels(texture, tempProxy->origin(), 0, 0, width, height,
512                                         tempDrawInfo.fWriteConfig, buffer, rowBytes)) {
513            return false;
514        }
515        tempProxy = nullptr;
516
517        SkMatrix matrix;
518        matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
519        GrRenderTargetContext* renderTargetContext = dst->asRenderTargetContext();
520        if (!renderTargetContext) {
521            return false;
522        }
523        GrPaint paint;
524        paint.addColorFragmentProcessor(std::move(fp));
525        paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
526        paint.setAllowSRGBInputs(dst->colorSpaceInfo().isGammaCorrect() ||
527                                 GrPixelConfigIsSRGB(dst->colorSpaceInfo().config()));
528        SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
529        renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, rect,
530                                        nullptr);
531
532        if (kFlushWrites_PixelOp & pixelOpsFlags) {
533            this->flushSurfaceWrites(renderTargetContext->asRenderTargetProxy());
534        }
535    } else {
536        return fContext->fGpu->writePixels(dstSurface, dstProxy->origin(), left, top, width,
537                                           height, srcConfig, buffer, rowBytes);
538    }
539    return true;
540}
541
542bool GrContextPriv::readSurfacePixels(GrSurfaceContext* src,
543                                      int left, int top, int width, int height,
544                                      GrPixelConfig dstConfig, SkColorSpace* dstColorSpace,
545                                      void* buffer, size_t rowBytes, uint32_t flags) {
546    // TODO: Color space conversion
547
548    ASSERT_SINGLE_OWNER_PRIV
549    RETURN_FALSE_IF_ABANDONED_PRIV
550    SkASSERT(src);
551    ASSERT_OWNED_PROXY_PRIV(src->asSurfaceProxy());
552    GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "readSurfacePixels", fContext);
553
554    // MDB TODO: delay this instantiation until later in the method
555    if (!src->asSurfaceProxy()->instantiate(fContext->resourceProvider())) {
556        return false;
557    }
558
559    GrSurfaceProxy* srcProxy = src->asSurfaceProxy();
560    GrSurface* srcSurface = srcProxy->priv().peekSurface();
561
562    // The src is premul but the dst is unpremul -> unpremul the src after or as part of the read
563    bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
564    if (!valid_pixel_conversion(srcProxy->config(), dstConfig, unpremul)) {
565        return false;
566    }
567
568    // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data,
569    // without any color spaces attached, and the caller wants us to unpremul.
570    bool useConfigConversionEffect =
571            unpremul &&
572            pm_upm_must_round_trip(srcProxy->config(), src->colorSpaceInfo().colorSpace()) &&
573            pm_upm_must_round_trip(dstConfig, dstColorSpace);
574
575    // Are we going to try to unpremul as part of a draw? For the non-legacy case, we always allow
576    // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly.
577    bool unpremulOnGpu = unpremul &&
578                         (!useConfigConversionEffect || fContext->validPMUPMConversionExists());
579
580    // Adjust the params so that if we wind up using an intermediate surface we've already done
581    // all the trimming and the temporary can be the min size required.
582    if (!GrSurfacePriv::AdjustReadPixelParams(srcSurface->width(), srcSurface->height(),
583                                              GrBytesPerPixel(dstConfig), &left,
584                                              &top, &width, &height, &buffer, &rowBytes)) {
585        return false;
586    }
587
588    GrGpu::DrawPreference drawPreference = unpremulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference
589                                                         : GrGpu::kNoDraw_DrawPreference;
590    GrGpu::ReadPixelTempDrawInfo tempDrawInfo;
591    if (!fContext->fGpu->getReadPixelsInfo(srcSurface, srcProxy->origin(), width, height, rowBytes,
592                                           dstConfig, &drawPreference, &tempDrawInfo)) {
593        return false;
594    }
595
596    if (!(kDontFlush_PixelOpsFlag & flags) && srcSurface->surfacePriv().hasPendingWrite()) {
597        this->flush(nullptr); // MDB TODO: tighten this
598    }
599
600    sk_sp<GrSurfaceProxy> proxyToRead = src->asSurfaceProxyRef();
601    bool didTempDraw = false;
602    if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
603        if (SkBackingFit::kExact == tempDrawInfo.fTempSurfaceFit) {
604            // We only respect this when the entire src is being read. Otherwise we can trigger too
605            // many odd ball texture sizes and trash the cache.
606            if (width != srcSurface->width() || height != srcSurface->height()) {
607                tempDrawInfo.fTempSurfaceFit= SkBackingFit::kApprox;
608            }
609        }
610        // TODO: Need to decide the semantics of this function for color spaces. Do we support
611        // conversion to a passed-in color space? For now, specifying nullptr means that this
612        // path will do no conversion, so it will match the behavior of the non-draw path.
613        sk_sp<GrRenderTargetContext> tempRTC = fContext->makeDeferredRenderTargetContext(
614                                                           tempDrawInfo.fTempSurfaceFit,
615                                                           tempDrawInfo.fTempSurfaceDesc.fWidth,
616                                                           tempDrawInfo.fTempSurfaceDesc.fHeight,
617                                                           tempDrawInfo.fTempSurfaceDesc.fConfig,
618                                                           nullptr,
619                                                           tempDrawInfo.fTempSurfaceDesc.fSampleCnt,
620                                                           false,
621                                                           tempDrawInfo.fTempSurfaceDesc.fOrigin);
622        if (tempRTC) {
623            SkMatrix textureMatrix = SkMatrix::MakeTrans(SkIntToScalar(left), SkIntToScalar(top));
624            sk_sp<GrTextureProxy> proxy = src->asTextureProxyRef();
625            auto fp = GrSimpleTextureEffect::Make(std::move(proxy), textureMatrix);
626            if (unpremulOnGpu) {
627                fp = fContext->createPMToUPMEffect(std::move(fp), useConfigConversionEffect);
628                // We no longer need to do this on CPU after the read back.
629                unpremul = false;
630            }
631            fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle);
632            if (!fp) {
633                return false;
634            }
635
636            GrPaint paint;
637            paint.addColorFragmentProcessor(std::move(fp));
638            paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
639            paint.setAllowSRGBInputs(true);
640            SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
641            tempRTC->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect,
642                                nullptr);
643            proxyToRead = tempRTC->asTextureProxyRef();
644            left = 0;
645            top = 0;
646            didTempDraw = true;
647        }
648    }
649
650    if (!proxyToRead) {
651        return false;
652    }
653
654    if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) {
655        return false;
656    }
657    GrPixelConfig configToRead = dstConfig;
658    if (didTempDraw) {
659        this->flushSurfaceWrites(proxyToRead.get());
660        configToRead = tempDrawInfo.fReadConfig;
661    }
662
663    if (!proxyToRead->instantiate(fContext->resourceProvider())) {
664        return false;
665    }
666
667    GrSurface* surfaceToRead = proxyToRead->priv().peekSurface();
668
669    if (!fContext->fGpu->readPixels(surfaceToRead, proxyToRead->origin(),
670                                    left, top, width, height, configToRead, buffer, rowBytes)) {
671        return false;
672    }
673
674    // Perform umpremul conversion if we weren't able to perform it as a draw.
675    if (unpremul) {
676        SkColorType colorType;
677        if (!GrPixelConfigToColorType(dstConfig, &colorType) ||
678            4 != SkColorTypeBytesPerPixel(colorType))
679        {
680            return false;
681        }
682
683        for (int y = 0; y < height; y++) {
684            SkUnpremultiplyRow<false>((uint32_t*) buffer, (const uint32_t*) buffer, width);
685            buffer = SkTAddOffset<void>(buffer, rowBytes);
686        }
687    }
688    return true;
689}
690
691void GrContextPriv::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) {
692    ASSERT_SINGLE_OWNER_PRIV
693    RETURN_IF_ABANDONED_PRIV
694    SkASSERT(proxy);
695    ASSERT_OWNED_PROXY_PRIV(proxy);
696    fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy, 0, nullptr);
697}
698
699void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) {
700    ASSERT_SINGLE_OWNER_PRIV
701    RETURN_IF_ABANDONED_PRIV
702    SkASSERT(proxy);
703    ASSERT_OWNED_PROXY_PRIV(proxy);
704    if (proxy->priv().hasPendingWrite()) {
705        this->flush(proxy);
706    }
707}
708
709void GrContextPriv::flushSurfaceIO(GrSurfaceProxy* proxy) {
710    ASSERT_SINGLE_OWNER_PRIV
711    RETURN_IF_ABANDONED_PRIV
712    SkASSERT(proxy);
713    ASSERT_OWNED_PROXY_PRIV(proxy);
714    if (proxy->priv().hasPendingIO()) {
715        this->flush(proxy);
716    }
717}
718
719////////////////////////////////////////////////////////////////////////////////
720int GrContext::getRecommendedSampleCount(GrPixelConfig config,
721                                         SkScalar dpi) const {
722    ASSERT_SINGLE_OWNER
723
724    if (!this->caps()->isConfigRenderable(config, true)) {
725        return 0;
726    }
727    int chosenSampleCount = 0;
728    if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) {
729        if (dpi >= 250.0f) {
730            chosenSampleCount = 4;
731        } else {
732            chosenSampleCount = 16;
733        }
734    }
735    int supportedSampleCount = fGpu->caps()->getSampleCount(chosenSampleCount, config);
736    return chosenSampleCount <= supportedSampleCount ? supportedSampleCount : 0;
737}
738
739sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy,
740                                                                 sk_sp<SkColorSpace> colorSpace) {
741    ASSERT_SINGLE_OWNER_PRIV
742
743    if (proxy->asRenderTargetProxy()) {
744        return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
745                                                               std::move(colorSpace), nullptr);
746    } else {
747        SkASSERT(proxy->asTextureProxy());
748        return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
749    }
750}
751
752sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrSurfaceDesc& dstDesc,
753                                                                  SkBackingFit fit,
754                                                                  SkBudgeted isDstBudgeted) {
755
756    sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeDeferred(fContext->resourceProvider(),
757                                                               dstDesc, fit, isDstBudgeted);
758    if (!proxy) {
759        return nullptr;
760    }
761
762    return this->makeWrappedSurfaceContext(std::move(proxy), nullptr);
763}
764
765sk_sp<GrTextureContext> GrContextPriv::makeBackendTextureContext(const GrBackendTexture& tex,
766                                                                 GrSurfaceOrigin origin,
767                                                                 sk_sp<SkColorSpace> colorSpace) {
768    ASSERT_SINGLE_OWNER_PRIV
769
770    sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTexture(tex));
771    if (!surface) {
772        return nullptr;
773    }
774
775    sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface), origin));
776    if (!proxy) {
777        return nullptr;
778    }
779
780    return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
781}
782
783sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext(
784                                                                   const GrBackendTexture& tex,
785                                                                   GrSurfaceOrigin origin,
786                                                                   int sampleCnt,
787                                                                   sk_sp<SkColorSpace> colorSpace,
788                                                                   const SkSurfaceProps* props) {
789    ASSERT_SINGLE_OWNER_PRIV
790
791    sk_sp<GrSurface> surface(
792            fContext->resourceProvider()->wrapRenderableBackendTexture(tex, sampleCnt));
793    if (!surface) {
794        return nullptr;
795    }
796
797    sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface), origin));
798    if (!proxy) {
799        return nullptr;
800    }
801
802    return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
803                                                           std::move(colorSpace), props);
804}
805
806sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext(
807                                                const GrBackendRenderTarget& backendRT,
808                                                GrSurfaceOrigin origin,
809                                                sk_sp<SkColorSpace> colorSpace,
810                                                const SkSurfaceProps* surfaceProps) {
811    ASSERT_SINGLE_OWNER_PRIV
812
813    sk_sp<GrRenderTarget> rt(fContext->resourceProvider()->wrapBackendRenderTarget(backendRT));
814    if (!rt) {
815        return nullptr;
816    }
817
818    sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(rt), origin));
819    if (!proxy) {
820        return nullptr;
821    }
822
823    return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
824                                                           std::move(colorSpace),
825                                                           surfaceProps);
826}
827
828sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext(
829                                                     const GrBackendTexture& tex,
830                                                     GrSurfaceOrigin origin,
831                                                     int sampleCnt,
832                                                     sk_sp<SkColorSpace> colorSpace,
833                                                     const SkSurfaceProps* surfaceProps) {
834    ASSERT_SINGLE_OWNER_PRIV
835
836    sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTextureAsRenderTarget(
837                                                                                        tex,
838                                                                                        sampleCnt));
839    if (!surface) {
840        return nullptr;
841    }
842
843    sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface), origin));
844    if (!proxy) {
845        return nullptr;
846    }
847
848    return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
849                                                           std::move(colorSpace),
850                                                           surfaceProps);
851}
852
853void GrContextPriv::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) {
854    fContext->fDrawingManager->addOnFlushCallbackObject(onFlushCBObject);
855}
856
857
858static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) {
859    switch (config) {
860        case kAlpha_8_GrPixelConfig:
861        case kRGB_565_GrPixelConfig:
862        case kRGBA_4444_GrPixelConfig:
863        case kBGRA_8888_GrPixelConfig:
864            return kRGBA_8888_GrPixelConfig;
865        case kSBGRA_8888_GrPixelConfig:
866            return kSRGBA_8888_GrPixelConfig;
867        case kAlpha_half_GrPixelConfig:
868            return kRGBA_half_GrPixelConfig;
869        default:
870            return kUnknown_GrPixelConfig;
871    }
872}
873
874sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContextWithFallback(
875                                                                 SkBackingFit fit,
876                                                                 int width, int height,
877                                                                 GrPixelConfig config,
878                                                                 sk_sp<SkColorSpace> colorSpace,
879                                                                 int sampleCnt,
880                                                                 bool willNeedMipMaps,
881                                                                 GrSurfaceOrigin origin,
882                                                                 const SkSurfaceProps* surfaceProps,
883                                                                 SkBudgeted budgeted) {
884    if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) {
885        config = GrPixelConfigFallback(config);
886    }
887
888    return this->makeDeferredRenderTargetContext(fit, width, height, config, std::move(colorSpace),
889                                                 sampleCnt, willNeedMipMaps, origin, surfaceProps,
890                                                 budgeted);
891}
892
893sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContext(
894                                                        SkBackingFit fit,
895                                                        int width, int height,
896                                                        GrPixelConfig config,
897                                                        sk_sp<SkColorSpace> colorSpace,
898                                                        int sampleCnt,
899                                                        bool willNeedMipMaps,
900                                                        GrSurfaceOrigin origin,
901                                                        const SkSurfaceProps* surfaceProps,
902                                                        SkBudgeted budgeted) {
903    if (this->abandoned()) {
904        return nullptr;
905    }
906
907    GrSurfaceDesc desc;
908    desc.fFlags = kRenderTarget_GrSurfaceFlag;
909    desc.fOrigin = origin;
910    desc.fWidth = width;
911    desc.fHeight = height;
912    desc.fConfig = config;
913    desc.fSampleCnt = sampleCnt;
914
915    sk_sp<GrTextureProxy> rtp;
916    if (!willNeedMipMaps) {
917        rtp = GrSurfaceProxy::MakeDeferred(this->resourceProvider(), desc, fit, budgeted);
918    } else {
919        rtp = GrSurfaceProxy::MakeDeferredMipMap(this->resourceProvider(), desc, budgeted);
920    }
921    if (!rtp) {
922        return nullptr;
923    }
924
925    sk_sp<GrRenderTargetContext> renderTargetContext(
926        fDrawingManager->makeRenderTargetContext(std::move(rtp),
927                                                 std::move(colorSpace),
928                                                 surfaceProps));
929    if (!renderTargetContext) {
930        return nullptr;
931    }
932
933    renderTargetContext->discard();
934
935    return renderTargetContext;
936}
937
938bool GrContext::abandoned() const {
939    ASSERT_SINGLE_OWNER
940    return fDrawingManager->wasAbandoned();
941}
942
943std::unique_ptr<GrFragmentProcessor> GrContext::createPMToUPMEffect(
944        std::unique_ptr<GrFragmentProcessor> fp, bool useConfigConversionEffect) {
945    ASSERT_SINGLE_OWNER
946    // We have specialized effects that guarantee round-trip conversion for some formats
947    if (useConfigConversionEffect) {
948        // We should have already called this->validPMUPMConversionExists() in this case
949        SkASSERT(fDidTestPMConversions);
950        // ...and it should have succeeded
951        SkASSERT(this->validPMUPMConversionExists());
952
953        return GrConfigConversionEffect::Make(std::move(fp),
954                                              GrConfigConversionEffect::kToUnpremul_PMConversion);
955    } else {
956        // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and
957        // explicitly round the results. Just do the obvious, naive thing in the shader.
958        return GrFragmentProcessor::UnpremulOutput(std::move(fp));
959    }
960}
961
962std::unique_ptr<GrFragmentProcessor> GrContext::createUPMToPMEffect(
963        std::unique_ptr<GrFragmentProcessor> fp, bool useConfigConversionEffect) {
964    ASSERT_SINGLE_OWNER
965    // We have specialized effects that guarantee round-trip conversion for these formats
966    if (useConfigConversionEffect) {
967        // We should have already called this->validPMUPMConversionExists() in this case
968        SkASSERT(fDidTestPMConversions);
969        // ...and it should have succeeded
970        SkASSERT(this->validPMUPMConversionExists());
971
972        return GrConfigConversionEffect::Make(std::move(fp),
973                                              GrConfigConversionEffect::kToPremul_PMConversion);
974    } else {
975        // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and
976        // explicitly round the results. Just do the obvious, naive thing in the shader.
977        return GrFragmentProcessor::PremulOutput(std::move(fp));
978    }
979}
980
981bool GrContext::validPMUPMConversionExists() {
982    ASSERT_SINGLE_OWNER
983    if (!fDidTestPMConversions) {
984        fPMUPMConversionsRoundTrip = GrConfigConversionEffect::TestForPreservingPMConversions(this);
985        fDidTestPMConversions = true;
986    }
987
988    // The PM<->UPM tests fail or succeed together so we only need to check one.
989    return fPMUPMConversionsRoundTrip;
990}
991
992//////////////////////////////////////////////////////////////////////////////
993
994void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
995    ASSERT_SINGLE_OWNER
996    if (maxTextures) {
997        *maxTextures = fResourceCache->getMaxResourceCount();
998    }
999    if (maxTextureBytes) {
1000        *maxTextureBytes = fResourceCache->getMaxResourceBytes();
1001    }
1002}
1003
1004void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
1005    ASSERT_SINGLE_OWNER
1006    fResourceCache->setLimits(maxTextures, maxTextureBytes);
1007}
1008
1009//////////////////////////////////////////////////////////////////////////////
1010
1011void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
1012    ASSERT_SINGLE_OWNER
1013    fResourceCache->dumpMemoryStatistics(traceMemoryDump);
1014}
1015
1016//////////////////////////////////////////////////////////////////////////////
1017
1018SkString GrContext::dump() const {
1019    SkDynamicMemoryWStream stream;
1020    SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty);
1021    writer.beginObject();
1022
1023    static const char* kBackendStr[] = {
1024        "Metal",
1025        "OpenGL",
1026        "Vulkan",
1027        "Mock",
1028    };
1029    GR_STATIC_ASSERT(0 == kMetal_GrBackend);
1030    GR_STATIC_ASSERT(1 == kOpenGL_GrBackend);
1031    GR_STATIC_ASSERT(2 == kVulkan_GrBackend);
1032    GR_STATIC_ASSERT(3 == kMock_GrBackend);
1033    writer.appendString("backend", kBackendStr[fBackend]);
1034
1035    writer.appendName("caps");
1036    fCaps->dumpJSON(&writer);
1037
1038    writer.appendName("gpu");
1039    fGpu->dumpJSON(&writer);
1040
1041    // Flush JSON to the memory stream
1042    writer.endObject();
1043    writer.flush();
1044
1045    // Null terminate the JSON data in the memory stream
1046    stream.write8(0);
1047
1048    // Allocate a string big enough to hold all the data, then copy out of the stream
1049    SkString result(stream.bytesWritten());
1050    stream.copyToAndReset(result.writable_str());
1051    return result;
1052}
1053