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

          Line data    Source code
       1             : /*
       2             :  * Copyright 2012 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 "GrSoftwarePathRenderer.h"
       9             : #include "GrAuditTrail.h"
      10             : #include "GrClip.h"
      11             : #include "GrGpuResourcePriv.h"
      12             : #include "GrPipelineBuilder.h"
      13             : #include "GrResourceProvider.h"
      14             : #include "GrSWMaskHelper.h"
      15             : #include "ops/GrRectOpFactory.h"
      16             : 
      17             : ////////////////////////////////////////////////////////////////////////////////
      18           0 : bool GrSoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
      19             :     // Pass on any style that applies. The caller will apply the style if a suitable renderer is
      20             :     // not found and try again with the new GrShape.
      21           0 :     return !args.fShape->style().applies() && SkToBool(fResourceProvider) &&
      22           0 :            (args.fAAType == GrAAType::kCoverage || args.fAAType == GrAAType::kNone);
      23             : }
      24             : 
      25             : ////////////////////////////////////////////////////////////////////////////////
      26           0 : static bool get_unclipped_shape_dev_bounds(const GrShape& shape, const SkMatrix& matrix,
      27             :                                            SkIRect* devBounds) {
      28           0 :     SkRect shapeBounds = shape.styledBounds();
      29           0 :     if (shapeBounds.isEmpty()) {
      30           0 :         return false;
      31             :     }
      32             :     SkRect shapeDevBounds;
      33           0 :     matrix.mapRect(&shapeDevBounds, shapeBounds);
      34             :     // Even though these are "unclipped" bounds we still clip to the int32_t range.
      35             :     // This is the largest int32_t that is representable exactly as a float. The next 63 larger ints
      36             :     // would round down to this value when cast to a float, but who really cares.
      37             :     // INT32_MIN is exactly representable.
      38             :     static constexpr int32_t kMaxInt = 2147483520;
      39           0 :     if (!shapeDevBounds.intersect(SkRect::MakeLTRB(INT32_MIN, INT32_MIN, kMaxInt, kMaxInt))) {
      40           0 :         return false;
      41             :     }
      42           0 :     shapeDevBounds.roundOut(devBounds);
      43           0 :     return true;
      44             : }
      45             : 
      46             : // Gets the shape bounds, the clip bounds, and the intersection (if any). Returns false if there
      47             : // is no intersection.
      48           0 : static bool get_shape_and_clip_bounds(int width, int height,
      49             :                                       const GrClip& clip,
      50             :                                       const GrShape& shape,
      51             :                                       const SkMatrix& matrix,
      52             :                                       SkIRect* unclippedDevShapeBounds,
      53             :                                       SkIRect* clippedDevShapeBounds,
      54             :                                       SkIRect* devClipBounds) {
      55             :     // compute bounds as intersection of rt size, clip, and path
      56           0 :     clip.getConservativeBounds(width, height, devClipBounds);
      57             : 
      58           0 :     if (!get_unclipped_shape_dev_bounds(shape, matrix, unclippedDevShapeBounds)) {
      59           0 :         *unclippedDevShapeBounds = SkIRect::EmptyIRect();
      60           0 :         *clippedDevShapeBounds = SkIRect::EmptyIRect();
      61           0 :         return false;
      62             :     }
      63           0 :     if (!clippedDevShapeBounds->intersect(*devClipBounds, *unclippedDevShapeBounds)) {
      64           0 :         *clippedDevShapeBounds = SkIRect::EmptyIRect();
      65           0 :         return false;
      66             :     }
      67           0 :     return true;
      68             : }
      69             : 
      70             : ////////////////////////////////////////////////////////////////////////////////
      71             : 
      72           0 : void GrSoftwarePathRenderer::DrawNonAARect(GrRenderTargetContext* renderTargetContext,
      73             :                                            GrPaint&& paint,
      74             :                                            const GrUserStencilSettings& userStencilSettings,
      75             :                                            const GrClip& clip,
      76             :                                            const SkMatrix& viewMatrix,
      77             :                                            const SkRect& rect,
      78             :                                            const SkMatrix& localMatrix) {
      79             :     std::unique_ptr<GrLegacyMeshDrawOp> op(GrRectOpFactory::MakeNonAAFill(
      80           0 :             paint.getColor(), viewMatrix, rect, nullptr, &localMatrix));
      81             : 
      82           0 :     GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
      83           0 :     pipelineBuilder.setUserStencil(&userStencilSettings);
      84           0 :     renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
      85           0 : }
      86             : 
      87           0 : void GrSoftwarePathRenderer::DrawAroundInvPath(GrRenderTargetContext* renderTargetContext,
      88             :                                                GrPaint&& paint,
      89             :                                                const GrUserStencilSettings& userStencilSettings,
      90             :                                                const GrClip& clip,
      91             :                                                const SkMatrix& viewMatrix,
      92             :                                                const SkIRect& devClipBounds,
      93             :                                                const SkIRect& devPathBounds) {
      94             :     SkMatrix invert;
      95           0 :     if (!viewMatrix.invert(&invert)) {
      96           0 :         return;
      97             :     }
      98             : 
      99             :     SkRect rect;
     100           0 :     if (devClipBounds.fTop < devPathBounds.fTop) {
     101           0 :         rect.iset(devClipBounds.fLeft, devClipBounds.fTop,
     102           0 :                   devClipBounds.fRight, devPathBounds.fTop);
     103           0 :         DrawNonAARect(renderTargetContext, GrPaint(paint), userStencilSettings, clip, SkMatrix::I(),
     104           0 :                       rect, invert);
     105             :     }
     106           0 :     if (devClipBounds.fLeft < devPathBounds.fLeft) {
     107           0 :         rect.iset(devClipBounds.fLeft, devPathBounds.fTop,
     108           0 :                   devPathBounds.fLeft, devPathBounds.fBottom);
     109           0 :         DrawNonAARect(renderTargetContext, GrPaint(paint), userStencilSettings, clip, SkMatrix::I(),
     110           0 :                       rect, invert);
     111             :     }
     112           0 :     if (devClipBounds.fRight > devPathBounds.fRight) {
     113           0 :         rect.iset(devPathBounds.fRight, devPathBounds.fTop,
     114           0 :                   devClipBounds.fRight, devPathBounds.fBottom);
     115           0 :         DrawNonAARect(renderTargetContext, GrPaint(paint), userStencilSettings, clip, SkMatrix::I(),
     116           0 :                       rect, invert);
     117             :     }
     118           0 :     if (devClipBounds.fBottom > devPathBounds.fBottom) {
     119           0 :         rect.iset(devClipBounds.fLeft, devPathBounds.fBottom,
     120           0 :                   devClipBounds.fRight, devClipBounds.fBottom);
     121           0 :         DrawNonAARect(renderTargetContext, std::move(paint), userStencilSettings, clip,
     122           0 :                       SkMatrix::I(), rect, invert);
     123             :     }
     124             : }
     125             : 
     126             : ////////////////////////////////////////////////////////////////////////////////
     127             : // return true on success; false on failure
     128           0 : bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) {
     129           0 :     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
     130             :                               "GrSoftwarePathRenderer::onDrawPath");
     131           0 :     if (!fResourceProvider) {
     132           0 :         return false;
     133             :     }
     134             : 
     135             :     // We really need to know if the shape will be inverse filled or not
     136           0 :     bool inverseFilled = false;
     137           0 :     SkTLazy<GrShape> tmpShape;
     138           0 :     SkASSERT(!args.fShape->style().applies());
     139           0 :     inverseFilled = args.fShape->inverseFilled();
     140             : 
     141             :     SkIRect unclippedDevShapeBounds, clippedDevShapeBounds, devClipBounds;
     142             :     // To prevent overloading the cache with entries during animations we limit the cache of masks
     143             :     // to cases where the matrix preserves axis alignment.
     144           0 :     bool useCache = fAllowCaching && !inverseFilled && args.fViewMatrix->preservesAxisAlignment() &&
     145           0 :                     args.fShape->hasUnstyledKey() && GrAAType::kCoverage == args.fAAType;
     146             : 
     147           0 :     if (!get_shape_and_clip_bounds(args.fRenderTargetContext->width(),
     148           0 :                                    args.fRenderTargetContext->height(),
     149           0 :                                    *args.fClip, *args.fShape,
     150           0 :                                    *args.fViewMatrix, &unclippedDevShapeBounds,
     151             :                                    &clippedDevShapeBounds,
     152             :                                    &devClipBounds)) {
     153           0 :         if (inverseFilled) {
     154           0 :             DrawAroundInvPath(args.fRenderTargetContext, std::move(args.fPaint),
     155           0 :                               *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix,
     156           0 :                               devClipBounds, unclippedDevShapeBounds);
     157             :         }
     158           0 :         return true;
     159             :     }
     160             : 
     161           0 :     const SkIRect* boundsForMask = &clippedDevShapeBounds;
     162           0 :     if (useCache) {
     163             :         // Use the cache only if >50% of the path is visible.
     164           0 :         int unclippedWidth = unclippedDevShapeBounds.width();
     165           0 :         int unclippedHeight = unclippedDevShapeBounds.height();
     166           0 :         int unclippedArea = unclippedWidth * unclippedHeight;
     167           0 :         int clippedArea = clippedDevShapeBounds.width() * clippedDevShapeBounds.height();
     168           0 :         int maxTextureSize = args.fRenderTargetContext->caps()->maxTextureSize();
     169           0 :         if (unclippedArea > 2 * clippedArea || unclippedWidth > maxTextureSize ||
     170             :             unclippedHeight > maxTextureSize) {
     171           0 :             useCache = false;
     172             :         } else {
     173           0 :             boundsForMask = &unclippedDevShapeBounds;
     174             :         }
     175             :     }
     176             : 
     177           0 :     GrUniqueKey maskKey;
     178             :     struct KeyData {
     179             :         SkScalar fFractionalTranslateX;
     180             :         SkScalar fFractionalTranslateY;
     181             :     };
     182             : 
     183           0 :     if (useCache) {
     184             :         // We require the upper left 2x2 of the matrix to match exactly for a cache hit.
     185           0 :         SkScalar sx = args.fViewMatrix->get(SkMatrix::kMScaleX);
     186           0 :         SkScalar sy = args.fViewMatrix->get(SkMatrix::kMScaleY);
     187           0 :         SkScalar kx = args.fViewMatrix->get(SkMatrix::kMSkewX);
     188           0 :         SkScalar ky = args.fViewMatrix->get(SkMatrix::kMSkewY);
     189           0 :         SkScalar tx = args.fViewMatrix->get(SkMatrix::kMTransX);
     190           0 :         SkScalar ty = args.fViewMatrix->get(SkMatrix::kMTransY);
     191             :         // Allow 8 bits each in x and y of subpixel positioning.
     192           0 :         SkFixed fracX = SkScalarToFixed(SkScalarFraction(tx)) & 0x0000FF00;
     193           0 :         SkFixed fracY = SkScalarToFixed(SkScalarFraction(ty)) & 0x0000FF00;
     194           0 :         static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
     195           0 :         GrUniqueKey::Builder builder(&maskKey, kDomain, 5 + args.fShape->unstyledKeySize());
     196           0 :         builder[0] = SkFloat2Bits(sx);
     197           0 :         builder[1] = SkFloat2Bits(sy);
     198           0 :         builder[2] = SkFloat2Bits(kx);
     199           0 :         builder[3] = SkFloat2Bits(ky);
     200           0 :         builder[4] = fracX | (fracY >> 8);
     201           0 :         args.fShape->writeUnstyledKey(&builder[5]);
     202             :         // FIXME: Doesn't the key need to consider whether we're using AA or not? In practice that
     203             :         // should always be true, though.
     204             :     }
     205             : 
     206           0 :     sk_sp<GrTextureProxy> proxy;
     207           0 :     if (useCache) {
     208           0 :         proxy = fResourceProvider->findProxyByUniqueKey(maskKey);
     209             :     }
     210           0 :     if (!proxy) {
     211           0 :         SkBackingFit fit = useCache ? SkBackingFit::kExact : SkBackingFit::kApprox;
     212           0 :         GrAA aa = GrAAType::kCoverage == args.fAAType ? GrAA::kYes : GrAA::kNo;
     213           0 :         proxy = GrSWMaskHelper::DrawShapeMaskToTexture(args.fContext, *args.fShape,
     214             :                                                        *boundsForMask, aa,
     215           0 :                                                        fit, args.fViewMatrix);
     216           0 :         if (!proxy) {
     217           0 :             return false;
     218             :         }
     219           0 :         if (useCache) {
     220           0 :             fResourceProvider->assignUniqueKeyToProxy(maskKey, proxy.get());
     221             :         }
     222             :     }
     223           0 :     if (inverseFilled) {
     224           0 :         DrawAroundInvPath(args.fRenderTargetContext, GrPaint(args.fPaint),
     225           0 :                           *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix, devClipBounds,
     226           0 :                           unclippedDevShapeBounds);
     227             :     }
     228           0 :     GrSWMaskHelper::DrawToTargetWithShapeMask(
     229           0 :             std::move(proxy), args.fRenderTargetContext, std::move(args.fPaint),
     230           0 :             *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix,
     231           0 :             SkIPoint{boundsForMask->fLeft, boundsForMask->fTop}, *boundsForMask);
     232             : 
     233           0 :     return true;
     234             : }

Generated by: LCOV version 1.13