Do writepixels alpha-premul using gpu

Review URL: http://codereview.appspot.com/5373064/



git-svn-id: http://skia.googlecode.com/svn/trunk@2668 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrGpuGLShaders.cpp b/src/gpu/GrGpuGLShaders.cpp
index 67b1c37..76b02ac 100644
--- a/src/gpu/GrGpuGLShaders.cpp
+++ b/src/gpu/GrGpuGLShaders.cpp
@@ -168,9 +168,19 @@
     }
 }
 
-template <typename T>
-T random_val(GrRandom* r, T count) {
-    return (T)(int)(r->nextF() * count);
+// GrRandoms nextU() values have patterns in the low bits
+// So using nextU() % array_count might never take some values.
+int random_int(GrRandom* r, int count) {
+    return (int)(r->nextF() * count);
+}
+
+// min is inclusive, max is exclusive
+int random_int(GrRandom* r, int min, int max) {
+    return (int)(r->nextF() * (max-min)) + min;
+}
+
+bool random_bool(GrRandom* r) {
+    return r->nextF() > .5f;
 }
 
 }
@@ -184,13 +194,18 @@
         StageDesc::kNoPerspective_OptFlagBit,
         StageDesc::kIdentity_CoordMapping
     };
+    static const int IN_CONFIG_FLAGS[] = {
+        StageDesc::kNone_InConfigFlag,
+        StageDesc::kSwapRAndB_InConfigFlag,
+        StageDesc::kSwapRAndB_InConfigFlag | StageDesc::kMulRGBByAlpha_InConfigFlag,
+        StageDesc::kMulRGBByAlpha_InConfigFlag,
+        StageDesc::kSmearAlpha_InConfigFlag,
+    };
     GrGLProgram program;
     ProgramDesc& pdesc = program.fProgramDesc;
 
     static const int NUM_TESTS = 512;
 
-    // GrRandoms nextU() values have patterns in the low bits
-    // So using nextU() % array_count might never take some values.
     GrRandom random;
     for (int t = 0; t < NUM_TESTS; ++t) {
 
@@ -204,33 +219,29 @@
 
         pdesc.fVertexLayout = 0;
         pdesc.fEmitsPointSize = random.nextF() > .5f;
-        pdesc.fColorInput = static_cast<int>(random.nextF() *
-                                             ProgramDesc::kColorInputCnt);
+        pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
 
-        int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt));
-        pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx;
+        pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);
 
-        idx = (int)(random.nextF() * (GrDrawState::kNumStages + 1));
-        pdesc.fFirstCoverageStage = idx;
+        pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);
 
-        pdesc.fVertexLayout |= (random.nextF() > .5f) ?
+        pdesc.fVertexLayout |= random_bool(&random) ?
                                     GrDrawTarget::kCoverage_VertexLayoutBit :
                                     0;
 
 #if GR_GL_EXPERIMENTAL_GS
         pdesc.fExperimentalGS = this->getCaps().fGeometryShaderSupport &&
-                                random.nextF() > .5f;
+                                random_bool(&random);
 #endif
-        pdesc.fOutputPM =  static_cast<int>(random.nextF() *
-                                            ProgramDesc::kOutputPMCnt);
+        pdesc.fOutputPM =  random_int(&random, ProgramDesc::kOutputPMCnt);
 
