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