Android N之SurfaceFlinger流程解析(3)

来源:互联网 发布:软件系统推广方案 编辑:程序博客网 时间:2024/06/09 16:05

SurfaceFlinger中关于EGL部分的解释:

什么是EGL?
EGL 是 OpenGL ES 和底层 Native 平台视窗系统之间的接口。

EGL的数据类型:

EGLBoolean ——EGL_TRUE =1, EGL_FALSE=0EGLint ——int 数据类型EGLDisplay ——系统显示 ID 或句柄,可以理解为一个前端的显示窗口EGLConfig ——Surface的EGL配置,可以理解为绘制目标framebuffer的配置属性EGLSurface ——系统窗口或 frame buffer 句柄 ,可以理解为一个后端的渲染目标窗口。EGLContext ——OpenGL ES 图形上下文,它代表了OpenGL状态机;如果没有它,OpenGL指令就没有执行的环境。NativeDisplayType——Native 系统显示类型,标识你所开发设备的物理屏幕NativeWindowType ——Native 系统窗口缓存类型,标识系统窗口NativePixmapType ——Native 系统 frame buffer,可以作为 Framebuffer 的系统图像(内存)数据类型,该类型只用于离屏渲染.

EGL的接口介绍:
1.获取Display

EGLDisplay eglGetDisplay(EGLNativeDisplayType display){    clearError();    uintptr_t index = reinterpret_cast<uintptr_t>(display);    if (index >= NUM_DISPLAYS) {        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);    }    if (egl_init_drivers() == EGL_FALSE) {        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);    }    EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);    return dpy;}

获得Display要调用EGLboolean eglGetDisplay(NativeDisplay dpy),参数一般为 EGL_DEFAULT_DISPLAY 。
2.初始化egl

EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor){    clearError();    egl_display_ptr dp = get_display(dpy);    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);    EGLBoolean res = dp->initialize(major, minor);    return res;}

调用 EGLboolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor),主要是做EGL初始化的工作。
3.选择Config

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;}

用EGLboolean eglGetConfigs(EGLDisplay dpy, EGLConfig * config, EGLint config_size, EGLint *num_config) 来获得所有config。然后会将获取到的Config结果保存在config[]中,而获取到的Config个数保存 在num_config中,调用eglGetConfig()来查询系统支持的Config总个数。
4.构造Surface

EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,                                    NativeWindowType window,                                    const EGLint *attrib_list){    clearError();    egl_connection_t* cnx = NULL;    egl_display_ptr dp = validate_display_connection(dpy, cnx);    if (dp) {        EGLDisplay iDpy = dp->disp.dpy;        int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);        if (result != OK) {            ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) "                    "failed (%#x) (already connected to another API?)",                    window, result);            return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);        }        // Set the native window's buffers format to match what this config requests.        // Whether to use sRGB gamma is not part of the EGLconfig, but is part        // of our native format. So if sRGB gamma is requested, we have to        // modify the EGLconfig's format before setting the native window's        // format.        // by default, just pick RGBA_8888        EGLint format = HAL_PIXEL_FORMAT_RGBA_8888;        android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN;        EGLint a = 0;        cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_ALPHA_SIZE, &a);        if (a > 0) {            // alpha-channel requested, there's really only one suitable format            format = HAL_PIXEL_FORMAT_RGBA_8888;        } else {            EGLint r, g, b;            r = g = b = 0;            cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_RED_SIZE,   &r);            cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_GREEN_SIZE, &g);            cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_BLUE_SIZE,  &b);            EGLint colorDepth = r + g + b;            if (colorDepth <= 16) {                format = HAL_PIXEL_FORMAT_RGB_565;            } else {                format = HAL_PIXEL_FORMAT_RGBX_8888;            }        }        // now select a corresponding sRGB format if needed        if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {            for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) {                if (*attr == EGL_GL_COLORSPACE_KHR) {                    if (ENABLE_EGL_KHR_GL_COLORSPACE) {                        dataSpace = modifyBufferDataspace(dataSpace, *(attr+1));                    } else {                        // Normally we'd pass through unhandled attributes to                        // the driver. But in case the driver implements this                        // extension but we're disabling it, we want to prevent                        // it getting through -- support will be broken without                        // our help.                        ALOGE("sRGB window surfaces not supported");                        return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);                    }                }            }        }        if (format != 0) {            int err = native_window_set_buffers_format(window, format);            if (err != 0) {                ALOGE("error setting native window pixel format: %s (%d)",                        strerror(-err), err);                native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);                return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);            }        }        if (dataSpace != 0) {            int err = native_window_set_buffers_data_space(window, dataSpace);            if (err != 0) {                ALOGE("error setting native window pixel dataSpace: %s (%d)",                        strerror(-err), err);                native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);                return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);            }        }        // the EGL spec requires that a new EGLSurface default to swap interval        // 1, so explicitly set that on the window here.        ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window);        anw->setSwapInterval(anw, 1);        EGLSurface surface = cnx->egl.eglCreateWindowSurface(                iDpy, config, window, attrib_list);        if (surface != EGL_NO_SURFACE) {            egl_surface_t* s = new egl_surface_t(dp.get(), config, window,                    surface, cnx);            return s;        }        // EGLSurface creation failed        native_window_set_buffers_format(window, 0);        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);    }    return EGL_NO_SURFACE;}

调用EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig confg, NativeWindow win, EGLint *cfg_attr)来创建一个Surface,其实这个Surface实际上就是一个FrameBuffer,也是后面渲染的目标。
5.创建Context

EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,                            EGLContext share_list, const EGLint *attrib_list){    clearError();    egl_connection_t* cnx = NULL;    const egl_display_ptr dp = validate_display_connection(dpy, cnx);    if (dp) {        if (share_list != EGL_NO_CONTEXT) {            if (!ContextRef(dp.get(), share_list).get()) {                return setError(EGL_BAD_CONTEXT, EGL_NO_CONTEXT);            }            egl_context_t* const c = get_context(share_list);            share_list = c->context;        }        EGLContext context = cnx->egl.eglCreateContext(                dp->disp.dpy, config, share_list, attrib_list);        if (context != EGL_NO_CONTEXT) {            // figure out if it's a GLESv1 or GLESv2            int version = 0;            if (attrib_list) {                while (*attrib_list != EGL_NONE) {                    GLint attr = *attrib_list++;                    GLint value = *attrib_list++;                    if (attr == EGL_CONTEXT_CLIENT_VERSION) {                        if (value == 1) {                            version = egl_connection_t::GLESv1_INDEX;                        } else if (value == 2 || value == 3) {                            version = egl_connection_t::GLESv2_INDEX;                        }                    }                };            }            egl_context_t* c = new egl_context_t(dpy, context, config, cnx,                    version);            return c;        }    }    return EGL_NO_CONTEXT;}

6.送显

EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface){    return eglSwapBuffersWithDamageKHR(dpy, surface, NULL, 0);}

7.EGL变量之间的绑定

EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,                            EGLSurface read, EGLContext ctx){    if (egl_display_t::is_valid(dpy) == EGL_FALSE)        return setError(EGL_BAD_DISPLAY, EGL_FALSE);    if (draw) {        egl_surface_t* s = (egl_surface_t*)draw;        if (!s->isValid())            return setError(EGL_BAD_SURFACE, EGL_FALSE);        if (s->dpy != dpy)            return setError(EGL_BAD_DISPLAY, EGL_FALSE);        // TODO: check that draw is compatible with the context    }    if (read && read!=draw) {        egl_surface_t* s = (egl_surface_t*)read;        if (!s->isValid())            return setError(EGL_BAD_SURFACE, EGL_FALSE);        if (s->dpy != dpy)            return setError(EGL_BAD_DISPLAY, EGL_FALSE);        // TODO: check that read is compatible with the context    }    EGLContext current_ctx = EGL_NO_CONTEXT;    if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))        return setError(EGL_BAD_MATCH, EGL_FALSE);    if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))        return setError(EGL_BAD_MATCH, EGL_FALSE);    if (ctx == EGL_NO_CONTEXT) {        // if we're detaching, we need the current context        current_ctx = (EGLContext)getGlThreadSpecific();    } else {        egl_context_t* c = egl_context_t::context(ctx);        egl_surface_t* d = (egl_surface_t*)draw;        egl_surface_t* r = (egl_surface_t*)read;        if ((d && d->ctx && d->ctx != ctx) ||            (r && r->ctx && r->ctx != ctx)) {            // one of the surface is bound to a context in another thread            return setError(EGL_BAD_ACCESS, EGL_FALSE);        }    }    ogles_context_t* gl = (ogles_context_t*)ctx;    if (makeCurrent(gl) == 0) {        if (ctx) {            egl_context_t* c = egl_context_t::context(ctx);            egl_surface_t* d = (egl_surface_t*)draw;            egl_surface_t* r = (egl_surface_t*)read;            if (c->draw) {                egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);                s->disconnect();                s->ctx = EGL_NO_CONTEXT;                if (s->zombie)                    delete s;            }            if (c->read) {                // FIXME: unlock/disconnect the read surface too             }            c->draw = draw;            c->read = read;            if (c->flags & egl_context_t::NEVER_CURRENT) {                c->flags &= ~egl_context_t::NEVER_CURRENT;                GLint w = 0;                GLint h = 0;                if (draw) {                    w = d->getWidth();                    h = d->getHeight();                }                ogles_surfaceport(gl, 0, 0);                ogles_viewport(gl, 0, 0, w, h);                ogles_scissor(gl, 0, 0, w, h);            }            if (d) {                if (d->connect() == EGL_FALSE) {                    return EGL_FALSE;                }                d->ctx = ctx;                d->bindDrawSurface(gl);            }            if (r) {                // FIXME: lock/connect the read surface too                 r->ctx = ctx;                r->bindReadSurface(gl);            }        } else {            // if surfaces were bound to the context bound to this thread            // mark then as unbound.            if (current_ctx) {                egl_context_t* c = egl_context_t::context(current_ctx);                egl_surface_t* d = (egl_surface_t*)c->draw;                egl_surface_t* r = (egl_surface_t*)c->read;                if (d) {                    c->draw = 0;                    d->disconnect();                    d->ctx = EGL_NO_CONTEXT;                    if (d->zombie)                        delete d;                }                if (r) {                    c->read = 0;                    r->ctx = EGL_NO_CONTEXT;                    // FIXME: unlock/disconnect the read surface too                 }            }        }        return EGL_TRUE;    }    return setError(EGL_BAD_ACCESS, EGL_FALSE);}

该接口将申请到的display,draw(surface)和 context进行了绑定。也就是说,在context下的OpenGL API指令将draw(surface)作为其渲染最终目的地。而display作为draw(surface)的前端显示。调用后,当前线程使用的EGLContex为context。

0 0
原创粉丝点击