添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

EGL资源的数据共享应用和底层驱动实现

已有 4201 次阅读 2015-8-12 19:22 |个人分类: OpenGL |系统分类: 科研笔记

为了某个原因成文于2013年,本文最有意义的是在最后揭示了如何实现免拷贝的数据共享(non-copy,zero-copy),我还没有在之前的书籍教材中有看到过介绍的。通过CPU和GPU直接的数据直接共享,GPU之上各API之间的数据直接共享,可以大幅度的提高性能。这是个普遍的思路,在各种应用背景下都可以实现并使用。

摘  要   随着移动设备的广泛应用,如何以更低的功耗提供更佳的用户体验成为一个非常重要的课题。EGL通过定义EGLSurface和EGL Image等资源,使得不同renderingAPI间以及和原生平台间的数据可以实现直接共享,从而降低功耗提高性能。本文整合分散在各种规范中的概念介绍了如何在应用层使用EGL资源进行数据共享,并解释了在驱动程序中是如何支持的思路,以深入理解,不仅知其然,而且知其所以然。

关键词    EGL, OpenGL ES, 低功耗, 数据共享

EGL是由Khronos组织维护的、连接OpenGL ES[ [1] ]和OpenVG[ [2] ]等rendering API与原生平台系统(native platformwindow system)的一套API接口,由核心规范[ [3] ]和扩展规范[ [4] ]组成。随着移动设备的广泛应用,如何以更低的功耗提供更佳的用户体验成为一个非常重要的课题。EGL通过定义EGL Surface和EGL Image等资源,使得不同rendering API间以及和原生平台间的数据可以实现直接共享,而无需拷贝。这种无拷贝机制不仅减少了内存读写从而降低功耗,而且提高了性能从而改善用户的体验。

由于不同的EGL资源在概念上相近,却在核心规范和多个扩展规范中被分别定义,容易混淆,因此,很有必要总结成文厘清概念,并解释其驱动程序的底层实现思路,以加深理解,从而更好的在移动设备上的应用程序中用好EGL资源。

2.EGL资源在应用层的数据共享

EGL Surface和EGLImage等EGL资源在应用程序中的创建和使用是类似的,具体函数名不同,但是形式上是类似的。而且两者最终都是通过成为绘制目标(RenderingTarget)或者纹理资源(Texture)来实现的,很容易造成函数的误用。

2.1 EGL Surface的创建和使用

EGL Surface的创建和使用在EGL核心规范中定义。EGL Surface分成 WindowSurface、PixmapSurface和PbufferSurface三种类型,分别由函数eglCreateWindowSurface、eglCreatePixmapSurface和eglCreatePbufferSurface/eglCreatePbufferFromClientBuffer创建,如图1所示,箭头上的注释是函数名。其中,WindowSurface来自窗口系统,是最终在屏幕可见的Surface;PixmapSurface和PbufferSurface则是不可见的,两者区别在于PbufferSurface属于EGL创建,而PixmapSurface则是来自原生平台系统。随着函数eglCreatePbufferFromClientBuffer的出现,使得PbufferSurface也可以来自原生平台系统。由于PixmapSurface的概念相对简单,而且和窗口系统的不可见资源具有对应关系,因此,一般来说,我们会倾向使用PixmapSurface而不是PbufferSurface。

在图1中,指向椭圆形EGL Surface的箭头表示Surface的被创建,而源自EGL Surface的箭头则表示Surface的被使用。箭头起始端的矩形中的变量是该箭头函数的主要参数,其中,EGLNativeWindowType win和EGLNativePixmapType pixmap一般都在原生平台中被定义,所以可以被原生平台中支持的函数所直接访问。例如X11系统中由Xlib库创建的Window和Pixmap。

无论哪种EGL Surface,都可以通过eglMakeCurrent函数成为Render Target,但是,由于eglMakeCurrent会导致graphics context的切换从而影响性能,所以,在可能的情况下,不可见的RenderTarget一般不使用EGL Surface,而使用FBO技术(FrameBuffer Object[ [5] ])。PBufferSurface还可以通过eglBindTexImage函数成为纹理资源(Texture),以作为graphicspipeline的数据来源;一般来说,原生平台提供商还会增加一个扩展规范,使得PixmapSurface也可以通过eglBindTexImage函数成为Texture。

2.2 EGL Image的创建和使用

