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