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