Merge "Use the default scale for text input."
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index e5ece8e..f6c55e4 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -65,6 +65,20 @@
 
 typedef void* (*android_pthread_entry)(void*);
 
+static pthread_once_t gDoSchedulingGroupOnce = PTHREAD_ONCE_INIT;
+static bool gDoSchedulingGroup = true;
+
+static void checkDoSchedulingGroup(void) {
+    char buf[PROPERTY_VALUE_MAX];
+    int len = property_get("debug.sys.noschedgroups", buf, "");
+    if (len > 0) {
+        int temp;
+        if (sscanf(buf, "%d", &temp) == 1) {
+            gDoSchedulingGroup = temp == 0;
+        }
+    }
+}
+
 struct thread_data_t {
     thread_func_t   entryFunction;
     void*           userData;
@@ -80,6 +94,15 @@
         char * name = t->threadName;
         delete t;
         setpriority(PRIO_PROCESS, 0, prio);
+        pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup);
+        if (gDoSchedulingGroup) {
+            if (prio >= ANDROID_PRIORITY_BACKGROUND) {
+                set_sched_policy(androidGetTid(), SP_BACKGROUND);
+            } else {
+                set_sched_policy(androidGetTid(), SP_FOREGROUND);
+            }
+        }
+        
         if (name) {
 #if defined(HAVE_PRCTL)
             // Mac OS doesn't have this, and we build libutil for the host too
@@ -281,22 +304,6 @@
 #endif
 }
 
-#if defined(HAVE_PTHREADS)
-static pthread_once_t gDoSchedulingGroupOnce = PTHREAD_ONCE_INIT;
-static bool gDoSchedulingGroup = true;
-
-static void checkDoSchedulingGroup(void) {
-    char buf[PROPERTY_VALUE_MAX];
-    int len = property_get("debug.sys.noschedgroups", buf, "");
-    if (len > 0) {
-        int temp;
-        if (sscanf(buf, "%d", &temp) == 1) {
-            gDoSchedulingGroup = temp == 0;
-        }
-    }
-}
-#endif
-
 int androidSetThreadSchedulingGroup(pid_t tid, int grp)
 {
     if (grp > ANDROID_TGROUP_MAX || grp < 0) { 
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 9228b0b..bd5fad2 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -240,7 +240,7 @@
         memset(images, 0, sizeof(images));
     }
     EGLDisplay dpy;
-    EGLConfig context;
+    EGLContext context;
     EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
 };
 
