rsdGL.cpp revision 653b53ebcd2bedc94ac486080d2e82e1920232e3
1/*
2 * Copyright (C) 2011 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 <ui/FramebufferNativeWindow.h>
18#include <ui/PixelFormat.h>
19#include <ui/EGLUtils.h>
20#include <ui/egl/android_natives.h>
21
22#include <sys/types.h>
23#include <sys/resource.h>
24#include <sched.h>
25
26#include <cutils/properties.h>
27
28#include <GLES/gl.h>
29#include <GLES/glext.h>
30#include <GLES2/gl2.h>
31#include <GLES2/gl2ext.h>
32
33#include <string.h>
34
35#include "rsdCore.h"
36#include "rsdGL.h"
37
38#include <malloc.h>
39#include "rsContext.h"
40#include "rsdShaderCache.h"
41#include "rsdVertexArray.h"
42#include "rsdFrameBufferObj.h"
43
44using namespace android;
45using namespace android::renderscript;
46
47static int32_t gGLContextCount = 0;
48
49static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
50    if (returnVal != EGL_TRUE) {
51        fprintf(stderr, "%s() returned %d\n", op, returnVal);
52    }
53
54    for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
55            = eglGetError()) {
56        fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
57                error);
58    }
59}
60
61static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
62
63#define X(VAL) {VAL, #VAL}
64    struct {EGLint attribute; const char* name;} names[] = {
65    X(EGL_BUFFER_SIZE),
66    X(EGL_ALPHA_SIZE),
67    X(EGL_BLUE_SIZE),
68    X(EGL_GREEN_SIZE),
69    X(EGL_RED_SIZE),
70    X(EGL_DEPTH_SIZE),
71    X(EGL_STENCIL_SIZE),
72    X(EGL_CONFIG_CAVEAT),
73    X(EGL_CONFIG_ID),
74    X(EGL_LEVEL),
75    X(EGL_MAX_PBUFFER_HEIGHT),
76    X(EGL_MAX_PBUFFER_PIXELS),
77    X(EGL_MAX_PBUFFER_WIDTH),
78    X(EGL_NATIVE_RENDERABLE),
79    X(EGL_NATIVE_VISUAL_ID),
80    X(EGL_NATIVE_VISUAL_TYPE),
81    X(EGL_SAMPLES),
82    X(EGL_SAMPLE_BUFFERS),
83    X(EGL_SURFACE_TYPE),
84    X(EGL_TRANSPARENT_TYPE),
85    X(EGL_TRANSPARENT_RED_VALUE),
86    X(EGL_TRANSPARENT_GREEN_VALUE),
87    X(EGL_TRANSPARENT_BLUE_VALUE),
88    X(EGL_BIND_TO_TEXTURE_RGB),
89    X(EGL_BIND_TO_TEXTURE_RGBA),
90    X(EGL_MIN_SWAP_INTERVAL),
91    X(EGL_MAX_SWAP_INTERVAL),
92    X(EGL_LUMINANCE_SIZE),
93    X(EGL_ALPHA_MASK_SIZE),
94    X(EGL_COLOR_BUFFER_TYPE),
95    X(EGL_RENDERABLE_TYPE),
96    X(EGL_CONFORMANT),
97   };
98#undef X
99
100    for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
101        EGLint value = -1;
102        EGLBoolean returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
103        if (returnVal) {
104            ALOGV(" %s: %d (0x%x)", names[j].name, value, value);
105        }
106    }
107}
108
109static void DumpDebug(RsdHal *dc) {
110    ALOGE(" EGL ver %i %i", dc->gl.egl.majorVersion, dc->gl.egl.minorVersion);
111    ALOGE(" EGL context %p  surface %p,  Display=%p", dc->gl.egl.context, dc->gl.egl.surface,
112         dc->gl.egl.display);
113    ALOGE(" GL vendor: %s", dc->gl.gl.vendor);
114    ALOGE(" GL renderer: %s", dc->gl.gl.renderer);
115    ALOGE(" GL Version: %s", dc->gl.gl.version);
116    ALOGE(" GL Extensions: %s", dc->gl.gl.extensions);
117    ALOGE(" GL int Versions %i %i", dc->gl.gl.majorVersion, dc->gl.gl.minorVersion);
118
119    ALOGV("MAX Textures %i, %i  %i", dc->gl.gl.maxVertexTextureUnits,
120         dc->gl.gl.maxFragmentTextureImageUnits, dc->gl.gl.maxTextureImageUnits);
121    ALOGV("MAX Attribs %i", dc->gl.gl.maxVertexAttribs);
122    ALOGV("MAX Uniforms %i, %i", dc->gl.gl.maxVertexUniformVectors,
123         dc->gl.gl.maxFragmentUniformVectors);
124    ALOGV("MAX Varyings %i", dc->gl.gl.maxVaryingVectors);
125}
126
127void rsdGLShutdown(const Context *rsc) {
128    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
129
130    dc->gl.shaderCache->cleanupAll();
131    delete dc->gl.shaderCache;
132    delete dc->gl.vertexArrayState;
133
134    if (dc->gl.egl.context != EGL_NO_CONTEXT) {
135        RSD_CALL_GL(eglMakeCurrent, dc->gl.egl.display,
136                    EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
137        RSD_CALL_GL(eglDestroySurface, dc->gl.egl.display, dc->gl.egl.surfaceDefault);
138        if (dc->gl.egl.surface != EGL_NO_SURFACE) {
139            RSD_CALL_GL(eglDestroySurface, dc->gl.egl.display, dc->gl.egl.surface);
140        }
141        RSD_CALL_GL(eglDestroyContext, dc->gl.egl.display, dc->gl.egl.context);
142        checkEglError("eglDestroyContext");
143    }
144
145    gGLContextCount--;
146    if (!gGLContextCount) {
147        RSD_CALL_GL(eglTerminate, dc->gl.egl.display);
148    }
149}
150
151bool rsdGLInit(const Context *rsc) {
152    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
153
154    dc->gl.egl.numConfigs = -1;
155    EGLint configAttribs[128];
156    EGLint *configAttribsPtr = configAttribs;
157    EGLint context_attribs2[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
158
159    memset(configAttribs, 0, sizeof(configAttribs));
160
161    configAttribsPtr[0] = EGL_SURFACE_TYPE;
162    configAttribsPtr[1] = EGL_WINDOW_BIT;
163    configAttribsPtr += 2;
164
165    configAttribsPtr[0] = EGL_RENDERABLE_TYPE;
166    configAttribsPtr[1] = EGL_OPENGL_ES2_BIT;
167    configAttribsPtr += 2;
168
169    configAttribsPtr[0] = EGL_RED_SIZE;
170    configAttribsPtr[1] = 8;
171    configAttribsPtr += 2;
172
173    configAttribsPtr[0] = EGL_GREEN_SIZE;
174    configAttribsPtr[1] = 8;
175    configAttribsPtr += 2;
176
177    configAttribsPtr[0] = EGL_BLUE_SIZE;
178    configAttribsPtr[1] = 8;
179    configAttribsPtr += 2;
180
181    if (rsc->mUserSurfaceConfig.alphaMin > 0) {
182        configAttribsPtr[0] = EGL_ALPHA_SIZE;
183        configAttribsPtr[1] = rsc->mUserSurfaceConfig.alphaMin;
184        configAttribsPtr += 2;
185    }
186
187    if (rsc->mUserSurfaceConfig.depthMin > 0) {
188        configAttribsPtr[0] = EGL_DEPTH_SIZE;
189        configAttribsPtr[1] = rsc->mUserSurfaceConfig.depthMin;
190        configAttribsPtr += 2;
191    }
192
193    if (rsc->mDev->mForceSW) {
194        configAttribsPtr[0] = EGL_CONFIG_CAVEAT;
195        configAttribsPtr[1] = EGL_SLOW_CONFIG;
196        configAttribsPtr += 2;
197    }
198
199    configAttribsPtr[0] = EGL_NONE;
200    rsAssert(configAttribsPtr < (configAttribs + (sizeof(configAttribs) / sizeof(EGLint))));
201
202    ALOGV("%p initEGL start", rsc);
203    rsc->setWatchdogGL("eglGetDisplay", __LINE__, __FILE__);
204    dc->gl.egl.display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
205    checkEglError("eglGetDisplay");
206
207    RSD_CALL_GL(eglInitialize, dc->gl.egl.display,
208                &dc->gl.egl.majorVersion, &dc->gl.egl.minorVersion);
209    checkEglError("eglInitialize");
210
211    EGLBoolean ret;
212
213    EGLint numConfigs = -1, n = 0;
214    rsc->setWatchdogGL("eglChooseConfig", __LINE__, __FILE__);
215    ret = eglChooseConfig(dc->gl.egl.display, configAttribs, 0, 0, &numConfigs);
216    checkEglError("eglGetConfigs", ret);
217
218    eglSwapInterval(dc->gl.egl.display, 0);
219
220    if (numConfigs) {
221        EGLConfig* const configs = new EGLConfig[numConfigs];
222
223        rsc->setWatchdogGL("eglChooseConfig", __LINE__, __FILE__);
224        ret = eglChooseConfig(dc->gl.egl.display,
225                configAttribs, configs, numConfigs, &n);
226        if (!ret || !n) {
227            checkEglError("eglChooseConfig", ret);
228            ALOGE("%p, couldn't find an EGLConfig matching the screen format\n", rsc);
229        }
230
231        // The first config is guaranteed to over-satisfy the constraints
232        dc->gl.egl.config = configs[0];
233
234        // go through the list and skip configs that over-satisfy our needs
235        for (int i=0 ; i<n ; i++) {
236            if (rsc->mUserSurfaceConfig.alphaMin <= 0) {
237                EGLint alphaSize;
238                eglGetConfigAttrib(dc->gl.egl.display,
239                        configs[i], EGL_ALPHA_SIZE, &alphaSize);
240                if (alphaSize > 0) {
241                    continue;
242                }
243            }
244
245            if (rsc->mUserSurfaceConfig.depthMin <= 0) {
246                EGLint depthSize;
247                eglGetConfigAttrib(dc->gl.egl.display,
248                        configs[i], EGL_DEPTH_SIZE, &depthSize);
249                if (depthSize > 0) {
250                    continue;
251                }
252            }
253
254            // Found one!
255            dc->gl.egl.config = configs[i];
256            break;
257        }
258
259        delete [] configs;
260    }
261
262    //if (props.mLogVisual) {
263    if (0) {
264        printEGLConfiguration(dc->gl.egl.display, dc->gl.egl.config);
265    }
266    //}
267
268    rsc->setWatchdogGL("eglCreateContext", __LINE__, __FILE__);
269    dc->gl.egl.context = eglCreateContext(dc->gl.egl.display, dc->gl.egl.config,
270                                          EGL_NO_CONTEXT, context_attribs2);
271    checkEglError("eglCreateContext");
272    if (dc->gl.egl.context == EGL_NO_CONTEXT) {
273        ALOGE("%p, eglCreateContext returned EGL_NO_CONTEXT", rsc);
274        rsc->setWatchdogGL(NULL, 0, NULL);
275        return false;
276    }
277    gGLContextCount++;
278
279
280    EGLint pbuffer_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
281    rsc->setWatchdogGL("eglCreatePbufferSurface", __LINE__, __FILE__);
282    dc->gl.egl.surfaceDefault = eglCreatePbufferSurface(dc->gl.egl.display, dc->gl.egl.config,
283                                                        pbuffer_attribs);
284    checkEglError("eglCreatePbufferSurface");
285    if (dc->gl.egl.surfaceDefault == EGL_NO_SURFACE) {
286        ALOGE("eglCreatePbufferSurface returned EGL_NO_SURFACE");
287        rsdGLShutdown(rsc);
288        rsc->setWatchdogGL(NULL, 0, NULL);
289        return false;
290    }
291
292    rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
293    ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
294                         dc->gl.egl.surfaceDefault, dc->gl.egl.context);
295    if (ret == EGL_FALSE) {
296        ALOGE("eglMakeCurrent returned EGL_FALSE");
297        checkEglError("eglMakeCurrent", ret);
298        rsdGLShutdown(rsc);
299        rsc->setWatchdogGL(NULL, 0, NULL);
300        return false;
301    }
302
303    dc->gl.gl.version = glGetString(GL_VERSION);
304    dc->gl.gl.vendor = glGetString(GL_VENDOR);
305    dc->gl.gl.renderer = glGetString(GL_RENDERER);
306    dc->gl.gl.extensions = glGetString(GL_EXTENSIONS);
307
308    //ALOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion);
309    //ALOGV("GL Version %s", mGL.mVersion);
310    //ALOGV("GL Vendor %s", mGL.mVendor);
311    //ALOGV("GL Renderer %s", mGL.mRenderer);
312    //ALOGV("GL Extensions %s", mGL.mExtensions);
313
314    const char *verptr = NULL;
315    if (strlen((const char *)dc->gl.gl.version) > 9) {
316        if (!memcmp(dc->gl.gl.version, "OpenGL ES-CM", 12)) {
317            verptr = (const char *)dc->gl.gl.version + 12;
318        }
319        if (!memcmp(dc->gl.gl.version, "OpenGL ES ", 10)) {
320            verptr = (const char *)dc->gl.gl.version + 9;
321        }
322    }
323
324    if (!verptr) {
325        ALOGE("Error, OpenGL ES Lite not supported");
326        rsdGLShutdown(rsc);
327        rsc->setWatchdogGL(NULL, 0, NULL);
328        return false;
329    } else {
330        sscanf(verptr, " %i.%i", &dc->gl.gl.majorVersion, &dc->gl.gl.minorVersion);
331    }
332
333    glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &dc->gl.gl.maxVertexAttribs);
334    glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &dc->gl.gl.maxVertexUniformVectors);
335    glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxVertexTextureUnits);
336
337    glGetIntegerv(GL_MAX_VARYING_VECTORS, &dc->gl.gl.maxVaryingVectors);
338    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxTextureImageUnits);
339
340    glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxFragmentTextureImageUnits);
341    glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &dc->gl.gl.maxFragmentUniformVectors);
342
343    dc->gl.gl.OES_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions,
344                                                "GL_OES_texture_npot");
345    dc->gl.gl.IMG_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions,
346                                                   "GL_IMG_texture_npot");
347    dc->gl.gl.NV_texture_npot_2D_mipmap = NULL != strstr((const char *)dc->gl.gl.extensions,
348                                                            "GL_NV_texture_npot_2D_mipmap");
349    dc->gl.gl.EXT_texture_max_aniso = 1.0f;
350    bool hasAniso = NULL != strstr((const char *)dc->gl.gl.extensions,
351                                   "GL_EXT_texture_filter_anisotropic");
352    if (hasAniso) {
353        glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &dc->gl.gl.EXT_texture_max_aniso);
354    }
355
356    if (0) {
357        DumpDebug(dc);
358    }
359
360    dc->gl.shaderCache = new RsdShaderCache();
361    dc->gl.vertexArrayState = new RsdVertexArrayState();
362    dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs);
363    dc->gl.currentFrameBuffer = NULL;
364    dc->mHasGraphics = true;
365
366    ALOGV("%p initGLThread end", rsc);
367    rsc->setWatchdogGL(NULL, 0, NULL);
368    return true;
369}
370
371
372bool rsdGLSetSurface(const Context *rsc, uint32_t w, uint32_t h, RsNativeWindow sur) {
373    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
374
375    EGLBoolean ret;
376    // WAR: Some drivers fail to handle 0 size surfaces correcntly.
377    // Use the pbuffer to avoid this pitfall.
378    if ((dc->gl.egl.surface != NULL) || (w == 0) || (h == 0)) {
379        rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
380        ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
381                             dc->gl.egl.surfaceDefault, dc->gl.egl.context);
382        checkEglError("eglMakeCurrent", ret);
383
384        rsc->setWatchdogGL("eglDestroySurface", __LINE__, __FILE__);
385        ret = eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface);
386        checkEglError("eglDestroySurface", ret);
387
388        dc->gl.egl.surface = NULL;
389        dc->gl.width = 1;
390        dc->gl.height = 1;
391    }
392
393    if (dc->gl.wndSurface != NULL) {
394        dc->gl.wndSurface->decStrong(NULL);
395    }
396
397    dc->gl.wndSurface = (ANativeWindow *)sur;
398    if (dc->gl.wndSurface != NULL) {
399        dc->gl.wndSurface->incStrong(NULL);
400        dc->gl.width = w;
401        dc->gl.height = h;
402
403        rsc->setWatchdogGL("eglCreateWindowSurface", __LINE__, __FILE__);
404        dc->gl.egl.surface = eglCreateWindowSurface(dc->gl.egl.display, dc->gl.egl.config,
405                                                    dc->gl.wndSurface, NULL);
406        checkEglError("eglCreateWindowSurface");
407        if (dc->gl.egl.surface == EGL_NO_SURFACE) {
408            ALOGE("eglCreateWindowSurface returned EGL_NO_SURFACE");
409        }
410
411        rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
412        ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surface,
413                             dc->gl.egl.surface, dc->gl.egl.context);
414        checkEglError("eglMakeCurrent", ret);
415    }
416    rsc->setWatchdogGL(NULL, 0, NULL);
417    return true;
418}
419
420void rsdGLSwap(const android::renderscript::Context *rsc) {
421    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
422    RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface);
423}
424
425void rsdGLSetPriority(const Context *rsc, int32_t priority) {
426    if (priority > 0) {
427        // Mark context as low priority.
428        ALOGV("low pri");
429    } else {
430        ALOGV("normal pri");
431    }
432}
433
434void rsdGLCheckError(const android::renderscript::Context *rsc,
435                     const char *msg, bool isFatal) {
436    GLenum err = glGetError();
437    if (err != GL_NO_ERROR) {
438        char buf[1024];
439        snprintf(buf, sizeof(buf), "GL Error = 0x%08x, from: %s", err, msg);
440
441        if (isFatal) {
442            rsc->setError(RS_ERROR_FATAL_DRIVER, buf);
443        } else {
444            switch (err) {
445            case GL_OUT_OF_MEMORY:
446                rsc->setError(RS_ERROR_OUT_OF_MEMORY, buf);
447                break;
448            default:
449                rsc->setError(RS_ERROR_DRIVER, buf);
450                break;
451            }
452        }
453
454        ALOGE("%p, %s", rsc, buf);
455    }
456
457}
458
459void rsdGLClearColor(const android::renderscript::Context *rsc,
460                     float r, float g, float b, float a) {
461    RSD_CALL_GL(glClearColor, r, g, b, a);
462    RSD_CALL_GL(glClear, GL_COLOR_BUFFER_BIT);
463}
464
465void rsdGLClearDepth(const android::renderscript::Context *rsc, float v) {
466    RSD_CALL_GL(glClearDepthf, v);
467    RSD_CALL_GL(glClear, GL_DEPTH_BUFFER_BIT);
468}
469
470void rsdGLFinish(const android::renderscript::Context *rsc) {
471    RSD_CALL_GL(glFinish);
472}
473
474void rsdGLDrawQuadTexCoords(const android::renderscript::Context *rsc,
475                            float x1, float y1, float z1, float u1, float v1,
476                            float x2, float y2, float z2, float u2, float v2,
477                            float x3, float y3, float z3, float u3, float v3,
478                            float x4, float y4, float z4, float u4, float v4) {
479
480    float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
481    const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
482
483    RsdVertexArray::Attrib attribs[2];
484    attribs[0].set(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "ATTRIB_position");
485    attribs[1].set(GL_FLOAT, 2, 8, false, (uint32_t)tex, "ATTRIB_texture0");
486
487    RsdVertexArray va(attribs, 2);
488    va.setup(rsc);
489
490    RSD_CALL_GL(glDrawArrays, GL_TRIANGLE_FAN, 0, 4);
491}
492