<commit_before>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/gpu/GrSurfaceDrawContext.h"

#include "include/core/SkDrawable.h"
#include "include/core/SkVertices.h"
#include "include/gpu/GrBackendSemaphore.h"
#include "include/gpu/GrDirectContext.h"
#include "include/gpu/GrRecordingContext.h"
#include "include/private/GrImageContext.h"
#include "include/private/SkShadowFlags.h"
#include "include/private/SkVx.h"
#include "include/utils/SkShadowUtils.h"
#include "src/core/SkAutoPixmapStorage.h"
#include "src/core/SkConvertPixels.h"
#include "src/core/SkDrawProcs.h"
#include "src/core/SkDrawShadowInfo.h"
#include "src/core/SkGlyphRunPainter.h"
#include "src/core/SkLatticeIter.h"
#include "src/core/SkMatrixPriv.h"
#include "src/core/SkMatrixProvider.h"
#include "src/core/SkRRectPriv.h"
#include "src/core/SkSurfacePriv.h"
#include "src/gpu/GrAppliedClip.h"
#include "src/gpu/GrAttachment.h"
#include "src/gpu/GrAuditTrail.h"
#include "src/gpu/GrBlurUtils.h"
#include "src/gpu/GrCaps.h"
#include "src/gpu/GrClip.h"
#include "src/gpu/GrColor.h"
#include "src/gpu/GrDataUtils.h"
#include "src/gpu/GrDirectContextPriv.h"
#include "src/gpu/GrDrawingManager.h"
#include "src/gpu/GrGpuResourcePriv.h"
#include "src/gpu/GrImageContextPriv.h"
#include "src/gpu/GrImageInfo.h"
#include "src/gpu/GrMemoryPool.h"
#include "src/gpu/GrPathRenderer.h"
#include "src/gpu/GrProxyProvider.h"
#include "src/gpu/GrRenderTarget.h"
#include "src/gpu/GrResourceProvider.h"
#include "src/gpu/GrStencilSettings.h"
#include "src/gpu/GrStyle.h"
#include "src/gpu/GrTracing.h"
#include "src/gpu/SkGr.h"
#include "src/gpu/effects/GrBicubicEffect.h"
#include "src/gpu/effects/GrBlendFragmentProcessor.h"
#include "src/gpu/effects/GrRRectEffect.h"
#include "src/gpu/geometry/GrQuad.h"
#include "src/gpu/geometry/GrQuadUtils.h"
#include "src/gpu/geometry/GrStyledShape.h"
#include "src/gpu/ops/GrAtlasTextOp.h"
#include "src/gpu/ops/GrClearOp.h"
#include "src/gpu/ops/GrDrawAtlasOp.h"
#include "src/gpu/ops/GrDrawOp.h"
#include "src/gpu/ops/GrDrawVerticesOp.h"
#include "src/gpu/ops/GrDrawableOp.h"
#include "src/gpu/ops/GrFillRRectOp.h"
#include "src/gpu/ops/GrFillRectOp.h"
#include "src/gpu/ops/GrLatticeOp.h"
#include "src/gpu/ops/GrOp.h"
#include "src/gpu/ops/GrOvalOpFactory.h"
#include "src/gpu/ops/GrRegionOp.h"
#include "src/gpu/ops/GrShadowRRectOp.h"
#include "src/gpu/ops/GrStrokeRectOp.h"
#include "src/gpu/ops/GrTextureOp.h"
#include "src/gpu/text/GrSDFTControl.h"
#include "src/gpu/text/GrTextBlobCache.h"

#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
#define ASSERT_SINGLE_OWNER        GR_ASSERT_SINGLE_OWNER(this->singleOwner())
#define RETURN_IF_ABANDONED        if (fContext->abandoned()) { return; }
#define RETURN_FALSE_IF_ABANDONED  if (fContext->abandoned()) { return false; }

//////////////////////////////////////////////////////////////////////////////

using DoSimplify = GrStyledShape::DoSimplify;

class AutoCheckFlush {
public:
    AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
        SkASSERT(fDrawingManager);
    }
    ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }

private:
    GrDrawingManager* fDrawingManager;
};

