Benchmarks can be rendered onscreen or off. Also added a script to plot results.

Change-Id: I269a0f4d7a91b4397f28354a350c214e5c0358d4
diff --git a/suite/pts/deviceTests/opengl/jni/GLNative.cpp b/suite/pts/deviceTests/opengl/jni/GLNative.cpp
index 28e8265..bd132b9 100644
--- a/suite/pts/deviceTests/opengl/jni/GLNative.cpp
+++ b/suite/pts/deviceTests/opengl/jni/GLNative.cpp
@@ -44,16 +44,13 @@
     // Sets up the renderer.
     bool success = gRenderer->setUp();
 
-    // Draw to the screen. This allows debugging and also warms up the HW.
-    success = success && gRenderer->draw(false);
-
     // Records the start time.
     double start = currentTimeMillis();
 
     // Draw off the screen.
     for (int i = 0; i < numFrames && success; i++) {
         // Draw a frame.
-        success = gRenderer->draw(true);
+        success = gRenderer->draw();
     }
 
     // Records the end time.
@@ -73,24 +70,28 @@
 // The following functions create the renderers for the various benchmarks.
 extern "C" JNIEXPORT void JNICALL
 Java_com_android_pts_opengl_primitive_GLActivity_setupFullPipelineBenchmark(
-        JNIEnv* env, jclass clazz, jobject surface, jint workload) {
-    gRenderer = new FullPipelineRenderer(ANativeWindow_fromSurface(env, surface), workload);
+        JNIEnv* env, jclass clazz, jobject surface, jboolean offscreen, jint workload) {
+    gRenderer = new FullPipelineRenderer(
+            ANativeWindow_fromSurface(env, surface), offscreen, workload);
 }
 
 extern "C" JNIEXPORT void JNICALL
 Java_com_android_pts_opengl_primitive_GLActivity_setupPixelOutputBenchmark(
-        JNIEnv* env, jclass clazz, jobject surface, jint workload) {
-    gRenderer = new PixelOutputRenderer(ANativeWindow_fromSurface(env, surface), workload);
+        JNIEnv* env, jclass clazz, jobject surface, jboolean offscreen, jint workload) {
+    gRenderer = new PixelOutputRenderer(
+            ANativeWindow_fromSurface(env, surface), offscreen, workload);
 }
 
 extern "C" JNIEXPORT void JNICALL
 Java_com_android_pts_opengl_primitive_GLActivity_setupShaderPerfBenchmark(
-        JNIEnv* env, jclass clazz, jobject surface, jint workload) {
-    gRenderer = new ShaderPerfRenderer(ANativeWindow_fromSurface(env, surface), workload);
+        JNIEnv* env, jclass clazz, jobject surface, jboolean offscreen, jint workload) {
+    gRenderer = new ShaderPerfRenderer(
+            ANativeWindow_fromSurface(env, surface), offscreen, workload);
 }
 
 extern "C" JNIEXPORT void JNICALL
 Java_com_android_pts_opengl_primitive_GLActivity_setupContextSwitchBenchmark(
-        JNIEnv* env, jclass clazz, jobject surface, jint workload) {
-    gRenderer = new ContextSwitchRenderer(ANativeWindow_fromSurface(env, surface), workload);
+        JNIEnv* env, jclass clazz, jobject surface, jboolean offscreen, jint workload) {
+    gRenderer = new ContextSwitchRenderer(
+            ANativeWindow_fromSurface(env, surface), offscreen, workload);
 }
diff --git a/suite/pts/deviceTests/opengl/jni/Renderer.cpp b/suite/pts/deviceTests/opengl/jni/Renderer.cpp
index 70445dc..0f5c3ba 100644
--- a/suite/pts/deviceTests/opengl/jni/Renderer.cpp
+++ b/suite/pts/deviceTests/opengl/jni/Renderer.cpp
@@ -33,10 +33,9 @@
         EGL_STENCIL_SIZE, 8,
         EGL_NONE };
 
