【发布时间】:2021-02-03 12:17:35
【问题描述】:
如何创建在 EGL 中工作的原生 X11 窗口?通过 eglIntro (https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglIntro.xhtml) 几乎没有关于此事的文档。或者,有没有办法通过 EGL 本身创建本机窗口?有一个 EGLNativeWindowType 我认为可以用来代替 X11 的原生窗口类型。
【问题讨论】:
如何创建在 EGL 中工作的原生 X11 窗口?通过 eglIntro (https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglIntro.xhtml) 几乎没有关于此事的文档。或者,有没有办法通过 EGL 本身创建本机窗口?有一个 EGLNativeWindowType 我认为可以用来代替 X11 的原生窗口类型。
【问题讨论】:
不,EGL 本身不提供 Xlib 包装器。您必须自己创建窗口。
以下是帮助您入门的最小示例。它指的是 GLES2,但它也应该适用于 GLES1。
首先,声明 Xlib 对象(显示和窗口)。
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <GLES2/gl2.h>
#include <EGL/egl.h>
// Native handles for window and display
Window win;
Display* xdisplay;
// EGL-related objects
EGLDisplay egl_display;
EGLConfig egl_conf;
EGLContext egl_context;
EGLSurface egl_surface;
int init_egl()
{
EGLint attr[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
// EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, /* If one needs GLES2 */
EGL_NONE
};
EGLint num_config;
EGLint major, minor;
EGLint ctxattr[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
egl_display = eglGetDisplay( (EGLNativeDisplayType) xdisplay );
if ( egl_display == EGL_NO_DISPLAY ) {
printf("Error getting EGL display\n");
return 0;
}
if ( !eglInitialize( egl_display, &major, &minor ) ) {
printf("Error initializing EGL\n");
return 0;
}
printf("EGL major: %d, minor %d\n", major, minor);
/* create EGL rendering context */
if ( !eglChooseConfig( shell->egl_display, attr, &shell->egl_conf, 1, &num_config ) ) {
printf("Failed to choose config (eglError: %x)\n", eglGetError());
return 0;
}
if ( num_config != 1 ) {
return 0;
}
egl_surface = eglCreateWindowSurface ( egl_display, egl_conf, win, NULL );
if (egl_surface == EGL_NO_SURFACE ) {
printf("CreateWindowSurface, EGL eglError: %d\n", eglGetError() );
return 0;
}
egl_context = eglCreateContext ( egl_display, egl_conf, EGL_NO_CONTEXT, ctxattr );
if ( egl_context == EGL_NO_CONTEXT ) {
printf("CreateContext, EGL eglError: %d\n", eglGetError() );
return 0;
}
return 1;
}
您将从main 函数调用X 事件处理程序过程。我留下了对printf 调用的评论,以显示事件值的命名方式,因此无需查找文档。如果“事件循环”的概念不清楚,那么我建议阅读通用 UI 事件处理。
void process_xevent(XEvent xev) {
// XNextEvent( xdisplay, &xev );
switch (xev.type)
{
case MotionNotify:
// printf("motion: %d %d\n", xev.xbutton.x, xev.xbutton.y);
break;
case KeyRelease:
// printf("rel (%d)\n", XLookupKeysym (&xev.xkey, 0));
break;
case KeyPress:
// printf("keypress (%d)\n", XLookupKeysym (&xev.xkey, 0));
break;
case ButtonPress:
// printf("BPress: state = %d, button = %d, x = %d, y = %d\n", xev.xbutton.state, xev.xbutton.button, xev.xbutton.x, xev.xbutton.y);
// printf("Type=%d\n", (int)xev.xbutton.type);
break;
case ButtonRelease:
// printf("BRelease: state = %d, button = %d, x = %d, y = %d\n", xev.xbutton.state, xev.xbutton.button, xev.xbutton.x, xev.xbutton.y);
// printf("Type=%d\n", (int)xev.xbutton.type);
break;
}
}
最后,在 main() 例程中创建并打开 display/Xwindow。
int main()
{
int egl_error;
Window root;
XSetWindowAttributes swa;
/* open standard display (primary screen) */
xdisplay = XOpenDisplay ( NULL );
if ( xdisplay == NULL ) {
printf("Error opening X display\n");
return 0;
}
一旦您打开了显示,就会创建并显示窗口。
最后,在 main() 例程中创建并打开 display/Xwindow。
// get the root window (usually the whole screen)
root = DefaultRootWindow( shell->xdisplay );
// list all events this window accepts
swa.event_mask =
StructureNotifyMask |
ExposureMask |
PointerMotionMask |
KeyPressMask |
KeyReleaseMask |
ButtonPressMask |
ButtonReleaseMask;
// Xlib's window creation
win = XCreateWindow (
xdisplay, root, 0, 0, 640, 480, 0,
CopyFromParent, InputOutput, CopyFromParent, CWEventMask,
&swa );
XMapWindow ( xdisplay , win ); // make window visible
XStoreName ( xdisplay , win , "EGL" );
当你有窗口时,初始化 EGL。
egl_error = init_egl();
if (!egl_error) {
return 1;
}
一旦你有了 EGL 和 Xlib 对象,你就可以开始事件处理循环了。
while (1) {
int keycode;
XEvent xev;
if ( XPending ( xdisplay ) )
if (XCheckWindowEvent(shell->xdisplay, shell->win, global_event_mask, &xev))
process_xevent(shell, xev);
/* if (should_exit) { break; } // set some global flag if you want to exit */
eglMakeCurrent( egl_display, egl_surface, egl_surface, egl_context );
/* Call OpenGL as you see fit */
/* get rendered buffer to the screen */
eglSwapBuffers ( egl_display, egl_surface );
}
// deinitialize
}
这应该可以帮助您入门。该代码是从一个较大的项目中提取的,因此在删除不相关的内容时可能会引入拼写错误。
总结答案并更准确地说,这里EGLNativeWindowType 专门用于X11/Xlib.h 标头中的Window,EGLNativeDisplayType 是Display*。
更简单的方法可能是使用libxcb,但我没有任何经过测试的示例代码。 GLFW library 可以成为依赖于操作系统的 OpenGL 上下文创建例程的有用来源。
【讨论】: