LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu - GrClipStackClip.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 224 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2016 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 "GrClipStackClip.h"
       9             : 
      10             : #include "GrAppliedClip.h"
      11             : #include "GrContextPriv.h"
      12             : #include "GrDrawingManager.h"
      13             : #include "GrRenderTargetContextPriv.h"
      14             : #include "GrFixedClip.h"
      15             : #include "GrGpuResourcePriv.h"
      16             : #include "GrRenderTargetPriv.h"
      17             : #include "GrStencilAttachment.h"
      18             : #include "GrSWMaskHelper.h"
      19             : #include "GrTextureProxy.h"
      20             : #include "effects/GrConvexPolyEffect.h"
      21             : #include "effects/GrRRectEffect.h"
      22             : #include "effects/GrTextureDomain.h"
      23             : #include "SkClipOpPriv.h"
      24             : 
      25             : typedef SkClipStack::Element Element;
      26             : typedef GrReducedClip::InitialState InitialState;
      27             : typedef GrReducedClip::ElementList ElementList;
      28             : 
      29             : static const int kMaxAnalyticElements = 4;
      30             : const char GrClipStackClip::kMaskTestTag[] = "clip_mask";
      31             : 
      32           0 : bool GrClipStackClip::quickContains(const SkRect& rect) const {
      33           0 :     if (!fStack || fStack->isWideOpen()) {
      34           0 :         return true;
      35             :     }
      36           0 :     return fStack->quickContains(rect);
      37             : }
      38             : 
      39           0 : bool GrClipStackClip::quickContains(const SkRRect& rrect) const {
      40           0 :     if (!fStack || fStack->isWideOpen()) {
      41           0 :         return true;
      42             :     }
      43           0 :     return fStack->quickContains(rrect);
      44             : }
      45             : 
      46           0 : bool GrClipStackClip::isRRect(const SkRect& origRTBounds, SkRRect* rr, GrAA* aa) const {
      47           0 :     if (!fStack) {
      48           0 :         return false;
      49             :     }
      50           0 :     const SkRect* rtBounds = &origRTBounds;
      51             :     bool isAA;
      52           0 :     if (fStack->isRRect(*rtBounds, rr, &isAA)) {
      53           0 :         *aa = GrBoolToAA(isAA);
      54           0 :         return true;
      55             :     }
      56           0 :     return false;
      57             : }
      58             : 
      59           0 : void GrClipStackClip::getConservativeBounds(int width, int height, SkIRect* devResult,
      60             :                                             bool* isIntersectionOfRects) const {
      61           0 :     if (!fStack) {
      62           0 :         devResult->setXYWH(0, 0, width, height);
      63           0 :         if (isIntersectionOfRects) {
      64           0 :             *isIntersectionOfRects = true;
      65             :         }
      66           0 :         return;
      67             :     }
      68             :     SkRect devBounds;
      69           0 :     fStack->getConservativeBounds(0, 0, width, height, &devBounds, isIntersectionOfRects);
      70           0 :     devBounds.roundOut(devResult);
      71             : }
      72             : 
      73             : ////////////////////////////////////////////////////////////////////////////////
      74             : // set up the draw state to enable the aa clipping mask.
      75           0 : static sk_sp<GrFragmentProcessor> create_fp_for_mask(GrResourceProvider* resourceProvider,
      76             :                                                      sk_sp<GrTextureProxy> mask,
      77             :                                                      const SkIRect &devBound) {
      78           0 :     SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height());
      79             :     return GrDeviceSpaceTextureDecalFragmentProcessor::Make(resourceProvider,
      80           0 :                                                             std::move(mask), domainTexels,
      81           0 :                                                             {devBound.fLeft, devBound.fTop});
      82             : }
      83             : 
      84             : // Does the path in 'element' require SW rendering? If so, return true (and,
      85             : // optionally, set 'prOut' to NULL. If not, return false (and, optionally, set
      86             : // 'prOut' to the non-SW path renderer that will do the job).
      87           0 : bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context,
      88             :                                           bool hasUserStencilSettings,
      89             :                                           const GrRenderTargetContext* renderTargetContext,
      90             :                                           const SkMatrix& viewMatrix,
      91             :                                           const Element* element,
      92             :                                           GrPathRenderer** prOut,
      93             :                                           bool needsStencil) {
      94           0 :     if (Element::kRect_Type == element->getType()) {
      95             :         // rects can always be drawn directly w/o using the software path
      96             :         // TODO: skip rrects once we're drawing them directly.
      97           0 :         if (prOut) {
      98           0 :             *prOut = nullptr;
      99             :         }
     100           0 :         return false;
     101             :     } else {
     102             :         // We shouldn't get here with an empty clip element.
     103           0 :         SkASSERT(Element::kEmpty_Type != element->getType());
     104             : 
     105             :         // the gpu alpha mask will draw the inverse paths as non-inverse to a temp buffer
     106           0 :         SkPath path;
     107           0 :         element->asPath(&path);
     108           0 :         if (path.isInverseFillType()) {
     109           0 :             path.toggleInverseFillType();
     110             :         }
     111             : 
     112             :         GrPathRendererChain::DrawType type =
     113           0 :                 needsStencil ? GrPathRendererChain::DrawType::kStencilAndColor
     114           0 :                              : GrPathRendererChain::DrawType::kColor;
     115             : 
     116           0 :         GrShape shape(path, GrStyle::SimpleFill());
     117             :         GrPathRenderer::CanDrawPathArgs canDrawArgs;
     118           0 :         canDrawArgs.fShaderCaps = context->caps()->shaderCaps();
     119           0 :         canDrawArgs.fViewMatrix = &viewMatrix;
     120           0 :         canDrawArgs.fShape = &shape;
     121           0 :         if (!element->isAA()) {
     122           0 :             canDrawArgs.fAAType = GrAAType::kNone;
     123           0 :         } else if (renderTargetContext->isUnifiedMultisampled()) {
     124           0 :             canDrawArgs.fAAType = GrAAType::kMSAA;
     125           0 :         } else if (renderTargetContext->isStencilBufferMultisampled()){
     126           0 :             canDrawArgs.fAAType = GrAAType::kMixedSamples;
     127             :         } else {
     128           0 :             canDrawArgs.fAAType = GrAAType::kCoverage;
     129             :         }
     130           0 :         canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
     131             : 
     132             :         // the 'false' parameter disallows use of the SW path renderer
     133             :         GrPathRenderer* pr =
     134           0 :             context->contextPriv().drawingManager()->getPathRenderer(canDrawArgs, false, type);
     135           0 :         if (prOut) {
     136           0 :             *prOut = pr;
     137             :         }
     138           0 :         return SkToBool(!pr);
     139             :     }
     140             : }
     141             : 
     142             : /*
     143             :  * This method traverses the clip stack to see if the GrSoftwarePathRenderer
     144             :  * will be used on any element. If so, it returns true to indicate that the
     145             :  * entire clip should be rendered in SW and then uploaded en masse to the gpu.
     146             :  */
     147           0 : bool GrClipStackClip::UseSWOnlyPath(GrContext* context,
     148             :                                     bool hasUserStencilSettings,
     149             :                                     const GrRenderTargetContext* renderTargetContext,
     150             :                                     const GrReducedClip& reducedClip) {
     151             :     // TODO: generalize this function so that when
     152             :     // a clip gets complex enough it can just be done in SW regardless
     153             :     // of whether it would invoke the GrSoftwarePathRenderer.
     154             : 
     155             :     // Set the matrix so that rendered clip elements are transformed to mask space from clip
     156             :     // space.
     157             :     SkMatrix translate;
     158           0 :     translate.setTranslate(SkIntToScalar(-reducedClip.left()), SkIntToScalar(-reducedClip.top()));
     159             : 
     160           0 :     for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()) {
     161           0 :         const Element* element = iter.get();
     162             : 
     163           0 :         SkClipOp op = element->getOp();
     164           0 :         bool invert = element->isInverseFilled();
     165           0 :         bool needsStencil = invert ||
     166           0 :                             kIntersect_SkClipOp == op || kReverseDifference_SkClipOp == op;
     167             : 
     168           0 :         if (PathNeedsSWRenderer(context, hasUserStencilSettings,
     169             :                                 renderTargetContext, translate, element, nullptr, needsStencil)) {
     170           0 :             return true;
     171             :         }
     172             :     }
     173           0 :     return false;
     174             : }
     175             : 
     176           0 : static bool get_analytic_clip_processor(const ElementList& elements,
     177             :                                         bool abortIfAA,
     178             :                                         const SkRect& drawDevBounds,
     179             :                                         sk_sp<GrFragmentProcessor>* resultFP) {
     180           0 :     SkASSERT(elements.count() <= kMaxAnalyticElements);
     181           0 :     SkSTArray<kMaxAnalyticElements, sk_sp<GrFragmentProcessor>> fps;
     182           0 :     ElementList::Iter iter(elements);
     183           0 :     while (iter.get()) {
     184           0 :         SkClipOp op = iter.get()->getOp();
     185             :         bool invert;
     186           0 :         bool skip = false;
     187           0 :         switch (op) {
     188             :             case kReplace_SkClipOp:
     189           0 :                 SkASSERT(iter.get() == elements.head());
     190             :                 // Fallthrough, handled same as intersect.
     191             :             case kIntersect_SkClipOp:
     192           0 :                 invert = false;
     193           0 :                 if (iter.get()->contains(drawDevBounds)) {
     194           0 :                     skip = true;
     195             :                 }
     196           0 :                 break;
     197             :             case kDifference_SkClipOp:
     198           0 :                 invert = true;
     199             :                 // We don't currently have a cheap test for whether a rect is fully outside an
     200             :                 // element's primitive, so don't attempt to set skip.
     201           0 :                 break;
     202             :             default:
     203           0 :                 return false;
     204             :         }
     205           0 :         if (!skip) {
     206             :             GrPrimitiveEdgeType edgeType;
     207           0 :             if (iter.get()->isAA()) {
     208           0 :                 if (abortIfAA) {
     209           0 :                     return false;
     210             :                 }
     211           0 :                 edgeType =
     212           0 :                     invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_GrProcessorEdgeType;
     213             :             } else {
     214           0 :                 edgeType =
     215           0 :                     invert ? kInverseFillBW_GrProcessorEdgeType : kFillBW_GrProcessorEdgeType;
     216             :             }
     217             : 
     218           0 :             switch (iter.get()->getType()) {
     219             :                 case SkClipStack::Element::kPath_Type:
     220           0 :                     fps.emplace_back(GrConvexPolyEffect::Make(edgeType, iter.get()->getPath()));
     221           0 :                     break;
     222             :                 case SkClipStack::Element::kRRect_Type: {
     223           0 :                     fps.emplace_back(GrRRectEffect::Make(edgeType, iter.get()->getRRect()));
     224           0 :                     break;
     225             :                 }
     226             :                 case SkClipStack::Element::kRect_Type: {
     227           0 :                     fps.emplace_back(GrConvexPolyEffect::Make(edgeType, iter.get()->getRect()));
     228           0 :                     break;
     229             :                 }
     230             :                 default:
     231           0 :                     break;
     232             :             }
     233           0 :             if (!fps.back()) {
     234           0 :                 return false;
     235             :             }
     236             :         }
     237           0 :         iter.next();
     238             :     }
     239             : 
     240           0 :     *resultFP = nullptr;
     241           0 :     if (fps.count()) {
     242           0 :         *resultFP = GrFragmentProcessor::RunInSeries(fps.begin(), fps.count());
     243             :     }
     244           0 :     return true;
     245             : }
     246             : 
     247             : ////////////////////////////////////////////////////////////////////////////////
     248             : // sort out what kind of clip mask needs to be created: alpha, stencil,
     249             : // scissor, or entirely software
     250           0 : bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTargetContext,
     251             :                             bool useHWAA, bool hasUserStencilSettings, GrAppliedClip* out,
     252             :                             SkRect* bounds) const {
     253           0 :     SkRect devBounds = SkRect::MakeIWH(renderTargetContext->width(), renderTargetContext->height());
     254           0 :     if (!devBounds.intersect(*bounds)) {
     255           0 :         return false;
     256             :     }
     257             : 
     258           0 :     if (!fStack || fStack->isWideOpen()) {
     259           0 :         return true;
     260             :     }
     261             : 
     262           0 :     const GrReducedClip reducedClip(*fStack, devBounds,
     263           0 :                                     renderTargetContext->priv().maxWindowRectangles());
     264             : 
     265           0 :     if (reducedClip.hasIBounds() && !GrClip::IsInsideClip(reducedClip.ibounds(), devBounds)) {
     266           0 :         out->addScissor(reducedClip.ibounds(), bounds);
     267             :     }
     268             : 
     269           0 :     if (!reducedClip.windowRectangles().empty()) {
     270           0 :         out->addWindowRectangles(reducedClip.windowRectangles(),
     271           0 :                                  GrWindowRectsState::Mode::kExclusive);
     272             :     }
     273             : 
     274           0 :     if (reducedClip.elements().isEmpty()) {
     275           0 :         return InitialState::kAllIn == reducedClip.initialState();
     276             :     }
     277             : 
     278             : #ifdef SK_DEBUG
     279           0 :     SkASSERT(reducedClip.hasIBounds());
     280             :     SkIRect rtIBounds = SkIRect::MakeWH(renderTargetContext->width(),
     281           0 :                                         renderTargetContext->height());
     282           0 :     const SkIRect& clipIBounds = reducedClip.ibounds();
     283           0 :     SkASSERT(rtIBounds.contains(clipIBounds)); // Mask shouldn't be larger than the RT.
     284             : #endif
     285             : 
     286             :     // An element count of 4 was chosen because of the common pattern in Blink of:
     287             :     //   isect RR
     288             :     //   diff  RR
     289             :     //   isect convex_poly
     290             :     //   isect convex_poly
     291             :     // when drawing rounded div borders. This could probably be tuned based on a
     292             :     // configuration's relative costs of switching RTs to generate a mask vs
     293             :     // longer shaders.
     294           0 :     if (reducedClip.elements().count() <= kMaxAnalyticElements) {
     295             :         // When there are multiple samples we want to do per-sample clipping, not compute a
     296             :         // fractional pixel coverage.
     297           0 :         bool disallowAnalyticAA = renderTargetContext->isStencilBufferMultisampled();
     298           0 :         if (disallowAnalyticAA && !renderTargetContext->numColorSamples()) {
     299             :             // With a single color sample, any coverage info is lost from color once it hits the
     300             :             // color buffer anyway, so we may as well use coverage AA if nothing else in the pipe
     301             :             // is multisampled.
     302           0 :             disallowAnalyticAA = useHWAA || hasUserStencilSettings;
     303             :         }
     304           0 :         sk_sp<GrFragmentProcessor> clipFP;
     305           0 :         if (reducedClip.requiresAA() &&
     306           0 :             get_analytic_clip_processor(reducedClip.elements(), disallowAnalyticAA, devBounds,
     307             :                                         &clipFP)) {
     308           0 :             out->addCoverageFP(std::move(clipFP));
     309           0 :             return true;
     310             :         }
     311             :     }
     312             : 
     313             :     // If the stencil buffer is multisampled we can use it to do everything.
     314           0 :     if (!renderTargetContext->isStencilBufferMultisampled() && reducedClip.requiresAA()) {
     315           0 :         sk_sp<GrTextureProxy> result;
     316           0 :         if (UseSWOnlyPath(context, hasUserStencilSettings, renderTargetContext, reducedClip)) {
     317             :             // The clip geometry is complex enough that it will be more efficient to create it
     318             :             // entirely in software
     319           0 :             result = this->createSoftwareClipMask(context, reducedClip);
     320             :         } else {
     321           0 :             result = this->createAlphaClipMask(context, reducedClip);
     322             :         }
     323             : 
     324           0 :         if (result) {
     325             :             // The mask's top left coord should be pinned to the rounded-out top left corner of
     326             :             // the clip's device space bounds.
     327           0 :             out->addCoverageFP(create_fp_for_mask(context->resourceProvider(), std::move(result),
     328           0 :                                                   reducedClip.ibounds()));
     329           0 :             return true;
     330             :         }
     331             :         // if alpha clip mask creation fails fall through to the non-AA code paths
     332             :     }
     333             : 
     334           0 :     GrRenderTarget* rt = renderTargetContext->accessRenderTarget();
     335           0 :     if (!rt) {
     336           0 :         return true;
     337             :     }
     338             : 
     339             :     // use the stencil clip if we can't represent the clip as a rectangle.
     340           0 :     if (!context->resourceProvider()->attachStencilAttachment(rt)) {
     341           0 :         SkDebugf("WARNING: failed to attach stencil buffer for clip mask. Clip will be ignored.\n");
     342           0 :         return true;
     343             :     }
     344             : 
     345             :     // This relies on the property that a reduced sub-rect of the last clip will contain all the
     346             :     // relevant window rectangles that were in the last clip. This subtle requirement will go away
     347             :     // after clipping is overhauled.
     348           0 :     if (renderTargetContext->priv().mustRenderClip(reducedClip.elementsGenID(),
     349             :                                                    reducedClip.ibounds())) {
     350           0 :         reducedClip.drawStencilClipMask(context, renderTargetContext);
     351           0 :         renderTargetContext->priv().setLastClip(reducedClip.elementsGenID(), reducedClip.ibounds());
     352             :     }
     353           0 :     out->addStencilClip();
     354           0 :     return true;
     355             : }
     356             : 
     357             : ////////////////////////////////////////////////////////////////////////////////
     358             : // Create a 8-bit clip mask in alpha
     359             : 
     360           0 : static void create_clip_mask_key(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey* key) {
     361           0 :     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
     362           0 :     GrUniqueKey::Builder builder(key, kDomain, 3, GrClipStackClip::kMaskTestTag);
     363           0 :     builder[0] = clipGenID;
     364             :     // SkToS16 because image filters outset layers to a size indicated by the filter, which can
     365             :     // sometimes result in negative coordinates from device space.
     366           0 :     builder[1] = SkToS16(bounds.fLeft) | (SkToS16(bounds.fRight) << 16);
     367           0 :     builder[2] = SkToS16(bounds.fTop) | (SkToS16(bounds.fBottom) << 16);
     368           0 : }
     369             : 
     370           0 : static void add_invalidate_on_pop_message(const SkClipStack& stack, int32_t clipGenID,
     371             :                                           const GrUniqueKey& clipMaskKey) {
     372           0 :     SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
     373           0 :     while (const Element* element = iter.prev()) {
     374           0 :         if (element->getGenID() == clipGenID) {
     375             :             std::unique_ptr<GrUniqueKeyInvalidatedMessage> msg(
     376           0 :                     new GrUniqueKeyInvalidatedMessage(clipMaskKey));
     377           0 :             element->addResourceInvalidationMessage(std::move(msg));
     378           0 :             return;
     379             :         }
     380           0 :     }
     381           0 :     SkDEBUGFAIL("Gen ID was not found in stack.");
     382             : }
     383             : 
     384           0 : sk_sp<GrTextureProxy> GrClipStackClip::createAlphaClipMask(GrContext* context,
     385             :                                                            const GrReducedClip& reducedClip) const {
     386           0 :     GrResourceProvider* resourceProvider = context->resourceProvider();
     387           0 :     GrUniqueKey key;
     388           0 :     create_clip_mask_key(reducedClip.elementsGenID(), reducedClip.ibounds(), &key);
     389             : 
     390           0 :     sk_sp<GrTextureProxy> proxy(resourceProvider->findProxyByUniqueKey(key));
     391           0 :     if (proxy) {
     392           0 :         return proxy;
     393             :     }
     394             : 
     395             :     sk_sp<GrRenderTargetContext> rtc(context->makeRenderTargetContextWithFallback(
     396             :                                                                              SkBackingFit::kApprox,
     397             :                                                                              reducedClip.width(),
     398             :                                                                              reducedClip.height(),
     399             :                                                                              kAlpha_8_GrPixelConfig,
     400           0 :                                                                              nullptr));
     401           0 :     if (!rtc) {
     402           0 :         return nullptr;
     403             :     }
     404             : 
     405           0 :     if (!reducedClip.drawAlphaClipMask(rtc.get())) {
     406           0 :         return nullptr;
     407             :     }
     408             : 
     409           0 :     sk_sp<GrTextureProxy> result(rtc->asTextureProxyRef());
     410           0 :     if (!result) {
     411           0 :         return nullptr;
     412             :     }
     413             : 
     414           0 :     resourceProvider->assignUniqueKeyToProxy(key, result.get());
     415             :     // MDB TODO (caching): this has to play nice with the GrSurfaceProxy's caching
     416           0 :     add_invalidate_on_pop_message(*fStack, reducedClip.elementsGenID(), key);
     417             : 
     418           0 :     return result;
     419             : }
     420             : 
     421           0 : sk_sp<GrTextureProxy> GrClipStackClip::createSoftwareClipMask(
     422             :                                                           GrContext* context,
     423             :                                                           const GrReducedClip& reducedClip) const {
     424           0 :     GrUniqueKey key;
     425           0 :     create_clip_mask_key(reducedClip.elementsGenID(), reducedClip.ibounds(), &key);
     426             : 
     427           0 :     sk_sp<GrTextureProxy> proxy(context->resourceProvider()->findProxyByUniqueKey(key));
     428           0 :     if (proxy) {
     429           0 :         return proxy;
     430             :     }
     431             : 
     432             :     // The mask texture may be larger than necessary. We round out the clip bounds and pin the top
     433             :     // left corner of the resulting rect to the top left of the texture.
     434           0 :     SkIRect maskSpaceIBounds = SkIRect::MakeWH(reducedClip.width(), reducedClip.height());
     435             : 
     436           0 :     GrSWMaskHelper helper;
     437             : 
     438             :     // Set the matrix so that rendered clip elements are transformed to mask space from clip
     439             :     // space.
     440             :     SkMatrix translate;
     441           0 :     translate.setTranslate(SkIntToScalar(-reducedClip.left()), SkIntToScalar(-reducedClip.top()));
     442             : 
     443           0 :     if (!helper.init(maskSpaceIBounds, &translate)) {
     444           0 :         return nullptr;
     445             :     }
     446           0 :     helper.clear(InitialState::kAllIn == reducedClip.initialState() ? 0xFF : 0x00);
     447             : 
     448           0 :     for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()) {
     449           0 :         const Element* element = iter.get();
     450           0 :         SkClipOp op = element->getOp();
     451           0 :         GrAA aa = GrBoolToAA(element->isAA());
     452             : 
     453           0 :         if (kIntersect_SkClipOp == op || kReverseDifference_SkClipOp == op) {
     454             :             // Intersect and reverse difference require modifying pixels outside of the geometry
     455             :             // that is being "drawn". In both cases we erase all the pixels outside of the geometry
     456             :             // but leave the pixels inside the geometry alone. For reverse difference we invert all
     457             :             // the pixels before clearing the ones outside the geometry.
     458           0 :             if (kReverseDifference_SkClipOp == op) {
     459           0 :                 SkRect temp = SkRect::Make(reducedClip.ibounds());
     460             :                 // invert the entire scene
     461           0 :                 helper.drawRect(temp, SkRegion::kXOR_Op, GrAA::kNo, 0xFF);
     462             :             }
     463           0 :             SkPath clipPath;
     464           0 :             element->asPath(&clipPath);
     465           0 :             clipPath.toggleInverseFillType();
     466           0 :             GrShape shape(clipPath, GrStyle::SimpleFill());
     467           0 :             helper.drawShape(shape, SkRegion::kReplace_Op, aa, 0x00);
     468           0 :             continue;
     469             :         }
     470             : 
     471             :         // The other ops (union, xor, diff) only affect pixels inside
     472             :         // the geometry so they can just be drawn normally
     473           0 :         if (Element::kRect_Type == element->getType()) {
     474           0 :             helper.drawRect(element->getRect(), (SkRegion::Op)op, aa, 0xFF);
     475             :         } else {
     476           0 :             SkPath path;
     477           0 :             element->asPath(&path);
     478           0 :             GrShape shape(path, GrStyle::SimpleFill());
     479           0 :             helper.drawShape(shape, (SkRegion::Op)op, aa, 0xFF);
     480             :         }
     481             :     }
     482             : 
     483           0 :     sk_sp<GrTextureProxy> result(helper.toTextureProxy(context, SkBackingFit::kApprox));
     484             : 
     485           0 :     context->resourceProvider()->assignUniqueKeyToProxy(key, result.get());
     486             :     // MDB TODO (caching): this has to play nice with the GrSurfaceProxy's caching
     487           0 :     add_invalidate_on_pop_message(*fStack, reducedClip.elementsGenID(), key);
     488           0 :     return result;
     489             : }

Generated by: LCOV version 1.13