Merge "save benchmark results"
diff --git a/tests/RenderScriptTests/PerfTest/AndroidManifest.xml b/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
index e024882..aafd176 100644
--- a/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
+++ b/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
@@ -1,6 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.perftest">
+    
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    
     <uses-sdk android:minSdkVersion="11" />
     <application android:label="PerfTest"
       android:icon="@drawable/test_pattern">
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
index 4d4adf6..7cd55fa 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
@@ -17,7 +17,14 @@
 package com.android.perftest;
 
 import java.io.Writer;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
 
+import android.os.Environment;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -36,9 +43,15 @@
 
 public class RsBenchRS {
 
+    private static final String TAG = "RsBenchRS";
+
     int mWidth;
     int mHeight;
     int mLoops;
+    int mCurrentLoop;
+
+    int mBenchmarkDimX;
+    int mBenchmarkDimY;
 
     public RsBenchRS() {
     }
@@ -53,6 +66,9 @@
         mMode = 0;
         mMaxModes = 0;
         mLoops = loops;
+        mCurrentLoop = 0;
+        mBenchmarkDimX = 1280;
+        mBenchmarkDimY = 720;
         initRS();
     }
 
@@ -120,25 +136,66 @@
     int mMode;
     int mMaxModes;
 
+    String[] mTestNames;
+    float[] mLocalTestResults;
+
     public void onActionDown(int x, int y) {
         mMode ++;
         mMode = mMode % mMaxModes;
         mScript.set_gDisplayMode(mMode);
     }
 
+    private void saveTestResults() {
+        String state = Environment.getExternalStorageState();
+        if (!Environment.MEDIA_MOUNTED.equals(state)) {
+            Log.v(TAG, "sdcard is read only");
+            return;
+        }
+        File sdCard = Environment.getExternalStorageDirectory();
+        if (!sdCard.canWrite()) {
+            Log.v(TAG, "ssdcard is read only");
+            return;
+        }
+
+        File resultFile = new File(sdCard, "rsbench_result" + mCurrentLoop + ".csv");
+        resultFile.setWritable(true, false);
+
+        try {
+            BufferedWriter results = new BufferedWriter(new FileWriter(resultFile));
+            for (int i = 0; i < mLocalTestResults.length; i ++) {
+                results.write(mTestNames[i] + ", " + mLocalTestResults[i] + ",\n");
+            }
+            results.close();
+            Log.v(TAG, "Saved results in: " + resultFile.getAbsolutePath());
+        } catch (IOException e) {
+            Log.v(TAG, "Unable to write result file " + e.getMessage());
+        }
+    }
+
     /**
      * Create a message handler to handle message sent from the script
      */
     protected RSMessageHandler mRsMessage = new RSMessageHandler() {
         public void run() {
-            if (mID == mScript.get_RS_MSG_TEST_DONE()) {
+            if (mID == mScript.get_RS_MSG_RESULTS_READY()) {
+                for (int i = 0; i < mLocalTestResults.length; i ++) {
+                    mLocalTestResults[i] = Float.intBitsToFloat(mData[i]);
+                }
+                saveTestResults();
+                if (mLoops > 0) {
+                    mCurrentLoop ++;
+                    mCurrentLoop = mCurrentLoop % mLoops;
+                }
+                return;
+
+            } else if (mID == mScript.get_RS_MSG_TEST_DONE()) {
                 synchronized(this) {
                     stopTest = true;
                     this.notifyAll();
                 }
                 return;
             } else {
-                Log.v("RsBenchRS", "Perf test got unexpected message");
+                Log.v(TAG, "Perf test got unexpected message");
                 return;
             }
         }
@@ -247,7 +304,7 @@
         mPVA = new ProgramVertexFixedFunction.Constants(mRS);
         ((ProgramVertexFixedFunction)mProgVertex).bindConstants(mPVA);
         Matrix4f proj = new Matrix4f();
-        proj.loadOrthoWindow(mWidth, mHeight);
+        proj.loadOrthoWindow(mBenchmarkDimX, mBenchmarkDimY);
         mPVA.setProjection(proj);
 
         mScript.set_gProgVertex(mProgVertex);
@@ -370,11 +427,11 @@
     }
 
     private void initMesh() {
-        m10by10Mesh = getMbyNMesh(mWidth, mHeight, 10, 10);
+        m10by10Mesh = getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, 10, 10);
         mScript.set_g10by10Mesh(m10by10Mesh);
-        m100by100Mesh = getMbyNMesh(mWidth, mHeight, 100, 100);
+        m100by100Mesh = getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, 100, 100);
         mScript.set_g100by100Mesh(m100by100Mesh);
-        mWbyHMesh= getMbyNMesh(mWidth, mHeight, mWidth/4, mHeight/4);
+        mWbyHMesh= getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, mBenchmarkDimX/4, mBenchmarkDimY/4);
         mScript.set_gWbyHMesh(mWbyHMesh);
 
         FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.torus);
@@ -427,6 +484,29 @@
         mScript.set_gCullNone(mCullNone);
     }
 
