1 /* 2 * Copyright (C) 2007 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 package android.view; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.UnsupportedAppUsage; 22 import android.content.res.CompatibilityInfo.Translator; 23 import android.graphics.Canvas; 24 import android.graphics.GraphicBuffer; 25 import android.graphics.Matrix; 26 import android.graphics.RecordingCanvas; 27 import android.graphics.Rect; 28 import android.graphics.RenderNode; 29 import android.graphics.SurfaceTexture; 30 import android.os.Parcel; 31 import android.os.Parcelable; 32 import android.util.Log; 33 34 import dalvik.system.CloseGuard; 35 36 import java.lang.annotation.Retention; 37 import java.lang.annotation.RetentionPolicy; 38 39 /** 40 * Handle onto a raw buffer that is being managed by the screen compositor. 41 * 42 * <p>A Surface is generally created by or from a consumer of image buffers (such as a 43 * {@link android.graphics.SurfaceTexture}, {@link android.media.MediaRecorder}, or 44 * {@link android.renderscript.Allocation}), and is handed to some kind of producer (such as 45 * {@link android.opengl.EGL14#eglCreateWindowSurface(android.opengl.EGLDisplay,android.opengl.EGLConfig,java.lang.Object,int[],int) OpenGL}, 46 * {@link android.media.MediaPlayer#setSurface MediaPlayer}, or 47 * {@link android.hardware.camera2.CameraDevice#createCaptureSession CameraDevice}) to draw 48 * into.</p> 49 * 50 * <p><strong>Note:</strong> A Surface acts like a 51 * {@link java.lang.ref.WeakReference weak reference} to the consumer it is associated with. By 52 * itself it will not keep its parent consumer from being reclaimed.</p> 53 */ 54 public class Surface implements Parcelable { 55 private static final String TAG = "Surface"; 56 nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)57 private static native long nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture) 58 throws OutOfResourcesException; 59 nativeCreateFromSurfaceControl(long surfaceControlNativeObject)60 private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject); nativeGetFromSurfaceControl(long surfaceObject, long surfaceControlNativeObject)61 private static native long nativeGetFromSurfaceControl(long surfaceObject, 62 long surfaceControlNativeObject); 63 nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)64 private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty) 65 throws OutOfResourcesException; nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas)66 private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas); 67 68 @UnsupportedAppUsage nativeRelease(long nativeObject)69 private static native void nativeRelease(long nativeObject); nativeIsValid(long nativeObject)70 private static native boolean nativeIsValid(long nativeObject); nativeIsConsumerRunningBehind(long nativeObject)71 private static native boolean nativeIsConsumerRunningBehind(long nativeObject); nativeReadFromParcel(long nativeObject, Parcel source)72 private static native long nativeReadFromParcel(long nativeObject, Parcel source); nativeWriteToParcel(long nativeObject, Parcel dest)73 private static native void nativeWriteToParcel(long nativeObject, Parcel dest); 74 nativeAllocateBuffers(long nativeObject)75 private static native void nativeAllocateBuffers(long nativeObject); 76 nativeGetWidth(long nativeObject)77 private static native int nativeGetWidth(long nativeObject); nativeGetHeight(long nativeObject)78 private static native int nativeGetHeight(long nativeObject); 79 nativeGetNextFrameNumber(long nativeObject)80 private static native long nativeGetNextFrameNumber(long nativeObject); nativeSetScalingMode(long nativeObject, int scalingMode)81 private static native int nativeSetScalingMode(long nativeObject, int scalingMode); nativeForceScopedDisconnect(long nativeObject)82 private static native int nativeForceScopedDisconnect(long nativeObject); nativeAttachAndQueueBuffer(long nativeObject, GraphicBuffer buffer)83 private static native int nativeAttachAndQueueBuffer(long nativeObject, GraphicBuffer buffer); 84 nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled)85 private static native int nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled); nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled)86 private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled); 87 88 public static final @android.annotation.NonNull Parcelable.Creator<Surface> CREATOR = 89 new Parcelable.Creator<Surface>() { 90 @Override 91 public Surface createFromParcel(Parcel source) { 92 try { 93 Surface s = new Surface(); 94 s.readFromParcel(source); 95 return s; 96 } catch (Exception e) { 97 Log.e(TAG, "Exception creating surface from parcel", e); 98 return null; 99 } 100 } 101 102 @Override 103 public Surface[] newArray(int size) { 104 return new Surface[size]; 105 } 106 }; 107 108 private final CloseGuard mCloseGuard = CloseGuard.get(); 109 110 // Guarded state. 111 @UnsupportedAppUsage 112 final Object mLock = new Object(); // protects the native state 113 @UnsupportedAppUsage 114 private String mName; 115 @UnsupportedAppUsage 116 long mNativeObject; // package scope only for SurfaceControl access 117 @UnsupportedAppUsage 118 private long mLockedObject; 119 private int mGenerationId; // incremented each time mNativeObject changes 120 private final Canvas mCanvas = new CompatibleCanvas(); 121 122 // A matrix to scale the matrix set by application. This is set to null for 123 // non compatibility mode. 124 private Matrix mCompatibleMatrix; 125 126 private HwuiContext mHwuiContext; 127 128 private boolean mIsSingleBuffered; 129 private boolean mIsSharedBufferModeEnabled; 130 private boolean mIsAutoRefreshEnabled; 131 132 /** @hide */ 133 @Retention(RetentionPolicy.SOURCE) 134 @IntDef(prefix = { "SCALING_MODE_" }, value = { 135 SCALING_MODE_FREEZE, 136 SCALING_MODE_SCALE_TO_WINDOW, 137 SCALING_MODE_SCALE_CROP, 138 SCALING_MODE_NO_SCALE_CROP 139 }) 140 public @interface ScalingMode {} 141 // From system/window.h 142 /** @hide */ 143 public static final int SCALING_MODE_FREEZE = 0; 144 /** @hide */ 145 public static final int SCALING_MODE_SCALE_TO_WINDOW = 1; 146 /** @hide */ 147 public static final int SCALING_MODE_SCALE_CROP = 2; 148 /** @hide */ 149 public static final int SCALING_MODE_NO_SCALE_CROP = 3; 150 151 /** @hide */ 152 @IntDef(prefix = { "ROTATION_" }, value = { 153 ROTATION_0, 154 ROTATION_90, 155 ROTATION_180, 156 ROTATION_270 157 }) 158 @Retention(RetentionPolicy.SOURCE) 159 public @interface Rotation {} 160 161 /** 162 * Rotation constant: 0 degree rotation (natural orientation) 163 */ 164 public static final int ROTATION_0 = 0; 165 166 /** 167 * Rotation constant: 90 degree rotation. 168 */ 169 public static final int ROTATION_90 = 1; 170 171 /** 172 * Rotation constant: 180 degree rotation. 173 */ 174 public static final int ROTATION_180 = 2; 175 176 /** 177 * Rotation constant: 270 degree rotation. 178 */ 179 public static final int ROTATION_270 = 3; 180 181 /** 182 * Create an empty surface, which will later be filled in by readFromParcel(). 183 * @hide 184 */ 185 @UnsupportedAppUsage Surface()186 public Surface() { 187 } 188 189 /** 190 * Create a Surface assosciated with a given {@link SurfaceControl}. Buffers submitted to this 191 * surface will be displayed by the system compositor according to the parameters 192 * specified by the control. Multiple surfaces may be constructed from one SurfaceControl, 193 * but only one can be connected (e.g. have an active EGL context) at a time. 194 * 195 * @param from The SurfaceControl to assosciate this Surface with 196 */ Surface(@onNull SurfaceControl from)197 public Surface(@NonNull SurfaceControl from) { 198 copyFrom(from); 199 } 200 201 /** 202 * Create Surface from a {@link SurfaceTexture}. 203 * 204 * Images drawn to the Surface will be made available to the {@link 205 * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link 206 * SurfaceTexture#updateTexImage}. 207 * 208 * Please note that holding onto the Surface created here is not enough to 209 * keep the provided SurfaceTexture from being reclaimed. In that sense, 210 * the Surface will act like a 211 * {@link java.lang.ref.WeakReference weak reference} to the SurfaceTexture. 212 * 213 * @param surfaceTexture The {@link SurfaceTexture} that is updated by this 214 * Surface. 215 * @throws OutOfResourcesException if the surface could not be created. 216 */ Surface(SurfaceTexture surfaceTexture)217 public Surface(SurfaceTexture surfaceTexture) { 218 if (surfaceTexture == null) { 219 throw new IllegalArgumentException("surfaceTexture must not be null"); 220 } 221 mIsSingleBuffered = surfaceTexture.isSingleBuffered(); 222 synchronized (mLock) { 223 mName = surfaceTexture.toString(); 224 setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture)); 225 } 226 } 227 228 /* called from android_view_Surface_createFromIGraphicBufferProducer() */ 229 @UnsupportedAppUsage Surface(long nativeObject)230 private Surface(long nativeObject) { 231 synchronized (mLock) { 232 setNativeObjectLocked(nativeObject); 233 } 234 } 235 236 @Override finalize()237 protected void finalize() throws Throwable { 238 try { 239 if (mCloseGuard != null) { 240 mCloseGuard.warnIfOpen(); 241 } 242 release(); 243 } finally { 244 super.finalize(); 245 } 246 } 247 248 /** 249 * Release the local reference to the server-side surface. 250 * Always call release() when you're done with a Surface. 251 * This will make the surface invalid. 252 */ release()253 public void release() { 254 synchronized (mLock) { 255 if (mNativeObject != 0) { 256 nativeRelease(mNativeObject); 257 setNativeObjectLocked(0); 258 } 259 if (mHwuiContext != null) { 260 mHwuiContext.destroy(); 261 mHwuiContext = null; 262 } 263 } 264 } 265 266 /** 267 * Free all server-side state associated with this surface and 268 * release this object's reference. This method can only be 269 * called from the process that created the service. 270 * @hide 271 */ 272 @UnsupportedAppUsage destroy()273 public void destroy() { 274 release(); 275 } 276 277 /** 278 * Destroys the HwuiContext without completely 279 * releasing the Surface. 280 * @hide 281 */ hwuiDestroy()282 public void hwuiDestroy() { 283 if (mHwuiContext != null) { 284 mHwuiContext.destroy(); 285 mHwuiContext = null; 286 } 287 } 288 289 /** 290 * Returns true if this object holds a valid surface. 291 * 292 * @return True if it holds a physical surface, so lockCanvas() will succeed. 293 * Otherwise returns false. 294 */ isValid()295 public boolean isValid() { 296 synchronized (mLock) { 297 if (mNativeObject == 0) return false; 298 return nativeIsValid(mNativeObject); 299 } 300 } 301 302 /** 303 * Gets the generation number of this surface, incremented each time 304 * the native surface contained within this object changes. 305 * 306 * @return The current generation number. 307 * @hide 308 */ getGenerationId()309 public int getGenerationId() { 310 synchronized (mLock) { 311 return mGenerationId; 312 } 313 } 314 315 /** 316 * Returns the next frame number which will be dequeued for rendering. 317 * Intended for use with SurfaceFlinger's deferred transactions API. 318 * 319 * @hide 320 */ 321 @UnsupportedAppUsage getNextFrameNumber()322 public long getNextFrameNumber() { 323 synchronized (mLock) { 324 checkNotReleasedLocked(); 325 return nativeGetNextFrameNumber(mNativeObject); 326 } 327 } 328 329 /** 330 * Returns true if the consumer of this Surface is running behind the producer. 331 * 332 * @return True if the consumer is more than one buffer ahead of the producer. 333 * @hide 334 */ isConsumerRunningBehind()335 public boolean isConsumerRunningBehind() { 336 synchronized (mLock) { 337 checkNotReleasedLocked(); 338 return nativeIsConsumerRunningBehind(mNativeObject); 339 } 340 } 341 342 /** 343 * Gets a {@link Canvas} for drawing into this surface. 344 * 345 * After drawing into the provided {@link Canvas}, the caller must 346 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. 347 * 348 * @param inOutDirty A rectangle that represents the dirty region that the caller wants 349 * to redraw. This function may choose to expand the dirty rectangle if for example 350 * the surface has been resized or if the previous contents of the surface were 351 * not available. The caller must redraw the entire dirty region as represented 352 * by the contents of the inOutDirty rectangle upon return from this function. 353 * The caller may also pass <code>null</code> instead, in the case where the 354 * entire surface should be redrawn. 355 * @return A canvas for drawing into the surface. 356 * 357 * @throws IllegalArgumentException If the inOutDirty rectangle is not valid. 358 * @throws OutOfResourcesException If the canvas cannot be locked. 359 */ lockCanvas(Rect inOutDirty)360 public Canvas lockCanvas(Rect inOutDirty) 361 throws Surface.OutOfResourcesException, IllegalArgumentException { 362 synchronized (mLock) { 363 checkNotReleasedLocked(); 364 if (mLockedObject != 0) { 365 // Ideally, nativeLockCanvas() would throw in this situation and prevent the 366 // double-lock, but that won't happen if mNativeObject was updated. We can't 367 // abandon the old mLockedObject because it might still be in use, so instead 368 // we just refuse to re-lock the Surface. 369 throw new IllegalArgumentException("Surface was already locked"); 370 } 371 mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty); 372 return mCanvas; 373 } 374 } 375 376 /** 377 * Posts the new contents of the {@link Canvas} to the surface and 378 * releases the {@link Canvas}. 379 * 380 * @param canvas The canvas previously obtained from {@link #lockCanvas}. 381 */ unlockCanvasAndPost(Canvas canvas)382 public void unlockCanvasAndPost(Canvas canvas) { 383 synchronized (mLock) { 384 checkNotReleasedLocked(); 385 386 if (mHwuiContext != null) { 387 mHwuiContext.unlockAndPost(canvas); 388 } else { 389 unlockSwCanvasAndPost(canvas); 390 } 391 } 392 } 393 unlockSwCanvasAndPost(Canvas canvas)394 private void unlockSwCanvasAndPost(Canvas canvas) { 395 if (canvas != mCanvas) { 396 throw new IllegalArgumentException("canvas object must be the same instance that " 397 + "was previously returned by lockCanvas"); 398 } 399 if (mNativeObject != mLockedObject) { 400 Log.w(TAG, "WARNING: Surface's mNativeObject (0x" + 401 Long.toHexString(mNativeObject) + ") != mLockedObject (0x" + 402 Long.toHexString(mLockedObject) +")"); 403 } 404 if (mLockedObject == 0) { 405 throw new IllegalStateException("Surface was not locked"); 406 } 407 try { 408 nativeUnlockCanvasAndPost(mLockedObject, canvas); 409 } finally { 410 nativeRelease(mLockedObject); 411 mLockedObject = 0; 412 } 413 } 414 415 /** 416 * Gets a {@link Canvas} for drawing into this surface. 417 * 418 * After drawing into the provided {@link Canvas}, the caller must 419 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. 420 * 421 * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated 422 * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported"> 423 * unsupported drawing operations</a> for a list of what is and isn't 424 * supported in a hardware-accelerated canvas. It is also required to 425 * fully cover the surface every time {@link #lockHardwareCanvas()} is 426 * called as the buffer is not preserved between frames. Partial updates 427 * are not supported. 428 * 429 * @return A canvas for drawing into the surface. 430 * 431 * @throws IllegalStateException If the canvas cannot be locked. 432 */ lockHardwareCanvas()433 public Canvas lockHardwareCanvas() { 434 synchronized (mLock) { 435 checkNotReleasedLocked(); 436 if (mHwuiContext == null) { 437 mHwuiContext = new HwuiContext(false); 438 } 439 return mHwuiContext.lockCanvas( 440 nativeGetWidth(mNativeObject), 441 nativeGetHeight(mNativeObject)); 442 } 443 } 444 445 /** 446 * Gets a {@link Canvas} for drawing into this surface that supports wide color gamut. 447 * 448 * After drawing into the provided {@link Canvas}, the caller must 449 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. 450 * 451 * Unlike {@link #lockCanvas(Rect)} and {@link #lockHardwareCanvas()}, 452 * this will return a hardware-accelerated canvas that supports wide color gamut. 453 * See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported"> 454 * unsupported drawing operations</a> for a list of what is and isn't 455 * supported in a hardware-accelerated canvas. It is also required to 456 * fully cover the surface every time {@link #lockHardwareCanvas()} is 457 * called as the buffer is not preserved between frames. Partial updates 458 * are not supported. 459 * 460 * @return A canvas for drawing into the surface. 461 * 462 * @throws IllegalStateException If the canvas cannot be locked. 463 * 464 * @hide 465 */ lockHardwareWideColorGamutCanvas()466 public Canvas lockHardwareWideColorGamutCanvas() { 467 synchronized (mLock) { 468 checkNotReleasedLocked(); 469 if (mHwuiContext != null && !mHwuiContext.isWideColorGamut()) { 470 mHwuiContext.destroy(); 471 mHwuiContext = null; 472 } 473 if (mHwuiContext == null) { 474 mHwuiContext = new HwuiContext(true); 475 } 476 return mHwuiContext.lockCanvas( 477 nativeGetWidth(mNativeObject), 478 nativeGetHeight(mNativeObject)); 479 } 480 } 481 482 /** 483 * @deprecated This API has been removed and is not supported. Do not use. 484 */ 485 @Deprecated unlockCanvas(Canvas canvas)486 public void unlockCanvas(Canvas canvas) { 487 throw new UnsupportedOperationException(); 488 } 489 490 /** 491 * Sets the translator used to scale canvas's width/height in compatibility 492 * mode. 493 */ setCompatibilityTranslator(Translator translator)494 void setCompatibilityTranslator(Translator translator) { 495 if (translator != null) { 496 float appScale = translator.applicationScale; 497 mCompatibleMatrix = new Matrix(); 498 mCompatibleMatrix.setScale(appScale, appScale); 499 } 500 } 501 502 /** 503 * Copy another surface to this one. This surface now holds a reference 504 * to the same data as the original surface, and is -not- the owner. 505 * This is for use by the window manager when returning a window surface 506 * back from a client, converting it from the representation being managed 507 * by the window manager to the representation the client uses to draw 508 * in to it. 509 * 510 * @param other {@link SurfaceControl} to copy from. 511 * @hide 512 */ 513 @UnsupportedAppUsage copyFrom(SurfaceControl other)514 public void copyFrom(SurfaceControl other) { 515 if (other == null) { 516 throw new IllegalArgumentException("other must not be null"); 517 } 518 519 long surfaceControlPtr = other.mNativeObject; 520 if (surfaceControlPtr == 0) { 521 throw new NullPointerException( 522 "null SurfaceControl native object. Are you using a released SurfaceControl?"); 523 } 524 long newNativeObject = nativeGetFromSurfaceControl(mNativeObject, surfaceControlPtr); 525 526 synchronized (mLock) { 527 if (newNativeObject == mNativeObject) { 528 return; 529 } 530 if (mNativeObject != 0) { 531 nativeRelease(mNativeObject); 532 } 533 setNativeObjectLocked(newNativeObject); 534 } 535 } 536 537 /** 538 * Gets a reference a surface created from this one. This surface now holds a reference 539 * to the same data as the original surface, and is -not- the owner. 540 * This is for use by the window manager when returning a window surface 541 * back from a client, converting it from the representation being managed 542 * by the window manager to the representation the client uses to draw 543 * in to it. 544 * 545 * @param other {@link SurfaceControl} to create surface from. 546 * 547 * @hide 548 */ createFrom(SurfaceControl other)549 public void createFrom(SurfaceControl other) { 550 if (other == null) { 551 throw new IllegalArgumentException("other must not be null"); 552 } 553 554 long surfaceControlPtr = other.mNativeObject; 555 if (surfaceControlPtr == 0) { 556 throw new NullPointerException( 557 "null SurfaceControl native object. Are you using a released SurfaceControl?"); 558 } 559 long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr); 560 561 synchronized (mLock) { 562 if (mNativeObject != 0) { 563 nativeRelease(mNativeObject); 564 } 565 setNativeObjectLocked(newNativeObject); 566 } 567 } 568 569 /** 570 * This is intended to be used by {@link SurfaceView#updateWindow} only. 571 * @param other access is not thread safe 572 * @hide 573 * @deprecated 574 */ 575 @Deprecated 576 @UnsupportedAppUsage transferFrom(Surface other)577 public void transferFrom(Surface other) { 578 if (other == null) { 579 throw new IllegalArgumentException("other must not be null"); 580 } 581 if (other != this) { 582 final long newPtr; 583 synchronized (other.mLock) { 584 newPtr = other.mNativeObject; 585 other.setNativeObjectLocked(0); 586 } 587 588 synchronized (mLock) { 589 if (mNativeObject != 0) { 590 nativeRelease(mNativeObject); 591 } 592 setNativeObjectLocked(newPtr); 593 } 594 } 595 } 596 597 @Override describeContents()598 public int describeContents() { 599 return 0; 600 } 601 readFromParcel(Parcel source)602 public void readFromParcel(Parcel source) { 603 if (source == null) { 604 throw new IllegalArgumentException("source must not be null"); 605 } 606 607 synchronized (mLock) { 608 // nativeReadFromParcel() will either return mNativeObject, or 609 // create a new native Surface and return it after reducing 610 // the reference count on mNativeObject. Either way, it is 611 // not necessary to call nativeRelease() here. 612 // NOTE: This must be kept synchronized with the native parceling code 613 // in frameworks/native/libs/Surface.cpp 614 mName = source.readString(); 615 mIsSingleBuffered = source.readInt() != 0; 616 setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source)); 617 } 618 } 619 620 @Override writeToParcel(Parcel dest, int flags)621 public void writeToParcel(Parcel dest, int flags) { 622 if (dest == null) { 623 throw new IllegalArgumentException("dest must not be null"); 624 } 625 synchronized (mLock) { 626 // NOTE: This must be kept synchronized with the native parceling code 627 // in frameworks/native/libs/Surface.cpp 628 dest.writeString(mName); 629 dest.writeInt(mIsSingleBuffered ? 1 : 0); 630 nativeWriteToParcel(mNativeObject, dest); 631 } 632 if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) { 633 release(); 634 } 635 } 636 637 @Override toString()638 public String toString() { 639 synchronized (mLock) { 640 return "Surface(name=" + mName + ")/@0x" + 641 Integer.toHexString(System.identityHashCode(this)); 642 } 643 } 644 setNativeObjectLocked(long ptr)645 private void setNativeObjectLocked(long ptr) { 646 if (mNativeObject != ptr) { 647 if (mNativeObject == 0 && ptr != 0) { 648 mCloseGuard.open("release"); 649 } else if (mNativeObject != 0 && ptr == 0) { 650 mCloseGuard.close(); 651 } 652 mNativeObject = ptr; 653 mGenerationId += 1; 654 if (mHwuiContext != null) { 655 mHwuiContext.updateSurface(); 656 } 657 } 658 } 659 checkNotReleasedLocked()660 private void checkNotReleasedLocked() { 661 if (mNativeObject == 0) { 662 throw new IllegalStateException("Surface has already been released."); 663 } 664 } 665 666 /** 667 * Allocate buffers ahead of time to avoid allocation delays during rendering 668 * @hide 669 */ allocateBuffers()670 public void allocateBuffers() { 671 synchronized (mLock) { 672 checkNotReleasedLocked(); 673 nativeAllocateBuffers(mNativeObject); 674 } 675 } 676 677 /** 678 * Set the scaling mode to be used for this surfaces buffers 679 * @hide 680 */ setScalingMode(@calingMode int scalingMode)681 void setScalingMode(@ScalingMode int scalingMode) { 682 synchronized (mLock) { 683 checkNotReleasedLocked(); 684 int err = nativeSetScalingMode(mNativeObject, scalingMode); 685 if (err != 0) { 686 throw new IllegalArgumentException("Invalid scaling mode: " + scalingMode); 687 } 688 } 689 } 690 forceScopedDisconnect()691 void forceScopedDisconnect() { 692 synchronized (mLock) { 693 checkNotReleasedLocked(); 694 int err = nativeForceScopedDisconnect(mNativeObject); 695 if (err != 0) { 696 throw new RuntimeException("Failed to disconnect Surface instance (bad object?)"); 697 } 698 } 699 } 700 701 /** 702 * Transfer ownership of buffer and present it on the Surface. 703 * @hide 704 */ attachAndQueueBuffer(GraphicBuffer buffer)705 public void attachAndQueueBuffer(GraphicBuffer buffer) { 706 synchronized (mLock) { 707 checkNotReleasedLocked(); 708 int err = nativeAttachAndQueueBuffer(mNativeObject, buffer); 709 if (err != 0) { 710 throw new RuntimeException( 711 "Failed to attach and queue buffer to Surface (bad object?)"); 712 } 713 } 714 } 715 716 /** 717 * Returns whether or not this Surface is backed by a single-buffered SurfaceTexture 718 * @hide 719 */ isSingleBuffered()720 public boolean isSingleBuffered() { 721 return mIsSingleBuffered; 722 } 723 724 /** 725 * <p>The shared buffer mode allows both the application and the surface compositor 726 * (SurfaceFlinger) to concurrently access this surface's buffer. While the 727 * application is still required to issue a present request 728 * (see {@link #unlockCanvasAndPost(Canvas)}) to the compositor when an update is required, 729 * the compositor may trigger an update at any time. Since the surface's buffer is shared 730 * between the application and the compositor, updates triggered by the compositor may 731 * cause visible tearing.</p> 732 * 733 * <p>The shared buffer mode can be used with 734 * {@link #setAutoRefreshEnabled(boolean) auto-refresh} to avoid the overhead of 735 * issuing present requests.</p> 736 * 737 * <p>If the application uses the shared buffer mode to reduce latency, it is 738 * recommended to use software rendering (see {@link #lockCanvas(Rect)} to ensure 739 * the graphics workloads are not affected by other applications and/or the system 740 * using the GPU. When using software rendering, the application should update the 741 * smallest possible region of the surface required.</p> 742 * 743 * <p class="note">The shared buffer mode might not be supported by the underlying 744 * hardware. Enabling shared buffer mode on hardware that does not support it will 745 * not yield an error but the application will not benefit from lower latency (and 746 * tearing will not be visible).</p> 747 * 748 * <p class="note">Depending on how many and what kind of surfaces are visible, the 749 * surface compositor may need to copy the shared buffer before it is displayed. When 750 * this happens, the latency benefits of shared buffer mode will be reduced.</p> 751 * 752 * @param enabled True to enable the shared buffer mode on this surface, false otherwise 753 * 754 * @see #isSharedBufferModeEnabled() 755 * @see #setAutoRefreshEnabled(boolean) 756 * 757 * @hide 758 */ setSharedBufferModeEnabled(boolean enabled)759 public void setSharedBufferModeEnabled(boolean enabled) { 760 if (mIsSharedBufferModeEnabled != enabled) { 761 int error = nativeSetSharedBufferModeEnabled(mNativeObject, enabled); 762 if (error != 0) { 763 throw new RuntimeException( 764 "Failed to set shared buffer mode on Surface (bad object?)"); 765 } else { 766 mIsSharedBufferModeEnabled = enabled; 767 } 768 } 769 } 770 771 /** 772 * @return True if shared buffer mode is enabled on this surface, false otherwise 773 * 774 * @see #setSharedBufferModeEnabled(boolean) 775 * 776 * @hide 777 */ isSharedBufferModeEnabled()778 public boolean isSharedBufferModeEnabled() { 779 return mIsSharedBufferModeEnabled; 780 } 781 782 /** 783 * <p>When auto-refresh is enabled, the surface compositor (SurfaceFlinger) 784 * automatically updates the display on a regular refresh cycle. The application 785 * can continue to issue present requests but it is not required. Enabling 786 * auto-refresh may result in visible tearing.</p> 787 * 788 * <p>Auto-refresh has no effect if the {@link #setSharedBufferModeEnabled(boolean) 789 * shared buffer mode} is not enabled.</p> 790 * 791 * <p>Because auto-refresh will trigger continuous updates of the display, it is 792 * recommended to turn it on only when necessary. For example, in a drawing/painting 793 * application auto-refresh should be enabled on finger/pen down and disabled on 794 * finger/pen up.</p> 795 * 796 * @param enabled True to enable auto-refresh on this surface, false otherwise 797 * 798 * @see #isAutoRefreshEnabled() 799 * @see #setSharedBufferModeEnabled(boolean) 800 * 801 * @hide 802 */ setAutoRefreshEnabled(boolean enabled)803 public void setAutoRefreshEnabled(boolean enabled) { 804 if (mIsAutoRefreshEnabled != enabled) { 805 int error = nativeSetAutoRefreshEnabled(mNativeObject, enabled); 806 if (error != 0) { 807 throw new RuntimeException("Failed to set auto refresh on Surface (bad object?)"); 808 } else { 809 mIsAutoRefreshEnabled = enabled; 810 } 811 } 812 } 813 814 /** 815 * @return True if auto-refresh is enabled on this surface, false otherwise 816 * 817 * @hide 818 */ isAutoRefreshEnabled()819 public boolean isAutoRefreshEnabled() { 820 return mIsAutoRefreshEnabled; 821 } 822 823 /** 824 * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or 825 * when a SurfaceTexture could not successfully be allocated. 826 */ 827 @SuppressWarnings("serial") 828 public static class OutOfResourcesException extends RuntimeException { OutOfResourcesException()829 public OutOfResourcesException() { 830 } OutOfResourcesException(String name)831 public OutOfResourcesException(String name) { 832 super(name); 833 } 834 } 835 836 /** 837 * Returns a human readable representation of a rotation. 838 * 839 * @param rotation The rotation. 840 * @return The rotation symbolic name. 841 * 842 * @hide 843 */ rotationToString(int rotation)844 public static String rotationToString(int rotation) { 845 switch (rotation) { 846 case Surface.ROTATION_0: { 847 return "ROTATION_0"; 848 } 849 case Surface.ROTATION_90: { 850 return "ROTATION_90"; 851 } 852 case Surface.ROTATION_180: { 853 return "ROTATION_180"; 854 } 855 case Surface.ROTATION_270: { 856 return "ROTATION_270"; 857 } 858 default: { 859 return Integer.toString(rotation); 860 } 861 } 862 } 863 864 /** 865 * A Canvas class that can handle the compatibility mode. 866 * This does two things differently. 867 * <ul> 868 * <li>Returns the width and height of the target metrics, rather than 869 * native. For example, the canvas returns 320x480 even if an app is running 870 * in WVGA high density. 871 * <li>Scales the matrix in setMatrix by the application scale, except if 872 * the matrix looks like obtained from getMatrix. This is a hack to handle 873 * the case that an application uses getMatrix to keep the original matrix, 874 * set matrix of its own, then set the original matrix back. There is no 875 * perfect solution that works for all cases, and there are a lot of cases 876 * that this model does not work, but we hope this works for many apps. 877 * </ul> 878 */ 879 private final class CompatibleCanvas extends Canvas { 880 // A temp matrix to remember what an application obtained via {@link getMatrix} 881 private Matrix mOrigMatrix = null; 882 883 @Override setMatrix(Matrix matrix)884 public void setMatrix(Matrix matrix) { 885 if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) { 886 // don't scale the matrix if it's not compatibility mode, or 887 // the matrix was obtained from getMatrix. 888 super.setMatrix(matrix); 889 } else { 890 Matrix m = new Matrix(mCompatibleMatrix); 891 m.preConcat(matrix); 892 super.setMatrix(m); 893 } 894 } 895 896 @SuppressWarnings("deprecation") 897 @Override getMatrix(Matrix m)898 public void getMatrix(Matrix m) { 899 super.getMatrix(m); 900 if (mOrigMatrix == null) { 901 mOrigMatrix = new Matrix(); 902 } 903 mOrigMatrix.set(m); 904 } 905 } 906 907 private final class HwuiContext { 908 private final RenderNode mRenderNode; 909 private long mHwuiRenderer; 910 private RecordingCanvas mCanvas; 911 private final boolean mIsWideColorGamut; 912 HwuiContext(boolean isWideColorGamut)913 HwuiContext(boolean isWideColorGamut) { 914 mRenderNode = RenderNode.create("HwuiCanvas", null); 915 mRenderNode.setClipToBounds(false); 916 mRenderNode.setForceDarkAllowed(false); 917 mIsWideColorGamut = isWideColorGamut; 918 mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject, 919 isWideColorGamut); 920 } 921 lockCanvas(int width, int height)922 Canvas lockCanvas(int width, int height) { 923 if (mCanvas != null) { 924 throw new IllegalStateException("Surface was already locked!"); 925 } 926 mCanvas = mRenderNode.beginRecording(width, height); 927 return mCanvas; 928 } 929 unlockAndPost(Canvas canvas)930 void unlockAndPost(Canvas canvas) { 931 if (canvas != mCanvas) { 932 throw new IllegalArgumentException("canvas object must be the same instance that " 933 + "was previously returned by lockCanvas"); 934 } 935 mRenderNode.endRecording(); 936 mCanvas = null; 937 nHwuiDraw(mHwuiRenderer); 938 } 939 updateSurface()940 void updateSurface() { 941 nHwuiSetSurface(mHwuiRenderer, mNativeObject); 942 } 943 destroy()944 void destroy() { 945 if (mHwuiRenderer != 0) { 946 nHwuiDestroy(mHwuiRenderer); 947 mHwuiRenderer = 0; 948 } 949 } 950 isWideColorGamut()951 boolean isWideColorGamut() { 952 return mIsWideColorGamut; 953 } 954 } 955 nHwuiCreate(long rootNode, long surface, boolean isWideColorGamut)956 private static native long nHwuiCreate(long rootNode, long surface, boolean isWideColorGamut); nHwuiSetSurface(long renderer, long surface)957 private static native void nHwuiSetSurface(long renderer, long surface); nHwuiDraw(long renderer)958 private static native void nHwuiDraw(long renderer); nHwuiDestroy(long renderer)959 private static native void nHwuiDestroy(long renderer); 960 } 961