Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
      5  * in compliance with the License. You may obtain a copy of the License at
      6  *
      7  * http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the License
     10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
     11  * or implied. See the License for the specific language governing permissions and limitations under
     12  * the License.
     13  */
     14 #include "Renderer.h"
     15 #include <graphics/GLUtils.h>
     16 
     17 #define LOG_TAG "CTS_OPENGL"
     18 #define LOG_NDEBUG 0
     19 #include <android/log.h>
     20 
     21 #include <Trace.h>
     22 
     23 // Used to center the grid on the screen.
     24 #define CENTER_GRID(x) ((((x) * 2.0 + 1) - OFFSCREEN_GRID_SIZE) / OFFSCREEN_GRID_SIZE)
     25 // Leave a good error message if something fails.
     26 #define EGL_RESULT_CHECK(X) do { \
     27                                    EGLint error = eglGetError(); \
     28                                    if (!(X) || error != EGL_SUCCESS) { \
     29                                        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, \
     30                                           "EGL error '%d' at %s:%d", error, __FILE__, __LINE__);\
     31                                        return false; \
     32                                     } \
     33                             } while (0)
     34 
     35 static const int FBO_NUM_VERTICES = 6;
     36 
     37 static const float FBO_VERTICES[FBO_NUM_VERTICES * 3] = {
     38         0.1f, 0.1f, -0.1f,
     39         -0.1f, 0.1f, -0.1f,
     40         -0.1f, -0.1f, -0.1f,
     41         -0.1f, -0.1f, -0.1f,
     42         0.1f, -0.1f, -0.1f,
     43         0.1f, 0.1f, -0.1f };
     44 static const float FBO_TEX_COORDS[FBO_NUM_VERTICES * 2] = {
     45         1.0f, 1.0f,
     46         0.0f, 1.0f,
     47         0.0f, 0.0f,
     48         0.0f, 0.0f,
     49         1.0f, 0.0f,
     50         1.0f, 1.0f };
     51 
     52 static const char* FBO_VERTEX =
     53         "attribute vec4 a_Position;"
     54         "attribute vec2 a_TexCoord;"
     55         "uniform float u_XOffset;"
     56         "uniform float u_YOffset;"
     57         "varying vec2 v_TexCoord;"
     58         "void main() {"
     59         "  v_TexCoord = a_TexCoord;"
     60         "  gl_Position.x = a_Position.x + u_XOffset;"
     61         "  gl_Position.y = a_Position.y + u_YOffset;"
     62         "  gl_Position.zw = a_Position.zw;"
     63         "}";
     64 
     65 static const char* FBO_FRAGMENT =
     66         "precision mediump float;"
     67         "uniform sampler2D u_Texture;"
     68         "varying vec2 v_TexCoord;"
     69         "void main() {"
     70         "  gl_FragColor = texture2D(u_Texture, v_TexCoord);"
     71         "}";
     72 
     73 static const EGLint contextAttribs[] = {
     74         EGL_CONTEXT_CLIENT_VERSION, 2,
     75         EGL_NONE };
     76 
     77 static const EGLint configAttribs[] = {
     78         EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
     79         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
     80         EGL_RED_SIZE, 8,
     81         EGL_GREEN_SIZE, 8,
     82         EGL_BLUE_SIZE, 8,
     83         EGL_ALPHA_SIZE, 8,
     84         EGL_DEPTH_SIZE, 16,
     85         EGL_STENCIL_SIZE, 8,
     86         EGL_NONE };
     87 
     88 static const int FBO_SIZE = 128;
     89 
     90 Renderer::Renderer(EGLNativeWindowType window, bool offscreen) :
     91         mOffscreen(offscreen), mEglDisplay(EGL_NO_DISPLAY), mEglSurface(EGL_NO_SURFACE),
     92         mEglContext(EGL_NO_CONTEXT), mWindow(window)  {
     93 }
     94 
     95 bool Renderer::eglSetUp() {
     96     SCOPED_TRACE();
     97     mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     98     EGL_RESULT_CHECK(mEglDisplay != EGL_NO_DISPLAY);
     99 
    100     EGLint major;
    101     EGLint minor;
    102     EGL_RESULT_CHECK(eglInitialize(mEglDisplay, &major, &minor));
    103 
    104     EGLint numConfigs = 0;
    105     EGL_RESULT_CHECK(eglChooseConfig(mEglDisplay, configAttribs, &mGlConfig, 1, &numConfigs)
    106                      && (numConfigs > 0));
    107 
    108     mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, mWindow, NULL);
    109     EGL_RESULT_CHECK(mEglSurface != EGL_NO_SURFACE);
    110 
    111     mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT, contextAttribs);
    112     EGL_RESULT_CHECK(mEglContext != EGL_NO_CONTEXT);
    113 
    114     EGL_RESULT_CHECK(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext));
    115     EGL_RESULT_CHECK(eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &mWidth));
    116     EGL_RESULT_CHECK(eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &mHeight));
    117 
    118     return true;
    119 }
    120 
    121 void Renderer::eglTearDown() {
    122     SCOPED_TRACE();
    123     eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    124 
    125     if (mEglContext != EGL_NO_CONTEXT) {
    126         eglDestroyContext(mEglDisplay, mEglContext);
    127         mEglContext = EGL_NO_CONTEXT;
    128     }
    129 
    130     if (mEglSurface != EGL_NO_SURFACE) {
    131         mEglSurface = EGL_NO_SURFACE;
    132     }
    133 
    134     if (mEglDisplay != EGL_NO_DISPLAY) {
    135         eglTerminate(mEglDisplay);
    136         mEglDisplay = EGL_NO_DISPLAY;
    137     }
    138 }
    139 
    140 bool Renderer::setUp(int /*workload*/) {
    141     SCOPED_TRACE();
    142 
    143     EGL_RESULT_CHECK(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext));
    144 
    145     if (mOffscreen) {
    146         mFboWidth = FBO_SIZE;
    147         mFboHeight = FBO_SIZE;
    148 
    149         glGenFramebuffers(1, &mFboId);
    150         glBindFramebuffer(GL_FRAMEBUFFER, mFboId);
    151 
    152         glGenRenderbuffers(1, &mFboDepthId);
    153         glBindRenderbuffer(GL_RENDERBUFFER, mFboDepthId);
    154         glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, mFboWidth, mFboHeight);
    155         glBindRenderbuffer(GL_RENDERBUFFER, 0);
    156         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
    157                                   GL_RENDERBUFFER, mFboDepthId);
    158 
    159         mFboTexId = GLUtils::genTexture(mFboWidth, mFboHeight, 0);
    160         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFboTexId, 0);
    161 
    162         GLuint err = glGetError();
    163         if (err != GL_NO_ERROR) {
    164             __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "GLError %d", err);
    165             return false;
    166         }
    167 
    168         GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    169         if (status != GL_FRAMEBUFFER_COMPLETE) {
    170            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Framebuffer not complete: %d", status);
    171             return false;
    172         }
    173         // Create fbo program.
    174         mFboProgId = GLUtils::createProgram(&FBO_VERTEX, &FBO_FRAGMENT);
    175         if (mFboProgId == 0) {
    176             return false;
    177         }
    178         // Bind attributes.
    179         mFboTexUniformHandle = glGetUniformLocation(mFboProgId, "u_Texture");
    180         mFboXOffsetUniformHandle = glGetUniformLocation(mFboProgId, "u_XOffset");
    181         mFboYOffsetUniformHandle = glGetUniformLocation(mFboProgId, "u_YOffset");
    182         mFboPositionHandle = glGetAttribLocation(mFboProgId, "a_Position");
    183         mFboTexCoordHandle = glGetAttribLocation(mFboProgId, "a_TexCoord");
    184     } else {
    185         mFboWidth = 0;
    186         mFboHeight = 0;
    187         mFboId = 0;
    188         mFboDepthId = 0;
    189         mFboTexId = 0;
    190     }
    191 
    192     GLuint err = glGetError();
    193     if (err != GL_NO_ERROR) {
    194         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "GLError %d in setUp", err);
    195         return false;
    196     }
    197 
    198     return true;
    199 }
    200 
    201 bool Renderer::tearDown() {
    202     SCOPED_TRACE();
    203     if (mOffscreen) {
    204         if (mFboId != 0) {
    205             glDeleteFramebuffers(1, &mFboId);
    206             mFboId = 0;
    207         }
    208         if (mFboDepthId != 0) {
    209             glDeleteRenderbuffers(1, &mFboDepthId);
    210             mFboDepthId = 0;
    211         }
    212         if (mFboTexId != 0) {
    213             glDeleteTextures(1, &mFboTexId);
    214             mFboTexId = 0;
    215         }
    216     }
    217     GLuint err = glGetError();
    218     if (err != GL_NO_ERROR) {
    219         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "GLError %d in tearDown", err);
    220         return false;
    221     }
    222 
    223     return true;
    224 }
    225 
    226 bool Renderer::draw() {
    227     SCOPED_TRACE();
    228 
    229     EGL_RESULT_CHECK(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext));
    230 
    231     glBindFramebuffer(GL_FRAMEBUFFER, 0);
    232     glViewport(0, 0, mWidth, mHeight);
    233 
    234     if (mOffscreen) {
    235         // Set the background clear color to black.
    236         glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    237         glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    238         for (int i = 0; i < OFFSCREEN_INNER_FRAMES; i++) {
    239             // Switch to FBO and re-attach.
    240             glBindFramebuffer(GL_FRAMEBUFFER, mFboId);
    241             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
    242                                     GL_RENDERBUFFER, mFboDepthId);
    243             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
    244                                  GL_TEXTURE_2D, mFboTexId, 0);
    245             glViewport(0, 0, mFboWidth, mFboHeight);
    246 
    247             // Render workload.
    248             drawWorkload();
    249             glFlush();
    250 
    251             // Switch back to display.
    252             glBindFramebuffer(GL_FRAMEBUFFER, 0);
    253             glViewport(0, 0, mWidth, mHeight);
    254 
    255             // No culling of back faces
    256             glDisable (GL_CULL_FACE);
    257             // No depth testing
    258             glDisable (GL_DEPTH_TEST);
    259             // No blending
    260             glDisable (GL_BLEND);
    261 
    262             glUseProgram(mFboProgId);
    263 
    264             // Set the texture.
    265             glActiveTexture (GL_TEXTURE0);
    266             glBindTexture(GL_TEXTURE_2D, mFboTexId);
    267             glUniform1i(mFboTexUniformHandle, 0);
    268 
    269             // Set the offsets
    270             glUniform1f(mFboXOffsetUniformHandle, CENTER_GRID(i / OFFSCREEN_GRID_SIZE));
    271             glUniform1f(mFboYOffsetUniformHandle, CENTER_GRID(i % OFFSCREEN_GRID_SIZE));
    272 
    273             glEnableVertexAttribArray(mFboPositionHandle);
    274             glEnableVertexAttribArray(mFboTexCoordHandle);
    275             glVertexAttribPointer(mFboPositionHandle, 3, GL_FLOAT, false, 0, FBO_VERTICES);
    276             glVertexAttribPointer(mFboTexCoordHandle, 2, GL_FLOAT, false, 0, FBO_TEX_COORDS);
    277 
    278             // Render FBO to display.
    279             glDrawArrays(GL_TRIANGLES, 0, FBO_NUM_VERTICES);
    280         }
    281     } else {
    282         // Render workload.
    283         drawWorkload();
    284     }
    285 
    286     GLuint err = glGetError();
    287     if (err != GL_NO_ERROR) {
    288         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "GLError %d in draw", err);
    289         return false;
    290     }
    291 
    292     EGL_RESULT_CHECK(eglSwapBuffers(mEglDisplay, mEglSurface));
    293     return true;
    294 }
    295