Make program unit test run clean and add it to tests program

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


git-svn-id: http://skia.googlecode.com/svn/trunk@2121 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp
index fe42855..4699851 100644
--- a/gpu/src/GrGLProgram.cpp
+++ b/gpu/src/GrGLProgram.cpp
@@ -1091,7 +1091,7 @@
         segments->fVSCode.appendf("\t%s -= vec2(%g, %g) * %s;\n",
                                   varyingName.c_str(), scale, scale,
                                   imageIncrementName.c_str());
-}
+    }
 
     /// Fragment Shader Stuff
     GrStringBuilder fsCoordName;
@@ -1265,17 +1265,32 @@
         segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
         segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
     } else if (ProgramDesc::StageDesc::kConvolution_FetchMode == desc.fFetchMode) {
-        segments->fFSCode.append("\tvec4 sum = vec4(0, 0, 0, 0);\n");
-        segments->fFSCode.appendf("\tvec2 coord = %s;\n", sampleCoords.c_str());
-        segments->fFSCode.appendf("\tfor (int i = 0; i < %d; i++) {\n", desc.fKernelWidth);
-        segments->fFSCode.appendf("\t\tsum += %s(%s, coord)%s * %s[i];\n",
-                                  texFunc.c_str(), samplerName.c_str(),
-                                  smear, kernelName.c_str());
-        segments->fFSCode.appendf("\t\tcoord += %s;\n",
+        GrStringBuilder sumVar("sum");
+        sumVar.appendS32(stageNum);
+        GrStringBuilder coordVar("coord");
+        coordVar.appendS32(stageNum);
+
+        segments->fFSCode.appendf("\tvec4 %s = vec4(0, 0, 0, 0);\n",
+                                  sumVar.c_str());
+        segments->fFSCode.appendf("\tvec2 %s = %s;\n", 
+                                  coordVar.c_str(),
+                                  sampleCoords.c_str());
+        segments->fFSCode.appendf("\tfor (int i = 0; i < %d; i++) {\n",
+                                  desc.fKernelWidth);
+        segments->fFSCode.appendf("\t\t%s += %s(%s, %s)%s * %s[i];\n",
+                                  sumVar.c_str(), texFunc.c_str(),
+                                  samplerName.c_str(), coordVar.c_str(), smear,
+                                  kernelName.c_str());
+        segments->fFSCode.appendf("\t\t%s += %s;\n",
+                                  coordVar.c_str(),
                                   imageIncrementName.c_str());
         segments->fFSCode.appendf("\t}\n");
-        segments->fFSCode.appendf("\t%s = sum%s;\n", fsOutColor, modulate.c_str());
+        segments->fFSCode.appendf("\t%s = %s%s;\n", fsOutColor,
+                                  sumVar.c_str(), modulate.c_str());
     } else {
-        segments->fFSCode.appendf("\t%s = %s(%s, %s)%s%s;\n", fsOutColor, texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), smear, modulate.c_str());
+        segments->fFSCode.appendf("\t%s = %s(%s, %s)%s%s;\n",
+                                  fsOutColor, texFunc.c_str(), 
+                                  samplerName.c_str(), sampleCoords.c_str(),
+                                  smear, modulate.c_str());
     }
 }
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index adac9b0..5afd77e 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -143,7 +143,7 @@
     }
 };
 
