1 /* 2 * Copyright (C) 2011 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 17 package android.opengl.cts; 18 19 import android.content.Context; 20 import android.opengl.GLES20; 21 import android.opengl.GLSurfaceView; 22 import android.util.Log; 23 24 import java.nio.ByteBuffer; 25 import java.nio.ByteOrder; 26 import java.nio.FloatBuffer; 27 28 import javax.microedition.khronos.egl.EGL10; 29 import javax.microedition.khronos.egl.EGLConfig; 30 import javax.microedition.khronos.egl.EGLDisplay; 31 import javax.microedition.khronos.opengles.GL10; 32 33 /** 34 * {@link GLSurfaceView} that uses the EGL configuration specified. Draws a couple frames of a red 35 * triangle and then calls the callback. 36 */ 37 public class EglConfigGLSurfaceView extends GLSurfaceView { 38 39 private static final String TAG = EglConfigGLSurfaceView.class.getName(); 40 41 private final int mConfigId; 42 43 private final Runnable mCallback; 44 45 public EglConfigGLSurfaceView(Context context, int configId, int contextClientVersion, 46 Runnable callback) { 47 super(context); 48 mConfigId = configId; 49 mCallback = callback; 50 setEGLConfigChooser(new ConfigChooser()); 51 setEGLContextClientVersion(contextClientVersion); 52 setRenderer(contextClientVersion == 1 53 ? new Renderer() 54 : new Renderer20()); 55 } 56 57 private class ConfigChooser implements GLSurfaceView.EGLConfigChooser { 58 59 public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { 60 int[] attributeList = new int[] { 61 EGL10.EGL_CONFIG_ID, mConfigId, 62 EGL10.EGL_NONE 63 }; 64 65 EGLConfig[] configs = new EGLConfig[1]; 66 if (egl.eglChooseConfig(display, attributeList, configs, 1, new int[] {1})) { 67 // Print out the configuration since we may crash... 68 printConfig(egl, display, configs[0]); 69 return configs[0]; 70 } else { 71 throw new IllegalStateException("Could not get EGL config..."); 72 } 73 } 74 } 75 76 private class Renderer implements GLSurfaceView.Renderer { 77 78 private int mNumFrames; 79 80 private FloatBuffer mFloatBuffer; 81 82 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 83 float[] triangleVertices = { 84 0.0f, 1.0f, -1.0f, 85 -1.0f, -1.0f, -1.0f, 86 1.0f, -1.0f, -1.0f 87 }; 88 89 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(triangleVertices.length * 4); 90 byteBuffer.order(ByteOrder.nativeOrder()); 91 92 mFloatBuffer = ByteBuffer.allocateDirect(triangleVertices.length * 4) 93 .order(ByteOrder.nativeOrder()) 94 .asFloatBuffer(); 95 mFloatBuffer.put(triangleVertices).position(0); 96 97 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 98 } 99 100 public void onDrawFrame(GL10 gl) { 101 gl.glClear(GL10.GL_COLOR_BUFFER_BIT); 102 gl.glColor4f(1.0f, 0, 0, 0); 103 gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFloatBuffer); 104 gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3); 105 106 if (++mNumFrames == 10) { 107 post(mCallback); 108 } 109 } 110 111 public void onSurfaceChanged(GL10 gl, int width, int height) { 112 gl.glViewport(0, 0, width, height); 113 } 114 } 115 116 private class Renderer20 implements GLSurfaceView.Renderer { 117 118 private FloatBuffer mFloatBuffer; 119 120 private final String mVertexShader = 121 "attribute vec4 aPosition;\n" + 122 "void main() {\n" + 123 " gl_Position = aPosition;\n" + 124 "}\n"; 125 126 private final String mFragmentShader = 127 "void main() {\n" + 128 " gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n" + 129 "}\n"; 130 131 private int mProgram; 132 133 private int maPositionHandle; 134 135 private int mNumFrames; 136 137 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 138 mProgram = createProgram(mVertexShader, mFragmentShader); 139 if (mProgram == 0) { 140 throw new RuntimeException("Could not create program"); 141 } 142 143 maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition"); 144 checkGlError("glGetAttribLocation aPosition"); 145 if (maPositionHandle == -1) { 146 throw new RuntimeException("Could not get attrib location for aPosition"); 147 } 148 149 float[] triangleVertices = { 150 0.0f, 1.0f, 0.0f, 151 -1.0f, -1.0f, 0.0f, 152 1.0f, -1.0f, 0.0f 153 }; 154 155 mFloatBuffer = ByteBuffer.allocateDirect(triangleVertices.length * 4) 156 .order(ByteOrder.nativeOrder()) 157 .asFloatBuffer(); 158 mFloatBuffer.put(triangleVertices).position(0); 159 } 160 161 private int createProgram(String vertexSource, String fragmentSource) { 162 int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); 163 if (vertexShader == 0) { 164 return 0; 165 } 166 167 int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); 168 if (pixelShader == 0) { 169 return 0; 170 } 171 172 int program = GLES20.glCreateProgram(); 173 if (program != 0) { 174 GLES20.glAttachShader(program, vertexShader); 175 checkGlError("glAttachShader"); 176 GLES20.glAttachShader(program, pixelShader); 177 checkGlError("glAttachShader"); 178 GLES20.glLinkProgram(program); 179 int[] linkStatus = new int[1]; 180 GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); 181 if (linkStatus[0] != GLES20.GL_TRUE) { 182 Log.e(TAG, "Could not link program: "); 183 Log.e(TAG, GLES20.glGetProgramInfoLog(program)); 184 GLES20.glDeleteProgram(program); 185 program = 0; 186 } 187 } 188 return program; 189 } 190 191 private int loadShader(int shaderType, String source) { 192 int shader = GLES20.glCreateShader(shaderType); 193 if (shader != 0) { 194 GLES20.glShaderSource(shader, source); 195 GLES20.glCompileShader(shader); 196 int[] compiled = new int[1]; 197 GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); 198 if (compiled[0] == 0) { 199 Log.e(TAG, "Could not compile shader " + shaderType + ":"); 200 Log.e(TAG, GLES20.glGetShaderInfoLog(shader)); 201 GLES20.glDeleteShader(shader); 202 shader = 0; 203 } 204 } 205 return shader; 206 } 207 208 private void checkGlError(String op) { 209 int error; 210 while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 211 Log.e(TAG, op + ": glError " + error); 212 throw new RuntimeException(op + ": glError " + error); 213 } 214 } 215 216 @Override 217 public void onDrawFrame(GL10 gl) { 218 GLES20.glClearColor(0, 0, 0, 1); 219 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 220 GLES20.glUseProgram(mProgram); 221 222 GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 223 0, mFloatBuffer); 224 checkGlError("glVertexAttribPointer maPosition"); 225 226 GLES20.glEnableVertexAttribArray(maPositionHandle); 227 checkGlError("glEnableVertexAttribArray maPositionHandle"); 228 229 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); 230 checkGlError("glDrawArrays"); 231 232 if (++mNumFrames == 10) { 233 post(mCallback); 234 } 235 } 236 237 public void onSurfaceChanged(GL10 gl, int width, int height) { 238 GLES20.glViewport(0, 0, width, height); 239 } 240 } 241 242 /** Ripped from the NDK sample GL2JNIView class. */ 243 private static void printConfig(EGL10 egl, EGLDisplay display, 244 EGLConfig config) { 245 int[] attributes = { 246 EGL10.EGL_BUFFER_SIZE, 247 EGL10.EGL_ALPHA_SIZE, 248 EGL10.EGL_BLUE_SIZE, 249 EGL10.EGL_GREEN_SIZE, 250 EGL10.EGL_RED_SIZE, 251 EGL10.EGL_DEPTH_SIZE, 252 EGL10.EGL_STENCIL_SIZE, 253 EGL10.EGL_CONFIG_CAVEAT, 254 EGL10.EGL_CONFIG_ID, 255 EGL10.EGL_LEVEL, 256 EGL10.EGL_MAX_PBUFFER_HEIGHT, 257 EGL10.EGL_MAX_PBUFFER_PIXELS, 258 EGL10.EGL_MAX_PBUFFER_WIDTH, 259 EGL10.EGL_NATIVE_RENDERABLE, 260 EGL10.EGL_NATIVE_VISUAL_ID, 261 EGL10.EGL_NATIVE_VISUAL_TYPE, 262 0x3030, // EGL10.EGL_PRESERVED_RESOURCES, 263 EGL10.EGL_SAMPLES, 264 EGL10.EGL_SAMPLE_BUFFERS, 265 EGL10.EGL_SURFACE_TYPE, 266 EGL10.EGL_TRANSPARENT_TYPE, 267 EGL10.EGL_TRANSPARENT_RED_VALUE, 268 EGL10.EGL_TRANSPARENT_GREEN_VALUE, 269 EGL10.EGL_TRANSPARENT_BLUE_VALUE, 270 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, 271 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, 272 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, 273 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, 274 EGL10.EGL_LUMINANCE_SIZE, 275 EGL10.EGL_ALPHA_MASK_SIZE, 276 EGL10.EGL_COLOR_BUFFER_TYPE, 277 EGL10.EGL_RENDERABLE_TYPE, 278 0x3042 // EGL10.EGL_CONFORMANT 279 }; 280 String[] names = { 281 "EGL_BUFFER_SIZE", 282 "EGL_ALPHA_SIZE", 283 "EGL_BLUE_SIZE", 284 "EGL_GREEN_SIZE", 285 "EGL_RED_SIZE", 286 "EGL_DEPTH_SIZE", 287 "EGL_STENCIL_SIZE", 288 "EGL_CONFIG_CAVEAT", 289 "EGL_CONFIG_ID", 290 "EGL_LEVEL", 291 "EGL_MAX_PBUFFER_HEIGHT", 292 "EGL_MAX_PBUFFER_PIXELS", 293 "EGL_MAX_PBUFFER_WIDTH", 294 "EGL_NATIVE_RENDERABLE", 295 "EGL_NATIVE_VISUAL_ID", 296 "EGL_NATIVE_VISUAL_TYPE", 297 "EGL_PRESERVED_RESOURCES", 298 "EGL_SAMPLES", 299 "EGL_SAMPLE_BUFFERS", 300 "EGL_SURFACE_TYPE", 301 "EGL_TRANSPARENT_TYPE", 302 "EGL_TRANSPARENT_RED_VALUE", 303 "EGL_TRANSPARENT_GREEN_VALUE", 304 "EGL_TRANSPARENT_BLUE_VALUE", 305 "EGL_BIND_TO_TEXTURE_RGB", 306 "EGL_BIND_TO_TEXTURE_RGBA", 307 "EGL_MIN_SWAP_INTERVAL", 308 "EGL_MAX_SWAP_INTERVAL", 309 "EGL_LUMINANCE_SIZE", 310 "EGL_ALPHA_MASK_SIZE", 311 "EGL_COLOR_BUFFER_TYPE", 312 "EGL_RENDERABLE_TYPE", 313 "EGL_CONFORMANT" 314 }; 315 int[] value = new int[1]; 316 for (int i = 0; i < attributes.length; i++) { 317 int attribute = attributes[i]; 318 String name = names[i]; 319 if (egl.eglGetConfigAttrib(display, config, attribute, value)) { 320 Log.w(TAG, String.format(" %s: %d\n", name, value[0])); 321 } else { 322 // Log.w(TAG, String.format(" %s: failed\n", name)); 323 while (egl.eglGetError() != EGL10.EGL_SUCCESS); 324 } 325 } 326 } 327 } 328