1 /* 2 * Copyright (C) 2009 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 com.android.gl2jni; 18 /* 19 * Copyright (C) 2008 The Android Open Source Project 20 * 21 * Licensed under the Apache License, Version 2.0 (the "License"); 22 * you may not use this file except in compliance with the License. 23 * You may obtain a copy of the License at 24 * 25 * http://www.apache.org/licenses/LICENSE-2.0 26 * 27 * Unless required by applicable law or agreed to in writing, software 28 * distributed under the License is distributed on an "AS IS" BASIS, 29 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 30 * See the License for the specific language governing permissions and 31 * limitations under the License. 32 */ 33 34 35 import android.content.Context; 36 import android.graphics.PixelFormat; 37 import android.opengl.GLSurfaceView; 38 import android.util.AttributeSet; 39 import android.util.Log; 40 import android.view.KeyEvent; 41 import android.view.MotionEvent; 42 43 import javax.microedition.khronos.egl.EGL10; 44 import javax.microedition.khronos.egl.EGLConfig; 45 import javax.microedition.khronos.egl.EGLContext; 46 import javax.microedition.khronos.egl.EGLDisplay; 47 import javax.microedition.khronos.opengles.GL10; 48 49 /** 50 * A simple GLSurfaceView sub-class that demonstrate how to perform 51 * OpenGL ES 2.0 rendering into a GL Surface. Note the following important 52 * details: 53 * 54 * - The class must use a custom context factory to enable 2.0 rendering. 55 * See ContextFactory class definition below. 56 * 57 * - The class must use a custom EGLConfigChooser to be able to select 58 * an EGLConfig that supports 2.0. This is done by providing a config 59 * specification to eglChooseConfig() that has the attribute 60 * EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag 61 * set. See ConfigChooser class definition below. 62 * 63 * - The class must select the surface's format, then choose an EGLConfig 64 * that matches it exactly (with regards to red/green/blue/alpha channels 65 * bit depths). Failure to do so would result in an EGL_BAD_MATCH error. 66 */ 67 class GL2JNIView extends GLSurfaceView { 68 private static String TAG = "GL2JNIView"; 69 private static final boolean DEBUG = false; 70 GL2JNIView(Context context)71 public GL2JNIView(Context context) { 72 super(context); 73 init(false, 0, 0); 74 } 75 GL2JNIView(Context context, boolean translucent, int depth, int stencil)76 public GL2JNIView(Context context, boolean translucent, int depth, int stencil) { 77 super(context); 78 init(translucent, depth, stencil); 79 } 80 init(boolean translucent, int depth, int stencil)81 private void init(boolean translucent, int depth, int stencil) { 82 83 /* By default, GLSurfaceView() creates a RGB_565 opaque surface. 84 * If we want a translucent one, we should change the surface's 85 * format here, using PixelFormat.TRANSLUCENT for GL Surfaces 86 * is interpreted as any 32-bit surface with alpha by SurfaceFlinger. 87 */ 88 if (translucent) { 89 this.getHolder().setFormat(PixelFormat.TRANSLUCENT); 90 } 91 92 /* Setup the context factory for 2.0 rendering. 93 * See ContextFactory class definition below 94 */ 95 setEGLContextFactory(new ContextFactory()); 96 97 /* We need to choose an EGLConfig that matches the format of 98 * our surface exactly. This is going to be done in our 99 * custom config chooser. See ConfigChooser class definition 100 * below. 101 */ 102 setEGLConfigChooser( translucent ? 103 new ConfigChooser(8, 8, 8, 8, depth, stencil) : 104 new ConfigChooser(5, 6, 5, 0, depth, stencil) ); 105 106 /* Set the renderer responsible for frame rendering */ 107 setRenderer(new Renderer()); 108 } 109 110 private static class ContextFactory implements GLSurfaceView.EGLContextFactory { 111 private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig)112 public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { 113 Log.w(TAG, "creating OpenGL ES 2.0 context"); 114 checkEglError("Before eglCreateContext", egl); 115 int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; 116 EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); 117 checkEglError("After eglCreateContext", egl); 118 return context; 119 } 120 destroyContext(EGL10 egl, EGLDisplay display, EGLContext context)121 public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { 122 egl.eglDestroyContext(display, context); 123 } 124 } 125 checkEglError(String prompt, EGL10 egl)126 private static void checkEglError(String prompt, EGL10 egl) { 127 int error; 128 while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { 129 Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error)); 130 } 131 } 132 133 private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { 134 ConfigChooser(int r, int g, int b, int a, int depth, int stencil)135 public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) { 136 mRedSize = r; 137 mGreenSize = g; 138 mBlueSize = b; 139 mAlphaSize = a; 140 mDepthSize = depth; 141 mStencilSize = stencil; 142 } 143 144 /* This EGL config specification is used to specify 2.0 rendering. 145 * We use a minimum size of 4 bits for red/green/blue, but will 146 * perform actual matching in chooseConfig() below. 147 */ 148 private static int EGL_OPENGL_ES2_BIT = 4; 149 private static int[] s_configAttribs2 = 150 { 151 EGL10.EGL_RED_SIZE, 4, 152 EGL10.EGL_GREEN_SIZE, 4, 153 EGL10.EGL_BLUE_SIZE, 4, 154 EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 155 EGL10.EGL_NONE 156 }; 157 chooseConfig(EGL10 egl, EGLDisplay display)158 public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { 159 160 /* Get the number of minimally matching EGL configurations 161 */ 162 int[] num_config = new int[1]; 163 egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config); 164 165 int numConfigs = num_config[0]; 166 167 if (numConfigs <= 0) { 168 throw new IllegalArgumentException("No configs match configSpec"); 169 } 170 171 /* Allocate then read the array of minimally matching EGL configs 172 */ 173 EGLConfig[] configs = new EGLConfig[numConfigs]; 174 egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config); 175 176 if (DEBUG) { 177 printConfigs(egl, display, configs); 178 } 179 /* Now return the "best" one 180 */ 181 return chooseConfig(egl, display, configs); 182 } 183 chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs)184 public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, 185 EGLConfig[] configs) { 186 for(EGLConfig config : configs) { 187 int d = findConfigAttrib(egl, display, config, 188 EGL10.EGL_DEPTH_SIZE, 0); 189 int s = findConfigAttrib(egl, display, config, 190 EGL10.EGL_STENCIL_SIZE, 0); 191 192 // We need at least mDepthSize and mStencilSize bits 193 if (d < mDepthSize || s < mStencilSize) 194 continue; 195 196 // We want an *exact* match for red/green/blue/alpha 197 int r = findConfigAttrib(egl, display, config, 198 EGL10.EGL_RED_SIZE, 0); 199 int g = findConfigAttrib(egl, display, config, 200 EGL10.EGL_GREEN_SIZE, 0); 201 int b = findConfigAttrib(egl, display, config, 202 EGL10.EGL_BLUE_SIZE, 0); 203 int a = findConfigAttrib(egl, display, config, 204 EGL10.EGL_ALPHA_SIZE, 0); 205 206 if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize) 207 return config; 208 } 209 return null; 210 } 211 findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue)212 private int findConfigAttrib(EGL10 egl, EGLDisplay display, 213 EGLConfig config, int attribute, int defaultValue) { 214 215 if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { 216 return mValue[0]; 217 } 218 return defaultValue; 219 } 220 printConfigs(EGL10 egl, EGLDisplay display, EGLConfig[] configs)221 private void printConfigs(EGL10 egl, EGLDisplay display, 222 EGLConfig[] configs) { 223 int numConfigs = configs.length; 224 Log.w(TAG, String.format("%d configurations", numConfigs)); 225 for (int i = 0; i < numConfigs; i++) { 226 Log.w(TAG, String.format("Configuration %d:\n", i)); 227 printConfig(egl, display, configs[i]); 228 } 229 } 230 printConfig(EGL10 egl, EGLDisplay display, EGLConfig config)231 private void printConfig(EGL10 egl, EGLDisplay display, 232 EGLConfig config) { 233 int[] attributes = { 234 EGL10.EGL_BUFFER_SIZE, 235 EGL10.EGL_ALPHA_SIZE, 236 EGL10.EGL_BLUE_SIZE, 237 EGL10.EGL_GREEN_SIZE, 238 EGL10.EGL_RED_SIZE, 239 EGL10.EGL_DEPTH_SIZE, 240 EGL10.EGL_STENCIL_SIZE, 241 EGL10.EGL_CONFIG_CAVEAT, 242 EGL10.EGL_CONFIG_ID, 243 EGL10.EGL_LEVEL, 244 EGL10.EGL_MAX_PBUFFER_HEIGHT, 245 EGL10.EGL_MAX_PBUFFER_PIXELS, 246 EGL10.EGL_MAX_PBUFFER_WIDTH, 247 EGL10.EGL_NATIVE_RENDERABLE, 248 EGL10.EGL_NATIVE_VISUAL_ID, 249 EGL10.EGL_NATIVE_VISUAL_TYPE, 250 0x3030, // EGL10.EGL_PRESERVED_RESOURCES, 251 EGL10.EGL_SAMPLES, 252 EGL10.EGL_SAMPLE_BUFFERS, 253 EGL10.EGL_SURFACE_TYPE, 254 EGL10.EGL_TRANSPARENT_TYPE, 255 EGL10.EGL_TRANSPARENT_RED_VALUE, 256 EGL10.EGL_TRANSPARENT_GREEN_VALUE, 257 EGL10.EGL_TRANSPARENT_BLUE_VALUE, 258 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, 259 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, 260 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, 261 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, 262 EGL10.EGL_LUMINANCE_SIZE, 263 EGL10.EGL_ALPHA_MASK_SIZE, 264 EGL10.EGL_COLOR_BUFFER_TYPE, 265 EGL10.EGL_RENDERABLE_TYPE, 266 0x3042 // EGL10.EGL_CONFORMANT 267 }; 268 String[] names = { 269 "EGL_BUFFER_SIZE", 270 "EGL_ALPHA_SIZE", 271 "EGL_BLUE_SIZE", 272 "EGL_GREEN_SIZE", 273 "EGL_RED_SIZE", 274 "EGL_DEPTH_SIZE", 275 "EGL_STENCIL_SIZE", 276 "EGL_CONFIG_CAVEAT", 277 "EGL_CONFIG_ID", 278 "EGL_LEVEL", 279 "EGL_MAX_PBUFFER_HEIGHT", 280 "EGL_MAX_PBUFFER_PIXELS", 281 "EGL_MAX_PBUFFER_WIDTH", 282 "EGL_NATIVE_RENDERABLE", 283 "EGL_NATIVE_VISUAL_ID", 284 "EGL_NATIVE_VISUAL_TYPE", 285 "EGL_PRESERVED_RESOURCES", 286 "EGL_SAMPLES", 287 "EGL_SAMPLE_BUFFERS", 288 "EGL_SURFACE_TYPE", 289 "EGL_TRANSPARENT_TYPE", 290 "EGL_TRANSPARENT_RED_VALUE", 291 "EGL_TRANSPARENT_GREEN_VALUE", 292 "EGL_TRANSPARENT_BLUE_VALUE", 293 "EGL_BIND_TO_TEXTURE_RGB", 294 "EGL_BIND_TO_TEXTURE_RGBA", 295 "EGL_MIN_SWAP_INTERVAL", 296 "EGL_MAX_SWAP_INTERVAL", 297 "EGL_LUMINANCE_SIZE", 298 "EGL_ALPHA_MASK_SIZE", 299 "EGL_COLOR_BUFFER_TYPE", 300 "EGL_RENDERABLE_TYPE", 301 "EGL_CONFORMANT" 302 }; 303 int[] value = new int[1]; 304 for (int i = 0; i < attributes.length; i++) { 305 int attribute = attributes[i]; 306 String name = names[i]; 307 if ( egl.eglGetConfigAttrib(display, config, attribute, value)) { 308 Log.w(TAG, String.format(" %s: %d\n", name, value[0])); 309 } else { 310 // Log.w(TAG, String.format(" %s: failed\n", name)); 311 while (egl.eglGetError() != EGL10.EGL_SUCCESS); 312 } 313 } 314 } 315 316 // Subclasses can adjust these values: 317 protected int mRedSize; 318 protected int mGreenSize; 319 protected int mBlueSize; 320 protected int mAlphaSize; 321 protected int mDepthSize; 322 protected int mStencilSize; 323 private int[] mValue = new int[1]; 324 } 325 326 private static class Renderer implements GLSurfaceView.Renderer { onDrawFrame(GL10 gl)327 public void onDrawFrame(GL10 gl) { 328 GL2JNILib.step(); 329 } 330 onSurfaceChanged(GL10 gl, int width, int height)331 public void onSurfaceChanged(GL10 gl, int width, int height) { 332 GL2JNILib.init(width, height); 333 } 334 onSurfaceCreated(GL10 gl, EGLConfig config)335 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 336 // Do nothing. 337 } 338 } 339 } 340