termux-x11/app/src/main/jni/lorie/egl-helper.cpp

182 lines
5.4 KiB
C++

#include <log.h>
#include <lorie-egl-helper.hpp>
#include <GLES2/gl2.h>
static char* eglGetErrorText(int code) {
switch(eglGetError()) {
#define E(code, desc) case code: return (char*) desc; break;
case EGL_SUCCESS: return nullptr; // "No error"
E(EGL_NOT_INITIALIZED, "EGL not initialized or failed to initialize");
E(EGL_BAD_ACCESS, "Resource inaccessible");
E(EGL_BAD_ALLOC, "Cannot allocate resources");
E(EGL_BAD_ATTRIBUTE, "Unrecognized attribute or attribute value");
E(EGL_BAD_CONTEXT, "Invalid EGL context");
E(EGL_BAD_CONFIG, "Invalid EGL frame buffer configuration");
E(EGL_BAD_CURRENT_SURFACE, "Current surface is no longer valid");
E(EGL_BAD_DISPLAY, "Invalid EGL display");
E(EGL_BAD_SURFACE, "Invalid surface");
E(EGL_BAD_MATCH, "Inconsistent arguments");
E(EGL_BAD_PARAMETER, "Invalid argument");
E(EGL_BAD_NATIVE_PIXMAP, "Invalid native pixmap");
E(EGL_BAD_NATIVE_WINDOW, "Invalid native window");
E(EGL_CONTEXT_LOST, "Context lost");
#undef E
default: return (char*) "Unknown error";
}
}
#undef checkEGLError
void checkEGLError(int line) {
char *error = eglGetErrorText(eglGetError());
if (error != nullptr)
LOGE("EGL: %s after %d", error, line);
}
#define checkEGLError() checkEGLError(__LINE__)
bool LorieEGLHelper::init(EGLNativeDisplayType display) {
EGLint majorVersion, minorVersion;
LOGV("Initializing EGL");
dpy = eglGetDisplay(display); checkEGLError();
if (dpy == EGL_NO_DISPLAY) {
LOGE("LorieEGLHelper::init : eglGetDisplay failed: %s", eglGetErrorText(eglGetError()));
return false;
}
if (eglInitialize(dpy, &majorVersion, &minorVersion) != EGL_TRUE) {
LOGE("LorieEGLHelper::init : eglInitialize failed: %s", eglGetErrorText(eglGetError()));
return false;
}
const EGLint configAttribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_NONE
};
EGLint numConfigs;
if (eglChooseConfig(dpy, configAttribs, &cfg, 1, &numConfigs) != EGL_TRUE) {
LOGE("LorieEGLHelper::init : eglChooseConfig failed: %s", eglGetErrorText(eglGetError()));
return false;
}
eglBindAPI(EGL_OPENGL_ES_API);
const EGLint ctxattribs[] = {
EGL_CONTEXT_CLIENT_VERSION,
2, // Request opengl ES2.0
EGL_NONE
};
ctx = eglCreateContext(dpy, cfg, NULL, ctxattribs);
if (ctx == EGL_NO_CONTEXT) {
LOGE("LorieEGLHelper::init : eglCreateContext failed: %s", eglGetErrorText(eglGetError()));
return false;
}
if (eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONFIG_KHR) != EGL_TRUE) {
LOGE("LorieEGLHelper::init : eglMakeCurrent failed: %s", eglGetErrorText(eglGetError()));
return false;
}
return true;
}
bool LorieEGLHelper::setWindow(EGLNativeWindowType window) {
LOGV("Trying to use window %p", window);
if (sfc != EGL_NO_SURFACE) {
if (eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) != EGL_TRUE) {
LOGE("LorieEGLHelper::setWindow : eglMakeCurrent (EGL_NO_SURFACE) failed: %s", eglGetErrorText(eglGetError()));
return false;
}
if (eglDestroySurface(dpy, sfc) != EGL_TRUE) {
LOGE("LorieEGLHelper::setWindow : eglDestoySurface failed: %s", eglGetErrorText(eglGetError()));
return false;
}
};
sfc = EGL_NO_SURFACE;
win = window;
if (win == EGL_NO_WINDOW) {
if (onUninit != nullptr) onUninit();
return true;
}
sfc = eglCreateWindowSurface(dpy, cfg, win, NULL);
if (sfc == EGL_NO_SURFACE) {
LOGE("LorieEGLHelper::setWindow : eglCreateWindowSurface failed: %s", eglGetErrorText(eglGetError()));
if (onUninit != nullptr) onUninit();
return false;
}
if (eglMakeCurrent(dpy, sfc, sfc, ctx) != EGL_TRUE) {
LOGE("LorieEGLHelper::setWindow : eglMakeCurrent failed: %s", eglGetErrorText(eglGetError()));
if (onUninit != nullptr) onUninit();
return false;
}
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
swap();
if (onInit != nullptr)
onInit();
return true;
}
void LorieEGLHelper::swap() {
EGLint b = eglSwapBuffers(dpy, sfc);
if (b != EGL_TRUE) {
EGLint err = eglGetError();
if (err == EGL_BAD_SURFACE) {
LOGE("eglSwapBuffers failed because of invalid surface. Regenerating surface.");
setWindow(win);
} else if (err == EGL_BAD_CONTEXT || err == EGL_CONTEXT_LOST) {
LOGE("eglSwapBuffers failed because of invalid context. Regenerating context.");
const EGLint ctxattribs[] = {
EGL_CONTEXT_CLIENT_VERSION,
2, // Request opengl ES2.0
EGL_NONE
};
ctx = eglCreateContext(dpy, cfg, NULL, ctxattribs);
if (ctx == EGL_NO_CONTEXT) {
LOGE("LorieEGLHelper::init : eglCreateContext failed: %s", eglGetErrorText(eglGetError()));
return;
}
}
}
}
void LorieEGLHelper::uninit() {
if (eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) != EGL_TRUE) {
LOGE("LorieEGLHelper::uninit : eglMakeCurrent failed: %s", eglGetErrorText(eglGetError()));
return;
}
if (eglDestroyContext(dpy, ctx) != EGL_TRUE) {
LOGE("LorieEGLHelper::uninit : eglDestroyContext failed: %s", eglGetErrorText(eglGetError()));
return;
}
ctx = EGL_NO_CONTEXT;
if (eglDestroySurface(dpy, sfc) != EGL_TRUE) {
LOGE("LorieEGLHelper::uninit : eglDestroySurface failed: %s", eglGetErrorText(eglGetError()));
return;
}
sfc = EGL_NO_SURFACE;
if (eglTerminate(dpy) != EGL_TRUE) {
LOGE("LorieEGLHelper::uninit : eglTerminate failed: %s", eglGetErrorText(eglGetError()));
return;
}
dpy = EGL_NO_DISPLAY;
}