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.graphics.lowlatency
18 
19 import android.hardware.HardwareBuffer
20 import android.opengl.GLES20
21 import androidx.graphics.opengl.FrameBufferRenderer
22 import androidx.graphics.opengl.SyncStrategy
23 import androidx.graphics.opengl.egl.EGLSpec
24 import androidx.hardware.SyncFenceCompat
25 
26 /**
27  * [SyncStrategy] implementation that optimizes for front buffered rendering use cases. More
28  * specifically this attempts to avoid unnecessary synchronization overhead wherever possible.
29  *
30  * This will always provide a fence if the corresponding layer transitions from an invisible to a
31  * visible state. If the layer is already visible and front buffer usage flags are support on the
32  * device, then no fence is provided. If this flag is not supported, then a fence is created to
33  * ensure contents are flushed to the single buffer.
34  *
35  * @param usageFlags usage flags that describe the [HardwareBuffer] that is used as the destination
36  *   for rendering content within [FrameBufferRenderer]. The usage flags can be obtained via
37  *   [HardwareBuffer.getUsage] or by passing in the same flags from [HardwareBuffer.create]
38  */
39 class FrontBufferSyncStrategy(usageFlags: Long) : SyncStrategy {
40     private val supportsFrontBufferUsage = (usageFlags and HardwareBuffer.USAGE_FRONT_BUFFER) != 0L
41     private var mFrontBufferVisible: Boolean = false
42 
43     /**
44      * Tells whether the corresponding front buffer layer is visible in its current state or not.
45      * Utilize this to dictate when a [SyncFenceCompat] will be created when using
46      * [createSyncFence].
47      */
48     var isVisible
49         get() = mFrontBufferVisible
50         set(visibility) {
51             mFrontBufferVisible = visibility
52         }
53 
54     /**
55      * Creates a [SyncFenceCompat] based on various conditions. If the layer is changing from
56      * invisible to visible, a fence is provided. If the layer is already visible and front buffer
57      * usage flag is supported on the device, then no fence is provided. If front buffer usage is
58      * not supported, then a fence is created and destroyed to flush contents to screen.
59      */
createSyncFencenull60     override fun createSyncFence(eglSpec: EGLSpec): SyncFenceCompat? {
61         return if (!isVisible) {
62             SyncFenceCompat.createNativeSyncFence()
63         } else if (supportsFrontBufferUsage) {
64             GLES20.glFlush()
65             return null
66         } else {
67             val fence = SyncFenceCompat.createNativeSyncFence()
68             fence.close()
69             return null
70         }
71     }
72 }
73