EGL Image最初在扩展规范EGL_KHR_image中定义,为了进一步扩展的需要,在2008年11月19号被分成为两个扩展规范,如图2的椭圆形EGLImage向上部分所示,其中,EGL_KHR_image_base定义了EGLImage的相关概念和相应的eglCreateImageKHR函数,该函数的两个关键参数是target和buffer,另一个扩展规范是EGL_KHR_image_pixmap,使得原生平台的pixmap可以被创建为EGL Image。在此基础上,Android平台提出了EGL_Android_image_native_buffer使得android平台定义的ANativeWindowBuffer可以被创建为EGL Image;还有EGL_KHR_gl_texture_2D_image,EGL_KHR_gl_texture_3D_image,EGL_KHR_gl_renderbuffer_image和EGL_KHR_gl_texture_cubemap_image等扩展规范使得OpenGLES中的资源可以被创建为EGL Image。一般的,每个原生平台提供者都会提供其私有的扩展规范来创建相应的EGLImage。

EGL Image的使用在OpenGLES的扩展规范中被定义,如图2的椭圆形EGL Surface部分向下所示,首先,EGL Image被重新定义(typedef)为GLeglImageOES,然后,扩展规范GL_OES_EGL_image定义了两个函数,使得EGL Image可以被当做2D Texture或者Renderbuffer使用,可分别作为graphicspipeline的数据来源和绘制目标。另一个扩展规范GL_OES_EGL_image_external定义了一个新的Texture类型GL_TEXTURE_EXTERNAL_OES,使得诸如YUV等以前不被OpenGL ES支持的格式的EGL Image,可以被直接作为一个Texture从而被OpenGL ES所支持,当然,其背后离不开驱动程序内部增加shader指令进行格式转换,假以时日,可能会出现直接支持YUV等格式的texture采样硬件。

3.EGL资源在驱动底层的实现

EGL Surface和EGLImage数据结构的c语言定义都是void *,它们可以从多种来源被创建,也有多个使用场合,那么,在驱动底层是如何光凭void *就能知道当前情况呢,一个参考实现是使用基础struct和magic number,其中,magic number在基础struct中被定义,所有相关资源数据结构的最开始部分就是基础struct。这样,在创建时返回对应资源数据结构(struct)的指针作为void *的handle,在使用时则将此handle强制转回基础struct指针,然后根据struct中magic number数据成员的值来得知原始资源是什么从而将其用好。

之前提到,有些资源还可以被原生平台提供的函数读写,那么,是怎么实现CPU和GPU对同一资源的访问呢?抛开表象看本质,我们知道所有资源最终都是由物理存储器中的内存页面组成,CPU通过其内存管理单元(MMU)进行地址映射从而访问到真实存储,有了这些信息,内核态的驱动程序就可以通过配置GPU的类MMU单元,从而使得GPU也可以访问这些资源,这也就意味着graphicspipeline可以读写这些资源。在此,需要特别关注并解决好CPU和GPU对同一资源的并发访问和cache刷新的技术问题。

知其然,也知其所以然。通过以上对EGL Surface和EGLImage的介绍,包括如何创建和使用,也包括在驱动底层的支持思路,可以深入理解这些EGL资源的无需拷贝的数据共享机制是如何降低功耗和提高性能。特别地,将所有相关重要概念都在文中的两幅图中表现出来,做到一目了然,这对用好EGL资源具有重要意义。限于篇幅所限,无法对EGL Surface和EGLImage进行更多细节上的介绍,需要用户在使用细节上参考相应的EGL和OpenGLES的核心规范和扩展规范。

[1] OpenGL ES - The Standard for Embedded Accelerated 3D Graphics, http://www.khronos.org/opengles/

[2] OpenVG - The Standard for Vector Graphics Acceleration, http://www.khronos.org/openvg/

[3] Jon Leech, Khronos Native Platform Graphics Interface (EGL Version 1.4 – April6, 2011) http://www.khronos.org/registry/egl/specs/eglspec.1.4.20110406.pdf

[4] Khronos EGL API Registry, http://www.khronos.org/registry/egl/

[5] Aaftab Munshi, GL_OES_framebuffer_object, http://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt


扩展参考 http://blog.chinaunix.net/uid-20235103-id-2974856.html



转载本文请联系原作者获取授权,同时请注明本文来自郭叶军科学网博客。
链接地址: http://blog.sciencenet.cn/blog-1420268-912560.html

