几个相似的概念
-
OpenCV
从图像到数据,提供图像处理和视频处理的基础算法库,还涉及一些机器学习的算法,比如人机互动,物体识别,人脸识别,动作识别,运动跟踪,运动分析,汽车安全驾驶
-
OpenGL
从数据到图像,主要用于生成二维、三维图像,绘制合适的视觉图像给人看
-
OpenGL ES
OpenGL的子集,删减了一些低效的操作方式,但兼容性也更差一点
-
WebGL
基于 OpenGL ES 2.0 的 Javascript API,用于Web浏览器呈现交互式3D图形
-
Vulkan
免费开放的、跨平台的、底层的图形 API,旨在取代OpenGL
-
DirectX
windows平台上提升多媒体程序执行效率的API,就它不是跨平台的
OpenGL ES的使用场景
- 图片处理。比如图片色调转换、美颜等。视频滤镜、音频滤镜.
- 摄像头预览效果处理。比如美颜相机、恶搞相机等。
- 视频处理。摄像头预览效果处理可以,这个自然也不在话下了。
- 3D 游戏。比如神庙逃亡、都市赛车等。
OpenGL ES EGL
EGL 是渲染 API(如 OpenGL ES)和原生窗口系统之间的接口
不同平台有不同的EGL系统,windows上是WGL,Linux上是GLX,Apple OS上是AGL
EGL绘图步骤
- 获取 EGLDisplay 对象:eglGetDisplay()
- 初始化与 EGLDisplay 之间的连接:eglInitialize()
- 获取 EGLConfig 对象:eglChooseConfig()
- 创建 EGLContext 实例:eglCreateContext()
- 创建 EGLSurface 实例:eglCreateWindowSurface()
- 连接 EGLContext 和 EGLSurface:eglMakeCurrent()
- 使用 OpenGL ES API 绘制图形:gl_*()
- 切换 front buffer 和 back buffer 送显:eglSwapBuffer()
- 断开并释放与 EGLSurface 关联的 EGLContext 对象:eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- 删除 EGLSurface 对象:eglDestroySurface()
- 删除 EGLContext 对象:eglDestroyContext()
- 终止与 EGLDisplay 之间的连接:eglTerminate(EGLDisplay)
- 释放线程:eglReleaseThread()
示例代码
#include "ViceScreenDisplay.h"
namespace android {
static const char* kSystemAssets = "/system/etc/mmi/";
sp<SurfaceComposerClient> ViceScreenDisplay::session(){
return mSession;
}
int ViceScreenDisplay::readyToshow(){
//first ref
mSession = new SurfaceComposerClient();
status_t err = mSession->linkToComposerDeath(this);
SLOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
if (err == NO_ERROR) {
// Load the animation content -- this can be slow (eg 200ms)
// called before waitForSurfaceFlinger() in main() to avoid wait
ALOGD(" mSession->linkToComposerDeath NO_ERROR");
}
const char* root = getenv("ANDROID_ROOT");
String8 path(root);
path.appendPath(kSystemAssets);
mAssets.addAssetPath(path, NULL, false /* appAsLib */, true /* isSystemAsset */);
ALOGD("readyToshow Assets path = %s",path.string());
const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
ALOGD("runToshow displayIds = %d",(int)displayIds.size());
mDisplayToken = SurfaceComposerClient::getPhysicalDisplayToken(displayIds[1]);
if (mDisplayToken == nullptr){
ALOGD("runToshow mDisplayToken is nullptr");
return -1;
}
DisplayInfo dinfo;
status_t status = SurfaceComposerClient::getDisplayInfo(mDisplayToken, &dinfo);
if (status)
return -1;
// create the native surface
control = session()->createSurface(String8("showAtVice"),
dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
SurfaceComposerClient::Transaction t;
layer_state_t* ls = t.getLayerState(control);
DisplayState& ds(t.getDisplayState(mDisplayToken));
ALOGD("runToshow layerStack %d",ds.layerStack);
while(ds.layerStack != 4096){
ds = t.getDisplayState(mDisplayToken);
t.setLayerStack(control, 4096);
t.setDisplayLayerStack(mDisplayToken,4096);
Rect viceRect(0,0,1920,1280);
t.setDisplayProjection(mDisplayToken,0,viceRect,viceRect);
ALOGD("runToshow get the layerStack %d layerstate %d",ds.layerStack,ls->layerStack);
}
t.setLayer(control, 0x40000000)
.apply();
sp<Surface> s = control->getSurface();
// initialize opengl and egl
const EGLint attribs[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 0,
EGL_NONE
};
EGLint w, h;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;
//1.获取显示设备,使用默认的渲染类型
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY || eglGetError() != EGL_SUCCESS)
ALOGD("eglGetDisplay fail");
else
ALOGD("eglGetDisplay success");
//2.初始化EGL
EGLBoolean initialize = eglInitialize(display, nullptr, nullptr);
//3.自定义配置
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
//5.创建窗口渲染区域,相当于创建画布,用户想要绘制的信息都要先绘制到EGLSurface上,然后通过EGLDisplay显示
surface = eglCreateWindowSurface(display, config, s.get(), nullptr);
//4.创建上下文对象,该对象包含了操作所需要的所有状态信息,没有该对象,OpenGL指令就没有执行的环境
context = eglCreateContext(display, config, nullptr, nullptr);
//获取画布的宽高
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
//6.将创建的surface,display,context进行绑定,连接,因为一个应用程序可能创建多个context
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
return NO_INIT;
mDisplay = display;
mContext = context;
mSurface = surface;
mWidth = w;
mHeight = h;
mFlingerSurfaceControl = control;
mFlingerSurface = s;
mTargetInset = -1;
return 0;
}
int ViceScreenDisplay::clear(){
ALOGD("clear");
//9.将surface,display,context解绑
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
//11.销毁context
eglDestroyContext(mDisplay, mContext);
//10.销毁surface
eglDestroySurface(mDisplay, mSurface);
mFlingerSurface.clear();
mFlingerSurfaceControl.clear();
//12.终止显示
eglTerminate(mDisplay);
//13.释放线程
eglReleaseThread();
return 0;
}
int ViceScreenDisplay::runToshow(){
initTexture(&mAndroid[0], mAssets, "fct-display.png");
ALOGD("init texture result,mAndroid[0].w=%d, mAndroid[0].h=%d, mAndroid[0].name=%u ",mAndroid[0].w,mAndroid[0].h,mAndroid[0].name);
// clear screen
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(mDisplay, mSurface);
glEnable(GL_TEXTURE_2D);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
const GLint xc = (mWidth - mAndroid[0].w) / 2;
const GLint yc = (mHeight - mAndroid[0].h) / 2;
const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
updateRect.height());
// Blend state
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
while(1) {
glDisable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
//7.绘制图形
glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
//ALOGD("drawing graphic,mDisplay:%s, mSurface:%s",mDisplay,mSurface);
//8.将EGLSurface中的数据交换到EGLDisplay,将绘制的内容输出到屏幕进行显示
ALOGD(" start drawing...");
EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
ALOGD(" drawing result,res:%u",res);
if (res == EGL_FALSE){
ALOGD(" drawing false");
break;
} else if (res == EGL_TRUE){
ALOGD(" drawing success");
} else {
ALOGD(" drawing unknown");
}
}
glDeleteTextures(1, &mAndroid[0].name);
return 0;
}
status_t ViceScreenDisplay::initTexture(Texture* texture, AssetManager& assets,
const char* name) {
Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
if (asset == nullptr){
ALOGD("initTexture NO_INIT");
return NO_INIT;
}
SkBitmap bitmap;
sk_sp<SkData> data = SkData::MakeWithoutCopy(asset->getBuffer(false),
asset->getLength());
sk_sp<SkImage> image = SkImage::MakeFromEncoded(data);
image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode);
asset->close();
delete asset;
const int w = bitmap.width();
const int h = bitmap.height();
const void* p = bitmap.getPixels();
GLint crop[4] = { 0, h, w, -h };
texture->w = w;
texture->h = h;
glGenTextures(1, &texture->name);
glBindTexture(GL_TEXTURE_2D, texture->name);
switch (bitmap.colorType()) {
case kAlpha_8_SkColorType:
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
GL_UNSIGNED_BYTE, p);
break;
case kARGB_4444_SkColorType:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
GL_UNSIGNED_SHORT_4_4_4_4, p);
break;
case kN32_SkColorType:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
GL_UNSIGNED_BYTE, p);
break;
case kRGB_565_SkColorType:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
GL_UNSIGNED_SHORT_5_6_5, p);
break;
default:
break;
}
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
return NO_ERROR;
}
void ViceScreenDisplay::binderDied(const wp<IBinder>&)
{
// woah, surfaceflinger died!
ALOGD("SurfaceFlinger died, exiting...");
// calling requestExit() is not enough here because the Surface code
// might be blocked on a condition variable that will never be updated.
kill( getpid(), SIGKILL );
}
ViceScreenDisplay::~ViceScreenDisplay() {
ALOGD("~ViceScreenDisplay");
}
}
;// namespace android