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