在一个多窗口的图形化操作系统中,显示服务器的任务就是组织这些窗口展现给用户。实际的显示服务器有Linux世界基于X11协议的XServer或者Wayland协议的Weston,还有Android里的SurfaceFlinger。但是除了显示,他们同时包含了输入管理(鼠标、键盘等)的功能,本文主要还是讨论图形显示部分,通过将显示服务器用到的技术分解,实际来看看如何实现一个显示服务器。

需求分析

在命令行Linux操作系统中实现一个支持GPU图形应用的显示服务器:

  1. 每个图形应用绘制到一个缓冲(Buffer)
  2. 图形应用将这个缓冲交给显示服务器组装成帧缓冲(Framebuffer)
  3. 显示服务器将帧缓冲显示到显示器上
图一:显示服务器需求

一个简单的OpenGL应用

这是一个在Linux X11系统下简单的OpenGL应用【1】,效果是在一个X11窗口中绘制一个红色三角形。我们看看OpenGL应用是如何跟显示服务器(XServer)交互的。注意这里忽略了无关参数和代码,下同。

Display

首先用EGL从X11的Display和Window创建Context,然后用OpenGL进行实际绘制,最后用EGL的eglSwapBuffers将绘制好的缓冲交给XServer去显示。

这个例子的目的,一是看看OpenGL应用和显示服务器的接口,二是看看在显示服务器那边,我们也想用OpenGL做窗口组装的话还需要什么。

以下三个例子会展示如何解决:

  1. 在没有显示服务器(自己就是显示服务器)的情况下创建Context进行OpenGL绘制
  2. 将绘制好的帧缓冲给显示器显示
  3. 应用将缓冲交给显示服务器去组装

无显示服务器的OpenGL绘制

例二【2】是在没有显示服务器的情况下,用EGL+GBM做OpenGL绘制的例子:

int

GBM是一个GPU缓冲管理的API,可以直接从GPU的设备文件(/dev/dri/renderD128)创建一个gbm_device,然后再创建一个代表GPU缓冲的gbm_surface。支持EGL_MESA_platform_gbm扩展【5】的EGL接口可以利用gbm_device和gbm_surface来创建EGLDisplay和EGLSurface。接下来就和EGL+X11那个例子一样了。

显示器显示帧缓冲

显示帧缓冲可以参考例三【3】,首先打开GPU设备文件/dev/dri/card0(这个文件同时支持绘图和显示,而/dev/dri/renderD128只有绘图功能)。然后就能调用KMS接口获取当前连着显示器的Connector/Encoder/Crtc,这三个模块的功能:Crtc从帧缓冲读取数据给Encoder,Encoder编码数据给Connector,Connector输出HDMI/DP/VGA接口的信号。最后drmModeFBPtr代表Crtc要读取的帧缓冲。当前drmModeFBPtr所指向的帧缓冲里面应该是命令行界面,我们需要为自己的绘图缓冲创建一个新的drmModeFBPtr。

int

在上一个例子中我们将图形绘制在了gbm_surface上,这里就从gbm_surface创建一个新的drmModeFBPtr然后取代原来的命令行drmModeFBPtr给drmModeCrtcPtr显示:

struct

应用和显示服务器间传递缓冲

现在我们知道自己实现的应用和显示服务器端如何用OpenGL进行绘制,而且显示服务器如何将绘制好的帧缓冲拿去显示。最后的一个问题就是应用如何将缓冲传递给显示服务器用于组装。应用和显示服务器是两个独立进程,这个需求只能用进程间通信来解决,但是图形系统所需传递的数据量巨大(一帧往往需要几MB,每秒60帧,就是上百MB/s,这还只是一个应用), 如果用传统的进程间通信方法比如Socket和System V IPC,性能会很差。所以我们需要一种零拷贝的进程间共享缓冲的方式。

例四【4】展示了使用dma-buf+unix local socket达到应用和显示服务器间零拷贝传递缓冲的实现。里面是应用部分的代码,是显示服务器部分的代码。首先我们创建两个进程分别代表应用和显示服务器,用socketpair建立unix local socket连接(出于演示方便,真实的显示服务器会用完整的socket listen/bind/connect/accept流程):

int

然后是应用端,我们用GBM接口获得缓冲的文件描述(File Descriptor),这个文件描述只是一个句柄,在Linux内核里代表了一个关联缓冲的dma-buf结构体。我们只需要在进程间传递这个文件描述就可以共享他所代表的缓冲而不用拷贝。传递文件描述的方法就是这个Unix Local Socket的sendmsg函数。

// 获得缓冲

最后是显示服务器端,用recvmsg接收应用传送来的文件描述,然后还原为gbm_bo。支持EGL_KHR_image_pixmap扩展【6】的EGL可以将gbm_bo转换为EGLImageKHR(对于支持EGL_EXT_image_dma_buf_import扩展【7】的EGL可以直接将文件描述转换为EGLImageKHR)。支持GL_OES_EGL_image扩展【8】的OpenGL可以将EGLImageKHR转换为贴图,这样就能将应用的缓冲作为一个OpengGL的贴图进行组装成帧缓冲的绘图操作了。

