1/*
2 * Copyright (C) 2010-2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.perftest;
18
19import java.io.Writer;
20import java.io.BufferedWriter;
21import java.io.FileWriter;
22import java.io.IOException;
23import java.io.File;
24import java.io.FileOutputStream;
25import java.io.OutputStream;
26
27import android.os.Environment;
28import android.content.res.Resources;
29import android.renderscript.*;
30import android.renderscript.Element.DataKind;
31import android.renderscript.Element.DataType;
32import android.renderscript.Allocation.MipmapControl;
33import android.renderscript.Program.TextureType;
34import android.renderscript.RenderScript.RSMessageHandler;
35import android.renderscript.Sampler.Value;
36import android.renderscript.Mesh.Primitive;
37import android.renderscript.Matrix4f;
38import android.renderscript.ProgramVertexFixedFunction;
39
40import android.util.Log;
41
42
43public class RsBenchRS {
44
45    private static final String TAG = "RsBenchRS";
46    int mWidth;
47    int mHeight;
48    int mLoops;
49    int mCurrentLoop;
50
51    int mBenchmarkDimX;
52    int mBenchmarkDimY;
53
54    public RsBenchRS() {
55    }
56
57    public void init(RenderScriptGL rs, Resources res, int width, int height, int loops) {
58        mRS = rs;
59        mRes = res;
60        mWidth = width;
61        mHeight = height;
62        mMode = 0;
63        mLoops = loops;
64        mCurrentLoop = 0;
65        mBenchmarkDimX = 1280;
66        mBenchmarkDimY = 720;
67        initRS();
68    }
69
70    private boolean stopTest = false;
71
72    private Resources mRes;
73    private RenderScriptGL mRS;
74
75    private ProgramStore mProgStoreBlendNone;
76    private ProgramStore mProgStoreBlendAlpha;
77
78    private ProgramFragment mProgFragmentTexture;
79    private ProgramFragment mProgFragmentColor;
80
81    private ProgramVertex mProgVertex;
82    private ProgramVertexFixedFunction.Constants mPVA;
83    private ProgramVertexFixedFunction.Constants mPvProjectionAlloc;
84
85    private ScriptC_rsbench mScript;
86
87    ScriptField_TestScripts_s.Item[] mIndividualTests;
88
89    int mMode;
90
91    String[] mTestNames;
92    float[] mLocalTestResults;
93
94    static Allocation createZeroTerminatedAlloc(RenderScript rs,
95                                                String str,
96                                                int usage) {
97        byte[] allocArray = null;
98        try {
99            allocArray = str.getBytes("UTF-8");
100            byte[] allocArrayZero = new byte[allocArray.length + 1];
101            System.arraycopy(allocArray, 0, allocArrayZero, 0, allocArray.length);
102            allocArrayZero[allocArrayZero.length - 1] = '\0';
103            Allocation alloc = Allocation.createSized(rs, Element.U8(rs),
104                                                      allocArrayZero.length, usage);
105            alloc.copyFrom(allocArrayZero);
106            return alloc;
107        }
108        catch (Exception e) {
109            throw new RSRuntimeException("Could not convert string to utf-8.");
110        }
111
112    }
113
114    void appendTests(RsBenchBaseTest testSet) {
115        ScriptField_TestScripts_s.Item[] newTests = testSet.getTests();
116        if (mIndividualTests != null) {
117            ScriptField_TestScripts_s.Item[] combined;
118            combined = new ScriptField_TestScripts_s.Item[newTests.length + mIndividualTests.length];
119            System.arraycopy(mIndividualTests, 0, combined, 0, mIndividualTests.length);
120            System.arraycopy(newTests, 0, combined, mIndividualTests.length, newTests.length);
121            mIndividualTests = combined;
122        } else {
123            mIndividualTests = newTests;
124        }
125
126        String[] newNames = testSet.getTestNames();
127        if (mTestNames != null) {
128            String[] combinedNames;
129            combinedNames = new String[newNames.length + mTestNames.length];
130            System.arraycopy(mTestNames, 0, combinedNames, 0, mTestNames.length);
131            System.arraycopy(newNames, 0, combinedNames, mTestNames.length, newNames.length);
132            mTestNames = combinedNames;
133        } else {
134            mTestNames = newNames;
135        }
136    }
137
138    void createTestAllocation() {
139        int numTests = mIndividualTests.length;
140        mLocalTestResults = new float[numTests];
141        ScriptField_TestScripts_s allTests;
142        allTests = new ScriptField_TestScripts_s(mRS, numTests);
143        for (int i = 0; i < numTests; i ++) {
144            allTests.set(mIndividualTests[i], i, false);
145        }
146        allTests.copyAll();
147        mScript.bind_gTestScripts(allTests);
148    }
149
150    private void saveTestResults() {
151        String state = Environment.getExternalStorageState();
152        if (!Environment.MEDIA_MOUNTED.equals(state)) {
153            Log.v(TAG, "sdcard is read only");
154            return;
155        }
156        File sdCard = Environment.getExternalStorageDirectory();
157        if (!sdCard.canWrite()) {
158            Log.v(TAG, "ssdcard is read only");
159            return;
160        }
161
162        File resultFile = new File(sdCard, "rsbench_result" + mCurrentLoop + ".csv");
163        resultFile.setWritable(true, false);
164
165        try {
166            BufferedWriter results = new BufferedWriter(new FileWriter(resultFile));
167            for (int i = 0; i < mLocalTestResults.length; i ++) {
168                results.write(mTestNames[i] + ", " + mLocalTestResults[i] + ",\n");
169            }
170            results.close();
171            Log.v(TAG, "Saved results in: " + resultFile.getAbsolutePath());
172        } catch (IOException e) {
173            Log.v(TAG, "Unable to write result file " + e.getMessage());
174        }
175    }
176
177    /**
178     * Create a message handler to handle message sent from the script
179     */
180    protected RSMessageHandler mRsMessage = new RSMessageHandler() {
181        public void run() {
182            if (mID == mScript.get_RS_MSG_RESULTS_READY()) {
183                for (int i = 0; i < mLocalTestResults.length; i ++) {
184                    mLocalTestResults[i] = Float.intBitsToFloat(mData[i]);
185                }
186                saveTestResults();
187                if (mLoops > 0) {
188                    mCurrentLoop ++;
189                    mCurrentLoop = mCurrentLoop % mLoops;
190                }
191                return;
192
193            } else if (mID == mScript.get_RS_MSG_TEST_DONE()) {
194                synchronized(this) {
195                    stopTest = true;
196                    this.notifyAll();
197                }
198                return;
199            } else {
200                Log.v(TAG, "Perf test got unexpected message");
201                return;
202            }
203        }
204    };
205
206    /**
207     * Wait for message from the script
208     */
209    public boolean testIsFinished() {
210        synchronized(this) {
211            while (true) {
212                if (stopTest) {
213                    return true;
214                } else {
215                    try {
216                        this.wait(60*1000);
217                    } catch (InterruptedException e) {
218                        e.printStackTrace();
219                    }
220                }
221            }
222        }
223    }
224
225    private void initProgramFragment() {
226
227        ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
228        texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
229                              ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
230        mProgFragmentTexture = texBuilder.create();
231        mProgFragmentTexture.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
232
233        ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
234        colBuilder.setVaryingColor(false);
235        mProgFragmentColor = colBuilder.create();
236
237        mScript.set_gProgFragmentTexture(mProgFragmentTexture);
238    }
239
240    private void initProgramVertex() {
241        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
242        mProgVertex = pvb.create();
243
244        mPVA = new ProgramVertexFixedFunction.Constants(mRS);
245        ((ProgramVertexFixedFunction)mProgVertex).bindConstants(mPVA);
246        Matrix4f proj = new Matrix4f();
247        proj.loadOrthoWindow(mBenchmarkDimX, mBenchmarkDimY);
248        mPVA.setProjection(proj);
249
250        mScript.set_gProgVertex(mProgVertex);
251    }
252
253    private int strlen(byte[] array) {
254        int count = 0;
255        while(count < array.length && array[count] != 0) {
256            count ++;
257        }
258        return count;
259    }
260
261    public void setDebugMode(int num) {
262        mScript.invoke_setDebugMode(num);
263    }
264
265    public void setBenchmarkMode(int benchNum) {
266        mScript.invoke_setBenchmarkMode(benchNum);
267    }
268
269    public void pause(boolean pause) {
270        mScript.set_gPauseRendering(pause);
271    }
272
273    private void initRS() {
274
275        mScript = new ScriptC_rsbench(mRS, mRes, R.raw.rsbench);
276        mRS.bindRootScript(mScript);
277
278        mRS.setMessageHandler(mRsMessage);
279
280        mScript.set_gMaxLoops(mLoops);
281
282        initProgramVertex();
283        initProgramFragment();
284        mScript.set_gFontSerif(Font.create(mRS, mRes, "serif", Font.Style.NORMAL, 8));
285
286        Type.Builder b = new Type.Builder(mRS, Element.RGBA_8888(mRS));
287        b.setX(mBenchmarkDimX).setY(mBenchmarkDimY);
288        Allocation offscreen = Allocation.createTyped(mRS,
289                                                      b.create(),
290                                                      Allocation.USAGE_GRAPHICS_TEXTURE |
291                                                      Allocation.USAGE_GRAPHICS_RENDER_TARGET);
292        mScript.set_gRenderBufferColor(offscreen);
293
294        b = new Type.Builder(mRS,
295                             Element.createPixel(mRS, DataType.UNSIGNED_16,
296                             DataKind.PIXEL_DEPTH));
297        b.setX(mBenchmarkDimX).setY(mBenchmarkDimY);
298        offscreen = Allocation.createTyped(mRS,
299                                           b.create(),
300                                           Allocation.USAGE_GRAPHICS_RENDER_TARGET);
301        mScript.set_gRenderBufferDepth(offscreen);
302        mScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS));
303
304        RsBenchBaseTest test = new TextTest();
305        if (test.init(mRS, mRes)) {
306            appendTests(test);
307        }
308        test = new FillTest();
309        if (test.init(mRS, mRes)) {
310            appendTests(test);
311        }
312        test = new MeshTest();
313        if (test.init(mRS, mRes)) {
314            appendTests(test);
315        }
316        test = new TorusTest();
317        if (test.init(mRS, mRes)) {
318            appendTests(test);
319        }
320        test = new UiTest();
321        if (test.init(mRS, mRes)) {
322            appendTests(test);
323        }
324        createTestAllocation();
325
326        mScript.set_gLoadComplete(true);
327    }
328}
329