Implementing Shader Perf Benchmark as a fractal.

And tuned some other benchmarks.

Change-Id: I290540c3580fb7d8ab2b4577e00a1dd1a2ec55b4
diff --git a/suite/pts/deviceTests/opengl/jni/GLUtils.cpp b/suite/pts/deviceTests/opengl/jni/GLUtils.cpp
index f62f5b8..9e75f2c 100644
--- a/suite/pts/deviceTests/opengl/jni/GLUtils.cpp
+++ b/suite/pts/deviceTests/opengl/jni/GLUtils.cpp
@@ -15,6 +15,10 @@
 #include <GLUtils.h>
 #include <stdlib.h>
 
+#define LOG_TAG "PTS_OPENGL"
+#define LOG_NDEBUG 0
+#include "utils/Log.h"
+
 // Loads the given source code as a shader of the given type.
 static GLuint loadShader(GLenum shaderType, const char** source) {
     GLuint shader = glCreateShader(shaderType);
@@ -24,6 +28,14 @@
         GLint compiled = 0;
         glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
         if (!compiled) {
+            GLint infoLen = 0;
+            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+            if (infoLen > 0) {
+                char* infoLog = (char*) malloc(sizeof(char) * infoLen);
+                glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
+                ALOGE("Error compiling shader:\n%s\n", infoLog);
+                free(infoLog);
+            }
             glDeleteShader(shader);
             shader = 0;
         }
@@ -38,29 +50,29 @@
         return 0;
     }
 