-Renderer::Renderer(ANativeWindow* window, int workload) :
-        mEglDisplay(EGL_NO_DISPLAY), mEglSurface(EGL_NO_SURFACE), mEglContext(EGL_NO_CONTEXT) {
-    mWindow = window;
-    mWorkload = workload;
+Renderer::Renderer(ANativeWindow* window, bool offscreen, int workload) :
+        mWindow(window), mEglDisplay(EGL_NO_DISPLAY), mEglSurface(EGL_NO_SURFACE),
+        mEglContext(EGL_NO_CONTEXT), mOffscreen(offscreen), mWorkload(workload) {
 }
 
 bool Renderer::setUp() {
@@ -83,10 +82,16 @@
 
     glViewport(0, 0, width, height);
 
-    int w = GLUtils::roundUpToSmallestPowerOf2(width);
-    int h = GLUtils::roundUpToSmallestPowerOf2(height);
-    if (!createFBO(mFboId, mRboId, mCboId, w, h)) {
-        return false;
+    if (mOffscreen) {
+        int w = GLUtils::roundUpToSmallestPowerOf2(width);
+        int h = GLUtils::roundUpToSmallestPowerOf2(height);
+        if (!createFBO(mFboId, mRboId, mCboId, w, h)) {
+            return false;
+        }
+    } else {
+        mFboId = 0;
+        mRboId = 0;
+        mCboId = 0;
     }
 
     GLuint err = glGetError();
diff --git a/suite/pts/deviceTests/opengl/jni/Renderer.h b/suite/pts/deviceTests/opengl/jni/Renderer.h
index 10e179a..a50d81c 100644
--- a/suite/pts/deviceTests/opengl/jni/Renderer.h
+++ b/suite/pts/deviceTests/opengl/jni/Renderer.h
@@ -22,10 +22,10 @@
 
 class Renderer {
 public:
-    Renderer(ANativeWindow* window, int workload);
+    Renderer(ANativeWindow* window, bool offscreen, int workload);
     virtual bool setUp();
     virtual bool tearDown();
-    virtual bool draw(bool offscreen) = 0;
+    virtual bool draw() = 0;
     virtual ~Renderer() {};
 protected:
     bool createFBO(GLuint& fboId, GLuint& rboId, GLuint& cboId, int width, int height);
@@ -37,9 +37,10 @@
     GLuint mFboId; //Frame buffer
     GLuint mRboId; //Depth buffer
     GLuint mCboId; //Color buffer
-    GLuint mProgram;
+    GLuint mProgramId;
     EGLint width;
     EGLint height;
+    bool mOffscreen;
     int mWorkload;
 };
 #endif
diff --git a/suite/pts/deviceTests/opengl/jni/contextswitch/ContextSwitchRenderer.cpp b/suite/pts/deviceTests/opengl/jni/contextswitch/ContextSwitchRenderer.cpp
index f69a9f5..8e4b7e2 100644
--- a/suite/pts/deviceTests/opengl/jni/contextswitch/ContextSwitchRenderer.cpp
+++ b/suite/pts/deviceTests/opengl/jni/contextswitch/ContextSwitchRenderer.cpp
@@ -65,8 +65,8 @@
         "  gl_FragColor = texture2D(u_Texture, v_TexCoord);"
         "}";
 
-ContextSwitchRenderer::ContextSwitchRenderer(ANativeWindow* window, int workload) :
-        Renderer(window, workload), mContexts(NULL) {
+ContextSwitchRenderer::ContextSwitchRenderer(ANativeWindow* window, bool offscreen, int workload) :
+        Renderer(window, offscreen, workload), mContexts(NULL) {
 }
 
 bool ContextSwitchRenderer::setUp() {
@@ -83,13 +83,15 @@
 
     mContexts = new EGLContext[mWorkload];
     mTextureIds = new GLuint[mWorkload];
-    mFboIds = new GLuint[mWorkload];
-    mRboIds = new GLuint[mWorkload];
-    mCboIds = new GLuint[mWorkload];
-    mPrograms = new GLuint[mWorkload];
+    mProgramIds = new GLuint[mWorkload];
     mTextureUniformHandles = new GLuint[mWorkload];
     mPositionHandles = new GLuint[mWorkload];
     mTexCoordHandles = new GLuint[mWorkload];
+    if (mOffscreen) {
+        mFboIds = new GLuint[mWorkload];
+        mRboIds = new GLuint[mWorkload];
+        mCboIds = new GLuint[mWorkload];
+    }
     for (int i = 0; i < mWorkload; i++) {
         mContexts[i] = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT, contextAttribs);
         if (EGL_NO_CONTEXT == mContexts[i] || EGL_SUCCESS != eglGetError()) {
@@ -101,26 +103,28 @@
             return false;
         }
 
-        // Setup FBOs.
-        if (!Renderer::createFBO(mFboIds[i], mRboIds[i], mCboIds[i], w, h)) {
-            return false;
+        if (mOffscreen) {
+            // Setup FBOs.
+            if (!Renderer::createFBO(mFboIds[i], mRboIds[i], mCboIds[i], w, h)) {
+                return false;
+            }
         }
 
         // Setup textures.
-        mTextureIds[i] = GLUtils::genRandTex(width, height);
+        mTextureIds[i] = GLUtils::genRandTex(2, 2);
         if (mTextureIds[i] == 0) {
             return false;
         }
 
         // Create program.
-        mPrograms[i] = GLUtils::createProgram(&CS_VERTEX, &CS_FRAGMENT);
-        if (mPrograms[i] == 0) {
+        mProgramIds[i] = GLUtils::createProgram(&CS_VERTEX, &CS_FRAGMENT);
+        if (mProgramIds[i] == 0) {
             return false;
         }
         // Bind attributes.
-        mTextureUniformHandles[i] = glGetUniformLocation(mPrograms[i], "u_Texture");
-        mPositionHandles[i] = glGetAttribLocation(mPrograms[i], "a_Position");
-        mTexCoordHandles[i] = glGetAttribLocation(mPrograms[i], "a_TexCoord");
+        mTextureUniformHandles[i] = glGetUniformLocation(mProgramIds[i], "u_Texture");
+        mPositionHandles[i] = glGetAttribLocation(mProgramIds[i], "a_Position");
+        mTexCoordHandles[i] = glGetAttribLocation(mProgramIds[i], "a_TexCoord");
     }
 
     GLuint err = glGetError();
@@ -139,17 +143,19 @@
         }
         delete[] mContexts;
     }
-    if (mFboIds) {
-        glDeleteFramebuffers(mWorkload, mFboIds);
-        delete[] mFboIds;
-    }
-    if (mRboIds) {
-        glDeleteRenderbuffers(mWorkload, mRboIds);
-        delete[] mRboIds;
-    }
-    if (mCboIds) {
-        glDeleteRenderbuffers(mWorkload, mCboIds);
-        delete[] mCboIds;
+    if (mOffscreen) {
+        if (mFboIds) {
+            glDeleteFramebuffers(mWorkload, mFboIds);
+            delete[] mFboIds;
+        }
+        if (mRboIds) {
+            glDeleteRenderbuffers(mWorkload, mRboIds);
+            delete[] mRboIds;
+        }
+        if (mCboIds) {
+            glDeleteRenderbuffers(mWorkload, mCboIds);
+            delete[] mCboIds;
+        }
     }
     if (mTextureIds) {
         glDeleteTextures(mWorkload, mTextureIds);
@@ -161,22 +167,25 @@
     return true;
 }
 
-bool ContextSwitchRenderer::draw(bool offscreen) {
+bool ContextSwitchRenderer::draw() {
     for (int i = 0; i < mWorkload; i++) {
         if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mContexts[i])
                 || EGL_SUCCESS != eglGetError()) {
             return false;
         }
-        glBindFramebuffer(GL_FRAMEBUFFER, (offscreen) ? mFboIds[i] : 0);
-        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
-            return false;
+
+        if (mOffscreen) {
+            glBindFramebuffer(GL_FRAMEBUFFER, mFboIds[i]);
+            if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+                return false;
+            }
         }
 
         glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
         glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
 
-        glUseProgram(mPrograms[i]);
-        glActiveTexture (GL_TEXTURE0);
+        glUseProgram(mProgramIds[i]);
+        glActiveTexture(GL_TEXTURE0);
         // Bind the texture to this unit.
         glBindTexture(GL_TEXTURE_2D, mTextureIds[i]);
 
@@ -199,5 +208,5 @@
         return false;
     }
 
-    return (offscreen) ? true : eglSwapBuffers(mEglDisplay, mEglSurface);
+    return (mOffscreen) ? true : eglSwapBuffers(mEglDisplay, mEglSurface);
 }
diff --git a/suite/pts/deviceTests/opengl/jni/contextswitch/ContextSwitchRenderer.h b/suite/pts/deviceTests/opengl/jni/contextswitch/ContextSwitchRenderer.h
index c2ef8e1..3dfe9f3 100644
--- a/suite/pts/deviceTests/opengl/jni/contextswitch/ContextSwitchRenderer.h
+++ b/suite/pts/deviceTests/opengl/jni/contextswitch/ContextSwitchRenderer.h
@@ -18,11 +18,11 @@
 
 class ContextSwitchRenderer: public Renderer {
 public:
-    ContextSwitchRenderer(ANativeWindow* window, int workload);
+    ContextSwitchRenderer(ANativeWindow* window, bool offscreen, int workload);
     virtual ~ContextSwitchRenderer() {};
     bool setUp();
     bool tearDown();
-    bool draw(bool offscreen);
+    bool draw();
 private:
     GLuint mTextureUniformHandle;
     GLuint mPositionHandle;
@@ -32,7 +32,7 @@
     GLuint* mFboIds;
     GLuint* mRboIds;
     GLuint* mCboIds;
-    GLuint* mPrograms;
+    GLuint* mProgramIds;
     GLuint* mTextureUniformHandles;
     GLuint* mPositionHandles;
     GLuint* mTexCoordHandles;
diff --git a/suite/pts/deviceTests/opengl/jni/fullpipeline/FullPipelineRenderer.cpp b/suite/pts/deviceTests/opengl/jni/fullpipeline/FullPipelineRenderer.cpp
index 35389d2..c2ffecc 100644
--- a/suite/pts/deviceTests/opengl/jni/fullpipeline/FullPipelineRenderer.cpp
+++ b/suite/pts/deviceTests/opengl/jni/fullpipeline/FullPipelineRenderer.cpp
@@ -95,9 +95,9 @@
         "  gl_FragColor = (diffuse * texture2D(u_Texture, v_TexCoordinate));\n"
         "}";
 
-FullPipelineRenderer::FullPipelineRenderer(ANativeWindow* window, int workload) :
-        Renderer(window, workload), mProgram(NULL), mSceneGraph(NULL), mModelMatrix(NULL),
-        mViewMatrix(NULL), mProjectionMatrix(NULL), mMesh(NULL) {
+FullPipelineRenderer::FullPipelineRenderer(ANativeWindow* window, bool offscreen, int workload) :
+        Renderer(window, offscreen, workload), mProgram(NULL), mSceneGraph(NULL),
+        mModelMatrix(NULL), mViewMatrix(NULL), mProjectionMatrix(NULL), mMesh(NULL) {
 }
 
 bool FullPipelineRenderer::setUp() {
@@ -105,10 +105,10 @@
         return false;
     }
 
-    GLuint programId = GLUtils::createProgram(&FP_VERTEX, &FP_FRAGMENT);
-    if (programId == 0)
+    mProgramId = GLUtils::createProgram(&FP_VERTEX, &FP_FRAGMENT);
+    if (mProgramId == 0)
         return false;
-    mProgram = new FullPipelineProgram(programId);
+    mProgram = new FullPipelineProgram(mProgramId);
 
     mModelMatrix = new Matrix();
 
@@ -191,14 +191,16 @@
     return true;
 }
 
-bool FullPipelineRenderer::draw(bool offscreen) {
-    glBindFramebuffer(GL_FRAMEBUFFER, (offscreen) ? mFboId : 0);
+bool FullPipelineRenderer::draw() {
+    if (mOffscreen) {
+        glBindFramebuffer(GL_FRAMEBUFFER, mFboId);
+    }
     // Set the background clear color to black.
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
     // Use culling to remove back faces.
-    glEnable (GL_CULL_FACE);
+    glEnable(GL_CULL_FACE);
     // Use depth testing.
-    glEnable (GL_DEPTH_TEST);
+    glEnable(GL_DEPTH_TEST);
     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
     mModelMatrix->identity();
     mSceneGraph->draw(*mProgram, *mModelMatrix, *mViewMatrix, *mProjectionMatrix);
@@ -209,7 +211,7 @@
         return false;
     }
 
-    if (offscreen) {
+    if (mOffscreen) {
         glFinish();
         return true;
     } else {
diff --git a/suite/pts/deviceTests/opengl/jni/fullpipeline/FullPipelineRenderer.h b/suite/pts/deviceTests/opengl/jni/fullpipeline/FullPipelineRenderer.h
index 61a732262..0c5acae 100644
--- a/suite/pts/deviceTests/opengl/jni/fullpipeline/FullPipelineRenderer.h
+++ b/suite/pts/deviceTests/opengl/jni/fullpipeline/FullPipelineRenderer.h
@@ -23,11 +23,11 @@
 
 class FullPipelineRenderer: public Renderer {
 public:
-    FullPipelineRenderer(ANativeWindow* window, int workload);
+    FullPipelineRenderer(ANativeWindow* window, bool offscreen, int workload);
     virtual ~FullPipelineRenderer() {};
     bool setUp();
     bool tearDown();
-    bool draw(bool offscreen);
+    bool draw();
 private:
     FullPipelineProgram* mProgram;
     ProgramNode* mSceneGraph;
diff --git a/suite/pts/deviceTests/opengl/jni/pixeloutput/PixelOutputRenderer.cpp b/suite/pts/deviceTests/opengl/jni/pixeloutput/PixelOutputRenderer.cpp
index cfddafa..95bf52b 100644
--- a/suite/pts/deviceTests/opengl/jni/pixeloutput/PixelOutputRenderer.cpp
+++ b/suite/pts/deviceTests/opengl/jni/pixeloutput/PixelOutputRenderer.cpp
@@ -52,8 +52,8 @@
         "  gl_FragColor = texture2D(u_Texture, v_TexCoord);"
         "}";
 
-PixelOutputRenderer::PixelOutputRenderer(ANativeWindow* window, int workload) :
-        Renderer(window, workload) {
+PixelOutputRenderer::PixelOutputRenderer(ANativeWindow* window, bool offscreen, int workload) :
+        Renderer(window, offscreen, workload) {
 }
 
 bool PixelOutputRenderer::setUp() {
@@ -62,13 +62,13 @@
     }
 
     // Create program.
-    mProgram = GLUtils::createProgram(&PO_VERTEX, &PO_FRAGMENT);
-    if (mProgram == 0)
+    mProgramId = GLUtils::createProgram(&PO_VERTEX, &PO_FRAGMENT);
+    if (mProgramId == 0)
         return false;
     // Bind attributes.
-    mTextureUniformHandle = glGetUniformLocation(mProgram, "u_Texture");
-    mPositionHandle = glGetAttribLocation(mProgram, "a_Position");
-    mTexCoordHandle = glGetAttribLocation(mProgram, "a_TexCoord");
+    mTextureUniformHandle = glGetUniformLocation(mProgramId, "u_Texture");
+    mPositionHandle = glGetAttribLocation(mProgramId, "a_Position");
+    mTexCoordHandle = glGetAttribLocation(mProgramId, "a_TexCoord");
 
     // Setup texture.
     mTextureId = GLUtils::genRandTex(width, height);
@@ -89,9 +89,11 @@
     return true;
 }
 
-bool PixelOutputRenderer::draw(bool offscreen) {
-    glBindFramebuffer(GL_FRAMEBUFFER, (offscreen) ? mFboId : 0);
-    glUseProgram (mProgram);
+bool PixelOutputRenderer::draw() {
+    if (mOffscreen) {
+        glBindFramebuffer(GL_FRAMEBUFFER, mFboId);
+    }
+    glUseProgram(mProgramId);
     // Set the background clear color to black.
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
@@ -106,7 +108,7 @@
     glEnable(GL_BLEND);
     glBlendFunc(GL_ONE, GL_ONE);
 
-    glActiveTexture (GL_TEXTURE0);
+    glActiveTexture(GL_TEXTURE0);
     // Bind the texture to this unit.
     glBindTexture(GL_TEXTURE_2D, mTextureId);
     // Tell the texture uniform sampler to use this texture in the shader by binding to texture
@@ -128,7 +130,7 @@
         return false;
     }
 
-    if (offscreen) {
+    if (mOffscreen) {
         glFinish();
         return true;
     } else {
diff --git a/suite/pts/deviceTests/opengl/jni/pixeloutput/PixelOutputRenderer.h b/suite/pts/deviceTests/opengl/jni/pixeloutput/PixelOutputRenderer.h
index ed631e2..6422517 100644
--- a/suite/pts/deviceTests/opengl/jni/pixeloutput/PixelOutputRenderer.h
+++ b/suite/pts/deviceTests/opengl/jni/pixeloutput/PixelOutputRenderer.h
@@ -18,11 +18,11 @@
 
 class PixelOutputRenderer: public Renderer {
 public:
-    PixelOutputRenderer(ANativeWindow* window, int workload);
+    PixelOutputRenderer(ANativeWindow* window, bool offscreen, int workload);
     virtual ~PixelOutputRenderer() {};
     bool setUp();
     bool tearDown();
-    bool draw(bool offscreen);
+    bool draw();
 private:
     GLuint mTextureId;
     GLuint mTextureUniformHandle;
diff --git a/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.cpp b/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.cpp
index bbb5f68..a3fea22 100644
--- a/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.cpp
+++ b/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.cpp
@@ -42,8 +42,8 @@
                                 "  gl_FragColor = v_Position;"
                                 "}";
 
-ShaderPerfRenderer::ShaderPerfRenderer(ANativeWindow* window, int workload) :
-        Renderer(window, workload) {
+ShaderPerfRenderer::ShaderPerfRenderer(ANativeWindow* window, bool offscreen, int workload) :
+        Renderer(window, offscreen, workload) {
 }
 
 bool ShaderPerfRenderer::setUp() {
@@ -51,17 +51,19 @@
         return false;
     }
     // Create program.
-    mProgram = GLUtils::createProgram(&SP_VERTEX, &SP_FRAGMENT);
-    if (mProgram == 0)
+    mProgramId = GLUtils::createProgram(&SP_VERTEX, &SP_FRAGMENT);
+    if (mProgramId == 0)
         return false;
     // Bind attributes.
-    mPositionHandle = glGetAttribLocation(mProgram, "a_Position");
+    mPositionHandle = glGetAttribLocation(mProgramId, "a_Position");
     return true;
 }
 
-bool ShaderPerfRenderer::draw(bool offscreen) {
-    glBindFramebuffer(GL_FRAMEBUFFER, (offscreen) ? mFboId : 0);
-    glUseProgram(mProgram);
+bool ShaderPerfRenderer::draw() {
+    if (mOffscreen) {
+        glBindFramebuffer(GL_FRAMEBUFFER, mFboId);
+    }
+    glUseProgram(mProgramId);
     // Set the background clear color to black.
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
@@ -80,7 +82,7 @@
         return false;
     }
 
-    if (offscreen) {
+    if (mOffscreen) {
         glFinish();
         return true;
     } else {
diff --git a/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.h b/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.h
index 2e5cb98..22e0420 100644
--- a/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.h
+++ b/suite/pts/deviceTests/opengl/jni/shaderperf/ShaderPerfRenderer.h
@@ -18,10 +18,10 @@
 
 class ShaderPerfRenderer: public Renderer {
 public:
-    ShaderPerfRenderer(ANativeWindow* window, int workload);
+    ShaderPerfRenderer(ANativeWindow* window, bool offscreen, int workload);
     virtual ~ShaderPerfRenderer() {};
     bool setUp();
-    bool draw(bool offscreen);
+    bool draw();
 private:
     GLuint mPositionHandle;
 };
diff --git a/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLActivity.java b/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLActivity.java
index 5f75cbb..dece656 100644
--- a/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLActivity.java
+++ b/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLActivity.java
@@ -25,6 +25,8 @@
 import com.android.pts.util.ResultType;
 import com.android.pts.util.ResultUnit;
 
+import java.util.ArrayList;
+
 public class GLActivity extends Activity {
 
     public final static String TAG = "GLActivity";
@@ -33,6 +35,10 @@
      */
     public final static String INTENT_EXTRA_BENCHMARK_NAME = "benchmark_name";
     /**
+     * Holds whether or not the benchmark is to be run offscreen.
+     */
+    public final static String INTENT_EXTRA_OFFSCREEN = "offscreen";
+    /**
      * Holds the number of milliseconds to wait before timing out.
      */
     public final static String INTENT_EXTRA_TIMEOUT = "timeout";
@@ -50,22 +56,27 @@
     private volatile Surface mSurface;
 
     private Benchmark mBenchmark;
+    private boolean mOffscreen;
     private int mTimeout;
-    private double mMinFps;
+    private int mMinFps;
     private int mNumFrames;
     private volatile int mWorkload = 0;
 
+    public ArrayList<Double> fpsValues = new ArrayList<Double>();
+
     @Override
     public void onCreate(Bundle data) {
         super.onCreate(data);
         System.loadLibrary("ptsopengl_jni");
         Intent intent = getIntent();
         mBenchmark = Benchmark.valueOf(intent.getStringExtra(INTENT_EXTRA_BENCHMARK_NAME));
+        mOffscreen = intent.getBooleanExtra(INTENT_EXTRA_OFFSCREEN, false);
         mTimeout = intent.getIntExtra(INTENT_EXTRA_TIMEOUT, 0);
-        mMinFps = intent.getDoubleExtra(INTENT_EXTRA_MIN_FPS, 0);
+        mMinFps = intent.getIntExtra(INTENT_EXTRA_MIN_FPS, 0);
         mNumFrames = intent.getIntExtra(INTENT_EXTRA_NUM_FRAMES, 0);
 
         Log.i(TAG, "Benchmark: " + mBenchmark);
+        Log.i(TAG, "Offscreen: " + mOffscreen);
         Log.i(TAG, "Time Out: " + mTimeout);
         Log.i(TAG, "Min FPS: " + mMinFps);
         Log.i(TAG, "Num Frames: " + mNumFrames);
@@ -97,13 +108,17 @@
         return mWorkload;
     }
 
-    private static native void setupFullPipelineBenchmark(Surface surface, int workload);
+    private static native void setupFullPipelineBenchmark(
+            Surface surface, boolean offscreen, int workload);
 
-    private static native void setupPixelOutputBenchmark(Surface surface, int workload);
+    private static native void setupPixelOutputBenchmark(
+            Surface surface, boolean offscreen, int workload);
 
-    private static native void setupShaderPerfBenchmark(Surface surface, int workload);
+    private static native void setupShaderPerfBenchmark(
+            Surface surface, boolean offscreen, int workload);
 
-    private static native void setupContextSwitchBenchmark(Surface surface, int workload);
+    private static native void setupContextSwitchBenchmark(
+            Surface surface, boolean offscreen, int workload);
 
     private static native boolean startBenchmark(int numFrames, double[] frameTimes);
 
@@ -127,16 +142,16 @@
                 // Setup the benchmark.
                 switch (mBenchmark) {
                     case FullPipeline:
-                        setupFullPipelineBenchmark(mSurface, wl);
+                        setupFullPipelineBenchmark(mSurface, mOffscreen, wl);
                         break;
                     case PixelOutput:
-                        setupPixelOutputBenchmark(mSurface, wl);
+                        setupPixelOutputBenchmark(mSurface, mOffscreen, wl);
                         break;
                     case ShaderPerf:
-                        setupShaderPerfBenchmark(mSurface, wl);
+                        setupShaderPerfBenchmark(mSurface, mOffscreen, wl);
                         break;
                     case ContextSwitch:
-                        setupContextSwitchBenchmark(mSurface, wl);
+                        setupContextSwitchBenchmark(mSurface, mOffscreen, wl);
                         break;
                 }
                 watchDog.start();
@@ -150,8 +165,7 @@
                     // Calculate FPS.
                     double totalTimeTaken = times[1] - times[0];
                     double meanFps = mNumFrames * 1000.0f / totalTimeTaken;
-                    Log.i(TAG, "Workload: " + wl);
-                    Log.i(TAG, "Mean FPS: " + meanFps);
+                    fpsValues.add(meanFps);
                     if (meanFps >= mMinFps) {
                         // Iteration passed, proceed to next one.
                         mWorkload++;
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 e944b9a..bb63ee8 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
@@ -22,52 +22,72 @@
 import android.opengl.Matrix;
 import android.util.Log;
 import java.util.Arrays;
+
 /**
  * Runs the Primitive OpenGL ES 2.0 Benchmarks.
  */
 public class GLBenchmark extends PtsActivityInstrumentationTestCase2<GLActivity> {
 
-    private static final double MIN_FPS = 50;
-
     public GLBenchmark() {
         super(GLActivity.class);
     }
 
     /**
-     * Runs the full OpenGL ES 2.0 pipeline test.
-     *
-     * @throws Exception If the benchmark could not be run.
+     * Runs the full OpenGL ES 2.0 pipeline test offscreen.
      */
-    public void testFullPipeline() throws Exception {
-        runBenchmark(Benchmark.FullPipeline, 500, 50000, 1);
+    public void testFullPipelineOffscreen() throws Exception {
+        runBenchmark(Benchmark.FullPipeline, true, 500, 100000, 25, 0);
     }
 
     /**
-     * Runs the pixel output test.
-     *
-     * @throws Exception If the benchmark could not be run.
+     * Runs the full OpenGL ES 2.0 pipeline test onscreen.
      */
-    public void testPixelOutput() throws Exception {
-        runBenchmark(Benchmark.PixelOutput, 500, 50000, 1);
+    public void testFullPipelineOnscreen() throws Exception {
+        runBenchmark(Benchmark.FullPipeline, false, 500, 100000, 25, 0);
     }
 
     /**
-     * Runs the shader performance test.
-     *
-     * @throws Exception If the benchmark could not be run.
+     * Runs the pixel output test offscreen.
      */
-    public void testShaderPerf() throws Exception {
+    public void testPixelOutputOffscreen() throws Exception {
+        runBenchmark(Benchmark.PixelOutput, true, 500, 100000, 25, 0);
+    }
+
+    /**
+     * Runs the pixel output test onscreen.
+     */
+    public void testPixelOutputOnscreen() throws Exception {
+        runBenchmark(Benchmark.PixelOutput, false, 500, 100000, 25, 0);
+    }
+
+    /**
+     * Runs the shader performance test offscreen.
+     */
+    public void testShaderPerfOffscreen() throws Exception {
         // TODO(stuartscott): Not yet implemented
-        // runBenchmark(Benchmark.ShaderPerf, 500, 50000, 1);
+        // runBenchmark(Benchmark.ShaderPerf, true, 500, 100000, 25, 0);
     }
 
     /**
-     * Runs the OpenGL context switch overhead test.
-     *
-     * @throws Exception If the benchmark could not be run.
+     * Runs the shader performance test onscreen.
      */
-    public void testContextSwitch() throws Exception {
-        runBenchmark(Benchmark.ContextSwitch, 500, 50000, 1);
+    public void testShaderPerfOnscreen() throws Exception {
+        // TODO(stuartscott): Not yet implemented
+        // runBenchmark(Benchmark.ShaderPerf, false, 500, 100000, 25, 0);
+    }
+
+    /**
+     * Runs the context switch overhead test offscreen.
+     */
+    public void testContextSwitchOffscreen() throws Exception {
+        runBenchmark(Benchmark.ContextSwitch, true, 500, 100000, 25, 0);
+    }
+
+    /**
+     * Runs the context switch overhead test onscreen.
+     */
+    public void testContextSwitchOnscreen() throws Exception {
+        runBenchmark(Benchmark.ContextSwitch, false, 500, 100000, 25, 0);
     }
 
     /**
@@ -78,13 +98,18 @@
      * @param timeout The milliseconds to wait for an iteration of the benchmark before timing out.
      * @throws Exception If the benchmark could not be run.
      */
-    private void runBenchmark(Benchmark benchmark, int numFrames, int timeout, int target)
-            throws Exception {
+    private void runBenchmark(Benchmark benchmark,
+            boolean offscreen,
+            int numFrames,
+            int timeout,
+            int minFps,
+            int target) throws Exception {
         String benchmarkName = benchmark.toString();
         Intent intent = new Intent();
         intent.putExtra(GLActivity.INTENT_EXTRA_BENCHMARK_NAME, benchmarkName);
+        intent.putExtra(GLActivity.INTENT_EXTRA_OFFSCREEN, offscreen);
         intent.putExtra(GLActivity.INTENT_EXTRA_TIMEOUT, timeout);
-        intent.putExtra(GLActivity.INTENT_EXTRA_MIN_FPS, MIN_FPS);
+        intent.putExtra(GLActivity.INTENT_EXTRA_MIN_FPS, minFps);
         intent.putExtra(GLActivity.INTENT_EXTRA_NUM_FRAMES, numFrames);
 
         GLActivity activity = null;
@@ -94,9 +119,9 @@
             // Represents the maximum workload it can do whilst maintaining MIN_FPS.
             int workload = activity.waitForCompletion();
             if (workload < target) {
-                throw new Exception("Benchmark did not reach target. Got " + workload
-                        + ", target was " + target);
+                throw new Exception("Benchmark did not reach " + target + ", got " + workload);
             }
+            Log.i(GLActivity.TAG, "FPS Values: " + activity.fpsValues);
             getReportLog()
                     .printSummary("Workload", workload, ResultType.HIGHER_BETTER, ResultUnit.SCORE);
         } finally {