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