1 /*
2  * Copyright 2023 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.lowlatency
18 
19 import android.annotation.SuppressLint
20 import android.hardware.HardwareBuffer
21 import android.os.Build
22 import androidx.annotation.RequiresApi
23 import androidx.graphics.surface.SurfaceControlCompat
24 import androidx.hardware.USAGE_COMPOSER_OVERLAY
25 
26 internal class FrontBufferUtils private constructor() {
27 
28     companion object {
29 
30         internal const val TAG = "FrontBufferUtils"
31 
32         /** Flags that are expected to be supported on all [HardwareBuffer] instances */
33         @SuppressLint("WrongConstant")
34         internal const val BaseFlags =
35             HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or
36                 HardwareBuffer.USAGE_GPU_COLOR_OUTPUT or
37                 USAGE_COMPOSER_OVERLAY
38 
obtainHardwareBufferUsageFlagsnull39         internal fun obtainHardwareBufferUsageFlags(): Long =
40             if (!UseCompatSurfaceControl && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
41                 UsageFlagsVerificationHelper.obtainUsageFlagsV33()
42             } else {
43                 BaseFlags
44             }
45 
46         internal const val UseCompatSurfaceControl = false
47 
configureFrontBufferLayerFrameRatenull48         fun configureFrontBufferLayerFrameRate(
49             frontBufferSurfaceControl: SurfaceControlCompat,
50             frameRate: Float = 1000f,
51             transaction: SurfaceControlCompat.Transaction? = null
52         ): SurfaceControlCompat.Transaction? {
53             var targetTransaction: SurfaceControlCompat.Transaction? = transaction
54             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
55                 if (targetTransaction == null) {
56                     targetTransaction = SurfaceControlCompat.Transaction()
57                 }
58                 targetTransaction.setFrameRate(
59                     frontBufferSurfaceControl,
60                     frameRate,
61                     SurfaceControlCompat.FRAME_RATE_COMPATIBILITY_DEFAULT,
62                     SurfaceControlCompat.CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
63                 )
64             }
65             return targetTransaction
66         }
67     }
68 }
69 
70 /** Helper class to avoid class verification failures */
71 @RequiresApi(Build.VERSION_CODES.Q)
72 internal class UsageFlagsVerificationHelper private constructor() {
73     companion object {
74 
75         /**
76          * Helper method to determine if a particular HardwareBuffer usage flag is supported. Even
77          * though the FRONT_BUFFER_USAGE and COMPOSER_OVERLAY flags are introduced in Android T, not
78          * all devices may support this flag. So we conduct a capability query with a sample 1x1
79          * HardwareBuffer with the provided flag to see if it is compatible
80          */
81         // Suppressing WrongConstant warnings as we are leveraging a constant with the same value
82         // as HardwareBuffer.USAGE_COMPOSER_OVERLAY to avoid SDK checks as the constant has been
83         // supported in the NDK for several platform releases.
84         // See:
85         // developer.android.com/ndk/reference/group/a-hardware-buffer#ahardwarebuffer_usageflags
86         @SuppressLint("WrongConstant")
87         @RequiresApi(Build.VERSION_CODES.Q)
isSupportednull88         internal fun isSupported(flag: Long): Boolean =
89             HardwareBuffer.isSupported(
90                 1, // width
91                 1, // height
92                 HardwareBuffer.RGBA_8888, // format
93                 1, // layers
94                 FrontBufferUtils.BaseFlags or flag
95             )
96 
97         @RequiresApi(Build.VERSION_CODES.TIRAMISU)
98         fun obtainUsageFlagsV33(): Long {
99             // First verify if the front buffer usage flag is supported along with the
100             // "usage composer overlay" flag that was introduced in API level 33
101             return if (isSupported(HardwareBuffer.USAGE_FRONT_BUFFER)) {
102                 FrontBufferUtils.BaseFlags or HardwareBuffer.USAGE_FRONT_BUFFER
103             } else {
104                 // If the front buffer usage flag is not supported, configure the CPU write flag
105                 // in order to prevent arm frame buffer compression from causing visual artifacts
106                 // on certain devices like the Samsung Galaxy Tab S6 lite. See b/365131024
107                 FrontBufferUtils.BaseFlags or HardwareBuffer.USAGE_CPU_WRITE_OFTEN
108             }
109         }
110     }
111 }
112