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::Transaction{}.setLayer(sc, 0x7FFFFFFF)
    273             .setMatrix(sc, scale, 0.0f, 0.0f, scale)
    274             .show(sc)
    275             .apply();
    276 
    277     sp<ANativeWindow> anw = sc->getSurface();
    278     EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL);
    279     if (s == EGL_NO_SURFACE) {
    280         fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
    281         return false;
    282     }
    283 
    284     *surfaceControl = sc;
    285     *surface = s;
    286     return true;
    287 }
    288 
    289 static bool compileShader(GLenum shaderType, const char* src,
    290         GLuint* outShader) {
    291     GLuint shader = glCreateShader(shaderType);
    292     if (shader == 0) {
    293         fprintf(stderr, "glCreateShader error: %#x\n", glGetError());
    294         return false;
    295     }
    296 
    297     glShaderSource(shader, 1, &src, NULL);
    298     glCompileShader(shader);
    299 
    300     GLint compiled = 0;
    301     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
    302     if (!compiled) {
    303         GLint infoLen = 0;
    304         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
    305         if (infoLen) {
    306             char* buf = new char[infoLen];
    307             if (buf) {
    308                 glGetShaderInfoLog(shader, infoLen, NULL, buf);
    309                 fprintf(stderr, "Shader compile log:\n%s\n", buf);
    310                 delete[] buf;
    311             }
    312         }
    313         glDeleteShader(shader);
    314         return false;
    315     }
    316     *outShader = shader;
    317     return true;
    318 }
    319 
    320 static void printShaderSource(const char* const* src) {
    321     for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
    322         fprintf(stderr, "%3zu: %s\n", i+1, src[i]);
    323     }
    324 }
    325 
    326 static const char* makeShaderString(const char* const* src) {
    327     size_t len = 0;
    328     for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
    329         // The +1 is for the '\n' that will be added.
    330         len += strlen(src[i]) + 1;
    331     }
    332 
    333     char* result = new char[len+1];
    334     char* end = result;
    335     for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
    336         strcpy(end, src[i]);
    337         end += strlen(src[i]);
    338         *end = '\n';
    339         end++;
    340     }
    341     *end = '\0';
    342 
    343     return result;
    344 }
    345 
    346 static bool compileShaderLines(GLenum shaderType, const char* const* lines,
    347         GLuint* outShader) {
    348     const char* src = makeShaderString(lines);
    349     bool result = compileShader(shaderType, src, outShader);
    350     if (!result) {
    351         fprintf(stderr, "Shader source:\n");
    352         printShaderSource(lines);
    353         delete[] src;
    354         return false;
    355     }
    356     delete[] src;
    357 
    358     return true;
    359 }
    360 
    361 static bool linkShaderProgram(GLuint vs, GLuint fs, GLuint* outPgm) {
    362     GLuint program = glCreateProgram();
    363     if (program == 0) {
    364         fprintf(stderr, "glCreateProgram error: %#x\n", glGetError());
    365         return false;
    366     }
    367 
    368     glAttachShader(program, vs);
    369     glAttachShader(program, fs);
    370     glLinkProgram(program);
    371     GLint linkStatus = GL_FALSE;
    372     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
    373     if (linkStatus != GL_TRUE) {
    374         GLint bufLength = 0;
    375         glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
    376         if (bufLength) {
    377             char* buf = new char[bufLength];
    378             if (buf) {
    379                 glGetProgramInfoLog(program, bufLength, NULL, buf);
    380                 fprintf(stderr, "Program link log:\n%s\n", buf);
    381                 delete[] buf;
    382             }
    383         }
    384         glDeleteProgram(program);
    385         program = 0;
    386     }
    387 
    388     *outPgm = program;
    389     return program != 0;
    390 }
    391 
    392 bool GLHelper::setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders) {
    393     mShaderPrograms = new GLuint[numShaders];
    394     bool result = true;
    395 
    396     for (size_t i = 0; i < numShaders && result; i++) {
    397         GLuint vs, fs;
    398 
    399         result = compileShaderLines(GL_VERTEX_SHADER,
    400                 shaderDescs[i].vertexShader, &vs);
    401         if (!result) {
    402             return false;
    403         }
    404 
    405         result = compileShaderLines(GL_FRAGMENT_SHADER,
    406                 shaderDescs[i].fragmentShader, &fs);
    407         if (!result) {
    408             glDeleteShader(vs);
    409             return false;
    410         }
    411 
    412         result = linkShaderProgram(vs, fs, &mShaderPrograms[i]);
    413         glDeleteShader(vs);
    414         glDeleteShader(fs);
    415     }
    416 
    417     mNumShaders = numShaders;
    418     mShaderDescs = shaderDescs;
    419 
    420     return result;
    421 }
    422 
    423 bool GLHelper::getDitherTexture(GLuint* outTexName) {
    424     if (mDitherTexture == 0) {
    425         const uint8_t pattern[] = {
    426              0,  8,  2, 10,
    427             12,  4, 14,  6,
    428              3, 11,  1,  9,
    429             15,  7, 13,  5
    430         };
    431 
    432         glGenTextures(1, &mDitherTexture);
    433         glBindTexture(GL_TEXTURE_2D, mDitherTexture);
    434 
    435         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    436         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    437 
    438         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    439         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    440 
    441         glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE,
    442                 DITHER_KERNEL_SIZE, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &pattern);
    443     }
    444 
    445     *outTexName = mDitherTexture;
    446 
    447     return true;
    448 }
    449 
    450 }
    451