无窗口OpenGL

33
我想要一个无窗口的OpenGL上下文(在GNU/Linux和Windows平台上均可)。我不会渲染任何东西,只是调用像glGetStringglCompileShader等函数。
我已经做了一些搜索,但没有找到有用的信息,除了创建一个隐藏的窗口,这似乎对我来说是一种hack方法。
所以是否有更好的方法(适用于任何平台)?
编辑:在Xorg上,我能够创建并附加一个OpenGL上下文到根窗口。
#include<stdio.h>
#include<stdlib.h>
#include<X11/X.h>
#include<X11/Xlib.h>
#include<GL/gl.h>
#include<GL/glx.h>

int main(int argc, const char* argv[]){
  Display *dpy;
  Window root;
  GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
  XVisualInfo *vi;
  GLXContext glc;

  dpy = XOpenDisplay(NULL);

  if ( !dpy ) {
    printf("\n\tcannot connect to X server\n\n");
    exit(0);
  }

  root = DefaultRootWindow(dpy);
  vi = glXChooseVisual(dpy, 0, att);

  if (!vi) {
    printf("\n\tno appropriate visual found\n\n");
    exit(0);
  }

  glc = glXCreateContext(dpy, vi, NULL, GL_TRUE);
  glXMakeCurrent(dpy, root, glc);

  printf("vendor: %s\n", (const char*)glGetString(GL_VENDOR));

  return 0;
}

编辑2:根据被接受的答案,我已经写了一篇关于无窗口OpenGL的简短文章(包括示例代码)。


1
在Windows平台上使用GetDesktopWindow。 - Luca
5个回答

22

实际上,创建一个“传统”的渲染上下文需要一个窗口句柄(在X11上是根窗口,在Windows上是桌面窗口是很好的选择)。它用于获取OpenGL信息和扩展可用性。

一旦获得了该信息,就可以销毁渲染上下文并释放“虚拟”窗口!

你应该测试扩展ARB_extensions_stringARB_create_context_profile,(在这些页面中描述:ARB_create_context)。然后,你可以通过调用CreateContextAttribs来以跨平台的方式创建一个渲染上下文,而无需关联系统窗口并仅需要系统设备上下文

        int[] mContextAttrib = new int[] {
            Wgl.CONTEXT_MAJOR_VERSION, REQUIRED_OGL_VERSION_MAJOR,
            Wgl.CONTEXT_MINOR_VERSION, REQUIRED_OGL_VERSION_MINOR,
            Wgl.CONTEXT_PROFILE_MASK, (int)(Wgl.CONTEXT_CORE_PROFILE_BIT),
            Wgl.CONTEXT_FLAGS, (int)(Wgl.CONTEXT_FORWARD_COMPATIBLE_BIT),
            0
        };


        if ((mRenderContext = Wgl.CreateContextAttribs(mDeviceContext, pSharedContext, mContextAttrib)) == IntPtr.Zero)
            throw new Exception("unable to create context");
然后,如果你只想编译着色器(而不是渲染),你可以将帧缓冲对象或系统窗口与创建的渲染上下文关联起来。
使用 “CreateContextAttribs” 有很多优点:
- 它是跨平台的。 - 可以请求特定的OpenGL实现。 - 可以请求大于3.2的OpenGL实现。 - 可以强制启用向前兼容选项(仅进行着色器渲染,这是未来的方式)。 - 可以在向前兼容上下文中选择特定的OpenGL实现配置文件(目前仅有核心配置文件,但将来可能会有更多)。 - 即使实际驱动程序实现未定义如何使用此选项,也可以启用调试选项。
然而,旧硬件/驱动程序可能无法实现此扩展,因此建议编写回退代码以创建向后兼容的上下文。

你如何在Windows上做同样的事情? - Petar Ivanov
@PetarIvanov,使用C#完全相同的可执行文件。但是,所有OpenGL API都是可移植的。 - Luca

8
在创建窗口之前,OpenGL不知道你使用的是哪种实现。例如,在远程X-Windows会话中和DRI X-Windows会话中,OpenGL的驱动程序(以及不同的硬件加速)是非常不同的。这些情况下着色器语言支持可能是不同的,并且着色器编译器的输出肯定会依赖于实现,以及基于资源耗尽生成的任何错误。
因此,虽然实际上创建窗口可能并非必需,但你必须以某种方式将上下文与图形硬件(或其缺乏)相关联,由于可以使用窗口来完成这项工作,因此没有人费心实现替代方法。

创建一个上下文并将其与根窗口相关联如何? - ext
@ext: 听起来是一个合理的方法。请注意,OpenGL不需要编写任何额外的代码来处理这种情况,它仍然是“将新上下文与某个窗口关联”,而不是“将新上下文与此图形卡关联,我没有窗口”。只要小心不要在根窗口上实际渲染即可。 - Ben Voigt

2

您需要一个窗口来承载上下文,而且您需要上下文才能做任何事情。

来源

如果您不想显示任何东西,请将窗口设置为不可见。

如果有其他方法可以解决这个问题,它肯定会被记录在某处并且很容易被找到,因为这不是一个罕见的问题。


1
我所做的一件事情——虽然有点投机取巧——是为了避免创建自己的GL窗口开销,而是利用打开的进程窗口。理解OpenGL的关键在于:只需要使用wglCreateContext调用创建一个有效的DC即可创建GL上下文。文档中没有任何内容说明它必须是你拥有的DC。为了测试这个功能,我弹出了《魔兽世界》并利用SPY ++获取了一个窗口句柄,然后手动将该句柄插入到GetDC调用中,返回一个有效的设备上下文,然后像平常一样运行我的GL代码。没有创建自己的GL窗口。当我用《魔兽世界》和《星际迷航Online》进行测试时,发生了什么https://universalbri.wordpress.com/2015/06/05/experiment-results。所以回答你的问题,是的,你需要一个窗口,但文档中没有说明该窗口必须归你所有。
现在请注意:我无法使用桌面窗口获得有效的视觉输出,但是我能够成功地使用getDeskTopWindow API为HWND创建DC,然后调用GetDC。因此,如果您想要使用OpenGL进行非可视处理,请告诉我您正在做什么,我很好奇,如果您确实能够让GetDesktopWindow方法与视觉效果一起工作,请在此线程上重新发布您所做的内容。
祝你好运。
不要让任何人告诉你它做不到。
有志者事竟成。

1

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