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