Home | History | Annotate | Download | only in gpu
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #ifndef GrPathRenderer_DEFINED
     10 #define GrPathRenderer_DEFINED
     11 
     12 #include "GrDrawTarget.h"
     13 #include "GrStencil.h"
     14 #include "GrStrokeInfo.h"
     15 
     16 #include "SkDrawProcs.h"
     17 #include "SkTArray.h"
     18 
     19 class SkPath;
     20 
     21 struct GrPoint;
     22 
     23 /**
     24  *  Base class for drawing paths into a GrDrawTarget.
     25  *
     26  *  Derived classes can use stages GrPaint::kTotalStages through GrPipelineBuilder::kNumStages-1.
     27  *  The stages before GrPaint::kTotalStages are reserved for setting up the draw (i.e., textures and
     28  *  filter masks).
     29  */
     30 class SK_API GrPathRenderer : public SkRefCnt {
     31 public:
     32     GrPathRenderer();
     33 
     34     /**
     35      * A caller may wish to use a path renderer to draw a path into the stencil buffer. However,
     36      * the path renderer itself may require use of the stencil buffer. Also a path renderer may
     37      * use a GrProcessor coverage stage that sets coverage to zero to eliminate pixels that are
     38      * covered by bounding geometry but outside the path. These exterior pixels would still be
     39      * rendered into the stencil.
     40      *
     41      * A GrPathRenderer can provide three levels of support for stenciling paths:
     42      * 1) kNoRestriction: This is the most general. The caller sets up the GrPipelineBuilder on the target
     43      *                    and calls drawPath(). The path is rendered exactly as the draw state
     44      *                    indicates including support for simultaneous color and stenciling with
     45      *                    arbitrary stenciling rules. Pixels partially covered by AA paths are
     46      *                    affected by the stencil settings.
     47      * 2) kStencilOnly: The path renderer cannot apply arbitrary stencil rules nor shade and stencil
     48      *                  simultaneously. The path renderer does support the stencilPath() function
     49      *                  which performs no color writes and writes a non-zero stencil value to pixels
     50      *                  covered by the path.
     51      * 3) kNoSupport: This path renderer cannot be used to stencil the path.
     52      */
     53     enum StencilSupport {
     54         kNoSupport_StencilSupport,
     55         kStencilOnly_StencilSupport,
     56         kNoRestriction_StencilSupport,
     57     };
     58 
     59     /**
     60      * This function is to get the stencil support for a particular path. The path's fill must
     61      * not be an inverse type.
     62      *
     63      * @param path      the path that will be drawn
     64      * @param stroke    the stroke information (width, join, cap).
     65      */
     66     StencilSupport getStencilSupport(const SkPath& path, const GrStrokeInfo& stroke) const {
     67         SkASSERT(!path.isInverseFillType());
     68         return this->onGetStencilSupport(path, stroke);
     69     }
     70 
     71     /** Args to canDrawPath()
     72      *
     73      * fShaderCaps       The shader caps
     74      * fPipelineBuilder  The pipelineBuilder
     75      * fViewMatrix       The viewMatrix
     76      * fPath             The path to draw
     77      * fStroke           The stroke information (width, join, cap)
     78      * fAntiAlias        True if anti-aliasing is required.
     79      */
     80     struct CanDrawPathArgs {
     81         const GrShaderCaps*         fShaderCaps;
     82         const SkMatrix*             fViewMatrix;
     83         const SkPath*               fPath;
     84         const GrStrokeInfo*         fStroke;
     85         bool                        fAntiAlias;
     86 
     87         // These next two are only used by GrStencilAndCoverPathRenderer
     88         bool                        fIsStencilDisabled;
     89         bool                        fIsStencilBufferMSAA;
     90 
     91         void validate() const {
     92             SkASSERT(fShaderCaps);
     93             SkASSERT(fViewMatrix);
     94             SkASSERT(fPath);
     95             SkASSERT(fStroke);
     96             SkASSERT(!fPath->isEmpty());
     97         }
     98     };
     99 
    100     /**
    101      * Returns true if this path renderer is able to render the path. Returning false allows the
    102      * caller to fallback to another path renderer This function is called when searching for a path
    103      * renderer capable of rendering a path.
    104      *
    105      * @return  true if the path can be drawn by this object, false otherwise.
    106      */
    107     bool canDrawPath(const CanDrawPathArgs& args) const {
    108         SkDEBUGCODE(args.validate();)
    109         return this->onCanDrawPath(args);
    110     }
    111 
    112     /**
    113      * Args to drawPath()
    114      *
    115      * fTarget                The target that the path will be rendered to
    116      * fResourceProvider      The resource provider for creating gpu resources to render the path
    117      * fPipelineBuilder       The pipelineBuilder
    118      * fColor                 Color to render with
    119      * fViewMatrix            The viewMatrix
    120      * fPath                  the path to draw.
    121      * fStroke                the stroke information (width, join, cap)
    122      * fAntiAlias             true if anti-aliasing is required.
    123      */
    124     struct DrawPathArgs {
    125         GrDrawTarget*               fTarget;
    126         GrResourceProvider*         fResourceProvider;
    127         GrPipelineBuilder*          fPipelineBuilder;
    128         GrColor                     fColor;
    129         const SkMatrix*             fViewMatrix;
    130         const SkPath*               fPath;
    131         const GrStrokeInfo*         fStroke;
    132         bool                        fAntiAlias;
    133 
    134         void validate() const {
    135             SkASSERT(fTarget);
    136             SkASSERT(fResourceProvider);
    137             SkASSERT(fPipelineBuilder);
    138             SkASSERT(fViewMatrix);
    139             SkASSERT(fPath);
    140             SkASSERT(fStroke);
    141             SkASSERT(!fPath->isEmpty());
    142         }
    143     };
    144 
    145     /**
    146      * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
    147      * the subclass must respect the stencil settings of the GrPipelineBuilder.
    148      */
    149     bool drawPath(const DrawPathArgs& args) {
    150         SkDEBUGCODE(args.validate();)
    151 #ifdef SK_DEBUG
    152         CanDrawPathArgs canArgs;
    153         canArgs.fShaderCaps = args.fTarget->caps()->shaderCaps();
    154         canArgs.fViewMatrix = args.fViewMatrix;
    155         canArgs.fPath = args.fPath;
    156         canArgs.fStroke = args.fStroke;
    157         canArgs.fAntiAlias = args.fAntiAlias;
    158 
    159         canArgs.fIsStencilDisabled = args.fPipelineBuilder->getStencil().isDisabled();
    160         canArgs.fIsStencilBufferMSAA =
    161                           args.fPipelineBuilder->getRenderTarget()->isStencilBufferMultisampled();
    162         SkASSERT(this->canDrawPath(canArgs));
    163         SkASSERT(args.fPipelineBuilder->getStencil().isDisabled() ||
    164                  kNoRestriction_StencilSupport == this->getStencilSupport(*args.fPath,
    165                                                                           *args.fStroke));
    166 #endif
    167         return this->onDrawPath(args);
    168     }
    169 
    170     /* Args to stencilPath().
    171      *
    172      * fTarget                The target that the path will be rendered to.
    173      * fResourceProvider      The resource provider for creating gpu resources to render the path
    174      * fPipelineBuilder       The pipeline builder.
    175      * fViewMatrix            Matrix applied to the path.
    176      * fPath                  The path to draw.
    177      * fStroke                The stroke information (width, join, cap)
    178      */
    179     struct StencilPathArgs {
    180         GrDrawTarget*       fTarget;
    181         GrResourceProvider* fResourceProvider;
    182         GrPipelineBuilder*  fPipelineBuilder;
    183         const SkMatrix*     fViewMatrix;
    184         const SkPath*       fPath;
    185         const GrStrokeInfo* fStroke;
    186 
    187         void validate() const {
    188             SkASSERT(fTarget);
    189             SkASSERT(fResourceProvider);
    190             SkASSERT(fPipelineBuilder);
    191             SkASSERT(fViewMatrix);
    192             SkASSERT(fPath);
    193             SkASSERT(fStroke);
    194             SkASSERT(!fPath->isEmpty());
    195         }
    196     };
    197 
    198     /**
    199      * Draws the path to the stencil buffer. Assume the writable stencil bits are already
    200      * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
    201      *
    202      */
    203     void stencilPath(const StencilPathArgs& args) {
    204         SkDEBUGCODE(args.validate();)
    205         SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fPath, *args.fStroke));
    206 
    207         this->onStencilPath(args);
    208     }
    209 
    210     // Helper for determining if we can treat a thin stroke as a hairline w/ coverage.
    211     // If we can, we draw lots faster (raster device does this same test).
    212     static bool IsStrokeHairlineOrEquivalent(const GrStrokeInfo& stroke, const SkMatrix& matrix,
    213                                              SkScalar* outCoverage) {
    214         if (stroke.isDashed()) {
    215             return false;
    216         }
    217         if (stroke.isHairlineStyle()) {
    218             if (outCoverage) {
    219                 *outCoverage = SK_Scalar1;
    220             }
    221             return true;
    222         }
    223         return stroke.getStyle() == SkStrokeRec::kStroke_Style &&
    224             SkDrawTreatAAStrokeAsHairline(stroke.getWidth(), matrix, outCoverage);
    225     }
    226 
    227 protected:
    228     // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set
    229     // by devSize. Non-inverse path bounds will not necessarily be clipped to devSize.
    230     static void GetPathDevBounds(const SkPath& path,
    231                                  int devW,
    232                                  int devH,
    233                                  const SkMatrix& matrix,
    234                                  SkRect* bounds);
    235 
    236     // Helper version that gets the dev width and height from a GrSurface.
    237     static void GetPathDevBounds(const SkPath& path,
    238                                  const GrSurface* device,
    239                                  const SkMatrix& matrix,
    240                                  SkRect* bounds) {
    241         GetPathDevBounds(path, device->width(), device->height(), matrix, bounds);
    242     }
    243 
    244 private:
    245     /**
    246      * Subclass overrides if it has any limitations of stenciling support.
    247      */
    248     virtual StencilSupport onGetStencilSupport(const SkPath&, const GrStrokeInfo&) const {
    249         return kNoRestriction_StencilSupport;
    250     }
    251 
    252     /**
    253      * Subclass implementation of drawPath()
    254      */
    255     virtual bool onDrawPath(const DrawPathArgs& args) = 0;
    256 
    257     /**
    258      * Subclass implementation of canDrawPath()
    259      */
    260     virtual bool onCanDrawPath(const CanDrawPathArgs& args) const = 0;
    261 
    262     /**
    263      * Subclass implementation of stencilPath(). Subclass must override iff it ever returns
    264      * kStencilOnly in onGetStencilSupport().
    265      */
    266     virtual void onStencilPath(const StencilPathArgs& args) {
    267         GR_STATIC_CONST_SAME_STENCIL(kIncrementStencil,
    268                                      kReplace_StencilOp,
    269                                      kReplace_StencilOp,
    270                                      kAlways_StencilFunc,
    271                                      0xffff,
    272                                      0xffff,
    273                                      0xffff);
    274         args.fPipelineBuilder->setStencil(kIncrementStencil);
    275         args.fPipelineBuilder->setDisableColorXPFactory();
    276         DrawPathArgs drawArgs;
    277         drawArgs.fTarget = args.fTarget;
    278         drawArgs.fResourceProvider = args.fResourceProvider;
    279         drawArgs.fPipelineBuilder = args.fPipelineBuilder;
    280         drawArgs.fColor = 0xFFFFFFFF;
    281         drawArgs.fViewMatrix = args.fViewMatrix;
    282         drawArgs.fPath = args.fPath;
    283         drawArgs.fStroke = args.fStroke;
    284         drawArgs.fAntiAlias = false;
    285         this->drawPath(drawArgs);
    286     }
    287 
    288 
    289     typedef SkRefCnt INHERITED;
    290 };
    291 
    292 #endif
    293