blob: acf01222a39ff035bcca87b03417c4a00c04cd04 [file] [log] [blame]
/*
* 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<AHardwareBuffer> 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;
}
} // namespace virtualcamera
} // namespace companion
} // namespace android