std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::Make(GrRecordingContext* context,
                                                                 GrColorType colorType,
                                                                 sk_sp<SkColorSpace> colorSpace,
                                                                 sk_sp<GrSurfaceProxy> proxy,
                                                                 GrSurfaceOrigin origin,
                                                                 const SkSurfaceProps& surfaceProps,
                                                                 bool flushTimeOpsTask) {
    if (!proxy) {
        return nullptr;
    }

    const GrBackendFormat& format = proxy->backendFormat();
    GrSwizzle readSwizzle, writeSwizzle;
    if (colorType != GrColorType::kUnknown) {
        readSwizzle = context->priv().caps()->getReadSwizzle(format, colorType);
        writeSwizzle = context->priv().caps()->getWriteSwizzle(format, colorType);
    }

    GrSurfaceProxyView readView (           proxy, origin,  readSwizzle);
    GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);

    return std::make_unique<GrSurfaceDrawContext>(context,
                                                  std::move(readView),
                                                  std::move(writeView),
                                                  colorType,
                                                  std::move(colorSpace),
                                                  surfaceProps,
                                                  flushTimeOpsTask);
}

std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::Make(
        GrRecordingContext* context,
        sk_sp<SkColorSpace> colorSpace,
        SkBackingFit fit,
        SkISize dimensions,
        const GrBackendFormat& format,
        int sampleCnt,
        GrMipmapped mipMapped,
        GrProtected isProtected,
        GrSwizzle readSwizzle,
        GrSwizzle writeSwizzle,
        GrSurfaceOrigin origin,
        SkBudgeted budgeted,
        const SkSurfaceProps& surfaceProps) {
    // It is probably not necessary to check if the context is abandoned here since uses of the
    // GrSurfaceDrawContext which need the context will mostly likely fail later on without an
    // issue. However having this hear adds some reassurance in case there is a path doesn't handle
    // an abandoned context correctly. It also lets us early out of some extra work.
    if (context->abandoned()) {
        return nullptr;
    }

    sk_sp<GrTextureProxy> proxy = context->priv().proxyProvider()->createProxy(
            format,
            dimensions,
            GrRenderable::kYes,
            sampleCnt,
            mipMapped,
            fit,
            budgeted,
            isProtected);
    if (!proxy) {
        return nullptr;
    }

    GrSurfaceProxyView readView (           proxy, origin,  readSwizzle);
    GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);

    auto rtc = std::make_unique<GrSurfaceDrawContext>(context,
                                                      std::move(readView),
                                                      std::move(writeView),
                                                      GrColorType::kUnknown,
                                                      std::move(colorSpace),
                                                      surfaceProps);
    rtc->discard();
    return rtc;
}

std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::Make(
        GrRecordingContext* context,
        GrColorType colorType,
        sk_sp<SkColorSpace> colorSpace,
        SkBackingFit fit,
        SkISize dimensions,
        const SkSurfaceProps& surfaceProps,
        int sampleCnt,
        GrMipmapped mipMapped,
        GrProtected isProtected,
        GrSurfaceOrigin origin,
        SkBudgeted budgeted) {
    auto format = context->priv().caps()->getDefaultBackendFormat(colorType, GrRenderable::kYes);
    if (!format.isValid()) {
        return nullptr;
    }
    sk_sp<GrTextureProxy> proxy = context->priv().proxyProvider()->createProxy(format,
                                                                               dimensions,
                                                                               GrRenderable::kYes,
                                                                               sampleCnt,
                                                                               mipMapped,
                                                                               fit,
                                                                               budgeted,
                                                                               isProtected);
    if (!proxy) {
        return nullptr;
    }

    return GrSurfaceDrawContext::Make(context,
                                      colorType,
                                      std::move(colorSpace),
                                      std::move(proxy),
                                      origin,
                                      surfaceProps);
}

std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::MakeWithFallback(
        GrRecordingContext* context,
        GrColorType colorType,
        sk_sp<SkColorSpace> colorSpace,
        SkBackingFit fit,
        SkISize dimensions,
        const SkSurfaceProps& surfaceProps,
        int sampleCnt,
        GrMipmapped mipMapped,
        GrProtected isProtected,
        GrSurfaceOrigin origin,
        SkBudgeted budgeted) {
    auto [ct, format] = GetFallbackColorTypeAndFormat(context, colorType, sampleCnt);
    if (ct == GrColorType::kUnknown) {
        return nullptr;
    }
    return GrSurfaceDrawContext::Make(context, ct, colorSpace, fit, dimensions, surfaceProps,
                                      sampleCnt, mipMapped, isProtected, origin, budgeted);
}

