1 /* 2 * 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.hardware 18 19 import android.opengl.EGL14 20 import android.opengl.EGL15 21 import android.opengl.GLES20 22 import android.os.Build 23 import androidx.annotation.RequiresApi 24 import androidx.graphics.lowlatency.FrontBufferUtils 25 import androidx.graphics.surface.SurfaceControlCompat 26 import androidx.opengl.EGLExt 27 import androidx.opengl.EGLSyncKHR 28 29 /** 30 * A synchronization primitive which signals when hardware units have completed work on a particular 31 * resource. They initially start in an unsignaled state and make a one-time transaction to either a 32 * signaled or error state. 33 * 34 * [SyncFenceCompat] is a presentation fence used in combination with 35 * [SurfaceControlCompat.Transaction.setBuffer]. Note that depending on API level, this will utilize 36 * either [android.hardware.SyncFence] or a compatibility implementation. 37 */ 38 class SyncFenceCompat : AutoCloseable { 39 internal val mImpl: SyncFenceImpl 40 41 companion object { 42 /** 43 * Creates a native synchronization fence from an EGLSync object. 44 * 45 * @throws IllegalStateException if EGL dependencies cannot be resolved 46 */ 47 @JvmStatic createNativeSyncFencenull48 fun createNativeSyncFence(): SyncFenceCompat { 49 val usePlatformSyncFence = 50 !FrontBufferUtils.UseCompatSurfaceControl && 51 Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU 52 return if (usePlatformSyncFence) { 53 SyncFenceCompatVerificationHelper.createSyncFenceCompatV33() 54 } else { 55 val display = 56 EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY) 57 ?: throw IllegalStateException("No EGL Display available") 58 val eglSync: EGLSyncKHR = 59 EGLExt.eglCreateSyncKHR(display, EGLExt.EGL_SYNC_NATIVE_FENCE_ANDROID, null) 60 ?: throw IllegalStateException("Unable to create sync object") 61 GLES20.glFlush() 62 63 val syncFenceCompat = EGLExt.eglDupNativeFenceFDANDROID(display, eglSync) 64 EGLExt.eglDestroySyncKHR(display, eglSync) 65 66 syncFenceCompat 67 } 68 } 69 70 /** 71 * An invalid signal time. Represents either the signal time for a SyncFence that isn't 72 * valid (that is, [isValid] is `false`), or if an error occurred while attempting to 73 * retrieve the signal time. 74 */ 75 const val SIGNAL_TIME_INVALID: Long = -1L 76 77 /** 78 * A pending signal time. This is equivalent to the max value of a long, representing an 79 * infinitely far point in the future. 80 */ 81 const val SIGNAL_TIME_PENDING: Long = Long.MAX_VALUE 82 } 83 84 internal constructor(syncFence: SyncFenceV19) { 85 mImpl = syncFence 86 } 87 88 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 89 internal constructor(syncFence: android.hardware.SyncFence) { 90 mImpl = SyncFenceV33(syncFence) 91 } 92 93 /** 94 * Waits for a [SyncFenceCompat] to signal for up to the timeout duration 95 * 96 * @param timeoutNanos time in nanoseconds to wait for before timing out. 97 */ awaitnull98 fun await(timeoutNanos: Long): Boolean = mImpl.await(timeoutNanos) 99 100 /** Waits forever for a [SyncFenceImpl] to signal */ 101 fun awaitForever(): Boolean = mImpl.awaitForever() 102 103 /** Close the [SyncFenceImpl] */ 104 override fun close() { 105 mImpl.close() 106 } 107 108 /** 109 * Returns the time that the fence signaled in the [CLOCK_MONOTONIC] time domain. This returns 110 * an instant, [SyncFenceCompat.SIGNAL_TIME_INVALID] if the SyncFence is invalid, and if the 111 * fence hasn't yet signaled, then [SyncFenceCompat.SIGNAL_TIME_PENDING] is returned. 112 */ 113 @RequiresApi(Build.VERSION_CODES.O) getSignalTimeNanosnull114 fun getSignalTimeNanos(): Long { 115 return mImpl.getSignalTimeNanos() 116 } 117 118 /** 119 * Checks if the SyncFence object is valid. 120 * 121 * @return `true` if it is valid, `false` otherwise 122 */ isValidnull123 fun isValid() = mImpl.isValid() 124 } 125 126 /** Helper class to avoid class verification failures */ 127 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 128 internal class SyncFenceCompatVerificationHelper private constructor() { 129 companion object { 130 private val mEmptyAttributes = longArrayOf(EGL14.EGL_NONE.toLong()) 131 132 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 133 fun createSyncFenceCompatV33(): SyncFenceCompat { 134 val display = EGL14.eglGetCurrentDisplay() 135 if (display == EGL15.EGL_NO_DISPLAY) { 136 throw RuntimeException("no EGL display") 137 } 138 val error = EGL14.eglGetError() 139 if (error != EGL14.EGL_SUCCESS) { 140 throw RuntimeException("eglGetPlatformDisplay failed") 141 } 142 143 val eglSync = 144 EGL15.eglCreateSync( 145 display, 146 android.opengl.EGLExt.EGL_SYNC_NATIVE_FENCE_ANDROID, 147 mEmptyAttributes, 148 0 149 ) 150 GLES20.glFlush() 151 val syncFenceCompat = 152 SyncFenceCompat(android.opengl.EGLExt.eglDupNativeFenceFDANDROID(display, eglSync)) 153 EGL15.eglDestroySync(display, eglSync) 154 155 return syncFenceCompat 156 } 157 } 158 } 159