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