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