1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.test.uibench.opengl; 17 18 import android.content.res.Resources; 19 import android.graphics.Bitmap; 20 import android.graphics.BitmapFactory; 21 import android.graphics.SurfaceTexture; 22 import android.opengl.GLUtils; 23 import android.util.Log; 24 25 import com.android.test.uibench.R; 26 27 import java.nio.ByteBuffer; 28 import java.nio.ByteOrder; 29 import java.nio.FloatBuffer; 30 31 import javax.microedition.khronos.egl.EGL10; 32 import javax.microedition.khronos.egl.EGLConfig; 33 import javax.microedition.khronos.egl.EGLContext; 34 import javax.microedition.khronos.egl.EGLDisplay; 35 import javax.microedition.khronos.egl.EGLSurface; 36 37 import static android.opengl.GLES20.GL_CLAMP_TO_EDGE; 38 import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT; 39 import static android.opengl.GLES20.GL_COMPILE_STATUS; 40 import static android.opengl.GLES20.GL_FLOAT; 41 import static android.opengl.GLES20.GL_FRAGMENT_SHADER; 42 import static android.opengl.GLES20.GL_LINEAR; 43 import static android.opengl.GLES20.GL_LINK_STATUS; 44 import static android.opengl.GLES20.GL_NO_ERROR; 45 import static android.opengl.GLES20.GL_RGBA; 46 import static android.opengl.GLES20.GL_TEXTURE0; 47 import static android.opengl.GLES20.GL_TEXTURE_2D; 48 import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER; 49 import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER; 50 import static android.opengl.GLES20.GL_TEXTURE_WRAP_S; 51 import static android.opengl.GLES20.GL_TEXTURE_WRAP_T; 52 import static android.opengl.GLES20.GL_TRIANGLE_STRIP; 53 import static android.opengl.GLES20.GL_TRUE; 54 import static android.opengl.GLES20.GL_UNSIGNED_BYTE; 55 import static android.opengl.GLES20.GL_VERTEX_SHADER; 56 import static android.opengl.GLES20.glActiveTexture; 57 import static android.opengl.GLES20.glAttachShader; 58 import static android.opengl.GLES20.glBindTexture; 59 import static android.opengl.GLES20.glClear; 60 import static android.opengl.GLES20.glClearColor; 61 import static android.opengl.GLES20.glCompileShader; 62 import static android.opengl.GLES20.glCreateProgram; 63 import static android.opengl.GLES20.glCreateShader; 64 import static android.opengl.GLES20.glDeleteProgram; 65 import static android.opengl.GLES20.glDeleteShader; 66 import static android.opengl.GLES20.glDrawArrays; 67 import static android.opengl.GLES20.glEnableVertexAttribArray; 68 import static android.opengl.GLES20.glGenTextures; 69 import static android.opengl.GLES20.glGetAttribLocation; 70 import static android.opengl.GLES20.glGetError; 71 import static android.opengl.GLES20.glGetProgramInfoLog; 72 import static android.opengl.GLES20.glGetProgramiv; 73 import static android.opengl.GLES20.glGetShaderInfoLog; 74 import static android.opengl.GLES20.glGetShaderiv; 75 import static android.opengl.GLES20.glGetUniformLocation; 76 import static android.opengl.GLES20.glLinkProgram; 77 import static android.opengl.GLES20.glShaderSource; 78 import static android.opengl.GLES20.glTexParameteri; 79 import static android.opengl.GLES20.glUniform1i; 80 import static android.opengl.GLES20.glUseProgram; 81 import static android.opengl.GLES20.glVertexAttribPointer; 82 83 public class ImageFlipRenderThread extends Thread { 84 public static final String LOG_TAG = "GLTextureView"; 85 86 static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 87 static final int EGL_OPENGL_ES2_BIT = 4; 88 89 private volatile boolean mFinished; 90 91 private final Resources mResources; 92 private final SurfaceTexture mSurface; 93 94 private EGL10 mEgl; 95 private EGLDisplay mEglDisplay; 96 private EGLConfig mEglConfig; 97 private EGLContext mEglContext; 98 private EGLSurface mEglSurface; 99 ImageFlipRenderThread(Resources resources, SurfaceTexture surface)100 public ImageFlipRenderThread(Resources resources, SurfaceTexture surface) { 101 mResources = resources; 102 mSurface = surface; 103 } 104 105 private static final String sSimpleVS = 106 "attribute vec4 position;\n" + 107 "attribute vec2 texCoords;\n" + 108 "varying vec2 outTexCoords;\n" + 109 "\nvoid main(void) {\n" + 110 " outTexCoords = texCoords;\n" + 111 " gl_Position = position;\n" + 112 "}\n\n"; 113 private static final String sSimpleFS = 114 "precision mediump float;\n\n" + 115 "varying vec2 outTexCoords;\n" + 116 "uniform sampler2D texture;\n" + 117 "\nvoid main(void) {\n" + 118 " gl_FragColor = texture2D(texture, outTexCoords);\n" + 119 "}\n\n"; 120 121 private static final int FLOAT_SIZE_BYTES = 4; 122 private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; 123 private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0; 124 private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3; 125 private final float[] mTriangleVerticesData = { 126 // X, Y, Z, U, V 127 -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 128 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 129 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 130 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 131 }; 132 133 @Override run()134 public void run() { 135 initGL(); 136 137 FloatBuffer triangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length 138 * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer(); 139 triangleVertices.put(mTriangleVerticesData).position(0); 140 141 int texture = loadTexture(R.drawable.large_photo); 142 int program = buildProgram(sSimpleVS, sSimpleFS); 143 144 int attribPosition = glGetAttribLocation(program, "position"); 145 checkGlError(); 146 147 int attribTexCoords = glGetAttribLocation(program, "texCoords"); 148 checkGlError(); 149 150 int uniformTexture = glGetUniformLocation(program, "texture"); 151 checkGlError(); 152 153 glBindTexture(GL_TEXTURE_2D, texture); 154 checkGlError(); 155 156 glUseProgram(program); 157 checkGlError(); 158 159 glEnableVertexAttribArray(attribPosition); 160 checkGlError(); 161 162 glEnableVertexAttribArray(attribTexCoords); 163 checkGlError(); 164 165 glUniform1i(uniformTexture, 0); 166 checkGlError(); 167 168 // drawQuad 169 triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET); 170 glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false, 171 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices); 172 checkGlError(); 173 174 triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET); 175 glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false, 176 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices); 177 checkGlError(); 178 179 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 180 checkGlError(); 181 182 while (!mFinished) { 183 checkCurrent(); 184 185 glClear(GL_COLOR_BUFFER_BIT); 186 checkGlError(); 187 188 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 189 checkGlError(); 190 191 if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) { 192 throw new RuntimeException("Cannot swap buffers"); 193 } 194 checkEglError(); 195 196 try { 197 Thread.sleep(2000); 198 } catch (InterruptedException e) { 199 // Ignore 200 } 201 } 202 203 finishGL(); 204 } 205 loadTexture(int resource)206 private int loadTexture(int resource) { 207 int[] textures = new int[1]; 208 209 glActiveTexture(GL_TEXTURE0); 210 glGenTextures(1, textures, 0); 211 checkGlError(); 212 213 int texture = textures[0]; 214 glBindTexture(GL_TEXTURE_2D, texture); 215 checkGlError(); 216 217 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 218 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 219 220 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 221 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 222 223 Bitmap bitmap = BitmapFactory.decodeResource(mResources, resource); 224 225 GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0); 226 checkGlError(); 227 228 bitmap.recycle(); 229 230 return texture; 231 } 232 buildProgram(String vertex, String fragment)233 private static int buildProgram(String vertex, String fragment) { 234 int vertexShader = buildShader(vertex, GL_VERTEX_SHADER); 235 if (vertexShader == 0) return 0; 236 237 int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); 238 if (fragmentShader == 0) return 0; 239 240 int program = glCreateProgram(); 241 glAttachShader(program, vertexShader); 242 checkGlError(); 243 244 glAttachShader(program, fragmentShader); 245 checkGlError(); 246 247 glLinkProgram(program); 248 checkGlError(); 249 250 int[] status = new int[1]; 251 glGetProgramiv(program, GL_LINK_STATUS, status, 0); 252 if (status[0] != GL_TRUE) { 253 String error = glGetProgramInfoLog(program); 254 Log.d(LOG_TAG, "Error while linking program:\n" + error); 255 glDeleteShader(vertexShader); 256 glDeleteShader(fragmentShader); 257 glDeleteProgram(program); 258 return 0; 259 } 260 261 return program; 262 } 263 buildShader(String source, int type)264 private static int buildShader(String source, int type) { 265 int shader = glCreateShader(type); 266 267 glShaderSource(shader, source); 268 checkGlError(); 269 270 glCompileShader(shader); 271 checkGlError(); 272 273 int[] status = new int[1]; 274 glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0); 275 if (status[0] != GL_TRUE) { 276 String error = glGetShaderInfoLog(shader); 277 Log.d(LOG_TAG, "Error while compiling shader:\n" + error); 278 glDeleteShader(shader); 279 return 0; 280 } 281 282 return shader; 283 } 284 checkEglError()285 private void checkEglError() { 286 int error = mEgl.eglGetError(); 287 if (error != EGL10.EGL_SUCCESS) { 288 Log.w(LOG_TAG, "EGL error = 0x" + Integer.toHexString(error)); 289 } 290 } 291 checkGlError()292 private static void checkGlError() { 293 int error = glGetError(); 294 if (error != GL_NO_ERROR) { 295 Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error)); 296 } 297 } 298 finishGL()299 private void finishGL() { 300 mEgl.eglDestroyContext(mEglDisplay, mEglContext); 301 mEgl.eglDestroySurface(mEglDisplay, mEglSurface); 302 } 303 checkCurrent()304 private void checkCurrent() { 305 if (!mEglContext.equals(mEgl.eglGetCurrentContext()) || 306 !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) { 307 if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 308 throw new RuntimeException("eglMakeCurrent failed " 309 + GLUtils.getEGLErrorString(mEgl.eglGetError())); 310 } 311 } 312 } 313 initGL()314 private void initGL() { 315 mEgl = (EGL10) EGLContext.getEGL(); 316 317 mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 318 if (mEglDisplay == EGL10.EGL_NO_DISPLAY) { 319 throw new RuntimeException("eglGetDisplay failed " 320 + GLUtils.getEGLErrorString(mEgl.eglGetError())); 321 } 322 323 int[] version = new int[2]; 324 if (!mEgl.eglInitialize(mEglDisplay, version)) { 325 throw new RuntimeException("eglInitialize failed " + 326 GLUtils.getEGLErrorString(mEgl.eglGetError())); 327 } 328 329 mEglConfig = chooseEglConfig(); 330 if (mEglConfig == null) { 331 throw new RuntimeException("eglConfig not initialized"); 332 } 333 334 mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); 335 336 mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, null); 337 338 if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) { 339 int error = mEgl.eglGetError(); 340 if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { 341 Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); 342 return; 343 } 344 throw new RuntimeException("createWindowSurface failed " 345 + GLUtils.getEGLErrorString(error)); 346 } 347 348 if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 349 throw new RuntimeException("eglMakeCurrent failed " 350 + GLUtils.getEGLErrorString(mEgl.eglGetError())); 351 } 352 } 353 354 createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig)355 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { 356 int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE}; 357 return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); 358 } 359 chooseEglConfig()360 private EGLConfig chooseEglConfig() { 361 int[] configsCount = new int[1]; 362 EGLConfig[] configs = new EGLConfig[1]; 363 int[] configSpec = getConfig(); 364 if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) { 365 throw new IllegalArgumentException("eglChooseConfig failed " + 366 GLUtils.getEGLErrorString(mEgl.eglGetError())); 367 } else if (configsCount[0] > 0) { 368 return configs[0]; 369 } 370 return null; 371 } 372 getConfig()373 private static int[] getConfig() { 374 return new int[]{ 375 EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 376 EGL10.EGL_RED_SIZE, 8, 377 EGL10.EGL_GREEN_SIZE, 8, 378 EGL10.EGL_BLUE_SIZE, 8, 379 EGL10.EGL_ALPHA_SIZE, 8, 380 EGL10.EGL_DEPTH_SIZE, 0, 381 EGL10.EGL_STENCIL_SIZE, 0, 382 EGL10.EGL_NONE 383 }; 384 } 385 finish()386 public void finish() { 387 mFinished = true; 388 } 389 } 390