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.imagejb;
18 
19 import android.app.Activity;
20 import android.content.Intent;
21 import android.graphics.Point;
22 import android.graphics.SurfaceTexture;
23 import android.os.Bundle;
24 import android.renderscript.Allocation;
25 import android.renderscript.RenderScript;
26 import android.util.Log;
27 import android.view.Surface;
28 import android.view.TextureView;
29 import android.view.View;
30 import android.view.WindowManager;
31 import android.widget.SeekBar;
32 import android.widget.Spinner;
33 import android.widget.TextView;
34 
35 import androidx.test.InstrumentationRegistry;
36 
37 public class ImageProcessingActivityJB extends Activity
38                                        implements SeekBar.OnSeekBarChangeListener,
39                                                   TextureView.SurfaceTextureListener {
40     private final String TAG = "Img";
41 
42     private Spinner mSpinner;
43     private SeekBar mBar1;
44     private SeekBar mBar2;
45     private SeekBar mBar3;
46     private SeekBar mBar4;
47     private SeekBar mBar5;
48 
49     private int mBars[] = new int[5];
50     private int mBarsOld[] = new int[5];
51 
52     private TextView mText1;
53     private TextView mText2;
54     private TextView mText3;
55     private TextView mText4;
56     private TextView mText5;
57     private SizedTV mDisplayView;
58 
59     private int mTestList[];
60     private float mTestResults[];
61 
62     private boolean mToggleIO;
63     private boolean mToggleDVFS;
64     private boolean mToggleLong;
65     private boolean mTogglePause;
66     private boolean mToggleAnimate;
67     private boolean mToggleDisplay;
68     private int mBitmapWidth;
69     private int mBitmapHeight;
70     private boolean mDemoMode;
71     private float mMinTestRuntime;
72     private int mMinTestIterations;
73 
74     // Updates pending is a counter of how many kernels have been
75     // sent to RS for processing
76     //
77     // In benchmark this is incremented each time a kernel is launched and
78     // decremented each time a kernel completes
79     //
80     // In demo mode, each UI input increments the counter and it is zeroed
81     // when the latest settings are sent to RS for processing.
82     private int mUpdatesPending;
83 
84     // In demo mode this is used to count updates in the pipeline.  It's
85     // incremented when work is submitted to RS and decremented when invalidate is
86     // called to display a result.
87     private int mShowsPending;
88 
89     // Initialize the parameters for Instrumentation tests.
prepareInstrumentationTest()90     protected void prepareInstrumentationTest() {
91         mTestList = new int[1];
92         mBitmapWidth = 1920;
93         mBitmapHeight = 1080;
94         mTestResults = new float[1];
95 
96         startProcessor();
97     }
98 
99     static public class SizedTV extends TextureView {
100         int mWidth;
101         int mHeight;
102 
SizedTV(android.content.Context c)103         public SizedTV(android.content.Context c) {
104             super(c);
105             mWidth = 800;
106             mHeight = 450;
107         }
108 
SizedTV(android.content.Context c, android.util.AttributeSet attrs)109         public SizedTV(android.content.Context c, android.util.AttributeSet attrs) {
110             super(c, attrs);
111             mWidth = 800;
112             mHeight = 450;
113         }
114 
SizedTV(android.content.Context c, android.util.AttributeSet attrs, int f)115         public SizedTV(android.content.Context c, android.util.AttributeSet attrs, int f) {
116             super(c, attrs, f);
117             mWidth = 800;
118             mHeight = 450;
119         }
120 
onMeasure(int w, int h)121         protected void onMeasure(int w, int h) {
122             setMeasuredDimension(mWidth, mHeight);
123         }
124     }
125 
126     /////////////////////////////////////////////////////////////////////////
127 
128     // Message processor to handle notifications for when kernel completes
129     private class MessageProcessor extends RenderScript.RSMessageHandler {
MessageProcessor()130         MessageProcessor() {
131         }
132 
run()133         public void run() {
134             synchronized(mProcessor) {
135                 // In demo mode, decrement the pending displays and notify the
136                 // UI processor it can now enqueue more work if additional updates
137                 // are blocked by a full pipeline.
138                 if (mShowsPending > 0) {
139                     mShowsPending --;
140                     mProcessor.notifyAll();
141                 }
142             }
143         }
144     }
145 
146 
147     /////////////////////////////////////////////////////////////////////////
148     // Processor is a helper thread for running the work without
149     // blocking the UI thread.
150     class Processor extends Thread {
151         RenderScript mRS;
152         Allocation mInPixelsAllocation;
153         Allocation mInPixelsAllocation2;
154         Allocation mOutDisplayAllocation;
155         Allocation mOutPixelsAllocation;
156 
157         private Surface mOutSurface;
158         private float mLastResult;
159         private boolean mRun = true;
160         private boolean mDoingBenchmark;
161         private TestBase mTest;
162         private TextureView mDisplayView;
163 
164         private boolean mBenchmarkMode;
165 
166         // We don't want to call the "changed" methods excessively as this
167         // can cause extra work for drivers.  Before running a test update
168         // any bars which have changed.
runTest()169         void runTest() {
170             if (mBars[0] != mBarsOld[0]) {
171                 mTest.onBar1Changed(mBars[0]);
172                 mBarsOld[0] = mBars[0];
173             }
174             if (mBars[1] != mBarsOld[1]) {
175                 mTest.onBar2Changed(mBars[1]);
176                 mBarsOld[1] = mBars[1];
177             }
178             if (mBars[2] != mBarsOld[2]) {
179                 mTest.onBar3Changed(mBars[2]);
180                 mBarsOld[2] = mBars[2];
181             }
182             if (mBars[3] != mBarsOld[3]) {
183                 mTest.onBar4Changed(mBars[3]);
184                 mBarsOld[3] = mBars[3];
185             }
186             if (mBars[4] != mBarsOld[4]) {
187                 mTest.onBar5Changed(mBars[4]);
188                 mBarsOld[4] = mBars[4];
189             }
190             mTest.runTest();
191         }
192 
Processor(RenderScript rs, TextureView v, boolean benchmarkMode)193         Processor(RenderScript rs, TextureView v, boolean benchmarkMode) {
194             mRS = rs;
195             mDisplayView = v;
196 
197             mRS.setMessageHandler(new MessageProcessor());
198 
199             switch(mBitmapWidth) {
200             case 3840:
201                 mInPixelsAllocation = Allocation.createFromBitmapResource(
202                         mRS, getResources(), R.drawable.img3840x2160a);
203                 mInPixelsAllocation2 = Allocation.createFromBitmapResource(
204                         mRS, getResources(), R.drawable.img3840x2160b);
205                 break;
206             case 1920:
207                 mInPixelsAllocation = Allocation.createFromBitmapResource(
208                         mRS, getResources(), R.drawable.img1920x1080a);
209                 mInPixelsAllocation2 = Allocation.createFromBitmapResource(
210                         mRS, getResources(), R.drawable.img1920x1080b);
211                 break;
212             case 1280:
213                 mInPixelsAllocation = Allocation.createFromBitmapResource(
214                         mRS, getResources(), R.drawable.img1280x720a);
215                 mInPixelsAllocation2 = Allocation.createFromBitmapResource(
216                         mRS, getResources(), R.drawable.img1280x720b);
217                 break;
218             case 800:
219                 mInPixelsAllocation = Allocation.createFromBitmapResource(
220                         mRS, getResources(), R.drawable.img800x450a);
221                 mInPixelsAllocation2 = Allocation.createFromBitmapResource(
222                         mRS, getResources(), R.drawable.img800x450b);
223                 break;
224             }
225 
226             // We create the output allocation using USAGE_IO_OUTPUT so we can share the
227             // bits with a TextureView.  This is more efficient than using a bitmap.
228             mOutDisplayAllocation = Allocation.createTyped(mRS, mInPixelsAllocation.getType(),
229                                                                Allocation.MipmapControl.MIPMAP_NONE,
230                                                                Allocation.USAGE_SCRIPT |
231                                                                Allocation.USAGE_IO_OUTPUT);
232             mOutPixelsAllocation = mOutDisplayAllocation;
233 
234             if (!mToggleIO) {
235                 // Not using USAGE_IO for the script so create a non-io kernel to copy from
236                 mOutPixelsAllocation = Allocation.createTyped(mRS, mInPixelsAllocation.getType(),
237                                                               Allocation.MipmapControl.MIPMAP_NONE,
238                                                               Allocation.USAGE_SCRIPT);
239             }
240 
241             mBenchmarkMode = benchmarkMode;
242             start();
243         }
244 
245         // Run one loop of kernels for at least the specified minimum time.
246         // The function returns the average time in ms for the test run
runBenchmarkLoop(float minTime, int minIter)247         private Result runBenchmarkLoop(float minTime, int minIter) {
248             mUpdatesPending = 0;
249             Result r = new Result();
250 
251             long t = java.lang.System.nanoTime();
252             do {
253                 synchronized(this) {
254                     // Shows pending is used to track the number of kernels in the RS pipeline
255                     // We throttle it to 2.  This provide some buffering to allow a kernel to be started
256                     // before we are nofitied the previous finished.  However, larger numbers are uncommon
257                     // in interactive apps as they introduce 'lag' between user input and display.
258                     mShowsPending++;
259                     if (mShowsPending > 2) {
260                         try {
261                             this.wait();
262                         } catch(InterruptedException e) {
263                         }
264                     }
265                 }
266 
267                 // If animations are enabled update the test state.
268                 if (mToggleAnimate) {
269                     mTest.animateBars(r.getTotalTime());
270                 }
271 
272                 // Run the kernel
273                 mTest.runTest();
274 
275                 if (mToggleDisplay) {
276                     // If we are not outputting directly to the TextureView we need to copy from
277                     // our temporary buffer.
278                     if (mOutDisplayAllocation != mOutPixelsAllocation) {
279                         mOutDisplayAllocation.copyFrom(mOutPixelsAllocation);
280                     }
281 
282                     // queue the update of the TextureView with the allocation contents
283                     mOutDisplayAllocation.ioSend();
284                 }
285 
286                 // Send our RS message handler a message so we know when this work has completed
287                 mRS.sendMessage(0, null);
288 
289                 // Finish previous iteration before recording the time. Without this, the first
290                 // few iterations finish very quickly and the later iterations take much longer
291                 mRS.finish();
292 
293                 long t2 = java.lang.System.nanoTime();
294                 r.add((t2 - t) / 1000000000.f);
295                 t = t2;
296             } while (r.getTotalTime() < minTime || r.getIterations() < minIter);
297 
298             // Wait for any stray operations to complete and update the final time
299             mRS.finish();
300             return r;
301         }
302 
303         // Method to retreive benchmark results for instrumentation tests.
getInstrumentationResult(IPTestListJB.TestName t)304         Result getInstrumentationResult(IPTestListJB.TestName t) {
305             mTest = changeTest(t, false);
306             return getBenchmark();
307         }
308 
309         // Get a benchmark result for a specific test
getBenchmark()310         private Result getBenchmark() {
311             mDoingBenchmark = true;
312             mUpdatesPending = 0;
313 
314             if (mToggleDVFS) {
315                 mDvfsWar.go();
316             }
317 
318             // We run a short bit of work before starting the actual test
319             // this is to let any power management do its job and respond
320             runBenchmarkLoop(0.3f, 0);
321 
322             // Run the actual benchmark
323             Result r = runBenchmarkLoop(mMinTestRuntime, mMinTestIterations);
324 
325             Log.v("rs", "Test: time=" + r.getTotalTime() + "s,  frames=" + r.getIterations() +
326                   ", avg=" + r.getAvg() * 1000.f + ", stdcoef=" + r.getStdCoef() * 100.0f + "%");
327 
328             mDoingBenchmark = false;
329             return r;
330         }
331 
run()332         public void run() {
333             Surface lastSurface = null;
334             while (mRun) {
335                 // Our loop for launching tests or benchmarks
336                 synchronized(this) {
337                     // If we have no work to do, or we have displays pending, wait
338                     if ((mUpdatesPending == 0) || (mShowsPending != 0)) {
339                         try {
340                             this.wait();
341                         } catch(InterruptedException e) {
342                         }
343                     }
344 
345                     // We may have been asked to exit while waiting
346                     if (!mRun) return;
347 
348                     // During startup we may not have a surface yet to display, if
349                     // this is the case, wait.
350                     if ((mOutSurface == null) || (mOutPixelsAllocation == null)) {
351                         continue;
352                     }
353 
354                     // Our display surface changed, set it.
355                     if (lastSurface != mOutSurface) {
356                         mOutDisplayAllocation.setSurface(mOutSurface);
357                         lastSurface = mOutSurface;
358                     }
359                 }
360 
361                 if (mBenchmarkMode) {
362                     // Loop over the tests we want to benchmark
363                     for (int ct=0; (ct < mTestList.length) && mRun; ct++) {
364 
365                         // For reproducibility we wait a short time for any sporadic work
366                         // created by the user touching the screen to launch the test to pass.
367                         // Also allows for things to settle after the test changes.
368                         mRS.finish();
369                         try {
370                             sleep(250);
371                         } catch(InterruptedException e) {
372                         }
373 
374                         // If we just ran a test, we destroy it here to relieve some memory pressure
375                         if (mTest != null) {
376                             mTest.destroy();
377                         }
378 
379                         // Select the next test
380                         mTest = changeTest(mTestList[ct], false);
381 
382                         // If the user selected the "long pause" option, wait
383                         if (mTogglePause) {
384                             for (int i=0; (i < 100) && mRun; i++) {
385                                 try {
386                                     sleep(100);
387                                 } catch(InterruptedException e) {
388                                 }
389                             }
390                         }
391 
392                         // Run the test
393                         mTestResults[ct] = getBenchmark().getAvg() * 1000.0f;
394                     }
395                     onBenchmarkFinish(mRun);
396                 } else {
397                     boolean update = false;
398                     synchronized(this) {
399                         // If we have updates to process and are not blocked by pending shows,
400                         // start the next kernel
401                         if ((mUpdatesPending > 0) && (mShowsPending == 0)) {
402                             mUpdatesPending = 0;
403                             update = true;
404                             mShowsPending++;
405                         }
406                     }
407 
408                     if (update) {
409                         // Run the kernel
410                         runTest();
411 
412                         // If we are not outputting directly to the TextureView we need to copy from
413                         // our temporary buffer.
414                         if (mOutDisplayAllocation != mOutPixelsAllocation) {
415                             mOutDisplayAllocation.copyFrom(mOutPixelsAllocation);
416                         }
417 
418                         // queue the update of the TextureView with the allocation contents
419                         mOutDisplayAllocation.ioSend();
420 
421                         // Send our RS message handler a message so we know when this work has completed
422                         mRS.sendMessage(0, null);
423                     }
424                 }
425             }
426 
427         }
428 
update()429         public void update() {
430             // something UI related has changed, enqueue an update if one is not
431             // already pending.  Wake the worker if needed
432             synchronized(this) {
433                 if (mUpdatesPending < 2) {
434                     mUpdatesPending++;
435                     notifyAll();
436                 }
437             }
438         }
439 
setSurface(Surface s)440         public void setSurface(Surface s) {
441             mOutSurface = s;
442             update();
443         }
444 
exit()445         public void exit() {
446             mRun = false;
447 
448             synchronized(this) {
449                 notifyAll();
450             }
451 
452             try {
453                 this.join();
454             } catch(InterruptedException e) {
455             }
456 
457             mInPixelsAllocation.destroy();
458             mInPixelsAllocation2.destroy();
459             if (mOutPixelsAllocation != mOutDisplayAllocation) {
460                 mOutPixelsAllocation.destroy();
461             }
462 
463             if (mTest != null) {
464                 mTest.destroy();
465                 mTest = null;
466             }
467             mOutDisplayAllocation.destroy();
468             mRS.destroy();
469 
470             mInPixelsAllocation = null;
471             mInPixelsAllocation2 = null;
472             mOutPixelsAllocation = null;
473             mOutDisplayAllocation = null;
474             mRS = null;
475         }
476     }
477 
478     ///////////////////////////////////////////////////////////////////////////////////////
479 
480     static class DVFSWorkaround {
481         static class spinner extends Thread {
482             boolean mRun = true;
483             long mNextSleep;
484 
spinner()485             spinner() {
486                 setPriority(MIN_PRIORITY);
487                 start();
488             }
489 
run()490             public void run() {
491                 while (mRun) {
492                     Thread.yield();
493                     synchronized(this) {
494                         long t = java.lang.System.currentTimeMillis();
495                         if (t > mNextSleep) {
496                             try {
497                                 this.wait();
498                             } catch(InterruptedException e) {
499                             }
500                         }
501                     }
502                 }
503             }
504 
go(long t)505             public void go(long t) {
506                 synchronized(this) {
507                     mNextSleep = t;
508                     notifyAll();
509                 }
510             }
511         }
512 
513         spinner s1;
DVFSWorkaround()514         DVFSWorkaround() {
515             s1 = new spinner();
516         }
517 
go()518         void go() {
519             long t = java.lang.System.currentTimeMillis() + 2000;
520             s1.go(t);
521         }
522 
destroy()523         void destroy() {
524             synchronized(this) {
525                 s1.mRun = false;
526                 notifyAll();
527             }
528         }
529     }
530     DVFSWorkaround mDvfsWar = new DVFSWorkaround();
531 
532     ///////////////////////////////////////////////////////////
533 
534 
535     private boolean mDoingBenchmark;
536     public Processor mProcessor;
537 
changeTest(IPTestListJB.TestName t, boolean setupUI)538     TestBase changeTest(IPTestListJB.TestName t, boolean setupUI) {
539         TestBase tb = IPTestListJB.newTest(t);
540 
541         tb.createBaseTest(this);
542         if (setupUI) {
543             setupBars(tb);
544         }
545         return tb;
546     }
547 
changeTest(int id, boolean setupUI)548     TestBase changeTest(int id, boolean setupUI) {
549         IPTestListJB.TestName t = IPTestListJB.TestName.values()[id];
550         return changeTest(t, setupUI);
551     }
552 
onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)553     public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
554         if (fromUser) {
555             if (seekBar == mBar1) {
556                 mBars[0] = progress;
557             } else if (seekBar == mBar2) {
558                 mBars[1] = progress;
559             } else if (seekBar == mBar3) {
560                 mBars[2] = progress;
561             } else if (seekBar == mBar4) {
562                 mBars[3] = progress;
563             } else if (seekBar == mBar5) {
564                 mBars[4] = progress;
565             }
566             mProcessor.update();
567         }
568     }
569 
onStartTrackingTouch(SeekBar seekBar)570     public void onStartTrackingTouch(SeekBar seekBar) {
571     }
572 
onStopTrackingTouch(SeekBar seekBar)573     public void onStopTrackingTouch(SeekBar seekBar) {
574     }
575 
setupBars(TestBase t)576     void setupBars(TestBase t) {
577         mSpinner.setVisibility(View.VISIBLE);
578         t.onSpinner1Setup(mSpinner);
579 
580         mBar1.setVisibility(View.VISIBLE);
581         mText1.setVisibility(View.VISIBLE);
582         t.onBar1Setup(mBar1, mText1);
583 
584         mBar2.setVisibility(View.VISIBLE);
585         mText2.setVisibility(View.VISIBLE);
586         t.onBar2Setup(mBar2, mText2);
587 
588         mBar3.setVisibility(View.VISIBLE);
589         mText3.setVisibility(View.VISIBLE);
590         t.onBar3Setup(mBar3, mText3);
591 
592         mBar4.setVisibility(View.VISIBLE);
593         mText4.setVisibility(View.VISIBLE);
594         t.onBar4Setup(mBar4, mText4);
595 
596         mBar5.setVisibility(View.VISIBLE);
597         mText5.setVisibility(View.VISIBLE);
598         t.onBar5Setup(mBar5, mText5);
599     }
600 
hideBars()601     void hideBars() {
602         mSpinner.setVisibility(View.INVISIBLE);
603 
604         mBar1.setVisibility(View.INVISIBLE);
605         mText1.setVisibility(View.INVISIBLE);
606 
607         mBar2.setVisibility(View.INVISIBLE);
608         mText2.setVisibility(View.INVISIBLE);
609 
610         mBar3.setVisibility(View.INVISIBLE);
611         mText3.setVisibility(View.INVISIBLE);
612 
613         mBar4.setVisibility(View.INVISIBLE);
614         mText4.setVisibility(View.INVISIBLE);
615 
616         mBar5.setVisibility(View.INVISIBLE);
617         mText5.setVisibility(View.INVISIBLE);
618     }
619 
620     @Override
onCreate(Bundle savedInstanceState)621     protected void onCreate(Bundle savedInstanceState) {
622         super.onCreate(savedInstanceState);
623         setContentView(R.layout.main);
624         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
625 
626         mDisplayView = findViewById(R.id.display);
627 
628         mSpinner = findViewById(R.id.spinner1);
629 
630         mBar1 = findViewById(R.id.slider1);
631         mBar2 = findViewById(R.id.slider2);
632         mBar3 = findViewById(R.id.slider3);
633         mBar4 = findViewById(R.id.slider4);
634         mBar5 = findViewById(R.id.slider5);
635 
636         mBar1.setOnSeekBarChangeListener(this);
637         mBar2.setOnSeekBarChangeListener(this);
638         mBar3.setOnSeekBarChangeListener(this);
639         mBar4.setOnSeekBarChangeListener(this);
640         mBar5.setOnSeekBarChangeListener(this);
641 
642         mText1 = findViewById(R.id.slider1Text);
643         mText2 = findViewById(R.id.slider2Text);
644         mText3 = findViewById(R.id.slider3Text);
645         mText4 = findViewById(R.id.slider4Text);
646         mText5 = findViewById(R.id.slider5Text);
647     }
648 
649     @Override
onPause()650     protected void onPause() {
651         super.onPause();
652         if (mProcessor != null) {
653             mProcessor.exit();
654             mProcessor = null;
655         }
656     }
657 
onBenchmarkFinish(boolean ok)658     public void onBenchmarkFinish(boolean ok) {
659         if (ok) {
660             Intent intent = new Intent();
661             intent.putExtra("tests", mTestList);
662             intent.putExtra("results", mTestResults);
663             setResult(RESULT_OK, intent);
664         } else {
665             setResult(RESULT_CANCELED);
666         }
667         finish();
668     }
669 
670 
startProcessor()671     void startProcessor() {
672         Point size = new Point();
673         getWindowManager().getDefaultDisplay().getSize(size);
674 
675         int mScreenWidth = size.x;
676         int mScreenHeight = size.y;
677 
678         int tw = mBitmapWidth;
679         int th = mBitmapHeight;
680 
681         if (tw > mScreenWidth || th > mScreenHeight) {
682             float s1 = (float)tw / (float)mScreenWidth;
683             float s2 = (float)th / (float)mScreenHeight;
684 
685             if (s1 > s2) {
686                 tw /= s1;
687                 th /= s1;
688             } else {
689                 tw /= s2;
690                 th /= s2;
691             }
692         }
693 
694         android.util.Log.v("rs", "TV sizes " + tw + ", " + th);
695 
696         mDisplayView.mWidth = tw;
697         mDisplayView.mHeight = th;
698         //mDisplayView.setTransform(new android.graphics.Matrix());
699 
700         mProcessor = new Processor(RenderScript.create(this), mDisplayView, !mDemoMode);
701         mDisplayView.setSurfaceTextureListener(this);
702 
703         if (mDemoMode) {
704             mProcessor.mTest = changeTest(mTestList[0], true);
705         }
706     }
707 
708     @Override
onResume()709     protected void onResume() {
710         super.onResume();
711         Intent i = getIntent();
712         mTestList = i.getIntArrayExtra("tests");
713 
714         mToggleIO = i.getBooleanExtra("enable io", false);
715         mToggleDVFS = i.getBooleanExtra("enable dvfs", false);
716         mToggleLong = i.getBooleanExtra("enable long", false);
717         mTogglePause = i.getBooleanExtra("enable pause", false);
718         mToggleAnimate = i.getBooleanExtra("enable animate", false);
719         mToggleDisplay = i.getBooleanExtra("enable display", false);
720         mBitmapWidth = i.getIntExtra("resolution X", 0);
721         mBitmapHeight = i.getIntExtra("resolution Y", 0);
722         mDemoMode = i.getBooleanExtra("demo", false);
723 
724         // Default values
725         mMinTestRuntime = 1.0f;
726         mMinTestIterations = 2;
727 
728         // Pass in arguments from "am instrumentation ..." if present
729         // This is wrapped in a try..catch because there was an exception thrown whenever
730         // instrumentation was not used (ie. when the graphical interface was used)
731         try {
732             Bundle extras = InstrumentationRegistry.getArguments();
733             String passedInString = null;
734             if ( extras != null ) {
735                 if ( extras.containsKey ("minimum_test_runtime") ) {
736                     mMinTestRuntime = Float.parseFloat(extras.getString("minimum_test_runtime"));
737                 }
738                 if ( extras.containsKey ("minimum_test_iterations") ) {
739                     mMinTestIterations = Integer.parseInt(
740                             extras.getString("minimum_test_iterations"));
741                 }
742             }
743         } catch(Exception e) {
744         }
745 
746         // User chose the longer pre-set runtime
747         if (mToggleLong) {
748             mMinTestRuntime = 10.f;
749         }
750 
751         // Hide the bars in demo mode.
752         // Calling from onResume() to make sure the operation is on the UI thread.
753         if (!mDemoMode) {
754             hideBars();
755         }
756         // Start the processor only when a non-empty list received from the intent.
757         if (mTestList != null) {
758             mTestResults = new float[mTestList.length];
759             startProcessor();
760         }
761     }
762 
onDestroy()763     protected void onDestroy() {
764         super.onDestroy();
765     }
766 
767 
768     @Override
onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)769     public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
770         mProcessor.setSurface(new Surface(surface));
771     }
772 
773     @Override
onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)774     public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
775         mProcessor.setSurface(new Surface(surface));
776     }
777 
778     @Override
onSurfaceTextureDestroyed(SurfaceTexture surface)779     public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
780         if (mProcessor != null) {
781             mProcessor.setSurface(null);
782         }
783         return true;
784     }
785 
786     @Override
onSurfaceTextureUpdated(SurfaceTexture surface)787     public void onSurfaceTextureUpdated(SurfaceTexture surface) {
788     }
789 }
790