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