@@ -1770,7 +1770,7 @@
          egl_connection_t* const cnx = &gEGLImpl[i];
          if (image->images[i] != EGL_NO_IMAGE_KHR) {
              if (cnx->dso) {
-                 if (cnx->egl.eglCreateImageKHR) {
+                 if (cnx->egl.eglDestroyImageKHR) {
                      if (cnx->egl.eglDestroyImageKHR(
                              dp->disp[i].dpy, image->images[i])) {
                          success = true;
diff --git a/opengl/tests/angeles/app-linux.cpp b/opengl/tests/angeles/app-linux.cpp
index 9f80ed4..4d10ee5 100644
--- a/opengl/tests/angeles/app-linux.cpp
+++ b/opengl/tests/angeles/app-linux.cpp
@@ -63,7 +63,7 @@
 int gAppAlive = 1;
 
 static const char sAppName[] =
-    "San Angeles Observation OpenGL ES version example (Linux)";
+        "San Angeles Observation OpenGL ES version example (Linux)";
 
 static int sWindowWidth = WINDOW_DEFAULT_WIDTH;
 static int sWindowHeight = WINDOW_DEFAULT_HEIGHT;
@@ -74,22 +74,22 @@
 const char *egl_strerror(unsigned err)
 {
     switch(err){
-    case EGL_SUCCESS: return "SUCCESS";
-    case EGL_NOT_INITIALIZED: return "NOT INITIALIZED";
-    case EGL_BAD_ACCESS: return "BAD ACCESS";
-    case EGL_BAD_ALLOC: return "BAD ALLOC";
-    case EGL_BAD_ATTRIBUTE: return "BAD_ATTRIBUTE";
-    case EGL_BAD_CONFIG: return "BAD CONFIG";
-    case EGL_BAD_CONTEXT: return "BAD CONTEXT";
-    case EGL_BAD_CURRENT_SURFACE: return "BAD CURRENT SURFACE";
-    case EGL_BAD_DISPLAY: return "BAD DISPLAY";
-    case EGL_BAD_MATCH: return "BAD MATCH";
-    case EGL_BAD_NATIVE_PIXMAP: return "BAD NATIVE PIXMAP";
-    case EGL_BAD_NATIVE_WINDOW: return "BAD NATIVE WINDOW";
-    case EGL_BAD_PARAMETER: return "BAD PARAMETER";
-    case EGL_BAD_SURFACE: return "BAD_SURFACE";
-//    case EGL_CONTEXT_LOST: return "CONTEXT LOST";
-    default: return "UNKNOWN";
+        case EGL_SUCCESS: return "SUCCESS";
+        case EGL_NOT_INITIALIZED: return "NOT INITIALIZED";
+        case EGL_BAD_ACCESS: return "BAD ACCESS";
+        case EGL_BAD_ALLOC: return "BAD ALLOC";
+        case EGL_BAD_ATTRIBUTE: return "BAD_ATTRIBUTE";
+        case EGL_BAD_CONFIG: return "BAD CONFIG";
+        case EGL_BAD_CONTEXT: return "BAD CONTEXT";
+        case EGL_BAD_CURRENT_SURFACE: return "BAD CURRENT SURFACE";
+        case EGL_BAD_DISPLAY: return "BAD DISPLAY";
+        case EGL_BAD_MATCH: return "BAD MATCH";
+        case EGL_BAD_NATIVE_PIXMAP: return "BAD NATIVE PIXMAP";
+        case EGL_BAD_NATIVE_WINDOW: return "BAD NATIVE WINDOW";
+        case EGL_BAD_PARAMETER: return "BAD PARAMETER";
+        case EGL_BAD_SURFACE: return "BAD_SURFACE";
+        //    case EGL_CONTEXT_LOST: return "CONTEXT LOST";
+        default: return "UNKNOWN";
     }
 }
 
@@ -118,52 +118,59 @@
         fprintf(stderr, "EGL Error: 0x%04x\n", (int)error);
 }
 
-static int initGraphics()
+static int initGraphics(unsigned samples)
 {
     EGLint configAttribs[] = {
-         EGL_DEPTH_SIZE, 16,
-         EGL_NONE
-     };
-     
-     EGLint majorVersion;
-     EGLint minorVersion;
-     EGLContext context;
-     EGLConfig config;
-     EGLSurface surface;
-     EGLint w, h;
-     EGLDisplay dpy;
+            EGL_DEPTH_SIZE, 16,
+            EGL_SAMPLE_BUFFERS, samples ? 1 : 0,
+                    EGL_SAMPLES, samples,
+                    EGL_NONE
+    };
 
-     EGLNativeWindowType window = android_createDisplaySurface();
-     
-     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-     eglInitialize(dpy, &majorVersion, &minorVersion);
-          
-     status_t err = EGLUtils::selectConfigForNativeWindow(
-             dpy, configAttribs, window, &config);
-     if (err) {
-         fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
-         return 0;
-     }
+    EGLint majorVersion;
+    EGLint minorVersion;
+    EGLContext context;
+    EGLConfig config;
+    EGLSurface surface;
+    EGLint w, h;
+    EGLDisplay dpy;
 
-     surface = eglCreateWindowSurface(dpy, config, window, NULL);
-     egl_error("eglCreateWindowSurface");
+    EGLNativeWindowType window = android_createDisplaySurface();
 
-     fprintf(stderr,"surface = %p\n", surface);
+    dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    eglInitialize(dpy, &majorVersion, &minorVersion);
 
-     context = eglCreateContext(dpy, config, NULL, NULL);
-     egl_error("eglCreateContext");
-     fprintf(stderr,"context = %p\n", context);
-     
-     eglMakeCurrent(dpy, surface, surface, context);   
-     egl_error("eglMakeCurrent");
+    status_t err = EGLUtils::selectConfigForNativeWindow(
+            dpy, configAttribs, window, &config);
+    if (err) {
+        fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+        return 0;
+    }
 
-     eglQuerySurface(dpy, surface, EGL_WIDTH, &sWindowWidth);
-     eglQuerySurface(dpy, surface, EGL_HEIGHT, &sWindowHeight);
+    surface = eglCreateWindowSurface(dpy, config, window, NULL);
+    egl_error("eglCreateWindowSurface");
+
+    fprintf(stderr,"surface = %p\n", surface);
+
+    context = eglCreateContext(dpy, config, NULL, NULL);
+    egl_error("eglCreateContext");
+    fprintf(stderr,"context = %p\n", context);
+
+    eglMakeCurrent(dpy, surface, surface, context);
+    egl_error("eglMakeCurrent");
+
+    eglQuerySurface(dpy, surface, EGL_WIDTH, &sWindowWidth);
+    eglQuerySurface(dpy, surface, EGL_HEIGHT, &sWindowHeight);
 
     sEglDisplay = dpy;
     sEglSurface = surface;
     sEglContext = context;
 
+    if (samples == 0) {
+        // GL_MULTISAMPLE is enabled by default
+        glDisable(GL_MULTISAMPLE);
+    }
+
     return EGL_TRUE;
 }
 
@@ -179,11 +186,14 @@
 
 int main(int argc, char *argv[])
 {
-    // not referenced:
-    argc = argc;
-    argv = argv;
+    unsigned samples = 0;
+    printf("usage: %s [samples]\n", argv[0]);
+    if (argc == 2) {
+        samples = atoi( argv[1] );
+        printf("Multisample enabled: GL_SAMPLES = %u\n", samples);
+    }
 
-    if (!initGraphics())
+    if (!initGraphics(samples))
     {
         fprintf(stderr, "Graphics initialization failed.\n");
         return EXIT_FAILURE;
@@ -195,7 +205,7 @@
     int frameCount = 0;
     gettimeofday(&timeTemp, NULL);
     double totalTime = timeTemp.tv_usec/1000000.0 + timeTemp.tv_sec;
-    
+
     while (gAppAlive)
     {
         struct timeval timeNow;
diff --git a/opengl/tests/gl_perf/fill_common.cpp b/opengl/tests/gl_perf/fill_common.cpp
index 36db1b0..a069f67 100644
--- a/opengl/tests/gl_perf/fill_common.cpp
+++ b/opengl/tests/gl_perf/fill_common.cpp
@@ -14,9 +14,15 @@
  * limitations under the License.
  */
 
+#include "fragment_shaders.cpp"
+
 FILE * fOut = NULL;
 void ptSwap();
 
+static char gCurrentTestName[1024];
+static uint32_t gWidth = 0;
+static uint32_t gHeight = 0;
+
 static void checkGlError(const char* op) {
     for (GLint error = glGetError(); error; error
             = glGetError()) {
@@ -112,20 +118,21 @@
     gTime = getTime();
 }
 
-void endTimer(const char *str, int w, int h, double dc, int count) {
+
+static void endTimer(int count) {
     uint64_t t2 = getTime();
     double delta = ((double)(t2 - gTime)) / 1000000000;
-    double pixels = dc * (w * h) * count;
+    double pixels = (gWidth * gHeight) * count;
     double mpps = pixels / delta / 1000000;
-    double dc60 = pixels / delta / (w * h) / 60;
+    double dc60 = ((double)count) / delta / 60;
 
     if (fOut) {
-        fprintf(fOut, "%s, %f, %f\r\n", str, mpps, dc60);
+        fprintf(fOut, "%s, %f, %f\r\n", gCurrentTestName, mpps, dc60);
         fflush(fOut);
     } else {
-        printf("%s, %f, %f\n", str, mpps, dc60);
+        printf("%s, %f, %f\n", gCurrentTestName, mpps, dc60);
     }
-    LOGI("%s, %f, %f\r\n", str, mpps, dc60);
+    LOGI("%s, %f, %f\r\n", gCurrentTestName, mpps, dc60);
 }
 
 
@@ -137,86 +144,17 @@
     "varying vec4 v_color;\n"
     "varying vec2 v_tex0;\n"
     "varying vec2 v_tex1;\n"
+    "uniform vec2 u_texOff;\n"
 
     "void main() {\n"
     "    v_color = a_color;\n"
     "    v_tex0 = a_tex0;\n"
     "    v_tex1 = a_tex1;\n"
+    "    v_tex0.x += u_texOff.x;\n"
+    "    v_tex1.y += u_texOff.y;\n"
     "    gl_Position = a_pos;\n"
     "}\n";
 
-static const char gShaderPrefix[] =
-    "precision mediump float;\n"
-    "uniform vec4 u_color;\n"
-    "uniform vec4 u_0;\n"
-    "uniform vec4 u_1;\n"
-    "uniform vec4 u_2;\n"
-    "uniform vec4 u_3;\n"
-    "varying vec4 v_color;\n"
-    "varying vec2 v_tex0;\n"
-    "varying vec2 v_tex1;\n"
-    "uniform sampler2D u_tex0;\n"
-    "uniform sampler2D u_tex1;\n"
-    "void main() {\n";
-
-static const char gShaderPostfix[] =
-    "  gl_FragColor = c;\n"
-    "}\n";
-
-
-static char * append(char *d, const char *s) {
-    size_t len = strlen(s);
-    memcpy(d, s, len);
-    return d + len;
-}
-
-static char * genShader(
-    bool useVarColor,
-    int texCount,
-    bool modulateFirstTex,
-    int extraMath)
-{
-    char *str = (char *)calloc(16 * 1024, 1);
-    char *tmp = append(str, gShaderPrefix);
-
-    if (modulateFirstTex || !texCount) {
-        if (useVarColor) {
-            tmp = append(tmp, "  vec4 c = v_color;\n");
-        } else {
-            tmp = append(tmp, "  vec4 c = u_color;\n");
-        }
-    } else {
-        tmp = append(tmp, "  vec4 c = texture2D(u_tex0, v_tex0);\n");
-    }
-
-    if (modulateFirstTex && texCount) {
-        tmp = append(tmp, "  c *= texture2D(u_tex0, v_tex0);\n");
-    }
-    if (texCount > 1) {
-        tmp = append(tmp, "  c *= texture2D(u_tex1, v_tex1);\n");
-    }
-
-    if (extraMath > 0) {
-        tmp = append(tmp, "  c *= u_0;\n");
-    }
-    if (extraMath > 1) {
-        tmp = append(tmp, "  c += u_1;\n");
-    }
-    if (extraMath > 2) {
-        tmp = append(tmp, "  c *= u_2;\n");
-    }
-    if (extraMath > 3) {
-        tmp = append(tmp, "  c += u_3;\n");
-    }
-
-
-    tmp = append(tmp, gShaderPostfix);
-    tmp[0] = 0;
-
-    //printf("%s", str);
-    return str;
-}
-
 static void setupVA() {
     static const float vtx[] = {
         -1.0f,-1.0f,
@@ -231,8 +169,8 @@
     static const float tex0[] = {
         0.0f,0.0f,
         1.0f,0.0f,
-        1.0f,1.0f,
-        0.0f,1.0f };
+        0.0f,1.0f,
+        1.0f,1.0f };
     static const float tex1[] = {
         1.0f,0.0f,
         1.0f,1.0f,
@@ -261,8 +199,8 @@
     }
 }
 
-static void doLoop(bool clear, int pgm, uint32_t w, uint32_t h, const char *str) {
-    if (clear) {
+static void doLoop(bool warmup, int pgm, uint32_t passCount) {
+    if (warmup) {
         glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
         ptSwap();
@@ -272,7 +210,10 @@
 
     startTimer();
     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
-    for (int ct=0; ct < 100; ct++) {
+    for (uint32_t ct=0; ct < passCount; ct++) {
+        int loc = glGetUniformLocation(pgm, "u_texOff");
+        glUniform2f(loc, ((float)ct) / passCount, ((float)ct) / 2.f / passCount);
+
         randUniform(pgm, "u_color");
         randUniform(pgm, "u_0");
         randUniform(pgm, "u_1");
@@ -282,14 +223,24 @@
     }
     ptSwap();
     glFinish();
-    endTimer(str, w, h, 1, 100);
+    endTimer(passCount);
+}
+
+
+static uint32_t rgb(uint32_t r, uint32_t g, uint32_t b)
+{
+    uint32_t ret = 0xff000000;
+    ret |= r & 0xff;
+    ret |= (g & 0xff) << 8;
+    ret |= (b & 0xff) << 16;
+    return ret;
 }
 
 void genTextures() {
     uint32_t *m = (uint32_t *)malloc(1024*1024*4);
     for (int y=0; y < 1024; y++){
         for (int x=0; x < 1024; x++){
-            m[y*1024 + x] = 0xff0000ff | ((x & 0xff) << 8) | (y << 16);
+            m[y*1024 + x] = rgb(x, (((x+y) & 0xff) == 0x7f) * 0xff, y);
         }
     }
     glBindTexture(GL_TEXTURE_2D, 1);
@@ -301,7 +252,7 @@
 
     for (int y=0; y < 16; y++){
         for (int x=0; x < 16; x++){
-            m[y*16 + x] = 0xff0000ff | (x<<12) | (y<<20);
+            m[y*16 + x] = rgb(x << 4, (((x+y) & 0xf) == 0x7) * 0xff, y << 4);
         }
     }
     glBindTexture(GL_TEXTURE_2D, 2);
@@ -310,7 +261,38 @@
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
+    free(m);
 }
 
+static void doSingleTest(uint32_t pgmNum, int tex) {
+    const char *pgmTxt = gFragmentTests[pgmNum]->txt;
+    int pgm = createProgram(gVertexShader, pgmTxt);
+    if (!pgm) {
+        printf("error running test\n");
+        return;
+    }
+    int loc = glGetUniformLocation(pgm, "u_tex0");
+    if (loc >= 0) glUniform1i(loc, 0);
+    loc = glGetUniformLocation(pgm, "u_tex1");
+    if (loc >= 0) glUniform1i(loc, 1);
+
+
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, tex);
+    glActiveTexture(GL_TEXTURE1);
+    glBindTexture(GL_TEXTURE_2D, tex);
+    glActiveTexture(GL_TEXTURE0);
+
+    glBlendFunc(GL_ONE, GL_ONE);
+    glDisable(GL_BLEND);
+    //sprintf(str2, "%i, %i, %i, %i, %i, 0",
+            //useVarColor, texCount, modulateFirstTex, extraMath, tex0);
+    //doLoop(true, pgm, w, h, str2);
+    //doLoop(false, pgm, w, h, str2);
+
+    glEnable(GL_BLEND);
+    sprintf(gCurrentTestName, "%s, %i, %i, 1", gFragmentTests[pgmNum]->name, pgmNum, tex);
+    doLoop(true, pgm, 100);
+    doLoop(false, pgm, 100);
+}
 
diff --git a/opengl/tests/gl_perf/filltest.cpp b/opengl/tests/gl_perf/filltest.cpp
index 0dd4e22..3f8faca 100644
--- a/opengl/tests/gl_perf/filltest.cpp
+++ b/opengl/tests/gl_perf/filltest.cpp
@@ -33,65 +33,19 @@
 
 #include "fill_common.cpp"
 
-static void doSingleTest(uint32_t w, uint32_t h,
-                         bool useVarColor,
-                         int texCount,
-                         bool modulateFirstTex,
-                         int extraMath,
-                         int tex0, int tex1) {
-    char *pgmTxt = genShader(useVarColor, texCount, modulateFirstTex, extraMath);
-    int pgm = createProgram(gVertexShader, pgmTxt);
-    if (!pgm) {
-        printf("error running test\n");
-        return;
-    }
-    int loc = glGetUniformLocation(pgm, "u_tex0");
-    if (loc >= 0) glUniform1i(loc, 0);
-    loc = glGetUniformLocation(pgm, "u_tex1");
-    if (loc >= 0) glUniform1i(loc, 1);
-
-    glActiveTexture(GL_TEXTURE0);
-    glBindTexture(GL_TEXTURE_2D, tex0);
-    glActiveTexture(GL_TEXTURE1);
-    glBindTexture(GL_TEXTURE_2D, tex1);
-    glActiveTexture(GL_TEXTURE0);
-
-    char str2[1024];
-
-    glBlendFunc(GL_ONE, GL_ONE);
-    glDisable(GL_BLEND);
-    //sprintf(str2, "%i, %i, %i, %i, %i, 0",
-            //useVarColor, texCount, modulateFirstTex, extraMath, tex0);
-    //doLoop(true, pgm, w, h, str2);
-    //doLoop(false, pgm, w, h, str2);
-
-    glEnable(GL_BLEND);
-    sprintf(str2, "%i, %i, %i, %i, %i, 1",
-            useVarColor, texCount, modulateFirstTex, extraMath, tex0);
-    doLoop(true, pgm, w, h, str2);
-    doLoop(false, pgm, w, h, str2);
-}
 
 bool doTest(uint32_t w, uint32_t h) {
+    gWidth = w;
+    gHeight = h;
     setupVA();
     genTextures();
 
     printf("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n");
 
-    for (int texCount = 0; texCount < 2; texCount++) {
-        for (int extraMath = 0; extraMath < 5; extraMath++) {
-
-            doSingleTest(w, h, false, texCount, false, extraMath, 1, 1);
-            doSingleTest(w, h, true, texCount, false, extraMath, 1, 1);
-            if (texCount) {
-                doSingleTest(w, h, false, texCount, true, extraMath, 1, 1);
-                doSingleTest(w, h, true, texCount, true, extraMath, 1, 1);
-
-                doSingleTest(w, h, false, texCount, false, extraMath, 2, 2);
-                doSingleTest(w, h, true, texCount, false, extraMath, 2, 2);
-                doSingleTest(w, h, false, texCount, true, extraMath, 2, 2);
-                doSingleTest(w, h, true, texCount, true, extraMath, 2, 2);
-            }
+    for (uint32_t num = 0; num < gFragmentTestCount; num++) {
+        doSingleTest(num, 2);
+        if (gFragmentTests[num]->texCount) {
+            doSingleTest(num, 1);
         }
     }
 
diff --git a/opengl/tests/gl_perf/fragment_shaders.cpp b/opengl/tests/gl_perf/fragment_shaders.cpp
new file mode 100644
index 0000000..79d5ead
--- /dev/null
+++ b/opengl/tests/gl_perf/fragment_shaders.cpp
@@ -0,0 +1,139 @@
+
+typedef struct FragmentTestRec {
+	const char * name;
+	uint32_t texCount;
+	const char * txt;
+} FragmentTest;
+
+static FragmentTest fpFill = {
+	"Solid color", 0,
+
+    "precision mediump float;\n"
+    "uniform vec4 u_color;\n"
+    "void main() {\n"
+    "  gl_FragColor = u_color;\n"
+    "}\n"
+};
+
+static FragmentTest fpGradient = {
+	"Solid gradient", 0,
+
+    "precision mediump float;\n"
+    "varying lowp vec4 v_color;\n"
+    "void main() {\n"
+    "  gl_FragColor = v_color;\n"
+    "}\n"
+};
+
+static FragmentTest fpCopyTex = {
+	"Texture copy", 1,
+
+    "precision mediump float;\n"
+    "varying vec2 v_tex0;\n"
+    "uniform sampler2D u_tex0;\n"
+    "void main() {\n"
+    "  gl_FragColor = texture2D(u_tex0, v_tex0);\n"
+    "}\n"
+};
+
+static FragmentTest fpCopyTexGamma = {
+	"Texture copy with gamma", 1,
+
+    "precision mediump float;\n"
+    "varying vec2 v_tex0;\n"
+    "uniform sampler2D u_tex0;\n"
+    "void main() {\n"
+    "  vec4 t = texture2D(u_tex0, v_tex0);\n"
+    "  t.rgb = pow(t.rgb, vec3(1.4, 1.4, 1.4));\n"
+    "  gl_FragColor = t;\n"
+    "}\n"
+};
+
+static FragmentTest fpTexSpec = {
+	"Texture spec", 1,
+
+    "precision mediump float;\n"
+    "varying vec2 v_tex0;\n"
+    "uniform sampler2D u_tex0;\n"
+    "void main() {\n"
+    "  vec4 t = texture2D(u_tex0, v_tex0);\n"
+    "  float simSpec = dot(gl_FragCoord.xyz, gl_FragCoord.xyz);\n"
+    "  simSpec = pow(clamp(simSpec, 0.1, 1.0), 40.0);\n"
+    "  gl_FragColor = t + vec4(simSpec, simSpec, simSpec, simSpec);\n"
+    "}\n"
+};
+
+static FragmentTest fpDepTex = {
+	"Dependent Lookup", 1,
+
+    "precision mediump float;\n"
+    "varying vec2 v_tex0;\n"
+    "uniform sampler2D u_tex0;\n"
+    "void main() {\n"
+    "  vec4 t = texture2D(u_tex0, v_tex0);\n"
+    "  t += texture2D(u_tex0, t.xy);\n"
+    "  gl_FragColor = t;\n"
+    "}\n"
+};
+
+static FragmentTest fpModulateConstantTex = {
+	"Texture modulate constant", 1,
+
+    "precision mediump float;\n"
+    "varying vec2 v_tex0;\n"
+    "uniform sampler2D u_tex0;\n"
+    "uniform vec4 u_color;\n"
+
+    "void main() {\n"
+    "  lowp vec4 c = texture2D(u_tex0, v_tex0);\n"
+	"  c *= u_color;\n"
+    "  gl_FragColor = c;\n"
+    "}\n"
+};
+
+static FragmentTest fpModulateVaryingTex = {
+	"Texture modulate gradient", 1,
+
+    "precision mediump float;\n"
+    "varying vec2 v_tex0;\n"
+    "varying lowp vec4 v_color;\n"
+    "uniform sampler2D u_tex0;\n"
+
+    "void main() {\n"
+    "  lowp vec4 c = texture2D(u_tex0, v_tex0);\n"
+	"  c *= v_color;\n"
+    "  gl_FragColor = c;\n"
+    "}\n"
+};
+
+static FragmentTest fpModulateVaryingConstantTex = {
+	"Texture modulate gradient constant", 1,
+
+    "precision mediump float;\n"
+    "varying vec2 v_tex0;\n"
+    "varying lowp vec4 v_color;\n"
+    "uniform sampler2D u_tex0;\n"
+    "uniform vec4 u_color;\n"
+
+    "void main() {\n"
+    "  lowp vec4 c = texture2D(u_tex0, v_tex0);\n"
+	"  c *= v_color;\n"
+	"  c *= u_color;\n"
+    "  gl_FragColor = c;\n"
+    "}\n"
+};
+
+static FragmentTest *gFragmentTests[] = {
+	&fpFill,
+	&fpGradient,
+	&fpCopyTex,
+	&fpCopyTexGamma,
+   &fpTexSpec,
+   &fpDepTex,
+	&fpModulateConstantTex,
+	&fpModulateVaryingTex,
+	&fpModulateVaryingConstantTex,
+
+};
+
+static const size_t gFragmentTestCount = sizeof(gFragmentTests) / sizeof(gFragmentTests[0]);
diff --git a/opengl/tests/gl_perfapp/jni/gl_code.cpp b/opengl/tests/gl_perfapp/jni/gl_code.cpp
index e643292..f993371 100644
--- a/opengl/tests/gl_perfapp/jni/gl_code.cpp
+++ b/opengl/tests/gl_perfapp/jni/gl_code.cpp
@@ -32,82 +32,17 @@
 
 // Saves the parameters of the test (so we can print them out when we finish the timing.)
 
-char saveBuf[1024];
-
 
 int pgm;
 
 void ptSwap() {
 }
 
-static void doSingleTest(uint32_t w, uint32_t h,
-                         bool useVarColor,
-                         int texCount,
-                         bool modulateFirstTex,
-                         int extraMath,
-                         int tex0, int tex1) {
-    int doSingleTestState = (stateClock / doLoopStates) % doSingleTestStates;
-    // LOGI("doSingleTest %d\n", doSingleTestState);
-    switch (doSingleTestState) {
-	case 0: {
-	    char *pgmTxt = genShader(useVarColor, texCount, modulateFirstTex, extraMath);
-	    pgm = createProgram(gVertexShader, pgmTxt);
-	    if (!pgm) {
-		LOGE("error running test\n");
-		return;
-	    }
-	    int loc = glGetUniformLocation(pgm, "u_tex0");
-	    if (loc >= 0) glUniform1i(loc, 0);
-	    loc = glGetUniformLocation(pgm, "u_tex1");
-	    if (loc >= 0) glUniform1i(loc, 1);
+void doTest() {
+    uint32_t testNum = stateClock >> 2;
+    int texSize = ((stateClock >> 1) & 0x1) + 1;
 
-	    glActiveTexture(GL_TEXTURE0);
-	    glBindTexture(GL_TEXTURE_2D, tex0);
-	    glActiveTexture(GL_TEXTURE1);
-	    glBindTexture(GL_TEXTURE_2D, tex1);
-	    glActiveTexture(GL_TEXTURE0);
-
-
-	    glBlendFunc(GL_ONE, GL_ONE);
-	    glDisable(GL_BLEND);
-            char str2[1024];
-	    sprintf(str2, "%i, %i, %i, %i, %i, 0",
-		    useVarColor, texCount, modulateFirstTex, extraMath, tex0);
-
-    	    doLoop((stateClock % doLoopStates) != 0, pgm, w, h, str2);
-	 }
-         break;
-         case 1: {
-            char str2[1024];
-	    glEnable(GL_BLEND);
-	    sprintf(str2, "%i, %i, %i, %i, %i, 1",
-		    useVarColor, texCount, modulateFirstTex, extraMath, tex0);
-	    doLoop((stateClock % doLoopStates) != 0, pgm, w, h, str2);
-        }
-        break;
-    }
-}
-
-
-void doTest(uint32_t w, uint32_t h) {
-    int testState = stateClock / (doLoopStates * doSingleTestStates);
-    int texCount;
-    int extraMath;
-    int testSubState;
-    const int extraMathCount = 5;
-    const int texCount0SubTestCount = 2;
-    const int texCountNSubTestCount = 8;
-
-    if ( testState < extraMathCount * texCount0SubTestCount) {
-       texCount = 0; // Only 10 tests for texCount 0
-       extraMath = (testState / texCount0SubTestCount) % extraMathCount;
-       testSubState = testState % texCount0SubTestCount;
-    } else {
-       texCount = 1 + (testState - extraMathCount * texCount0SubTestCount) / (extraMathCount * texCountNSubTestCount);
-       extraMath = (testState / texCountNSubTestCount) % extraMathCount;
-       testSubState = testState % texCountNSubTestCount;
-    }
-    if (texCount >= 3) {
+    if (testNum >= gFragmentTestCount) {
        LOGI("done\n");
        if (fOut) {
            fclose(fOut);
@@ -117,36 +52,10 @@
        return;
     }
 
-
     // LOGI("doTest %d %d %d\n", texCount, extraMath, testSubState);
 
-    switch(testSubState) {
-	case 0:
-            doSingleTest(w, h, false, texCount, false, extraMath, 1, 1);
-	break;
-	case 1:
-            doSingleTest(w, h, true, texCount, false, extraMath, 1, 1);
-	break;
-	case 2:
-                doSingleTest(w, h, false, texCount, true, extraMath, 1, 1);
-	break;
-	case 3:
-                doSingleTest(w, h, true, texCount, true, extraMath, 1, 1);
-	break;
-
-	case 4:
-                doSingleTest(w, h, false, texCount, false, extraMath, 2, 2);
-	break;
-	case 5:
-                doSingleTest(w, h, true, texCount, false, extraMath, 2, 2);
-	break;
-	case 6:
-                doSingleTest(w, h, false, texCount, true, extraMath, 2, 2);
-	break;
-	case 7:
-                doSingleTest(w, h, true, texCount, true, extraMath, 2, 2);
-	break;
-    }
+//        for (uint32_t num = 0; num < gFragmentTestCount; num++) {
+    doSingleTest(testNum, texSize);
 }
 
 extern "C" {
@@ -156,27 +65,27 @@
 
 JNIEXPORT void JNICALL Java_com_android_glperf_GLPerfLib_init(JNIEnv * env, jobject obj,  jint width, jint height)
 {
+    gWidth = width;
+    gHeight = height;
     if (!done) {
-	    w = width;
-	    h = height;
-	    stateClock = 0;
-	    done = false;
-	    setupVA();
-	    genTextures();
-	    const char* fileName = "/sdcard/glperf.csv";
+            stateClock = 0;
+            done = false;
+            setupVA();
+            genTextures();
+            const char* fileName = "/sdcard/glperf.csv";
             if (fOut != NULL) {
                  LOGI("Closing partially written output.n");
                  fclose(fOut);
                  fOut = NULL;
             }
-	    LOGI("Writing to: %s\n",fileName);
-	    fOut = fopen(fileName, "w");
-	    if (fOut == NULL) {
-		LOGE("Could not open: %s\n", fileName);
-	    }
+            LOGI("Writing to: %s\n",fileName);
+            fOut = fopen(fileName, "w");
+            if (fOut == NULL) {
+                LOGE("Could not open: %s\n", fileName);
+            }
 
-	    LOGI("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n");
-	    if (fOut) fprintf(fOut,"varColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\r\n");
+            LOGI("\nvarColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\n");
+            if (fOut) fprintf(fOut,"varColor, texCount, modulate, extraMath, texSize, blend, Mpps, DC60\r\n");
     }
 }
 
@@ -184,11 +93,11 @@
 {
     if (! done) {
         if (stateClock > 0 && ((stateClock & 1) == 0)) {
-	    endTimer(saveBuf, w, h, 1, 100);
+            //endTimer(100);
         }
-        doTest(w, h);
+        doTest();
         stateClock++;
     } else {
-	    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+            glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
     }
 }