Android OpenGL ES 2.0 与3.0兼容方案

1. 检查系统是否支持GLES3.0

检查系统支持的OpenGL版本的方法有一下几种方法:

  1. 查看EGL版本, 1.4以上
  2. EGL 查询Client版本号
  3. GL_VERSION
  4. GL_SHADING_LANGUAGE_VERSION

1.1 EGL版本检查

此方法适用于创建EGLContext阶段。
要支持GLES3.0 要求EGL版本在1.4以上。
EGL初始化的时候会返回EGL的版本信息,根据此版本选择合适的GLES版本号,具体代码如下:

    if (!eglInitialize(m_display, &major, &minor)) {
        return XR_EGL_BAD_DISPLAY;
    }

    LOGI("eglInitialize: major: %d, minor: %d", major, minor);
    if (minor >= 4 && s_nGLVersion >= 3) {
        nGLRenderType = EGL_OPENGL_ES3_BIT_KHR;
    } else {
        nGLRenderType = EGL_OPENGL_ES2_BIT;
        s_nGLVersion = 2;
    }

    ...

    EGLint attribList[]{
            EGL_CONTEXT_CLIENT_VERSION, s_nGLVersion,
            EGL_NONE
    };
    m_context = eglCreateContext(m_display, config, sharedContext, attribList);

1.2 EGL 查询Client版本号

    int clientVersion;
    eglQueryContext(m_display, m_context, EGL_CONTEXT_CLIENT_VERSION, &clientVersion);
    LOGI("EGLContext created, client version %d\n", clientVersion);

1.3 GL_VERSION

此方法必须在EGLContext已经创建好的前提是下才能使用。

    const char* versionStr = (const char*)glGetString(GL_VERSION);
    return strstr(versionStr, "OpenGL ES 3.") && gl3stubInit();

1.4 GL_SHADING_LANGUAGE_VERSION

此方法必须在EGLContext已经创建好的前提是下才能使用。

        std::string glslVersion = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
        if ( glslVersion.empty())
        {
            bRet = false;
        }
        bRet =  (strncmp( "OpenGL ES GLSL ES 3", glslVersion.c_str(), 19) == 0) ;

1.5 备注

在Android很多机型中,哪怕EGL_CONTEXT_CLIENT_VERSION申请的是2.0的版本,最终也会创建GLES3.0的环境

2. OpenGL ES 3.0 打桩

如果手机不支持GLES3.0,那么常规的使用方法就需要用宏把GLES 3.0的API包起来,否者就会出现变异问题。采用宏的方式会造成代码混乱,可读性较差。

针对上面的问题,这里提供一种打桩的形式,就是通过eglGetProcAddress把GLES接口嗅探出来。具体实现如下:

/*
 * GL3Stub.h
 */

GLboolean gl3stubInit();

/*-------------------------------------------------------------------------
 * Data type definitions
 *-----------------------------------------------------------------------*/

/* OpenGL ES 3.0 */

typedef unsigned short   GLhalf;
#if __ANDROID_API__ <= 19
typedef khronos_int64_t  GLint64;
typedef khronos_uint64_t GLuint64;
typedef struct __GLsync *GLsync;
#endif

/*-------------------------------------------------------------------------
 * Token definitions
 *-----------------------------------------------------------------------*/

/* OpenGL ES core versions */
#define GL_ES_VERSION_3_0                                1

/* OpenGL ES 3.0 */

#define GL_READ_BUFFER                                   0x0C02
#define GL_UNPACK_ROW_LENGTH                             0x0CF2
#define GL_UNPACK_SKIP_ROWS                              0x0CF3
#define GL_UNPACK_SKIP_PIXELS                            0x0CF4
#define GL_PACK_ROW_LENGTH                               0x0D02
#define GL_PACK_SKIP_ROWS                                0x0D03

........
/*
 * GL3Stub.c
 */

 GLboolean gl3stubInit() {
    #define FIND_PROC(s) s = (void*)eglGetProcAddress(#s)
    FIND_PROC(glReadBuffer);
    FIND_PROC(glDrawRangeElements);
    FIND_PROC(glTexImage3D);
    ...
    #undef FIND_PROC

    if (!glReadBuffer ||
        !glDrawRangeElements ||
        !glTexImage3D ||
        !glTexSubImage3D ||
        ...
        ) {
        return GL_FALSE;
    }
}

/* Function pointer definitions */
GL_APICALL void           (* GL_APIENTRY glReadBuffer) (GLenum mode);
GL_APICALL void           (* GL_APIENTRY glDrawRangeElements) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices);
GL_APICALL void           (* GL_APIENTRY glTexImage3D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
GL_APICALL void           (* GL_APIENTRY glTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
GL_APICALL void           (* GL_APIENTRY glCopyTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
GL_APICALL void           (* GL_APIENTRY glCompressedTexImage3D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
GL_APICALL void           (* GL_APIENTRY glCompressedTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
GL_APICALL void           (* GL_APIENTRY glGenQueries) (GLsizei n, GLuint* ids);

...

3. 动态库加载

Android OpenGL ES库有三个:

  • libGLESv1_CM.so : GLES 1.0
  • libGLESv2.so : GLES 2.0
  • libGLESv3.so : GLES 3.0

但是在实际使用中发现:libGLESv2.so中已经支持了GLES3.0.
所以我们只要加载libGLESv2.so就可以了。

你可能感兴趣的:(Android,OpenGL)