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