1 2 /* 3 * Copyright 2010 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 10 11 #ifndef GrProcessorStage_DEFINED 12 #define GrProcessorStage_DEFINED 13 14 #include "GrBackendProcessorFactory.h" 15 #include "GrCoordTransform.h" 16 #include "GrProcessor.h" 17 #include "GrGeometryProcessor.h" 18 #include "GrProgramElementRef.h" 19 #include "SkMatrix.h" 20 #include "SkShader.h" 21 22 // TODO: Make two variations on this class: One for GrDrawState that only owns regular refs 23 // and supports compatibility checks and changing local coords. The second is for GrOptDrawState, 24 // is immutable, and only owns pending execution refs. This requries removing the common base 25 // class from GrDrawState and GrOptDrawState called GrRODrawState and converting to GrOptDrawState 26 // when draws are enqueued in the GrInOrderDrawBuffer. 27 class GrProcessorStage { 28 public: 29 explicit GrProcessorStage(const GrProcessor* proc) 30 : fProc(SkRef(proc)) { 31 fCoordChangeMatrixSet = false; 32 } 33 34 GrProcessorStage(const GrProcessorStage& other) { 35 fCoordChangeMatrixSet = other.fCoordChangeMatrixSet; 36 if (other.fCoordChangeMatrixSet) { 37 fCoordChangeMatrix = other.fCoordChangeMatrix; 38 } 39 fProc.initAndRef(other.fProc); 40 } 41 42 static bool AreCompatible(const GrProcessorStage& a, const GrProcessorStage& b, 43 bool usingExplicitLocalCoords) { 44 SkASSERT(a.fProc.get()); 45 SkASSERT(b.fProc.get()); 46 47 if (!a.getProcessor()->isEqual(*b.getProcessor())) { 48 return false; 49 } 50 51 // We always track the coord change matrix, but it has no effect when explicit local coords 52 // are used. 53 if (usingExplicitLocalCoords) { 54 return true; 55 } 56 57 if (a.fCoordChangeMatrixSet != b.fCoordChangeMatrixSet) { 58 return false; 59 } 60 61 if (!a.fCoordChangeMatrixSet) { 62 return true; 63 } 64 65 return a.fCoordChangeMatrix == b.fCoordChangeMatrix; 66 } 67 68 /** 69 * This is called when the coordinate system in which the geometry is specified will change. 70 * 71 * @param matrix The transformation from the old coord system in which geometry is specified 72 * to the new one from which it will actually be drawn. 73 */ 74 void localCoordChange(const SkMatrix& matrix) { 75 if (fCoordChangeMatrixSet) { 76 fCoordChangeMatrix.preConcat(matrix); 77 } else { 78 fCoordChangeMatrixSet = true; 79 fCoordChangeMatrix = matrix; 80 } 81 } 82 83 class SavedCoordChange { 84 public: 85 SkDEBUGCODE(SavedCoordChange() : fEffectUniqueID(SK_InvalidUniqueID) {}) 86 private: 87 bool fCoordChangeMatrixSet; 88 SkMatrix fCoordChangeMatrix; 89 SkDEBUGCODE(mutable uint32_t fEffectUniqueID;) 90 91 friend class GrProcessorStage; 92 }; 93 94 /** 95 * This gets the current coordinate system change. It is the accumulation of 96 * localCoordChange calls since the effect was installed. It is used when then caller 97 * wants to temporarily change the source geometry coord system, draw something, and then 98 * restore the previous coord system (e.g. temporarily draw in device coords). 99 */ 100 void saveCoordChange(SavedCoordChange* savedCoordChange) const { 101 savedCoordChange->fCoordChangeMatrixSet = fCoordChangeMatrixSet; 102 if (fCoordChangeMatrixSet) { 103 savedCoordChange->fCoordChangeMatrix = fCoordChangeMatrix; 104 } 105 SkASSERT(SK_InvalidUniqueID == savedCoordChange->fEffectUniqueID); 106 SkDEBUGCODE(savedCoordChange->fEffectUniqueID = fProc->getUniqueID();) 107 } 108 109 /** 110 * This balances the saveCoordChange call. 111 */ 112 void restoreCoordChange(const SavedCoordChange& savedCoordChange) { 113 fCoordChangeMatrixSet = savedCoordChange.fCoordChangeMatrixSet; 114 if (fCoordChangeMatrixSet) { 115 fCoordChangeMatrix = savedCoordChange.fCoordChangeMatrix; 116 } 117 SkASSERT(savedCoordChange.fEffectUniqueID == fProc->getUniqueID()); 118 SkDEBUGCODE(savedCoordChange.fEffectUniqueID = SK_InvalidUniqueID); 119 } 120 121 /** 122 * Gets the matrix representing all changes of coordinate system since the GrProcessor was 123 * installed in the stage. 124 */ 125 const SkMatrix& getCoordChangeMatrix() const { 126 if (fCoordChangeMatrixSet) { 127 return fCoordChangeMatrix; 128 } else { 129 return SkMatrix::I(); 130 } 131 } 132 133 bool isPerspectiveCoordTransform(int matrixIndex, bool useExplicitLocalCoords) const { 134 const GrCoordTransform& coordTransform = this->getProcessor()->coordTransform(matrixIndex); 135 SkMatrix::TypeMask type0 = coordTransform.getMatrix().getType(); 136 SkMatrix::TypeMask type1 = SkMatrix::kIdentity_Mask; 137 if (kLocal_GrCoordSet == coordTransform.sourceCoords()) { 138 type1 = useExplicitLocalCoords ? 139 SkMatrix::kIdentity_Mask : this->getCoordChangeMatrix().getType(); 140 } 141 142 int combinedTypes = type0 | type1; 143 if (SkMatrix::kPerspective_Mask & combinedTypes) { 144 return true; 145 } else { 146 return false; 147 } 148 } 149 150 const GrProcessor* getProcessor() const { return fProc.get(); } 151 152 void convertToPendingExec() { fProc.convertToPendingExec(); } 153 154 private: 155 bool fCoordChangeMatrixSet; 156 SkMatrix fCoordChangeMatrix; 157 GrProgramElementRef<const GrProcessor> fProc; 158 }; 159 160 class GrFragmentStage : public GrProcessorStage { 161 public: 162 GrFragmentStage(const GrFragmentProcessor* fp) : GrProcessorStage(fp) {} 163 164 const GrFragmentProcessor* getFragmentProcessor() const { 165 return static_cast<const GrFragmentProcessor*>(this->getProcessor()); 166 } 167 }; 168 169 class GrGeometryStage : public GrProcessorStage { 170 public: 171 GrGeometryStage(const GrGeometryProcessor* gp) : GrProcessorStage(gp) {} 172 173 const GrGeometryProcessor* getGeometryProcessor() const { 174 return static_cast<const GrGeometryProcessor*>(this->getProcessor()); 175 } 176 }; 177 178 #endif 179