Home | History | Annotate | Download | only in flatland
      1 /*
      2  * Copyright (C) 2012 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 <GLES2/gl2.h>
     18 #include <GLES2/gl2ext.h>
     19 
     20 #include <ui/DisplayInfo.h>
     21 #include <gui/SurfaceComposerClient.h>
     22 
     23 #include "GLHelper.h"
     24 
     25  namespace android {
     26 
     27 GLHelper::GLHelper() :
     28     mDisplay(EGL_NO_DISPLAY),
     29     mContext(EGL_NO_CONTEXT),
     30     mDummySurface(EGL_NO_SURFACE),
     31     mConfig(0),
     32     mShaderPrograms(NULL),
     33     mDitherTexture(0) {
     34 }
     35 
     36 GLHelper::~GLHelper() {
     37 }
     38 
     39 bool GLHelper::setUp(const ShaderDesc* shaderDescs, size_t numShaders) {
     40     bool result;
     41 
     42     mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     43     if (mDisplay == EGL_NO_DISPLAY) {
     44         fprintf(stderr, "eglGetDisplay error: %#x\n", eglGetError());
     45         return false;
     46     }
     47 
     48     EGLint majorVersion;
     49     EGLint minorVersion;
     50     result = eglInitialize(mDisplay, &majorVersion, &minorVersion);
     51     if (result != EGL_TRUE) {
     52         fprintf(stderr, "eglInitialize error: %#x\n", eglGetError());
     53         return false;
     54     }
     55 
     56     EGLint numConfigs = 0;
     57     EGLint configAttribs[] = {
     58         EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
     59         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
     60         EGL_RED_SIZE, 8,
     61         EGL_GREEN_SIZE, 8,
     62         EGL_BLUE_SIZE, 8,
     63         EGL_ALPHA_SIZE, 8,
     64         EGL_NONE
     65     };
     66     result = eglChooseConfig(mDisplay, configAttribs, &mConfig, 1,
     67             &numConfigs);
     68     if (result != EGL_TRUE) {
     69         fprintf(stderr, "eglChooseConfig error: %#x\n", eglGetError());
     70         return false;
     71     }
     72 
     73     EGLint contextAttribs[] = {
     74         EGL_CONTEXT_CLIENT_VERSION, 2,
     75         EGL_NONE
     76     };
     77     mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT,
     78             contextAttribs);
     79     if (mContext == EGL_NO_CONTEXT) {
     80         fprintf(stderr, "eglCreateContext error: %#x\n", eglGetError());
     81         return false;
     82     }
     83 
     84     bool resultb = createNamedSurfaceTexture(0, 1, 1, &mDummyGLConsumer,
     85             &mDummySurface);
     86     if (!resultb) {
     87         return false;
     88     }
     89 
     90     resultb = makeCurrent(mDummySurface);
     91     if (!resultb) {
     92         return false;
     93     }
     94 
     95     resultb = setUpShaders(shaderDescs, numShaders);
     96     if (!resultb) {
     97         return false;
     98     }
     99 
    100     return true;
    101 }
    102 
    103 void GLHelper::tearDown() {
    104     if (mShaderPrograms != NULL) {
    105         delete[] mShaderPrograms;
    106         mShaderPrograms = NULL;
    107     }
    108 
    109     if (mSurfaceComposerClient != NULL) {
    110         mSurfaceComposerClient->dispose();
    111         mSurfaceComposerClient.clear();
    112     }
    113 
    114     if (mDisplay != EGL_NO_DISPLAY) {
    115         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
    116                 EGL_NO_CONTEXT);
    117     }
    118 
    119     if (mContext != EGL_NO_CONTEXT) {
    120         eglDestroyContext(mDisplay, mContext);
    121     }
    122 
    123     if (mDummySurface != EGL_NO_SURFACE) {
    124         eglDestroySurface(mDisplay, mDummySurface);
    125     }
    126 
    127     mDisplay = EGL_NO_DISPLAY;
    128     mContext = EGL_NO_CONTEXT;
    129     mDummySurface = EGL_NO_SURFACE;
    130     mDummyGLConsumer.clear();
    131     mConfig = 0;
    132 }
    133 
    134 bool GLHelper::makeCurrent(EGLSurface surface) {
    135     EGLint result;
    136 
    137     result = eglMakeCurrent(mDisplay, surface, surface, mContext);
    138     if (result != EGL_TRUE) {
    139         fprintf(stderr, "eglMakeCurrent error: %#x\n", eglGetError());
    140         return false;
    141     }
    142 
    143     EGLint w, h;
    144     eglQuerySurface(mDisplay, surface, EGL_WIDTH, &w);
    145     eglQuerySurface(mDisplay, surface, EGL_HEIGHT, &h);
    146     glViewport(0, 0, w, h);
    147 
    148     return true;
    149 }
    150 
    151 bool GLHelper::createSurfaceTexture(uint32_t w, uint32_t h,
    152         sp<GLConsumer>* glConsumer, EGLSurface* surface,
    153         GLuint* name) {
    154     if (!makeCurrent(mDummySurface)) {
    155         return false;
    156     }
    157 
    158     *name = 0;
    159     glGenTextures(1, name);
    160     if (*name == 0) {
    161         fprintf(stderr, "glGenTextures error: %#x\n", glGetError());
    162         return false;
    163     }
    164 
    165     return createNamedSurfaceTexture(*name, w, h, glConsumer, surface);
    166 }
    167 
    168 void GLHelper::destroySurface(EGLSurface* surface) {
    169     if (eglGetCurrentSurface(EGL_READ) == *surface ||
    170             eglGetCurrentSurface(EGL_DRAW) == *surface) {
    171         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
    172                 EGL_NO_CONTEXT);
    173     }
    174     eglDestroySurface(mDisplay, *surface);
    175     *surface = EGL_NO_SURFACE;
    176 }
    177 
    178 bool GLHelper::swapBuffers(EGLSurface surface) {
    179     EGLint result;
    180     result = eglSwapBuffers(mDisplay, surface);
    181     if (result != EGL_TRUE) {
    182         fprintf(stderr, "eglSwapBuffers error: %#x\n", eglGetError());
    183         return false;
    184     }
    185     return true;
    186 }
    187 
    188 bool GLHelper::getShaderProgram(const char* name, GLuint* outPgm) {
    189     for (size_t i = 0; i < mNumShaders; i++) {
    190         if (strcmp(mShaderDescs[i].name, name) == 0) {
    191             *outPgm = mShaderPrograms[i];
    192             return true;
    193         }
    194     }
    195 
    196     fprintf(stderr, "unknown shader name: \"%s\"\n", name);
    197 
    198     return false;
    199 }
    200 
    201 bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h,
    202         sp<GLConsumer>* glConsumer, EGLSurface* surface) {
    203     sp<IGraphicBufferProducer> producer;
    204     sp<IGraphicBufferConsumer> consumer;
    205     BufferQueue::createBufferQueue(&producer, &consumer);
    206     sp<GLConsumer> glc = new GLConsumer(consumer, name,
    207             GL_TEXTURE_EXTERNAL_OES, false, true);
    208     glc->setDefaultBufferSize(w, h);
    209     producer->setMaxDequeuedBufferCount(2);
    210     glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
    211 
    212     sp<ANativeWindow> anw = new Surface(producer);
    213     EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL);
    214     if (s == EGL_NO_SURFACE) {
    215         fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
    216         return false;
    217     }
    218 
    219     *glConsumer = glc;
    220     *surface = s;
    221     return true;
    222 }
    223 
    224 bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) {
    225     sp<IBinder> dpy = mSurfaceComposerClient->getBuiltInDisplay(0);
    226     if (dpy == NULL) {
    227         fprintf(stderr, "SurfaceComposer::getBuiltInDisplay failed.\n");
    228         return false;
    229     }
    230 
    231     DisplayInfo info;
    232     status_t err = mSurfaceComposerClient->getDisplayInfo(dpy, &info);
    233     if (err != NO_ERROR) {
    234         fprintf(stderr, "SurfaceComposer::getDisplayInfo failed: %#x\n", err);
    235         return false;
    236     }
    237 
    238     float scaleX = float(info.w) / float(w);
    239     float scaleY = float(info.h) / float(h);
    240     *scale = scaleX < scaleY ? scaleX : scaleY;
    241 
    242     return true;
    243 }
    244 
    245 bool GLHelper::createWindowSurface(uint32_t w, uint32_t h,
    246         sp<SurfaceControl>* surfaceControl, EGLSurface* surface) {
    247     bool result;
    248     status_t err;
    249 
    250     if (mSurfaceComposerClient == NULL) {
    251         mSurfaceComposerClient = new SurfaceComposerClient;
    252     }
    253     err = mSurfaceComposerClient->initCheck();
    254     if (err != NO_ERROR) {
    255         fprintf(stderr, "SurfaceComposerClient::initCheck error: %#x\n", err);
    256         return false;
    257     }
    258 
    259     sp<SurfaceControl> sc = mSurfaceComposerClient->createSurface(
    260             String8("Benchmark"), w, h, PIXEL_FORMAT_RGBA_8888, 0);
    261     if (sc == NULL || !sc->isValid()) {
    262         fprintf(stderr, "Failed to create SurfaceControl.\n");
    263         return false;
    264     }
    265 
    266     float scale;
    267     result = computeWindowScale(w, h, &scale);
    268     if (!result) {
    269         return false;
    270     }
    271 
    272     SurfaceComposerClient::openGlobalTransaction();
    273     err = sc->setLayer(0x7FFFFFFF);
    274     if (err != NO_ERROR) {
    275         fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err);
    276         return false;
    277     }
    278     err = sc->setMatrix(scale, 0.0f, 0.0f, scale);
    279     if (err != NO_ERROR) {
    280         fprintf(stderr, "SurfaceComposer::setMatrix error: %#x\n", err);
    281         return false;
    282     }
    283 
    284     err = sc->show();
    285     if (err != NO_ERROR) {
    286         fprintf(stderr, "SurfaceComposer::show error: %#x\n", err);
    287         return false;
    288     }
    289     SurfaceComposerClient::closeGlobalTransaction();
    290 
    291     sp<ANativeWindow> anw = sc->getSurface();
    292     EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL);
    293     if (s == EGL_NO_SURFACE) {
    294         fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
    295         return false;
    296     }
    297 
    298     *surfaceControl = sc;
    299     *surface = s;
    300     return true;
    301 }
    302 
    303 static bool compileShader(GLenum shaderType, const char* src,
    304         GLuint* outShader) {
    305     GLuint shader = glCreateShader(shaderType);
    306     if (shader == 0) {
    307         fprintf(stderr, "glCreateShader error: %#x\n", glGetError());
    308         return false;
    309     }
    310 
    311     glShaderSource(shader, 1, &src, NULL);
    312     glCompileShader(shader);
    313 
    314     GLint compiled = 0;
    315     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
    316     if (!compiled) {
    317         GLint infoLen = 0;
    318         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
    319         if (infoLen) {
    320             char* buf = new char[infoLen];
    321             if (buf) {
    322                 glGetShaderInfoLog(shader, infoLen, NULL, buf);
    323                 fprintf(stderr, "Shader compile log:\n%s\n", buf);
    324                 delete[] buf;
    325             }
    326         }
    327         glDeleteShader(shader);
    328         return false;
    329     }
    330     *outShader = shader;
    331     return true;
    332 }
    333 
    334 static void printShaderSource(const char* const* src) {
    335     for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
    336         fprintf(stderr, "%3zu: %s\n", i+1, src[i]);
    337     }
    338 }
    339 
    340 static const char* makeShaderString(const char* const* src) {
    341     size_t len = 0;
    342     for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
    343         // The +1 is for the '\n' that will be added.
    344         len += strlen(src[i]) + 1;
    345     }
    346 
    347     char* result = new char[len+1];
    348     char* end = result;
    349     for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
    350         strcpy(end, src[i]);
    351         end += strlen(src[i]);
    352         *end = '\n';
    353         end++;
    354     }
    355     *end = '\0';
    356 
    357     return result;
    358 }
    359 
    360 static bool compileShaderLines(GLenum shaderType, const char* const* lines,
    361         GLuint* outShader) {
    362     const char* src = makeShaderString(lines);
    363     bool result = compileShader(shaderType, src, outShader);
    364     if (!result) {
    365         fprintf(stderr, "Shader source:\n");
    366         printShaderSource(lines);
    367         delete[] src;
    368         return false;
    369     }
    370     delete[] src;
    371 
    372     return true;
    373 }
    374 
    375 static bool linkShaderProgram(GLuint vs, GLuint fs, GLuint* outPgm) {
    376     GLuint program = glCreateProgram();
    377     if (program == 0) {
    378         fprintf(stderr, "glCreateProgram error: %#x\n", glGetError());
    379         return false;
    380     }
    381 
    382     glAttachShader(program, vs);
    383     glAttachShader(program, fs);
    384     glLinkProgram(program);
    385     GLint linkStatus = GL_FALSE;
    386     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
    387     if (linkStatus != GL_TRUE) {
    388         GLint bufLength = 0;
    389         glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
    390         if (bufLength) {
    391             char* buf = new char[bufLength];
    392             if (buf) {
    393                 glGetProgramInfoLog(program, bufLength, NULL, buf);
    394                 fprintf(stderr, "Program link log:\n%s\n", buf);
    395                 delete[] buf;
    396             }
    397         }
    398         glDeleteProgram(program);
    399         program = 0;
    400     }
    401 
    402     *outPgm = program;
    403     return program != 0;
    404 }
    405 
    406 bool GLHelper::setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders) {
    407     mShaderPrograms = new GLuint[numShaders];
    408     bool result = true;
    409 
    410     for (size_t i = 0; i < numShaders && result; i++) {
    411         GLuint vs, fs;
    412 
    413         result = compileShaderLines(GL_VERTEX_SHADER,
    414                 shaderDescs[i].vertexShader, &vs);
    415         if (!result) {
    416             return false;
    417         }
    418 
    419         result = compileShaderLines(GL_FRAGMENT_SHADER,
    420                 shaderDescs[i].fragmentShader, &fs);
    421         if (!result) {
    422             glDeleteShader(vs);
    423             return false;
    424         }
    425 
    426         result = linkShaderProgram(vs, fs, &mShaderPrograms[i]);
    427         glDeleteShader(vs);
    428         glDeleteShader(fs);
    429     }
    430 
    431     mNumShaders = numShaders;
    432     mShaderDescs = shaderDescs;
    433 
    434     return result;
    435 }
    436 
    437 bool GLHelper::getDitherTexture(GLuint* outTexName) {
    438     if (mDitherTexture == 0) {
    439         const uint8_t pattern[] = {
    440              0,  8,  2, 10,
    441             12,  4, 14,  6,
    442              3, 11,  1,  9,
    443             15,  7, 13,  5
    444         };
    445 
    446         glGenTextures(1, &mDitherTexture);
    447         glBindTexture(GL_TEXTURE_2D, mDitherTexture);
    448 
    449         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    450         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    451 
    452         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    453         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    454 
    455         glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE,
    456                 DITHER_KERNEL_SIZE, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &pattern);
    457     }
    458 
    459     *outTexName = mDitherTexture;
    460 
    461     return true;
    462 }
    463 
    464 }
    465