michael@0: /* michael@0: * Copyright 2011 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #ifndef GrDrawState_DEFINED michael@0: #define GrDrawState_DEFINED michael@0: michael@0: #include "GrBackendEffectFactory.h" michael@0: #include "GrBlend.h" michael@0: #include "GrColor.h" michael@0: #include "GrEffectStage.h" michael@0: #include "GrPaint.h" michael@0: #include "GrPoint.h" michael@0: #include "GrRenderTarget.h" michael@0: #include "GrStencil.h" michael@0: #include "GrTemplates.h" michael@0: #include "GrTexture.h" michael@0: #include "GrTypesPriv.h" michael@0: #include "effects/GrSimpleTextureEffect.h" michael@0: michael@0: #include "SkMatrix.h" michael@0: #include "SkTypes.h" michael@0: #include "SkXfermode.h" michael@0: michael@0: class GrDrawState : public SkRefCnt { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(GrDrawState) michael@0: michael@0: GrDrawState() { michael@0: SkDEBUGCODE(fBlockEffectRemovalCnt = 0;) michael@0: this->reset(); michael@0: } michael@0: michael@0: GrDrawState(const SkMatrix& initialViewMatrix) { michael@0: SkDEBUGCODE(fBlockEffectRemovalCnt = 0;) michael@0: this->reset(initialViewMatrix); michael@0: } michael@0: michael@0: /** michael@0: * Copies another draw state. michael@0: **/ michael@0: GrDrawState(const GrDrawState& state) : INHERITED() { michael@0: SkDEBUGCODE(fBlockEffectRemovalCnt = 0;) michael@0: *this = state; michael@0: } michael@0: michael@0: /** michael@0: * Copies another draw state with a preconcat to the view matrix. michael@0: **/ michael@0: GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix) { michael@0: SkDEBUGCODE(fBlockEffectRemovalCnt = 0;) michael@0: *this = state; michael@0: if (!preConcatMatrix.isIdentity()) { michael@0: for (int i = 0; i < fColorStages.count(); ++i) { michael@0: fColorStages[i].localCoordChange(preConcatMatrix); michael@0: } michael@0: for (int i = 0; i < fCoverageStages.count(); ++i) { michael@0: fCoverageStages[i].localCoordChange(preConcatMatrix); michael@0: } michael@0: } michael@0: } michael@0: michael@0: virtual ~GrDrawState() { SkASSERT(0 == fBlockEffectRemovalCnt); } michael@0: michael@0: /** michael@0: * Resets to the default state. GrEffects will be removed from all stages. michael@0: */ michael@0: void reset() { this->onReset(NULL); } michael@0: michael@0: void reset(const SkMatrix& initialViewMatrix) { this->onReset(&initialViewMatrix); } michael@0: michael@0: /** michael@0: * Initializes the GrDrawState based on a GrPaint, view matrix and render target. Note that michael@0: * GrDrawState encompasses more than GrPaint. Aspects of GrDrawState that have no GrPaint michael@0: * equivalents are set to default values. Clipping will be enabled. michael@0: */ michael@0: void setFromPaint(const GrPaint& , const SkMatrix& viewMatrix, GrRenderTarget*); michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: /// @name Vertex Attributes michael@0: //// michael@0: michael@0: enum { michael@0: kMaxVertexAttribCnt = kLast_GrVertexAttribBinding + 4, michael@0: }; michael@0: michael@0: /** michael@0: * The format of vertices is represented as an array of GrVertexAttribs, with each representing michael@0: * the type of the attribute, its offset, and semantic binding (see GrVertexAttrib in michael@0: * GrTypesPriv.h). michael@0: * michael@0: * The mapping of attributes with kEffect bindings to GrEffect inputs is specified when michael@0: * setEffect is called. michael@0: */ michael@0: michael@0: /** michael@0: * Sets vertex attributes for next draw. The object driving the templatization michael@0: * should be a global GrVertexAttrib array that is never changed. michael@0: */ michael@0: template void setVertexAttribs(int count) { michael@0: this->setVertexAttribs(A, count); michael@0: } michael@0: michael@0: const GrVertexAttrib* getVertexAttribs() const { return fCommon.fVAPtr; } michael@0: int getVertexAttribCount() const { return fCommon.fVACount; } michael@0: michael@0: size_t getVertexSize() const; michael@0: michael@0: /** michael@0: * Sets default vertex attributes for next draw. The default is a single attribute: michael@0: * {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribType} michael@0: */ michael@0: void setDefaultVertexAttribs(); michael@0: michael@0: /** michael@0: * Getters for index into getVertexAttribs() for particular bindings. -1 is returned if the michael@0: * binding does not appear in the current attribs. These bindings should appear only once in michael@0: * the attrib array. michael@0: */ michael@0: michael@0: int positionAttributeIndex() const { michael@0: return fCommon.fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]; michael@0: } michael@0: int localCoordAttributeIndex() const { michael@0: return fCommon.fFixedFunctionVertexAttribIndices[kLocalCoord_GrVertexAttribBinding]; michael@0: } michael@0: int colorVertexAttributeIndex() const { michael@0: return fCommon.fFixedFunctionVertexAttribIndices[kColor_GrVertexAttribBinding]; michael@0: } michael@0: int coverageVertexAttributeIndex() const { michael@0: return fCommon.fFixedFunctionVertexAttribIndices[kCoverage_GrVertexAttribBinding]; michael@0: } michael@0: michael@0: bool hasLocalCoordAttribute() const { michael@0: return -1 != fCommon.fFixedFunctionVertexAttribIndices[kLocalCoord_GrVertexAttribBinding]; michael@0: } michael@0: bool hasColorVertexAttribute() const { michael@0: return -1 != fCommon.fFixedFunctionVertexAttribIndices[kColor_GrVertexAttribBinding]; michael@0: } michael@0: bool hasCoverageVertexAttribute() const { michael@0: return -1 != fCommon.fFixedFunctionVertexAttribIndices[kCoverage_GrVertexAttribBinding]; michael@0: } michael@0: michael@0: bool validateVertexAttribs() const; michael@0: michael@0: /** michael@0: * Helper to save/restore vertex attribs michael@0: */ michael@0: class AutoVertexAttribRestore { michael@0: public: michael@0: AutoVertexAttribRestore(GrDrawState* drawState) { michael@0: SkASSERT(NULL != drawState); michael@0: fDrawState = drawState; michael@0: fVAPtr = drawState->fCommon.fVAPtr; michael@0: fVACount = drawState->fCommon.fVACount; michael@0: fDrawState->setDefaultVertexAttribs(); michael@0: } michael@0: michael@0: ~AutoVertexAttribRestore(){ michael@0: fDrawState->setVertexAttribs(fVAPtr, fVACount); michael@0: } michael@0: michael@0: private: michael@0: GrDrawState* fDrawState; michael@0: const GrVertexAttrib* fVAPtr; michael@0: int fVACount; michael@0: }; michael@0: michael@0: /** michael@0: * Accessing positions, local coords, or colors, of a vertex within an array is a hassle michael@0: * involving casts and simple math. These helpers exist to keep GrDrawTarget clients' code a bit michael@0: * nicer looking. michael@0: */ michael@0: michael@0: /** michael@0: * Gets a pointer to a GrPoint of a vertex's position or texture michael@0: * coordinate. michael@0: * @param vertices the vertex array michael@0: * @param vertexIndex the index of the vertex in the array michael@0: * @param vertexSize the size of each vertex in the array michael@0: * @param offset the offset in bytes of the vertex component. michael@0: * Defaults to zero (corresponding to vertex position) michael@0: * @return pointer to the vertex component as a GrPoint michael@0: */ michael@0: static GrPoint* GetVertexPoint(void* vertices, michael@0: int vertexIndex, michael@0: int vertexSize, michael@0: int offset = 0) { michael@0: intptr_t start = GrTCast(vertices); michael@0: return GrTCast(start + offset + michael@0: vertexIndex * vertexSize); michael@0: } michael@0: static const GrPoint* GetVertexPoint(const void* vertices, michael@0: int vertexIndex, michael@0: int vertexSize, michael@0: int offset = 0) { michael@0: intptr_t start = GrTCast(vertices); michael@0: return GrTCast(start + offset + michael@0: vertexIndex * vertexSize); michael@0: } michael@0: michael@0: /** michael@0: * Gets a pointer to a GrColor inside a vertex within a vertex array. michael@0: * @param vertices the vetex array michael@0: * @param vertexIndex the index of the vertex in the array michael@0: * @param vertexSize the size of each vertex in the array michael@0: * @param offset the offset in bytes of the vertex color michael@0: * @return pointer to the vertex component as a GrColor michael@0: */ michael@0: static GrColor* GetVertexColor(void* vertices, michael@0: int vertexIndex, michael@0: int vertexSize, michael@0: int offset) { michael@0: intptr_t start = GrTCast(vertices); michael@0: return GrTCast(start + offset + michael@0: vertexIndex * vertexSize); michael@0: } michael@0: static const GrColor* GetVertexColor(const void* vertices, michael@0: int vertexIndex, michael@0: int vertexSize, michael@0: int offset) { michael@0: const intptr_t start = GrTCast(vertices); michael@0: return GrTCast(start + offset + michael@0: vertexIndex * vertexSize); michael@0: } michael@0: michael@0: /// @} michael@0: michael@0: /** michael@0: * Determines whether src alpha is guaranteed to be one for all src pixels michael@0: */ michael@0: bool srcAlphaWillBeOne() const; michael@0: michael@0: /** michael@0: * Determines whether the output coverage is guaranteed to be one for all pixels hit by a draw. michael@0: */ michael@0: bool hasSolidCoverage() const; michael@0: michael@0: /// @} michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: /// @name Color michael@0: //// michael@0: michael@0: /** michael@0: * Sets color for next draw to a premultiplied-alpha color. michael@0: * michael@0: * @param color the color to set. michael@0: */ michael@0: void setColor(GrColor color) { fCommon.fColor = color; } michael@0: michael@0: GrColor getColor() const { return fCommon.fColor; } michael@0: michael@0: /** michael@0: * Sets the color to be used for the next draw to be michael@0: * (r,g,b,a) = (alpha, alpha, alpha, alpha). michael@0: * michael@0: * @param alpha The alpha value to set as the color. michael@0: */ michael@0: void setAlpha(uint8_t a) { michael@0: this->setColor((a << 24) | (a << 16) | (a << 8) | a); michael@0: } michael@0: michael@0: /** michael@0: * Constructor sets the color to be 'color' which is undone by the destructor. michael@0: */ michael@0: class AutoColorRestore : public ::SkNoncopyable { michael@0: public: michael@0: AutoColorRestore() : fDrawState(NULL), fOldColor(0) {} michael@0: michael@0: AutoColorRestore(GrDrawState* drawState, GrColor color) { michael@0: fDrawState = NULL; michael@0: this->set(drawState, color); michael@0: } michael@0: michael@0: void reset() { michael@0: if (NULL != fDrawState) { michael@0: fDrawState->setColor(fOldColor); michael@0: fDrawState = NULL; michael@0: } michael@0: } michael@0: michael@0: void set(GrDrawState* drawState, GrColor color) { michael@0: this->reset(); michael@0: fDrawState = drawState; michael@0: fOldColor = fDrawState->getColor(); michael@0: fDrawState->setColor(color); michael@0: } michael@0: michael@0: ~AutoColorRestore() { this->reset(); } michael@0: private: michael@0: GrDrawState* fDrawState; michael@0: GrColor fOldColor; michael@0: }; michael@0: michael@0: /// @} michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: /// @name Coverage michael@0: //// michael@0: michael@0: /** michael@0: * Sets a constant fractional coverage to be applied to the draw. The michael@0: * initial value (after construction or reset()) is 0xff. The constant michael@0: * coverage is ignored when per-vertex coverage is provided. michael@0: */ michael@0: void setCoverage(uint8_t coverage) { michael@0: fCommon.fCoverage = GrColorPackRGBA(coverage, coverage, coverage, coverage); michael@0: } michael@0: michael@0: uint8_t getCoverage() const { michael@0: return GrColorUnpackR(fCommon.fCoverage); michael@0: } michael@0: michael@0: GrColor getCoverageColor() const { michael@0: return fCommon.fCoverage; michael@0: } michael@0: michael@0: /// @} michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: /// @name Effect Stages michael@0: /// Each stage hosts a GrEffect. The effect produces an output color or coverage in the fragment michael@0: /// shader. Its inputs are the output from the previous stage as well as some variables michael@0: /// available to it in the fragment and vertex shader (e.g. the vertex position, the dst color, michael@0: /// the fragment position, local coordinates). michael@0: /// michael@0: /// The stages are divided into two sets, color-computing and coverage-computing. The final michael@0: /// color stage produces the final pixel color. The coverage-computing stages function exactly michael@0: /// as the color-computing but the output of the final coverage stage is treated as a fractional michael@0: /// pixel coverage rather than as input to the src/dst color blend step. michael@0: /// michael@0: /// The input color to the first color-stage is either the constant color or interpolated michael@0: /// per-vertex colors. The input to the first coverage stage is either a constant coverage michael@0: /// (usually full-coverage) or interpolated per-vertex coverage. michael@0: /// michael@0: /// See the documentation of kCoverageDrawing_StateBit for information about disabling the michael@0: /// the color / coverage distinction. michael@0: //// michael@0: michael@0: const GrEffectRef* addColorEffect(const GrEffectRef* effect, int attr0 = -1, int attr1 = -1) { michael@0: SkASSERT(NULL != effect); michael@0: SkNEW_APPEND_TO_TARRAY(&fColorStages, GrEffectStage, (effect, attr0, attr1)); michael@0: return effect; michael@0: } michael@0: michael@0: const GrEffectRef* addCoverageEffect(const GrEffectRef* effect, int attr0 = -1, int attr1 = -1) { michael@0: SkASSERT(NULL != effect); michael@0: SkNEW_APPEND_TO_TARRAY(&fCoverageStages, GrEffectStage, (effect, attr0, attr1)); michael@0: return effect; michael@0: } michael@0: michael@0: /** michael@0: * Creates a GrSimpleTextureEffect that uses local coords as texture coordinates. michael@0: */ michael@0: void addColorTextureEffect(GrTexture* texture, const SkMatrix& matrix) { michael@0: GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix); michael@0: this->addColorEffect(effect)->unref(); michael@0: } michael@0: michael@0: void addCoverageTextureEffect(GrTexture* texture, const SkMatrix& matrix) { michael@0: GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix); michael@0: this->addCoverageEffect(effect)->unref(); michael@0: } michael@0: michael@0: void addColorTextureEffect(GrTexture* texture, michael@0: const SkMatrix& matrix, michael@0: const GrTextureParams& params) { michael@0: GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix, params); michael@0: this->addColorEffect(effect)->unref(); michael@0: } michael@0: michael@0: void addCoverageTextureEffect(GrTexture* texture, michael@0: const SkMatrix& matrix, michael@0: const GrTextureParams& params) { michael@0: GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix, params); michael@0: this->addCoverageEffect(effect)->unref(); michael@0: } michael@0: michael@0: /** michael@0: * When this object is destroyed it will remove any effects from the draw state that were added michael@0: * after its constructor. michael@0: */ michael@0: class AutoRestoreEffects : public ::SkNoncopyable { michael@0: public: michael@0: AutoRestoreEffects() : fDrawState(NULL), fColorEffectCnt(0), fCoverageEffectCnt(0) {} michael@0: michael@0: AutoRestoreEffects(GrDrawState* ds) : fDrawState(NULL), fColorEffectCnt(0), fCoverageEffectCnt(0) { michael@0: this->set(ds); michael@0: } michael@0: michael@0: ~AutoRestoreEffects() { this->set(NULL); } michael@0: michael@0: void set(GrDrawState* ds) { michael@0: if (NULL != fDrawState) { michael@0: int n = fDrawState->fColorStages.count() - fColorEffectCnt; michael@0: SkASSERT(n >= 0); michael@0: fDrawState->fColorStages.pop_back_n(n); michael@0: n = fDrawState->fCoverageStages.count() - fCoverageEffectCnt; michael@0: SkASSERT(n >= 0); michael@0: fDrawState->fCoverageStages.pop_back_n(n); michael@0: SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;) michael@0: } michael@0: fDrawState = ds; michael@0: if (NULL != ds) { michael@0: fColorEffectCnt = ds->fColorStages.count(); michael@0: fCoverageEffectCnt = ds->fCoverageStages.count(); michael@0: SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;) michael@0: } michael@0: } michael@0: michael@0: private: michael@0: GrDrawState* fDrawState; michael@0: int fColorEffectCnt; michael@0: int fCoverageEffectCnt; michael@0: }; michael@0: michael@0: int numColorStages() const { return fColorStages.count(); } michael@0: int numCoverageStages() const { return fCoverageStages.count(); } michael@0: int numTotalStages() const { return this->numColorStages() + this->numCoverageStages(); } michael@0: michael@0: const GrEffectStage& getColorStage(int stageIdx) const { return fColorStages[stageIdx]; } michael@0: const GrEffectStage& getCoverageStage(int stageIdx) const { return fCoverageStages[stageIdx]; } michael@0: michael@0: /** michael@0: * Checks whether any of the effects will read the dst pixel color. michael@0: */ michael@0: bool willEffectReadDstColor() const; michael@0: michael@0: /// @} michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: /// @name Blending michael@0: //// michael@0: michael@0: /** michael@0: * Sets the blending function coefficients. michael@0: * michael@0: * The blend function will be: michael@0: * D' = sat(S*srcCoef + D*dstCoef) michael@0: * michael@0: * where D is the existing destination color, S is the incoming source michael@0: * color, and D' is the new destination color that will be written. sat() michael@0: * is the saturation function. michael@0: * michael@0: * @param srcCoef coefficient applied to the src color. michael@0: * @param dstCoef coefficient applied to the dst color. michael@0: */ michael@0: void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) { michael@0: fCommon.fSrcBlend = srcCoeff; michael@0: fCommon.fDstBlend = dstCoeff; michael@0: #ifdef SK_DEBUG michael@0: if (GrBlendCoeffRefsDst(dstCoeff)) { michael@0: GrPrintf("Unexpected dst blend coeff. Won't work correctly with coverage stages.\n"); michael@0: } michael@0: if (GrBlendCoeffRefsSrc(srcCoeff)) { michael@0: GrPrintf("Unexpected src blend coeff. Won't work correctly with coverage stages.\n"); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: GrBlendCoeff getSrcBlendCoeff() const { return fCommon.fSrcBlend; } michael@0: GrBlendCoeff getDstBlendCoeff() const { return fCommon.fDstBlend; } michael@0: michael@0: void getDstBlendCoeff(GrBlendCoeff* srcBlendCoeff, michael@0: GrBlendCoeff* dstBlendCoeff) const { michael@0: *srcBlendCoeff = fCommon.fSrcBlend; michael@0: *dstBlendCoeff = fCommon.fDstBlend; michael@0: } michael@0: michael@0: /** michael@0: * Sets the blending function constant referenced by the following blending michael@0: * coefficients: michael@0: * kConstC_GrBlendCoeff michael@0: * kIConstC_GrBlendCoeff michael@0: * kConstA_GrBlendCoeff michael@0: * kIConstA_GrBlendCoeff michael@0: * michael@0: * @param constant the constant to set michael@0: */ michael@0: void setBlendConstant(GrColor constant) { fCommon.fBlendConstant = constant; } michael@0: michael@0: /** michael@0: * Retrieves the last value set by setBlendConstant() michael@0: * @return the blending constant value michael@0: */ michael@0: GrColor getBlendConstant() const { return fCommon.fBlendConstant; } michael@0: michael@0: /** michael@0: * Determines whether multiplying the computed per-pixel color by the pixel's fractional michael@0: * coverage before the blend will give the correct final destination color. In general it michael@0: * will not as coverage is applied after blending. michael@0: */ michael@0: bool canTweakAlphaForCoverage() const; michael@0: michael@0: /** michael@0: * Optimizations for blending / coverage to that can be applied based on the current state. michael@0: */ michael@0: enum BlendOptFlags { michael@0: /** michael@0: * No optimization michael@0: */ michael@0: kNone_BlendOpt = 0, michael@0: /** michael@0: * Don't draw at all michael@0: */ michael@0: kSkipDraw_BlendOptFlag = 0x1, michael@0: /** michael@0: * Emit the src color, disable HW blending (replace dst with src) michael@0: */ michael@0: kDisableBlend_BlendOptFlag = 0x2, michael@0: /** michael@0: * The coverage value does not have to be computed separately from alpha, the the output michael@0: * color can be the modulation of the two. michael@0: */ michael@0: kCoverageAsAlpha_BlendOptFlag = 0x4, michael@0: /** michael@0: * Instead of emitting a src color, emit coverage in the alpha channel and r,g,b are michael@0: * "don't cares". michael@0: */ michael@0: kEmitCoverage_BlendOptFlag = 0x8, michael@0: /** michael@0: * Emit transparent black instead of the src color, no need to compute coverage. michael@0: */ michael@0: kEmitTransBlack_BlendOptFlag = 0x10, michael@0: }; michael@0: GR_DECL_BITFIELD_OPS_FRIENDS(BlendOptFlags); michael@0: michael@0: /** michael@0: * Determines what optimizations can be applied based on the blend. The coefficients may have michael@0: * to be tweaked in order for the optimization to work. srcCoeff and dstCoeff are optional michael@0: * params that receive the tweaked coefficients. Normally the function looks at the current michael@0: * state to see if coverage is enabled. By setting forceCoverage the caller can speculatively michael@0: * determine the blend optimizations that would be used if there was partial pixel coverage. michael@0: * michael@0: * Subclasses of GrDrawTarget that actually draw (as opposed to those that just buffer for michael@0: * playback) must call this function and respect the flags that replace the output color. michael@0: */ michael@0: BlendOptFlags getBlendOpts(bool forceCoverage = false, michael@0: GrBlendCoeff* srcCoeff = NULL, michael@0: GrBlendCoeff* dstCoeff = NULL) const; michael@0: michael@0: /// @} michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: /// @name View Matrix michael@0: //// michael@0: michael@0: /** michael@0: * Sets the view matrix to identity and updates any installed effects to compensate for the michael@0: * coord system change. michael@0: */ michael@0: bool setIdentityViewMatrix(); michael@0: michael@0: /** michael@0: * Retrieves the current view matrix michael@0: * @return the current view matrix. michael@0: */ michael@0: const SkMatrix& getViewMatrix() const { return fCommon.fViewMatrix; } michael@0: michael@0: /** michael@0: * Retrieves the inverse of the current view matrix. michael@0: * michael@0: * If the current view matrix is invertible, return true, and if matrix michael@0: * is non-null, copy the inverse into it. If the current view matrix is michael@0: * non-invertible, return false and ignore the matrix parameter. michael@0: * michael@0: * @param matrix if not null, will receive a copy of the current inverse. michael@0: */ michael@0: bool getViewInverse(SkMatrix* matrix) const { michael@0: // TODO: determine whether we really need to leave matrix unmodified michael@0: // at call sites when inversion fails. michael@0: SkMatrix inverse; michael@0: if (fCommon.fViewMatrix.invert(&inverse)) { michael@0: if (matrix) { michael@0: *matrix = inverse; michael@0: } michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * Preconcats the current view matrix and restores the previous view matrix in the destructor. michael@0: * Effect matrices are automatically adjusted to compensate and adjusted back in the destructor. michael@0: */ michael@0: class AutoViewMatrixRestore : public ::SkNoncopyable { michael@0: public: michael@0: AutoViewMatrixRestore() : fDrawState(NULL) {} michael@0: michael@0: AutoViewMatrixRestore(GrDrawState* ds, const SkMatrix& preconcatMatrix) { michael@0: fDrawState = NULL; michael@0: this->set(ds, preconcatMatrix); michael@0: } michael@0: michael@0: ~AutoViewMatrixRestore() { this->restore(); } michael@0: michael@0: /** michael@0: * Can be called prior to destructor to restore the original matrix. michael@0: */ michael@0: void restore(); michael@0: michael@0: void set(GrDrawState* drawState, const SkMatrix& preconcatMatrix); michael@0: michael@0: /** Sets the draw state's matrix to identity. This can fail because the current view matrix michael@0: is not invertible. */ michael@0: bool setIdentity(GrDrawState* drawState); michael@0: michael@0: private: michael@0: void doEffectCoordChanges(const SkMatrix& coordChangeMatrix); michael@0: michael@0: GrDrawState* fDrawState; michael@0: SkMatrix fViewMatrix; michael@0: int fNumColorStages; michael@0: SkAutoSTArray<8, GrEffectStage::SavedCoordChange> fSavedCoordChanges; michael@0: }; michael@0: michael@0: /// @} michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: /// @name Render Target michael@0: //// michael@0: michael@0: /** michael@0: * Sets the render-target used at the next drawing call michael@0: * michael@0: * @param target The render target to set. michael@0: */ michael@0: void setRenderTarget(GrRenderTarget* target) { michael@0: fRenderTarget.reset(SkSafeRef(target)); michael@0: } michael@0: michael@0: /** michael@0: * Retrieves the currently set render-target. michael@0: * michael@0: * @return The currently set render target. michael@0: */ michael@0: const GrRenderTarget* getRenderTarget() const { return fRenderTarget.get(); } michael@0: GrRenderTarget* getRenderTarget() { return fRenderTarget.get(); } michael@0: michael@0: class AutoRenderTargetRestore : public ::SkNoncopyable { michael@0: public: michael@0: AutoRenderTargetRestore() : fDrawState(NULL), fSavedTarget(NULL) {} michael@0: AutoRenderTargetRestore(GrDrawState* ds, GrRenderTarget* newTarget) { michael@0: fDrawState = NULL; michael@0: fSavedTarget = NULL; michael@0: this->set(ds, newTarget); michael@0: } michael@0: ~AutoRenderTargetRestore() { this->restore(); } michael@0: michael@0: void restore() { michael@0: if (NULL != fDrawState) { michael@0: fDrawState->setRenderTarget(fSavedTarget); michael@0: fDrawState = NULL; michael@0: } michael@0: SkSafeSetNull(fSavedTarget); michael@0: } michael@0: michael@0: void set(GrDrawState* ds, GrRenderTarget* newTarget) { michael@0: this->restore(); michael@0: michael@0: if (NULL != ds) { michael@0: SkASSERT(NULL == fSavedTarget); michael@0: fSavedTarget = ds->getRenderTarget(); michael@0: SkSafeRef(fSavedTarget); michael@0: ds->setRenderTarget(newTarget); michael@0: fDrawState = ds; michael@0: } michael@0: } michael@0: private: michael@0: GrDrawState* fDrawState; michael@0: GrRenderTarget* fSavedTarget; michael@0: }; michael@0: michael@0: /// @} michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: /// @name Stencil michael@0: //// michael@0: michael@0: /** michael@0: * Sets the stencil settings to use for the next draw. michael@0: * Changing the clip has the side-effect of possibly zeroing michael@0: * out the client settable stencil bits. So multipass algorithms michael@0: * using stencil should not change the clip between passes. michael@0: * @param settings the stencil settings to use. michael@0: */ michael@0: void setStencil(const GrStencilSettings& settings) { michael@0: fCommon.fStencilSettings = settings; michael@0: } michael@0: michael@0: /** michael@0: * Shortcut to disable stencil testing and ops. michael@0: */ michael@0: void disableStencil() { michael@0: fCommon.fStencilSettings.setDisabled(); michael@0: } michael@0: michael@0: const GrStencilSettings& getStencil() const { return fCommon.fStencilSettings; } michael@0: michael@0: GrStencilSettings* stencil() { return &fCommon.fStencilSettings; } michael@0: michael@0: /// @} michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: /// @name State Flags michael@0: //// michael@0: michael@0: /** michael@0: * Flags that affect rendering. Controlled using enable/disableState(). All michael@0: * default to disabled. michael@0: */ michael@0: enum StateBits { michael@0: /** michael@0: * Perform dithering. TODO: Re-evaluate whether we need this bit michael@0: */ michael@0: kDither_StateBit = 0x01, michael@0: /** michael@0: * Perform HW anti-aliasing. This means either HW FSAA, if supported by the render target, michael@0: * or smooth-line rendering if a line primitive is drawn and line smoothing is supported by michael@0: * the 3D API. michael@0: */ michael@0: kHWAntialias_StateBit = 0x02, michael@0: /** michael@0: * Draws will respect the clip, otherwise the clip is ignored. michael@0: */ michael@0: kClip_StateBit = 0x04, michael@0: /** michael@0: * Disables writing to the color buffer. Useful when performing stencil michael@0: * operations. michael@0: */ michael@0: kNoColorWrites_StateBit = 0x08, michael@0: michael@0: /** michael@0: * Usually coverage is applied after color blending. The color is blended using the coeffs michael@0: * specified by setBlendFunc(). The blended color is then combined with dst using coeffs michael@0: * of src_coverage, 1-src_coverage. Sometimes we are explicitly drawing a coverage mask. In michael@0: * this case there is no distinction between coverage and color and the caller needs direct michael@0: * control over the blend coeffs. When set, there will be a single blend step controlled by michael@0: * setBlendFunc() which will use coverage*color as the src color. michael@0: */ michael@0: kCoverageDrawing_StateBit = 0x10, michael@0: michael@0: // Users of the class may add additional bits to the vector michael@0: kDummyStateBit, michael@0: kLastPublicStateBit = kDummyStateBit-1, michael@0: }; michael@0: michael@0: void resetStateFlags() { michael@0: fCommon.fFlagBits = 0; michael@0: } michael@0: michael@0: /** michael@0: * Enable render state settings. michael@0: * michael@0: * @param stateBits bitfield of StateBits specifying the states to enable michael@0: */ michael@0: void enableState(uint32_t stateBits) { michael@0: fCommon.fFlagBits |= stateBits; michael@0: } michael@0: michael@0: /** michael@0: * Disable render state settings. michael@0: * michael@0: * @param stateBits bitfield of StateBits specifying the states to disable michael@0: */ michael@0: void disableState(uint32_t stateBits) { michael@0: fCommon.fFlagBits &= ~(stateBits); michael@0: } michael@0: michael@0: /** michael@0: * Enable or disable stateBits based on a boolean. michael@0: * michael@0: * @param stateBits bitfield of StateBits to enable or disable michael@0: * @param enable if true enable stateBits, otherwise disable michael@0: */ michael@0: void setState(uint32_t stateBits, bool enable) { michael@0: if (enable) { michael@0: this->enableState(stateBits); michael@0: } else { michael@0: this->disableState(stateBits); michael@0: } michael@0: } michael@0: michael@0: bool isDitherState() const { michael@0: return 0 != (fCommon.fFlagBits & kDither_StateBit); michael@0: } michael@0: michael@0: bool isHWAntialiasState() const { michael@0: return 0 != (fCommon.fFlagBits & kHWAntialias_StateBit); michael@0: } michael@0: michael@0: bool isClipState() const { michael@0: return 0 != (fCommon.fFlagBits & kClip_StateBit); michael@0: } michael@0: michael@0: bool isColorWriteDisabled() const { michael@0: return 0 != (fCommon.fFlagBits & kNoColorWrites_StateBit); michael@0: } michael@0: michael@0: bool isCoverageDrawing() const { michael@0: return 0 != (fCommon.fFlagBits & kCoverageDrawing_StateBit); michael@0: } michael@0: michael@0: bool isStateFlagEnabled(uint32_t stateBit) const { michael@0: return 0 != (stateBit & fCommon.fFlagBits); michael@0: } michael@0: michael@0: /// @} michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: /// @name Face Culling michael@0: //// michael@0: michael@0: enum DrawFace { michael@0: kInvalid_DrawFace = -1, michael@0: michael@0: kBoth_DrawFace, michael@0: kCCW_DrawFace, michael@0: kCW_DrawFace, michael@0: }; michael@0: michael@0: /** michael@0: * Controls whether clockwise, counterclockwise, or both faces are drawn. michael@0: * @param face the face(s) to draw. michael@0: */ michael@0: void setDrawFace(DrawFace face) { michael@0: SkASSERT(kInvalid_DrawFace != face); michael@0: fCommon.fDrawFace = face; michael@0: } michael@0: michael@0: /** michael@0: * Gets whether the target is drawing clockwise, counterclockwise, michael@0: * or both faces. michael@0: * @return the current draw face(s). michael@0: */ michael@0: DrawFace getDrawFace() const { return fCommon.fDrawFace; } michael@0: michael@0: /// @} michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: michael@0: bool operator ==(const GrDrawState& s) const { michael@0: if (fRenderTarget.get() != s.fRenderTarget.get() || michael@0: fColorStages.count() != s.fColorStages.count() || michael@0: fCoverageStages.count() != s.fCoverageStages.count() || michael@0: fCommon != s.fCommon) { michael@0: return false; michael@0: } michael@0: for (int i = 0; i < fColorStages.count(); i++) { michael@0: if (fColorStages[i] != s.fColorStages[i]) { michael@0: return false; michael@0: } michael@0: } michael@0: for (int i = 0; i < fCoverageStages.count(); i++) { michael@0: if (fCoverageStages[i] != s.fCoverageStages[i]) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: bool operator !=(const GrDrawState& s) const { return !(*this == s); } michael@0: michael@0: GrDrawState& operator= (const GrDrawState& s) { michael@0: SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages()); michael@0: this->setRenderTarget(s.fRenderTarget.get()); michael@0: fCommon = s.fCommon; michael@0: fColorStages = s.fColorStages; michael@0: fCoverageStages = s.fCoverageStages; michael@0: return *this; michael@0: } michael@0: michael@0: private: michael@0: michael@0: void onReset(const SkMatrix* initialViewMatrix) { michael@0: SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages()); michael@0: fColorStages.reset(); michael@0: fCoverageStages.reset(); michael@0: michael@0: fRenderTarget.reset(NULL); michael@0: michael@0: this->setDefaultVertexAttribs(); michael@0: michael@0: fCommon.fColor = 0xffffffff; michael@0: if (NULL == initialViewMatrix) { michael@0: fCommon.fViewMatrix.reset(); michael@0: } else { michael@0: fCommon.fViewMatrix = *initialViewMatrix; michael@0: } michael@0: fCommon.fSrcBlend = kOne_GrBlendCoeff; michael@0: fCommon.fDstBlend = kZero_GrBlendCoeff; michael@0: fCommon.fBlendConstant = 0x0; michael@0: fCommon.fFlagBits = 0x0; michael@0: fCommon.fStencilSettings.setDisabled(); michael@0: fCommon.fCoverage = 0xffffffff; michael@0: fCommon.fDrawFace = kBoth_DrawFace; michael@0: } michael@0: michael@0: /** Fields that are identical in GrDrawState and GrDrawState::DeferredState. */ michael@0: struct CommonState { michael@0: // These fields are roughly sorted by decreasing likelihood of being different in op== michael@0: GrColor fColor; michael@0: SkMatrix fViewMatrix; michael@0: GrBlendCoeff fSrcBlend; michael@0: GrBlendCoeff fDstBlend; michael@0: GrColor fBlendConstant; michael@0: uint32_t fFlagBits; michael@0: const GrVertexAttrib* fVAPtr; michael@0: int fVACount; michael@0: GrStencilSettings fStencilSettings; michael@0: GrColor fCoverage; michael@0: DrawFace fDrawFace; michael@0: michael@0: // This is simply a different representation of info in fVertexAttribs and thus does michael@0: // not need to be compared in op==. michael@0: int fFixedFunctionVertexAttribIndices[kGrFixedFunctionVertexAttribBindingCnt]; michael@0: michael@0: bool operator== (const CommonState& other) const { michael@0: bool result = fColor == other.fColor && michael@0: fViewMatrix.cheapEqualTo(other.fViewMatrix) && michael@0: fSrcBlend == other.fSrcBlend && michael@0: fDstBlend == other.fDstBlend && michael@0: fBlendConstant == other.fBlendConstant && michael@0: fFlagBits == other.fFlagBits && michael@0: fVACount == other.fVACount && michael@0: !memcmp(fVAPtr, other.fVAPtr, fVACount * sizeof(GrVertexAttrib)) && michael@0: fStencilSettings == other.fStencilSettings && michael@0: fCoverage == other.fCoverage && michael@0: fDrawFace == other.fDrawFace; michael@0: SkASSERT(!result || 0 == memcmp(fFixedFunctionVertexAttribIndices, michael@0: other.fFixedFunctionVertexAttribIndices, michael@0: sizeof(fFixedFunctionVertexAttribIndices))); michael@0: return result; michael@0: } michael@0: bool operator!= (const CommonState& other) const { return !(*this == other); } michael@0: }; michael@0: michael@0: /** GrDrawState uses GrEffectStages to hold stage state which holds a ref on GrEffectRef. michael@0: DeferredState must directly reference GrEffects, however. */ michael@0: struct SavedEffectStage { michael@0: SavedEffectStage() : fEffect(NULL) {} michael@0: const GrEffect* fEffect; michael@0: GrEffectStage::SavedCoordChange fCoordChange; michael@0: }; michael@0: michael@0: public: michael@0: /** michael@0: * DeferredState contains all of the data of a GrDrawState but does not hold refs on GrResource michael@0: * objects. Resources are allowed to hit zero ref count while in DeferredStates. Their internal michael@0: * dispose mechanism returns them to the cache. This allows recycling resources through the michael@0: * the cache while they are in a deferred draw queue. michael@0: */ michael@0: class DeferredState { michael@0: public: michael@0: DeferredState() : fRenderTarget(NULL) { michael@0: SkDEBUGCODE(fInitialized = false;) michael@0: } michael@0: // TODO: Remove this when DeferredState no longer holds a ref to the RT michael@0: ~DeferredState() { SkSafeUnref(fRenderTarget); } michael@0: michael@0: void saveFrom(const GrDrawState& drawState) { michael@0: fCommon = drawState.fCommon; michael@0: // TODO: Here we will copy the GrRenderTarget pointer without taking a ref. michael@0: fRenderTarget = drawState.fRenderTarget.get(); michael@0: SkSafeRef(fRenderTarget); michael@0: // Here we ref the effects directly rather than the effect-refs. TODO: When the effect- michael@0: // ref gets fully unref'ed it will cause the underlying effect to unref its resources michael@0: // and recycle them to the cache (if no one else is holding a ref to the resources). michael@0: fStages.reset(drawState.fColorStages.count() + drawState.fCoverageStages.count()); michael@0: fColorStageCnt = drawState.fColorStages.count(); michael@0: for (int i = 0; i < fColorStageCnt; ++i) { michael@0: fStages[i].saveFrom(drawState.fColorStages[i]); michael@0: } michael@0: for (int i = 0; i < drawState.fCoverageStages.count(); ++i) { michael@0: fStages[i + fColorStageCnt].saveFrom(drawState.fCoverageStages[i]); michael@0: } michael@0: SkDEBUGCODE(fInitialized = true;) michael@0: } michael@0: michael@0: void restoreTo(GrDrawState* drawState) { michael@0: SkASSERT(fInitialized); michael@0: drawState->fCommon = fCommon; michael@0: drawState->setRenderTarget(fRenderTarget); michael@0: // reinflate color/cov stage arrays. michael@0: drawState->fColorStages.reset(); michael@0: for (int i = 0; i < fColorStageCnt; ++i) { michael@0: SkNEW_APPEND_TO_TARRAY(&drawState->fColorStages, GrEffectStage, (fStages[i])); michael@0: } michael@0: int coverageStageCnt = fStages.count() - fColorStageCnt; michael@0: drawState->fCoverageStages.reset(); michael@0: for (int i = 0; i < coverageStageCnt; ++i) { michael@0: SkNEW_APPEND_TO_TARRAY(&drawState->fCoverageStages, michael@0: GrEffectStage, (fStages[i + fColorStageCnt])); michael@0: } michael@0: } michael@0: michael@0: bool isEqual(const GrDrawState& state) const { michael@0: int numCoverageStages = fStages.count() - fColorStageCnt; michael@0: if (fRenderTarget != state.fRenderTarget.get() || michael@0: fColorStageCnt != state.fColorStages.count() || michael@0: numCoverageStages != state.fCoverageStages.count() || michael@0: fCommon != state.fCommon) { michael@0: return false; michael@0: } michael@0: bool explicitLocalCoords = state.hasLocalCoordAttribute(); michael@0: for (int i = 0; i < fColorStageCnt; ++i) { michael@0: if (!fStages[i].isEqual(state.fColorStages[i], explicitLocalCoords)) { michael@0: return false; michael@0: } michael@0: } michael@0: for (int i = 0; i < numCoverageStages; ++i) { michael@0: int s = fColorStageCnt + i; michael@0: if (!fStages[s].isEqual(state.fCoverageStages[i], explicitLocalCoords)) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: private: michael@0: typedef SkAutoSTArray<8, GrEffectStage::DeferredStage> DeferredStageArray; michael@0: michael@0: GrRenderTarget* fRenderTarget; michael@0: CommonState fCommon; michael@0: int fColorStageCnt; michael@0: DeferredStageArray fStages; michael@0: michael@0: SkDEBUGCODE(bool fInitialized;) michael@0: }; michael@0: michael@0: private: michael@0: michael@0: SkAutoTUnref fRenderTarget; michael@0: CommonState fCommon; michael@0: michael@0: typedef SkSTArray<4, GrEffectStage> EffectStageArray; michael@0: EffectStageArray fColorStages; michael@0: EffectStageArray fCoverageStages; michael@0: michael@0: // Some of the auto restore objects assume that no effects are removed during their lifetime. michael@0: // This is used to assert that this condition holds. michael@0: SkDEBUGCODE(int fBlockEffectRemovalCnt;) michael@0: michael@0: /** michael@0: * Sets vertex attributes for next draw. michael@0: * michael@0: * @param attribs the array of vertex attributes to set. michael@0: * @param count the number of attributes being set, limited to kMaxVertexAttribCnt. michael@0: */ michael@0: void setVertexAttribs(const GrVertexAttrib attribs[], int count); michael@0: michael@0: typedef SkRefCnt INHERITED; michael@0: }; michael@0: michael@0: GR_MAKE_BITFIELD_OPS(GrDrawState::BlendOptFlags); michael@0: michael@0: #endif