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 "GrPathRendererChain.h"
     14 #include "GrStencil.h"
     15 #include "GrStrokeInfo.h"
     16 
     17 #include "SkDrawProcs.h"
     18 #include "SkTArray.h"
     19 
     20 class SkPath;
     21 
     22 struct GrPoint;
     23 
     24 /**
     25  *  Base class for drawing paths into a GrDrawTarget.
     26  *
     27  *  Derived classes can use stages GrPaint::kTotalStages through GrPipelineBuilder::kNumStages-1.
     28  *  The stages before GrPaint::kTotalStages are reserved for setting up the draw (i.e., textures and
     29  *  filter masks).
     30  */
     31 class SK_API GrPathRenderer : public SkRefCnt {
     32 public:
     33     SK_DECLARE_INST_COUNT(GrPathRenderer)
     34 
     35     /**
     36      * This is called to install custom path renderers in every GrContext at create time. The
     37      * default implementation in GrCreatePathRenderer_none.cpp does not add any additional
     38      * renderers. Link against another implementation to install your own. The first added is the
     39      * most preferred path renderer, second is second most preferred, etc.
     40      *
     41      * @param context   the context that will use the path renderer
     42      * @param prChain   the chain to add path renderers to.
     43      */
     44     static void AddPathRenderers(GrContext* context, GrPathRendererChain* prChain);
     45 
     46 
     47     GrPathRenderer();
     48 
     49     /**
     50      * A caller may wish to use a path renderer to draw a path into the stencil buffer. However,
     51      * the path renderer itself may require use of the stencil buffer. Also a path renderer may
     52      * use a GrProcessor coverage stage that sets coverage to zero to eliminate pixels that are
     53      * covered by bounding geometry but outside the path. These exterior pixels would still be
     54      * rendered into the stencil.
     55      *
     56      * A GrPathRenderer can provide three levels of support for stenciling paths:
     57      * 1) kNoRestriction: This is the most general. The caller sets up the GrPipelineBuilder on the target
     58      *                    and calls drawPath(). The path is rendered exactly as the draw state
     59      *                    indicates including support for simultaneous color and stenciling with
     60      *                    arbitrary stenciling rules. Pixels partially covered by AA paths are
     61      *                    affected by the stencil settings.
     62      * 2) kStencilOnly: The path renderer cannot apply arbitrary stencil rules nor shade and stencil
     63      *                  simultaneously. The path renderer does support the stencilPath() function
     64      *                  which performs no color writes and writes a non-zero stencil value to pixels
     65      *                  covered by the path.
     66      * 3) kNoSupport: This path renderer cannot be used to stencil the path.
     67      */
     68     typedef GrPathRendererChain::StencilSupport StencilSupport;
     69     static const StencilSupport kNoSupport_StencilSupport =
     70         GrPathRendererChain::kNoSupport_StencilSupport;
     71     static const StencilSupport kStencilOnly_StencilSupport =
     72         GrPathRendererChain::kStencilOnly_StencilSupport;
     73     static const StencilSupport kNoRestriction_StencilSupport =
     74         GrPathRendererChain::kNoRestriction_StencilSupport;
     75 
     76     /**
     77      * This function is to get the stencil support for a particular path. The path's fill must
     78      * not be an inverse type.
     79      *
     80      * @param target    target that the path will be rendered to
     81      * @param path      the path that will be drawn
     82      * @param stroke    the stroke information (width, join, cap).
     83      */
     84     StencilSupport getStencilSupport(const GrDrawTarget* target,
     85                                      const GrPipelineBuilder* pipelineBuilder,
     86                                      const SkPath& path,
     87                                      const GrStrokeInfo& stroke) const {
     88         SkASSERT(!path.isInverseFillType());
     89         return this->onGetStencilSupport(target, pipelineBuilder, path, stroke);
     90     }
     91 
     92     /**
     93      * Returns true if this path renderer is able to render the path. Returning false allows the
     94      * caller to fallback to another path renderer This function is called when searching for a path
     95      * renderer capable of rendering a path.
     96      *
     97      * @param target           The target that the path will be rendered to
     98      * @param pipelineBuilder  The pipelineBuilder
     99      * @param viewMatrix       The viewMatrix
    100      * @param path             The path to draw
    101      * @param stroke           The stroke information (width, join, cap)
    102      * @param antiAlias        True if anti-aliasing is required.
    103      *
    104      * @return  true if the path can be drawn by this object, false otherwise.
    105      */
    106     virtual bool canDrawPath(const GrDrawTarget* target,
    107                              const GrPipelineBuilder* pipelineBuilder,
    108                              const SkMatrix& viewMatrix,
    109                              const SkPath& path,
    110                              const GrStrokeInfo& rec,
    111                              bool antiAlias) const = 0;
    112     /**
    113      * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
    114      * the subclass must respect the stencil settings of the target's draw state.
    115      *
    116      * @param target                The target that the path will be rendered to
    117      * @param pipelineBuilder       The pipelineBuilder
    118      * @param viewMatrix            The viewMatrix
    119      * @param path                  the path to draw.
    120      * @param stroke                the stroke information (width, join, cap)
    121      * @param antiAlias             true if anti-aliasing is required.
    122      */
    123     bool drawPath(GrDrawTarget* target,
    124                   GrPipelineBuilder* ds,
    125                   GrColor color,
    126                   const SkMatrix& viewMatrix,
    127                   const SkPath& path,
    128                   const GrStrokeInfo& stroke,
    129                   bool antiAlias) {
    130         SkASSERT(!path.isEmpty());
    131         SkASSERT(this->canDrawPath(target, ds, viewMatrix, path, stroke, antiAlias));
    132         SkASSERT(ds->getStencil().isDisabled() ||
    133                  kNoRestriction_StencilSupport == this->getStencilSupport(target, ds, path,
    134                                                                           stroke));
    135         return this->onDrawPath(target, ds, color, viewMatrix, path, stroke, antiAlias);
    136     }
    137 
    138     /**
    139      * Draws the path to the stencil buffer. Assume the writable stencil bits are already
    140      * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
    141      *
    142      * @param path                  the path to draw.
    143      * @param stroke                the stroke information (width, join, cap)
    144      * @param target                target that the path will be rendered to
    145      */
    146     void stencilPath(GrDrawTarget* target,
    147                      GrPipelineBuilder* ds,
    148                      const SkMatrix& viewMatrix,
    149                      const SkPath& path,
    150                      const GrStrokeInfo& stroke) {
    151         SkASSERT(!path.isEmpty());
    152         SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(target, ds, path, stroke));
    153         this->onStencilPath(target, ds, viewMatrix, path, stroke);
    154     }
    155 
    156     // Helper for determining if we can treat a thin stroke as a hairline w/ coverage.
    157     // If we can, we draw lots faster (raster device does this same test).
    158     static bool IsStrokeHairlineOrEquivalent(const GrStrokeInfo& stroke, const SkMatrix& matrix,
    159                                              SkScalar* outCoverage) {
    160         if (stroke.isDashed()) {
    161             return false;
    162         }
    163         if (stroke.getStrokeRec().isHairlineStyle()) {
    164             if (outCoverage) {
    165                 *outCoverage = SK_Scalar1;
    166             }
    167             return true;
    168         }
    169         return stroke.getStrokeRec().getStyle() == SkStrokeRec::kStroke_Style &&
    170             SkDrawTreatAAStrokeAsHairline(stroke.getStrokeRec().getWidth(), matrix, outCoverage);
    171     }
    172 
    173 protected:
    174     /**
    175      * Subclass overrides if it has any limitations of stenciling support.
    176      */
    177     virtual StencilSupport onGetStencilSupport(const GrDrawTarget*,
    178                                                const GrPipelineBuilder*,
    179                                                const SkPath&,
    180                                                const GrStrokeInfo&) const {
    181         return kNoRestriction_StencilSupport;
    182     }
    183 
    184     /**
    185      * Subclass implementation of drawPath()
    186      */
    187     virtual bool onDrawPath(GrDrawTarget*,
    188                             GrPipelineBuilder*,
    189                             GrColor,
    190                             const SkMatrix& viewMatrix,
    191                             const SkPath&,
    192                             const GrStrokeInfo&,
    193                             bool antiAlias) = 0;
    194 
    195     /**
    196      * Subclass implementation of stencilPath(). Subclass must override iff it ever returns
    197      * kStencilOnly in onGetStencilSupport().
    198      */
    199     virtual void onStencilPath(GrDrawTarget* target,
    200                                GrPipelineBuilder* pipelineBuilder,
    201                                const SkMatrix& viewMatrix,
    202                                const SkPath& path,
    203                                const GrStrokeInfo& stroke) {
    204         GR_STATIC_CONST_SAME_STENCIL(kIncrementStencil,
    205                                      kReplace_StencilOp,
    206                                      kReplace_StencilOp,
    207                                      kAlways_StencilFunc,
    208                                      0xffff,
    209                                      0xffff,
    210                                      0xffff);
    211         pipelineBuilder->setStencil(kIncrementStencil);
    212         pipelineBuilder->setDisableColorXPFactory();
    213         this->drawPath(target, pipelineBuilder, GrColor_WHITE, viewMatrix, path, stroke, false);
    214     }
    215 
    216     // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set
    217     // by devSize. Non-inverse path bounds will not necessarily be clipped to devSize.
    218     static void GetPathDevBounds(const SkPath& path,
    219                                  int devW,
    220                                  int devH,
    221                                  const SkMatrix& matrix,
    222                                  SkRect* bounds);
    223 
    224     // Helper version that gets the dev width and height from a GrSurface.
    225     static void GetPathDevBounds(const SkPath& path,
    226                                  const GrSurface* device,
    227                                  const SkMatrix& matrix,
    228                                  SkRect* bounds) {
    229         GetPathDevBounds(path, device->width(), device->height(), matrix, bounds);
    230     }
    231 
    232 private:
    233 
    234     typedef SkRefCnt INHERITED;
    235 };
    236 
    237 #endif
    238