2019独角兽企业重金招聘Python工程师标准>>>
最近在折腾EGL1.1和OpenGL ES1.1。想实现OpenGL ES与本地API或者其他库的API的混合渲染,遇到了一些麻烦。
平台:Windows,WinCE
图形库:AGG,OpenGL ES
首先是使用AGG库,先画了2D的场景,想在上面放置一些3D的物体。最好的方式是AGG和OpenGL能够公用一个缓冲区。AGG先在这个缓冲区上渲染,然后交给OpenGL渲染。
EGL中有几种创建缓冲区的方式eglCreateWindowSurface,eglCreatePBufferSurface,eglCreatePixmapSurface。
这几种的区别大致如下:
绑定本地窗口句柄 NativeWindowType | 绑定本地类型缓冲区NativeBitmapType | 单缓冲区还是双缓冲区 | 备注 | |
window surface(on-screen) | 是 | 否 | 双缓冲区 | 默认在back buffer中渲染,需要通过eglSwapBuffer来把渲染的结果显示到屏幕。也有EGL_RENDER_TYPE可设置为EGL_SINGLE_BUFFER但这个要看ES的实现。不一定有效,在EGL1.1之前没有这个参数 |
PBuffer(off-screen) | 否 | 否 | 单缓冲区 | 不绑定任何本地的东西。需要指定EGL_WIDTH,EGL_HEIGHT参数,来创建对应的大小。不可以被显示,调用eglSwapBuffer是无效的。这种缓冲区可以直接用作纹理数据,因为直接在显存中分配的。用完记得释放,显存是珍稀资源! |
pixmapbuffer(off-screen) | 否 | 是 | 单缓冲区 | 绑定本地的像素缓冲区,本地API也可以使用这一块缓冲区。opengl ES在这上渲染就直接渲染到该缓冲区汇中。 |
目前只试验了一种方式成功了。(共用一个缓冲区的方法行不通)
我先创建了一个缓冲区PBuffer surface或者 windows surface ,pixmapsurface都行。。然后在这个PBuffer上进行OpenGL ES的绘制3D物体。再通过glReadPixel的方式读取,缓冲区的数据作为图像数据,再使用AGG的绘图方法进行贴图。这样就简单的实现了AGG和OPENGL ES的交互。 eglCopyBuffer应该也是可以的。还没进行测试。还需要继续研究.
简单的初始化流程:
bool CGLGraphics::InitGLES(void *hwnd)
{TIME_STAT;timeLogger.Log(_T("InitGLES."));EGLConfig configs[10];EGLint matchingConfigs;EGLint configAttribs[] = {EGL_SURFACE_TYPE, EGL_PIXMAP_BIT,EGL_CONFORMANT, EGL_OPENGL_ES_BIT,EGL_NONE};EGLint aEGLContextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 1,EGL_NONE};m_hwnd = hwnd;m_hdc = ::GetDC((HWND)m_hwnd);EGLDisplay glesDisplay = eglGetDisplay((NativeDisplayType)m_hdc); if(!eglInitialize(glesDisplay, NULL, NULL)){timeLogger.Log(_T("eglInitialize Failed!"));return false;}EGLint buffersize = 0;EGLint config_num = 0;eglGetConfigs(glesDisplay, configs, 10, &config_num);eglGetConfigAttrib(glesDisplay, configs[0], EGL_BUFFER_SIZE, &buffersize);timeLogger.Log(_T("display buffer size is %d\n"), buffersize);eglChooseConfig(glesDisplay, configAttribs, NULL, 10, &matchingConfigs); if(!eglChooseConfig(glesDisplay, configAttribs, &configs[0], 10, &matchingConfigs)){return false;}EGLint surfaceAttr[] = {//EGL_RENDER_BUFFER,EGL_SINGLE_BUFFER, //EGL1.1不支持,支持的话开了这个直接用glFlush就可以了EGL_NONE};EGLSurface glesSurface = eglCreateWindowSurface(glesDisplay, configs[0], (NativeWindowType)m_hwnd, surfaceAttr); if(!glesSurface){EGLint errCode = eglGetError();tstring err;switch (errCode){case EGL_NO_SURFACE:err = _T("no surface");break;case EGL_BAD_DISPLAY:err = _T("bad display"); break;case EGL_BAD_CONFIG:err = _T("bad config"); break;case EGL_BAD_ATTRIBUTE:err = _T("bad ATTRIBUTE"); break;case EGL_BAD_MATCH:err = _T("bad Match"); break;}timeLogger.Log(err.c_str());glesSurface = eglCreateWindowSurface(glesDisplay, configs[0], (NativeWindowType)m_hwnd, NULL);if (!glesSurface){ return false;}}EGLContext glesContext = eglCreateContext(glesDisplay, configs[0], EGL_NO_CONTEXT, aEGLContextAttributes); if(!glesContext){glesContext = eglCreateContext(glesDisplay, configs[0], EGL_NO_CONTEXT, NULL);if (!glesContext){timeLogger.Log(_T("eglCreateContext Failed!")); return false;}} if (!eglMakeCurrent(glesDisplay, glesSurface, glesSurface, glesContext)){EGLint errCode = eglGetError();tstring err;switch (errCode){case EGL_BAD_ALLOC :err = _T(" EGL_BAD_ALLOC "); break;case EGL_BAD_DISPLAY:err = _T("bad display"); break;case EGL_BAD_CONFIG:err = _T("bad config"); break;case EGL_BAD_NATIVE_PIXMAP :err = _T("bad EGL_BAD_NATIVE_PIXMAP "); break;case EGL_BAD_NATIVE_WINDOW :err = _T(" EGL_BAD_NATIVE_WINDOW "); break;case EGL_BAD_CURRENT_SURFACE :err = _T(" EGL_BAD_CURRENT_SURFACE "); break;case EGL_BAD_MATCH:err = _T("bad Match"); break;case EGL_CONTEXT_LOST :err = _T("EGL_CONTEXT_LOST "); break;}timeLogger.Log(err.c_str());timeLogger.Log(_T("eglMakeCurrent Failed!"));return false;}m_display = glesDisplay;m_surface = glesSurface;
....
...}