-        bool edgeAA = random.nextF() > .5f;
+        bool edgeAA = random_bool(&random);
         if (edgeAA) {
-            bool vertexEdgeAA = random.nextF() > .5f;
+            bool vertexEdgeAA = random_bool(&random);
             if (vertexEdgeAA) {
                 pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
                 if (this->getCaps().fShaderDerivativeSupport) {
-                    pdesc.fVertexEdgeType = random.nextF() > 0.5f ?
+                    pdesc.fVertexEdgeType = random_bool(&random) ?
                         GrDrawState::kHairQuad_EdgeType :
                         GrDrawState::kHairLine_EdgeType;
                 } else {
@@ -238,49 +249,57 @@
                 }
                 pdesc.fEdgeAANumEdges = 0;
             } else {
-                pdesc.fEdgeAANumEdges =  static_cast<int>(1 + random.nextF() *
-                                                          this->getMaxEdges());
-                pdesc.fEdgeAAConcave = random.nextF() > .5f;
+                pdesc.fEdgeAANumEdges = random_int(&random, 1, this->getMaxEdges());
+                pdesc.fEdgeAAConcave = random_bool(&random);
             }
         } else {
             pdesc.fEdgeAANumEdges = 0;
         }
 
         if (this->getCaps().fDualSourceBlendingSupport) {
-            pdesc.fDualSrcOutput =
-               (ProgramDesc::DualSrcOutput)
-               (int)(random.nextF() * ProgramDesc::kDualSrcOutputCnt);
+            pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
         } else {
             pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
         }
 
         for (int s = 0; s < GrDrawState::kNumStages; ++s) {
             // enable the stage?
-            if (random.nextF() > .5f) {
+            if (random_bool(&random)) {
                 // use separate tex coords?
-                if (random.nextF() > .5f) {
-                    int t = (int)(random.nextF() * GrDrawState::kMaxTexCoords);
+                if (random_bool(&random)) {
+                    int t = random_int(&random, GrDrawState::kMaxTexCoords);
                     pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
                 } else {
                     pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
                 }
             }
             // use text-formatted verts?
-            if (random.nextF() > .5f) {
+            if (random_bool(&random)) {
                 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
             }
-            idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
             StageDesc& stage = pdesc.fStages[s];
-            stage.fOptFlags = STAGE_OPTS[idx];
-            stage.fSwizzle = random_val(&random, StageDesc::kSwizzleCnt);
-            stage.fCoordMapping =  random_val(&random, StageDesc::kCoordMappingCnt);
-            stage.fFetchMode = random_val(&random, StageDesc::kFetchModeCnt);
+            stage.fOptFlags = STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
+            stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
+            stage.fCoordMapping =  random_int(&random, StageDesc::kCoordMappingCnt);
+            stage.fFetchMode = random_int(&random, StageDesc::kFetchModeCnt);
             // convolution shaders don't work with persp tex matrix
             if (stage.fFetchMode == StageDesc::kConvolution_FetchMode) {
                 stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
             }
             stage.setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
-            stage.fKernelWidth = static_cast<int8_t>(4 * random.nextF() + 2);
+            switch (stage.fFetchMode) {
+                case StageDesc::kSingle_FetchMode:
+                    stage.fKernelWidth = 0;
+                    break;
+                case StageDesc::kConvolution_FetchMode:
+                    stage.fKernelWidth = random_int(&random, 2, 8);
+                    stage.fInConfigFlags &= ~StageDesc::kMulRGBByAlpha_InConfigFlag;
+                    break;
+                case StageDesc::k2x2_FetchMode:
+                    stage.fKernelWidth = 0;
+                    stage.fInConfigFlags &= ~StageDesc::kMulRGBByAlpha_InConfigFlag;
+                    break;
+            }
         }
         CachedData cachedData;
         if (!program.genProgram(this->glInterface(),
@@ -1001,19 +1020,19 @@
                 stage.fOptFlags |= StageDesc::kCustomTextureDomain_OptFlagBit;
             }
 
+            stage.fInConfigFlags = 0;
             if (!this->glCaps().fTextureSwizzleSupport) {
                 if (GrPixelConfigIsAlphaOnly(texture->config())) {
                     // if we don't have texture swizzle support then
                     // the shader must do an alpha smear after reading
                     // the texture
-                    stage.fSwizzle = StageDesc::kAlphaSmear_Swizzle;
+                    stage.fInConfigFlags |= StageDesc::kSmearAlpha_InConfigFlag;
                 } else if (sampler.swapsRAndB()) {
-                    stage.fSwizzle = StageDesc::kSwapRAndB_Swizzle;
-                } else {
-                    stage.fSwizzle = StageDesc::kNone_Swizzle;
+                    stage.fInConfigFlags |= StageDesc::kSwapRAndB_InConfigFlag;
                 }
-            } else {
-                stage.fSwizzle = StageDesc::kNone_Swizzle;
+            }
+            if (GrPixelConfigIsUnpremultiplied(texture->config())) {
+                stage.fInConfigFlags = StageDesc::kMulRGBByAlpha_InConfigFlag;
             }
 
             if (sampler.getFilter() == GrSamplerState::kConvolution_Filter) {
@@ -1022,11 +1041,11 @@
                 stage.fKernelWidth = 0;
             }
         } else {
-            stage.fOptFlags     = 0;
-            stage.fCoordMapping = (StageDesc::CoordMapping) 0;
-            stage.fSwizzle      = (StageDesc::Swizzle) 0;
-            stage.fFetchMode    = (StageDesc::FetchMode) 0;
-            stage.fKernelWidth  = 0;
+            stage.fOptFlags         = 0;
+            stage.fCoordMapping     = (StageDesc::CoordMapping) 0;
+            stage.fInConfigFlags    = 0;
+            stage.fFetchMode        = (StageDesc::FetchMode) 0;
+            stage.fKernelWidth      = 0;
         }
     }