std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::MakeFromBackendTexture(
        GrRecordingContext* context,
        GrColorType colorType,
        sk_sp<SkColorSpace> colorSpace,
        const GrBackendTexture& tex,
        int sampleCnt,
        GrSurfaceOrigin origin,
        const SkSurfaceProps& surfaceProps,
        sk_sp<GrRefCntedCallback> releaseHelper) {
    SkASSERT(sampleCnt > 0);
    sk_sp<GrTextureProxy> proxy(context->priv().proxyProvider()->wrapRenderableBackendTexture(
            tex, sampleCnt, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
            std::move(releaseHelper)));
    if (!proxy) {
        return nullptr;
    }

    return GrSurfaceDrawContext::Make(context, colorType, std::move(colorSpace), std::move(proxy),
                                      origin, surfaceProps);
}

std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::MakeFromBackendRenderTarget(
        GrRecordingContext* context,
        GrColorType colorType,
        sk_sp<SkColorSpace> colorSpace,
        const GrBackendRenderTarget& rt,
        GrSurfaceOrigin origin,
        const SkSurfaceProps& surfaceProps,
        sk_sp<GrRefCntedCallback> releaseHelper) {
    sk_sp<GrSurfaceProxy> proxy(
            context->priv().proxyProvider()->wrapBackendRenderTarget(rt, std::move(releaseHelper)));
    if (!proxy) {
        return nullptr;
    }

    return GrSurfaceDrawContext::Make(context, colorType, std::move(colorSpace), std::move(proxy),
                                      origin, surfaceProps);
}

std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::MakeFromVulkanSecondaryCB(
        GrRecordingContext* context,
        const SkImageInfo& imageInfo,
        const GrVkDrawableInfo& vkInfo,
        const SkSurfaceProps& props) {
    sk_sp<GrSurfaceProxy> proxy(
            context->priv().proxyProvider()->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
                                                                                 vkInfo));
    if (!proxy) {
        return nullptr;
    }

    return GrSurfaceDrawContext::Make(context, SkColorTypeToGrColorType(imageInfo.colorType()),
                                      imageInfo.refColorSpace(), std::move(proxy),
                                      kTopLeft_GrSurfaceOrigin, props);
}

// In MDB mode the reffing of the 'getLastOpsTask' call's result allows in-progress
// GrOpsTask to be picked up and added to by renderTargetContexts lower in the call
// stack. When this occurs with a closed GrOpsTask, a new one will be allocated
// when the surfaceDrawContext attempts to use it (via getOpsTask).
GrSurfaceDrawContext::GrSurfaceDrawContext(GrRecordingContext* context,
                                           GrSurfaceProxyView readView,
                                           GrSurfaceProxyView writeView,
                                           GrColorType colorType,
                                           sk_sp<SkColorSpace> colorSpace,
                                           const SkSurfaceProps& surfaceProps,
                                           bool flushTimeOpsTask)
        : GrSurfaceFillContext(context,
                               std::move(readView),
                               std::move(writeView),
                               {colorType, kPremul_SkAlphaType, std::move(colorSpace)},
                               flushTimeOpsTask)
        , fSurfaceProps(surfaceProps)
        , fGlyphPainter(*this) {
    SkDEBUGCODE(this->validate();)
}

GrSurfaceDrawContext::~GrSurfaceDrawContext() {
    ASSERT_SINGLE_OWNER
}

inline GrAAType GrSurfaceDrawContext::chooseAAType(GrAA aa) {
    if (GrAA::kNo == aa) {
        // On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect
        // that.
        if (this->numSamples() > 1 && !this->caps()->multisampleDisableSupport()) {
            return GrAAType::kMSAA;
        }
        return GrAAType::kNone;
    }
    return (this->numSamples() > 1) ? GrAAType::kMSAA : GrAAType::kCoverage;
}

GrMipmapped GrSurfaceDrawContext::mipmapped() const {
    if (const GrTextureProxy* proxy = this->asTextureProxy()) {
        return proxy->mipmapped();
    }
    return GrMipmapped::kNo;
}

