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