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 
17 package com.android.rs.image;
18 
19 import android.app.Activity;
20 import android.os.Bundle;
21 import android.os.Handler;
22 import android.os.Message;
23 import android.graphics.BitmapFactory;
24 import android.graphics.Bitmap;
25 import android.graphics.Canvas;
26 import android.view.SurfaceView;
27 import android.widget.AdapterView;
28 import android.widget.ArrayAdapter;
29 import android.widget.ImageView;
30 import android.widget.SeekBar;
31 import android.widget.Spinner;
32 import android.widget.TextView;
33 import android.view.View;
34 import android.util.Log;
35 import android.renderscript.ScriptC;
36 import android.renderscript.RenderScript;
37 import android.renderscript.Type;
38 import android.renderscript.Allocation;
39 import android.renderscript.Element;
40 import android.renderscript.Script;
41 
42 import android.os.Environment;
43 import java.io.BufferedWriter;
44 import java.io.File;
45 import java.io.FileWriter;
46 import java.io.IOException;
47 
48 public 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     /**
60      * Define enum type for test names
61      */
62     public enum TestName {
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_FLOAT ("Mandelbrot fp32"),
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         ARTISTIC_1("Artistic 1"),
103         HISTOGRAM ("Histogram"),
104         MANDELBROT_DOUBLE ("Mandelbrot fp64"),
105         RESIZE_BICUBIC_SCRIPT ("Resize BiCubic Script"),
106         RESIZE_BICUBIC_INTRINSIC ("Resize BiCubic Intrinsic"),
107         MIRROR ("Mirror Image");
108 
109         private final String name;
110 
TestName(String s)111         private TestName(String s) {
112             name = s;
113         }
114 
115         // return quoted string as displayed test name
toString()116         public String toString() {
117             return name;
118         }
119     }
120 
121     Bitmap mBitmapOut;
122 
123     private Spinner mSpinner;
124     private SeekBar mBar1;
125     private SeekBar mBar2;
126     private SeekBar mBar3;
127     private SeekBar mBar4;
128     private SeekBar mBar5;
129     private TextView mText1;
130     private TextView mText2;
131     private TextView mText3;
132     private TextView mText4;
133     private TextView mText5;
134 
135     private TextView mBenchmarkResult;
136     private Spinner mTestSpinner;
137 
138     private ImageView mDisplayView;
139 
140     private boolean mDoingBenchmark;
141 
142     private TestBase mTest;
143     private int mRunCount;
144 
updateDisplay()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 
onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)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 
onStartTrackingTouch(SeekBar seekBar)208     public void onStartTrackingTouch(SeekBar seekBar) {
209     }
210 
onStopTrackingTouch(SeekBar seekBar)211     public void onStopTrackingTouch(SeekBar seekBar) {
212     }
213 
setupBars()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 
changeTest(TestName testName)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_FLOAT:
327             mTest = new Mandelbrot(false);
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         case ARTISTIC_1:
363             mTest = new Artistic1();
364             break;
365         case HISTOGRAM:
366             mTest = new Histogram();
367             break;
368         case MANDELBROT_DOUBLE:
369             mTest = new Mandelbrot(true);
370             break;
371         case RESIZE_BICUBIC_SCRIPT:
372             mTest = new Resize(false);
373             break;
374         case RESIZE_BICUBIC_INTRINSIC:
375             mTest = new Resize(true);
376             break;
377         case MIRROR:
378             mTest = new Mirror();
379             break;
380         }
381 
382         mTest.createBaseTest(this);
383         setupBars();
384 
385         mTest.runTest();
386         updateDisplay();
387         mBenchmarkResult.setText("Result: not run");
388     }
389 
setupTests()390     void setupTests() {
391         mTestSpinner.setAdapter(new ArrayAdapter<TestName>(
392             this, R.layout.spinner_layout, TestName.values()));
393     }
394 
395     private AdapterView.OnItemSelectedListener mTestSpinnerListener =
396             new AdapterView.OnItemSelectedListener() {
397                 public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
398                     changeTest(TestName.values()[pos]);
399                 }
400 
401                 public void onNothingSelected(AdapterView parent) {
402 
403                 }
404             };
405 
init()406     void init() {
407         mRS = RenderScript.create(this);
408         mInPixelsAllocation = Allocation.createFromBitmapResource(
409                 mRS, getResources(), R.drawable.img1600x1067);
410         mInPixelsAllocation2 = Allocation.createFromBitmapResource(
411                 mRS, getResources(), R.drawable.img1600x1067b);
412         mBitmapOut = Bitmap.createBitmap(mInPixelsAllocation.getType().getX(),
413                                          mInPixelsAllocation.getType().getY(),
414                                          Bitmap.Config.ARGB_8888);
415         mBitmapOut.setHasAlpha(false);
416         mOutPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapOut);
417 
418         mDisplayView = findViewById(R.id.display);
419         mDisplayView.setImageBitmap(mBitmapOut);
420 
421         mSpinner = findViewById(R.id.spinner1);
422 
423         mBar1 = findViewById(R.id.slider1);
424         mBar2 = findViewById(R.id.slider2);
425         mBar3 = findViewById(R.id.slider3);
426         mBar4 = findViewById(R.id.slider4);
427         mBar5 = findViewById(R.id.slider5);
428 
429         mBar1.setOnSeekBarChangeListener(this);
430         mBar2.setOnSeekBarChangeListener(this);
431         mBar3.setOnSeekBarChangeListener(this);
432         mBar4.setOnSeekBarChangeListener(this);
433         mBar5.setOnSeekBarChangeListener(this);
434 
435         mText1 = findViewById(R.id.slider1Text);
436         mText2 = findViewById(R.id.slider2Text);
437         mText3 = findViewById(R.id.slider3Text);
438         mText4 = findViewById(R.id.slider4Text);
439         mText5 = findViewById(R.id.slider5Text);
440 
441         mTestSpinner = findViewById(R.id.filterselection);
442         mTestSpinner.setOnItemSelectedListener(mTestSpinnerListener);
443 
444         mBenchmarkResult = findViewById(R.id.benchmarkText);
445         mBenchmarkResult.setText("Result: not run");
446 
447         setupTests();
448         changeTest(TestName.LEVELS_VEC3_RELAXED);
449     }
450 
cleanup()451     void cleanup() {
452         synchronized(this) {
453             RenderScript rs = mRS;
454             mRS = null;
455             while(mDoingBenchmark) {
456                 try {
457                     Thread.sleep(1, 0);
458                 } catch(InterruptedException e) {
459                 }
460 
461             }
462             rs.destroy();
463         }
464 
465         mInPixelsAllocation = null;
466         mInPixelsAllocation2 = null;
467         mOutPixelsAllocation = null;
468         mBitmapOut = null;
469     }
470 
471     @Override
onCreate(Bundle savedInstanceState)472     protected void onCreate(Bundle savedInstanceState) {
473         super.onCreate(savedInstanceState);
474         setContentView(R.layout.main);
475 
476         init();
477     }
478 
479     @Override
onPause()480     protected void onPause() {
481         super.onPause();
482 
483         cleanup();
484     }
485 
486 
487     @Override
onResume()488     protected void onResume() {
489         super.onResume();
490 
491         if (null == mRS) {
492             init();
493         }
494     }
495 
496     // button hook
benchmark(View v)497     public void benchmark(View v) {
498         float t = getBenchmark();
499         //long javaTime = javaFilter();
500         //mBenchmarkResult.setText("RS: " + t + " ms  Java: " + javaTime + " ms");
501         mBenchmarkResult.setText("Result: " + t + " ms");
502         Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + t);
503     }
504 
benchmark_all(View v)505     public void benchmark_all(View v) {
506         // write result into a file
507         File externalStorage = Environment.getExternalStorageDirectory();
508         if (!externalStorage.canWrite()) {
509             Log.v(TAG, "sdcard is not writable");
510             return;
511         }
512         File resultFile = new File(externalStorage, RESULT_FILE);
513         resultFile.setWritable(true, false);
514         try {
515             BufferedWriter rsWriter = new BufferedWriter(new FileWriter(resultFile));
516             Log.v(TAG, "Saved results in: " + resultFile.getAbsolutePath());
517             for (TestName tn: TestName.values()) {
518                 changeTest(tn);
519                 float t = getBenchmark();
520                 String s = new String("" + tn.toString() + ", " + t);
521                 rsWriter.write(s + "\n");
522                 Log.v(TAG, "Test " + s + "ms\n");
523             }
524             rsWriter.close();
525         } catch (IOException e) {
526             Log.v(TAG, "Unable to write result file " + e.getMessage());
527         }
528         changeTest(TestName.LEVELS_VEC3_RELAXED);
529     }
530 
531 
532 
533     // For benchmark test
getBenchmark()534     public float getBenchmark() {
535         if (mRS == null) {
536             return 0;
537         }
538         mDoingBenchmark = true;
539 
540         mTest.setupBenchmark();
541         long result = 0;
542 
543         //Log.v(TAG, "Warming");
544         long t = java.lang.System.currentTimeMillis() + 250;
545         do {
546             mTest.runTest();
547             mTest.finish();
548         } while (t > java.lang.System.currentTimeMillis());
549 
550         //Log.v(TAG, "Benchmarking");
551         int ct = 0;
552         t = java.lang.System.currentTimeMillis();
553         do {
554             mTest.runTest();
555             mTest.finish();
556             ct++;
557         } while ((t+1000) > java.lang.System.currentTimeMillis());
558         t = java.lang.System.currentTimeMillis() - t;
559         float ft = (float)t;
560         ft /= ct;
561 
562         mTest.exitBenchmark();
563         mDoingBenchmark = false;
564 
565         return ft;
566     }
567 }
568