最近在折腾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;
....
...
}