如何尽可能获取有关OpenGL上下文的信息

3

大家好,感谢您花时间阅读这篇文章!

我正在编写一款使用GTK2/3 + OpenGL开发的程序,我已经成功地运行了两个版本:

  • (a) GTK+2 + GtkGlext扩展 -> 运行得非常好!
  • (b) GTK+3 + LibX11 -> 运行良好!

除了(a)中的渲染速度明显快于(b),其他都看起来很正常...我不知道原因在哪里。以下是一些创建OpenGL上下文所使用的代码段示例:

  • (a)

    // To create the context, and the associated GtkWidget 
    
    GdkGLConfig * glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGBA | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE);
    GtkWidget * drawing_area = gtk_drawing_area_new ();
    gtk_widget_set_gl_capability (drawing_area, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE);
    g_signal_connect (G_OBJECT (drawing_area), "expose-event", G_CALLBACK (on_expose), data);
    
    // And later on to draw using the OpenGL context: 
    
    gboolean on_expose (GtkWidget * widg, GdkEvent * event, gpointer data)
    {
      GdkGLContext * glcontext  = gtk_widget_get_gl_context (widg);
      GdkGLDrawable * gldrawable = gtk_widget_get_gl_drawable (widg);
      if (gdk_gl_drawable_gl_begin (gldrawable, glcontext))
      {
        // OpenGL instructions to draw here !
        gdk_gl_drawable_swap_buffers (view -> gldrawable);
        gdk_gl_drawable_gl_end (view -> gldrawable);
      }
      return TRUE;
    }
    
  • (b)

    // To create the GtkWidget 
    
     GtkWidget * drawing_area = gtk_drawing_area_new ();
     // Next line is required to avoid background flickering
     gtk_widget_set_double_buffered (drawing_area, FALSE);
     g_signal_connect (G_OBJECT (drawing_area), "realize", G_CALLBACK(on_realize), data);
     g_signal_connect (G_OBJECT (drawing_area), "draw", G_CALLBACK(on_expose), data);
    
    // To create the OpenGL context
    
    GLXContext glcontext;
    
    G_MODULE_EXPORT void on_realize (GtkWidget * widg, gpointer data)
    {
      GdkWindow * xwin = gtk_widget_get_window (widg);
      GLint attr_list[] = {GLX_DOUBLEBUFFER,
                           GLX_RGBA,
                           GLX_DEPTH_SIZE, 16,
                           GLX_RED_SIZE,   8,
                           GLX_GREEN_SIZE, 8,
                           GLX_BLUE_SIZE,  8,
                           None};
       XVisualInfo * visualinfo = glXChooseVisual (GDK_WINDOW_XDISPLAY (xwin), gdk_screen_get_number (gdk_window_get_screen (xwin)), attr_list);
       glcontext = glXCreateContext (GDK_WINDOW_XDISPLAY (xwin), visualinfo, NULL, TRUE);
       xfree (visualinfo);
    }
    
    // To Draw using the OpenGL context
    
    G_MODULE_EXPORT gboolean on_expose (GtkWidget * widg, cairo_t * cr, gpointer data)
    {
      GdkWindow * win = gtk_widget_get_window (widg);
      if (glXMakeCurrent (GDK_WINDOW_XDISPLAY (xwin), GDK_WINDOW_XID (xwin), glcontext))
      {
         // OpenGL instructions to draw here !
         glXSwapBuffers (GDK_WINDOW_XDISPLAY (win), GDK_WINDOW_XID (win));
       }
       return TRUE;
    }
    
尝试理解为什么(a)比(b)更快,我下载了GtkGLext库的源代码并阅读了它们,发现命令与对X11的调用完全相同。现在我的想法是,(b)中以下一行可能是原因:
gtk_widget_set_double_buffered (drawing_area, FALSE);

渲染出了问题,我无能为力... 或者OpenGL上下文之间存在差异,这可能解释我注意到的行为。如果我按照这个方向进行跟进,我需要尽可能详细地比较两个上下文...到目前为止,我选择了似乎是获取信息的最常见方式:

OpenGL Version                  : 3.0 Mesa 12.0.3
OpenGL Vendor                   : nouveau
OpenGL Renderer                 : Gallium 0.4 on NVCF
OpenGL Shading Version          : 1.30

