• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.camera.panorama;
18 
19 import android.content.Context;
20 import android.graphics.PixelFormat;
21 import android.opengl.GLSurfaceView;
22 import android.os.ConditionVariable;
23 import android.util.AttributeSet;
24 import android.util.Log;
25 
26 import javax.microedition.khronos.egl.EGL10;
27 import javax.microedition.khronos.egl.EGLConfig;
28 import javax.microedition.khronos.egl.EGLContext;
29 import javax.microedition.khronos.egl.EGLDisplay;
30 
31 public class MosaicRendererSurfaceView extends GLSurfaceView {
32     private static final String TAG = "MosaicRendererSurfaceView";
33     private static final boolean DEBUG = false;
34     private MosaicRendererSurfaceViewRenderer mRenderer;
35     private ConditionVariable mPreviewFrameReadyForProcessing;
36 
MosaicRendererSurfaceView(Context context)37     public MosaicRendererSurfaceView(Context context) {
38         super(context);
39         init(false, 0, 0);
40         setZOrderMediaOverlay(true);
41     }
42 
MosaicRendererSurfaceView(Context context, AttributeSet attrs)43     public MosaicRendererSurfaceView(Context context, AttributeSet attrs) {
44         super(context, attrs);
45         init(false, 0, 0);
46         setZOrderMediaOverlay(true);
47     }
48 
MosaicRendererSurfaceView(Context context, boolean translucent, int depth, int stencil)49     public MosaicRendererSurfaceView(Context context, boolean translucent, int depth, int stencil) {
50         super(context);
51         init(translucent, depth, stencil);
52         setZOrderMediaOverlay(true);
53     }
54 
init(boolean translucent, int depth, int stencil)55     private void init(boolean translucent, int depth, int stencil) {
56 
57         /* By default, GLSurfaceView() creates a RGB_565 opaque surface.
58          * If we want a translucent one, we should change the surface's
59          * format here, using PixelFormat.TRANSLUCENT for GL Surfaces
60          * is interpreted as any 32-bit surface with alpha by SurfaceFlinger.
61          */
62         if (translucent) {
63             this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
64         }
65 
66         /* Setup the context factory for 2.0 rendering.
67          * See ContextFactory class definition below
68          */
69         setEGLContextFactory(new ContextFactory());
70 
71         /* We need to choose an EGLConfig that matches the format of
72          * our surface exactly. This is going to be done in our
73          * custom config chooser. See ConfigChooser class definition
74          * below.
75          */
76         setEGLConfigChooser(
77             translucent ? new ConfigChooser(8, 8, 8, 8, depth, stencil) :
78             new ConfigChooser(5, 6, 5, 0, depth, stencil));
79 
80         /* Set the renderer responsible for frame rendering */
81         mRenderer = new MosaicRendererSurfaceViewRenderer();
82         setRenderer(mRenderer);
83         setRenderMode(RENDERMODE_WHEN_DIRTY);
84         mPreviewFrameReadyForProcessing = new ConditionVariable();
85     }
86 
87     private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
88         private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig)89         public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
90             Log.w(TAG, "creating OpenGL ES 2.0 context");
91             checkEglError("Before eglCreateContext", egl);
92             int[] attribList = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
93             EGLContext context = egl.eglCreateContext(
94                 display, eglConfig, EGL10.EGL_NO_CONTEXT, attribList);
95             checkEglError("After eglCreateContext", egl);
96             return context;
97         }
98 
destroyContext(EGL10 egl, EGLDisplay display, EGLContext context)99         public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
100             egl.eglDestroyContext(display, context);
101         }
102     }
103 
checkEglError(String prompt, EGL10 egl)104     private static void checkEglError(String prompt, EGL10 egl) {
105         int error;
106         while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {
107             Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
108         }
109     }
110 
111     private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {
112 
ConfigChooser(int r, int g, int b, int a, int depth, int stencil)113         public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {
114             mRedSize = r;
115             mGreenSize = g;
116             mBlueSize = b;
117             mAlphaSize = a;
118             mDepthSize = depth;
119             mStencilSize = stencil;
120         }
121 
122         /* This EGL config specification is used to specify 2.0 rendering.
123          * We use a minimum size of 4 bits for red/green/blue, but will
124          * perform actual matching in chooseConfig() below.
125          */
126         private static final int EGL_OPENGL_ES2_BIT = 4;
127         private static final int[] CONFIG_ATTRIBUTES =
128         {
129             EGL10.EGL_RED_SIZE, 4,
130             EGL10.EGL_GREEN_SIZE, 4,
131             EGL10.EGL_BLUE_SIZE, 4,
132             EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
133             EGL10.EGL_NONE
134         };
135 
chooseConfig(EGL10 egl, EGLDisplay display)136         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
137 
138             /* Get the number of minimally matching EGL configurations
139              */
140             int[] numConfig = new int[1];
141             egl.eglChooseConfig(display, CONFIG_ATTRIBUTES, null, 0, numConfig);
142 
143             int numConfigs = numConfig[0];
144 
145             if (numConfigs <= 0) {
146                 throw new IllegalArgumentException("No configs match configSpec");
147             }
148 
149             /* Allocate then read the array of minimally matching EGL configs
150              */
151             EGLConfig[] configs = new EGLConfig[numConfigs];
152             egl.eglChooseConfig(display, CONFIG_ATTRIBUTES, configs, numConfigs, numConfig);
153 
154             if (DEBUG) {
155                  printConfigs(egl, display, configs);
156             }
157             /* Now return the "best" one
158              */
159             return chooseConfig(egl, display, configs);
160         }
161 
chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs)162         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
163                 EGLConfig[] configs) {
164             for (EGLConfig config : configs) {
165                 int d = findConfigAttrib(egl, display, config,
166                         EGL10.EGL_DEPTH_SIZE, 0);
167                 int s = findConfigAttrib(egl, display, config,
168                         EGL10.EGL_STENCIL_SIZE, 0);
169 
170                 // We need at least mDepthSize and mStencilSize bits
171                 if (d < mDepthSize || s < mStencilSize)
172                     continue;
173 
174                 // We want an *exact* match for red/green/blue/alpha
175                 int r = findConfigAttrib(egl, display, config,
176                         EGL10.EGL_RED_SIZE, 0);
177                 int g = findConfigAttrib(egl, display, config,
178                             EGL10.EGL_GREEN_SIZE, 0);
179                 int b = findConfigAttrib(egl, display, config,
180                             EGL10.EGL_BLUE_SIZE, 0);
181                 int a = findConfigAttrib(egl, display, config,
182                         EGL10.EGL_ALPHA_SIZE, 0);
183 
184                 if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize)
185                     return config;
186             }
187             return null;
188         }
189 
findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue)190         private int findConfigAttrib(EGL10 egl, EGLDisplay display,
191                 EGLConfig config, int attribute, int defaultValue) {
192 
193             if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
194                 return mValue[0];
195             }
196             return defaultValue;
197         }
198 
printConfigs(EGL10 egl, EGLDisplay display, EGLConfig[] configs)199         private void printConfigs(EGL10 egl, EGLDisplay display,
200             EGLConfig[] configs) {
201             int numConfigs = configs.length;
202             Log.w(TAG, String.format("%d configurations", numConfigs));
203             for (int i = 0; i < numConfigs; i++) {
204                 Log.w(TAG, String.format("Configuration %d:\n", i));
205                 printConfig(egl, display, configs[i]);
206             }
207         }
208 
printConfig(EGL10 egl, EGLDisplay display, EGLConfig config)209         private void printConfig(EGL10 egl, EGLDisplay display,
210                 EGLConfig config) {
211             int[] attributes = {
212                     EGL10.EGL_BUFFER_SIZE,
213                     EGL10.EGL_ALPHA_SIZE,
214                     EGL10.EGL_BLUE_SIZE,
215                     EGL10.EGL_GREEN_SIZE,
216                     EGL10.EGL_RED_SIZE,
217                     EGL10.EGL_DEPTH_SIZE,
218                     EGL10.EGL_STENCIL_SIZE,
219                     EGL10.EGL_CONFIG_CAVEAT,
220                     EGL10.EGL_CONFIG_ID,
221                     EGL10.EGL_LEVEL,
222                     EGL10.EGL_MAX_PBUFFER_HEIGHT,
223                     EGL10.EGL_MAX_PBUFFER_PIXELS,
224                     EGL10.EGL_MAX_PBUFFER_WIDTH,
225                     EGL10.EGL_NATIVE_RENDERABLE,
226                     EGL10.EGL_NATIVE_VISUAL_ID,
227                     EGL10.EGL_NATIVE_VISUAL_TYPE,
228                     0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
229                     EGL10.EGL_SAMPLES,
230                     EGL10.EGL_SAMPLE_BUFFERS,
231                     EGL10.EGL_SURFACE_TYPE,
232                     EGL10.EGL_TRANSPARENT_TYPE,
233                     EGL10.EGL_TRANSPARENT_RED_VALUE,
234                     EGL10.EGL_TRANSPARENT_GREEN_VALUE,
235                     EGL10.EGL_TRANSPARENT_BLUE_VALUE,
236                     0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
237                     0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
238                     0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
239                     0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
240                     EGL10.EGL_LUMINANCE_SIZE,
241                     EGL10.EGL_ALPHA_MASK_SIZE,
242                     EGL10.EGL_COLOR_BUFFER_TYPE,
243                     EGL10.EGL_RENDERABLE_TYPE,
244                     0x3042 // EGL10.EGL_CONFORMANT
245             };
246             String[] names = {
247                     "EGL_BUFFER_SIZE",
248                     "EGL_ALPHA_SIZE",
249                     "EGL_BLUE_SIZE",
250                     "EGL_GREEN_SIZE",
251                     "EGL_RED_SIZE",
252                     "EGL_DEPTH_SIZE",
253                     "EGL_STENCIL_SIZE",
254                     "EGL_CONFIG_CAVEAT",
255                     "EGL_CONFIG_ID",
256                     "EGL_LEVEL",
257                     "EGL_MAX_PBUFFER_HEIGHT",
258                     "EGL_MAX_PBUFFER_PIXELS",
259                     "EGL_MAX_PBUFFER_WIDTH",
260                     "EGL_NATIVE_RENDERABLE",
261                     "EGL_NATIVE_VISUAL_ID",
262                     "EGL_NATIVE_VISUAL_TYPE",
263                     "EGL_PRESERVED_RESOURCES",
264                     "EGL_SAMPLES",
265                     "EGL_SAMPLE_BUFFERS",
266                     "EGL_SURFACE_TYPE",
267                     "EGL_TRANSPARENT_TYPE",
268                     "EGL_TRANSPARENT_RED_VALUE",
269                     "EGL_TRANSPARENT_GREEN_VALUE",
270                     "EGL_TRANSPARENT_BLUE_VALUE",
271                     "EGL_BIND_TO_TEXTURE_RGB",
272                     "EGL_BIND_TO_TEXTURE_RGBA",
273                     "EGL_MIN_SWAP_INTERVAL",
274                     "EGL_MAX_SWAP_INTERVAL",
275                     "EGL_LUMINANCE_SIZE",
276                     "EGL_ALPHA_MASK_SIZE",
277                     "EGL_COLOR_BUFFER_TYPE",
278                     "EGL_RENDERABLE_TYPE",
279                     "EGL_CONFORMANT"
280             };
281             int[] value = new int[1];
282             for (int i = 0; i < attributes.length; i++) {
283                 int attribute = attributes[i];
284                 String name = names[i];
285                 if (egl.eglGetConfigAttrib(display, config, attribute, value)) {
286                     Log.w(TAG, String.format("  %s: %d\n", name, value[0]));
287                 } else {
288                     // Log.w(TAG, String.format("  %s: failed\n", name));
289                     while (egl.eglGetError() != EGL10.EGL_SUCCESS);
290                 }
291             }
292         }
293 
294         // Subclasses can adjust these values:
295         protected int mRedSize;
296         protected int mGreenSize;
297         protected int mBlueSize;
298         protected int mAlphaSize;
299         protected int mDepthSize;
300         protected int mStencilSize;
301         private int[] mValue = new int[1];
302     }
303 
lockPreviewReadyFlag()304     public void lockPreviewReadyFlag() {
305         mPreviewFrameReadyForProcessing.close();
306     }
307 
unlockPreviewReadyFlag()308     private void unlockPreviewReadyFlag() {
309         mPreviewFrameReadyForProcessing.open();
310     }
311 
waitUntilPreviewReady()312     public void waitUntilPreviewReady() {
313         mPreviewFrameReadyForProcessing.block();
314     }
315 
setReady()316     public void setReady() {
317         queueEvent(new Runnable() {
318 
319             @Override
320             public void run() {
321                 mRenderer.setReady();
322             }
323         });
324     }
325 
preprocess(final float[] transformMatrix)326     public void preprocess(final float[] transformMatrix) {
327         queueEvent(new Runnable() {
328 
329             @Override
330             public void run() {
331                 mRenderer.preprocess(transformMatrix);
332             }
333         });
334     }
335 
transferGPUtoCPU()336     public void transferGPUtoCPU() {
337         queueEvent(new Runnable() {
338 
339             @Override
340             public void run() {
341                 mRenderer.transferGPUtoCPU();
342                 unlockPreviewReadyFlag();
343             }
344         });
345     }
346 
setWarping(final boolean flag)347     public void setWarping(final boolean flag) {
348         queueEvent(new Runnable() {
349 
350             @Override
351             public void run() {
352                 mRenderer.setWarping(flag);
353             }
354         });
355     }
356 
getRenderer()357     public MosaicRendererSurfaceViewRenderer getRenderer() {
358         return mRenderer;
359     }
360 
361 }
362