EGL资源的数据共享应用和底层驱动实现已有 4201 次阅读2015-8-12 19:22|个人分类:OpenGL|系统分类:科研笔记为了某个原因成文于2013年,本文最有意义的是在最后揭示了如何实现免拷贝的数据共享(non-copy,zero-copy),我还没有在之前的书籍教材中有看到过介绍的。通过CPU和GPU直接的数据直接共享,GPU之上各API之间的数据直接共享,可以大幅度的提高性能。这是个普遍的思路,在各种应用背景下都可以实现并使用。摘要随着移动设备的广泛应...
EGL Image代表一种由 EGL 客户API(如OpenGL,OpenVG)创建的 共享 资源 类型。它的本意是 共享 2D图像 数据 ,但是并没有明确限定 共享 数据 的格式以及 共享 的目的,所以理论上来讲, 应用 程序以及相关的客户API可以基于任意的目的创建任意类型的 共享 数据 。          关于 EGL Image的一种使用情景就是通过它来创建一个2D纹理。相关函数原型声明如下: EGL API EGL Ima
1. 概览 EGL 是介于各种粉刷(rendering)API如(OpenGL,OpenVG等)和 底层 窗口系统平台之间的接口。 EGL 提供各种机制创建图形context和粉刷surface供客户API使用。同时, EGL 也在绘图的过程中为本地绘图平台和客户api提供同步机制。 EGL 提供远程和间接粉刷机制,而GLX API则有这个机制。 2. EGL 操作 2.1本地窗口系统和粉刷API EGL 可以
Linux上的OpenGL无头( EGL ):示例程序 该存储库包含一个示例python程序,该程序以无头模式(无显示)运行GPU计算(OpenGL) 。 该程序使用 EGL (以及可选的GBM)初始化OpenGL上下文。 它将连接到/dev/dri/<something>内核DRM接口文件。 然后,为了测试它是否有效,它调用了非常基本的OpenGL绘制函数来绘制一个蓝色矩形,并编写一个ppm图像文件。 操作系统库 无论如何,您都需要带有libGL和lib EGL 的合适的GPU 驱动 程序。 如果您使用最新的Nvidia 驱动 程序,这可能就足够了。 否则(例如,英特尔集成GPU),程序将尝试加载li
-【参考-khronos- egl (最新版本1.5)】https://www.khronos.org/ egl -【参考-khronos- egl -api(目前共34个API,不包括Khronos扩展)】https://www.khronos.org/registry/ EGL /sdk/docs/man/ -【参考-khronos- egl -intro】https://www.khronos.org/registry/ EGL /sdk/docs/man/html/ egl Intro.xhtml EGL .
EGL (Embedded System Graphics Library)是用于嵌入式系统的图形库,用于管理OpenGL ES或OpenVG与本地窗口系统之间的通信。在配置 EGL 之前,需要确保您已经安装了OpenGL ES和OpenVG的 驱动 程序。 下面是一些基本的配置步骤: 1. 创建 EGL 上下文 在 应用 程序初始化期间,需要创建 EGL 上下文来管理OpenGL ES或OpenVG渲染。可以使用以下代码创建一个 EGL 上下文: EGL Display display = egl GetDisplay( EGL _DEFAULT_DISPLAY); EGL int major, minor; egl Initialize(display, &major, &minor); EGL int configAttribs[] = { EGL _SURFACE_TYPE, EGL _WINDOW_BIT, EGL _RED_SIZE, 8, EGL _GREEN_SIZE, 8, EGL _BLUE_SIZE, 8, EGL _ALPHA_SIZE, 8, EGL _NONE EGL int numConfigs; EGL Config config; egl ChooseConfig(display, configAttribs, &config, 1, &numConfigs); EGL Surface surface = egl CreateWindowSurface(display, config, window, NULL); EGL int contextAttribs[] = { EGL _CONTEXT_CLIENT_VERSION, 2, EGL _NONE EGL Context context = egl CreateContext(display, config, EGL _NO_CONTEXT, contextAttribs); egl MakeCurrent(display, surface, surface, context); 请注意,这只是创建 EGL 上下文的基本代码示例。您需要根据您的 应用 程序需要进行修改。 2. 绑定OpenGL ES或OpenVG 在创建 EGL 上下文后,需要将OpenGL ES或OpenVG与 EGL 绑定。可以使用以下代码: egl BindAPI( EGL _OPENGL_ES_API); 或者,如果您正在使用OpenVG: egl BindAPI( EGL _OPENVG_API); 3. 渲染 一旦您的 EGL 上下文已经创建和绑定,您就可以开始渲染OpenGL ES或OpenVG图形了。您可以使用OpenGL ES或OpenVG API来绘制图形。 4. 清理 最后,在 应用 程序退出时,需要清理 EGL 上下文。您可以使用以下代码: egl MakeCurrent(display, EGL _NO_SURFACE, EGL _NO_SURFACE, EGL _NO_CONTEXT); egl DestroyContext(display, context); egl DestroySurface(display, surface); egl Terminate(display); 这些是基本的 EGL 配置步骤。您可能需要根据您的 应用 程序需要进行修改。