/* * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * Not a Contribution. * * Copyright 2015 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. */ #include "glengine.h" #include <utils/Log.h> #include "engine.h" void checkGlError(const char *, int); void checkEglError(const char *, int); class EngineContext { public: EGLDisplay eglDisplay; EGLContext eglContext; EGLSurface eglSurface; EngineContext() { eglDisplay = EGL_NO_DISPLAY; eglContext = EGL_NO_CONTEXT; eglSurface = EGL_NO_SURFACE; } }; //----------------------------------------------------------------------------- // Make Current void engine_bind(void* context) //----------------------------------------------------------------------------- { EngineContext* engineContext = (EngineContext*)(context); EGL(eglMakeCurrent(engineContext->eglDisplay, engineContext->eglSurface, engineContext->eglSurface, engineContext->eglContext)); } //----------------------------------------------------------------------------- // store the current context(caller) void* engine_backup() { EngineContext* callerContext = new EngineContext(); // store the previous display/context callerContext->eglDisplay = eglGetCurrentDisplay(); callerContext->eglContext = eglGetCurrentContext(); callerContext->eglSurface = eglGetCurrentSurface(EGL_DRAW); return (void*)callerContext; } //----------------------------------------------------------------------------- // frees the backed up caller context void engine_free_backup(void* context) { EngineContext* callerContext = (EngineContext*)(context); delete callerContext; } //----------------------------------------------------------------------------- // initialize GL // void* engine_initialize(bool isSecure) //----------------------------------------------------------------------------- { EngineContext* engineContext = new EngineContext(); // display engineContext->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); EGL(eglBindAPI(EGL_OPENGL_ES_API)); // initialize EGL(eglInitialize(engineContext->eglDisplay, 0, 0)); // config EGLConfig eglConfig; EGLint eglConfigAttribList[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE}; int numConfig = 0; EGL(eglChooseConfig(engineContext->eglDisplay, eglConfigAttribList, &eglConfig, 1, &numConfig)); // context EGLint eglContextAttribList[] = {EGL_CONTEXT_CLIENT_VERSION, 3, isSecure ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE, isSecure ? EGL_TRUE : EGL_NONE, EGL_NONE}; engineContext->eglContext = eglCreateContext(engineContext->eglDisplay, eglConfig, NULL, eglContextAttribList); // surface EGLint eglSurfaceAttribList[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, isSecure ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE, isSecure ? EGL_TRUE : EGL_NONE, EGL_NONE}; engineContext->eglSurface = eglCreatePbufferSurface(engineContext->eglDisplay, eglConfig, eglSurfaceAttribList); eglMakeCurrent(engineContext->eglDisplay, engineContext->eglSurface, engineContext->eglSurface, engineContext->eglContext); ALOGI("In %s context = %p", __FUNCTION__, (void *)(engineContext->eglContext)); return (void*)(engineContext); } //----------------------------------------------------------------------------- // Shutdown. void engine_shutdown(void* context) //----------------------------------------------------------------------------- { EngineContext* engineContext = (EngineContext*)context; EGL(eglMakeCurrent(engineContext->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); EGL(eglDestroySurface(engineContext->eglDisplay, engineContext->eglSurface)); EGL(eglDestroyContext(engineContext->eglDisplay, engineContext->eglContext)); EGL(eglTerminate(engineContext->eglDisplay)); engineContext->eglDisplay = EGL_NO_DISPLAY; engineContext->eglContext = EGL_NO_CONTEXT; engineContext->eglSurface = EGL_NO_SURFACE; } //----------------------------------------------------------------------------- void engine_deleteInputBuffer(unsigned int id) //----------------------------------------------------------------------------- { if (id != 0) { GL(glDeleteTextures(1, &id)); } } //----------------------------------------------------------------------------- void engine_deleteProgram(unsigned int id) //----------------------------------------------------------------------------- { if (id != 0) { GL(glDeleteProgram(id)); } } //----------------------------------------------------------------------------- void engine_setData2f(int location, float* data) //----------------------------------------------------------------------------- { GL(glUniform2f(location, data[0], data[1])); } //----------------------------------------------------------------------------- unsigned int engine_load3DTexture(void *colorMapData, int sz, int format) //----------------------------------------------------------------------------- { GLuint texture = 0; GL(glGenTextures(1, &texture)); GL(glBindTexture(GL_TEXTURE_3D, texture)); GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)); GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); GL(glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB10_A2, sz, sz, sz, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, colorMapData)); return texture; } //----------------------------------------------------------------------------- unsigned int engine_load1DTexture(void *data, int sz, int format) //----------------------------------------------------------------------------- { GLuint texture = 0; if ((data != 0) && (sz != 0)) { GL(glGenTextures(1, &texture)); GL(glBindTexture(GL_TEXTURE_2D, texture)); GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, sz, 1, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, data)); } return texture; } //----------------------------------------------------------------------------- void dumpShaderLog(int shader) //----------------------------------------------------------------------------- { int success = 0; GLchar infoLog[512]; GL(glGetShaderiv(shader, GL_COMPILE_STATUS, &success)); if (!success) { glGetShaderInfoLog(shader, 512, NULL, infoLog); ALOGI("Shader Failed to compile: %s\n", infoLog); } } //----------------------------------------------------------------------------- GLuint engine_loadProgram(int vertexEntries, const char **vertex, int fragmentEntries, const char **fragment) //----------------------------------------------------------------------------- { GLuint progId = glCreateProgram(); int vertId = glCreateShader(GL_VERTEX_SHADER); int fragId = glCreateShader(GL_FRAGMENT_SHADER); GL(glShaderSource(vertId, vertexEntries, vertex, 0)); GL(glCompileShader(vertId)); dumpShaderLog(vertId); GL(glShaderSource(fragId, fragmentEntries, fragment, 0)); GL(glCompileShader(fragId)); dumpShaderLog(fragId); GL(glAttachShader(progId, vertId)); GL(glAttachShader(progId, fragId)); GL(glLinkProgram(progId)); GL(glDetachShader(progId, vertId)); GL(glDetachShader(progId, fragId)); GL(glDeleteShader(vertId)); GL(glDeleteShader(fragId)); return progId; } //----------------------------------------------------------------------------- void WaitOnNativeFence(int fd) //----------------------------------------------------------------------------- { if (fd != -1) { EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fd, EGL_NONE}; EGLSyncKHR sync = eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); if (sync == EGL_NO_SYNC_KHR) { ALOGE("%s - Failed to Create sync from source fd", __FUNCTION__); } else { // the gpu will wait for this sync - not this cpu thread. EGL(eglWaitSyncKHR(eglGetCurrentDisplay(), sync, 0)); EGL(eglDestroySyncKHR(eglGetCurrentDisplay(), sync)); } } } //----------------------------------------------------------------------------- int CreateNativeFence() //----------------------------------------------------------------------------- { int fd = -1; EGLSyncKHR sync = eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); GL(glFlush()); if (sync == EGL_NO_SYNC_KHR) { ALOGE("%s - Failed to Create Native Fence sync", __FUNCTION__); } else { fd = eglDupNativeFenceFDANDROID(eglGetCurrentDisplay(), sync); if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { ALOGE("%s - Failed to dup sync", __FUNCTION__); } EGL(eglDestroySyncKHR(eglGetCurrentDisplay(), sync)); } return fd; } //----------------------------------------------------------------------------- void engine_setDestination(int id, int x, int y, int w, int h) //----------------------------------------------------------------------------- { GL(glBindFramebuffer(GL_FRAMEBUFFER, id)); GL(glViewport(x, y, w, h)); } //----------------------------------------------------------------------------- void engine_setProgram(int id) //----------------------------------------------------------------------------- { GL(glUseProgram(id)); } //----------------------------------------------------------------------------- void engine_set2DInputBuffer(int binding, unsigned int id) //----------------------------------------------------------------------------- { GL(glActiveTexture(GL_TEXTURE0 + binding)); GL(glBindTexture(GL_TEXTURE_2D, id)); } //----------------------------------------------------------------------------- void engine_set3DInputBuffer(int binding, unsigned int id) //----------------------------------------------------------------------------- { GL(glActiveTexture(GL_TEXTURE0 + binding)); GL(glBindTexture(GL_TEXTURE_3D, id)); } //----------------------------------------------------------------------------- void engine_setExternalInputBuffer(int binding, unsigned int id) //----------------------------------------------------------------------------- { GL(glActiveTexture(GL_TEXTURE0 + binding)); GL(glBindTexture(0x8D65, id)); } //----------------------------------------------------------------------------- int engine_blit(int srcFenceFd) //----------------------------------------------------------------------------- { int fd = -1; WaitOnNativeFence(srcFenceFd); float fullscreen_vertices[]{0.0f, 2.0f, 0.0f, 0.0f, 2.0f, 0.0f}; GL(glEnableVertexAttribArray(0)); GL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, fullscreen_vertices)); GL(glDrawArrays(GL_TRIANGLES, 0, 3)); fd = CreateNativeFence(); GL(glFlush()); return fd; } //----------------------------------------------------------------------------- void checkGlError(const char *file, int line) //----------------------------------------------------------------------------- { for (GLint error = glGetError(); error; error = glGetError()) { char *pError; switch (error) { case GL_NO_ERROR: pError = (char *)"GL_NO_ERROR"; break; case GL_INVALID_ENUM: pError = (char *)"GL_INVALID_ENUM"; break; case GL_INVALID_VALUE: pError = (char *)"GL_INVALID_VALUE"; break; case GL_INVALID_OPERATION: pError = (char *)"GL_INVALID_OPERATION"; break; case GL_OUT_OF_MEMORY: pError = (char *)"GL_OUT_OF_MEMORY"; break; case GL_INVALID_FRAMEBUFFER_OPERATION: pError = (char *)"GL_INVALID_FRAMEBUFFER_OPERATION"; break; default: ALOGE("glError (0x%x) %s:%d\n", error, file, line); return; } ALOGE("glError (%s) %s:%d\n", pError, file, line); return; } return; } //----------------------------------------------------------------------------- void checkEglError(const char *file, int line) //----------------------------------------------------------------------------- { for (int i = 0; i < 5; i++) { const EGLint error = eglGetError(); if (error == EGL_SUCCESS) { break; } char *pError; switch (error) { case EGL_SUCCESS: pError = (char *)"EGL_SUCCESS"; break; case EGL_NOT_INITIALIZED: pError = (char *)"EGL_NOT_INITIALIZED"; break; case EGL_BAD_ACCESS: pError = (char *)"EGL_BAD_ACCESS"; break; case EGL_BAD_ALLOC: pError = (char *)"EGL_BAD_ALLOC"; break; case EGL_BAD_ATTRIBUTE: pError = (char *)"EGL_BAD_ATTRIBUTE"; break; case EGL_BAD_CONTEXT: pError = (char *)"EGL_BAD_CONTEXT"; break; case EGL_BAD_CONFIG: pError = (char *)"EGL_BAD_CONFIG"; break; case EGL_BAD_CURRENT_SURFACE: pError = (char *)"EGL_BAD_CURRENT_SURFACE"; break; case EGL_BAD_DISPLAY: pError = (char *)"EGL_BAD_DISPLAY"; break; case EGL_BAD_SURFACE: pError = (char *)"EGL_BAD_SURFACE"; break; case EGL_BAD_MATCH: pError = (char *)"EGL_BAD_MATCH"; break; case EGL_BAD_PARAMETER: pError = (char *)"EGL_BAD_PARAMETER"; break; case EGL_BAD_NATIVE_PIXMAP: pError = (char *)"EGL_BAD_NATIVE_PIXMAP"; break; case EGL_BAD_NATIVE_WINDOW: pError = (char *)"EGL_BAD_NATIVE_WINDOW"; break; case EGL_CONTEXT_LOST: pError = (char *)"EGL_CONTEXT_LOST"; break; default: ALOGE("eglError (0x%x) %s:%d\n", error, file, line); return; } ALOGE("eglError (%s) %s:%d\n", pError, file, line); return; } return; }