Home | History | Annotate | Download | only in panorama
      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 
     37     public MosaicRendererSurfaceView(Context context) {
     38         super(context);
     39         init(false, 0, 0);
     40         setZOrderMediaOverlay(true);
     41     }
     42 
     43     public MosaicRendererSurfaceView(Context context, AttributeSet attrs) {
     44         super(context, attrs);
     45         init(false, 0, 0);
     46         setZOrderMediaOverlay(true);
     47     }
     48 
     49     public MosaicRendererSurfaceView(Context context, boolean translucent, int depth, int stencil) {
     50         super(context);
     51         init(translucent, depth, stencil);
     52         setZOrderMediaOverlay(true);
     53     }
     54 
     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;
     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 
     99         public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
    100             egl.eglDestroyContext(display, context);
    101         }
    102     }
    103 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    304     public void lockPreviewReadyFlag() {
    305         mPreviewFrameReadyForProcessing.close();
    306     }
    307 
    308     private void unlockPreviewReadyFlag() {
    309         mPreviewFrameReadyForProcessing.open();
    310     }
    311 
    312     public void waitUntilPreviewReady() {
    313         mPreviewFrameReadyForProcessing.block();
    314     }
    315 
    316     public void setReady() {
    317         queueEvent(new Runnable() {
    318 
    319             @Override
    320             public void run() {
    321                 mRenderer.setReady();
    322             }
    323         });
    324     }
    325 
    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 
    336     public void transferGPUtoCPU() {
    337         queueEvent(new Runnable() {
    338 
    339             @Override
    340             public void run() {
    341                 mRenderer.transferGPUtoCPU();
    342                 unlockPreviewReadyFlag();
    343             }
    344         });
    345     }
    346 
    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 
    357     public MosaicRendererSurfaceViewRenderer getRenderer() {
    358         return mRenderer;
    359     }
    360 
    361 }
    362