简介
每一硬件平台都有其独特的显示配置,具体取决于 LCD 面板(或 HDMI 等外部视频输出)属性、LCD 控制器、GPU,以及可用的内存和带宽。 EGL 使用 EGLConfig 抽象来实现跨平台移植。 对于每一个给定的硬件平台,每个 EGLConfig 与可能的显示配置对应。
为了创建“表面”(用于渲染输出的目标缓存的 EGL 术语),有必要提供 EGLConfig。 此 EGLConfig 必须从所有可用范围中选定,具体通过发出详细说明您所需要的特性(指代为属性)的请求来进行。
这一示例演示如何在创建表面时从可用范围中选择正确的 EGLConfig。
/* Get a display handle and initalize EGL */ EGLint major, minor; EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(display, &major, &minor); /* Request an RGB565 config. with 4x anti-aliasing * (4x is 'free' on Mali*/ EGLint attributes = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6, EGL_BLUE_SIZE, 5, EGL_SAMPLES, 4, EGL_NONE } EGLint numberConfigs; EGLConfig* matchingConfigs; /* Number of matching EGLConfig's returned in numberConfigs, but because * the 3rd argument is NULL no configs will actually be returned */ if (EGL_FALSE == eglChooseConfig(display, attributes, NULL,0, &numberConfigs)) { /* An error */ } if (numberConfigs == 0) { /* An error */ } /* Allocate some space to store list of matching configs... */ matchingConfigs = (EGLConfig*)malloc( numberConfigs * sizeof(EGLConfig)); /* ...and this time actually get the list (notice the 3rd argument is * now the buffer to write matching EGLConfig's to) */ if (EGL_FALSE == eglChooseConfig(display, attributes, matchingConfigs, numberConfigs, &numberConfigs)) { /* An error */ }
潜在问题
EGL 并不等同对待所有属性,并且在一些情形中,EGL 不会查找完全匹配项。例如,如果请求在 Z 缓存 (EGL_DEPTH_SIZE) 中具有一定数量的位的 EGLConfig,它会被视为最小值。 位数较高的 EGLConfig 依然会被考虑。 如果有多个匹配的 EGLConfig,则它们都会被返回。
另外,EGL 将兼容的 EGLConfig 按照 EGL 规格中定义的特定顺序进行排序。 此顺序并非始终都明了。
为了说明这两项原则,请以某一需要 16 位色的应用程序为例。 为了这一目的,它可能会请求一个值为 5 的 EGL_RED_SIZE、一个值为 6 的 EGL_GREEN_SIZE,以及一个值为 5 的 EGL_BLUE_SIZE 。颜色通道深度是视为最小值的属性,因此兼容 EGLConfig 的列表将包含所有 16 位颜色深度,以及更多颜色的深度,如 EGL_RED_SIZE 等于 8、 EGL_GREEN_SIZE 等于 8,以及 EGL_BLUE_SIZE 等于 8。由于找到了多个匹配的 EGLConfig,驱动程序将对它们进行排序。 颜色通道深度属性的排序行为意味着颜色数较高的 EGLConfig 将排在前列。 因此,尽管请求了 16 位显示,列表中的第一个 EGLConfig 实际上是 24/32 位显示。
此外,还有一个优先级的概念用来确定用于对匹配的 EGLConfig 进行排序的顺序属性。为了进行说明,我们假设将值为 16 的 EGL_BUFFER_SIZE 添加到请求中的属性列表中。 EGL_BUFFER_SIZE 是总的颜色缓存深度。EGL_BUFFER_SIZE 的排序顺序是从最小到最大,因此似乎能够解决上述的问题,因为第一个 EGLConfig 将是 16 位显示。 遗憾的是,这依然不行。因为 EGL_BUFFER_SIZE 属性的优先级低于EGL_[RED|GREEN|BLUE]_SIZE。 这表示驱动程序依然会根据各个颜色通道的最大值来排序。 为了获得 16 位颜色缓存,必须从请求中删除较高优先级的个别颜色通道属性。
最后,还得考虑请求中的属性是否足够精确。 如果请求中仅包含值为 16 的 EGL_BUFFER_SIZE 的属性,它会选择颜色缓存总深度为16 位的EGLConfig,但这可以是 RGB565、RGBA5551 或 RGBA4444。 如果 EGLConfig 的目的是为了绘制OS 位图 [1],则务必要精确匹配格式 [2]。
后果
根据平台的不同,尤其是在颜色深度的情形中,EGLConfig 选择不当可能会降低性能或导致运行时错误。 例如,在颜色深度/格式不匹配时,GPU 可能必须要渲染至离屏临时缓冲区(需要额外内存),接着 CPU 必须将各个像素从选定的格式转换为实际需要的格式,并且最终拷贝至实际目的地(过程中消耗许多 CPU 周期)。
/* The EGLConfig we will eventually use. * Set to NULL to detect the case where no suitable config. Is found */ EGLConfig chosenConfig = NULL; /* Look at each EGLConfig */ for (int ii=0; ii<numberConfigs; ii++) { EGLBoolean success; EGLint red, green, blue; /* Read the relevent attributes of the EGLConfig */ success = eglGetConfigAttrib(display, matchingConfigs[ii], EGL_RED_SIZE, &red); success &= eglGetConfigAttrib(display, matchingConfigs[ii], EGL_BLUE_SIZE, &blue); success &= eglGetConfigAttrib(display, matchingConfigs[ii], EGL_GREEN_SIZE, &green); /* Check that no error occurred and the attributes match */ if ( success == EGL_TRUE) && (red==5) && (green==6) && (blue==5) ) { chosenConfig=match[ii]; break; } } if (chosenConfig == NULL) { /* An error */ } free(matchingConfigs);
结论
我们可以从上述注释中清楚地认识到,如果应用程序或平台对 EGLConfig 有具体的要求,则必须要小心操作以便在请求中使用正确的属性;而且,如果有可能返回任何不适当的 EGLConfig,则应检查各个 EGLConfig 的相关属性。
这是该主题的简单介绍;EGL 规格中详述了精确选择、排序和优先级行为,您可从 http://www.khronos.org/registry/egl/ 获取该规格。
建议您阅读(至少)第 3.4 节“配置管理”。
额外信息
本示例的完整源代码列表在 OpenGL ES SDK for Linux on ARM 和 OpenGL ES 2.0 SDK for Android 中提供,其中还提供了演示其用法的许多其他示例。