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.khronos.gl2VBO;
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 {
327         long frameCount = 0;
328         long lastFpsTime = 0;
329 
onDrawFrame(GL10 gl)330     	public void onDrawFrame(GL10 gl) {
331     		frameCount++;
332 
333             long delay = System.currentTimeMillis() - lastFpsTime;
334             //If last FPS was calculated more than 1 second ago
335             if (delay > 1000) {
336                 //Calculate FPS
337                 double FPS = ((double)frameCount/(double)delay)*1000.0; //delay is in milliseconds, that's why *1000
338                 frameCount = 0; //Reset frame counter
339                 lastFpsTime = System.currentTimeMillis(); //Reset fps timer
340 
341                 Log.d("FPS", FPS + " FPS");
342             }
343 
344             GL2JNILib.step();
345         }
346 
onSurfaceChanged(GL10 gl, int width, int height)347         public void onSurfaceChanged(GL10 gl, int width, int height) {
348             GL2JNILib.init(width, height);
349             lastFpsTime = System.currentTimeMillis();
350         }
351 
onSurfaceCreated(GL10 gl, EGLConfig config)352         public void onSurfaceCreated(GL10 gl, EGLConfig config) {
353             // Do nothing.
354         }
355     }
356 }
357