-    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource);
-    if (!pixelShader) {
+    GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource);
+    if (!fragmentShader) {
         return 0;
     }
 
     GLuint program = glCreateProgram();
     if (program) {
-        bool success = true;
         glAttachShader(program, vertexShader);
-        if (GLenum(GL_NO_ERROR) != glGetError()) {
-            success = false;
-        }
-        glAttachShader(program, pixelShader);
-        if (GLenum(GL_NO_ERROR) != glGetError()) {
-            success = false;
-        }
+        glAttachShader(program, fragmentShader);
 
-        GLint linkStatus = GL_FALSE;
-        if (success) {
-            glLinkProgram(program);
-            glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
-        }
-        if (linkStatus != GL_TRUE || !success) {
+        GLint linkStatus;
+        glLinkProgram(program);
+        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+
+        if (!linkStatus) {
+            GLint infoLen = 0;
+            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
+            if (infoLen > 0) {
+                char* infoLog = (char*) malloc(sizeof(char) * infoLen);
+                glGetProgramInfoLog(program, infoLen, NULL, infoLog);
+                ALOGE("Error linking program:\n%s\n", infoLog);
+                free(infoLog);
+            }
             glDeleteProgram(program);
             program = 0;
         }
diff --git a/suite/pts/deviceTests/opengl/jni/fullpipeline/FullPipelineRenderer.cpp b/suite/pts/deviceTests/opengl/jni/fullpipeline/FullPipelineRenderer.cpp
index c2ffecc..4cab669 100644
--- a/suite/pts/deviceTests/opengl/jni/fullpipeline/FullPipelineRenderer.cpp
+++ b/suite/pts/deviceTests/opengl/jni/fullpipeline/FullPipelineRenderer.cpp
@@ -115,7 +115,7 @@
     // Position the eye in front of the origin.
     float eyeX = 0.0f;
     float eyeY = 0.0f;
-    float eyeZ = 2.0f;
+    float eyeZ = 1.5f;
 
     // We are looking at the origin
     float centerX = 0.0f;
@@ -138,7 +138,7 @@
     float bottom = -1.0f;
     float top = 1.0f;
     float near = 1.0f;
-    float far = 3.0f;
+    float far = 2.0f;
 
     mProjectionMatrix = Matrix::newFrustum(left, right, bottom, top, near, far);
 
diff --git a/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.cpp b/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.cpp
index a3fea22..6d98c9a 100644
--- a/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.cpp
+++ b/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.cpp
@@ -14,10 +14,14 @@
 #include "ShaderPerfRenderer.h"
 #include <GLUtils.h>
 
+#include <math.h>
+
 #define LOG_TAG "PTS_OPENGL"
 #define LOG_NDEBUG 0
 #include "utils/Log.h"
 
+static const float GOLDEN_RATIO = (1.0 + sqrt(5.0)) / 2.0;
+
 static const int SP_NUM_VERTICES = 6;
 
 static const float SP_VERTICES[SP_NUM_VERTICES * 3] = {
@@ -28,19 +32,66 @@
         1.0f, -1.0f, -1.0f,
         1.0f, 1.0f, -1.0f };
 
-static const char* SP_VERTEX = "attribute vec4 a_Position;"
-                              "varying vec4 v_Position;"
-                              "void main() {"
-                              "  v_Position = a_Position;"
-                              "  gl_Position = a_Position;"
-                              "}";
+static const float SP_TEX_COORDS[SP_NUM_VERTICES * 2] = {
+        1.0f, 1.0f,
+        0.0f, 1.0f,
+        0.0f, 0.0f,
+        0.0f, 0.0f,
+        1.0f, 0.0f,
+        1.0f, 1.0f };
 
-// TODO At the moment this a very simple shader. Later on this will get more complex.
-static const char* SP_FRAGMENT = "precision mediump float;"
-                                "varying vec4 v_Position;"
-                                "void main() {"
-                                "  gl_FragColor = v_Position;"
-                                "}";
+static const char* SP_VERTEX =
+        "attribute vec4 a_Position;"
+        "attribute vec2 a_TexCoord;"
+        "varying vec2 v_TexCoord;"
+        "void main() {"
+        "  v_TexCoord = a_TexCoord;"
+        "  gl_Position = a_Position;"
+        "}";
+
+static const char* SP_FRAGMENT_1 =
+        "precision mediump float;"
+        "uniform vec2 u_Seed;"
+        "uniform sampler2D u_Texture;"
+        "varying vec2 v_TexCoord;"
+        "void main() {"
+        "  int count = ";
+
+//Add workload here
+
+static const char* SP_FRAGMENT_2 =
+        " * 5;"//workload * 5 (5 is a balanced number, bigger = more work)
+        "  vec2 z;"
+        "  z.x = 3.0 * (v_TexCoord.x - 0.5);"
+        "  z.y = 2.0 * (v_TexCoord.y - 0.5);"
+        "  float u = 0.0;"
+        "  for (int i = 0; i < count; i++) {"
+        "    float x = (z.x * z.x - z.y * z.y) + u_Seed.x;"
+        "    float y = (z.y * z.x + z.x * z.y) + u_Seed.y;"
+        "    if (((x * x + y * y) > 4.0) && (u == 0.0)) {"
+        "      u = float(i) / float(count);"
+        "    }"
+        "    z.x = x;"
+        "    z.y = y;"
+        "  }"
+        "  gl_FragColor = texture2D(u_Texture, vec2(u, 0.0));"
+        "}";
+
+// Copies the source array from 0 up to and including the '\0' character to the
+// destination array starting from the given start position. Unlike strcpy, this
+// returns the number of characters which were copied.
+static int charCopy(const char* source, char* dest, int destStart) {
+    int srcAddr = 0;
+    int destAddr = destStart;
+    char current;
+    do {
+        current = source[srcAddr];
+        dest[destAddr] = current;
+        srcAddr++;
+        destAddr++;
+    } while (current != '\0');
+    return destAddr - destStart;
+}
 
 ShaderPerfRenderer::ShaderPerfRenderer(ANativeWindow* window, bool offscreen, int workload) :
         Renderer(window, offscreen, workload) {
@@ -50,12 +101,49 @@
     if (!Renderer::setUp()) {
         return false;
     }
+
+    const int MAX_FRAGMENT_SHADER_SIZE = 1000;
+    char* spFragment = new char[MAX_FRAGMENT_SHADER_SIZE];
+    // Add the first part.
+    int index = charCopy(SP_FRAGMENT_1, spFragment, 0);
+    // Add the count, overwriting the '\0' added by charCopy.
+    spFragment[index - 1] = (char) (((int) '0') + mWorkload);
+    // Add the second part.
+    index += charCopy(SP_FRAGMENT_2, spFragment, index);
     // Create program.
-    mProgramId = GLUtils::createProgram(&SP_VERTEX, &SP_FRAGMENT);
+    mProgramId = GLUtils::createProgram(&SP_VERTEX, const_cast<const char**>(&spFragment));
+    delete[] spFragment;
     if (mProgramId == 0)
         return false;
     // Bind attributes.
+    mTextureUniformHandle = glGetUniformLocation(mProgramId, "u_Texture");
+    mSeedUniformHandle = glGetUniformLocation(mProgramId, "u_Seed");
     mPositionHandle = glGetAttribLocation(mProgramId, "a_Position");
+    mTexCoordHandle = glGetAttribLocation(mProgramId, "a_TexCoord");
+
+    const int SIZE = 256;
+    uint32_t* m = new uint32_t[SIZE];
+    if (m != NULL) {
+        uint32_t* d = m;
+        for (int i = 0; i < SIZE; i++) {
+            *d = 0xff000000 | ((i & 0xff) << 16);
+            d++;
+        }
+        glGenTextures(1, &mTextureId);
+        glBindTexture(GL_TEXTURE_2D, mTextureId);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SIZE, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, m);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    }
+    delete[] m;
+
+    GLuint err = glGetError();
+    if (err != GL_NO_ERROR) {
+        ALOGV("GLError %d", err);
+        return false;
+    }
+
     return true;
 }
 
@@ -64,15 +152,26 @@
         glBindFramebuffer(GL_FRAMEBUFFER, mFboId);
     }
     glUseProgram(mProgramId);