void GrSurfaceDrawContext::drawGlyphRunListNoCache(const GrClip* clip,
                                                   const SkMatrixProvider& viewMatrix,
                                                   const SkGlyphRunList& glyphRunList,
                                                   const SkPaint& paint) {
    GrSDFTControl control =
            fContext->priv().getSDFTControl(fSurfaceProps.isUseDeviceIndependentFonts());
    const SkPoint drawOrigin = glyphRunList.origin();
    SkMatrix drawMatrix = viewMatrix.localToDevice();
    drawMatrix.preTranslate(drawOrigin.x(), drawOrigin.y());
    GrSubRunAllocator* const alloc = this->subRunAlloc();

    for (auto& glyphRun : glyphRunList) {
        GrSubRunNoCachePainter painter{this, alloc, clip, viewMatrix, glyphRunList, paint};

        // Make and add the text ops.
        fGlyphPainter.processGlyphRun(glyphRun,
                                      drawMatrix,
                                      paint,
                                      control,
                                      &painter);
    }
}

void GrSurfaceDrawContext::drawGlyphRunListWithCache(const GrClip* clip,
                                                     const SkMatrixProvider& viewMatrix,
                                                     const SkGlyphRunList& glyphRunList,
                                                     const SkPaint& paint) {
    SkMatrix drawMatrix(viewMatrix.localToDevice());
    drawMatrix.preTranslate(glyphRunList.origin().x(), glyphRunList.origin().y());

    GrSDFTControl control =
            this->recordingContext()->priv().getSDFTControl(
                    this->surfaceProps().isUseDeviceIndependentFonts());

    auto [canCache, key] = GrTextBlob::Key::Make(glyphRunList,
                                                 paint,
                                                 fSurfaceProps,
                                                 this->colorInfo(),
                                                 drawMatrix,
                                                 control);

    sk_sp<GrTextBlob> blob;
    GrTextBlobCache* textBlobCache = fContext->priv().getTextBlobCache();
    if (canCache) {
        blob = textBlobCache->find(key);
    }

    if (blob == nullptr || !blob->canReuse(paint, drawMatrix)) {
        if (blob != nullptr) {
            SkASSERT(!drawMatrix.hasPerspective());
            // We have to remake the blob because changes may invalidate our masks.
            // TODO we could probably get away with reuse most of the time if the pointer is unique,
            //      but we'd have to clear the SubRun information
            textBlobCache->remove(blob.get());
        }

        blob = GrTextBlob::Make(glyphRunList, paint, drawMatrix, control, &fGlyphPainter);

        if (canCache) {
            blob->addKey(key);
            // The blob may already have been created on a different thread. Use the first one
            // that was there.
            blob = textBlobCache->addOrReturnExisting(glyphRunList, blob);
        }
    }

    for (const GrSubRun& subRun : blob->subRunList()) {
        subRun.draw(clip, viewMatrix, glyphRunList, paint, this);
    }
}

// choose to use the GrTextBlob cache or not.
bool gGrDrawTextNoCache = false;
void GrSurfaceDrawContext::drawGlyphRunList(const GrClip* clip,
                                            const SkMatrixProvider& viewMatrix,
                                            const SkGlyphRunList& glyphRunList,
                                            const SkPaint& paint) {
    ASSERT_SINGLE_OWNER
    RETURN_IF_ABANDONED
    SkDEBUGCODE(this->validate();)
    GR_CREATE_TRACE_MARKER_CONTEXT("GrSurfaceDrawContext", "drawGlyphRunList", fContext);

    // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
    // secondary command buffers because it would require stopping and starting a render pass which
    // we don't have access to.
    if (this->wrapsVkSecondaryCB()) {
        return;
    }

    if (gGrDrawTextNoCache) {
        // drawGlyphRunListNoCache lives in GrTextBlob.cpp to share sub run implementation code.
        this->drawGlyphRunListNoCache(clip, viewMatrix, glyphRunList, paint);
    } else {
        this->drawGlyphRunListWithCache(clip, viewMatrix, glyphRunList, paint);
    }
}

