/* * Copyright (C) 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. */ // #define LOG_NDEBUG 0 #define LOG_TAG "EglFramebuffer" #include "EglFramebuffer.h" #include "EGL/eglext.h" #include "EglUtil.h" #include "GLES/gl.h" #include "GLES2/gl2.h" #include "GLES2/gl2ext.h" #include "android/hardware_buffer.h" #include "log/log.h" namespace android { namespace companion { namespace virtualcamera { EglFrameBuffer::EglFrameBuffer(EGLDisplay display, std::shared_ptr hwBuffer) : mHardwareBuffer(hwBuffer), mEglDisplay(display) { if (hwBuffer == nullptr) { ALOGE("Cannot construct EglFramebuffer from null hwBuffer"); return; } AHardwareBuffer_Desc hwBufferDesc; AHardwareBuffer_describe(hwBuffer.get(), &hwBufferDesc); mWidth = hwBufferDesc.width; mHeight = hwBufferDesc.height; EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(hwBuffer.get()); mEglImageKhr = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, 0); if (checkEglError("eglCreateImageKHR")) { return; } // Create texture backed by the hardware buffer. glGenTextures(1, &mTextureId); glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureId); glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)mEglImageKhr); if (checkEglError("configure external texture")) { return; } // Create framebuffer backed by the texture. glGenFramebuffers(1, &mFramebufferId); glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferId); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_EXTERNAL_OES, mTextureId, 0); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { ALOGE("Failed to configure framebuffer for texture"); return; // false; } if (checkEglError("glCheckFramebufferStatus")) { return; // false; } } EglFrameBuffer::~EglFrameBuffer() { if (mFramebufferId != 0) { glDeleteFramebuffers(1, &mFramebufferId); } if (mTextureId != 0) { glDeleteTextures(1, &mTextureId); } if (mEglImageKhr != EGL_NO_IMAGE_KHR) { eglDestroyImageKHR(mEglDisplay, mEglDisplay); } } bool EglFrameBuffer::beforeDraw() { glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferId); if (checkEglError("glBindFramebuffer")) { return false; } glViewport(0, 0, mWidth, mHeight); return true; } bool EglFrameBuffer::afterDraw() { glFinish(); glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); return true; } int EglFrameBuffer::getWidth() const { return mWidth; } int EglFrameBuffer::getHeight() const { return mHeight; } std::shared_ptr EglFrameBuffer::getHardwareBuffer() { return mHardwareBuffer; } } // namespace virtualcamera } // namespace companion } // namespace android