HardwareRenderer.java revision 162a0217563f4665da6eb183dfce0fef740f641f
1/* 2 * Copyright (C) 2010 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 18package android.view; 19 20import android.content.ComponentCallbacks; 21import android.graphics.Paint; 22import android.graphics.Rect; 23import android.graphics.SurfaceTexture; 24import android.os.SystemClock; 25import android.os.SystemProperties; 26import android.util.Log; 27 28import javax.microedition.khronos.egl.EGL10; 29import javax.microedition.khronos.egl.EGL11; 30import javax.microedition.khronos.egl.EGLConfig; 31import javax.microedition.khronos.egl.EGLContext; 32import javax.microedition.khronos.egl.EGLDisplay; 33import javax.microedition.khronos.egl.EGLSurface; 34import javax.microedition.khronos.opengles.GL; 35 36/** 37 * Interface for rendering a ViewAncestor using hardware acceleration. 38 * 39 * @hide 40 */ 41public abstract class HardwareRenderer { 42 static final String LOG_TAG = "HardwareRenderer"; 43 44 /** 45 * Turn on to only refresh the parts of the screen that need updating. 46 * When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY} 47 * must also have the value "true". 48 */ 49 public static final boolean RENDER_DIRTY_REGIONS = true; 50 51 /** 52 * System property used to enable or disable dirty regions invalidation. 53 * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true. 54 * The default value of this property is assumed to be true. 55 * 56 * Possible values: 57 * "true", to enable partial invalidates 58 * "false", to disable partial invalidates 59 */ 60 static final String RENDER_DIRTY_REGIONS_PROPERTY = "hwui.render_dirty_regions"; 61 62 /** 63 * System property used to enable or disable vsync. 64 * The default value of this property is assumed to be false. 65 * 66 * Possible values: 67 * "true", to disable vsync 68 * "false", to enable vsync 69 */ 70 static final String DISABLE_VSYNC_PROPERTY = "hwui.disable_vsync"; 71 72 /** 73 * Turn on to draw dirty regions every other frame. 74 */ 75 private static final boolean DEBUG_DIRTY_REGION = false; 76 77 /** 78 * A process can set this flag to false to prevent the use of hardware 79 * rendering. 80 * 81 * @hide 82 */ 83 public static boolean sRendererDisabled = false; 84 85 private boolean mEnabled; 86 private boolean mRequested = true; 87 88 /** 89 * Invoke this method to disable hardware rendering in the current process. 90 * 91 * @hide 92 */ 93 public static void disable() { 94 sRendererDisabled = true; 95 } 96 97 /** 98 * Indicates whether hardware acceleration is available under any form for 99 * the view hierarchy. 100 * 101 * @return True if the view hierarchy can potentially be hardware accelerated, 102 * false otherwise 103 */ 104 public static boolean isAvailable() { 105 return GLES20Canvas.isAvailable(); 106 } 107 108 /** 109 * Destroys the hardware rendering context. 110 * 111 * @param full If true, destroys all associated resources. 112 */ 113 abstract void destroy(boolean full); 114 115 /** 116 * Initializes the hardware renderer for the specified surface. 117 * 118 * @param holder The holder for the surface to hardware accelerate. 119 * 120 * @return True if the initialization was successful, false otherwise. 121 */ 122 abstract boolean initialize(SurfaceHolder holder) throws Surface.OutOfResourcesException; 123 124 /** 125 * Updates the hardware renderer for the specified surface. 126 * 127 * @param holder The holder for the surface to hardware accelerate. 128 */ 129 abstract void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException; 130 131 /** 132 * This method should be invoked whenever the current hardware renderer 133 * context should be reset. 134 */ 135 abstract void invalidate(); 136 137 /** 138 * This method should be invoked to ensure the hardware renderer is in 139 * valid state (for instance, to ensure the correct EGL context is bound 140 * to the current thread.) 141 * 142 * @return true if the renderer is now valid, false otherwise 143 */ 144 abstract boolean validate(); 145 146 /** 147 * Setup the hardware renderer for drawing. This is called whenever the 148 * size of the target surface changes or when the surface is first created. 149 * 150 * @param width Width of the drawing surface. 151 * @param height Height of the drawing surface. 152 */ 153 abstract void setup(int width, int height); 154 155 /** 156 * Interface used to receive callbacks whenever a view is drawn by 157 * a hardware renderer instance. 158 */ 159 interface HardwareDrawCallbacks { 160 /** 161 * Invoked before a view is drawn by a hardware renderer. 162 * 163 * @param canvas The Canvas used to render the view. 164 */ 165 void onHardwarePreDraw(HardwareCanvas canvas); 166 167 /** 168 * Invoked after a view is drawn by a hardware renderer. 169 * 170 * @param canvas The Canvas used to render the view. 171 */ 172 void onHardwarePostDraw(HardwareCanvas canvas); 173 } 174 175 /** 176 * Draws the specified view. 177 * 178 * @param view The view to draw. 179 * @param attachInfo AttachInfo tied to the specified view. 180 * @param callbacks Callbacks invoked when drawing happens. 181 * @param dirty The dirty rectangle to update, can be null. 182 */ 183 abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks, 184 Rect dirty); 185 186 /** 187 * Creates a new display list that can be used to record batches of 188 * drawing operations. 189 * 190 * @return A new display list. 191 */ 192 abstract DisplayList createDisplayList(); 193 194 /** 195 * Creates a new hardware layer. A hardware layer built by calling this 196 * method will be treated as a texture layer, instead of as a render target. 197 * 198 * @param isOpaque Whether the layer should be opaque or not 199 * 200 * @return A hardware layer 201 */ 202 abstract HardwareLayer createHardwareLayer(boolean isOpaque); 203 204 /** 205 * Creates a new hardware layer. 206 * 207 * @param width The minimum width of the layer 208 * @param height The minimum height of the layer 209 * @param isOpaque Whether the layer should be opaque or not 210 * 211 * @return A hardware layer 212 */ 213 abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque); 214 215 /** 216 * Creates a new {@link SurfaceTexture} that can be used to render into the 217 * specified hardware layer. 218 * 219 * 220 * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture} 221 * 222 * @return A {@link SurfaceTexture} 223 */ 224 abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer); 225 226 /** 227 * Initializes the hardware renderer for the specified surface and setup the 228 * renderer for drawing, if needed. This is invoked when the ViewAncestor has 229 * potentially lost the hardware renderer. The hardware renderer should be 230 * reinitialized and setup when the render {@link #isRequested()} and 231 * {@link #isEnabled()}. 232 * 233 * @param width The width of the drawing surface. 234 * @param height The height of the drawing surface. 235 * @param attachInfo The 236 * @param holder 237 */ 238 void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, 239 SurfaceHolder holder) throws Surface.OutOfResourcesException { 240 if (isRequested()) { 241 // We lost the gl context, so recreate it. 242 if (!isEnabled()) { 243 if (initialize(holder)) { 244 setup(width, height); 245 } 246 } 247 } 248 } 249 250 /** 251 * Creates a hardware renderer using OpenGL. 252 * 253 * @param glVersion The version of OpenGL to use (1 for OpenGL 1, 11 for OpenGL 1.1, etc.) 254 * @param translucent True if the surface is translucent, false otherwise 255 * 256 * @return A hardware renderer backed by OpenGL. 257 */ 258 static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) { 259 switch (glVersion) { 260 case 2: 261 return Gl20Renderer.create(translucent); 262 } 263 throw new IllegalArgumentException("Unknown GL version: " + glVersion); 264 } 265 266 /** 267 * Invoke this method when the system is running out of memory. This 268 * method will attempt to recover as much memory as possible, based on 269 * the specified hint. 270 * 271 * @param level Hint about the amount of memory that should be trimmed, 272 * see {@link android.content.ComponentCallbacks} 273 */ 274 static void trimMemory(int level) { 275 Gl20Renderer.flushCaches(level); 276 } 277 278 /** 279 * Indicates whether hardware acceleration is currently enabled. 280 * 281 * @return True if hardware acceleration is in use, false otherwise. 282 */ 283 boolean isEnabled() { 284 return mEnabled; 285 } 286 287 /** 288 * Indicates whether hardware acceleration is currently enabled. 289 * 290 * @param enabled True if the hardware renderer is in use, false otherwise. 291 */ 292 void setEnabled(boolean enabled) { 293 mEnabled = enabled; 294 } 295 296 /** 297 * Indicates whether hardware acceleration is currently request but not 298 * necessarily enabled yet. 299 * 300 * @return True if requested, false otherwise. 301 */ 302 boolean isRequested() { 303 return mRequested; 304 } 305 306 /** 307 * Indicates whether hardware acceleration is currently requested but not 308 * necessarily enabled yet. 309 * 310 * @return True to request hardware acceleration, false otherwise. 311 */ 312 void setRequested(boolean requested) { 313 mRequested = requested; 314 } 315 316 @SuppressWarnings({"deprecation"}) 317 static abstract class GlRenderer extends HardwareRenderer { 318 // These values are not exposed in our EGL APIs 319 static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 320 static final int EGL_OPENGL_ES2_BIT = 4; 321 static final int EGL_SURFACE_TYPE = 0x3033; 322 static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400; 323 324 private static final int SURFACE_STATE_ERROR = 0; 325 private static final int SURFACE_STATE_SUCCESS = 1; 326 private static final int SURFACE_STATE_UPDATED = 2; 327 328 static EGL10 sEgl; 329 static EGLDisplay sEglDisplay; 330 static EGLConfig sEglConfig; 331 static final Object[] sEglLock = new Object[0]; 332 333 static final ThreadLocal<EGLContext> sEglContextStorage = new ThreadLocal<EGLContext>(); 334 335 EGLContext mEglContext; 336 Thread mEglThread; 337 338 EGLSurface mEglSurface; 339 340 GL mGl; 341 HardwareCanvas mCanvas; 342 int mFrameCount; 343 Paint mDebugPaint; 344 345 static boolean sDirtyRegions; 346 static final boolean sDirtyRegionsRequested; 347 static { 348 String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true"); 349 //noinspection PointlessBooleanExpression,ConstantConditions 350 sDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty); 351 sDirtyRegionsRequested = sDirtyRegions; 352 } 353 354 boolean mDirtyRegionsEnabled; 355 final boolean mVsyncDisabled; 356 357 final int mGlVersion; 358 final boolean mTranslucent; 359 360 private boolean mDestroyed; 361 362 private final Rect mRedrawClip = new Rect(); 363 364 GlRenderer(int glVersion, boolean translucent) { 365 mGlVersion = glVersion; 366 mTranslucent = translucent; 367 368 final String vsyncProperty = SystemProperties.get(DISABLE_VSYNC_PROPERTY, "false"); 369 mVsyncDisabled = "true".equalsIgnoreCase(vsyncProperty); 370 if (mVsyncDisabled) { 371 Log.d(LOG_TAG, "Disabling v-sync"); 372 } 373 } 374 375 /** 376 * Indicates whether this renderer instance can track and update dirty regions. 377 */ 378 boolean hasDirtyRegions() { 379 return mDirtyRegionsEnabled; 380 } 381 382 /** 383 * Return a string for the EGL error code, or the hex representation 384 * if the error is unknown. 385 * 386 * @param error The EGL error to convert into a String. 387 * 388 * @return An error string correponding to the EGL error code. 389 */ 390 static String getEGLErrorString(int error) { 391 switch (error) { 392 case EGL10.EGL_SUCCESS: 393 return "EGL_SUCCESS"; 394 case EGL10.EGL_NOT_INITIALIZED: 395 return "EGL_NOT_INITIALIZED"; 396 case EGL10.EGL_BAD_ACCESS: 397 return "EGL_BAD_ACCESS"; 398 case EGL10.EGL_BAD_ALLOC: 399 return "EGL_BAD_ALLOC"; 400 case EGL10.EGL_BAD_ATTRIBUTE: 401 return "EGL_BAD_ATTRIBUTE"; 402 case EGL10.EGL_BAD_CONFIG: 403 return "EGL_BAD_CONFIG"; 404 case EGL10.EGL_BAD_CONTEXT: 405 return "EGL_BAD_CONTEXT"; 406 case EGL10.EGL_BAD_CURRENT_SURFACE: 407 return "EGL_BAD_CURRENT_SURFACE"; 408 case EGL10.EGL_BAD_DISPLAY: 409 return "EGL_BAD_DISPLAY"; 410 case EGL10.EGL_BAD_MATCH: 411 return "EGL_BAD_MATCH"; 412 case EGL10.EGL_BAD_NATIVE_PIXMAP: 413 return "EGL_BAD_NATIVE_PIXMAP"; 414 case EGL10.EGL_BAD_NATIVE_WINDOW: 415 return "EGL_BAD_NATIVE_WINDOW"; 416 case EGL10.EGL_BAD_PARAMETER: 417 return "EGL_BAD_PARAMETER"; 418 case EGL10.EGL_BAD_SURFACE: 419 return "EGL_BAD_SURFACE"; 420 case EGL11.EGL_CONTEXT_LOST: 421 return "EGL_CONTEXT_LOST"; 422 default: 423 return "0x" + Integer.toHexString(error); 424 } 425 } 426 427 /** 428 * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)} 429 * is invoked and the requested flag is turned off. The error code is 430 * also logged as a warning. 431 */ 432 void checkEglErrors() { 433 if (isEnabled()) { 434 int error = sEgl.eglGetError(); 435 if (error != EGL10.EGL_SUCCESS) { 436 // something bad has happened revert to 437 // normal rendering. 438 fallback(error != EGL11.EGL_CONTEXT_LOST); 439 Log.w(LOG_TAG, "EGL error: " + getEGLErrorString(error)); 440 } 441 } 442 } 443 444 private void fallback(boolean fallback) { 445 destroy(true); 446 if (fallback) { 447 // we'll try again if it was context lost 448 setRequested(false); 449 Log.w(LOG_TAG, "Mountain View, we've had a problem here. " 450 + "Switching back to software rendering."); 451 } 452 } 453 454 @Override 455 boolean initialize(SurfaceHolder holder) throws Surface.OutOfResourcesException { 456 if (isRequested() && !isEnabled()) { 457 initializeEgl(); 458 mGl = createEglSurface(holder); 459 mDestroyed = false; 460 461 if (mGl != null) { 462 int err = sEgl.eglGetError(); 463 if (err != EGL10.EGL_SUCCESS) { 464 destroy(true); 465 setRequested(false); 466 } else { 467 if (mCanvas == null) { 468 mCanvas = createCanvas(); 469 } 470 if (mCanvas != null) { 471 setEnabled(true); 472 } else { 473 Log.w(LOG_TAG, "Hardware accelerated Canvas could not be created"); 474 } 475 } 476 477 return mCanvas != null; 478 } 479 } 480 return false; 481 } 482 483 @Override 484 void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException { 485 if (isRequested() && isEnabled()) { 486 createEglSurface(holder); 487 } 488 } 489 490 abstract GLES20Canvas createCanvas(); 491 492 void initializeEgl() { 493 synchronized (sEglLock) { 494 if (sEgl == null && sEglConfig == null) { 495 sEgl = (EGL10) EGLContext.getEGL(); 496 497 // Get to the default display. 498 sEglDisplay = sEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 499 500 if (sEglDisplay == EGL10.EGL_NO_DISPLAY) { 501 throw new RuntimeException("eglGetDisplay failed " 502 + getEGLErrorString(sEgl.eglGetError())); 503 } 504 505 // We can now initialize EGL for that display 506 int[] version = new int[2]; 507 if (!sEgl.eglInitialize(sEglDisplay, version)) { 508 throw new RuntimeException("eglInitialize failed " + 509 getEGLErrorString(sEgl.eglGetError())); 510 } 511 512 sEglConfig = chooseEglConfig(); 513 if (sEglConfig == null) { 514 // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without 515 if (sDirtyRegions) { 516 sDirtyRegions = false; 517 sEglConfig = chooseEglConfig(); 518 if (sEglConfig == null) { 519 throw new RuntimeException("eglConfig not initialized"); 520 } 521 } else { 522 throw new RuntimeException("eglConfig not initialized"); 523 } 524 } 525 } 526 } 527 528 mEglContext = sEglContextStorage.get(); 529 mEglThread = Thread.currentThread(); 530 531 if (mEglContext == null) { 532 mEglContext = createContext(sEgl, sEglDisplay, sEglConfig); 533 sEglContextStorage.set(mEglContext); 534 } 535 } 536 537 private EGLConfig chooseEglConfig() { 538 int[] configsCount = new int[1]; 539 EGLConfig[] configs = new EGLConfig[1]; 540 int[] configSpec = getConfig(sDirtyRegions); 541 if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) { 542 throw new IllegalArgumentException("eglChooseConfig failed " + 543 getEGLErrorString(sEgl.eglGetError())); 544 } else if (configsCount[0] > 0) { 545 return configs[0]; 546 } 547 return null; 548 } 549 550 abstract int[] getConfig(boolean dirtyRegions); 551 552 GL createEglSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException { 553 // Check preconditions. 554 if (sEgl == null) { 555 throw new RuntimeException("egl not initialized"); 556 } 557 if (sEglDisplay == null) { 558 throw new RuntimeException("eglDisplay not initialized"); 559 } 560 if (sEglConfig == null) { 561 throw new RuntimeException("eglConfig not initialized"); 562 } 563 if (Thread.currentThread() != mEglThread) { 564 throw new IllegalStateException("HardwareRenderer cannot be used " 565 + "from multiple threads"); 566 } 567 568 /* 569 * The window size has changed, so we need to create a new 570 * surface. 571 */ 572 if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) { 573 /* 574 * Unbind and destroy the old EGL surface, if 575 * there is one. 576 */ 577 sEgl.eglMakeCurrent(sEglDisplay, EGL10.EGL_NO_SURFACE, 578 EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); 579 sEgl.eglDestroySurface(sEglDisplay, mEglSurface); 580 } 581 582 // Create an EGL surface we can render into. 583 mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null); 584 585 if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) { 586 int error = sEgl.eglGetError(); 587 if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { 588 Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); 589 return null; 590 } 591 throw new RuntimeException("createWindowSurface failed " 592 + getEGLErrorString(error)); 593 } 594 595 /* 596 * Before we can issue GL commands, we need to make sure 597 * the context is current and bound to a surface. 598 */ 599 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 600 throw new Surface.OutOfResourcesException("eglMakeCurrent failed " 601 + getEGLErrorString(sEgl.eglGetError())); 602 } 603 604 // If mDirtyRegions is set, this means we have an EGL configuration 605 // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set 606 if (sDirtyRegions) { 607 if (!(mDirtyRegionsEnabled = GLES20Canvas.preserveBackBuffer())) { 608 Log.w(LOG_TAG, "Backbuffer cannot be preserved"); 609 } 610 } else if (sDirtyRegionsRequested) { 611 // If mDirtyRegions is not set, our EGL configuration does not 612 // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default 613 // swap behavior might be EGL_BUFFER_PRESERVED, which means we 614 // want to set mDirtyRegions. We try to do this only if dirty 615 // regions were initially requested as part of the device 616 // configuration (see RENDER_DIRTY_REGIONS) 617 mDirtyRegionsEnabled = GLES20Canvas.isBackBufferPreserved(); 618 } 619 620 return mEglContext.getGL(); 621 } 622 623 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { 624 int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL10.EGL_NONE }; 625 626 return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, 627 mGlVersion != 0 ? attrib_list : null); 628 } 629 630 @Override 631 void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, 632 SurfaceHolder holder) throws Surface.OutOfResourcesException { 633 if (isRequested()) { 634 checkEglErrors(); 635 super.initializeIfNeeded(width, height, attachInfo, holder); 636 } 637 } 638 639 @Override 640 void destroy(boolean full) { 641 if (full && mCanvas != null) { 642 mCanvas = null; 643 } 644 645 if (!isEnabled() || mDestroyed) return; 646 647 mDestroyed = true; 648 649 sEgl.eglMakeCurrent(sEglDisplay, EGL10.EGL_NO_SURFACE, 650 EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); 651 sEgl.eglDestroySurface(sEglDisplay, mEglSurface); 652 653 mEglSurface = null; 654 mGl = null; 655 656 setEnabled(false); 657 } 658 659 @Override 660 void invalidate() { 661 // Cancels any existing buffer to ensure we'll get a buffer 662 // of the right size before we call eglSwapBuffers 663 sEgl.eglMakeCurrent(sEglDisplay, EGL10.EGL_NO_SURFACE, 664 EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); 665 } 666 667 @Override 668 boolean validate() { 669 return checkCurrent() != SURFACE_STATE_ERROR; 670 } 671 672 @Override 673 void setup(int width, int height) { 674 mCanvas.setViewport(width, height); 675 } 676 677 boolean canDraw() { 678 return mGl != null && mCanvas != null; 679 } 680 681 void onPreDraw(Rect dirty) { 682 } 683 684 void onPostDraw() { 685 } 686 687 @Override 688 void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks, 689 Rect dirty) { 690 if (canDraw()) { 691 if (!hasDirtyRegions()) { 692 dirty = null; 693 } 694 attachInfo.mIgnoreDirtyState = true; 695 attachInfo.mDrawingTime = SystemClock.uptimeMillis(); 696 697 view.mPrivateFlags |= View.DRAWN; 698 699 final int surfaceState = checkCurrent(); 700 if (surfaceState != SURFACE_STATE_ERROR) { 701 // We had to change the current surface and/or context, redraw everything 702 if (surfaceState == SURFACE_STATE_UPDATED) { 703 dirty = null; 704 } 705 706 onPreDraw(dirty); 707 708 HardwareCanvas canvas = mCanvas; 709 attachInfo.mHardwareCanvas = canvas; 710 711 int saveCount = canvas.save(); 712 callbacks.onHardwarePreDraw(canvas); 713 714 try { 715 view.mRecreateDisplayList = 716 (view.mPrivateFlags & View.INVALIDATED) == View.INVALIDATED; 717 view.mPrivateFlags &= ~View.INVALIDATED; 718 719 DisplayList displayList = view.getDisplayList(); 720 if (displayList != null) { 721 if (canvas.drawDisplayList(displayList, view.getWidth(), 722 view.getHeight(), mRedrawClip)) { 723 if (mRedrawClip.isEmpty() || view.getParent() == null) { 724 view.invalidate(); 725 } else { 726 view.getParent().invalidateChild(view, mRedrawClip); 727 } 728 mRedrawClip.setEmpty(); 729 } 730 } else { 731 // Shouldn't reach here 732 view.draw(canvas); 733 } 734 735 if (DEBUG_DIRTY_REGION) { 736 if (mDebugPaint == null) { 737 mDebugPaint = new Paint(); 738 mDebugPaint.setColor(0x7fff0000); 739 } 740 if (dirty != null && (mFrameCount++ & 1) == 0) { 741 canvas.drawRect(dirty, mDebugPaint); 742 } 743 } 744 } finally { 745 callbacks.onHardwarePostDraw(canvas); 746 canvas.restoreToCount(saveCount); 747 view.mRecreateDisplayList = false; 748 } 749 750 onPostDraw(); 751 752 attachInfo.mIgnoreDirtyState = false; 753 754 sEgl.eglSwapBuffers(sEglDisplay, mEglSurface); 755 checkEglErrors(); 756 } 757 } 758 } 759 760 /** 761 * Ensures the current EGL context is the one we expect. 762 * 763 * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current, 764 * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or 765 * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one 766 */ 767 private int checkCurrent() { 768 if (mEglThread != Thread.currentThread()) { 769 throw new IllegalStateException("Hardware acceleration can only be used with a " + 770 "single UI thread.\nOriginal thread: " + mEglThread + "\n" + 771 "Current thread: " + Thread.currentThread()); 772 } 773 774 if (!mEglContext.equals(sEgl.eglGetCurrentContext()) || 775 !mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) { 776 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 777 fallback(true); 778 Log.e(LOG_TAG, "eglMakeCurrent failed " + 779 getEGLErrorString(sEgl.eglGetError())); 780 return SURFACE_STATE_ERROR; 781 } else { 782 return SURFACE_STATE_UPDATED; 783 } 784 } 785 return SURFACE_STATE_SUCCESS; 786 } 787 } 788 789 /** 790 * Hardware renderer using OpenGL ES 2.0. 791 */ 792 static class Gl20Renderer extends GlRenderer { 793 private GLES20Canvas mGlCanvas; 794 795 Gl20Renderer(boolean translucent) { 796 super(2, translucent); 797 } 798 799 @Override 800 GLES20Canvas createCanvas() { 801 return mGlCanvas = new GLES20Canvas(mTranslucent); 802 } 803 804 @Override 805 int[] getConfig(boolean dirtyRegions) { 806 return new int[] { 807 EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 808 EGL10.EGL_RED_SIZE, 8, 809 EGL10.EGL_GREEN_SIZE, 8, 810 EGL10.EGL_BLUE_SIZE, 8, 811 EGL10.EGL_ALPHA_SIZE, 8, 812 EGL10.EGL_DEPTH_SIZE, 0, 813 EGL10.EGL_STENCIL_SIZE, 0, 814 EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT | 815 (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0), 816 EGL10.EGL_NONE 817 }; 818 } 819 820 @Override 821 boolean canDraw() { 822 return super.canDraw() && mGlCanvas != null; 823 } 824 825 @Override 826 void onPreDraw(Rect dirty) { 827 mGlCanvas.onPreDraw(dirty); 828 } 829 830 @Override 831 void onPostDraw() { 832 mGlCanvas.onPostDraw(); 833 } 834 835 @Override 836 void destroy(boolean full) { 837 try { 838 super.destroy(full); 839 } finally { 840 if (full && mGlCanvas != null) { 841 mGlCanvas = null; 842 } 843 } 844 } 845 846 @Override 847 void setup(int width, int height) { 848 super.setup(width, height); 849 if (mVsyncDisabled) { 850 GLES20Canvas.disableVsync(); 851 } 852 } 853 854 @Override 855 DisplayList createDisplayList() { 856 return new GLES20DisplayList(); 857 } 858 859 @Override 860 HardwareLayer createHardwareLayer(boolean isOpaque) { 861 return new GLES20TextureLayer(isOpaque); 862 } 863 864 @Override 865 HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) { 866 return new GLES20RenderLayer(width, height, isOpaque); 867 } 868 869 @Override 870 SurfaceTexture createSurfaceTexture(HardwareLayer layer) { 871 return ((GLES20TextureLayer) layer).getSurfaceTexture(); 872 } 873 874 static HardwareRenderer create(boolean translucent) { 875 if (GLES20Canvas.isAvailable()) { 876 return new Gl20Renderer(translucent); 877 } 878 return null; 879 } 880 881 static void flushCaches(int level) { 882 switch (level) { 883 case ComponentCallbacks.TRIM_MEMORY_MODERATE: 884 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE); 885 break; 886 case ComponentCallbacks.TRIM_MEMORY_COMPLETE: 887 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL); 888 break; 889 } 890 } 891 } 892} 893