1 /* <lambda>null2 * Copyright 2022 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.annotation.SuppressLint 20 import android.graphics.Rect 21 import android.graphics.Region 22 import android.hardware.HardwareBuffer 23 import android.os.Build 24 import android.view.AttachedSurfaceControl 25 import android.view.SurfaceView 26 import androidx.annotation.RequiresApi 27 import androidx.graphics.lowlatency.BufferTransformHintResolver.Companion.UNKNOWN_TRANSFORM 28 import androidx.graphics.lowlatency.FrontBufferUtils 29 import androidx.graphics.surface.SurfaceControlCompat.Companion.BUFFER_TRANSFORM_ROTATE_270 30 import androidx.graphics.surface.SurfaceControlCompat.Companion.BUFFER_TRANSFORM_ROTATE_90 31 import androidx.graphics.surface.SurfaceControlCompat.Companion.CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS 32 import androidx.graphics.surface.SurfaceControlCompat.Companion.FRAME_RATE_COMPATIBILITY_DEFAULT 33 import androidx.hardware.SyncFenceCompat 34 import androidx.hardware.SyncFenceImpl 35 import androidx.hardware.SyncFenceV19 36 import java.util.concurrent.Executor 37 38 private typealias ReleaseCallback = (SyncFenceCompat) -> Unit 39 40 /** Implementation of [SurfaceControlImpl] that wraps the [SurfaceControlWrapper] API. */ 41 @RequiresApi(Build.VERSION_CODES.Q) 42 internal class SurfaceControlV29 43 internal constructor(internal val surfaceControl: SurfaceControlWrapper) : SurfaceControlImpl { 44 45 /** 46 * Helper method to synchronously update the release callback for the buffer specified on this 47 * SurfaceControl and return the previous callback 48 */ 49 fun updateReleaseCallback(callback: ReleaseCallback?): ReleaseCallback? { 50 synchronized(this) { 51 val previous = releaseCallback 52 releaseCallback = callback 53 return previous 54 } 55 } 56 57 private var releaseCallback: ReleaseCallback? = null 58 59 fun getPreviousReleaseFd(transactionStats: Long) = 60 JniBindings.nGetPreviousReleaseFenceFd( 61 surfaceControl.mNativeSurfaceControl, 62 transactionStats 63 ) 64 65 /** See [SurfaceControlWrapper.isValid] */ 66 override fun isValid(): Boolean = surfaceControl.isValid() 67 68 /** See [SurfaceControlWrapper.release] */ 69 override fun release() { 70 surfaceControl.release() 71 } 72 73 /** See [SurfaceControlWrapper.Builder] */ 74 class Builder : SurfaceControlImpl.Builder { 75 private var builder = SurfaceControlWrapper.Builder() 76 77 /** See [SurfaceControlWrapper.Builder.setParent] */ 78 override fun setParent(surfaceView: SurfaceView): SurfaceControlImpl.Builder { 79 builder.setParent(surfaceView.holder.surface) 80 return this 81 } 82 83 /** See [SurfaceControlWrapper.Builder.setParent] */ 84 override fun setParent(surfaceControl: SurfaceControlCompat): SurfaceControlImpl.Builder { 85 builder.setParent(surfaceControl.scImpl.asWrapperSurfaceControl()) 86 return this 87 } 88 89 /** See [SurfaceControlWrapper.Builder.setDebugName] */ 90 override fun setName(name: String): SurfaceControlImpl.Builder { 91 builder.setDebugName(name) 92 return this 93 } 94 95 /** See [SurfaceControlWrapper.Builder.build] */ 96 override fun build(): SurfaceControlImpl = SurfaceControlV29(builder.build()) 97 } 98 99 /** See [SurfaceControlWrapper.Transaction] */ 100 class Transaction : SurfaceControlImpl.Transaction { 101 private val transaction = SurfaceControlWrapper.Transaction() 102 private val uncommittedBufferCallbackMap = HashMap<SurfaceControlImpl, BufferData?>() 103 private val pendingSetTransformCalls = HashMap<SurfaceControlImpl, Int>() 104 105 /** 106 * Class to wrap metadata around setBuffer calls. This is used to appropriately call the 107 * release callbacks as well as configure the buffer transform for older API levels 108 */ 109 private class BufferData( 110 val width: Int, 111 val height: Int, 112 val releaseCallback: ReleaseCallback? 113 ) 114 115 /** See [SurfaceControlWrapper.Transaction.commit] */ 116 override fun commit() { 117 setPendingBufferTransform() 118 updateReleaseCallbacks() 119 uncommittedBufferCallbackMap.clear() 120 pendingSetTransformCalls.clear() 121 transaction.commit() 122 } 123 124 private fun updateReleaseCallbacks() { 125 // store prev committed callbacks so we only need 1 onComplete callback 126 data class CallbackEntry( 127 val surfaceControl: SurfaceControlV29, 128 val callback: ReleaseCallback? 129 ) 130 val callbackInvokeList = mutableListOf<CallbackEntry>() 131 132 for (surfaceControl in uncommittedBufferCallbackMap.keys) { 133 (surfaceControl as? SurfaceControlV29)?.apply { 134 // add active buffers callback to list if we have a new buffer about to 135 // overwrite 136 val entry = uncommittedBufferCallbackMap[surfaceControl] 137 if (entry != null) { 138 callbackInvokeList.add(CallbackEntry(this, entry.releaseCallback)) 139 } 140 } 141 } 142 143 if (callbackInvokeList.size > 0) { 144 val callbackListener = 145 object : SurfaceControlCompat.TransactionCompletedListener { 146 override fun onTransactionCompleted(transactionStats: Long) { 147 callbackInvokeList.forEach { 148 val sc = it.surfaceControl 149 val currentCallback = it.callback 150 sc.updateReleaseCallback(currentCallback)?.let { prevCallback -> 151 val fileDescriptor = sc.getPreviousReleaseFd(transactionStats) 152 prevCallback.invoke( 153 SyncFenceCompat(SyncFenceV19(fileDescriptor)) 154 ) 155 } 156 } 157 callbackInvokeList.clear() 158 } 159 } 160 161 this.addTransactionCompletedListener(callbackListener) 162 } 163 } 164 165 private fun setPendingBufferTransform() { 166 for (surfaceControl in pendingSetTransformCalls.keys) { 167 uncommittedBufferCallbackMap[surfaceControl]?.let { 168 val transformation = 169 pendingSetTransformCalls.getOrDefault(surfaceControl, UNKNOWN_TRANSFORM) 170 if (transformation != UNKNOWN_TRANSFORM) { 171 val dstWidth: Int 172 val dstHeight: Int 173 if ( 174 transformation == BUFFER_TRANSFORM_ROTATE_90 || 175 transformation == BUFFER_TRANSFORM_ROTATE_270 176 ) { 177 dstWidth = it.height 178 dstHeight = it.width 179 } else { 180 dstWidth = it.width 181 dstHeight = it.height 182 } 183 transaction.setGeometry( 184 surfaceControl.asWrapperSurfaceControl(), 185 it.width, 186 it.height, 187 dstWidth, 188 dstHeight, 189 transformation 190 ) 191 } 192 } 193 } 194 } 195 196 /** See [SurfaceControlWrapper.Transaction.setVisibility] */ 197 override fun setVisibility( 198 surfaceControl: SurfaceControlImpl, 199 visible: Boolean 200 ): SurfaceControlImpl.Transaction { 201 transaction.setVisibility(surfaceControl.asWrapperSurfaceControl(), visible) 202 return this 203 } 204 205 /** See [SurfaceControlWrapper.Transaction.reparent] */ 206 override fun reparent( 207 surfaceControl: SurfaceControlImpl, 208 newParent: SurfaceControlImpl? 209 ): SurfaceControlImpl.Transaction { 210 transaction.reparent( 211 surfaceControl.asWrapperSurfaceControl(), 212 newParent?.asWrapperSurfaceControl() 213 ) 214 return this 215 } 216 217 /** See [SurfaceControlWrapper.Transaction.setBuffer] */ 218 override fun setBuffer( 219 surfaceControl: SurfaceControlImpl, 220 buffer: HardwareBuffer?, 221 fence: SyncFenceImpl?, 222 releaseCallback: ReleaseCallback? 223 ): SurfaceControlImpl.Transaction { 224 val previousEntry: BufferData? = 225 if (buffer != null) { 226 uncommittedBufferCallbackMap.put( 227 surfaceControl, 228 BufferData( 229 width = buffer.width, 230 height = buffer.height, 231 releaseCallback = releaseCallback 232 ) 233 ) 234 } else { 235 uncommittedBufferCallbackMap.remove(surfaceControl) 236 } 237 // we have a previous mapping in the same transaction, invoke callback 238 previousEntry?.releaseCallback?.invoke(DefaultSyncFence) 239 240 val targetBuffer = buffer ?: PlaceholderBuffer 241 // Ensure if we have a null value, we default to the default value for SyncFence 242 // argument to prevent null pointer dereference 243 if (fence == null) { 244 transaction.setBuffer(surfaceControl.asWrapperSurfaceControl(), targetBuffer) 245 } else { 246 transaction.setBuffer( 247 surfaceControl.asWrapperSurfaceControl(), 248 targetBuffer, 249 fence.asSyncFenceCompat() 250 ) 251 } 252 253 return this 254 } 255 256 /** See [SurfaceControlWrapper.Transaction.setLayer] */ 257 override fun setLayer( 258 surfaceControl: SurfaceControlImpl, 259 z: Int 260 ): SurfaceControlImpl.Transaction { 261 transaction.setLayer(surfaceControl.asWrapperSurfaceControl(), z) 262 return this 263 } 264 265 /** See [SurfaceControlWrapper.Transaction.addTransactionCommittedListener] */ 266 @RequiresApi(Build.VERSION_CODES.S) 267 override fun addTransactionCommittedListener( 268 executor: Executor, 269 listener: SurfaceControlCompat.TransactionCommittedListener 270 ): SurfaceControlImpl.Transaction { 271 transaction.addTransactionCommittedListener(executor, listener) 272 return this 273 } 274 275 /** See [SurfaceControlWrapper.Transaction.addTransactionCompletedListener] */ 276 fun addTransactionCompletedListener( 277 listener: SurfaceControlCompat.TransactionCompletedListener 278 ): SurfaceControlImpl.Transaction { 279 transaction.addTransactionCompletedListener(listener) 280 return this 281 } 282 283 /** See [SurfaceControlWrapper.Transaction.setDamageRegion] */ 284 override fun setDamageRegion( 285 surfaceControl: SurfaceControlImpl, 286 region: Region? 287 ): SurfaceControlImpl.Transaction { 288 transaction.setDamageRegion(surfaceControl.asWrapperSurfaceControl(), region) 289 return this 290 } 291 292 /** See [SurfaceControlWrapper.Transaction.setOpaque] */ 293 override fun setOpaque( 294 surfaceControl: SurfaceControlImpl, 295 isOpaque: Boolean 296 ): SurfaceControlImpl.Transaction { 297 transaction.setOpaque(surfaceControl.asWrapperSurfaceControl(), isOpaque) 298 return this 299 } 300 301 /** See [SurfaceControlWrapper.Transaction.setAlpha] */ 302 override fun setAlpha( 303 surfaceControl: SurfaceControlImpl, 304 alpha: Float 305 ): SurfaceControlImpl.Transaction { 306 transaction.setAlpha(surfaceControl.asWrapperSurfaceControl(), alpha) 307 return this 308 } 309 310 /** See [SurfaceControlWrapper.Transaction.setCrop] */ 311 @RequiresApi(Build.VERSION_CODES.S) 312 override fun setCrop( 313 surfaceControl: SurfaceControlImpl, 314 crop: Rect? 315 ): SurfaceControlImpl.Transaction { 316 transaction.setCrop(surfaceControl.asWrapperSurfaceControl(), crop) 317 return this 318 } 319 320 /** See [SurfaceControlWrapper.Transaction.setPosition] */ 321 @RequiresApi(Build.VERSION_CODES.S) 322 override fun setPosition( 323 surfaceControl: SurfaceControlImpl, 324 x: Float, 325 y: Float 326 ): SurfaceControlImpl.Transaction { 327 transaction.setPosition(surfaceControl.asWrapperSurfaceControl(), x, y) 328 return this 329 } 330 331 /** See [SurfaceControlWrapper.Transaction.setScale] */ 332 @RequiresApi(Build.VERSION_CODES.S) 333 override fun setScale( 334 surfaceControl: SurfaceControlImpl, 335 scaleX: Float, 336 scaleY: Float 337 ): SurfaceControlImpl.Transaction { 338 transaction.setScale(surfaceControl.asWrapperSurfaceControl(), scaleX, scaleY) 339 return this 340 } 341 342 /** See [SurfaceControlWrapper.Transaction.setBufferTransform] */ 343 override fun setBufferTransform( 344 surfaceControl: SurfaceControlImpl, 345 @SurfaceControlCompat.Companion.BufferTransform transformation: Int 346 ): Transaction { 347 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { 348 transaction.setBufferTransform( 349 surfaceControl.asWrapperSurfaceControl(), 350 transformation 351 ) 352 } else { 353 pendingSetTransformCalls[surfaceControl] = transformation 354 } 355 return this 356 } 357 358 /** See [SurfaceControlCompat.Transaction.setExtendedRangeBrightness] */ 359 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 360 override fun setExtendedRangeBrightness( 361 surfaceControl: SurfaceControlImpl, 362 currentBufferRatio: Float, 363 desiredRatio: Float 364 ): SurfaceControlImpl.Transaction { 365 throw UnsupportedOperationException( 366 "Configuring the extended range brightness is only available on Android U+" 367 ) 368 } 369 370 /** See [SurfaceControlCompat.Transaction.setDataSpace] */ 371 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 372 override fun setDataSpace( 373 surfaceControl: SurfaceControlImpl, 374 dataSpace: Int 375 ): SurfaceControlImpl.Transaction { 376 transaction.setDataSpace(surfaceControl.asWrapperSurfaceControl(), dataSpace) 377 return this 378 } 379 380 /** See [SurfaceControlCompat.Transaction.setFrameRate] */ 381 override fun setFrameRate( 382 scImpl: SurfaceControlImpl, 383 frameRate: Float, 384 compatibility: Int, 385 changeFrameRateStrategy: Int 386 ): Transaction { 387 transaction.setFrameRate( 388 scImpl.asWrapperSurfaceControl(), 389 frameRate, 390 compatibility, 391 changeFrameRateStrategy 392 ) 393 return this 394 } 395 396 /** See [SurfaceControlCompat.Transaction.clearFrameRate] */ 397 override fun clearFrameRate(scImpl: SurfaceControlImpl): SurfaceControlImpl.Transaction { 398 setFrameRate( 399 scImpl, 400 0f, 401 FRAME_RATE_COMPATIBILITY_DEFAULT, 402 CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS 403 ) 404 return this 405 } 406 407 /** See [SurfaceControlWrapper.Transaction.close] */ 408 override fun close() { 409 transaction.close() 410 } 411 412 override fun reparent( 413 surfaceControl: SurfaceControlImpl, 414 attachedSurfaceControl: AttachedSurfaceControl 415 ): SurfaceControlImpl.Transaction { 416 throw UnsupportedOperationException( 417 "Reparenting to an AttachedSurfaceControl is only available on Android T+." 418 ) 419 } 420 421 override fun commitTransactionOnDraw(attachedSurfaceControl: AttachedSurfaceControl) { 422 throw UnsupportedOperationException( 423 "Committing transactions synchronously with the draw pass of an " + 424 "AttachedSurfaceControl is only available on Android T+." 425 ) 426 } 427 428 private fun SyncFenceImpl.asSyncFenceCompat(): SyncFenceV19 = 429 if (this is SyncFenceV19) { 430 this 431 } else { 432 throw IllegalArgumentException( 433 "Expected SyncFenceCompat implementation " + "for API level 19" 434 ) 435 } 436 } 437 438 private companion object { 439 440 // Certain Android platform versions have inconsistent behavior when it comes to 441 // configuring a null HardwareBuffer. More specifically Android Q appears to crash 442 // and restart emulator instances. 443 // Additionally the SDK setBuffer API hides the buffer from the display if it is 444 // null but the NDK API does not and persists the buffer contents on screen. 445 // So instead change the buffer to a 1 x 1 placeholder to achieve a similar effect 446 // with more consistent behavior. 447 @SuppressLint("WrongConstant") 448 val PlaceholderBuffer = 449 HardwareBuffer.create(1, 1, HardwareBuffer.RGBA_8888, 1, FrontBufferUtils.BaseFlags) 450 451 val DefaultSyncFence = SyncFenceCompat(SyncFenceV19(-1)) 452 453 fun SurfaceControlImpl.asWrapperSurfaceControl(): SurfaceControlWrapper = 454 if (this is SurfaceControlV29) { 455 surfaceControl 456 } else { 457 throw IllegalArgumentException("Parent implementation is only for Android T+.") 458 } 459 } 460 } 461