RenderEngine.cpp revision 5cdc8994a0ecd751a6350b16a1bef8b6b0d09b11
1/* 2 * Copyright 2013 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#include <cutils/log.h> 18#include <ui/Rect.h> 19#include <ui/Region.h> 20 21#include "RenderEngine.h" 22#include "GLES10RenderEngine.h" 23#include "GLES11RenderEngine.h" 24#include "GLES20RenderEngine.h" 25#include "GLExtensions.h" 26#include "Mesh.h" 27 28// --------------------------------------------------------------------------- 29namespace android { 30// --------------------------------------------------------------------------- 31 32RenderEngine* RenderEngine::create(EGLDisplay display, EGLConfig config) { 33 // Also create our EGLContext 34 EGLint contextAttributes[] = { 35 EGL_CONTEXT_CLIENT_VERSION, 2, // MUST be first 36#ifdef EGL_IMG_context_priority 37#ifdef HAS_CONTEXT_PRIORITY 38#warning "using EGL_IMG_context_priority" 39 EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, 40#endif 41#endif 42 EGL_NONE, EGL_NONE 43 }; 44 45 EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes); 46 if (ctxt == EGL_NO_CONTEXT) { 47 // maybe ES 2.x is not supported 48 ALOGW("can't create an ES 2.x context, trying 1.x"); 49 ctxt = eglCreateContext(display, config, NULL, contextAttributes + 2); 50 } 51 52 // if can't create a GL context, we can only abort. 53 LOG_ALWAYS_FATAL_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed"); 54 55 56 // now figure out what version of GL did we actually get 57 // NOTE: a dummy surface is not needed if KHR_create_context is supported 58 59 EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE }; 60 EGLSurface dummy = eglCreatePbufferSurface(display, config, attribs); 61 LOG_ALWAYS_FATAL_IF(dummy==EGL_NO_SURFACE, "can't create dummy pbuffer"); 62 EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt); 63 LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current"); 64 65 GLExtensions& extensions(GLExtensions::getInstance()); 66 extensions.initWithGLStrings( 67 glGetString(GL_VENDOR), 68 glGetString(GL_RENDERER), 69 glGetString(GL_VERSION), 70 glGetString(GL_EXTENSIONS)); 71 72 GlesVersion version = parseGlesVersion( extensions.getVersion() ); 73 74 // initialize the renderer while GL is current 75 76 RenderEngine* engine = NULL; 77 switch (version) { 78 case GLES_VERSION_1_0: 79 engine = new GLES10RenderEngine(); 80 break; 81 case GLES_VERSION_1_1: 82 engine = new GLES11RenderEngine(); 83 break; 84 case GLES_VERSION_2_0: 85 case GLES_VERSION_3_0: 86 engine = new GLES20RenderEngine(); 87 break; 88 } 89 engine->setEGLContext(ctxt); 90 91 ALOGI("OpenGL ES informations:"); 92 ALOGI("vendor : %s", extensions.getVendor()); 93 ALOGI("renderer : %s", extensions.getRenderer()); 94 ALOGI("version : %s", extensions.getVersion()); 95 ALOGI("extensions: %s", extensions.getExtension()); 96 ALOGI("GL_MAX_TEXTURE_SIZE = %d", engine->getMaxTextureSize()); 97 ALOGI("GL_MAX_VIEWPORT_DIMS = %d", engine->getMaxViewportDims()); 98 99 eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 100 eglDestroySurface(display, dummy); 101 102 return engine; 103} 104 105RenderEngine::RenderEngine() : mEGLContext(EGL_NO_CONTEXT) { 106} 107 108RenderEngine::~RenderEngine() { 109} 110 111void RenderEngine::setEGLContext(EGLContext ctxt) { 112 mEGLContext = ctxt; 113} 114 115EGLContext RenderEngine::getEGLContext() const { 116 return mEGLContext; 117} 118 119void RenderEngine::checkErrors() const { 120 do { 121 // there could be more than one error flag 122 GLenum error = glGetError(); 123 if (error == GL_NO_ERROR) 124 break; 125 ALOGE("GL error 0x%04x", int(error)); 126 } while (true); 127} 128 129RenderEngine::GlesVersion RenderEngine::parseGlesVersion(const char* str) { 130 int major, minor; 131 if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) { 132 if (sscanf(str, "OpenGL ES %d.%d", &major, &minor) != 2) { 133 ALOGW("Unable to parse GL_VERSION string: \"%s\"", str); 134 return GLES_VERSION_1_0; 135 } 136 } 137 138 if (major == 1 && minor == 0) return GLES_VERSION_1_0; 139 if (major == 1 && minor >= 1) return GLES_VERSION_1_1; 140 if (major == 2 && minor >= 0) return GLES_VERSION_2_0; 141 if (major == 3 && minor >= 0) return GLES_VERSION_3_0; 142 143 ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor); 144 return GLES_VERSION_1_0; 145} 146 147void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, 148 float red, float green, float blue, float alpha) { 149 size_t c; 150 Rect const* r = region.getArray(&c); 151 Mesh mesh(Mesh::TRIANGLES, c*6, 2); 152 Mesh::VertexArray position(mesh.getPositionArray()); 153 for (size_t i=0 ; i<c ; i++, r++) { 154 position[i*6 + 0].x = r->left; 155 position[i*6 + 0].y = height - r->top; 156 position[i*6 + 1].x = r->left; 157 position[i*6 + 1].y = height - r->bottom; 158 position[i*6 + 2].x = r->right; 159 position[i*6 + 2].y = height - r->bottom; 160 position[i*6 + 3].x = r->left; 161 position[i*6 + 3].y = height - r->top; 162 position[i*6 + 4].x = r->right; 163 position[i*6 + 4].y = height - r->bottom; 164 position[i*6 + 5].x = r->right; 165 position[i*6 + 5].y = height - r->top; 166 } 167 fillWithColor(mesh, red, green, blue, alpha); 168} 169 170void RenderEngine::clearWithColor(float red, float green, float blue, float alpha) { 171 glClearColor(red, green, blue, alpha); 172 glClear(GL_COLOR_BUFFER_BIT); 173} 174 175void RenderEngine::setScissor( 176 uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) { 177 glScissor(left, bottom, right, top); 178 glEnable(GL_SCISSOR_TEST); 179} 180 181void RenderEngine::disableScissor() { 182 glDisable(GL_SCISSOR_TEST); 183} 184 185void RenderEngine::genTextures(size_t count, uint32_t* names) { 186 glGenTextures(count, names); 187} 188 189void RenderEngine::deleteTextures(size_t count, uint32_t const* names) { 190 glDeleteTextures(count, names); 191} 192 193// --------------------------------------------------------------------------- 194 195RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer( 196 RenderEngine& engine, EGLImageKHR image) : mEngine(engine) 197{ 198 GLuint tname, name; 199 // turn our EGLImage into a texture 200 glGenTextures(1, &tname); 201 glBindTexture(GL_TEXTURE_2D, tname); 202 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); 203 // create a Framebuffer Object to render into 204 glGenFramebuffersOES(1, &name); 205 glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); 206 glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, 207 GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0); 208 mStatus = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); 209 ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES, 210 "glCheckFramebufferStatusOES error %d", mStatus); 211 mTexName = tname; 212 mFbName = name; 213} 214 215RenderEngine::BindImageAsFramebuffer::~BindImageAsFramebuffer() { 216 // back to main framebuffer 217 glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); 218 glDeleteFramebuffersOES(1, &mFbName); 219 glDeleteTextures(1, &mTexName); 220 221} 222 223status_t RenderEngine::BindImageAsFramebuffer::getStatus() const { 224 return mStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE; 225} 226 227// --------------------------------------------------------------------------- 228}; // namespace android 229// --------------------------------------------------------------------------- 230