aboutsummaryrefslogtreecommitdiffstats
path: root/src/gpu/GrDrawState.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpu/GrDrawState.h')
-rw-r--r--src/gpu/GrDrawState.h754
1 files changed, 754 insertions, 0 deletions
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
new file mode 100644
index 0000000..4191c4a
--- /dev/null
+++ b/src/gpu/GrDrawState.h
@@ -0,0 +1,754 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrDrawState_DEFINED
+#define GrDrawState_DEFINED
+
+#include "GrColor.h"
+#include "GrMatrix.h"
+#include "GrNoncopyable.h"
+#include "GrSamplerState.h"
+#include "GrStencil.h"
+
+#include "SkXfermode.h"
+
+class GrRenderTarget;
+class GrTexture;
+
+struct GrDrawState {
+
+ /**
+ * Number of texture stages. Each stage takes as input a color and
+ * 2D texture coordinates. The color input to the first enabled stage is the
+ * per-vertex color or the constant color (setColor/setAlpha) if there are
+ * no per-vertex colors. For subsequent stages the input color is the output
+ * color from the previous enabled stage. The output color of each stage is
+ * the input color modulated with the result of a texture lookup. Texture
+ * lookups are specified by a texture a sampler (setSamplerState). Texture
+ * coordinates for each stage come from the vertices based on a
+ * GrVertexLayout bitfield. The output fragment color is the output color of
+ * the last enabled stage. The presence or absence of texture coordinates
+ * for each stage in the vertex layout indicates whether a stage is enabled
+ * or not.
+ */
+ enum {
+ kNumStages = 3,
+ kMaxTexCoords = kNumStages
+ };
+
+ /**
+ * Bitfield used to indicate a set of stages.
+ */
+ typedef uint32_t StageMask;
+ GR_STATIC_ASSERT(sizeof(StageMask)*8 >= GrDrawState::kNumStages);
+
+ GrDrawState() {
+ // make sure any pad is zero for memcmp
+ // all GrDrawState members should default to something
+ // valid by the memset
+ memset(this, 0, sizeof(GrDrawState));
+
+ // memset exceptions
+ fColorFilterMode = SkXfermode::kDstIn_Mode;
+ fFirstCoverageStage = kNumStages;
+
+ // pedantic assertion that our ptrs will
+ // be NULL (0 ptr is mem addr 0)
+ GrAssert((intptr_t)(void*)NULL == 0LL);
+
+ GrAssert(fStencilSettings.isDisabled());
+ fFirstCoverageStage = kNumStages;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Color
+ ////
+
+ /**
+ * Sets color for next draw to a premultiplied-alpha color.
+ *
+ * @param color the color to set.
+ */
+ void setColor(GrColor color) { fColor = color; }
+
+ GrColor getColor() const { return fColor; }
+
+ /**
+ * Sets the color to be used for the next draw to be
+ * (r,g,b,a) = (alpha, alpha, alpha, alpha).
+ *
+ * @param alpha The alpha value to set as the color.
+ */
+ void setAlpha(uint8_t a) {
+ this->setColor((a << 24) | (a << 16) | (a << 8) | a);
+ }
+
+ /**
+ * Add a color filter that can be represented by a color and a mode. Applied
+ * after color-computing texture stages.
+ */
+ void setColorFilter(GrColor c, SkXfermode::Mode mode) {
+ fColorFilterColor = c;
+ fColorFilterMode = mode;
+ }
+
+ GrColor getColorFilterColor() const { return fColorFilterColor; }
+ SkXfermode::Mode getColorFilterMode() const { return fColorFilterMode; }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Textures
+ ////
+
+ /**
+ * Sets the texture used at the next drawing call
+ *
+ * @param stage The texture stage for which the texture will be set
+ *
+ * @param texture The texture to set. Can be NULL though there is no
+ * advantage to settings a NULL texture if doing non-textured drawing
+ */
+ void setTexture(int stage, GrTexture* texture) {
+ GrAssert((unsigned)stage < kNumStages);
+ fTextures[stage] = texture;
+ }
+
+ /**
+ * Retrieves the currently set texture.
+ *
+ * @return The currently set texture. The return value will be NULL if no
+ * texture has been set, NULL was most recently passed to
+ * setTexture, or the last setTexture was destroyed.
+ */
+ const GrTexture* getTexture(int stage) const {
+ GrAssert((unsigned)stage < kNumStages);
+ return fTextures[stage];
+ }
+ GrTexture* getTexture(int stage) {
+ GrAssert((unsigned)stage < kNumStages);
+ return fTextures[stage];
+ }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Samplers
+ ////
+
+ /**
+ * Returns the current sampler for a stage.
+ */
+ const GrSamplerState& getSampler(int stage) const {
+ GrAssert((unsigned)stage < kNumStages);
+ return fSamplerStates[stage];
+ }
+
+ /**
+ * Writable pointer to a stage's sampler.
+ */
+ GrSamplerState* sampler(int stage) {
+ GrAssert((unsigned)stage < kNumStages);
+ return fSamplerStates + stage;
+ }
+
+ /**
+ * Preconcats the matrix of all samplers in the mask with the same matrix.
+ */
+ void preConcatSamplerMatrices(StageMask stageMask, const GrMatrix& matrix) {
+ GrAssert(!(stageMask & kIllegalStageMaskBits));
+ for (int i = 0; i < kNumStages; ++i) {
+ if ((1 << i) & stageMask) {
+ fSamplerStates[i].preConcatMatrix(matrix);
+ }
+ }
+ }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Coverage / Color Stages
+ ////
+
+ /**
+ * A common pattern is to compute a color with the initial stages and then
+ * modulate that color by a coverage value in later stage(s) (AA, mask-
+ * filters, glyph mask, etc). Color-filters, xfermodes, etc should be
+ * computed based on the pre-coverage-modulated color. The division of
+ * stages between color-computing and coverage-computing is specified by
+ * this method. Initially this is kNumStages (all stages
+ * are color-computing).
+ */
+ void setFirstCoverageStage(int firstCoverageStage) {
+ GrAssert((unsigned)firstCoverageStage <= kNumStages);
+ fFirstCoverageStage = firstCoverageStage;
+ }
+
+ /**
+ * Gets the index of the first coverage-computing stage.
+ */
+ int getFirstCoverageStage() const {
+ return fFirstCoverageStage;
+ }
+
+ ///@}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Blending
+ ////
+
+ /**
+ * Sets the blending function coeffecients.
+ *
+ * The blend function will be:
+ * D' = sat(S*srcCoef + D*dstCoef)
+ *
+ * where D is the existing destination color, S is the incoming source
+ * color, and D' is the new destination color that will be written. sat()
+ * is the saturation function.
+ *
+ * @param srcCoef coeffecient applied to the src color.
+ * @param dstCoef coeffecient applied to the dst color.
+ */
+ void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
+ fSrcBlend = srcCoeff;
+ fDstBlend = dstCoeff;
+ #if GR_DEBUG
+ switch (dstCoeff) {
+ case kDC_BlendCoeff:
+ case kIDC_BlendCoeff:
+ case kDA_BlendCoeff:
+ case kIDA_BlendCoeff:
+ GrPrintf("Unexpected dst blend coeff. Won't work correctly with"
+ "coverage stages.\n");
+ break;
+ default:
+ break;
+ }
+ switch (srcCoeff) {
+ case kSC_BlendCoeff:
+ case kISC_BlendCoeff:
+ case kSA_BlendCoeff:
+ case kISA_BlendCoeff:
+ GrPrintf("Unexpected src blend coeff. Won't work correctly with"
+ "coverage stages.\n");
+ break;
+ default:
+ break;
+ }
+ #endif
+ }
+
+ GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlend; }
+ GrBlendCoeff getDstBlendCoeff() const { return fDstBlend; }
+
+ void getDstBlendCoeff(GrBlendCoeff* srcBlendCoeff,
+ GrBlendCoeff* dstBlendCoeff) const {
+ *srcBlendCoeff = fSrcBlend;
+ *dstBlendCoeff = fDstBlend;
+ }
+
+ /**
+ * Sets the blending function constant referenced by the following blending
+ * coeffecients:
+ * kConstC_BlendCoeff
+ * kIConstC_BlendCoeff
+ * kConstA_BlendCoeff
+ * kIConstA_BlendCoeff
+ *
+ * @param constant the constant to set
+ */
+ void setBlendConstant(GrColor constant) { fBlendConstant = constant; }
+
+ /**
+ * Retrieves the last value set by setBlendConstant()
+ * @return the blending constant value
+ */
+ GrColor getBlendConstant() const { return fBlendConstant; }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name View Matrix
+ ////
+
+ /**
+ * Sets the matrix applied to veretx positions.
+ *
+ * In the post-view-matrix space the rectangle [0,w]x[0,h]
+ * fully covers the render target. (w and h are the width and height of the
+ * the rendertarget.)
+ */
+ void setViewMatrix(const GrMatrix& m) { fViewMatrix = m; }
+
+ /**
+ * Gets a writable pointer to the view matrix.
+ */
+ GrMatrix* viewMatrix() { return &fViewMatrix; }
+
+ /**
+ * Multiplies the current view matrix by a matrix
+ *
+ * After this call V' = V*m where V is the old view matrix,
+ * m is the parameter to this function, and V' is the new view matrix.
+ * (We consider positions to be column vectors so position vector p is
+ * transformed by matrix X as p' = X*p.)
+ *
+ * @param m the matrix used to modify the view matrix.
+ */
+ void preConcatViewMatrix(const GrMatrix& m) { fViewMatrix.preConcat(m); }
+
+ /**
+ * Multiplies the current view matrix by a matrix
+ *
+ * After this call V' = m*V where V is the old view matrix,
+ * m is the parameter to this function, and V' is the new view matrix.
+ * (We consider positions to be column vectors so position vector p is
+ * transformed by matrix X as p' = X*p.)
+ *
+ * @param m the matrix used to modify the view matrix.
+ */
+ void postConcatViewMatrix(const GrMatrix& m) { fViewMatrix.postConcat(m); }
+
+ /**
+ * Retrieves the current view matrix
+ * @return the current view matrix.
+ */
+ const GrMatrix& getViewMatrix() const { return fViewMatrix; }
+
+ /**
+ * Retrieves the inverse of the current view matrix.
+ *
+ * If the current view matrix is invertible, return true, and if matrix
+ * is non-null, copy the inverse into it. If the current view matrix is
+ * non-invertible, return false and ignore the matrix parameter.
+ *
+ * @param matrix if not null, will receive a copy of the current inverse.
+ */
+ bool getViewInverse(GrMatrix* matrix) const {
+ // TODO: determine whether we really need to leave matrix unmodified
+ // at call sites when inversion fails.
+ GrMatrix inverse;
+ if (fViewMatrix.invert(&inverse)) {
+ if (matrix) {
+ *matrix = inverse;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ class AutoViewMatrixRestore : public ::GrNoncopyable {
+ public:
+ AutoViewMatrixRestore() : fDrawState(NULL) {}
+ AutoViewMatrixRestore(GrDrawState* ds, const GrMatrix& newMatrix) {
+ fDrawState = NULL;
+ this->set(ds, newMatrix);
+ }
+ AutoViewMatrixRestore(GrDrawState* ds) {
+ fDrawState = NULL;
+ this->set(ds);
+ }
+ ~AutoViewMatrixRestore() {
+ this->set(NULL, GrMatrix::I());
+ }
+ void set(GrDrawState* ds, const GrMatrix& newMatrix) {
+ if (NULL != fDrawState) {
+ fDrawState->setViewMatrix(fSavedMatrix);
+ }
+ if (NULL != ds) {
+ fSavedMatrix = ds->getViewMatrix();
+ ds->setViewMatrix(newMatrix);
+ }
+ fDrawState = ds;
+ }
+ void set(GrDrawState* ds) {
+ if (NULL != fDrawState) {
+ fDrawState->setViewMatrix(fSavedMatrix);
+ }
+ if (NULL != ds) {
+ fSavedMatrix = ds->getViewMatrix();
+ }
+ fDrawState = ds;
+ }
+ private:
+ GrDrawState* fDrawState;
+ GrMatrix fSavedMatrix;
+ };
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Render Target
+ ////
+
+ /**
+ * Sets the rendertarget used at the next drawing call
+ *
+ * @param target The render target to set.
+ */
+ void setRenderTarget(GrRenderTarget* target) { fRenderTarget = target; }
+
+ /**
+ * Retrieves the currently set rendertarget.
+ *
+ * @return The currently set render target.
+ */
+ const GrRenderTarget* getRenderTarget() const { return fRenderTarget; }
+ GrRenderTarget* getRenderTarget() { return fRenderTarget; }
+
+ class AutoRenderTargetRestore : public ::GrNoncopyable {
+ public:
+ AutoRenderTargetRestore() : fDrawState(NULL), fSavedTarget(NULL) {}
+ AutoRenderTargetRestore(GrDrawState* ds, GrRenderTarget* newTarget) {
+ fDrawState = NULL;
+ this->set(ds, newTarget);
+ }
+ ~AutoRenderTargetRestore() { this->set(NULL, NULL); }
+ void set(GrDrawState* ds, GrRenderTarget* newTarget) {
+ if (NULL != fDrawState) {
+ fDrawState->setRenderTarget(fSavedTarget);
+ }
+ if (NULL != ds) {
+ fSavedTarget = ds->getRenderTarget();
+ ds->setRenderTarget(newTarget);
+ }
+ fDrawState = ds;
+ }
+ private:
+ GrDrawState* fDrawState;
+ GrRenderTarget* fSavedTarget;
+ };
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Stencil
+ ////
+
+ /**
+ * Sets the stencil settings to use for the next draw.
+ * Changing the clip has the side-effect of possibly zeroing
+ * out the client settable stencil bits. So multipass algorithms
+ * using stencil should not change the clip between passes.
+ * @param settings the stencil settings to use.
+ */
+ void setStencil(const GrStencilSettings& settings) {
+ fStencilSettings = settings;
+ }
+
+ /**
+ * Shortcut to disable stencil testing and ops.
+ */
+ void disableStencil() {
+ fStencilSettings.setDisabled();
+ }
+
+ const GrStencilSettings& getStencil() const { return fStencilSettings; }
+
+ GrStencilSettings* stencil() { return &fStencilSettings; }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Color Matrix
+ ////
+
+ /**
+ * Sets the color matrix to use for the next draw.
+ * @param matrix the 5x4 matrix to apply to the incoming color
+ */
+ void setColorMatrix(const float matrix[20]) {
+ memcpy(fColorMatrix, matrix, sizeof(fColorMatrix));
+ }
+
+ const float* getColorMatrix() const { return fColorMatrix; }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ // @name Edge AA
+ // There are two ways to perform antialiasing using edge equations. One
+ // is to specify an (linear or quadratic) edge eq per-vertex. This requires
+ // splitting vertices shared by primitives.
+ //
+ // The other is via setEdgeAAData which sets a set of edges and each
+ // is tested against all the edges.
+ ////
+
+ /**
+ * When specifying edges as vertex data this enum specifies what type of
+ * edges are in use. The edges are always 4 GrScalars in memory, even when
+ * the edge type requires fewer than 4.
+ */
+ enum VertexEdgeType {
+ /* 1-pixel wide line
+ 2D implicit line eq (a*x + b*y +c = 0). 4th component unused */
+ kHairLine_EdgeType,
+ /* 1-pixel wide quadratic
+ u^2-v canonical coords (only 2 components used) */
+ kHairQuad_EdgeType
+ };
+
+ /**
+ * Determines the interpretation per-vertex edge data when the
+ * kEdge_VertexLayoutBit is set (see GrDrawTarget). When per-vertex edges
+ * are not specified the value of this setting has no effect.
+ */
+ void setVertexEdgeType(VertexEdgeType type) {
+ fVertexEdgeType = type;
+ }
+
+ VertexEdgeType getVertexEdgeType() const {
+ return fVertexEdgeType;
+ }
+
+ /**
+ * The absolute maximum number of edges that may be specified for
+ * a single draw call when performing edge antialiasing. This is used for
+ * the size of several static buffers, so implementations of getMaxEdges()
+ * (below) should clamp to this value.
+ */
+ enum {
+ // TODO: this should be 32 when GrTesselatedPathRenderer is used
+ // Visual Studio 2010 does not permit a member array of size 0.
+ kMaxEdges = 1
+ };
+
+ class Edge {
+ public:
+ Edge() {}
+ Edge(float x, float y, float z) : fX(x), fY(y), fZ(z) {}
+ GrPoint intersect(const Edge& other) {
+ return GrPoint::Make(
+ SkFloatToScalar((fY * other.fZ - other.fY * fZ) /
+ (fX * other.fY - other.fX * fY)),
+ SkFloatToScalar((fX * other.fZ - other.fX * fZ) /
+ (other.fX * fY - fX * other.fY)));
+ }
+ float fX, fY, fZ;
+ };
+
+ /**
+ * Sets the edge data required for edge antialiasing.
+ *
+ * @param edges 3 * numEdges float values, representing the edge
+ * equations in Ax + By + C form
+ */
+ void setEdgeAAData(const Edge* edges, int numEdges) {
+ GrAssert(numEdges <= GrDrawState::kMaxEdges);
+ memcpy(fEdgeAAEdges, edges, numEdges * sizeof(GrDrawState::Edge));
+ fEdgeAANumEdges = numEdges;
+ }
+
+ int getNumAAEdges() const { return fEdgeAANumEdges; }
+
+ const Edge* getAAEdges() const { return fEdgeAAEdges; }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name State Flags
+ ////
+
+ /**
+ * Flags that affect rendering. Controlled using enable/disableState(). All
+ * default to disabled.
+ */
+ enum StateBits {
+ /**
+ * Perform dithering. TODO: Re-evaluate whether we need this bit
+ */
+ kDither_StateBit = 0x01,
+ /**
+ * Perform HW anti-aliasing. This means either HW FSAA, if supported
+ * by the render target, or smooth-line rendering if a line primitive
+ * is drawn and line smoothing is supported by the 3D API.
+ */
+ kHWAntialias_StateBit = 0x02,
+ /**
+ * Draws will respect the clip, otherwise the clip is ignored.
+ */
+ kClip_StateBit = 0x04,
+ /**
+ * Disables writing to the color buffer. Useful when performing stencil
+ * operations.
+ */
+ kNoColorWrites_StateBit = 0x08,
+ /**
+ * Modifies the behavior of edge AA specified by setEdgeAA. If set,
+ * will test edge pairs for convexity when rasterizing. Set this if the
+ * source polygon is non-convex.
+ */
+ kEdgeAAConcave_StateBit = 0x10,
+ /**
+ * Draws will apply the color matrix, otherwise the color matrix is
+ * ignored.
+ */
+ kColorMatrix_StateBit = 0x20,
+
+ // Users of the class may add additional bits to the vector
+ kDummyStateBit,
+ kLastPublicStateBit = kDummyStateBit-1,
+ };
+
+ void resetStateFlags() {
+ fFlagBits = 0;
+ }
+
+ /**
+ * Enable render state settings.
+ *
+ * @param flags bitfield of StateBits specifing the states to enable
+ */
+ void enableState(uint32_t stateBits) {
+ fFlagBits |= stateBits;
+ }
+
+ /**
+ * Disable render state settings.
+ *
+ * @param flags bitfield of StateBits specifing the states to disable
+ */
+ void disableState(uint32_t stateBits) {
+ fFlagBits &= ~(stateBits);
+ }
+
+ bool isDitherState() const {
+ return 0 != (fFlagBits & kDither_StateBit);
+ }
+
+ bool isHWAntialiasState() const {
+ return 0 != (fFlagBits & kHWAntialias_StateBit);
+ }
+
+ bool isClipState() const {
+ return 0 != (fFlagBits & kClip_StateBit);
+ }
+
+ bool isColorWriteDisabled() const {
+ return 0 != (fFlagBits & kNoColorWrites_StateBit);
+ }
+
+ bool isConcaveEdgeAAState() const {
+ return 0 != (fFlagBits & kEdgeAAConcave_StateBit);
+ }
+
+ bool isStateFlagEnabled(uint32_t stateBit) const {
+ return 0 != (stateBit & fFlagBits);
+ }
+
+ void copyStateFlags(const GrDrawState& ds) {
+ fFlagBits = ds.fFlagBits;
+ }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Face Culling
+ ////
+
+ enum DrawFace {
+ kBoth_DrawFace,
+ kCCW_DrawFace,
+ kCW_DrawFace,
+ };
+
+ /**
+ * Controls whether clockwise, counterclockwise, or both faces are drawn.
+ * @param face the face(s) to draw.
+ */
+ void setDrawFace(DrawFace face) {
+ fDrawFace = face;
+ }
+
+ /**
+ * Gets whether the target is drawing clockwise, counterclockwise,
+ * or both faces.
+ * @return the current draw face(s).
+ */
+ DrawFace getDrawFace() const {
+ return fDrawFace;
+ }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ // Most stages are usually not used, so conditionals here
+ // reduce the expected number of bytes touched by 50%.
+ bool operator ==(const GrDrawState& s) const {
+ if (memcmp(this, &s, this->leadingBytes())) return false;
+
+ for (int i = 0; i < kNumStages; i++) {
+ if (fTextures[i] &&
+ memcmp(&this->fSamplerStates[i], &s.fSamplerStates[i],
+ sizeof(GrSamplerState))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ bool operator !=(const GrDrawState& s) const { return !(*this == s); }
+
+ // Most stages are usually not used, so conditionals here
+ // reduce the expected number of bytes touched by 50%.
+ GrDrawState& operator =(const GrDrawState& s) {
+ memcpy(this, &s, this->leadingBytes());
+
+ for (int i = 0; i < kNumStages; i++) {
+ if (s.fTextures[i]) {
+ memcpy(&this->fSamplerStates[i], &s.fSamplerStates[i],
+ sizeof(GrSamplerState));
+ }
+ }
+
+ return *this;
+ }
+
+private:
+ static const StageMask kIllegalStageMaskBits = ~((1 << kNumStages)-1);
+ uint8_t fFlagBits;
+ GrBlendCoeff fSrcBlend : 8;
+ GrBlendCoeff fDstBlend : 8;
+ DrawFace fDrawFace : 8;
+ uint8_t fFirstCoverageStage;
+ SkXfermode::Mode fColorFilterMode : 8;
+ GrColor fBlendConstant;
+ GrTexture* fTextures[kNumStages];
+ GrRenderTarget* fRenderTarget;
+ GrColor fColor;
+ GrColor fColorFilterColor;
+ float fColorMatrix[20];
+ GrStencilSettings fStencilSettings;
+ GrMatrix fViewMatrix;
+ // @{ Data for GrTesselatedPathRenderer
+ // TODO: currently ignored in copying & comparison for performance.
+ // Must be considered if GrTesselatedPathRenderer is being used.
+
+ VertexEdgeType fVertexEdgeType;
+ int fEdgeAANumEdges;
+ Edge fEdgeAAEdges[kMaxEdges];
+
+ // @}
+ // This field must be last; it will not be copied or compared
+ // if the corresponding fTexture[] is NULL.
+ GrSamplerState fSamplerStates[kNumStages];
+
+ size_t leadingBytes() const {
+ // Can't use offsetof() with non-POD types, so stuck with pointer math.
+ // TODO: ignores GrTesselatedPathRenderer data structures. We don't
+ // have a compile-time flag that lets us know if it's being used, and
+ // checking at runtime seems to cost 5% performance.
+ return (size_t) ((unsigned char*)&fEdgeAANumEdges -
+ (unsigned char*)&fFlagBits);
+ }
+
+};
+
+#endif