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