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 <android/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) : 78 Renderer(window, offscreen), mContexts(NULL), mWorkload(0) { 79 } 80 81 bool ContextSwitchRenderer::setUp(int workload) { 82 SCOPED_TRACE(); 83 mWorkload = workload; 84 if (!Renderer::setUp(workload)) { 85 return false; 86 } 87 88 // Setup texture. 89 mTextureId = GLUtils::genTexture(CS_TEXTURE_SIZE, CS_TEXTURE_SIZE, GLUtils::RANDOM_FILL); 90 if (mTextureId == 0) { 91 return false; 92 } 93 94 // Create program. 95 mProgramId = GLUtils::createProgram(&CS_VERTEX, &CS_FRAGMENT); 96 if (mProgramId == 0) { 97 return false; 98 } 99 // Bind attributes. 100 mTextureUniformHandle = glGetUniformLocation(mProgramId, "u_Texture"); 101 mTranslateUniformHandle = glGetUniformLocation(mProgramId, "u_Translate"); 102 mPositionHandle = glGetAttribLocation(mProgramId, "a_Position"); 103 mTexCoordHandle = glGetAttribLocation(mProgramId, "a_TexCoord"); 104 105 mContexts = new EGLContext[NUM_WORKER_CONTEXTS]; 106 mFboIds = new GLuint[NUM_WORKER_CONTEXTS]; 107 for (int i = 0; i < NUM_WORKER_CONTEXTS; i++) { 108 // Create the contexts, they share data with the main one. 109 mContexts[i] = eglCreateContext(mEglDisplay, mGlConfig, mEglContext, contextAttribs); 110 if (EGL_NO_CONTEXT == mContexts[i] || EGL_SUCCESS != eglGetError()) { 111 return false; 112 } 113 114 if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mContexts[i]) 115 || EGL_SUCCESS != eglGetError()) { 116 return false; 117 } 118 if (mOffscreen) { 119 // FBOs are not shared across contexts, textures and renderbuffers are though. 120 glGenFramebuffers(1, &mFboIds[i]); 121 glBindFramebuffer(GL_FRAMEBUFFER, mFboIds[i]); 122 123 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 124 GL_RENDERBUFFER, mFboDepthId); 125 126 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 127 GL_TEXTURE_2D, mFboTexId, 0); 128 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 129 if (status != GL_FRAMEBUFFER_COMPLETE) { 130 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Framebuffer not complete: %d", status); 131 return false; 132 } 133 } 134 } 135 return true; 136 } 137 138 bool ContextSwitchRenderer::tearDown() { 139 SCOPED_TRACE(); 140 if (mContexts) { 141 // Destroy the contexts, the main one will be handled by Renderer::eglTearDown(). 142 for (int i = 0; i < NUM_WORKER_CONTEXTS; i++) { 143 if (mOffscreen) { 144 if (mFboIds[i] != 0) { 145 eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mContexts[i]); 146 glDeleteFramebuffers(1, &mFboIds[i]); 147 mFboIds[i] = 0; 148 } 149 } 150 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 151 eglDestroyContext(mEglDisplay, mContexts[i]); 152 } 153 delete[] mContexts; 154 } 155 eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); 156 if (mTextureId != 0) { 157 glDeleteTextures(1, &mTextureId); 158 mTextureId = 0; 159 } 160 if (!Renderer::tearDown()) { 161 return false; 162 } 163 return true; 164 } 165 166 void ContextSwitchRenderer::drawWorkload() { 167 SCOPED_TRACE(); 168 169 if (mWorkload > 8) { 170 return; // This test does not support higher workloads. 171 } 172 173 // Set the background clear color to black. 174 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 175 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 176 // No culling of back faces 177 glDisable(GL_CULL_FACE); 178 // No depth testing 179 glDisable(GL_DEPTH_TEST); 180 181 EGLSyncKHR fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL); 182 183 const int TOTAL_NUM_CONTEXTS = NUM_WORKER_CONTEXTS + 1; 184 const float TRANSLATION = 0.9f - (TOTAL_NUM_CONTEXTS * 0.2f); 185 for (int i = 0; i < TOTAL_NUM_CONTEXTS; i++) { 186 eglWaitSyncKHR(mEglDisplay, fence, 0); 187 eglDestroySyncKHR(mEglDisplay, fence); 188 glUseProgram(mProgramId); 189 190 // Set the texture. 191 glActiveTexture (GL_TEXTURE0); 192 glBindTexture(GL_TEXTURE_2D, mTextureId); 193 glUniform1i(mTextureUniformHandle, 0); 194 195 // Set the x translate. 196 glUniform1f(mTranslateUniformHandle, (i * 0.2f) + TRANSLATION); 197 198 glEnableVertexAttribArray(mPositionHandle); 199 glEnableVertexAttribArray(mTexCoordHandle); 200 glVertexAttribPointer(mPositionHandle, 3, GL_FLOAT, false, 0, CS_VERTICES); 201 glVertexAttribPointer(mTexCoordHandle, 2, GL_FLOAT, false, 0, CS_TEX_COORDS); 202 203 glDrawArrays(GL_TRIANGLES, 0, CS_NUM_VERTICES); 204 fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL); 205 206 // Switch to next context. 207 if (i < (mWorkload - 1)) { 208 eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mContexts[i]); 209 // Switch to FBO and re-attach. 210 if (mOffscreen) { 211 glBindFramebuffer(GL_FRAMEBUFFER, mFboIds[i]); 212 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 213 GL_RENDERBUFFER, mFboDepthId); 214 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 215 GL_TEXTURE_2D, mFboTexId, 0); 216 glViewport(0, 0, mFboWidth, mFboHeight); 217 } 218 } 219 GLuint err = glGetError(); 220 if (err != GL_NO_ERROR) { 221 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "GLError %d in drawWorkload", err); 222 break; 223 } 224 } 225 226 eglWaitSyncKHR(mEglDisplay, fence, 0); 227 eglDestroySyncKHR(mEglDisplay, fence); 228 229 // Switch back to the main context. 230 eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); 231 if (mOffscreen) { 232 glBindFramebuffer(GL_FRAMEBUFFER, mFboId); 233 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 234 GL_RENDERBUFFER, mFboDepthId); 235 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 236 GL_TEXTURE_2D, mFboTexId, 0); 237 glViewport(0, 0, mFboWidth, mFboHeight); 238 } 239 } 240