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