Home | History | Annotate | Download | only in android
      1 package com.jme3.system.android;
      2 
      3 import android.graphics.PixelFormat;
      4 import android.opengl.GLSurfaceView.EGLConfigChooser;
      5 import java.util.logging.Level;
      6 import java.util.logging.Logger;
      7 import javax.microedition.khronos.egl.EGL10;
      8 import javax.microedition.khronos.egl.EGLConfig;
      9 import javax.microedition.khronos.egl.EGLDisplay;
     10 
     11 /**
     12  * AndroidConfigChooser is used to determine the best suited EGL Config
     13  *
     14  * @author larynx
     15  */
     16 public class AndroidConfigChooser implements EGLConfigChooser {
     17 
     18     private static final Logger logger = Logger.getLogger(AndroidConfigChooser.class.getName());
     19     protected int clientOpenGLESVersion = 0;
     20     protected EGLConfig bestConfig = null;
     21     protected EGLConfig fastestConfig = null;
     22     protected EGLConfig choosenConfig = null;
     23     protected ConfigType type;
     24     protected int pixelFormat;
     25     protected boolean verbose = false;
     26     private final static int EGL_OPENGL_ES2_BIT = 4;
     27 
     28     public enum ConfigType {
     29 
     30         /**
     31          * RGB565, 0 alpha, 16 depth, 0 stencil
     32          */
     33         FASTEST,
     34         /**
     35          * RGB???, 0 alpha, >=16 depth, 0 stencil
     36          */
     37         BEST,
     38         /**
     39          * Turn off config chooser and use hardcoded
     40          * setEGLContextClientVersion(2); setEGLConfigChooser(5, 6, 5, 0, 16,
     41          * 0);
     42          */
     43         LEGACY
     44     }
     45 
     46     public AndroidConfigChooser(ConfigType type) {
     47         this.type = type;
     48     }
     49 
     50     /**
     51      * Gets called by the GLSurfaceView class to return the best config
     52      */
     53     @Override
     54     public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
     55         logger.info("GLSurfaceView asks for egl config, returning: ");
     56         logEGLConfig(choosenConfig, display, egl);
     57         return choosenConfig;
     58     }
     59 
     60     /**
     61      * findConfig is used to locate the best config and init the chooser with
     62      *
     63      * @param egl
     64      * @param display
     65      * @return true if successfull, false if no config was found
     66      */
     67     public boolean findConfig(EGL10 egl, EGLDisplay display) {
     68 
     69         if (type == ConfigType.BEST) {
     70             ComponentSizeChooser compChooser = new ComponentSizeChooser(8, 8, 8, 8, 32, 0);
     71             choosenConfig = compChooser.chooseConfig(egl, display);
     72 
     73             if (choosenConfig == null) {
     74                 compChooser = new ComponentSizeChooser(8, 8, 8, 0, 32, 0);
     75                 choosenConfig = compChooser.chooseConfig(egl, display);
     76                 if (choosenConfig == null) {
     77                     compChooser = new ComponentSizeChooser(8, 8, 8, 8, 16, 0);
     78                     choosenConfig = compChooser.chooseConfig(egl, display);
     79                     if (choosenConfig == null) {
     80                         compChooser = new ComponentSizeChooser(8, 8, 8, 0, 16, 0);
     81                         choosenConfig = compChooser.chooseConfig(egl, display);
     82                     }
     83                 }
     84             }
     85 
     86             logger.info("JME3 using best EGL configuration available here: ");
     87         } else {
     88             ComponentSizeChooser compChooser = new ComponentSizeChooser(5, 6, 5, 0, 16, 0);
     89             choosenConfig = compChooser.chooseConfig(egl, display);
     90             logger.info("JME3 using fastest EGL configuration available here: ");
     91         }
     92 
     93         if (choosenConfig != null) {
     94             logger.info("JME3 using choosen config: ");
     95             logEGLConfig(choosenConfig, display, egl);
     96             pixelFormat = getPixelFormat(choosenConfig, display, egl);
     97             clientOpenGLESVersion = getOpenGLVersion(choosenConfig, display, egl);
     98             return true;
     99         } else {
    100             logger.severe("###ERROR### Unable to get a valid OpenGL ES 2.0 config, nether Fastest nor Best found! Bug. Please report this.");
    101             clientOpenGLESVersion = 1;
    102             pixelFormat = PixelFormat.UNKNOWN;
    103             return false;
    104         }
    105     }
    106 
    107     private int getPixelFormat(EGLConfig conf, EGLDisplay display, EGL10 egl) {
    108         int[] value = new int[1];
    109         int result = PixelFormat.RGB_565;
    110 
    111         egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RED_SIZE, value);
    112         if (value[0] == 8) {
    113             result = PixelFormat.RGBA_8888;
    114             /*
    115             egl.eglGetConfigAttrib(display, conf, EGL10.EGL_ALPHA_SIZE, value);
    116             if (value[0] == 8)
    117             {
    118                 result = PixelFormat.RGBA_8888;
    119             }
    120             else
    121             {
    122                 result = PixelFormat.RGB_888;
    123             }*/
    124         }
    125 
    126         if (verbose) {
    127             logger.log(Level.INFO, "Using PixelFormat {0}", result);
    128         }
    129 
    130         //return result; TODO Test pixelformat
    131         return PixelFormat.TRANSPARENT;
    132     }
    133 
    134     private int getOpenGLVersion(EGLConfig conf, EGLDisplay display, EGL10 egl) {
    135         int[] value = new int[1];
    136         int result = 1;
    137 
    138         egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RENDERABLE_TYPE, value);
    139         // Check if conf is OpenGL ES 2.0
    140         if ((value[0] & EGL_OPENGL_ES2_BIT) != 0) {
    141             result = 2;
    142         }
    143 
    144         return result;
    145     }
    146 
    147     /**
    148      * log output with egl config details
    149      *
    150      * @param conf
    151      * @param display
    152      * @param egl
    153      */
    154     public void logEGLConfig(EGLConfig conf, EGLDisplay display, EGL10 egl) {
    155         int[] value = new int[1];
    156 
    157         egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RED_SIZE, value);
    158         logger.info(String.format("EGL_RED_SIZE  = %d", value[0]));
    159 
    160         egl.eglGetConfigAttrib(display, conf, EGL10.EGL_GREEN_SIZE, value);
    161         logger.info(String.format("EGL_GREEN_SIZE  = %d", value[0]));
    162 
    163         egl.eglGetConfigAttrib(display, conf, EGL10.EGL_BLUE_SIZE, value);
    164         logger.info(String.format("EGL_BLUE_SIZE  = %d", value[0]));
    165 
    166         egl.eglGetConfigAttrib(display, conf, EGL10.EGL_ALPHA_SIZE, value);
    167         logger.info(String.format("EGL_ALPHA_SIZE  = %d", value[0]));
    168 
    169         egl.eglGetConfigAttrib(display, conf, EGL10.EGL_DEPTH_SIZE, value);
    170         logger.info(String.format("EGL_DEPTH_SIZE  = %d", value[0]));
    171 
    172         egl.eglGetConfigAttrib(display, conf, EGL10.EGL_STENCIL_SIZE, value);
    173         logger.info(String.format("EGL_STENCIL_SIZE  = %d", value[0]));
    174 
    175         egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RENDERABLE_TYPE, value);
    176         logger.info(String.format("EGL_RENDERABLE_TYPE  = %d", value[0]));
    177 
    178         egl.eglGetConfigAttrib(display, conf, EGL10.EGL_SURFACE_TYPE, value);
    179         logger.info(String.format("EGL_SURFACE_TYPE  = %d", value[0]));
    180     }
    181 
    182     public int getClientOpenGLESVersion() {
    183         return clientOpenGLESVersion;
    184     }
    185 
    186     public void setClientOpenGLESVersion(int clientOpenGLESVersion) {
    187         this.clientOpenGLESVersion = clientOpenGLESVersion;
    188     }
    189 
    190     public int getPixelFormat() {
    191         return pixelFormat;
    192     }
    193 
    194     private abstract class BaseConfigChooser implements EGLConfigChooser {
    195 
    196         private boolean bClientOpenGLESVersionSet;
    197 
    198         public BaseConfigChooser(int[] configSpec) {
    199             bClientOpenGLESVersionSet = false;
    200             mConfigSpec = filterConfigSpec(configSpec);
    201         }
    202 
    203         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
    204             int[] num_config = new int[1];
    205             if (!egl.eglChooseConfig(display, mConfigSpec, null, 0,
    206                     num_config)) {
    207                 throw new IllegalArgumentException("eglChooseConfig failed");
    208             }
    209 
    210             int numConfigs = num_config[0];
    211 
    212             if (numConfigs <= 0) {
    213                 //throw new IllegalArgumentException("No configs match configSpec");
    214 
    215                 return null;
    216             }
    217 
    218             EGLConfig[] configs = new EGLConfig[numConfigs];
    219             if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
    220                     num_config)) {
    221                 throw new IllegalArgumentException("eglChooseConfig#2 failed");
    222             }
    223             EGLConfig config = chooseConfig(egl, display, configs);
    224             //if (config == null) {
    225             //    throw new IllegalArgumentException("No config chosen");
    226             //}
    227             return config;
    228         }
    229 
    230         abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
    231                 EGLConfig[] configs);
    232         protected int[] mConfigSpec;
    233 
    234         private int[] filterConfigSpec(int[] configSpec) {
    235             if (bClientOpenGLESVersionSet == true) {
    236                 return configSpec;
    237             }
    238             /*
    239              * We know none of the subclasses define EGL_RENDERABLE_TYPE. And we
    240              * know the configSpec is well formed.
    241              */
    242             int len = configSpec.length;
    243             int[] newConfigSpec = new int[len + 2];
    244             System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1);
    245             newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE;
    246             newConfigSpec[len] = 4; /*
    247              * EGL_OPENGL_ES2_BIT
    248              */
    249             newConfigSpec[len + 1] = EGL10.EGL_NONE;
    250 
    251             bClientOpenGLESVersionSet = true;
    252 
    253             return newConfigSpec;
    254         }
    255     }
    256 
    257     /**
    258      * Choose a configuration with exactly the specified r,g,b,a sizes, and at
    259      * least the specified depth and stencil sizes.
    260      */
    261     private class ComponentSizeChooser extends BaseConfigChooser {
    262 
    263         private int[] mValue;
    264         // Subclasses can adjust these values:
    265         protected int mRedSize;
    266         protected int mGreenSize;
    267         protected int mBlueSize;
    268         protected int mAlphaSize;
    269         protected int mDepthSize;
    270         protected int mStencilSize;
    271 
    272         public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
    273                 int alphaSize, int depthSize, int stencilSize) {
    274             super(new int[]{
    275                         EGL10.EGL_RED_SIZE, redSize,
    276                         EGL10.EGL_GREEN_SIZE, greenSize,
    277                         EGL10.EGL_BLUE_SIZE, blueSize,
    278                         EGL10.EGL_ALPHA_SIZE, alphaSize,
    279                         EGL10.EGL_DEPTH_SIZE, depthSize,
    280                         EGL10.EGL_STENCIL_SIZE, stencilSize,
    281                         EGL10.EGL_NONE});
    282             mValue = new int[1];
    283             mRedSize = redSize;
    284             mGreenSize = greenSize;
    285             mBlueSize = blueSize;
    286             mAlphaSize = alphaSize;
    287             mDepthSize = depthSize;
    288             mStencilSize = stencilSize;
    289         }
    290 
    291         @Override
    292         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
    293             for (EGLConfig config : configs) {
    294                 int d = findConfigAttrib(egl, display, config,
    295                         EGL10.EGL_DEPTH_SIZE, 0);
    296                 int s = findConfigAttrib(egl, display, config,
    297                         EGL10.EGL_STENCIL_SIZE, 0);
    298                 if ((d >= mDepthSize) && (s >= mStencilSize)) {
    299                     int r = findConfigAttrib(egl, display, config,
    300                             EGL10.EGL_RED_SIZE, 0);
    301                     int g = findConfigAttrib(egl, display, config,
    302                             EGL10.EGL_GREEN_SIZE, 0);
    303                     int b = findConfigAttrib(egl, display, config,
    304                             EGL10.EGL_BLUE_SIZE, 0);
    305                     int a = findConfigAttrib(egl, display, config,
    306                             EGL10.EGL_ALPHA_SIZE, 0);
    307                     if ((r == mRedSize) && (g == mGreenSize)
    308                             && (b == mBlueSize) && (a == mAlphaSize)) {
    309                         return config;
    310                     }
    311                 }
    312             }
    313             return null;
    314         }
    315 
    316         private int findConfigAttrib(EGL10 egl, EGLDisplay display,
    317                 EGLConfig config, int attribute, int defaultValue) {
    318 
    319             if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
    320                 return mValue[0];
    321             }
    322             return defaultValue;
    323         }
    324     }
    325 }
    326