Compile time vertex layout masks
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 15 Dec 2011 16:58:19 +0000 (16:58 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 15 Dec 2011 16:58:19 +0000 (16:58 +0000)
Review URL: http://codereview.appspot.com/5493049/

git-svn-id: http://skia.googlecode.com/svn/trunk@2878 2bbb7eff-a529-9590-31e7-b0007b416f81

src/gpu/GrDrawTarget.cpp

index 4211da9..6f05912 100644 (file)
 
 namespace {
 
-// recursive helper for creating mask with all the tex coord bits set for
-// one stage
-template <int N>
-int stage_mask_recur(int stage) {
-    return GrDrawTarget::StageTexCoordVertexLayoutBit(stage, N) |
-           stage_mask_recur<N+1>(stage);
-}
-template<> 
-int stage_mask_recur<GrDrawState::kNumStages>(int) { return 0; }
-
-// mask of all tex coord indices for one stage
-int stage_tex_coord_mask(int stage) {
-    return stage_mask_recur<0>(stage);
-}
-
-// mask of all bits relevant to one stage
-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>
-int tex_coord_mask_recur(int texCoordIdx) {
-    return GrDrawTarget::StageTexCoordVertexLayoutBit(N, texCoordIdx) |
-           tex_coord_mask_recur<N+1>(texCoordIdx);
+/**
+ * This function generates some masks that we like to have known at compile
+ * time. When the number of stages or tex coords is bumped or the way bits
+ * are defined in GrDrawTarget.h changes this funcion should be rerun to
+ * generate the new masks. (We attempted to force the compiler to generate the
+ * masks using recursive templates but always wound up with static initializers
+ * under gcc, even if they were just a series of immediate->memory moves.)
+ * 
+ */
+void gen_mask_arrays(GrVertexLayout* stageTexCoordMasks,
+                     GrVertexLayout* stageMasks,
+                     GrVertexLayout* texCoordMasks) {
+    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+        stageTexCoordMasks[s] = 0;
+        for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+            stageTexCoordMasks[s] |= GrDrawTarget::StageTexCoordVertexLayoutBit(s, t);
+        }
+        stageMasks[s] = stageTexCoordMasks[s] | GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
+    }
+    for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+        texCoordMasks[t] = 0;
+        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+            texCoordMasks[t] |= GrDrawTarget::StageTexCoordVertexLayoutBit(s, t);
+        }
+    }
 }
-template<> 
-int tex_coord_mask_recur<GrDrawState::kMaxTexCoords>(int) { return 0; }
 
-// mask of all bits relevant to one texture coordinate index
-int tex_coord_idx_mask(int texCoordIdx) {
-    return tex_coord_mask_recur<0>(texCoordIdx);
-}
+/** 
+ * Run this function to generate the code that declares the global masks.
+ */
+void gen_globals() {
+    GrVertexLayout stageTexCoordMasks[GrDrawState::kNumStages];
+    GrVertexLayout stageMasks[GrDrawState::kNumStages];
+    GrVertexLayout texCoordMasks[GrDrawState::kMaxTexCoords];
+    gen_mask_arrays(stageTexCoordMasks, stageMasks, texCoordMasks);
+    
+    GrPrintf("const GrVertexLayout gStageTexCoordMasks[] = {\n");
+    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+        GrPrintf("    0x%x,\n", stageTexCoordMasks[s]);
+    }
+    GrPrintf("};\n");
+    GrPrintf("GR_STATIC_ASSERT(GrDrawState::kNumStages == GR_ARRAY_COUNT(gStageTexCoordMasks));\n\n");
+    GrPrintf("const GrVertexLayout gStageMasks[] = {\n");
+    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+        GrPrintf("    0x%x,\n", stageMasks[s]);
+    }
+    GrPrintf("};\n");
+    GrPrintf("GR_STATIC_ASSERT(GrDrawState::kNumStages == GR_ARRAY_COUNT(gStageMasks));\n\n");
+    GrPrintf("const GrVertexLayout gTexCoordMasks[] = {\n");
+    for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+        GrPrintf("    0x%x,\n", texCoordMasks[t]);
+    }
+    GrPrintf("};\n");
+    GrPrintf("GR_STATIC_ASSERT(GrDrawState::kMaxTexCoords == GR_ARRAY_COUNT(gTexCoordMasks));\n");
+}
+
+/* These values were generated by the above function */
+const GrVertexLayout gStageTexCoordMasks[] = {
+    0x49,
+    0x92,
+    0x124
+};
+
+GR_STATIC_ASSERT(GrDrawState::kNumStages == GR_ARRAY_COUNT(gStageTexCoordMasks));
+const GrVertexLayout gStageMasks[] = {
+    0x249,
+    0x492,
+    0x924
+};
+
+GR_STATIC_ASSERT(GrDrawState::kNumStages == GR_ARRAY_COUNT(gStageMasks));
+const GrVertexLayout gTexCoordMasks[] = {
+    0x7,
+    0x38,
+    0x1c0,
+};
+GR_STATIC_ASSERT(GrDrawState::kMaxTexCoords == GR_ARRAY_COUNT(gTexCoordMasks));
 
 bool check_layout(GrVertexLayout layout) {
     // can only have 1 or 0 bits set for each stage.
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-        int stageBits = layout & stage_mask(s);
+        int stageBits = layout & gStageMasks[s];
         if (stageBits && !GrIsPow2(stageBits)) {
             return false;
         }
@@ -68,7 +110,7 @@ int num_tex_coords(GrVertexLayout layout) {
     int cnt = 0;
     // figure out how many tex coordinates are present
     for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
-        if (tex_coord_idx_mask(t) & layout) {
+        if (gTexCoordMasks[t] & layout) {
             ++cnt;
         }
     }
@@ -127,7 +169,7 @@ int GrDrawTarget::VertexStageCoordOffset(int stage, GrVertexLayout vertexLayout)
         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) {
+            if (gTexCoordMasks[t] & vertexLayout) {
                 offset += vecSize;
             }
         }
@@ -137,7 +179,7 @@ int GrDrawTarget::VertexStageCoordOffset(int stage, GrVertexLayout vertexLayout)
     return -1;
 }
 
