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.opengl 18 19 import android.hardware.HardwareBuffer 20 import android.opengl.GLES20 21 import android.os.Build 22 import androidx.annotation.RequiresApi 23 import androidx.graphics.opengl.egl.EGLSpec 24 import androidx.opengl.EGLExt 25 import androidx.opengl.EGLImageKHR 26 27 /** 28 * Object that enables rendering into a [HardwareBuffer] by creating a frame buffer object from it 29 * by leveraging Android specific EGL extensions to create an [EGLImageKHR] object that is loaded as 30 * a texture. 31 * 32 * @param egl [EGLSpec] used to specify EGL version and call various EGL methods 33 * @param hardwareBuffer the [HardwareBuffer] that this class wraps and used to generate a 34 * [EGLImageKHR] object 35 */ 36 @RequiresApi(Build.VERSION_CODES.O) 37 class FrameBuffer( 38 private val egl: EGLSpec, 39 val hardwareBuffer: HardwareBuffer, 40 ) : AutoCloseable { 41 42 private var eglImage: EGLImageKHR? 43 private var texture: Int = -1 44 45 /** Return the corresponding FrameBuffer identifier. */ 46 internal var frameBuffer: Int = -1 47 private set 48 49 /** Boolean that tells if the frame buffer is currently closed */ 50 var isClosed = false 51 private set 52 53 // Int array used for creation of fbos/textures 54 private val tmpBuffer = IntArray(1) 55 56 init { 57 val image: EGLImageKHR = 58 egl.eglCreateImageFromHardwareBuffer(hardwareBuffer) 59 ?: throw IllegalArgumentException("Unable to create EGLImage from HardwareBuffer") 60 eglImage = image 61 62 GLES20.glGenTextures(1, tmpBuffer, 0) 63 texture = tmpBuffer[0] 64 65 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture) 66 EGLExt.glEGLImageTargetTexture2DOES(GLES20.GL_TEXTURE_2D, image) 67 68 GLES20.glGenFramebuffers(1, tmpBuffer, 0) 69 frameBuffer = tmpBuffer[0] 70 } 71 72 /** 73 * Binds this frame buffer to the read and draw framebuffer targets if it's not closed. If the 74 * frame buffer is already closed this method will do nothing. 75 */ makeCurrentnull76 fun makeCurrent() { 77 if (!isClosed) { 78 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer) 79 GLES20.glFramebufferTexture2D( 80 GLES20.GL_FRAMEBUFFER, 81 GLES20.GL_COLOR_ATTACHMENT0, 82 GLES20.GL_TEXTURE_2D, 83 texture, 84 0 85 ) 86 } 87 } 88 89 /** 90 * Closes out the frame buffer, freeing all resources within it. This should be done only when 91 * the frame buffer is no longer needed or being accessed. 92 */ closenull93 override fun close() { 94 if (!isClosed) { 95 tmpBuffer[0] = frameBuffer 96 GLES20.glDeleteFramebuffers(1, tmpBuffer, 0) 97 frameBuffer = -1 98 99 tmpBuffer[0] = texture 100 GLES20.glDeleteTextures(1, tmpBuffer, 0) 101 texture = -1 102 103 eglImage?.let { egl.eglDestroyImageKHR(it) } 104 eglImage = null 105 hardwareBuffer.close() 106 isClosed = true 107 } 108 } 109 } 110