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