-int  GrDrawTarget::VertexColorOffset(GrVertexLayout vertexLayout) {
+int GrDrawTarget::VertexColorOffset(GrVertexLayout vertexLayout) {
     GrAssert(check_layout(vertexLayout));
 
     if (vertexLayout & kColor_VertexLayoutBit) {
@@ -149,7 +191,7 @@ int  GrDrawTarget::VertexColorOffset(GrVertexLayout vertexLayout) {
     return -1;
 }
 
-int  GrDrawTarget::VertexCoverageOffset(GrVertexLayout vertexLayout) {
+int GrDrawTarget::VertexCoverageOffset(GrVertexLayout vertexLayout) {
     GrAssert(check_layout(vertexLayout));
 
     if (vertexLayout & kCoverage_VertexLayoutBit) {
@@ -166,7 +208,7 @@ int  GrDrawTarget::VertexCoverageOffset(GrVertexLayout vertexLayout) {
     return -1;
 }
 
-int  GrDrawTarget::VertexEdgeOffset(GrVertexLayout vertexLayout) {
+int GrDrawTarget::VertexEdgeOffset(GrVertexLayout vertexLayout) {
     GrAssert(check_layout(vertexLayout));
 
     // edge pts are after the pos, tex coords, and color
@@ -200,7 +242,7 @@ int GrDrawTarget::VertexSizeAndOffsetsByIdx(
     int size = vecSize; // position
 
     for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
-        if (tex_coord_idx_mask(t) & vertexLayout) {
+        if (gTexCoordMasks[t] & vertexLayout) {
             if (NULL != texCoordOffsetsByIdx) {
                 texCoordOffsetsByIdx[t] = size;
             }
@@ -280,21 +322,21 @@ int GrDrawTarget::VertexSizeAndOffsetsByStage(
 bool GrDrawTarget::VertexUsesStage(int stage, GrVertexLayout vertexLayout) {
     GrAssert(stage < GrDrawState::kNumStages);
     GrAssert(check_layout(vertexLayout));
-    return !!(stage_mask(stage) & vertexLayout);
+    return !!(gStageMasks[stage] & vertexLayout);
 }
 
 bool GrDrawTarget::VertexUsesTexCoordIdx(int coordIndex,
                                          GrVertexLayout vertexLayout) {
     GrAssert(coordIndex < GrDrawState::kMaxTexCoords);
     GrAssert(check_layout(vertexLayout));
-    return !!(tex_coord_idx_mask(coordIndex) & vertexLayout);
+    return !!(gTexCoordMasks[coordIndex] & vertexLayout);
 }
 
 int GrDrawTarget::VertexTexCoordsForStage(int stage,
                                           GrVertexLayout vertexLayout) {
     GrAssert(stage < GrDrawState::kNumStages);
     GrAssert(check_layout(vertexLayout));
-    int bit = vertexLayout & stage_tex_coord_mask(stage);
+    int bit = vertexLayout & gStageTexCoordMasks[stage];
     if (bit) {
         // figure out which set of texture coordates is used
         // bits are ordered T0S0, T0S1, T0S2, ..., T1S0, T1S1, ...
@@ -308,6 +350,19 @@ int GrDrawTarget::VertexTexCoordsForStage(int stage,
 ////////////////////////////////////////////////////////////////////////////////
 
 void GrDrawTarget::VertexLayoutUnitTest() {
+    // Ensure that our globals mask arrays are correct
+    GrVertexLayout stageTexCoordMasks[GrDrawState::kNumStages];
+    GrVertexLayout stageMasks[GrDrawState::kNumStages];
+    GrVertexLayout texCoordMasks[GrDrawState::kMaxTexCoords];
+    gen_mask_arrays(stageTexCoordMasks, stageMasks, texCoordMasks);
+    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+        GrAssert(stageTexCoordMasks[s] == gStageTexCoordMasks[s]);
+        GrAssert(stageMasks[s] == gStageMasks[s]);
+    }
+    for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+        GrAssert(texCoordMasks[t] == gTexCoordMasks[t]);
+    }
+
     // not necessarily exhaustive
     static bool run;
     if (!run) {
@@ -322,9 +377,9 @@ void GrDrawTarget::VertexLayoutUnitTest() {
             }
             GrAssert(1 == GrDrawState::kMaxTexCoords ||
                      !check_layout(stageMask));
-            GrAssert(stage_tex_coord_mask(s) == stageMask);
+            GrAssert(gStageTexCoordMasks[s] == stageMask);
             stageMask |= StagePosAsTexCoordVertexLayoutBit(s);
-            GrAssert(stage_mask(s) == stageMask);
+            GrAssert(gStageMasks[s] == stageMask);
             GrAssert(!check_layout(stageMask));
         }
         for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
@@ -386,7 +441,7 @@ void GrDrawTarget::VertexLayoutUnitTest() {
                 GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexCoverageOffset(withCoverageAndColor));
                 GrAssert(2*sizeof(GrPoint) + 2 * sizeof(GrColor) == VertexSize(withCoverageAndColor));
             }
-            GrAssert(tex_coord_idx_mask(t) == tcMask);
+            GrAssert(gTexCoordMasks[t] == tcMask);
             GrAssert(check_layout(tcMask));
 
             int stageOffsets[GrDrawState::kNumStages];