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