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