void GrSurfaceDrawContext::drawPaint(const GrClip* clip,<commit_msg>create ops directly for drawGlyphs, etc.<commit_after>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/gpu/GrSurfaceDrawContext.h"

#include "include/core/SkDrawable.h"
#include "include/core/SkVertices.h"
#include "include/gpu/GrBackendSemaphore.h"
#include "include/gpu/GrDirectContext.h"
#include "include/gpu/GrRecordingContext.h"
#include "include/private/GrImageContext.h"
#include "include/private/SkShadowFlags.h"
#include "include/private/SkVx.h"
#include "include/utils/SkShadowUtils.h"
#include "src/core/SkAutoPixmapStorage.h"
#include "src/core/SkConvertPixels.h"
#include "src/core/SkDrawProcs.h"
#include "src/core/SkDrawShadowInfo.h"
#include "src/core/SkGlyphRunPainter.h"
#include "src/core/SkLatticeIter.h"
#include "src/core/SkMatrixPriv.h"
#include "src/core/SkMatrixProvider.h"
#include "src/core/SkRRectPriv.h"
#include "src/core/SkSurfacePriv.h"
#include "src/gpu/GrAppliedClip.h"
#include "src/gpu/GrAttachment.h"
#include "src/gpu/GrAuditTrail.h"
#include "src/gpu/GrBlurUtils.h"
#include "src/gpu/GrCaps.h"
#include "src/gpu/GrClip.h"
#include "src/gpu/GrColor.h"
#include "src/gpu/GrDataUtils.h"
#include "src/gpu/GrDirectContextPriv.h"
#include "src/gpu/GrDrawingManager.h"
#include "src/gpu/GrGpuResourcePriv.h"
#include "src/gpu/GrImageContextPriv.h"
#include "src/gpu/GrImageInfo.h"
#include "src/gpu/GrMemoryPool.h"
#include "src/gpu/GrPathRenderer.h"
#include "src/gpu/GrProxyProvider.h"
#include "src/gpu/GrRenderTarget.h"
#include "src/gpu/GrResourceProvider.h"
#include "src/gpu/GrStencilSettings.h"
#include "src/gpu/GrStyle.h"
#include "src/gpu/GrTracing.h"
#include "src/gpu/SkGr.h"
#include "src/gpu/effects/GrBicubicEffect.h"
#include "src/gpu/effects/GrBlendFragmentProcessor.h"
#include "src/gpu/effects/GrRRectEffect.h"
#include "src/gpu/geometry/GrQuad.h"
#include "src/gpu/geometry/GrQuadUtils.h"
#include "src/gpu/geometry/GrStyledShape.h"
#include "src/gpu/ops/GrAtlasTextOp.h"
#include "src/gpu/ops/GrClearOp.h"
#include "src/gpu/ops/GrDrawAtlasOp.h"
#include "src/gpu/ops/GrDrawOp.h"
#include "src/gpu/ops/GrDrawVerticesOp.h"
#include "src/gpu/ops/GrDrawableOp.h"
#include "src/gpu/ops/GrFillRRectOp.h"
#include "src/gpu/ops/GrFillRectOp.h"
#include "src/gpu/ops/GrLatticeOp.h"
#include "src/gpu/ops/GrOp.h"
#include "src/gpu/ops/GrOvalOpFactory.h"
#include "src/gpu/ops/GrRegionOp.h"
#include "src/gpu/ops/GrShadowRRectOp.h"
#include "src/gpu/ops/GrStrokeRectOp.h"
#include "src/gpu/ops/GrTextureOp.h"
#include "src/gpu/text/GrSDFTControl.h"
#include "src/gpu/text/GrTextBlobCache.h"

#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
#define ASSERT_SINGLE_OWNER        GR_ASSERT_SINGLE_OWNER(this->singleOwner())
#define RETURN_IF_ABANDONED        if (fContext->abandoned()) { return; }
#define RETURN_FALSE_IF_ABANDONED  if (fContext->abandoned()) { return false; }

//////////////////////////////////////////////////////////////////////////////

using DoSimplify = GrStyledShape::DoSimplify;

class AutoCheckFlush {
public:
    AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
        SkASSERT(fDrawingManager);
    }
    ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }

private:
    GrDrawingManager* fDrawingManager;
};