-void GrGpuGLShaders::ProgramUnitTest() {
+bool GrGpuGLShaders::programUnitTest() {
 
     static const int STAGE_OPTS[] = {
         0,
@@ -185,8 +185,13 @@
         idx = (int)(random.nextF() * (kNumStages+1));
         pdesc.fFirstCoverageStage = idx;
 
-        pdesc.fEdgeAANumEdges = (random.nextF() * (getMaxEdges() + 1));
-        pdesc.fEdgeAAConcave = random.nextF() > .5f;
+        bool edgeAA = random.nextF() > .5f;
+        if (edgeAA) {
+            pdesc.fEdgeAANumEdges = random.nextF() * this->getMaxEdges() + 1;
+            pdesc.fEdgeAAConcave = random.nextF() > .5f;
+        } else {
+            pdesc.fEdgeAANumEdges = 0;
+        }
 
         if (fDualSourceBlendingSupport) {
             pdesc.fDualSrcOutput =
@@ -217,10 +222,17 @@
             stage.fModulation = random_val(&random, StageDesc::kModulationCnt);
             stage.fCoordMapping =  random_val(&random, StageDesc::kCoordMappingCnt);
             stage.fFetchMode = random_val(&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 = 4 * random.nextF() + 2;
         }
         CachedData cachedData;
-        program.genProgram(&cachedData);
+        if (!program.genProgram(&cachedData)) {
+            return false;
+        }
         DeleteProgram(&cachedData);
         bool again = false;
         if (again) {
@@ -228,6 +240,7 @@
             DeleteProgram(&cachedData);
         }
     }
+    return true;
 }
 
 GrGpuGLShaders::GrGpuGLShaders() {
@@ -247,7 +260,7 @@
     fProgramCache = new ProgramCache();
 
 #if 0
-    ProgramUnitTest();
+    this->programUnitTest();
 #endif
 }
 
diff --git a/gpu/src/GrGpuGLShaders.h b/gpu/src/GrGpuGLShaders.h
index eb3ee37..be6f64e 100644
--- a/gpu/src/GrGpuGLShaders.h
+++ b/gpu/src/GrGpuGLShaders.h
@@ -26,6 +26,8 @@
 
     virtual void abandonResources();
 
+    bool programUnitTest();
+
 protected:
     // overrides from GrGpu
     virtual bool flushGraphicsState(GrPrimitiveType type);
@@ -74,8 +76,6 @@
 
     static void DeleteProgram(CachedData* programData);
 
-    void ProgramUnitTest();
-
     void buildProgram(GrPrimitiveType type);
 
     ProgramCache*               fProgramCache;
diff --git a/gyp/core.gyp b/gyp/core.gyp
index 7d38974..aa2a199 100644
--- a/gyp/core.gyp
+++ b/gyp/core.gyp
@@ -133,6 +133,7 @@
         '../src/core/SkStrokerPriv.cpp',
         '../src/core/SkStrokerPriv.h',
         '../src/core/SkTextFormatParams.h',
+        '../src/core/SkTLazy.h',
         '../src/core/SkTSearch.cpp',
         '../src/core/SkTSort.h',
         '../src/core/SkTemplatesPriv.h',
diff --git a/gyp/tests.gyp b/gyp/tests.gyp
index 25fffd1..93b1149 100644
--- a/gyp/tests.gyp
+++ b/gyp/tests.gyp
@@ -10,6 +10,7 @@
       'type': 'executable',
       'include_dirs' : [
         '../src/core',
+        '../gpu/src',
       ],
       'sources': [
         '../tests/BitmapCopyTest.cpp',
@@ -29,6 +30,7 @@
         '../tests/FillPathTest.cpp',
         '../tests/FlateTest.cpp',
         '../tests/GeometryTest.cpp',
+        '../tests/GLProgramsTest.cpp',
         '../tests/InfRectTest.cpp',
         '../tests/MathTest.cpp',
         '../tests/MatrixTest.cpp',
@@ -52,8 +54,9 @@
         '../tests/StreamTest.cpp',
         '../tests/StringTest.cpp',
         '../tests/Test.cpp',
+        '../tests/Test.h',
         '../tests/TestSize.cpp',
-	'../tests/ToUnicode.cpp',
+        '../tests/ToUnicode.cpp',
         '../tests/UtilsTest.cpp',
         '../tests/Writer32Test.cpp',
         '../tests/XfermodeTest.cpp',
@@ -62,6 +65,8 @@
         'core.gyp:core',
         'effects.gyp:effects',
         'experimental.gyp:experimental',
+        'gpu.gyp:gr',
+        'gpu.gyp:skgr',
         'images.gyp:images',
         'pdf.gyp:pdf',
         'utils.gyp:utils',
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
new file mode 100644
index 0000000..5cacade
--- /dev/null
+++ b/tests/GLProgramsTest.cpp
@@ -0,0 +1,21 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "GrContext.h"
+#include "GrGpuGLShaders.h"
+
+static void GLProgramsTest(skiatest::Reporter* reporter, GrContext* context) {
+    GrGpuGLShaders* shadersGpu = (GrGpuGLShaders*) context->getGpu();
+    REPORTER_ASSERT(reporter, shadersGpu->programUnitTest());
+}
+
+
+#include "TestClassDef.h"
+DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)
+
diff --git a/tests/Test.cpp b/tests/Test.cpp
index e1246c3..e8a16f4 100644
--- a/tests/Test.cpp
+++ b/tests/Test.cpp
@@ -7,6 +7,10 @@
  */
 #include "Test.h"
 
+#include "GrContext.h"
+#include "SkEGLContext.h"
+#include "SkTLazy.h"
+
 using namespace skiatest;
 
 Reporter::Reporter() {
@@ -70,3 +74,20 @@
     return fReporter->getCurrSuccess();
 }
 
+///////////////////////////////////////////////////////////////////////////////
+
+
+GrContext* GpuTest::GetContext() {
+    // preserve this order, we want gGrContext destroyed after gEGLContext
+    static SkTLazy<SkEGLContext> gEGLContext;
+    static SkAutoTUnref<GrContext> gGrContext;
+
+    if (NULL == gGrContext.get()) {
+        gEGLContext.init();
+        if (gEGLContext.get()->init(800, 600)) {
+            gGrContext.reset(GrContext::Create(kOpenGL_Shaders_GrEngine, NULL));
+        }
+    }
+    return gGrContext.get();
+}
+
diff --git a/tests/Test.h b/tests/Test.h
index c27f120..2c28b00 100644
--- a/tests/Test.h
+++ b/tests/Test.h
@@ -12,6 +12,9 @@
 #include "SkString.h"
 #include "SkTRegistry.h"
 
+class GrContext;
+class SkEGLContext;
+
 namespace skiatest {
 
     class Test;
@@ -94,6 +97,17 @@
         SkString    fName;
     };
 
+    class GpuTest : public Test{
+    public:
+        GpuTest() : Test() {
+            fContext = GetContext();
+        }
+    protected:
+        GrContext* fContext;
+    private:
+        static GrContext* GetContext();
+    };
+
     typedef SkTRegistry<Test*, void*> TestRegistry;
 }
 
diff --git a/tests/TestClassDef.h b/tests/TestClassDef.h
index ce9cff4..34f899f 100644
--- a/tests/TestClassDef.h
+++ b/tests/TestClassDef.h
@@ -29,3 +29,16 @@
         static TestRegistry gReg(classname::Factory);                       \
     }
 
+#define DEFINE_GPUTESTCLASS(uiname, classname, function)                    \
+    namespace skiatest {                                                    \
+        class classname : public GpuTest {                                  \
+        public:                                                             \
+            static Test* Factory(void*) { return SkNEW(classname); }        \
+        protected:                                                          \
+            virtual void onGetName(SkString* name) { name->set(uiname); }   \
+            virtual void onRun(Reporter* reporter) {                        \
+                function(reporter, fContext);                               \
+            }                                                               \
+        };                                                                  \
+        static TestRegistry gReg(classname::Factory);                       \
+    }