Home | History | Annotate | Download | only in RenderEngine
      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 EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
     29 
     30 // ---------------------------------------------------------------------------
     31 namespace android {
     32 // ---------------------------------------------------------------------------
     33 
     34 static bool findExtension(const char* exts, const char* name) {
     35     if (!exts)
     36         return false;
     37     size_t len = strlen(name);
     38 
     39     const char* pos = exts;
     40     while ((pos = strstr(pos, name)) != NULL) {
     41         if (pos[len] == '\0' || pos[len] == ' ')
     42             return true;
     43         pos += len;
     44     }
     45 
     46     return false;
     47 }
     48 
     49 RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) {
     50     // EGL_ANDROIDX_no_config_context is an experimental extension with no
     51     // written specification. It will be replaced by something more formal.
     52     // SurfaceFlinger is using it to allow a single EGLContext to render to
     53     // both a 16-bit primary display framebuffer and a 32-bit virtual display
     54     // framebuffer.
     55     //
     56     // The code assumes that ES2 or later is available if this extension is
     57     // supported.
     58     EGLConfig config = EGL_NO_CONFIG;
     59     if (!findExtension(
     60             eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
     61             "EGL_ANDROIDX_no_config_context")) {
     62         config = chooseEglConfig(display, hwcFormat);
     63     }
     64 
     65     EGLint renderableType = 0;
     66     if (config == EGL_NO_CONFIG) {
     67         renderableType = EGL_OPENGL_ES2_BIT;
     68     } else if (!eglGetConfigAttrib(display, config,
     69             EGL_RENDERABLE_TYPE, &renderableType)) {
     70         LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
     71     }
     72     EGLint contextClientVersion = 0;
     73     if (renderableType & EGL_OPENGL_ES2_BIT) {
     74         contextClientVersion = 2;
     75     } else if (renderableType & EGL_OPENGL_ES_BIT) {
     76         contextClientVersion = 1;
     77     } else {
     78         LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");
     79     }
     80 
     81     // Also create our EGLContext
     82     EGLint contextAttributes[] = {
     83             EGL_CONTEXT_CLIENT_VERSION, contextClientVersion,      // MUST be first
     84 #ifdef EGL_IMG_context_priority
     85 #ifdef HAS_CONTEXT_PRIORITY
     86 #warning "using EGL_IMG_context_priority"
     87             EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
     88 #endif
     89 #endif
     90             EGL_NONE, EGL_NONE
     91     };
     92     EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes);
     93 
     94     // if can't create a GL context, we can only abort.
     95     LOG_ALWAYS_FATAL_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed");
     96 
     97 
     98     // now figure out what version of GL did we actually get
     99     // NOTE: a dummy surface is not needed if KHR_create_context is supported
    100 
    101     EGLConfig dummyConfig = config;
    102     if (dummyConfig == EGL_NO_CONFIG) {
    103         dummyConfig = chooseEglConfig(display, hwcFormat);
    104     }
    105     EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE };
    106     EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs);
    107     LOG_ALWAYS_FATAL_IF(dummy==EGL_NO_SURFACE, "can't create dummy pbuffer");
    108     EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
    109     LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
    110 
    111     GLExtensions& extensions(GLExtensions::getInstance());
    112     extensions.initWithGLStrings(
    113             glGetString(GL_VENDOR),
    114             glGetString(GL_RENDERER),
    115             glGetString(GL_VERSION),
    116             glGetString(GL_EXTENSIONS));
    117 
    118     GlesVersion version = parseGlesVersion( extensions.getVersion() );
    119 
    120     // initialize the renderer while GL is current
    121 
    122     RenderEngine* engine = NULL;
    123     switch (version) {
    124     case GLES_VERSION_1_0:
    125         engine = new GLES10RenderEngine();
    126         break;
    127     case GLES_VERSION_1_1:
    128         engine = new GLES11RenderEngine();
    129         break;
    130     case GLES_VERSION_2_0:
    131     case GLES_VERSION_3_0:
    132         engine = new GLES20RenderEngine();
    133         break;
    134     }
    135     engine->setEGLHandles(config, ctxt);
    136 
    137     ALOGI("OpenGL ES informations:");
    138     ALOGI("vendor    : %s", extensions.getVendor());
    139     ALOGI("renderer  : %s", extensions.getRenderer());
    140     ALOGI("version   : %s", extensions.getVersion());
    141     ALOGI("extensions: %s", extensions.getExtension());
    142     ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
    143     ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
    144 
    145     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    146     eglDestroySurface(display, dummy);
    147 
    148     return engine;
    149 }
    150 
    151 RenderEngine::RenderEngine() : mEGLContext(EGL_NO_CONTEXT) {
    152 }
    153 
    154 RenderEngine::~RenderEngine() {
    155 }
    156 
    157 void RenderEngine::setEGLHandles(EGLConfig config, EGLContext ctxt) {
    158     mEGLConfig = config;
    159     mEGLContext = ctxt;
    160 }
    161 
    162 EGLContext RenderEngine::getEGLConfig() const {
    163     return mEGLConfig;
    164 }
    165 
    166 EGLContext RenderEngine::getEGLContext() const {
    167     return mEGLContext;
    168 }
    169 
    170 void RenderEngine::checkErrors() const {
    171     do {
    172         // there could be more than one error flag
    173         GLenum error = glGetError();
    174         if (error == GL_NO_ERROR)
    175             break;
    176         ALOGE("GL error 0x%04x", int(error));
    177     } while (true);
    178 }
    179 
    180 RenderEngine::GlesVersion RenderEngine::parseGlesVersion(const char* str) {
    181     int major, minor;
    182     if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) {
    183         if (sscanf(str, "OpenGL ES %d.%d", &major, &minor) != 2) {
    184             ALOGW("Unable to parse GL_VERSION string: \"%s\"", str);
    185             return GLES_VERSION_1_0;
    186         }
    187     }
    188 
    189     if (major == 1 && minor == 0) return GLES_VERSION_1_0;
    190     if (major == 1 && minor >= 1) return GLES_VERSION_1_1;
    191     if (major == 2 && minor >= 0) return GLES_VERSION_2_0;
    192     if (major == 3 && minor >= 0) return GLES_VERSION_3_0;
    193 
    194     ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor);
    195     return GLES_VERSION_1_0;
    196 }
    197 
    198 void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height,
    199         float red, float green, float blue, float alpha) {
    200     size_t c;
    201     Rect const* r = region.getArray(&c);
    202     Mesh mesh(Mesh::TRIANGLES, c*6, 2);
    203     Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
    204     for (size_t i=0 ; i<c ; i++, r++) {
    205         position[i*6 + 0].x = r->left;
    206         position[i*6 + 0].y = height - r->top;
    207         position[i*6 + 1].x = r->left;
    208         position[i*6 + 1].y = height - r->bottom;
    209         position[i*6 + 2].x = r->right;
    210         position[i*6 + 2].y = height - r->bottom;
    211         position[i*6 + 3].x = r->left;
    212         position[i*6 + 3].y = height - r->top;
    213         position[i*6 + 4].x = r->right;
    214         position[i*6 + 4].y = height - r->bottom;
    215         position[i*6 + 5].x = r->right;
    216         position[i*6 + 5].y = height - r->top;
    217     }
    218     setupFillWithColor(red, green, blue, alpha);
    219     drawMesh(mesh);
    220 }
    221 
    222 void RenderEngine::flush() {
    223     glFlush();
    224 }
    225 
    226 void RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
    227     glClearColor(red, green, blue, alpha);
    228     glClear(GL_COLOR_BUFFER_BIT);
    229 }
    230 
    231 void RenderEngine::setScissor(
    232         uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
    233     glScissor(left, bottom, right, top);
    234     glEnable(GL_SCISSOR_TEST);
    235 }
    236 
    237 void RenderEngine::disableScissor() {
    238     glDisable(GL_SCISSOR_TEST);
    239 }
    240 
    241 void RenderEngine::genTextures(size_t count, uint32_t* names) {
    242     glGenTextures(count, names);
    243 }
    244 
    245 void RenderEngine::deleteTextures(size_t count, uint32_t const* names) {
    246     glDeleteTextures(count, names);
    247 }
    248 
    249 void RenderEngine::readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) {
    250     glReadPixels(l, b, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
    251 }
    252 
    253 void RenderEngine::dump(String8& result) {
    254     const GLExtensions& extensions(GLExtensions::getInstance());
    255     result.appendFormat("GLES: %s, %s, %s\n",
    256             extensions.getVendor(),
    257             extensions.getRenderer(),
    258             extensions.getVersion());
    259     result.appendFormat("%s\n", extensions.getExtension());
    260 }
    261 
    262 // ---------------------------------------------------------------------------
    263 
    264 RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
    265         RenderEngine& engine, EGLImageKHR image) : mEngine(engine)
    266 {
    267     mEngine.bindImageAsFramebuffer(image, &mTexName, &mFbName, &mStatus);
    268 
    269     ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES,
    270             "glCheckFramebufferStatusOES error %d", mStatus);
    271 }
    272 
    273 RenderEngine::BindImageAsFramebuffer::~BindImageAsFramebuffer() {
    274     // back to main framebuffer
    275     mEngine.unbindFramebuffer(mTexName, mFbName);
    276 }
    277 
    278 status_t RenderEngine::BindImageAsFramebuffer::getStatus() const {
    279     return mStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
    280 }
    281 
    282 // ---------------------------------------------------------------------------
    283 
    284 static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs,
    285         EGLint attribute, EGLint wanted, EGLConfig* outConfig) {
    286     EGLConfig config = NULL;
    287     EGLint numConfigs = -1, n = 0;
    288     eglGetConfigs(dpy, NULL, 0, &numConfigs);
    289     EGLConfig* const configs = new EGLConfig[numConfigs];
    290     eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
    291 
    292     if (n) {
    293         if (attribute != EGL_NONE) {
    294             for (int i=0 ; i<n ; i++) {
    295                 EGLint value = 0;
    296                 eglGetConfigAttrib(dpy, configs[i], attribute, &value);
    297                 if (wanted == value) {
    298                     *outConfig = configs[i];
    299                     delete [] configs;
    300                     return NO_ERROR;
    301                 }
    302             }
    303         } else {
    304             // just pick the first one
    305             *outConfig = configs[0];
    306             delete [] configs;
    307             return NO_ERROR;
    308         }
    309     }
    310     delete [] configs;
    311     return NAME_NOT_FOUND;
    312 }
    313 
    314 class EGLAttributeVector {
    315     struct Attribute;
    316     class Adder;
    317     friend class Adder;
    318     KeyedVector<Attribute, EGLint> mList;
    319     struct Attribute {
    320         Attribute() {};
    321         Attribute(EGLint v) : v(v) { }
    322         EGLint v;
    323         bool operator < (const Attribute& other) const {
    324             // this places EGL_NONE at the end
    325             EGLint lhs(v);
    326             EGLint rhs(other.v);
    327             if (lhs == EGL_NONE) lhs = 0x7FFFFFFF;
    328             if (rhs == EGL_NONE) rhs = 0x7FFFFFFF;
    329             return lhs < rhs;
    330         }
    331     };
    332     class Adder {
    333         friend class EGLAttributeVector;
    334         EGLAttributeVector& v;
    335         EGLint attribute;
    336         Adder(EGLAttributeVector& v, EGLint attribute)
    337             : v(v), attribute(attribute) {
    338         }
    339     public:
    340         void operator = (EGLint value) {
    341             if (attribute != EGL_NONE) {
    342                 v.mList.add(attribute, value);
    343             }
    344         }
    345         operator EGLint () const { return v.mList[attribute]; }
    346     };
    347 public:
    348     EGLAttributeVector() {
    349         mList.add(EGL_NONE, EGL_NONE);
    350     }
    351     void remove(EGLint attribute) {
    352         if (attribute != EGL_NONE) {
    353             mList.removeItem(attribute);
    354         }
    355     }
    356     Adder operator [] (EGLint attribute) {
    357         return Adder(*this, attribute);
    358     }
    359     EGLint operator [] (EGLint attribute) const {
    360        return mList[attribute];
    361     }
    362     // cast-operator to (EGLint const*)
    363     operator EGLint const* () const { return &mList.keyAt(0).v; }
    364 };
    365 
    366 
    367 static status_t selectEGLConfig(EGLDisplay display, EGLint format,
    368     EGLint renderableType, EGLConfig* config) {
    369     // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
    370     // it is to be used with WIFI displays
    371     status_t err;
    372     EGLint wantedAttribute;
    373     EGLint wantedAttributeValue;
    374 
    375     EGLAttributeVector attribs;
    376     if (renderableType) {
    377         attribs[EGL_RENDERABLE_TYPE]            = renderableType;
    378         attribs[EGL_RECORDABLE_ANDROID]         = EGL_TRUE;
    379         attribs[EGL_SURFACE_TYPE]               = EGL_WINDOW_BIT|EGL_PBUFFER_BIT;
    380         attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE;
    381         attribs[EGL_RED_SIZE]                   = 8;
    382         attribs[EGL_GREEN_SIZE]                 = 8;
    383         attribs[EGL_BLUE_SIZE]                  = 8;
    384         wantedAttribute                         = EGL_NONE;
    385         wantedAttributeValue                    = EGL_NONE;
    386     } else {
    387         // if no renderable type specified, fallback to a simplified query
    388         wantedAttribute                         = EGL_NATIVE_VISUAL_ID;
    389         wantedAttributeValue                    = format;
    390     }
    391 
    392     err = selectConfigForAttribute(display, attribs,
    393             wantedAttribute, wantedAttributeValue, config);
    394     if (err == NO_ERROR) {
    395         EGLint caveat;
    396         if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat))
    397             ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!");
    398     }
    399 
    400     return err;
    401 }
    402 
    403 EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format) {
    404     status_t err;
    405     EGLConfig config;
    406 
    407     // First try to get an ES2 config
    408     err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config);
    409     if (err != NO_ERROR) {
    410         // If ES2 fails, try ES1
    411         err = selectEGLConfig(display, format, EGL_OPENGL_ES_BIT, &config);
    412         if (err != NO_ERROR) {
    413             // still didn't work, probably because we're on the emulator...
    414             // try a simplified query
    415             ALOGW("no suitable EGLConfig found, trying a simpler query");
    416             err = selectEGLConfig(display, format, 0, &config);
    417             if (err != NO_ERROR) {
    418                 // this EGL is too lame for android
    419                 LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up");
    420             }
    421         }
    422     }
    423 
    424     // print some debugging info
    425     EGLint r,g,b,a;
    426     eglGetConfigAttrib(display, config, EGL_RED_SIZE,   &r);
    427     eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
    428     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,  &b);
    429     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
    430     ALOGI("EGL information:");
    431     ALOGI("vendor    : %s", eglQueryString(display, EGL_VENDOR));
    432     ALOGI("version   : %s", eglQueryString(display, EGL_VERSION));
    433     ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS));
    434     ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
    435     ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
    436 
    437     return config;
    438 }
    439 
    440 // ---------------------------------------------------------------------------
    441 }; // namespace android
    442 // ---------------------------------------------------------------------------
    443