FrontBufferUtils.kt
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.graphics.lowlatency
import android.annotation.SuppressLint
import android.hardware.HardwareBuffer
import android.os.Build
import androidx.annotation.RequiresApi
internal class FrontBufferUtils private constructor() {
companion object {
internal const val TAG = "FrontBufferUtils"
// Leverage the same value as HardwareBuffer.USAGE_COMPOSER_OVERLAY.
// While this constant was introduced in the SDK in the Android T release, it has
// been available within the NDK as part of
// AHardwareBuffer_UsageFlags#AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY for quite some time.
// This flag is required for usage of ASurfaceTransaction#setBuffer
// Use a separate constant with the same value to avoid SDK warnings of accessing the
// newly added constant in the SDK.
// See:
// developer.android.com/ndk/reference/group/a-hardware-buffer#ahardwarebuffer_usageflags
private const val USAGE_COMPOSER_OVERLAY: Long = 2048L
/**
* Flags that are expected to be supported on all [HardwareBuffer] instances
*/
internal const val BaseFlags =
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or
HardwareBuffer.USAGE_GPU_COLOR_OUTPUT or
USAGE_COMPOSER_OVERLAY
internal fun obtainHardwareBufferUsageFlags(): Long =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
UsageFlagsVerificationHelper.obtainUsageFlagsV33()
} else {
BaseFlags
}
}
}
/**
* Helper class to avoid class verification failures
*/
@RequiresApi(Build.VERSION_CODES.Q)
internal class UsageFlagsVerificationHelper private constructor() {
companion object {
/**
* Helper method to determine if a particular HardwareBuffer usage flag is supported.
* Even though the FRONT_BUFFER_USAGE and COMPOSER_OVERLAY flags are introduced in
* Android T, not all devices may support this flag. So we conduct a capability query
* with a sample 1x1 HardwareBuffer with the provided flag to see if it is compatible
*/
// Suppressing WrongConstant warnings as we are leveraging a constant with the same value
// as HardwareBuffer.USAGE_COMPOSER_OVERLAY to avoid SDK checks as the constant has been
// supported in the NDK for several platform releases.
// See:
// developer.android.com/ndk/reference/group/a-hardware-buffer#ahardwarebuffer_usageflags
@SuppressLint("WrongConstant")
@RequiresApi(Build.VERSION_CODES.Q)
@androidx.annotation.DoNotInline
internal fun isSupported(flag: Long): Boolean =
HardwareBuffer.isSupported(
1, // width
1, // height
HardwareBuffer.RGBA_8888, // format
1, // layers
FrontBufferUtils.BaseFlags or flag
)
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@androidx.annotation.DoNotInline
fun obtainUsageFlagsV33(): Long {
// First verify if the front buffer usage flag is supported along with the
// "usage composer overlay" flag that was introduced in API level 33
return if (isSupported(HardwareBuffer.USAGE_FRONT_BUFFER)) {
FrontBufferUtils.BaseFlags or HardwareBuffer.USAGE_FRONT_BUFFER
} else {
FrontBufferUtils.BaseFlags
}
}
}
}