std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::Make(GrRecordingContext* context,
                                                                 GrColorType colorType,
                                                                 sk_sp<SkColorSpace> colorSpace,
                                                                 sk_sp<GrSurfaceProxy> proxy,
                                                                 GrSurfaceOrigin origin,
                                                                 const SkSurfaceProps& surfaceProps,
                                                                 bool flushTimeOpsTask) {
    if (!proxy) {
        return nullptr;
    }

    const GrBackendFormat& format = proxy->backendFormat();
    GrSwizzle readSwizzle, writeSwizzle;
    if (colorType != GrColorType::kUnknown) {
        readSwizzle = context->priv().caps()->getReadSwizzle(format, colorType);
        writeSwizzle = context->priv().caps()->getWriteSwizzle(format, colorType);
    }

    GrSurfaceProxyView readView (           proxy, origin,  readSwizzle);
    GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);

    return std::make_unique<GrSurfaceDrawContext>(context,
                                                  std::move(readView),
                                                  std::move(writeView),
                                                  colorType,
                                                  std::move(colorSpace),
                                                  surfaceProps,
                                                  flushTimeOpsTask);
}

std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::Make(
        GrRecordingContext* context,
        sk_sp<SkColorSpace> colorSpace,
        SkBackingFit fit,
        SkISize dimensions,
        const GrBackendFormat& format,
        int sampleCnt,
        GrMipmapped mipMapped,
        GrProtected isProtected,
        GrSwizzle readSwizzle,
        GrSwizzle writeSwizzle,
        GrSurfaceOrigin origin,
        SkBudgeted budgeted,
        const SkSurfaceProps& surfaceProps) {
    // It is probably not necessary to check if the context is abandoned here since uses of the
    // GrSurfaceDrawContext which need the context will mostly likely fail later on without an
    // issue. However having this hear adds some reassurance in case there is a path doesn't handle
    // an abandoned context correctly. It also lets us early out of some extra work.
    if (context->abandoned()) {
        return nullptr;
    }

    sk_sp<GrTextureProxy> proxy = context->priv().proxyProvider()->createProxy(
            format,
            dimensions,
            GrRenderable::kYes,
            sampleCnt,
            mipMapped,
            fit,
            budgeted,
            isProtected);
    if (!proxy) {
        return nullptr;
    }

    GrSurfaceProxyView readView (           proxy, origin,  readSwizzle);
    GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);

    auto rtc = std::make_unique<GrSurfaceDrawContext>(context,
                                                      std::move(readView),
                                                      std::move(writeView),
                                                      GrColorType::kUnknown,
                                                      std::move(colorSpace),
                                                      surfaceProps);
    rtc->discard();
    return rtc;
}

std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::Make(
        GrRecordingContext* context,
        GrColorType colorType,
        sk_sp<SkColorSpace> colorSpace,
        SkBackingFit fit,
        SkISize dimensions,
        const SkSurfaceProps& surfaceProps,
        int sampleCnt,
        GrMipmapped mipMapped,
        GrProtected isProtected,
        GrSurfaceOrigin origin,
        SkBudgeted budgeted) {
    auto format = context->priv().caps()->getDefaultBackendFormat(colorType, GrRenderable::kYes);
    if (!format.isValid()) {
        return nullptr;
    }
    sk_sp<GrTextureProxy> proxy = context->priv().proxyProvider()->createProxy(format,
                                                                               dimensions,
                                                                               GrRenderable::kYes,
                                                                               sampleCnt,
                                                                               mipMapped,
                                                                               fit,
                                                                               budgeted,
                                                                               isProtected);
    if (!proxy) {
        return nullptr;
    }

    return GrSurfaceDrawContext::Make(context,
                                      colorType,
                                      std::move(colorSpace),
                                      std::move(proxy),
                                      origin,
                                      surfaceProps);
}

std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::MakeWithFallback(
        GrRecordingContext* context,
        GrColorType colorType,
        sk_sp<SkColorSpace> colorSpace,
        SkBackingFit fit,
        SkISize dimensions,
        const SkSurfaceProps& surfaceProps,
        int sampleCnt,
        GrMipmapped mipMapped,
        GrProtected isProtected,
        GrSurfaceOrigin origin,
        SkBudgeted budgeted) {
    auto [ct, format] = GetFallbackColorTypeAndFormat(context, colorType, sampleCnt);
    if (ct == GrColorType::kUnknown) {
        return nullptr;
    }
    return GrSurfaceDrawContext::Make(context, ct, colorSpace, fit, dimensions, surfaceProps,
                                      sampleCnt, mipMapped, isProtected, origin, budgeted);
}