-    // Set the background clear color to black.
+    // Set the background clear color.
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
 
     // No culling of back faces
     glDisable(GL_CULL_FACE);
 
+    // Bind the texture.
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, mTextureId);
+    glUniform1i(mTextureUniformHandle, 0);
+
+    // Bind the seed.
+    glUniform2f(mSeedUniformHandle, GOLDEN_RATIO - 2.0f, GOLDEN_RATIO - 1.0f);
+
+    // Bind the vertices.
     glEnableVertexAttribArray(mPositionHandle);
+    glEnableVertexAttribArray(mTexCoordHandle);
     glVertexAttribPointer(mPositionHandle, 3, GL_FLOAT, false, 0, SP_VERTICES);
+    glVertexAttribPointer(mTexCoordHandle, 2, GL_FLOAT, false, 0, SP_TEX_COORDS);
 
     glDrawArrays(GL_TRIANGLES, 0, SP_NUM_VERTICES);
 
diff --git a/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.h b/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.h
index 22e0420..4460174 100644
--- a/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.h
+++ b/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.h
@@ -23,7 +23,11 @@
     bool setUp();
     bool draw();
 private:
+    GLuint mTextureId;
+    GLuint mTextureUniformHandle;
     GLuint mPositionHandle;
+    GLuint mTexCoordHandle;
+    GLuint mSeedUniformHandle;
 };
 
 #endif
diff --git a/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLBenchmark.java b/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLBenchmark.java
index b1c9112..0eab7cd 100644
--- a/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLBenchmark.java
+++ b/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLBenchmark.java
@@ -67,16 +67,14 @@
      * Runs the shader performance test offscreen.
      */
     public void testShaderPerfOffscreen() throws Exception {
-        // TODO(stuartscott): Not yet implemented
-        // runBenchmark(Benchmark.ShaderPerf, true, 500, 8, 1000000);
+        runBenchmark(Benchmark.ShaderPerf, true, 500, 8, 1000000);
     }
 
     /**
      * Runs the shader performance test onscreen.
      */
     public void testShaderPerfOnscreen() throws Exception {
-        // TODO(stuartscott): Not yet implemented
-        // runBenchmark(Benchmark.ShaderPerf, false, 500, 8, 1000000);
+        runBenchmark(Benchmark.ShaderPerf, false, 500, 8, 1000000);
     }
 
     /**