GPU device preserves pixel values across read/write/read of unpremul pixel values

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



git-svn-id: http://skia.googlecode.com/svn/trunk@3237 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGpuGLShaders.cpp b/src/gpu/gl/GrGpuGLShaders.cpp
index 4093a0d..a0a2df5 100644
--- a/src/gpu/gl/GrGpuGLShaders.cpp
+++ b/src/gpu/gl/GrGpuGLShaders.cpp
@@ -173,8 +173,9 @@
     static const int IN_CONFIG_FLAGS[] = {
         StageDesc::kNone_InConfigFlag,
         StageDesc::kSwapRAndB_InConfigFlag,
-        StageDesc::kSwapRAndB_InConfigFlag | StageDesc::kMulRGBByAlpha_InConfigFlag,
-        StageDesc::kMulRGBByAlpha_InConfigFlag,
+        StageDesc::kSwapRAndB_InConfigFlag |
+        StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag,
+        StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag,
         StageDesc::kSmearAlpha_InConfigFlag,
     };
     GrGLProgram program;
@@ -210,7 +211,7 @@
         pdesc.fExperimentalGS = this->getCaps().fGeometryShaderSupport &&
                                 random_bool(&random);
 #endif
-        pdesc.fOutputPM =  random_int(&random, ProgramDesc::kOutputPMCnt);
+        pdesc.fOutputConfig =  random_int(&random, ProgramDesc::kOutputConfigCnt);
 
         bool edgeAA = random_bool(&random);
         if (edgeAA) {
@@ -264,17 +265,20 @@
                 stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
             }
             stage.setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
+            static const uint32_t kMulByAlphaMask =
+                StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
+                StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
             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;
+                    stage.fInConfigFlags &= ~kMulByAlphaMask;
                     break;
                 case StageDesc::k2x2_FetchMode:
                     stage.fKernelWidth = 0;
-                    stage.fInConfigFlags &= ~StageDesc::kMulRGBByAlpha_InConfigFlag;
+                    stage.fInConfigFlags &= ~kMulByAlphaMask;
                     break;
             }
         }
@@ -1102,7 +1106,17 @@
                 }
             }
             if (GrPixelConfigIsUnpremultiplied(texture->config())) {
-                stage.fInConfigFlags |= StageDesc::kMulRGBByAlpha_InConfigFlag;
+                // The shader generator assumes that color channels are bytes
+                // when rounding.
+                GrAssert(4 == GrBytesPerPixel(texture->config()));
+                if (kUpOnWrite_DownOnRead_UnpremulConversion ==
+                    fUnpremulConversion) {
+                    stage.fInConfigFlags |=
+                        StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
+                } else {
+                    stage.fInConfigFlags |=
+                        StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag;
+                }
             }
 
             if (sampler.getFilter() == GrSamplerState::kConvolution_Filter) {
@@ -1120,9 +1134,18 @@
     }
 
     if (GrPixelConfigIsUnpremultiplied(drawState.getRenderTarget()->config())) {
-        desc.fOutputPM = ProgramDesc::kNo_OutputPM;
+        // The shader generator assumes that color channels are bytes
+        // when rounding.
+        GrAssert(4 == GrBytesPerPixel(drawState.getRenderTarget()->config()));
+        if (kUpOnWrite_DownOnRead_UnpremulConversion == fUnpremulConversion) {
+            desc.fOutputConfig =
+                ProgramDesc::kUnpremultiplied_RoundUp_OutputConfig;
+        } else {
+            desc.fOutputConfig =
+                ProgramDesc::kUnpremultiplied_RoundDown_OutputConfig;
+        }
     } else {
-        desc.fOutputPM = ProgramDesc::kYes_OutputPM;
+        desc.fOutputConfig = ProgramDesc::kPremultiplied_OutputConfig;
     }
 
     desc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;