Android N之SurfaceFlinger流程解析(6)

来源:互联网 发布:剑三代练淘宝下单好吗 编辑:程序博客网 时间:2024/06/05 10:43

今天晚上来看了一下在SurfaceFlinger类中的成员函数init中的关于创建RenderEngine的部分,首先看一下源码:

RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) {    // EGL_ANDROIDX_no_config_context is an experimental extension with no    // written specification. It will be replaced by something more formal.    // SurfaceFlinger is using it to allow a single EGLContext to render to    // both a 16-bit primary display framebuffer and a 32-bit virtual display    // framebuffer.    //    // The code assumes that ES2 or later is available if this extension is    // supported.    EGLConfig config = EGL_NO_CONFIG;    if (!findExtension(            eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),            "EGL_ANDROIDX_no_config_context")) {        config = chooseEglConfig(display, hwcFormat);    }    EGLint renderableType = 0;    if (config == EGL_NO_CONFIG) {        renderableType = EGL_OPENGL_ES2_BIT;    } else if (!eglGetConfigAttrib(display, config,            EGL_RENDERABLE_TYPE, &renderableType)) {        LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");    }    EGLint contextClientVersion = 0;    if (renderableType & EGL_OPENGL_ES2_BIT) {        contextClientVersion = 2;    } else if (renderableType & EGL_OPENGL_ES_BIT) {        contextClientVersion = 1;    } else {        LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");    }    // Also create our EGLContext    EGLint contextAttributes[] = {            EGL_CONTEXT_CLIENT_VERSION, contextClientVersion,      // MUST be first#ifdef EGL_IMG_context_priority#ifdef HAS_CONTEXT_PRIORITY#warning "using EGL_IMG_context_priority"            EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,#endif#endif            EGL_NONE, EGL_NONE    };    EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes);    // if can't create a GL context, we can only abort.    LOG_ALWAYS_FATAL_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed");    // now figure out what version of GL did we actually get    // NOTE: a dummy surface is not needed if KHR_create_context is supported    EGLConfig dummyConfig = config;    if (dummyConfig == EGL_NO_CONFIG) {        dummyConfig = chooseEglConfig(display, hwcFormat);    }    EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE };    EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs);    LOG_ALWAYS_FATAL_IF(dummy==EGL_NO_SURFACE, "can't create dummy pbuffer");    EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);    LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");    GLExtensions& extensions(GLExtensions::getInstance());    extensions.initWithGLStrings(            glGetString(GL_VENDOR),            glGetString(GL_RENDERER),            glGetString(GL_VERSION),            glGetString(GL_EXTENSIONS));    GlesVersion version = parseGlesVersion( extensions.getVersion() );    // initialize the renderer while GL is current    RenderEngine* engine = NULL;    switch (version) {    case GLES_VERSION_1_0:        engine = new GLES10RenderEngine();        break;    case GLES_VERSION_1_1:        engine = new GLES11RenderEngine();        break;    case GLES_VERSION_2_0:    case GLES_VERSION_3_0:        engine = new GLES20RenderEngine();        break;    }    engine->setEGLHandles(config, ctxt);    ALOGI("OpenGL ES informations:");    ALOGI("vendor    : %s", extensions.getVendor());    ALOGI("renderer  : %s", extensions.getRenderer());    ALOGI("version   : %s", extensions.getVersion());    ALOGI("extensions: %s", extensions.getExtension());    ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());    ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);    eglDestroySurface(display, dummy);    return engine;}

如果觉得一开始看代码不舒服的话,我们先来看一下示意图。

下面来继续分析在创建RenderEngine中的几个主要的函数:
1.chooseEglConfig
首先大概看一下chooseEglConfig的结构:
这里写图片描述
分别介绍一下其中涉及到的EGL的接口:
eglGetConfigs:
此函数用来获取显示设备支持的配置,其参数含义如下:

EGLBoolean eglGetConfigs(EGLDisplay display,    // 已初始化好                           EGLConfig* configs,    // 如果为NULL,则返回EGL_TRUE和numConfigs,即图形系统所有可用的配置                           EGLint maxConfigs,     // 上面那个configs数组的容量                           EGLint* numConfigs);   // 图形系统返回的实际的可用的配置个数,存储在configs数组里 

该函数源代码如下:

EGLBoolean eglGetConfigs(   EGLDisplay dpy,                            EGLConfig *configs,                            EGLint config_size, EGLint *num_config){    clearError();    const egl_display_ptr dp = validate_display(dpy);    if (!dp) return EGL_FALSE;    if (num_config==0) {        return setError(EGL_BAD_PARAMETER, EGL_FALSE);    }    EGLBoolean res = EGL_FALSE;    *num_config = 0;    egl_connection_t* const cnx = &gEGLImpl;    if (cnx->dso) {        res = cnx->egl.eglGetConfigs(                dp->disp.dpy, configs, config_size, num_config);    }    return res;}

eglChooseConfig:
此函数的工作主要是查询底层窗口系统支持的所有EGL表面配置,通过configAttributes []指定的需求,EGL返回最佳的配置列表。首先返回最佳配置的个数,然后分配空间存储返回分配置列表数组。然后选择RGB,深度最匹配的配置。
其参数的设置如下:

EGLBoolean eglChooseConfig(EGLDisplay display,                             const EGLint* attribs,    // 你想要的属性事先定义到这个数组里                             EGLConfig* configs,       // 图形系统将返回若干满足条件的配置到该数组                             EGLint maxConfigs,        // 上面数组的容量                             EGLint* numConfigs);      // 图形系统返回的可用的配置个数  

其源码如下:

EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,                            EGLConfig *configs, EGLint config_size,                            EGLint *num_config){    clearError();    const egl_display_ptr dp = validate_display(dpy);    if (!dp) return EGL_FALSE;    if (num_config==0) {        return setError(EGL_BAD_PARAMETER, EGL_FALSE);    }    EGLBoolean res = EGL_FALSE;    *num_config = 0;    egl_connection_t* const cnx = &gEGLImpl;    if (cnx->dso) {        if (attrib_list) {            char value[PROPERTY_VALUE_MAX];            property_get("debug.egl.force_msaa", value, "false");            if (!strcmp(value, "true")) {                size_t attribCount = 0;                EGLint attrib = attrib_list[0];                // Only enable MSAA if the context is OpenGL ES 2.0 and                // if no caveat is requested                const EGLint *attribRendererable = NULL;                const EGLint *attribCaveat = NULL;                // Count the number of attributes and look for                // EGL_RENDERABLE_TYPE and EGL_CONFIG_CAVEAT                while (attrib != EGL_NONE) {                    attrib = attrib_list[attribCount];                    switch (attrib) {                        case EGL_RENDERABLE_TYPE:                            attribRendererable = &attrib_list[attribCount];                            break;                        case EGL_CONFIG_CAVEAT:                            attribCaveat = &attrib_list[attribCount];                            break;                    }                    attribCount++;                }                if (attribRendererable && attribRendererable[1] == EGL_OPENGL_ES2_BIT &&                        (!attribCaveat || attribCaveat[1] != EGL_NONE)) {                    // Insert 2 extra attributes to force-enable MSAA 4x                    EGLint aaAttribs[attribCount + 4];                    aaAttribs[0] = EGL_SAMPLE_BUFFERS;                    aaAttribs[1] = 1;                    aaAttribs[2] = EGL_SAMPLES;                    aaAttribs[3] = 4;                    memcpy(&aaAttribs[4], attrib_list, attribCount * sizeof(EGLint));                    EGLint numConfigAA;                    EGLBoolean resAA = cnx->egl.eglChooseConfig(                            dp->disp.dpy, aaAttribs, configs, config_size, &numConfigAA);                    if (resAA == EGL_TRUE && numConfigAA > 0) {                        ALOGD("Enabling MSAA 4x");                        *num_config = numConfigAA;                        return resAA;                    }                }            }        }        res = cnx->egl.eglChooseConfig(                dp->disp.dpy, attrib_list, configs, config_size, num_config);    }    return res;}

eglGetConfigAttrib:
此函数的作用主要是查询指定配置的指定属性,其函数的参数定义如下:

EGLBoolean eglGetConfigAttrib(EGLDisplay display,    // 已初始化                                EGLConfig config,      // 某个配置                                EGLint attribute,      // 某个属性                                EGLint * value);  

其源码如下:

EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,        EGLint attribute, EGLint *value){    clearError();    egl_connection_t* cnx = NULL;    const egl_display_ptr dp = validate_display_connection(dpy, cnx);    if (!dp) return EGL_FALSE;    return cnx->egl.eglGetConfigAttrib(            dp->disp.dpy, config, attribute, value);}

以上为chooseEglConfig中的分析结果。

2.eglCreateContext
其主要的作用是创建渲染上下文,

EGLContext eglCreateContext(EGLDisplay display,                              EGLConfig config,                              EGLContext context,    // EGL_NO_CONTEXT表示不向其它的context共享资源                              const EGLint * attribs)

3.eglCreatePbufferSurface:主要是创建在显存中的帧
4.eglMakeCurrent:指定EGLcontext为当前上下文
5.eglDestroySurface:释放Surface相关资源

感觉这篇文章主要在解释egl的接口了,下次抽时间好好看一下egl的接口的实现。

0 0