最近工作比较忙,忙了2个多月,有一段时间没有写笔记了. 这段时间的工作内容接触到利用GPU处理图像,而我本身对数字图像处理一直比较感兴趣,顾借这次机会学习一些数字图像处理相关的技术.
数字图像一般像素数据较大,CPU设计的目的是通用计算,更擅长的是逻辑控制. 目前智能设备中为了更流畅的显示,一般都配有GPU, GPU的运算单元非常多,且数字图像一般都是逐个逐个像素处理,天然能利用GPU的并发能力. Android平台,目前能利用GPU计算的开源库有OpenAL, opengles 2.0等. android平台使用openCL不是非常方便, 而利用opengles 2.0的可编程管线就方便多了. 我们可以自己写着色器(shader)来处理图像.当然,也可以把其他可以并行处理的任务伪装成图像处理,利用GPU加速.
我将运行在android系统上,但不是运行在Dailvk虚拟机上,不调用任何android framework api的无窗口的本地程序称为android控制台程序 (它和linux控制台程序类似, android 的 C 运行时库是bionic, 而linux是 glibc.它和linux控制台应用程序最大的区别是Makefile写法和格式不一样). 有时候,从运行效率,调试和平台兼容等方面考虑,控制台程序则更适合某些场景. Android控制台程序需要把Android.mk文件的最后一行改成
include $(BUILD_EXECUTABLE)
而我们平时编译成动态库的Android.mk是这样写的
include $(BUILD_SHARED_LIBRARY)
.c文件的main函数写好了,NDK中也有GLES2相关的头文件,一开始我满怀希望的开始调用opengles 2.0 的接口.发现运行结果没有啥效果.我猜测该手机是不是不支持opengles 2.0, 可能只支持opengl 1.0. 无奈,只好看看获取opengl 的版本,打印看看
const GLubyte* version = glGetString(GL_VERSION);
if (NULL != version) {
Log("%s\n", version);
}
else {
Log("version info: NULL \n");
}
发现每次取得都是NULL.感觉opengl接口都没有调用成功.
之所以不能获取opengles的版本信息,是因为opengles 没有初始化,也就是没有准备opengl运行环境.opengl是跨平台的3D图形接口,与具体的操作系统显示窗口无关,但是通过opengl绘制的图像,需要保存在存储空间 (注意:不一定是内存,也可能是显存) 或者在具体的操作系统窗口显示.这时需要EGL实现跨平台. EGL 是 OpenGL ES 和底层 Native 平台视窗系统之间的接口。EGL是有统一规范的. 只有初始化EGL, 为opengl创建存储空间和状态机环境,opengl才能运行. 初始化EGL的步骤一般是固定的:
该方法是和系统平台相关的.
相关函数 eglGetDisplay()
该操作会进行一些内部初始化工作,并传回EGL的版本号.
相关函数 eglInitialize()
所谓Config就是EGL的相关参数,Config有很多的Attribute, 这些 Attribute决定opengl的格式和能力.
相关函数
eglGetConfigs()
eglGetConfigAttrib()
eglChooseConfig()
surface就是一块存储空间,供opengl存储处理后的数据.类型可以是在线渲染用于显示的framebuffer, 也可是内存的中的位图,也可以是用于离线渲染的显存.
相关函数:
eglCreateWindowSurface()
eglCreatePbufferSurface()
eglCreatePixmapSurface()
opengl的渲染管线从程序的角度来看就是一个状态机, context就是代表opengl的状态机.
相关函数 eglCreateContext()
相关函数
eglMakeCurrent()
至此EGL初始化完成, opengles运行环境准备好了.
这里只提到了相关的函数,具体参数和调用方法请参考相关文档.
其中选择配置很重要,不然可能会失败,我在这里花了很多时间.
处理图像的核心就是shader. shader成功编译链接后,会被GPU执行. shader主要分顶点shader和像素shader.关于shader的更多知识我需要持续学习.这里我只简单的记录如何创建shader.
相关函数glCreateShaderObject() , glShaderSource()
相关函数glCompileShader()
相关函数glCreateProgram()
相关 glAttachShader() , glLinkProgram()
相关函数 glUseProgram()
opengles提供了接口与shader中attribute 变量和uniform变量进行交互.
这些方法有: glGetAttribLocation() , glGetUniformLocation(), glVertexAttribPointer(), glUniform()等等函数.
到这来整个流程都完成了,剩下的核心就是写shader处理图像了.opengles 2.0 和 shader 我也是学习阶段, 我在github上开了一个仓库学习shader,欢迎感兴趣的朋友一起讨论,互相学习.