std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::MakeFromBackendTexture(
        GrRecordingContext* context,
        GrColorType colorType,
        sk_sp<SkColorSpace> colorSpace,
        const GrBackendTexture& tex,
        int sampleCnt,
        GrSurfaceOrigin origin,
        const SkSurfaceProps& surfaceProps,
        sk_sp<GrRefCntedCallback> releaseHelper) {
    SkASSERT(sampleCnt > 0);
    sk_sp<GrTextureProxy> proxy(context->priv().proxyProvider()->wrapRenderableBackendTexture(
            tex, sampleCnt, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
            std::move(releaseHelper)));
    if (!proxy) {
        return nullptr;
    }

    return GrSurfaceDrawContext::Make(context, colorType, std::move(colorSpace), std::move(proxy),
                                      origin, surfaceProps);
}

std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::MakeFromBackendRenderTarget(
        GrRecordingContext* context,
        GrColorType colorType,
        sk_sp<SkColorSpace> colorSpace,
        const GrBackendRenderTarget& rt,
        GrSurfaceOrigin origin,
        const SkSurfaceProps& surfaceProps,
        sk_sp<GrRefCntedCallback> releaseHelper) {
    sk_sp<GrSurfaceProxy> proxy(
            context->priv().proxyProvider()->wrapBackendRenderTarget(rt, std::move(releaseHelper)));
    if (!proxy) {
        return nullptr;
    }

    return GrSurfaceDrawContext::Make(context, colorType, std::move(colorSpace), std::move(proxy),
                                      origin, surfaceProps);
}

std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::MakeFromVulkanSecondaryCB(
        GrRecordingContext* context,
        const SkImageInfo& imageInfo,
        const GrVkDrawableInfo& vkInfo,
        const SkSurfaceProps& props) {
    sk_sp<GrSurfaceProxy> proxy(
            context->priv().proxyProvider()->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
                                                                                 vkInfo));
    if (!proxy) {
        return nullptr;
    }

    return GrSurfaceDrawContext::Make(context, SkColorTypeToGrColorType(imageInfo.colorType()),
                                      imageInfo.refColorSpace(), std::move(proxy),
                                      kTopLeft_GrSurfaceOrigin, props);
}

// In MDB mode the reffing of the 'getLastOpsTask' call's result allows in-progress
// GrOpsTask to be picked up and added to by renderTargetContexts lower in the call
// stack. When this occurs with a closed GrOpsTask, a new one will be allocated
// when the surfaceDrawContext attempts to use it (via getOpsTask).
GrSurfaceDrawContext::GrSurfaceDrawContext(GrRecordingContext* context,
                                           GrSurfaceProxyView readView,
                                           GrSurfaceProxyView writeView,
                                           GrColorType colorType,
                                           sk_sp<SkColorSpace> colorSpace,
                                           const SkSurfaceProps& surfaceProps,
                                           bool flushTimeOpsTask)
        : GrSurfaceFillContext(context,
                               std::move(readView),
                               std::move(writeView),
                               {colorType, kPremul_SkAlphaType, std::move(colorSpace)},
                               flushTimeOpsTask)
        , fSurfaceProps(surfaceProps)
        , fGlyphPainter(*this) {
    SkDEBUGCODE(this->validate();)
}

GrSurfaceDrawContext::~GrSurfaceDrawContext() {
    ASSERT_SINGLE_OWNER
}

inline GrAAType GrSurfaceDrawContext::chooseAAType(GrAA aa) {
    if (GrAA::kNo == aa) {
        // On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect
        // that.
        if (this->numSamples() > 1 && !this->caps()->multisampleDisableSupport()) {
            return GrAAType::kMSAA;
        }
        return GrAAType::kNone;
    }
    return (this->numSamples() > 1) ? GrAAType::kMSAA : GrAAType::kCoverage;
}

GrMipmapped GrSurfaceDrawContext::mipmapped() const {
    if (const GrTextureProxy* proxy = this->asTextureProxy()) {
        return proxy->mipmapped();
    }
    return GrMipmapped::kNo;
}

