Kevin Krumwiede
Kevin Krumwiede

Reputation: 10298

Purpose of EGLConfig in onSurfaceCreated?

The GLSurfaceView.Renderer interface includes the method onSurfaceCreated(GL10 gl, EGLConfig config). I know the GL10 parameter is largely obsolete, but what is the EGLConfig parameter used for? What is the point of it, given that it declares no public properties or methods? Is it an argument for something else?

Upvotes: 3

Views: 2454

Answers (2)

Reto Koradi
Reto Koradi

Reputation: 54592

While the EGLConfig class has no useful methods, you can still use the object to get properties of the configuration. This is done with the EGL10 class, which has methods that take EGLConfig instances as arguments.

Now, the next question is how you get an EGL10 instance. For this, you use the static getEgl() method on EGLContext. The method returns an EGL instance, which you can cast to an EGL10.

All in all, the whole thing will then look something like this:

EGL10 egl = (EGL10)EGLContext.getEGL();
EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

int[] val = new int[1];
egl.eglGetConfigAttrib(dpy, config, EGL10.EGL_DEPTH_SIZE, val);
int depthBits = val[0];

This code retrieves the number of bits in your depth buffer. For this specific example, you could of course also get the same value with glGetIntegerv(), but the code fragment shows how you can use the config to make EGL calls.

If you want to control which config is used, you call one of the setEGLConfigChooser() overrides on GLSurfaceView. The simpler ones allow you to specify how many bits you want for your color, depth and stencil buffers. The more flexible version allows you to pass in an implementation of the EGLConfigChooser interface, where you can implement your own code to choose your preferred configuration.

Upvotes: 4

AndyRoid
AndyRoid

Reputation: 5067

Research into the Source:

You won't get much from the documentation on developers.android.com, but I dug into the source and found out the following information:


A given Android device may support multiple EGLConfig rendering configurations. The available configurations may differ in how may channels of data are present, as well as how many bits are allocated to each channel. Therefore, the first thing GLSurfaceView has to do when starting to render is choose what EGLConfig to use.

By default GLSurfaceView chooses a EGLConfig that has an RGB_888 pixel format, with at least a 16-bit depth buffer and no stencil.

If you would prefer a different EGLConfig you can override the default behavior by calling one of the setEGLConfigChooser methods.


Looking at that specific interface for GLSurfaceView.Renderer and the method call for onSurfaceCreated(...). The source code defines the following:

    /**
     * Called when the surface is created or recreated.
     * <p>
     * Called when the rendering thread
     * starts and whenever the EGL context is lost. The EGL context will typically
     * be lost when the Android device awakes after going to sleep.
     * <p>
     * Since this method is called at the beginning of rendering, as well as
     * every time the EGL context is lost, this method is a convenient place to put
     * code to create resources that need to be created when the rendering
     * starts, and that need to be recreated when the EGL context is lost.
     * Textures are an example of a resource that you might want to create
     * here.
     * <p>
     * Note that when the EGL context is lost, all OpenGL resources associated
     * with that context will be automatically deleted. You do not need to call
     * the corresponding "glDelete" methods such as glDeleteTextures to
     * manually delete these lost resources.
     * <p>
     * @param gl the GL interface. Use <code>instanceof</code> to
     * test if the interface supports GL11 or higher interfaces.
     * @param config the EGLConfig of the created surface. Can be used
     * to create matching pbuffers.
     */
    void onSurfaceCreated(GL10 gl, EGLConfig config);

Further down in the source code for GLSurfaceView we see the following interface:

/**
 * An interface for choosing an EGLConfig configuration from a list of
 * potential configurations.
 * <p>
 * This interface must be implemented by clients wishing to call
 * {@link GLSurfaceView#setEGLConfigChooser(EGLConfigChooser)}
 */
public interface EGLConfigChooser {
    /**
     * Choose a configuration from the list. Implementors typically
     * implement this method by calling
     * {@link EGL10#eglChooseConfig} and iterating through the results. Please consult the
     * EGL specification available from The Khronos Group to learn how to call eglChooseConfig.
     * @param egl the EGL10 for the current display.
     * @param display the current display.
     * @return the chosen configuration.
     */
    EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
}

Then an abstract class defines the following:

/**
 * Choose a configuration with exactly the specified r,g,b,a sizes,
 * and at least the specified depth and stencil sizes.
 */
private abstract class BaseConfigChooser
        implements EGLConfigChooser {

    public BaseConfigChooser(int[] configSpec) {
        mConfigSpec = filterConfigSpec(configSpec);
    }

    public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
        int[] num_config = new int[1];

        if (!egl.eglChooseConfig(display, mConfigSpec, null, 0,
                num_config)) {
            throw new IllegalArgumentException("eglChooseConfig failed");
        }

        int numConfigs = num_config[0];

        if (numConfigs <= 0) {
            throw new IllegalArgumentException(
                    "No configs match configSpec");
        }

        EGLConfig[] configs = new EGLConfig[numConfigs];

        if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
                num_config)) {
            throw new IllegalArgumentException("eglChooseConfig#2 failed");
        }
        EGLConfig config = chooseConfig(egl, display, configs);
        if (config == null) {
            throw new IllegalArgumentException("No config chosen");
        }
        return config;
    }

    abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
            EGLConfig[] configs);

    protected int[] mConfigSpec;

    private int[] filterConfigSpec(int[] configSpec) {
        if (mEGLContextClientVersion != 2 && mEGLContextClientVersion != 3) {
            return configSpec;
        }

        /* We know none of the subclasses define EGL_RENDERABLE_TYPE.
         * And we know the configSpec is well formed.
         */
        int len = configSpec.length;
        int[] newConfigSpec = new int[len + 2];
        System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1);
        newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE;

        if (mEGLContextClientVersion == 2) {
            newConfigSpec[len] = EGL14.EGL_OPENGL_ES2_BIT;  /* EGL_OPENGL_ES2_BIT */
        } else {
            newConfigSpec[len] = EGLExt.EGL_OPENGL_ES3_BIT_KHR; /* EGL_OPENGL_ES3_BIT_KHR */
        }

        newConfigSpec[len+1] = EGL10.EGL_NONE;
        return newConfigSpec;

    }
}

You can see more of the source code here at this link: GLSurfaceView.java

The Point of EGLConfig:

This is taken from the book OpenGL 3.0 ES Programming.

An EGLconfig contains all the information about a surface made available by EGL. This includes information about the number of colors available, additional buffers associated with the configuration (such as depth and stencil buffers), the type of surfaces (Surface Type Translucent, etc.), and numerous other characteristics.

To query a particular list of EGLConfig characteristics we query using the following method:

EGLBoolean eglGetConfigAttrib(EGLDisplay display, EGLConfig config, EGLint attribute, EGLint value); 

More information on the type of EGLConfigs can be found in the book OpenGL ES 3.0 Programming Guide page 48.

Upvotes: 2

Related Questions