+    private int strlen(byte[] array) {
+        int count = 0;
+        while(count < array.length && array[count] != 0) {
+            count ++;
+        }
+        return count;
+    }
+
+    private void prepareTestData() {
+        mTestNames = new String[mMaxModes];
+        mLocalTestResults = new float[mMaxModes];
+        int scratchSize = 1024;
+        Allocation scratch = Allocation.createSized(mRS, Element.U8(mRS), scratchSize);
+        byte[] tmp = new byte[scratchSize];
+        mScript.bind_gStringBuffer(scratch);
+        for (int i = 0; i < mMaxModes; i ++) {
+            mScript.invoke_getTestName(i);
+            scratch.copyTo(tmp);
+            int len = strlen(tmp);
+            mTestNames[i] = new String(tmp, 0, len);
+        }
+    }
+
     private void initRS() {
 
         mScript = new ScriptC_rsbench(mRS, mRes, R.raw.rsbench);
@@ -435,6 +515,8 @@
         mMaxModes = mScript.get_gMaxModes();
         mScript.set_gMaxLoops(mLoops);
 
+        prepareTestData();
+
         initSamplers();
         initProgramStore();
         initProgramFragment();
@@ -446,7 +528,7 @@
         initCustomShaders();
 
         Type.Builder b = new Type.Builder(mRS, Element.RGBA_8888(mRS));
-        b.setX(1280).setY(720);
+        b.setX(mBenchmarkDimX).setY(mBenchmarkDimY);
         Allocation offscreen = Allocation.createTyped(mRS,
                                                       b.create(),
                                                       Allocation.USAGE_GRAPHICS_TEXTURE |
@@ -456,7 +538,7 @@
         b = new Type.Builder(mRS,
                              Element.createPixel(mRS, DataType.UNSIGNED_16,
                              DataKind.PIXEL_DEPTH));
-        b.setX(1280).setY(720);
+        b.setX(mBenchmarkDimX).setY(mBenchmarkDimY);
         offscreen = Allocation.createTyped(mRS,
                                            b.create(),
                                            Allocation.USAGE_GRAPHICS_RENDER_TARGET);
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
index 91bac88..198e3f8 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
@@ -21,10 +21,16 @@
 
 /* Message sent from script to renderscript */
 const int RS_MSG_TEST_DONE = 100;
+const int RS_MSG_RESULTS_READY = 101;
 
-const int gMaxModes = 26;
+const int gMaxModes = 25;
 int gMaxLoops;
 
+// Allocation to send test names back to java
+char *gStringBuffer = 0;
+// Allocation to write the results into
+static float gResultBuffer[gMaxModes];
+
 rs_program_vertex gProgVertex;
 rs_program_fragment gProgFragmentColor;
 rs_program_fragment gProgFragmentTexture;
@@ -168,7 +174,7 @@
     rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
 
     for (int i = 0; i < quadCount; i ++) {
-        float startX = 10 * i, startY = 10 * i;
+        float startX = 5 * i, startY = 5 * i;
         float width = gRenderSurfaceW - startX, height = gRenderSurfaceH - startY;
         rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
                              startX, startY + height, 0, 0, 1,
@@ -638,116 +644,121 @@
 static bool sendMsgFlag = false;
 
 static const char *testNames[] = {
-    "Finished text fill 1,",
-    "Finished text fill 2,",
-    "Finished text fill 3,",
-    "Finished text fill 4,",
-    "Finished text fill 5,",
-    "Finished 25.6k geo flat color,",
-    "Finished 51.2k geo flat color,",
-    "Finished 204.8k geo raster load flat color,",
-    "Finished 25.6k geo texture,",
-    "Finished 51.2k geo texture,",
-    "Finished 204.8k geo raster load texture,",
-    "Finished full screen mesh 10 by 10,",
-    "Finished full screen mesh 100 by 100,",
-    "Finished full screen mesh W / 4 by H / 4,",
-    "Finished 25.6k geo heavy vertex,",
-    "Finished 51.2k geo heavy vertex,",
-    "Finished 204.8k geo raster load heavy vertex,",
-    "Finished singletexture 5x fill,",
-    "Finished 3tex multitexture 5x fill,",
-    "Finished blend singletexture 5x fill,",
-    "Finished blend 3tex multitexture 5x fill,",
-    "Finished 25.6k geo heavy fragment,",
-    "Finished 51.2k geo heavy fragment,",
-    "Finished 204.8k geo raster load heavy fragment,",
-    "Finished 25.6k geo heavy fragment heavy vertex,",
-    "Finished 51.2k geo heavy fragment heavy vertex,",
-    "Finished 204.8k geo raster load heavy fragment heavy vertex,",
+    "Fill screen with text 1 time",
+    "Fill screen with text 3 times",
+    "Fill screen with text 5 times",
+    "Geo test 25.6k flat color",
+    "Geo test 51.2k flat color",
+    "Geo test 204.8k small tries flat color",
+    "Geo test 25.6k single texture",
+    "Geo test 51.2k single texture",
+    "Geo test 204.8k small tries single texture",
+    "Full screen mesh 10 by 10",
+    "Full screen mesh 100 by 100",
+    "Full screen mesh W / 4 by H / 4",
+    "Geo test 25.6k geo heavy vertex",
+    "Geo test 51.2k geo heavy vertex",
+    "Geo test 204.8k geo raster load heavy vertex",
+    "Fill screen 10x singletexture",
+    "Fill screen 10x 3tex multitexture",
+    "Fill screen 10x blended singletexture",
+    "Fill screen 10x blended 3tex multitexture",
+    "Geo test 25.6k heavy fragment",
+    "Geo test 51.2k heavy fragment",
+    "Geo test 204.8k small tries heavy fragment",
+    "Geo test 25.6k heavy fragment heavy vertex",
+    "Geo test 51.2k heavy fragment heavy vertex",
+    "Geo test 204.8k small tries heavy fragment heavy vertex",
 };
 
+void getTestName(int testIndex) {
+    int bufferLen = rsAllocationGetDimX(rsGetAllocation(gStringBuffer));
+    if (testIndex >= gMaxModes) {
+        return;
+    }
+    uint charIndex = 0;
+    while (testNames[testIndex][charIndex] != '\0' && charIndex < bufferLen) {
+        gStringBuffer[charIndex] = testNames[testIndex][charIndex];
+        charIndex ++;
+    }
+    gStringBuffer[charIndex] = '\0';
+}
+
 static void runTest(int index) {
     switch (index) {
     case 0:
         displayFontSamples(1);
         break;
     case 1:
-        displayFontSamples(2);
-        break;
-    case 2:
         displayFontSamples(3);
         break;
-    case 3:
-        displayFontSamples(4);
-        break;
-    case 4:
+    case 2:
         displayFontSamples(5);
         break;
-    case 5:
+    case 3:
         displaySimpleGeoSamples(false, 1);
         break;
-    case 6:
+    case 4:
         displaySimpleGeoSamples(false, 2);
         break;
-    case 7:
+    case 5:
         displaySimpleGeoSamples(false, 8);
         break;
-    case 8:
+    case 6:
         displaySimpleGeoSamples(true, 1);
         break;
-    case 9:
+    case 7:
         displaySimpleGeoSamples(true, 2);
         break;
-    case 10:
+    case 8:
         displaySimpleGeoSamples(true, 8);
         break;
-    case 11:
+    case 9:
         displayMeshSamples(0);
         break;
-    case 12:
+    case 10:
         displayMeshSamples(1);
         break;
-    case 13:
+    case 11:
         displayMeshSamples(2);
         break;
-    case 14:
+    case 12:
         displayCustomShaderSamples(1);
         break;
-    case 15:
+    case 13:
         displayCustomShaderSamples(2);
         break;
+    case 14:
+        displayCustomShaderSamples(10);
+        break;
+    case 15:
+        displaySingletexFill(false, 10);
+        break;
     case 16:
-        displayCustomShaderSamples(8);
+        displayMultitextureSample(false, 10);
         break;
     case 17:
-        displaySingletexFill(false, 5);
+        displaySingletexFill(true, 10);
         break;
     case 18:
-        displayMultitextureSample(false, 5);
+        displayMultitextureSample(true, 8);
         break;
     case 19:
-        displaySingletexFill(true, 5);
-        break;
-    case 20:
-        displayMultitextureSample(true, 5);
-        break;
-    case 21:
         displayPixelLightSamples(1, false);
         break;
-    case 22:
+    case 20:
         displayPixelLightSamples(2, false);
         break;
-    case 23:
+    case 21:
         displayPixelLightSamples(8, false);
         break;
-    case 24:
+    case 22:
         displayPixelLightSamples(1, true);
         break;
-    case 25:
+    case 23:
         displayPixelLightSamples(2, true);
         break;
-    case 26:
+    case 24:
         displayPixelLightSamples(8, true);
         break;
     }
@@ -782,9 +793,10 @@
         return 1;
     }
 
+    gDt = 1.0f / 60.0f;
+
     rsgFinish();
     int64_t start = rsUptimeMillis();
-    rsGetDt();
 
     int drawPos = 0;
     int frameCount = 100;
@@ -801,7 +813,6 @@
         gRenderSurfaceH = rsgGetHeight();
         int size = 8;
         drawOffscreenResult((drawPos+=size)%gRenderSurfaceW, (gRenderSurfaceH * 3) / 4, size, size);
-        gDt = rsGetDt();
     }
 
     rsgFinish();
@@ -809,6 +820,7 @@
     int64_t end = rsUptimeMillis();
     float fps = (float)(frameCount) / ((float)(end - start)*0.001f);
     rsDebug(testNames[benchMode], fps);
+    gResultBuffer[benchMode] = fps;
 
     drawOffscreenResult(0, 0,
                         gRenderSurfaceW / 2,
@@ -828,7 +840,8 @@
 
     gTorusRotation = 0;
 
-    if (benchMode > gMaxModes) {
+    if (benchMode == gMaxModes) {
+        rsSendToClientBlocking(RS_MSG_RESULTS_READY, gResultBuffer, gMaxModes*sizeof(float));
         benchMode = 0;
         runningLoops++;
         if ((gMaxLoops > 0) && (runningLoops > gMaxLoops) && !sendMsgFlag) {