// 接收dma-buf

结语

本文介绍的这些技术是显示服务器实现的基础,下一篇文章我们会讨论更深入的应用和显示服务器间的同步问题。

引用

  1. 例一:OpenGL应用
  2. 例二:无显示服务器OpenGL
  3. 例三:显示帧缓冲
  4. 例四:缓冲传递
  5. EGL_MESA_platform_gbm扩展
  6. EGL_KHR_image_pixmap扩展
  7. EGL_EXT_image_dma_buf_import扩展
  8. GL_OES_EGL_image扩展

android studio 显示图形_显示服务器实现(一)相关推荐

  1. android studio logcat 无筛选 显示全部日志 无应用包名区分

    android studio logcat 无筛选 显示全部日志 无应用包名区分 不显示所有应用 出现这个情况后很多同学无法解决,重启adb,重启studio,重启电脑,都是没用的... 其实是有个开 ...

  2. Android Studio Design界面不显示layout控件的解决方法

    Android Studio Design界面不显示layout控件的解决方法 参考文章: (1)Android Studio Design界面不显示layout控件的解决方法 (2)https:// ...

  3. android自定义控件不显示,解决Android Studio Design界面不显示layout控件的问题

    Android Studio更新到3.1.3后,发现拖到Design中的控件在预览界面中不显示: 解决办法: 在Styles.xml中的parent="..."中的Theme前添加 ...

  4. Android studio右侧Gradle窗口显示 nothing to show

    Android studio右侧Gradle窗口显示 nothing to show 前言 解决方法 完事 前言 今天在测试开发SDK的时候,玩了几次打包后,发现Android studio右侧Gra ...

  5. 用Android studio完成简单的显示时间

    用用Android studio完成简单的显示时间,并完成基础的布局改变,如字体大小,字体颜色等等问题. 在value中,颜色设置,可以自定义颜色. dimens中完成字体大小的设置. 完成日历设置: ...

  6. Android Studio模拟器启动时显示Could not automotically detect an ADB binary

    Android Studio模拟器启动时,会显示Could not automotically detect an ADB binary.的提示信息如图1所示. 图1 提示信息 图1中的提示信息的意思 ...

  7. android studio高德地图的显示于定位(附带逆地理编码围栏)

    首先注册高德成为开发者(打开高德地图,点击底部的开发者平台),创建应用,按照要求填写相应信息 网站:http://lbs.amap.com/api/android-sdk/guide/create-p ...

  8. android studio build variants,Android Studio毕业生风格没有显示在Build Variants中

    根据我的理解,Android Studio应该在"构建变体"面板中显示构建变体和风格的整个矩阵. 我创建了一个空项目,并附带以下build.gradle. buildscript ...

  9. Android Studio设置代理后显示:Cause: dl.google.com:443 failed to respond错误

    以前在Android Studio 的Preference设置中,设置了socks代理后,就能够正常的进行更新和自动下载依赖,最近老是有问题,今天在添加了新的依赖后,点编译按钮就显示 Cause: d ...

最新文章

  1. 不能定义声明dllimport_C#:多个声明的一个属性(DLLImport)
  2. 音视频技术开发周刊 94期
  3. Reactor中的Thread和Scheduler
  4. php 文件写入磁盘错误,Linux磁盘读写故障的通常处理流程
  5. MCU,RTOS,物联网之间的关系。
  6. [Java基础]内部类基础
  7. 使用SpringData出现java.lang.AbstractMethodError
  8. DXUT框架剖析(11)
  9. 要毕业了,整理要卖的书,发现大一大二的时候的涂鸦
  10. itunes gift card apple id 充值接口API秒冲接口收藏
  11. Oblog4.5跨站漏洞
  12. 2022.8.22 小W的玻璃弹珠 题解
  13. tolua++实现分析
  14. 使用Rancher的RKE快速部署Kubernetes集群
  15. WebRTC中的信令和内网穿透技术 STUN / TURN
  16. 数据挖掘——认识数据
  17. Android应用开发获取手机电池电量的简单方法
  18. GSM6.10转码与wav文件保存
  19. Python可视化:中国环保股上市公司市值Top20强
  20. 几款好用的子域名收集工具

热门文章

  1. 1051. 复数乘法 (15)
  2. 【C++深度剖析教程9】初探C++标准库
  3. Beta冲刺(9/7)——2019.5.31
  4. JS 判断两个时间的大小(可自由选择精确度:天,小时,分钟,秒)
  5. [BZOJ 5074] 小B的数字
  6. hdoj-3342-Legal or Not(拓扑排序)
  7. SVN中如何去除版本控制器
  8. 正则表达式在iOS中的运用
  9. 微信公众账户模拟登陆后的一系列操作
  10. Jetty 服务器架构分析(中)