X11 和 nVidia 驱动程序的奇怪 EGL 行为

Posted

技术标签:

【中文标题】X11 和 nVidia 驱动程序的奇怪 EGL 行为【英文标题】:Strange EGL behaviour with X11 and nVidia driver 【发布时间】:2019-10-02 08:10:06 【问题描述】:

我现在有一个奇怪的问题,我有这个使用 GTK2、OpenGL 和 EGL 的示例应用程序。我描述的奇怪行为只发生在带有官方 nVidia 驱动程序的 Linux 上的 nVidia GPU 上。在程序中你看到一个注释,如果你在代码中此时不使用glFlush OR glGetError,代码将不会绘制三角形,它只会显示红色(透明色)。如果你打电话给glGetErrorglFlush,它可以工作。

有人可以向我解释为什么会这样吗?代码如下:

#include <stdio.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <EGL/egl.h>
#include <GL/gl.h>

static EGLDisplay egl_display;
static EGLSurface egl_surface;
static EGLContext egl_context;

static void realize_cb (GtkWidget *widget)

    EGLConfig egl_config;
    EGLint n_config;
    EGLint attributes[] =  EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
                            EGL_NONE ;
    EGLint surf_attrs[] = 
        EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
        EGL_NONE
    ;

    egl_display = eglGetDisplay ((EGLNativeDisplayType) gdk_x11_display_get_xdisplay (gtk_widget_get_display (widget)));
    eglInitialize (egl_display, NULL, NULL);
    eglChooseConfig (egl_display, attributes, &egl_config, 1, &n_config);
    egl_surface = eglCreateWindowSurface (egl_display, egl_config, GDK_WINDOW_XID (gtk_widget_get_window (widget)), NULL);
    eglBindAPI (EGL_OPENGL_API);   
    egl_context = eglCreateContext (egl_display, egl_config, EGL_NO_CONTEXT, NULL);
    eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
    printf("GL Version: %s\n", glGetString(GL_VERSION));


static gboolean on_configure (GtkWidget *widget, GdkEvent *event, gpointer user_data)

    gtk_widget_queue_draw(widget);
    return FALSE;


static gboolean draw_cb (GtkWidget *widget, GdkEventExpose *expose, gpointer userdata)

    eglMakeCurrent (egl_display, egl_surface, egl_surface, egl_context);

    GtkAllocation alloc;
    gtk_widget_get_allocation(widget, &alloc);
    glViewport (0, 0, alloc.width, alloc.height);

    glClearColor (1, 0, 0, 1);
    glClearDepth(1.0);
    glClear (GL_COLOR_BUFFER_BIT);

    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    glOrtho (0, 100, 0, 100, 0, 1);

    glBegin (GL_TRIANGLES);
    glColor3f (1, 0, 0);
    glVertex2f (50, 10);
    glColor3f (0, 1, 0);
    glVertex2f (90, 90);
    glColor3f (0, 0, 1);
    glVertex2f (10, 90);
    glEnd ();

    /****************************
     * It does not matter if you call glGetError or glFlush here, if you do, it
     * works, if not, it only displays a red surface
     ****************************/
    //glGetError();
    //glFlush();
    eglSwapBuffers (egl_display, egl_surface);

    return TRUE;


int main (int argc, char **argv)

    GtkWidget *w;

    gtk_init (&argc, &argv);

    w = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_double_buffered (GTK_WIDGET (w), FALSE);
    g_signal_connect_after (G_OBJECT (w), "realize", G_CALLBACK (realize_cb), NULL);
    g_signal_connect (G_OBJECT (w), "expose-event", G_CALLBACK (draw_cb), NULL);
    g_signal_connect (G_OBJECT (w), "configure-event", G_CALLBACK (on_configure), NULL);
    gtk_widget_show (w);

    gtk_main ();

    return 0;

编译:

g++ -o gtkegl gtkegl.cc -lEGL -lGL $(pkg-config --libs --cflags gtk+-2.0) -lX11

【问题讨论】:

documentation for eglSwapBuffers 说“eglSwapBuffers 对上下文执行隐式刷新操作(glFlush 用于在交换之前绑定到表面的 OpenGL ES 或 OpenGL 上下文。”看起来像一个 Nvidia 错误。 好吧,即使 Swap 发出一个隐式的 Flush,显式调用它也不会造成太大的伤害:当命令缓冲区已经被刷新时发出,Flush 只是返回并且什么都不做。顺便说一句,幸运的是我有合适的硬件,所以我会试试这个代码。 已确认。 GL 版本:4.6.0 NVIDIA 418.56,GTX 980Ti。 很高兴它不仅发生在我身上:)。我也在 nvidia 论坛上发布了这个,但还没有任何反应。 @Nidhoegger ...有一个问题。 GTK+ 是必需的吗?罪魁祸首可能在 GDK 和 EGL 之间,因为我的 Xlib-only EGL 示例似乎没有表现出这个问题。 【参考方案1】:

eglSwapBuffers 是特定于线程上下文的。如果您以某种方式从另一个线程更改了渲染上下文,那么它会失败。

我看到几个可能的错误:

    您没有检查 eglMakeCurrent 返回值。它可能会失败。 您没有同步 draw_cb。它可以同时从不同的线程调用。 您从不同的地方调用 eglMakeCurrent。它们之间可能会发生冲突。

【讨论】:

在我的代码(以及上面的示例中)确保绘图仅在同一个线程中完成。同样在每次绘制之前,通过eglMakeCurrent 使上下文成为当前的。 我明白了,但你没有检查任何回报。 这是一个通常不包含错误检查的最小示例。我在这里得到了一个错误检查版本,并在我的生产代码中检查了错误

以上是关于X11 和 nVidia 驱动程序的奇怪 EGL 行为的主要内容,如果未能解决你的问题,请参考以下文章

我的OpenGL学习进阶之旅EGL简介

OpenGL ES 2 控制台帧缓冲光标

EGL 在处理程序中创建 iframe

使用 EGL 1.4 查询 OpenGL32.dll 版本问题

QXcbIntegration:无法创建平台 OpenGL 上下文,GLX 和 EGL 均未启用

EGL:创建 pBuffer 表面时是不是会创建 FBO?