1 /* 2 * Copyright 2021 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 androidx.graphics.surface 18 19 import android.graphics.Rect 20 import android.graphics.Region 21 import android.hardware.HardwareBuffer 22 import android.os.Build 23 import android.view.AttachedSurfaceControl 24 import android.view.Surface 25 import android.view.SurfaceControl 26 import android.view.SurfaceView 27 import android.view.Window 28 import androidx.annotation.FloatRange 29 import androidx.annotation.IntDef 30 import androidx.annotation.RequiresApi 31 import androidx.graphics.lowlatency.FrontBufferUtils 32 import androidx.graphics.utils.JniVisible 33 import androidx.hardware.DataSpace 34 import androidx.hardware.SyncFenceCompat 35 import java.util.concurrent.Executor 36 37 /** 38 * Handle to an on-screen Surface managed by the system compositor. [SurfaceControlCompat] is a 39 * combination of a buffer source, and metadata about how to display the buffers. By constructing a 40 * [Surface] from this [SurfaceControl] you can submit buffers to be composited. Using 41 * [SurfaceControlCompat.Transaction] you can manipulate various properties of how the buffer will 42 * be displayed on-screen. [SurfaceControlCompat]s are arranged into a scene-graph like hierarchy, 43 * and as such any [SurfaceControlCompat] may have a parent. Geometric properties like transform, 44 * crop, and Z-ordering will be inherited from the parent, as if the child were content in the 45 * parents buffer stream. 46 * 47 * This class differs slightly than [SurfaceControl] in that it backports some functionality to 48 * Android R and above by delegating to the related APIs available in the NDK. For newer Android 49 * versions, this leverages the equivalent [SurfaceControl] API available in the SDK 50 */ 51 @RequiresApi(Build.VERSION_CODES.Q) 52 class SurfaceControlCompat internal constructor(internal val scImpl: SurfaceControlImpl) { 53 54 companion object { 55 56 /** 57 * Constants for [Transaction.setBufferTransform]. 58 * 59 * Various transformations that can be applied to a buffer. 60 */ 61 @IntDef( 62 value = 63 [ 64 BUFFER_TRANSFORM_IDENTITY, 65 BUFFER_TRANSFORM_MIRROR_HORIZONTAL, 66 BUFFER_TRANSFORM_MIRROR_VERTICAL, 67 BUFFER_TRANSFORM_ROTATE_180, 68 BUFFER_TRANSFORM_ROTATE_90, 69 BUFFER_TRANSFORM_ROTATE_270 70 ] 71 ) 72 internal annotation class BufferTransform 73 74 /** The identity transformation. Maps a coordinate (x, y) onto itself. */ 75 const val BUFFER_TRANSFORM_IDENTITY = 0 76 77 /** Mirrors the buffer horizontally. Maps a point (x, y) to (-x, y) */ 78 const val BUFFER_TRANSFORM_MIRROR_HORIZONTAL = 1 79 80 /** Mirrors the buffer vertically. Maps a point (x, y) to (x, -y) */ 81 const val BUFFER_TRANSFORM_MIRROR_VERTICAL = 2 82 83 /** Rotates the buffer 180 degrees clockwise. Maps a point (x, y) to (-x, -y) */ 84 const val BUFFER_TRANSFORM_ROTATE_180 = 3 85 86 /** Rotates the buffer 90 degrees clockwise. Maps a point (x, y) to (-y, x) */ 87 const val BUFFER_TRANSFORM_ROTATE_90 = 4 88 89 /** Rotates the buffer 270 degrees clockwise. Maps a point (x, y) to (y, -x) */ 90 const val BUFFER_TRANSFORM_ROTATE_270 = 7 91 92 /** Constants for [Transaction.setFrameRate] */ 93 @IntDef(value = [CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, CHANGE_FRAME_RATE_ALWAYS]) 94 internal annotation class ChangeFrameRateStrategy 95 96 /** Change the frame rate only if the transition is going to be seamless. */ 97 const val CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0 98 99 /** 100 * Change the frame rate even if the transition is going to be non-seamless, i.e. with 101 * visual interruptions for the user. 102 */ 103 const val CHANGE_FRAME_RATE_ALWAYS = 1 104 105 /** Constants for configuring compatibility for [Transaction.setFrameRate] */ 106 @IntDef(value = [FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE]) 107 internal annotation class FrameRateCompatibility 108 109 /** 110 * There are no inherent restrictions on the frame rate. When the system selects a frame 111 * rate other than what the app requested, the app will be able to run at the system frame 112 * rate without requiring pull down (the mechanical process of "pulling", physically moving, 113 * frame content downward to advance it from one frame to the next at a repetitive rate). 114 * This value should be used when displaying game content, UIs, and anything that isn't 115 * video. 116 */ 117 const val FRAME_RATE_COMPATIBILITY_DEFAULT = 0 118 119 /** 120 * This compositing layer is being used to display content with an inherently fixed frame 121 * rate, e.g. a video that has a specific frame rate. When the system selects a frame rate 122 * other than what the app requested, the app will need to do pull down or use some other 123 * technique to adapt to the system's frame rate. Pull down involves the mechanical process 124 * of "pulling", physically moving, frame content downward to advance it from one frame to 125 * the next at a repetitive rate). The user experience is likely to be worse (e.g. more 126 * frame stuttering) than it would be if the system had chosen the app's requested frame 127 * rate. This value should be used for video content. 128 */ 129 const val FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1 130 } 131 132 /** 133 * Check whether this instance points to a valid layer with the system-compositor. For example 134 * this may be false if the layer was released ([release]). 135 */ isValidnull136 fun isValid(): Boolean = scImpl.isValid() 137 138 /** 139 * Release the local reference to the server-side surface. The [Surface] may continue to exist 140 * on-screen as long as its parent continues to exist. To explicitly remove a [Surface] from the 141 * screen use [Transaction.reparent] with a null-parent. After release, [isValid] will return 142 * false and other methods will throw an exception. Always call [release] when you are done with 143 * a [SurfaceControlCompat] instance. 144 */ 145 fun release() { 146 scImpl.release() 147 } 148 149 /** 150 * Builder class for [SurfaceControlCompat] objects. By default the [Surface] will be hidden, 151 * and have "unset" bounds, meaning it can be as large as the bounds of its parent if a buffer 152 * or child so requires. It is necessary to set at least a name via [Builder.setName] 153 */ 154 class Builder { 155 156 private val mBuilderImpl = createImpl() 157 158 /** 159 * Set a parent [Surface] from the provided [SurfaceView] for our new 160 * [SurfaceControlCompat]. Child surfaces are constrained to the onscreen region of their 161 * parent. Furthermore they stack relatively in Z order, and inherit the transformation of 162 * the parent. 163 * 164 * @param surfaceView Target [SurfaceView] used to provide the [Surface] this 165 * [SurfaceControlCompat] is associated with. 166 */ 167 @Suppress("MissingGetterMatchingBuilder") setParentnull168 fun setParent(surfaceView: SurfaceView): Builder { 169 mBuilderImpl.setParent(surfaceView) 170 return this 171 } 172 173 /** 174 * Set a parent [SurfaceControlCompat] for the new [SurfaceControlCompat] instance. 175 * Furthermore they stack relatively in Z order, and inherit the transformation of the 176 * parent. 177 * 178 * @param surfaceControl Target [SurfaceControlCompat] used as the parent for the newly 179 * created [SurfaceControlCompat] instance 180 */ 181 @Suppress("MissingGetterMatchingBuilder") setParentnull182 fun setParent(surfaceControl: SurfaceControlCompat): Builder { 183 mBuilderImpl.setParent(surfaceControl) 184 return this 185 } 186 187 /** 188 * Set a debugging-name for the [SurfaceControlCompat]. 189 * 190 * @param name Debugging name configured on the [SurfaceControlCompat] instance. 191 */ 192 @Suppress("MissingGetterMatchingBuilder") setNamenull193 fun setName(name: String): Builder { 194 mBuilderImpl.setName(name) 195 return this 196 } 197 198 /** 199 * Construct a new [SurfaceControlCompat] with the set parameters. The builder remains valid 200 * after the [SurfaceControlCompat] instance is created. 201 */ buildnull202 fun build(): SurfaceControlCompat = SurfaceControlCompat(mBuilderImpl.build()) 203 204 internal companion object { 205 @RequiresApi(Build.VERSION_CODES.Q) 206 fun createImpl(): SurfaceControlImpl.Builder { 207 val usePlatformTransaction = 208 !FrontBufferUtils.UseCompatSurfaceControl && 209 Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU 210 return if (usePlatformTransaction) { 211 SurfaceControlVerificationHelper.createBuilderV33() 212 } else { 213 SurfaceControlVerificationHelper.createBuilderV29() 214 } 215 } 216 } 217 } 218 219 /** 220 * Interface to handle request to 221 * [SurfaceControlV29.Transaction.addTransactionCompletedListener] 222 */ 223 @JniVisible 224 internal interface TransactionCompletedListener { 225 /** 226 * Invoked when a frame including the updates in a transaction was presented. 227 * 228 * Buffers which are replaced or removed from the scene in the transaction invoking this 229 * callback may be reused after this point. 230 */ onTransactionCompletednull231 @JniVisible fun onTransactionCompleted(transactionStats: Long) 232 } 233 234 /** 235 * Interface to handle request to 236 * [SurfaceControlCompat.Transaction.addTransactionCommittedListener] 237 */ 238 @JniVisible 239 interface TransactionCommittedListener { 240 /** Invoked when the transaction has been committed in SurfaceFlinger */ 241 @JniVisible fun onTransactionCommitted() 242 } 243 244 /** An atomic set of changes to a set of [SurfaceControlCompat]. */ 245 @RequiresApi(Build.VERSION_CODES.Q) 246 class Transaction : AutoCloseable { 247 /** internal mapping of buffer transforms used for testing purposes */ 248 internal val mBufferTransforms = HashMap<SurfaceControlCompat, Int>() 249 250 private val mImpl = createImpl() 251 252 /** 253 * Indicates whether the surface must be considered opaque, even if its pixel format is set 254 * to translucent. This can be useful if an application needs full RGBA 8888 support for 255 * instance but will still draw every pixel opaque. This flag only determines whether 256 * opacity will be sampled from the alpha channel. Plane-alpha from calls to setAlpha() can 257 * still result in blended composition regardless of the opaque setting. Combined effects 258 * are (assuming a buffer format with an alpha channel): 259 * 260 * OPAQUE + alpha(1.0) == opaque composition OPAQUE + alpha(0.x) == blended composition 261 * OPAQUE + alpha(0.0) == no composition !OPAQUE + alpha(1.0) == blended composition 262 * !OPAQUE + alpha(0.x) == blended composition !OPAQUE + alpha(0.0) == no composition If the 263 * underlying buffer lacks an alpha channel, it is as if setOpaque(true) were set 264 * automatically. 265 * 266 * @param surfaceControl Target [SurfaceControlCompat] to change the opaque flag for 267 * @param isOpaque Flag indicating if the [SurfaceControlCompat] should be fully opaque or 268 * transparent 269 */ setOpaquenull270 fun setOpaque(surfaceControl: SurfaceControlCompat, isOpaque: Boolean): Transaction { 271 mImpl.setOpaque(surfaceControl.scImpl, isOpaque) 272 return this 273 } 274 275 /** 276 * Sets the visibility of a given Layer and it's sub-tree. 277 * 278 * @param surfaceControl Target [SurfaceControlCompat] to change the visibility 279 * @param visible `true` to indicate the [SurfaceControlCompat] should be visible, `false` 280 * otherwise 281 */ setVisibilitynull282 fun setVisibility(surfaceControl: SurfaceControlCompat, visible: Boolean): Transaction { 283 mImpl.setVisibility(surfaceControl.scImpl, visible) 284 return this 285 } 286 287 /** 288 * Re-parents a given [SurfaceControlCompat] to a new parent. Children inherit transform 289 * (position, scaling) crop, visibility, and Z-ordering from their parents, as if the 290 * children were pixels within the parent [Surface]. 291 * 292 * @param surfaceControl Target [SurfaceControlCompat] instance to reparent 293 * @param newParent Parent [SurfaceControlCompat] that the target [SurfaceControlCompat] 294 * instance is added to. This can be null indicating that the target 295 * [SurfaceControlCompat] should be removed from the scene. 296 */ reparentnull297 fun reparent( 298 surfaceControl: SurfaceControlCompat, 299 newParent: SurfaceControlCompat? 300 ): Transaction { 301 mImpl.reparent(surfaceControl.scImpl, newParent?.scImpl) 302 return this 303 } 304 305 /** 306 * Re-parents a given [SurfaceControlCompat] to be a child of the [AttachedSurfaceControl]. 307 * Children inherit transform (position, scaling) crop, visibility, and Z-ordering from 308 * their parents, as if the children were pixels within the parent [Surface]. 309 * 310 * @param surfaceControl Target [SurfaceControlCompat] instance to reparent 311 * @param attachedSurfaceControl [AttachedSurfaceControl] instance that acts as the new 312 * parent of the provided [SurfaceControlCompat] instance. 313 */ 314 @RequiresApi(Build.VERSION_CODES.TIRAMISU) reparentnull315 fun reparent( 316 surfaceControl: SurfaceControlCompat, 317 attachedSurfaceControl: AttachedSurfaceControl 318 ): Transaction { 319 mImpl.reparent(surfaceControl.scImpl, attachedSurfaceControl) 320 return this 321 } 322 323 /** 324 * Updates the [HardwareBuffer] displayed for the [SurfaceControlCompat]. Note that the 325 * buffer must be allocated with [HardwareBuffer.USAGE_COMPOSER_OVERLAY] as well as 326 * [HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE] as the surface control might be composited using 327 * either an overlay or using the GPU. A presentation fence may be passed to improve 328 * performance by allowing the buffer to complete rendering while it is waiting for the 329 * transaction to be applied. For example, if the buffer is being produced by rendering with 330 * OpenGL ES then a fence created with the eglDupNativeFenceFDANDROID EGL extension API can 331 * be used to allow the GPU rendering to be concurrent with the transaction. The compositor 332 * will wait for the fence to be signaled before the buffer is displayed. If multiple 333 * buffers are set as part of the same transaction, the presentation fences of all of them 334 * must signal before any buffer is displayed. That is, the entire transaction is delayed 335 * until all presentation fences have signaled, ensuring the transaction remains consistent. 336 * 337 * @param surfaceControl Target [SurfaceControlCompat] to configure the provided buffer. 338 * @param buffer [HardwareBuffer] instance to be rendered by the [SurfaceControlCompat] 339 * instance. Use null to remove the current buffer that was previously configured on this 340 * [SurfaceControlCompat] instance. 341 * @param fence Optional [SyncFenceCompat] that serves as the presentation fence. If set, 342 * the [SurfaceControlCompat.Transaction] will not apply until the fence signals. 343 * @param releaseCallback Optional callback invoked when the buffer is ready for re-use 344 * after being presented to the display. This also includes a [SyncFenceCompat] instance 345 * that consumers must wait on before consuming the buffer 346 */ 347 @JvmOverloads setBuffernull348 fun setBuffer( 349 surfaceControl: SurfaceControlCompat, 350 buffer: HardwareBuffer?, 351 fence: SyncFenceCompat? = null, 352 releaseCallback: ((SyncFenceCompat) -> Unit)? = null 353 ): Transaction { 354 mImpl.setBuffer(surfaceControl.scImpl, buffer, fence?.mImpl, releaseCallback) 355 return this 356 } 357 358 /** 359 * Set the Z-order for a given [SurfaceControlCompat], relative to its siblings. If two 360 * siblings share the same Z order the ordering is undefined. [Surface]s with a negative Z 361 * will be placed below the parent [Surface]. 362 */ setLayernull363 fun setLayer(surfaceControl: SurfaceControlCompat, z: Int): Transaction { 364 mImpl.setLayer(surfaceControl.scImpl, z) 365 return this 366 } 367 368 /** 369 * Request to add a [SurfaceControlCompat.TransactionCommittedListener]. The callback is 370 * invoked when transaction is applied and the updates are ready to be presented. Once 371 * applied, any callbacks added before the commit will be cleared from the Transaction. This 372 * callback does not mean buffers have been released! It simply means that any new 373 * transactions applied will not overwrite the transaction for which we are receiving a 374 * callback and instead will be included in the next frame. If you are trying to avoid 375 * dropping frames (overwriting transactions), and unable to use timestamps (Which provide a 376 * more efficient solution), then this method provides a method to pace your transaction 377 * application. 378 * 379 * @param executor [Executor] to provide the thread the callback is invoked on. 380 * @param listener [TransactionCommittedListener] instance that is invoked when the 381 * transaction has been committed. 382 */ 383 @Suppress("PairedRegistration") 384 @RequiresApi(Build.VERSION_CODES.S) addTransactionCommittedListenernull385 fun addTransactionCommittedListener( 386 executor: Executor, 387 listener: TransactionCommittedListener 388 ): Transaction { 389 mImpl.addTransactionCommittedListener(executor, listener) 390 return this 391 } 392 393 /** 394 * Updates the region for the content on this surface updated in this transaction. The 395 * damage region is the area of the buffer that has changed since the previously sent 396 * buffer. This can be used to reduce the amount of recomposition that needs to happen when 397 * only a small region of the buffer is being updated, such as for a small blinking cursor 398 * or a loading indicator. 399 * 400 * @param surfaceControl Target [SurfaceControlCompat] to set damage region of. 401 * @param region The region to be set. If null, the entire buffer is assumed dirty. This is 402 * equivalent to not setting a damage region at all. 403 */ setDamageRegionnull404 fun setDamageRegion(surfaceControl: SurfaceControlCompat, region: Region?): Transaction { 405 mImpl.setDamageRegion(surfaceControl.scImpl, region) 406 return this 407 } 408 409 /** 410 * Set the alpha for a given surface. If the alpha is non-zero the SurfaceControl will be 411 * blended with the Surfaces under it according to the specified ratio. 412 * 413 * @param surfaceControl Target [SurfaceControlCompat] to set the alpha of. 414 * @param alpha The alpha to set. Value is between 0.0 and 1.0 inclusive. 415 */ setAlphanull416 fun setAlpha(surfaceControl: SurfaceControlCompat, alpha: Float): Transaction { 417 mImpl.setAlpha(surfaceControl.scImpl, alpha) 418 return this 419 } 420 421 /** 422 * Bounds the surface and its children to the bounds specified. Size of the surface will be 423 * ignored and only the crop and buffer size will be used to determine the bounds of the 424 * surface. If no crop is specified and the surface has no buffer, the surface bounds is 425 * only constrained by the size of its parent bounds. 426 * 427 * @param surfaceControl The [SurfaceControlCompat] to apply the crop to. This value cannot 428 * be null. 429 * @param crop Bounds of the crop to apply. This value can be null. 430 * @throws IllegalArgumentException if crop is not a valid rectangle. 431 */ setCropnull432 fun setCrop(surfaceControl: SurfaceControlCompat, crop: Rect?): Transaction { 433 mImpl.setCrop(surfaceControl.scImpl, crop) 434 return this 435 } 436 437 /** 438 * Sets the SurfaceControl to the specified position relative to the parent SurfaceControl 439 * 440 * @param surfaceControl The [SurfaceControlCompat] to change position. This value cannot be 441 * null 442 * @param x the X position 443 * @param y the Y position 444 */ setPositionnull445 fun setPosition(surfaceControl: SurfaceControlCompat, x: Float, y: Float): Transaction { 446 mImpl.setPosition(surfaceControl.scImpl, x, y) 447 return this 448 } 449 450 /** 451 * Sets the SurfaceControl to the specified scale with (0, 0) as the center point of the 452 * scale. 453 * 454 * @param surfaceControl The [SurfaceControlCompat] to change scale. This value cannot be 455 * null. 456 * @param scaleX the X scale 457 * @param scaleY the Y scale 458 */ setScalenull459 fun setScale( 460 surfaceControl: SurfaceControlCompat, 461 scaleX: Float, 462 scaleY: Float 463 ): Transaction { 464 mImpl.setScale(surfaceControl.scImpl, scaleX, scaleY) 465 return this 466 } 467 468 /** 469 * Sets the buffer transform that should be applied to the current buffer 470 * 471 * @param surfaceControl the [SurfaceControlCompat] to update. This value cannot be null. 472 * @param transformation The transform to apply to the buffer. Value is 473 * [SurfaceControlCompat.BUFFER_TRANSFORM_IDENTITY], 474 * [SurfaceControlCompat.BUFFER_TRANSFORM_MIRROR_HORIZONTAL], 475 * [SurfaceControlCompat.BUFFER_TRANSFORM_MIRROR_VERTICAL], 476 * [SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_90], 477 * [SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_180], 478 * [SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_270], 479 * [SurfaceControlCompat.BUFFER_TRANSFORM_MIRROR_HORIZONTAL] | 480 * [SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_90], or 481 * [SurfaceControlCompat.BUFFER_TRANSFORM_MIRROR_VERTICAL] | 482 * [SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_90] 483 */ setBufferTransformnull484 fun setBufferTransform( 485 surfaceControl: SurfaceControlCompat, 486 @BufferTransform transformation: Int 487 ): Transaction { 488 mBufferTransforms[surfaceControl] = transformation 489 mImpl.setBufferTransform(surfaceControl.scImpl, transformation) 490 return this 491 } 492 493 /** 494 * Sets the intended frame rate for [SurfaceControlCompat]. 495 * 496 * On devices that are capable of running the display at different refresh rates, the system 497 * may choose a display refresh rate to better match this surface's frame rate. Usage of 498 * this API won't directly affect the application's frame production pipeline. However, 499 * because the system may change the display refresh rate, calls to this function may result 500 * in changes to Choreographer callback timings, and changes to the time interval at which 501 * the system releases buffers back to the application. 502 * 503 * This method is only supported on Android R+ and is ignored on older platform versions. 504 * 505 * @param surfaceControl The target [SurfaceControlCompat] that will have it's frame rate 506 * changed 507 * @param frameRate The intended frame rate of this surface, in frames per second. 0 is a 508 * special value that indicates the app will accept the system's choice for the display 509 * frame rate, which is the default behavior if this function isn't called. Must be 510 * greater than or equal to 0. The frameRate param does not need to be a valid refresh 511 * rate for this device's display 512 * - e.g., it's fine to pass 30fps to a device that can only run the display at 60fps. 513 * 514 * @param compatibility The frame rate compatibility of this surface. The compatibility 515 * value may influence the system's choice of display frame rate. This must be either 516 * [FRAME_RATE_COMPATIBILITY_DEFAULT] or [FRAME_RATE_COMPATIBILITY_FIXED_SOURCE] This 517 * parameter is ignored when frameRate is 0. 518 * @param changeFrameRateStrategy Whether display refresh rate transitions should be 519 * seamless. A seamless transition does not have any visual interruptions, such as a black 520 * screen for a second or two. Must be either [CHANGE_FRAME_RATE_ALWAYS] or 521 * [CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS]. This parameter is only supported on Android S and 522 * when [frameRate] is not 0. This is ignored on older Android versions and when 523 * [frameRate] is 0. 524 */ setFrameRatenull525 fun setFrameRate( 526 surfaceControl: SurfaceControlCompat, 527 frameRate: Float, 528 @FrameRateCompatibility compatibility: Int, 529 @ChangeFrameRateStrategy changeFrameRateStrategy: Int 530 ): Transaction { 531 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 532 val strategy = 533 when (changeFrameRateStrategy) { 534 CHANGE_FRAME_RATE_ALWAYS -> changeFrameRateStrategy 535 CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS -> changeFrameRateStrategy 536 else -> CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS 537 } 538 mImpl.setFrameRate(surfaceControl.scImpl, frameRate, compatibility, strategy) 539 } 540 return this 541 } 542 543 /** 544 * Clears the frame rate which was set for the surface SurfaceControl. 545 * 546 * This is equivalent to calling [setFrameRate] with 0 for the framerate and 547 * [FRAME_RATE_COMPATIBILITY_DEFAULT] 548 * 549 * Note that this only has an effect for surfaces presented on the display. If this surface 550 * is consumed by something other than the system compositor, e.g. a media codec, this call 551 * has no effect. 552 * 553 * This is only supported on Android R and above. This is ignored on older Android versions. 554 * 555 * @param surfaceControl [SurfaceControlCompat] to clear the frame rate 556 */ clearFrameRatenull557 fun clearFrameRate(surfaceControl: SurfaceControlCompat): Transaction { 558 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 559 mImpl.clearFrameRate(surfaceControl.scImpl) 560 } 561 return this 562 } 563 564 /** 565 * Sets the desired extended range brightness for the layer. This only applies for layers 566 * that are displaying [HardwareBuffer] instances with a DataSpace of 567 * [DataSpace.RANGE_EXTENDED]. 568 * 569 * @param surfaceControl The layer whose extended range brightness is being specified 570 * @param currentBufferRatio The current hdr/sdr ratio of the current buffer. For example if 571 * the buffer was rendered with a target SDR whitepoint of 100 nits and a max display 572 * brightness of 200 nits, this should be set to 2.0f. 573 * 574 * Default value is 1.0f. 575 * 576 * Transfer functions that encode their own brightness ranges, such as HLG or PQ, should 577 * also set this to 1.0f and instead communicate extended content brightness information via 578 * metadata such as CTA861_3 or SMPTE2086. 579 * 580 * Must be finite && >= 1.0f 581 * 582 * @param desiredRatio The desired hdr/sdr ratio. This can be used to communicate the max 583 * desired brightness range. This is similar to the "max luminance" value in other HDR 584 * metadata formats, but represented as a ratio of the target SDR whitepoint to the max 585 * display brightness. The system may not be able to, or may choose not to, deliver the 586 * requested range. 587 * 588 * While requesting a large desired ratio will result in the most dynamic range, voluntarily 589 * reducing the requested range can help improve battery life as well as can improve quality 590 * by ensuring greater bit depth is allocated to the luminance range in use. 591 * 592 * Default value is 1.0f and indicates that extended range brightness is not being used, so 593 * the resulting SDR or HDR behavior will be determined entirely by the dataspace being used 594 * (ie, typically SDR however PQ or HLG transfer functions will still result in HDR) 595 * 596 * Must be finite && >= 1.0f 597 * 598 * @return this 599 */ 600 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) setExtendedRangeBrightnessnull601 fun setExtendedRangeBrightness( 602 surfaceControl: SurfaceControlCompat, 603 @FloatRange(from = 1.0, fromInclusive = true) currentBufferRatio: Float, 604 @FloatRange(from = 1.0, fromInclusive = true) desiredRatio: Float 605 ): Transaction { 606 mImpl.setExtendedRangeBrightness( 607 surfaceControl.scImpl, 608 currentBufferRatio, 609 desiredRatio 610 ) 611 return this 612 } 613 614 /** 615 * Set the [DataSpace] for the SurfaceControl. This will control how the buffer set with 616 * [setBuffer] is displayed. 617 * 618 * **NOTE** it is strongly recommended to verify that the display supports the corresponding 619 * [DataSpace] in advance before configuring the data space. For example, if 620 * [DataSpace.DATASPACE_DISPLAY_P3] is desired, consumers should verify that 621 * [Window.isWideGamut] returns true before proceeding. 622 * 623 * @param surfaceControl The SurfaceControl to update 624 * @param dataSpace The [DataSpace] to set it to. Must be one of named 625 * [android.hardware.DataSpace] types. 626 * @return this 627 * @see [android.view.SurfaceControl.Transaction.setDataSpace] 628 */ setDataSpacenull629 fun setDataSpace( 630 surfaceControl: SurfaceControlCompat, 631 @DataSpace.NamedDataSpace dataSpace: Int 632 ): Transaction { 633 mImpl.setDataSpace(surfaceControl.scImpl, dataSpace) 634 return this 635 } 636 637 /** 638 * Commit the transaction, clearing it's state, and making it usable as a new transaction. 639 * This will not release any resources and [SurfaceControlCompat.Transaction.close] must be 640 * called to release the transaction. 641 */ commitnull642 fun commit() { 643 mBufferTransforms.clear() 644 mImpl.commit() 645 } 646 647 /** Release the native transaction object, without committing it. */ closenull648 override fun close() { 649 mImpl.close() 650 } 651 652 /** 653 * Consume the passed in transaction, and request the View hierarchy to apply it atomically 654 * with the next draw. This transaction will be merged with the buffer transaction from the 655 * ViewRoot and they will show up on-screen atomically synced. This will not cause a draw to 656 * be scheduled, and if there are no other changes to the View hierarchy you may need to 657 * call View.invalidate() 658 * 659 * @param attachedSurfaceControl [AttachedSurfaceControl] associated with the ViewRoot that 660 * will apply the provided transaction on the next draw pass 661 */ 662 @RequiresApi(Build.VERSION_CODES.TIRAMISU) commitTransactionOnDrawnull663 fun commitTransactionOnDraw(attachedSurfaceControl: AttachedSurfaceControl) { 664 mImpl.commitTransactionOnDraw(attachedSurfaceControl) 665 } 666 667 internal companion object { 668 @RequiresApi(Build.VERSION_CODES.Q) createImplnull669 fun createImpl(): SurfaceControlImpl.Transaction { 670 val usePlatformSurfaceControl = 671 !FrontBufferUtils.UseCompatSurfaceControl && 672 Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU 673 return if (usePlatformSurfaceControl) { 674 SurfaceControlVerificationHelper.createTransactionV33() 675 } else { 676 SurfaceControlVerificationHelper.createTransactionV29() 677 } 678 } 679 } 680 } 681 } 682 683 /** Helper class to avoid class verification failures */ 684 internal class SurfaceControlVerificationHelper private constructor() { 685 686 companion object { 687 @RequiresApi(Build.VERSION_CODES.TIRAMISU) createBuilderV33null688 fun createBuilderV33(): SurfaceControlImpl.Builder = SurfaceControlV33.Builder() 689 690 @RequiresApi(Build.VERSION_CODES.Q) 691 fun createBuilderV29(): SurfaceControlImpl.Builder = SurfaceControlV29.Builder() 692 693 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 694 fun createTransactionV33(): SurfaceControlImpl.Transaction = SurfaceControlV33.Transaction() 695 696 @RequiresApi(Build.VERSION_CODES.Q) 697 fun createTransactionV29(): SurfaceControlImpl.Transaction = SurfaceControlV29.Transaction() 698 } 699 } 700