Home | History | Annotate | Download | only in contextswitch
      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 
     15 #include <android/native_window.h>
     16 
     17 #include <stdlib.h>
     18 
     19 #include <EGL/egl.h>
     20 #include <EGL/eglext.h>
     21 #include <GLES2/gl2.h>
     22 #include <GLES2/gl2ext.h>
     23 
     24 #include "ContextSwitchRenderer.h"
     25 #include <graphics/GLUtils.h>
     26 
     27 #define LOG_TAG "CTS_OPENGL"
     28 #define LOG_NDEBUG 0
     29 #include <utils/Log.h>
     30 #include <Trace.h>
     31 
     32 static const EGLint contextAttribs[] = {
     33         EGL_CONTEXT_CLIENT_VERSION, 2,
     34         EGL_NONE };
     35 
     36 static const int NUM_WORKER_CONTEXTS = 7;
     37 
     38 static const int CS_TEXTURE_SIZE = 64;
     39 
     40 static const int CS_NUM_VERTICES = 6;
     41 
     42 static const float CS_VERTICES[CS_NUM_VERTICES * 3] = {
     43         0.1f, 0.1f, -0.1f,
     44         -0.1f, 0.1f, -0.1f,
     45         -0.1f, -0.1f, -0.1f,
     46         -0.1f, -0.1f, -0.1f,
     47         0.1f, -0.1f, -0.1f,
     48         0.1f, 0.1f, -0.1f };
     49 
     50 static const float CS_TEX_COORDS[CS_NUM_VERTICES * 2] = {
     51         1.0f, 1.0f,
     52         0.0f, 1.0f,
     53         0.0f, 0.0f,
     54         0.0f, 0.0f,
     55         1.0f, 0.0f,
     56         1.0f, 1.0f };
     57 
     58 static const char* CS_VERTEX =
     59         "attribute vec4 a_Position;"
     60         "attribute vec2 a_TexCoord;"
     61         "uniform float u_Translate;"
     62         "varying vec2 v_TexCoord;"
     63         "void main() {"
     64         "  v_TexCoord = a_TexCoord;"
     65         "  gl_Position.x = a_Position.x + u_Translate;"
     66         "  gl_Position.yzw = a_Position.yzw;"
     67         "}";
     68 
     69 static const char* CS_FRAGMENT =
     70         "precision mediump float;"
     71         "uniform sampler2D u_Texture;"
     72         "varying vec2 v_TexCoord;"
     73         "void main() {"
     74         "  gl_FragColor = texture2D(u_Texture, v_TexCoord);"
     75         "}";
     76 
     77 ContextSwitchRenderer::ContextSwitchRenderer(ANativeWindow* window, bool offscreen, int workload) :
     78         Renderer(window, offscreen, workload), mContexts(NULL) {
     79 }
     80 
     81 bool ContextSwitchRenderer::setUp() {
     82     SCOPED_TRACE();
     83     if (!Renderer::setUp()) {
     84         return false;
     85     }
     86 
     87     // Setup texture.
     88     mTextureId = GLUtils::genTexture(CS_TEXTURE_SIZE, CS_TEXTURE_SIZE, GLUtils::RANDOM_FILL);
     89     if (mTextureId == 0) {
     90         return false;
     91     }
     92 
     93     // Create program.
     94     mProgramId = GLUtils::createProgram(&CS_VERTEX, &CS_FRAGMENT);
     95     if (mProgramId == 0) {
     96         return false;
     97     }
     98     // Bind attributes.
     99     mTextureUniformHandle = glGetUniformLocation(mProgramId, "u_Texture");
    100     mTranslateUniformHandle = glGetUniformLocation(mProgramId, "u_Translate");
    101     mPositionHandle = glGetAttribLocation(mProgramId, "a_Position");
    102     mTexCoordHandle = glGetAttribLocation(mProgramId, "a_TexCoord");
    103 
    104     mContexts = new EGLContext[NUM_WORKER_CONTEXTS];
    105     mFboIds = new GLuint[NUM_WORKER_CONTEXTS];
    106     for (int i = 0; i < NUM_WORKER_CONTEXTS; i++) {
    107         // Create the contexts, they share data with the main one.
    108         mContexts[i] = eglCreateContext(mEglDisplay, mGlConfig, mEglContext, contextAttribs);
    109         if (EGL_NO_CONTEXT == mContexts[i] || EGL_SUCCESS != eglGetError()) {
    110             return false;
    111         }
    112 
    113         if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mContexts[i])
    114                 || EGL_SUCCESS != eglGetError()) {
    115             return false;
    116         }
    117         if (mOffscreen) {
    118             // FBOs are not shared across contexts, textures and renderbuffers are though.
    119             glGenFramebuffers(1, &mFboIds[i]);
    120             glBindFramebuffer(GL_FRAMEBUFFER, mFboIds[i]);
    121 
    122             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
    123                                       GL_RENDERBUFFER, mFboDepthId);
    124 
    125             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
    126                                    GL_TEXTURE_2D, mFboTexId, 0);
    127             GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    128             if (status != GL_FRAMEBUFFER_COMPLETE) {
    129                 ALOGE("Framebuffer not complete: %d", status);
    130                 return false;
    131             }
    132         }
    133     }
    134     return true;
    135 }
    136 
    137 bool ContextSwitchRenderer::tearDown() {
    138     SCOPED_TRACE();
    139     if (mContexts) {
    140         // Destroy the contexts, the main one will be handled by Renderer::tearDown().
    141         for (int i = 0; i < NUM_WORKER_CONTEXTS; i++) {
    142             if (mOffscreen) {
    143                 if (mFboIds[i] != 0) {
    144                     eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mContexts[i]);
    145                     glDeleteFramebuffers(1, &mFboIds[i]);
    146                     mFboIds[i] = 0;
    147                 }
    148             }
    149             eglDestroyContext(mEglDisplay, mContexts[i]);
    150         }
    151         delete[] mContexts;
    152     }
    153     eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
    154     if (mTextureId != 0) {
    155         glDeleteTextures(1, &mTextureId);
    156         mTextureId = 0;
    157     }
    158     if (!Renderer::tearDown()) {
    159         return false;
    160     }
    161     return true;
    162 }
    163 
    164 void ContextSwitchRenderer::drawWorkload() {
    165     SCOPED_TRACE();
    166     // Set the background clear color to black.
    167     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    168     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    169     // No culling of back faces
    170     glDisable(GL_CULL_FACE);
    171     // No depth testing
    172     glDisable(GL_DEPTH_TEST);
    173 
    174     EGLSyncKHR fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL);
    175 
    176     const int TOTAL_NUM_CONTEXTS = NUM_WORKER_CONTEXTS + 1;
    177     const float TRANSLATION = 0.9f - (TOTAL_NUM_CONTEXTS * 0.2f);
    178     for (int i = 0; i < TOTAL_NUM_CONTEXTS; i++) {
    179         eglWaitSyncKHR(mEglDisplay, fence, 0);
    180         eglDestroySyncKHR(mEglDisplay, fence);
    181         glUseProgram(mProgramId);
    182 
    183         // Set the texture.
    184         glActiveTexture (GL_TEXTURE0);
    185         glBindTexture(GL_TEXTURE_2D, mTextureId);
    186         glUniform1i(mTextureUniformHandle, 0);
    187 
    188         // Set the x translate.
    189         glUniform1f(mTranslateUniformHandle, (i * 0.2f) + TRANSLATION);
    190 
    191         glEnableVertexAttribArray(mPositionHandle);
    192         glEnableVertexAttribArray(mTexCoordHandle);
    193         glVertexAttribPointer(mPositionHandle, 3, GL_FLOAT, false, 0, CS_VERTICES);
    194         glVertexAttribPointer(mTexCoordHandle, 2, GL_FLOAT, false, 0, CS_TEX_COORDS);
    195 
    196         glDrawArrays(GL_TRIANGLES, 0, CS_NUM_VERTICES);
    197         fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL);
    198 
    199         // Switch to next context.
    200         if (i < (mWorkload - 1)) {
    201             eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mContexts[i]);
    202             // Switch to FBO and re-attach.
    203             if (mOffscreen) {
    204                 glBindFramebuffer(GL_FRAMEBUFFER, mFboIds[i]);
    205                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
    206                                         GL_RENDERBUFFER, mFboDepthId);
    207                 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
    208                                      GL_TEXTURE_2D, mFboTexId, 0);
    209                 glViewport(0, 0, mFboWidth, mFboHeight);
    210             }
    211         }
    212         GLuint err = glGetError();
    213         if (err != GL_NO_ERROR) {
    214             ALOGE("GLError %d in drawWorkload", err);
    215             break;
    216         }
    217     }
    218 
    219     eglDestroySyncKHR(mEglDisplay, fence);
    220 
    221     // Switch back to the main context.
    222     eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
    223     if (mOffscreen) {
    224         glBindFramebuffer(GL_FRAMEBUFFER, mFboId);
    225         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
    226                                 GL_RENDERBUFFER, mFboDepthId);
    227         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
    228                              GL_TEXTURE_2D, mFboTexId, 0);
    229         glViewport(0, 0, mFboWidth, mFboHeight);
    230     }
    231 }
    232