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