Home | History | Annotate | Download | only in gpu
      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 #ifndef GrPathRenderer_DEFINED
      9 #define GrPathRenderer_DEFINED
     10 
     11 #include "GrCaps.h"
     12 #include "GrRenderTargetContext.h"
     13 #include "GrPaint.h"
     14 #include "GrShape.h"
     15 #include "GrUserStencilSettings.h"
     16 
     17 #include "SkDrawProcs.h"
     18 #include "SkTArray.h"
     19 
     20 class SkPath;
     21 class GrFixedClip;
     22 class GrHardClip;
     23 struct GrPoint;
     24 
     25 /**
     26  *  Base class for drawing paths into a GrOpList.
     27  */
     28 class SK_API GrPathRenderer : public SkRefCnt {
     29 public:
     30     GrPathRenderer();
     31 
     32     /**
     33      * A caller may wish to use a path renderer to draw a path into the stencil buffer. However,
     34      * the path renderer itself may require use of the stencil buffer. Also a path renderer may
     35      * use a GrProcessor coverage stage that sets coverage to zero to eliminate pixels that are
     36      * covered by bounding geometry but outside the path. These exterior pixels would still be
     37      * rendered into the stencil.
     38      *
     39      * A GrPathRenderer can provide three levels of support for stenciling paths:
     40      * 1) kNoRestriction: This is the most general. The caller passes a GrPaint and calls drawPath().
     41      *                    The path is rendered exactly as the draw state indicates including support
     42      *                    for simultaneous color and stenciling with arbitrary stenciling rules.
     43      *                    Pixels partially covered by AA paths are affected by the stencil settings.
     44      * 2) kStencilOnly: The path renderer cannot apply arbitrary stencil rules nor shade and stencil
     45      *                  simultaneously. The path renderer does support the stencilPath() function
     46      *                  which performs no color writes and writes a non-zero stencil value to pixels
     47      *                  covered by the path.
     48      * 3) kNoSupport: This path renderer cannot be used to stencil the path.
     49      */
     50     enum StencilSupport {
     51         kNoSupport_StencilSupport,
     52         kStencilOnly_StencilSupport,
     53         kNoRestriction_StencilSupport,
     54     };
     55 
     56     /**
     57      * This function is to get the stencil support for a particular path. The path's fill must
     58      * not be an inverse type. The path will always be filled and not stroked.
     59      *
     60      * @param shape   the shape that will be drawn. Must be simple fill styled and non-inverse
     61      *                filled.
     62      */
     63     StencilSupport getStencilSupport(const GrShape& shape) const {
     64         SkDEBUGCODE(SkPath path;)
     65         SkDEBUGCODE(shape.asPath(&path);)
     66         SkASSERT(shape.style().isSimpleFill());
     67         SkASSERT(!path.isInverseFillType());
     68         return this->onGetStencilSupport(shape);
     69     }
     70 
     71     enum class CanDrawPath {
     72         kNo,
     73         kAsBackup, // i.e. This renderer is better than SW fallback if no others can draw the path.
     74         kYes
     75     };
     76 
     77     struct CanDrawPathArgs {
     78         SkDEBUGCODE(CanDrawPathArgs() { memset(this, 0, sizeof(*this)); }) // For validation.
     79 
     80         const GrCaps*               fCaps;
     81         const SkIRect*              fClipConservativeBounds;
     82         const SkMatrix*             fViewMatrix;
     83         const GrShape*              fShape;
     84         GrAAType                    fAAType;
     85 
     86         // These next two are only used by GrStencilAndCoverPathRenderer
     87         bool                        fHasUserStencilSettings;
     88 
     89 #ifdef SK_DEBUG
     90         void validate() const {
     91             SkASSERT(fCaps);
     92             SkASSERT(fClipConservativeBounds);
     93             SkASSERT(fViewMatrix);
     94             SkASSERT(fShape);
     95         }
     96 #endif
     97     };
     98 
     99     /**
    100      * Returns how well this path renderer is able to render the given path. Returning kNo or
    101      * kAsBackup allows the caller to keep searching for a better path renderer. This function is
    102      * called when searching for the best path renderer to draw a path.
    103      */
    104     CanDrawPath canDrawPath(const CanDrawPathArgs& args) const {
    105         SkDEBUGCODE(args.validate();)
    106         return this->onCanDrawPath(args);
    107     }
    108 
    109     struct DrawPathArgs {
    110         GrContext*                   fContext;
    111         GrPaint&&                    fPaint;
    112         const GrUserStencilSettings* fUserStencilSettings;
    113         GrRenderTargetContext*       fRenderTargetContext;
    114         const GrClip*                fClip;
    115         const SkIRect*               fClipConservativeBounds;
    116         const SkMatrix*              fViewMatrix;
    117         const GrShape*               fShape;
    118         GrAAType                     fAAType;
    119         bool                         fGammaCorrect;
    120 #ifdef SK_DEBUG
    121         void validate() const {
    122             SkASSERT(fContext);
    123             SkASSERT(fUserStencilSettings);
    124             SkASSERT(fRenderTargetContext);
    125             SkASSERT(fClip);
    126             SkASSERT(fClipConservativeBounds);
    127             SkASSERT(fViewMatrix);
    128             SkASSERT(fShape);
    129         }
    130 #endif
    131     };
    132 
    133     /**
    134      * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
    135      * the subclass must respect the stencil settings.
    136      */
    137     bool drawPath(const DrawPathArgs& args) {
    138         SkDEBUGCODE(args.validate();)
    139 #ifdef SK_DEBUG
    140         CanDrawPathArgs canArgs;
    141         canArgs.fCaps = args.fContext->caps();
    142         canArgs.fClipConservativeBounds = args.fClipConservativeBounds;
    143         canArgs.fViewMatrix = args.fViewMatrix;
    144         canArgs.fShape = args.fShape;
    145         canArgs.fAAType = args.fAAType;
    146         canArgs.validate();
    147 
    148         canArgs.fHasUserStencilSettings = !args.fUserStencilSettings->isUnused();
    149         SkASSERT(!(canArgs.fAAType == GrAAType::kMSAA &&
    150                    GrFSAAType::kUnifiedMSAA != args.fRenderTargetContext->fsaaType()));
    151         SkASSERT(!(canArgs.fAAType == GrAAType::kMixedSamples &&
    152                    GrFSAAType::kMixedSamples != args.fRenderTargetContext->fsaaType()));
    153         SkASSERT(CanDrawPath::kNo != this->canDrawPath(canArgs));
    154         if (!args.fUserStencilSettings->isUnused()) {
    155             SkPath path;
    156             args.fShape->asPath(&path);
    157             SkASSERT(args.fShape->style().isSimpleFill());
    158             SkASSERT(kNoRestriction_StencilSupport == this->getStencilSupport(*args.fShape));
    159         }
    160 #endif
    161         return this->onDrawPath(args);
    162     }
    163 
    164     /**
    165      * Args to stencilPath(). fAAType cannot be kCoverage.
    166      */
    167     struct StencilPathArgs {
    168         SkDEBUGCODE(StencilPathArgs() { memset(this, 0, sizeof(*this)); }) // For validation.
    169 
    170         GrContext*             fContext;
    171         GrRenderTargetContext* fRenderTargetContext;
    172         const GrHardClip*      fClip;
    173         const SkIRect*         fClipConservativeBounds;
    174         const SkMatrix*        fViewMatrix;
    175         GrAAType               fAAType;
    176         const GrShape*         fShape;
    177 
    178 #ifdef SK_DEBUG
    179         void validate() const {
    180             SkASSERT(fContext);
    181             SkASSERT(fRenderTargetContext);
    182             SkASSERT(fClipConservativeBounds);
    183             SkASSERT(fViewMatrix);
    184             SkASSERT(fShape);
    185             SkASSERT(fShape->style().isSimpleFill());
    186             SkASSERT(GrAAType::kCoverage != fAAType);
    187             SkPath path;
    188             fShape->asPath(&path);
    189             SkASSERT(!path.isInverseFillType());
    190         }
    191 #endif
    192     };
    193 
    194     /**
    195      * Draws the path to the stencil buffer. Assume the writable stencil bits are already
    196      * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
    197      */
    198     void stencilPath(const StencilPathArgs& args) {
    199         SkDEBUGCODE(args.validate();)
    200         SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fShape));
    201         this->onStencilPath(args);
    202     }
    203 
    204     // Helper for determining if we can treat a thin stroke as a hairline w/ coverage.
    205     // If we can, we draw lots faster (raster device does this same test).
    206     static bool IsStrokeHairlineOrEquivalent(const GrStyle& style, const SkMatrix& matrix,
    207                                              SkScalar* outCoverage) {
    208         if (style.pathEffect()) {
    209             return false;
    210         }
    211         const SkStrokeRec& stroke = style.strokeRec();
    212         if (stroke.isHairlineStyle()) {
    213             if (outCoverage) {
    214                 *outCoverage = SK_Scalar1;
    215             }
    216             return true;
    217         }
    218         return stroke.getStyle() == SkStrokeRec::kStroke_Style &&
    219             SkDrawTreatAAStrokeAsHairline(stroke.getWidth(), matrix, outCoverage);
    220     }
    221 
    222 protected:
    223     // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set
    224     // by devSize. Non-inverse path bounds will not necessarily be clipped to devSize.
    225     static void GetPathDevBounds(const SkPath& path,
    226                                  int devW,
    227                                  int devH,
    228                                  const SkMatrix& matrix,
    229                                  SkRect* bounds);
    230 
    231 private:
    232     /**
    233      * Subclass overrides if it has any limitations of stenciling support.
    234      */
    235     virtual StencilSupport onGetStencilSupport(const GrShape&) const {
    236         return kNoRestriction_StencilSupport;
    237     }
    238 
    239     /**
    240      * Subclass implementation of drawPath()
    241      */
    242     virtual bool onDrawPath(const DrawPathArgs& args) = 0;
    243 
    244     /**
    245      * Subclass implementation of canDrawPath()
    246      */
    247     virtual CanDrawPath onCanDrawPath(const CanDrawPathArgs& args) const = 0;
    248 
    249     /**
    250      * Subclass implementation of stencilPath(). Subclass must override iff it ever returns
    251      * kStencilOnly in onGetStencilSupport().
    252      */
    253     virtual void onStencilPath(const StencilPathArgs& args) {
    254         static constexpr GrUserStencilSettings kIncrementStencil(
    255             GrUserStencilSettings::StaticInit<
    256                  0xffff,
    257                  GrUserStencilTest::kAlways,
    258                  0xffff,
    259                  GrUserStencilOp::kReplace,
    260                  GrUserStencilOp::kReplace,
    261                  0xffff>()
    262         );
    263 
    264         GrPaint paint;
    265         DrawPathArgs drawArgs{args.fContext,
    266                               std::move(paint),
    267                               &kIncrementStencil,
    268                               args.fRenderTargetContext,
    269                               nullptr,  // clip
    270                               args.fClipConservativeBounds,
    271                               args.fViewMatrix,
    272                               args.fShape,
    273                               args.fAAType,
    274                               false};
    275         this->drawPath(drawArgs);
    276     }
    277 
    278     typedef SkRefCnt INHERITED;
    279 };
    280 
    281 #endif
    282