void GrSurfaceDrawContext::drawGlyphRunListNoCache(const GrClip* clip,
                                                   const SkMatrixProvider& viewMatrix,
                                                   const SkGlyphRunList& glyphRunList,
                                                   const SkPaint& paint) {
    GrSDFTControl control =
            fContext->priv().getSDFTControl(fSurfaceProps.isUseDeviceIndependentFonts());
    const SkPoint drawOrigin = glyphRunList.origin();
    SkMatrix drawMatrix = viewMatrix.localToDevice();
    drawMatrix.preTranslate(drawOrigin.x(), drawOrigin.y());
    GrSubRunAllocator* const alloc = this->subRunAlloc();

    for (auto& glyphRun : glyphRunList) {
        GrSubRunNoCachePainter painter{this, alloc, clip, viewMatrix, glyphRunList, paint};

        // Make and add the text ops.
        fGlyphPainter.processGlyphRun(glyphRun,
                                      drawMatrix,
                                      paint,
                                      control,
                                      &painter);
    }
}

void GrSurfaceDrawContext::drawGlyphRunListWithCache(const GrClip* clip,
                                                     const SkMatrixProvider& viewMatrix,
                                                     const SkGlyphRunList& glyphRunList,
                                                     const SkPaint& paint) {
    SkMatrix drawMatrix(viewMatrix.localToDevice());
    drawMatrix.preTranslate(glyphRunList.origin().x(), glyphRunList.origin().y());

    GrSDFTControl control =
            this->recordingContext()->priv().getSDFTControl(
                    this->surfaceProps().isUseDeviceIndependentFonts());

    auto [canCache, key] = GrTextBlob::Key::Make(glyphRunList,
                                                 paint,
                                                 fSurfaceProps,
                                                 this->colorInfo(),
                                                 drawMatrix,
                                                 control);

    sk_sp<GrTextBlob> blob;
    GrTextBlobCache* textBlobCache = fContext->priv().getTextBlobCache();
    if (canCache) {
        blob = textBlobCache->find(key);
    }

    if (blob == nullptr || !blob->canReuse(paint, drawMatrix)) {
        if (blob != nullptr) {
            SkASSERT(!drawMatrix.hasPerspective());
            // We have to remake the blob because changes may invalidate our masks.
            // TODO we could probably get away with reuse most of the time if the pointer is unique,
            //      but we'd have to clear the SubRun information
            textBlobCache->remove(blob.get());
        }

        blob = GrTextBlob::Make(glyphRunList, paint, drawMatrix, control, &fGlyphPainter);

        if (canCache) {
            blob->addKey(key);
            // The blob may already have been created on a different thread. Use the first one
            // that was there.
            blob = textBlobCache->addOrReturnExisting(glyphRunList, blob);
        }
    }

    for (const GrSubRun& subRun : blob->subRunList()) {
        subRun.draw(clip, viewMatrix, glyphRunList, paint, this);
    }
}

// choose to use the GrTextBlob cache or not.
bool gGrDrawTextNoCache = false;
void GrSurfaceDrawContext::drawGlyphRunList(const GrClip* clip,
                                            const SkMatrixProvider& viewMatrix,
                                            const SkGlyphRunList& glyphRunList,
                                            const SkPaint& paint) {
    ASSERT_SINGLE_OWNER
    RETURN_IF_ABANDONED
    SkDEBUGCODE(this->validate();)
    GR_CREATE_TRACE_MARKER_CONTEXT("GrSurfaceDrawContext", "drawGlyphRunList", fContext);

    // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
    // secondary command buffers because it would require stopping and starting a render pass which
    // we don't have access to.
    if (this->wrapsVkSecondaryCB()) {
        return;
    }

    if (gGrDrawTextNoCache || glyphRunList.blob() == nullptr) {
        // If the glyphRunList does not have an associated text blob, then it was created by one of
        // the direct draw APIs (drawGlyphs, etc.). There is no need to create a GrTextBlob just
        // build the sub run directly and place it in the op.
        this->drawGlyphRunListNoCache(clip, viewMatrix, glyphRunList, paint);
    } else {
        this->drawGlyphRunListWithCache(clip, viewMatrix, glyphRunList, paint);
    }
}

void GrSurfaceDrawContext::drawPaint(const GrClip* clip,
{'fraction_non_alphanumeric': 0.09484022686401992, 'fraction_numerical': 0.0003873288144971642, 'mean_word_length': 1.886138613861386, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 159, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 224, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6591431', 'n_tokens_mistral': 9458, 'n_tokens_neox': 9292, 'n_words': 1981}