Towards issue #106

Adds notion of texture multiple stages but currently just uses 1.


git-svn-id: http://skia.googlecode.com/svn/trunk@694 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp
index 82f94a3..7ea9ff2 100644
--- a/gpu/src/GrDrawTarget.cpp
+++ b/gpu/src/GrDrawTarget.cpp
@@ -18,93 +18,265 @@
 #include "GrDrawTarget.h"
 #include "GrGpuVertex.h"
 
-#define VERTEX_LAYOUT_ASSERTS \
-    GrAssert(!(vertexLayout & kTextFormat_VertexLayoutBit) ||           \
-             vertexLayout == kTextFormat_VertexLayoutBit);              \
-    GrAssert(!(vertexLayout & kSeparateTexCoord_VertexLayoutBit) ||     \
-             !(vertexLayout & kPositionAsTexCoord_VertexLayoutBit));
+// recursive helper for creating mask with all the tex coord bits set for
+// one stage
+template <int N>
+static int stage_mask_recur(int stage) {
+    return GrDrawTarget::StageTexCoordVertexLayoutBit(stage, N) | 
+           stage_mask_recur<N+1>(stage);
+}
+template<>
+static int stage_mask_recur<GrDrawTarget::kNumStages>(int) { return 0; }
 
-size_t GrDrawTarget::VertexSize(GrVertexLayout vertexLayout) {
-    VERTEX_LAYOUT_ASSERTS
-    if ((vertexLayout & kTextFormat_VertexLayoutBit)) {
-        return 2 * sizeof(GrGpuTextVertex);
-    } else {
-        size_t size = sizeof(GrPoint);
-        if (vertexLayout & kSeparateTexCoord_VertexLayoutBit) {
-            size += sizeof(GrPoint);
-        }
-        if (vertexLayout & kColor_VertexLayoutBit) {
-            size += sizeof(GrColor);
-        }
-        return size;
-    }
+// mask of all tex coord indices for one stage
+static int stage_tex_coord_mask(int stage) {
+    return stage_mask_recur<0>(stage);
 }
 
-int GrDrawTarget::VertexTexCoordOffset(GrVertexLayout vertexLayout) {
-    VERTEX_LAYOUT_ASSERTS
-    if ((vertexLayout & kTextFormat_VertexLayoutBit)) {
-        return sizeof(GrGpuTextVertex);
-    } else if (vertexLayout & kSeparateTexCoord_VertexLayoutBit) {
-        return sizeof(GrPoint);
-    } else if (vertexLayout & kPositionAsTexCoord_VertexLayoutBit) {
+// mask of all bits relevant to one stage
+static int stage_mask(int stage) {
+    return stage_tex_coord_mask(stage) | 
+           GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(stage);
+}
+
+// recursive helper for creating mask of with all bits set relevant to one
+// texture coordinate index
+template <int N>
+static int tex_coord_mask_recur(int texCoordIdx) {
+    return GrDrawTarget::StageTexCoordVertexLayoutBit(N, texCoordIdx) | 
+           tex_coord_mask_recur<N+1>(texCoordIdx);
+}
+template<>
+static int tex_coord_mask_recur<GrDrawTarget::kMaxTexCoords>(int) { return 0; }
+
+// mask of all bits relevant to one texture coordinate index
+static int tex_coord_idx_mask(int texCoordIdx) {
+    return tex_coord_mask_recur<0>(texCoordIdx);
+}
+
+bool check_layout(GrVertexLayout layout) {
+    // can only have 1 or 0 bits set for each stage.
+    for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
+        int stageBits = layout & stage_mask(s);
+        if (stageBits && !GrIsPow2(stageBits)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+size_t GrDrawTarget::VertexSize(GrVertexLayout vertexLayout) {
+    GrAssert(check_layout(vertexLayout));
+    
+    size_t vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ? 
+                        sizeof(GrGpuTextVertex) :
+                        sizeof(GrPoint);
+
+    size_t size = vecSize; // position
+    for (int t = 0; t < kMaxTexCoords; ++t) {
+        if (tex_coord_idx_mask(t) & vertexLayout) {
+            size += vecSize;
+        }
+    }
+    if (vertexLayout & kColor_VertexLayoutBit) {
+        size += sizeof(GrColor);
+    }
+    return size;
+}
+
+int GrDrawTarget::VertexStageCoordOffset(int stage, GrVertexLayout vertexLayout) {
+    GrAssert(check_layout(vertexLayout));
+    if (StagePosAsTexCoordVertexLayoutBit(stage) & vertexLayout) {
         return 0;
     }
+    int tcIdx = VertexTexCoordsForStage(stage, vertexLayout);
+    if (tcIdx >= 0) {
+        
+        int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ? 
+                                    sizeof(GrGpuTextVertex) :
+                                    sizeof(GrPoint);
+        int offset = vecSize; // position
+        // figure out how many tex coordinates are present and precede this one.
+        for (int t = 0; t < tcIdx; ++t) {
+            if (tex_coord_idx_mask(t) & vertexLayout) {
+                offset += vecSize;
+            }
+        }
+        return offset;
+    }
+
     return -1;
 }
 
 int  GrDrawTarget::VertexColorOffset(GrVertexLayout vertexLayout) {
-    VERTEX_LAYOUT_ASSERTS
+    GrAssert(check_layout(vertexLayout));
+    
     if (vertexLayout & kColor_VertexLayoutBit) {
-        if (vertexLayout & kSeparateTexCoord_VertexLayoutBit) {
-            return 2 * sizeof(GrPoint);
-        } else {
-            return sizeof(GrPoint);
+        int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ? 
+                                    sizeof(GrGpuTextVertex) :
+                                    sizeof(GrPoint);
+        int offset = vecSize; // position
+        // figure out how many tex coordinates are present and precede this one.
+        for (int t = 0; t < kMaxTexCoords; ++t) {
+            if (tex_coord_idx_mask(t) & vertexLayout) {
+                offset += vecSize;
+            }
         }
+        return offset;
     }
     return -1;
 }
 
-int GrDrawTarget::VertexSizeAndOffsets(GrVertexLayout vertexLayout,
-                                       int* texCoordOffset,
-                                       int* colorOffset) {
-    VERTEX_LAYOUT_ASSERTS
-
-    GrAssert(NULL != texCoordOffset);
+int GrDrawTarget::VertexSizeAndOffsetsByIdx(GrVertexLayout vertexLayout,
+                                             int texCoordOffsetsByIdx[kMaxTexCoords],
+                                             int* colorOffset) {
+    GrAssert(check_layout(vertexLayout));
+    
+    GrAssert(NULL != texCoordOffsetsByIdx);
     GrAssert(NULL != colorOffset);
 
-    if ((vertexLayout & kTextFormat_VertexLayoutBit)) {
-        *texCoordOffset = sizeof(GrGpuTextVertex);
-        *colorOffset = 0;
-        return 2 * sizeof(GrGpuTextVertex);
-    } else {
-        size_t size = sizeof(GrPoint);
-        if (vertexLayout & kSeparateTexCoord_VertexLayoutBit) {
-            *texCoordOffset = sizeof(GrPoint);
-            size += sizeof(GrPoint);
-        } else if (vertexLayout & kPositionAsTexCoord_VertexLayoutBit) {
-            *texCoordOffset = 0;
+    int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ? 
+                                                    sizeof(GrGpuTextVertex) :
+                                                    sizeof(GrPoint);
+    int size = vecSize; // position
+    
+    for (int t = 0; t < kMaxTexCoords; ++t) {
+        if (tex_coord_idx_mask(t) & vertexLayout) {
+            texCoordOffsetsByIdx[t] = size;
+            size += vecSize;
         } else {
-            *texCoordOffset = -1;
+            texCoordOffsetsByIdx[t] = -1;
         }
-        if (vertexLayout & kColor_VertexLayoutBit) {
-            *colorOffset = size;
-            size += sizeof(GrColor);
-        } else {
-            *colorOffset = -1;
-        }
-        return size;
     }
+    if (kColor_VertexLayoutBit & vertexLayout) {
+        *colorOffset = size;
+        size += sizeof(GrColor);
+    } else {
+        *colorOffset = -1;
+    }
+    return size;
 }
 
-bool GrDrawTarget::VertexHasTexCoords(GrVertexLayout vertexLayout) {
-    return !!(vertexLayout & (kSeparateTexCoord_VertexLayoutBit   |
-                              kPositionAsTexCoord_VertexLayoutBit |
-                              kTextFormat_VertexLayoutBit));
+int GrDrawTarget::VertexSizeAndOffsetsByStage(GrVertexLayout vertexLayout,
+                                              int texCoordOffsetsByStage[kNumStages],
+                                              int* colorOffset) {
+    GrAssert(check_layout(vertexLayout));
+
+    GrAssert(NULL != texCoordOffsetsByStage);
+    GrAssert(NULL != colorOffset);
+    
+    int texCoordOffsetsByIdx[kMaxTexCoords];
+    int size = VertexSizeAndOffsetsByIdx(vertexLayout, 
+                                         texCoordOffsetsByIdx, 
+                                         colorOffset);
+    for (int s = 0; s < kNumStages; ++s) {
+        int tcIdx;
+        if (StagePosAsTexCoordVertexLayoutBit(s) & vertexLayout) {
+            texCoordOffsetsByStage[s] = 0;
+        } else if ((tcIdx = VertexTexCoordsForStage(s, vertexLayout)) >= 0) {
+            texCoordOffsetsByStage[s] = texCoordOffsetsByIdx[tcIdx];
+        } else {
+            texCoordOffsetsByStage[s] = -1;
+        }
+    }
+    return size;    
+}
+
+bool GrDrawTarget::VertexUsesStage(int stage, GrVertexLayout vertexLayout) {
+    GrAssert(stage < kNumStages);
+    GrAssert(check_layout(vertexLayout));
+    return !!(stage_mask(stage) & vertexLayout);
+}
+
+bool GrDrawTarget::VertexUsesTexCoordIdx(int coordIndex, 
+                                         GrVertexLayout vertexLayout) {
+    GrAssert(coordIndex < kMaxTexCoords);     
+    GrAssert(check_layout(vertexLayout));
+    return !!(tex_coord_idx_mask(coordIndex) & vertexLayout);
+}
+
+int GrDrawTarget::VertexTexCoordsForStage(int stage, GrVertexLayout vertexLayout) {
+    GrAssert(stage < kNumStages);
+    GrAssert(check_layout(vertexLayout));
+    int bit = vertexLayout & stage_tex_coord_mask(stage);
+    if (bit) {
+        // figure out which set of texture coordates is used
+        // bits are ordered T0S0, T0S1, T0S2, ..., T1S0, T1S1, ...
+        // and start at bit 0.
+        GR_STATIC_ASSERT(sizeof(GrVertexLayout) <= sizeof(uint32_t));
+        return (32 - Gr_clz(bit) - 1) / kNumStages;
+    }
+    return -1;
+}
+
+void GrDrawTarget::VertexLayoutUnitTest() {
+    // not necessarily exhaustive
+    static bool run;
+    if (!run) {
+        run = true;
+        for (int s = 0; s < kNumStages; ++s) {
+
+            GrAssert(!VertexUsesStage(s, 0));
+            GrAssert(-1 == VertexStageCoordOffset(s, 0));
+            GrVertexLayout stageMask = 0;
+            for (int t = 0; t < kMaxTexCoords; ++t) {
+                stageMask |= StageTexCoordVertexLayoutBit(s,t);
+            }
+            GrAssert(1 == kMaxTexCoords || !check_layout(stageMask));            
+            GrAssert(stage_tex_coord_mask(s) == stageMask);
+            stageMask |= StagePosAsTexCoordVertexLayoutBit(s);
+            GrAssert(stage_mask(s) == stageMask);
+            GrAssert(!check_layout(stageMask));
+        }
+        for (int t = 0; t < kMaxTexCoords; ++t) {
+            GrVertexLayout tcMask = 0;
+            GrAssert(!VertexUsesTexCoordIdx(t, 0));
+            for (int s = 0; s < kNumStages; ++s) {
+                tcMask |= StageTexCoordVertexLayoutBit(s,t);
+                GrAssert(VertexUsesStage(s, tcMask));
+                GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask));
+                GrAssert(VertexUsesTexCoordIdx(t, tcMask));
+                GrAssert(2*sizeof(GrPoint) == VertexSize(tcMask));
+                GrAssert(t == VertexTexCoordsForStage(s, tcMask));
+                for (int s2 = s + 1; s2 < kNumStages; ++s2) {
+                    GrAssert(-1 == VertexStageCoordOffset(s2, tcMask));
+                    GrAssert(!VertexUsesStage(s2, tcMask));
+                    GrAssert(-1 == VertexTexCoordsForStage(s2, tcMask));
+                    
+                    GrVertexLayout posAsTex = tcMask | StagePosAsTexCoordVertexLayoutBit(s2);
+                    GrAssert(0 == VertexStageCoordOffset(s2, posAsTex));
+                    GrAssert(VertexUsesStage(s2, posAsTex));
+                    GrAssert(2*sizeof(GrPoint) == VertexSize(posAsTex));
+                    GrAssert(-1 == VertexTexCoordsForStage(s2, posAsTex));
+                }
+                GrVertexLayout withColor = tcMask | kColor_VertexLayoutBit;
+                GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColor));
+                GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColor));
+            }
+            GrAssert(tex_coord_idx_mask(t) == tcMask);
+            GrAssert(check_layout(tcMask));
+            
+            int stageOffsets[kNumStages];
+            int colorOffset;
+            int size;
+            size = VertexSizeAndOffsetsByStage(tcMask, stageOffsets, &colorOffset);
+            GrAssert(2*sizeof(GrPoint) == size);
+            GrAssert(-1 == colorOffset);
+            for (int s = 0; s < kNumStages; ++s) {
+                GrAssert(VertexUsesStage(s, tcMask));
+                GrAssert(sizeof(GrPoint) == stageOffsets[s]);
+                GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask));
+            }
+        }
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 GrDrawTarget::GrDrawTarget() {
+#if GR_DEBUG
+    VertexLayoutUnitTest();
+#endif
     fReservedGeometry.fLocked = false;
 #if GR_DEBUG
     fReservedGeometry.fVertexCount  = ~0;
@@ -123,12 +295,14 @@
     return fClip;
 }
 
-void GrDrawTarget::setTexture(GrTexture* tex) {
-    fCurrDrawState.fTexture = tex;
+void GrDrawTarget::setTexture(int stage, GrTexture* tex) {
+    GrAssert(stage >= 0 && stage < kNumStages);
+    fCurrDrawState.fTextures[stage] = tex;
 }
 
-GrTexture* GrDrawTarget::currentTexture() const {
-    return fCurrDrawState.fTexture;
+GrTexture* GrDrawTarget::currentTexture(int stage) const {
+    GrAssert(stage >= 0 && stage < kNumStages);
+    return fCurrDrawState.fTextures[stage];
 }
 
 void GrDrawTarget::setRenderTarget(GrRenderTarget* target) {
@@ -139,21 +313,25 @@
     return fCurrDrawState.fRenderTarget;
 }
 
-void GrDrawTarget::concatViewMatrix(const GrMatrix& matrix) {
-    GrMatrix mv;
-    mv.setConcat(fCurrDrawState.fMatrixModeCache[kModelView_MatrixMode], matrix);
-    this->loadMatrix(mv, kModelView_MatrixMode);
+void GrDrawTarget::setViewMatrix(const GrMatrix& m) {
+    fCurrDrawState.fViewMatrix = m;
 }
 
+void GrDrawTarget::concatViewMatrix(const GrMatrix& matrix) {
+    fCurrDrawState.fViewMatrix.preConcat(matrix);
+}
+
+// Can't this just return a const&
 void GrDrawTarget::getViewMatrix(GrMatrix* matrix) const {
-    *matrix = fCurrDrawState.fMatrixModeCache[kModelView_MatrixMode];
+    *matrix = fCurrDrawState.fViewMatrix;
 }
 
 bool GrDrawTarget::getViewInverse(GrMatrix* matrix) const {
-    // Can we cache this somewhere?
+    // Mike:  Can we cache this somewhere? 
+    // Brian: Sure, do we use it often?
 
     GrMatrix inverse;
-    if (fCurrDrawState.fMatrixModeCache[kModelView_MatrixMode].invert(&inverse)) {
+    if (fCurrDrawState.fViewMatrix.invert(&inverse)) {
         if (matrix) {
             *matrix = inverse;
         }
@@ -162,8 +340,14 @@
     return false;
 }
 
-void GrDrawTarget::setSamplerState(const GrSamplerState& state) {
-    fCurrDrawState.fSamplerState = state;
+void GrDrawTarget::setSamplerState(int stage, const GrSamplerState& state) {
+    GrAssert(stage >= 0 && stage < kNumStages);
+    fCurrDrawState.fSamplerStates[stage] = state;
+}
+
+void GrDrawTarget::setTextureMatrix(int stage, const GrMatrix& m) {
+    GrAssert(stage >= 0 && stage < kNumStages);
+    fCurrDrawState.fTextureMatrices[stage] = m;
 }
 
 void GrDrawTarget::setStencilPass(StencilPass pass) {
@@ -182,10 +366,6 @@
     fCurrDrawState.fFlagBits &= ~(bits);
 }
 
-void GrDrawTarget::loadMatrix(const GrMatrix& matrix, MatrixMode m) {
-    fCurrDrawState.fMatrixModeCache[m] = matrix;
-}
-
 void GrDrawTarget::setPointSize(float size) {
     fCurrDrawState.fPointSize = size;
 }