Color Bits (R,G,B,A)            : 8, 8, 8, 0
Depth Bits                      : 24
Stencil Bits                    : 0
Max. Lights Allowed             : 8
Max. Texture Size               : 16384
Max. Clipping Planes            : 8
Max. Modelview Matrix Stacks    : 32
Max. Projection Matrix Stacks   : 32
Max. Attribute Stacks           : 16
Max. Texture Stacks             : 10

Total number of OpenGL Extensions   : 227
Extensions list:
     N°1    :   GL_AMD_conservative_depth
     N°2    :   GL_AMD_draw_buffers_blend
 ...

但两种上下文返回的信息完全相同...
感谢您已经到达那里...现在我的问题是:
有没有办法输出尽可能多的关于OpenGL上下文的信息,如何?
我欢迎您对我正在做的事情提出任何其他建议!
S.
PS:我正在使用GTK3的GtkGLArea小部件,但正如这里所述,我还没有到达那里。
[编辑]一些OpenGL指令:
// OpenGL instructions to draw here !

glLoadIdentity (); 
glPushMatrix ();
// d is the depth ... calculated somewhere else
glTranslated (0.0, 0.0, -d); 
// Skipping the rotation part for clarity, I am using a quaternion
rotate_camera (); 
// r, g, b and a are GLFloat values
glClearColor (r,g,b,a); 
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 
glDisable (GL_LIGHTING);
int i;
// nbds is the number of chemical bonds 
GLfloat * lineVertices;
// This is "roughly" what I do to draw chemical bonds, to give you an idea
for (i=0; i<nbds;i++)
{
   // get_bonds (i) gives backs a 6 float array
   lineVertices = get_bonds(i);
   glPushMatrix(); 
   glLineWidth (1.0); 
   glEnableClientState (GL_VERTEX_ARRAY); 
   glVertexPointer (3, GL_FLOAT, 0, lineVertices); 
   glDrawArrays (GL_LINES, 0, 2); 
   glDisableClientState (GL_VERTEX_ARRAY); 
   glPopMatrix();
}
glEnable (GL_LIGHTING);

[/EDIT]


据我所知,GTK端的双缓冲仅仅是为了将影响GTK小部件缓冲区的所有内容离屏渲染,然后在之后呈现。我不明白为什么这会以任何方式干扰GLX,或者为什么它应该施加严重的惩罚。您确定第二种情况下获得了直接渲染上下文吗?请使用LIBGL_ALWAYS_INDIRECT=1运行第一个应用程序,看看性能是否同样糟糕。 - thokra
你能发布一些实际的OpenGL代码吗(你用“// OpenGL instructions to draw here!”替换的部分)? - andlabs
@SébastienLeRoux 仅绘制一个基元的代码就足够了。或者您正在使用着色器和顶点数组? - andlabs
@thokra:谢谢! - Sébastien Le Roux
@SébastienLeRoux,你能否也在另一个问题中发布一下这个内容?这是因为GtkGLArea对于使用的OpenGL功能非常挑剔,所以我才会问。 - andlabs
显示剩余9条评论
1个回答

2
谢谢您的建议,"ApiTrace" 的想法很棒,这不仅让我发现了一个很好的工具,而且还帮助我找到了一些关于我的问题的线索。使用 ApiTrace:
  1. 我检查了我的程序的两个版本(a 和 b),发现它们都使用了完全相同的 OpenGL 上下文......非常详细和容易地添加......因此错误不是来自上下文初始化。
  2. 我发现,在版本(b)中,渲染比版本(a)更频繁地进行了 5 次......也就是说,对于同一帧,渲染了 5 次!
我得出的唯一合乎逻辑的结论是 GTK+ 2 和 3 之间的信号差异,在我的程序的版本(a)中,我使用了 expose-event,而在版本(b)中,我使用了一个 draw 事件(GtkDrawingArea 的新信号)......显然,在这一点上,GTK+ 库在版本 2 和 3 之间有一些行为差异......我正在努力找到一种解决方法......我将编辑此答案以提供进一步信息。
[编辑]你好世界, 回答我自己的问题,希望能帮助别人避免我犯的同样的错误。 为了重新绘制我的 OpenGL 窗口,我正在使用:
void update (GtkWidget * plot)
{
  gtk_widget_hide (plot);
  gtw_widget_show (plot);
}

相反我应该使用:

gtk_widget_queue_draw (plot);

所有问题都已解决![/编辑]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接