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