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