ImageProcessingActivity.java revision 89e20d27effd875431087a9188b20386b9c5aff0
1/*
2 * Copyright (C) 2012 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.rs.image;
18
19import android.app.Activity;
20import android.os.Bundle;
21import android.os.Handler;
22import android.os.Message;
23import android.graphics.BitmapFactory;
24import android.graphics.Bitmap;
25import android.graphics.Canvas;
26import android.view.SurfaceView;
27import android.widget.AdapterView;
28import android.widget.ArrayAdapter;
29import android.widget.ImageView;
30import android.widget.SeekBar;
31import android.widget.Spinner;
32import android.widget.TextView;
33import android.view.View;
34import android.util.Log;
35import android.renderscript.ScriptC;
36import android.renderscript.RenderScript;
37import android.renderscript.Type;
38import android.renderscript.Allocation;
39import android.renderscript.Element;
40import android.renderscript.Script;
41
42import android.os.Environment;
43import java.io.BufferedWriter;
44import java.io.File;
45import java.io.FileWriter;
46import java.io.IOException;
47
48public class ImageProcessingActivity extends Activity
49                                       implements SeekBar.OnSeekBarChangeListener {
50    private final String TAG = "Img";
51    public final String RESULT_FILE = "image_processing_result.csv";
52
53    RenderScript mRS;
54    Allocation mInPixelsAllocation;
55    Allocation mInPixelsAllocation2;
56    Allocation mOutPixelsAllocation;
57
58    /**
59     * Define enum type for test names
60     */
61    public enum TestName {
62        // totally there are 38 test cases
63        LEVELS_VEC3_RELAXED ("Levels Vec3 Relaxed"),
64        LEVELS_VEC4_RELAXED ("Levels Vec4 Relaxed"),
65        LEVELS_VEC3_FULL ("Levels Vec3 Full"),
66        LEVELS_VEC4_FULL ("Levels Vec4 Full"),
67        BLUR_RADIUS_25 ("Blur radius 25"),
68        INTRINSIC_BLUE_RADIUS_25 ("Intrinsic Blur radius 25"),
69        GREYSCALE ("Greyscale"),
70        GRAIN ("Grain"),
71        FISHEYE_FULL ("Fisheye Full"),
72        FISHEYE_RELAXED ("Fisheye Relaxed"),
73        FISHEYE_APPROXIMATE_FULL ("Fisheye Approximate Full"),
74        FISHEYE_APPROXIMATE_RELAXED ("Fisheye Approximate Relaxed"),
75        VIGNETTE_FULL ("Vignette Full"),
76        VIGNETTE_RELAXED ("Vignette Relaxed"),
77        VIGNETTE_APPROXIMATE_FULL ("Vignette Approximate Full"),
78        VIGNETTE_APPROXIMATE_RELAXED ("Vignette Approximate Relaxed"),
79        GROUP_TEST_EMULATED ("Group Test (emulated)"),
80        GROUP_TEST_NATIVE ("Group Test (native)"),
81        CONVOLVE_3X3 ("Convolve 3x3"),
82        INTRINSICS_CONVOLVE_3X3 ("Intrinsics Convolve 3x3"),
83        COLOR_MATRIX ("ColorMatrix"),
84        INTRINSICS_COLOR_MATRIX ("Intrinsics ColorMatrix"),
85        INTRINSICS_COLOR_MATRIX_GREY ("Intrinsics ColorMatrix Grey"),
86        COPY ("Copy"),
87        CROSS_PROCESS_USING_LUT ("CrossProcess (using LUT)"),
88        CONVOLVE_5X5 ("Convolve 5x5"),
89        INTRINSICS_CONVOLVE_5X5 ("Intrinsics Convolve 5x5"),
90        MANDELBROT ("Mandelbrot"),
91        INTRINSICS_BLEND ("Intrinsics Blend"),
92        INTRINSICS_BLUR_25G ("Intrinsics Blur 25 uchar"),
93        VIBRANCE ("Vibrance"),
94        BW_FILTER ("BW Filter"),
95        SHADOWS ("Shadows"),
96        CONTRAST ("Contrast"),
97        EXPOSURE ("Exposure"),
98        WHITE_BALANCE ("White Balance"),
99        COLOR_CUBE ("Color Cube"),
100        COLOR_CUBE_3D_INTRINSIC ("Color Cube (3D LUT intrinsic)"),
101        USAGE_IO ("Usage io)");
102
103
104        private final String name;
105
106        private TestName(String s) {
107            name = s;
108        }
109
110        // return quoted string as displayed test name
111        public String toString() {
112            return name;
113        }
114    }
115
116    Bitmap mBitmapIn;
117    Bitmap mBitmapIn2;
118    Bitmap mBitmapOut;
119
120    private Spinner mSpinner;
121    private SeekBar mBar1;
122    private SeekBar mBar2;
123    private SeekBar mBar3;
124    private SeekBar mBar4;
125    private SeekBar mBar5;
126    private TextView mText1;
127    private TextView mText2;
128    private TextView mText3;
129    private TextView mText4;
130    private TextView mText5;
131
132    private float mSaturation = 1.0f;
133
134    private TextView mBenchmarkResult;
135    private Spinner mTestSpinner;
136
137    private SurfaceView mSurfaceView;
138    private ImageView mDisplayView;
139
140    private boolean mDoingBenchmark;
141
142    private TestBase mTest;
143    private int mRunCount;
144
145    public void updateDisplay() {
146        mHandler.sendMessage(Message.obtain());
147    }
148
149    private Handler mHandler = new Handler() {
150        // Allow the filter to complete without blocking the UI
151        // thread.  When the message arrives that the op is complete
152        // we will either mark completion or start a new filter if
153        // more work is ready.  Either way, display the result.
154        @Override
155        public void handleMessage(Message msg) {
156            boolean doTest = false;
157            synchronized(this) {
158                if (mRS == null) {
159                    return;
160                }
161                mTest.updateBitmap(mBitmapOut);
162                mDisplayView.invalidate();
163                if (mRunCount > 0) {
164                    mRunCount--;
165                    if (mRunCount > 0) {
166                        doTest = true;
167                    }
168                }
169
170                if (doTest) {
171                    mTest.runTestSendMessage();
172                }
173            }
174        }
175
176    };
177
178    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
179        if (fromUser) {
180
181            if (seekBar == mBar1) {
182                mTest.onBar1Changed(progress);
183            } else if (seekBar == mBar2) {
184                mTest.onBar2Changed(progress);
185            } else if (seekBar == mBar3) {
186                mTest.onBar3Changed(progress);
187            } else if (seekBar == mBar4) {
188                mTest.onBar4Changed(progress);
189            } else if (seekBar == mBar5) {
190                mTest.onBar5Changed(progress);
191            }
192
193            boolean doTest = false;
194            synchronized(this) {
195                if (mRunCount == 0) {
196                    doTest = true;
197                    mRunCount = 1;
198                } else {
199                    mRunCount = 2;
200                }
201            }
202            if (doTest) {
203                mTest.runTestSendMessage();
204            }
205        }
206    }
207
208    public void onStartTrackingTouch(SeekBar seekBar) {
209    }
210
211    public void onStopTrackingTouch(SeekBar seekBar) {
212    }
213
214    void setupBars() {
215        mSpinner.setVisibility(View.VISIBLE);
216        mTest.onSpinner1Setup(mSpinner);
217
218        mBar1.setVisibility(View.VISIBLE);
219        mText1.setVisibility(View.VISIBLE);
220        mTest.onBar1Setup(mBar1, mText1);
221
222        mBar2.setVisibility(View.VISIBLE);
223        mText2.setVisibility(View.VISIBLE);
224        mTest.onBar2Setup(mBar2, mText2);
225
226        mBar3.setVisibility(View.VISIBLE);
227        mText3.setVisibility(View.VISIBLE);
228        mTest.onBar3Setup(mBar3, mText3);
229
230        mBar4.setVisibility(View.VISIBLE);
231        mText4.setVisibility(View.VISIBLE);
232        mTest.onBar4Setup(mBar4, mText4);
233
234        mBar5.setVisibility(View.VISIBLE);
235        mText5.setVisibility(View.VISIBLE);
236        mTest.onBar5Setup(mBar5, mText5);
237    }
238
239
240    void changeTest(TestName testName) {
241        if (mTest != null) {
242            mTest.destroy();
243        }
244        switch(testName) {
245        case LEVELS_VEC3_RELAXED:
246            mTest = new LevelsV4(false, false);
247            break;
248        case LEVELS_VEC4_RELAXED:
249            mTest = new LevelsV4(false, true);
250            break;
251        case LEVELS_VEC3_FULL:
252            mTest = new LevelsV4(true, false);
253            break;
254        case LEVELS_VEC4_FULL:
255            mTest = new LevelsV4(true, true);
256            break;
257        case BLUR_RADIUS_25:
258            mTest = new Blur25(false);
259            break;
260        case INTRINSIC_BLUE_RADIUS_25:
261            mTest = new Blur25(true);
262            break;
263        case GREYSCALE:
264            mTest = new Greyscale();
265            break;
266        case GRAIN:
267            mTest = new Grain();
268            break;
269        case FISHEYE_FULL:
270            mTest = new Fisheye(false, false);
271            break;
272        case FISHEYE_RELAXED:
273            mTest = new Fisheye(false, true);
274            break;
275        case FISHEYE_APPROXIMATE_FULL:
276            mTest = new Fisheye(true, false);
277            break;
278        case FISHEYE_APPROXIMATE_RELAXED:
279            mTest = new Fisheye(true, true);
280            break;
281        case VIGNETTE_FULL:
282            mTest = new Vignette(false, false);
283            break;
284        case VIGNETTE_RELAXED:
285            mTest = new Vignette(false, true);
286            break;
287        case VIGNETTE_APPROXIMATE_FULL:
288            mTest = new Vignette(true, false);
289            break;
290        case VIGNETTE_APPROXIMATE_RELAXED:
291            mTest = new Vignette(true, true);
292            break;
293        case GROUP_TEST_EMULATED:
294            mTest = new GroupTest(false);
295            break;
296        case GROUP_TEST_NATIVE:
297            mTest = new GroupTest(true);
298            break;
299        case CONVOLVE_3X3:
300            mTest = new Convolve3x3(false);
301            break;
302        case INTRINSICS_CONVOLVE_3X3:
303            mTest = new Convolve3x3(true);
304            break;
305        case COLOR_MATRIX:
306            mTest = new ColorMatrix(false, false);
307            break;
308        case INTRINSICS_COLOR_MATRIX:
309            mTest = new ColorMatrix(true, false);
310            break;
311        case INTRINSICS_COLOR_MATRIX_GREY:
312            mTest = new ColorMatrix(true, true);
313            break;
314        case COPY:
315            mTest = new Copy();
316            break;
317        case CROSS_PROCESS_USING_LUT:
318            mTest = new CrossProcess();
319            break;
320        case CONVOLVE_5X5:
321            mTest = new Convolve5x5(false);
322            break;
323        case INTRINSICS_CONVOLVE_5X5:
324            mTest = new Convolve5x5(true);
325            break;
326        case MANDELBROT:
327            mTest = new Mandelbrot();
328            break;
329        case INTRINSICS_BLEND:
330            mTest = new Blend();
331            break;
332        case INTRINSICS_BLUR_25G:
333            mTest = new Blur25G();
334            break;
335        case VIBRANCE:
336            mTest = new Vibrance();
337            break;
338        case BW_FILTER:
339            mTest = new BWFilter();
340            break;
341        case SHADOWS:
342            mTest = new Shadows();
343            break;
344        case CONTRAST:
345            mTest = new Contrast();
346            break;
347        case EXPOSURE:
348            mTest = new Exposure();
349            break;
350        case WHITE_BALANCE:
351            mTest = new WhiteBalance();
352            break;
353        case COLOR_CUBE:
354            mTest = new ColorCube(false);
355            break;
356        case COLOR_CUBE_3D_INTRINSIC:
357            mTest = new ColorCube(true);
358            break;
359        case USAGE_IO:
360            mTest = new UsageIO();
361            break;
362        }
363
364        mTest.createBaseTest(this, mBitmapIn, mBitmapIn2, mBitmapOut);
365        setupBars();
366
367        mTest.runTest();
368        updateDisplay();
369        mBenchmarkResult.setText("Result: not run");
370    }
371
372    void setupTests() {
373        mTestSpinner.setAdapter(new ArrayAdapter<TestName>(
374            this, R.layout.spinner_layout, TestName.values()));
375    }
376
377    private AdapterView.OnItemSelectedListener mTestSpinnerListener =
378            new AdapterView.OnItemSelectedListener() {
379                public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
380                    changeTest(TestName.values()[pos]);
381                }
382
383                public void onNothingSelected(AdapterView parent) {
384
385                }
386            };
387
388    void init() {
389        mBitmapIn = loadBitmap(R.drawable.img1600x1067);
390        mBitmapIn2 = loadBitmap(R.drawable.img1600x1067b);
391        mBitmapOut = Bitmap.createBitmap(mBitmapIn.getWidth(), mBitmapIn.getHeight(),
392                                         mBitmapIn.getConfig());
393
394        mSurfaceView = (SurfaceView) findViewById(R.id.surface);
395
396        mDisplayView = (ImageView) findViewById(R.id.display);
397        mDisplayView.setImageBitmap(mBitmapOut);
398
399        mSpinner = (Spinner) findViewById(R.id.spinner1);
400
401        mBar1 = (SeekBar) findViewById(R.id.slider1);
402        mBar2 = (SeekBar) findViewById(R.id.slider2);
403        mBar3 = (SeekBar) findViewById(R.id.slider3);
404        mBar4 = (SeekBar) findViewById(R.id.slider4);
405        mBar5 = (SeekBar) findViewById(R.id.slider5);
406
407        mBar1.setOnSeekBarChangeListener(this);
408        mBar2.setOnSeekBarChangeListener(this);
409        mBar3.setOnSeekBarChangeListener(this);
410        mBar4.setOnSeekBarChangeListener(this);
411        mBar5.setOnSeekBarChangeListener(this);
412
413        mText1 = (TextView) findViewById(R.id.slider1Text);
414        mText2 = (TextView) findViewById(R.id.slider2Text);
415        mText3 = (TextView) findViewById(R.id.slider3Text);
416        mText4 = (TextView) findViewById(R.id.slider4Text);
417        mText5 = (TextView) findViewById(R.id.slider5Text);
418
419        mTestSpinner = (Spinner) findViewById(R.id.filterselection);
420        mTestSpinner.setOnItemSelectedListener(mTestSpinnerListener);
421
422        mBenchmarkResult = (TextView) findViewById(R.id.benchmarkText);
423        mBenchmarkResult.setText("Result: not run");
424
425
426        mRS = RenderScript.create(this);
427        mInPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,
428                                                          Allocation.MipmapControl.MIPMAP_NONE,
429                                                          Allocation.USAGE_SHARED |
430                                                          Allocation.USAGE_GRAPHICS_TEXTURE |
431                                                          Allocation.USAGE_SCRIPT);
432        mInPixelsAllocation2 = Allocation.createFromBitmap(mRS, mBitmapIn2,
433                                                           Allocation.MipmapControl.MIPMAP_NONE,
434                                                           Allocation.USAGE_SHARED |
435                                                           Allocation.USAGE_GRAPHICS_TEXTURE |
436                                                           Allocation.USAGE_SCRIPT);
437        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapOut);
438
439
440        setupTests();
441        changeTest(TestName.LEVELS_VEC3_RELAXED);
442    }
443
444    void cleanup() {
445        synchronized(this) {
446            RenderScript rs = mRS;
447            mRS = null;
448            while(mDoingBenchmark) {
449                try {
450                    Thread.sleep(1, 0);
451                } catch(InterruptedException e) {
452                }
453
454            }
455            rs.destroy();
456        }
457
458        mInPixelsAllocation = null;
459        mInPixelsAllocation2 = null;
460        mOutPixelsAllocation = null;
461        mBitmapIn = null;
462        mBitmapIn2 = null;
463        mBitmapOut = null;
464    }
465
466    @Override
467    protected void onCreate(Bundle savedInstanceState) {
468        super.onCreate(savedInstanceState);
469        setContentView(R.layout.main);
470
471        init();
472    }
473
474    @Override
475    protected void onPause() {
476        super.onPause();
477
478        cleanup();
479    }
480
481
482    @Override
483    protected void onResume() {
484        super.onResume();
485
486        init();
487    }
488
489    private Bitmap loadBitmap(int resource) {
490        final BitmapFactory.Options options = new BitmapFactory.Options();
491        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
492        return BitmapFactory.decodeResource(getResources(), resource, options);
493    }
494
495    // button hook
496    public void benchmark(View v) {
497        float t = getBenchmark();
498        //long javaTime = javaFilter();
499        //mBenchmarkResult.setText("RS: " + t + " ms  Java: " + javaTime + " ms");
500        mBenchmarkResult.setText("Result: " + t + " ms");
501        Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + t);
502    }
503
504    public void benchmark_all(View v) {
505        // write result into a file
506        File externalStorage = Environment.getExternalStorageDirectory();
507        if (!externalStorage.canWrite()) {
508            Log.v(TAG, "sdcard is not writable");
509            return;
510        }
511        File resultFile = new File(externalStorage, RESULT_FILE);
512        resultFile.setWritable(true, false);
513        try {
514            BufferedWriter rsWriter = new BufferedWriter(new FileWriter(resultFile));
515            Log.v(TAG, "Saved results in: " + resultFile.getAbsolutePath());
516            for (TestName tn: TestName.values()) {
517                changeTest(tn);
518                float t = getBenchmark();
519                String s = new String("" + tn.toString() + ", " + t);
520                rsWriter.write(s + "\n");
521                Log.v(TAG, "Test " + s + "ms\n");
522            }
523            rsWriter.close();
524        } catch (IOException e) {
525            Log.v(TAG, "Unable to write result file " + e.getMessage());
526        }
527        changeTest(TestName.LEVELS_VEC3_RELAXED);
528    }
529
530
531
532    // For benchmark test
533    public float getBenchmark() {
534        if (mRS == null) {
535            return 0;
536        }
537        mDoingBenchmark = true;
538
539        mTest.setupBenchmark();
540        long result = 0;
541
542        //Log.v(TAG, "Warming");
543        long t = java.lang.System.currentTimeMillis() + 250;
544        do {
545            mTest.runTest();
546            mTest.finish();
547        } while (t > java.lang.System.currentTimeMillis());
548
549        //Log.v(TAG, "Benchmarking");
550        int ct = 0;
551        t = java.lang.System.currentTimeMillis();
552        do {
553            mTest.runTest();
554            mTest.finish();
555            ct++;
556        } while ((t+1000) > java.lang.System.currentTimeMillis());
557        t = java.lang.System.currentTimeMillis() - t;
558        float ft = (float)t;
559        ft /= ct;
560
561        mTest.exitBenchmark();
562        mDoingBenchmark = false;
563        return ft;
564    }
565}
566