使用带有 FBO 的 OpenGL 3.2+ 的 Linux 屏幕外渲染

Posted

技术标签:

【中文标题】使用带有 FBO 的 OpenGL 3.2+ 的 Linux 屏幕外渲染【英文标题】:Linux Rendering offscreen with OpenGL 3.2+ w/ FBOs 【发布时间】:2014-03-18 02:00:17 【问题描述】:

我有 ubuntu 机器和一个用 OS X 编写的命令行应用程序,它使用 FBO 渲染屏幕外的东西。这是代码的一部分。

        this->systemProvider->setupContext(); //be careful with this one. to add thingies to identify if a context is set up or not
    this->systemProvider->useContext();
    glewExperimental = GL_TRUE;
    glewInit();


    GLuint framebuffer, renderbuffer, depthRenderBuffer;

    GLuint imageWidth = _viewPortWidth,
            imageHeight = _viewPortHeight;

    //Set up a FBO with one renderbuffer attachment
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);

    glGenRenderbuffers(1, &renderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, imageWidth, imageHeight);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);


    //Now bind a depth buffer to the FBO
    glGenRenderbuffers(1, &depthRenderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, _viewPortWidth, _viewPortHeight);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderBuffer);

“系统提供程序”是围绕 OS X 的 NSOpenGLContext 的 C++ 包装器,它仅用于创建渲染上下文并使其成为当前状态,而不会将其与窗口相关联。所有的渲染都发生在 FBO 中。

我正在尝试对使用 GLX 的 Linux (Ubuntu) 使用相同的方法,但我很难做到,因为我看到 GLX 需要一个像素缓冲区。

我正在尝试学习本教程:

http://renderingpipeline.com/2012/05/windowless-opengl/

最后,它使用像素缓冲区使上下文成为当前的,我听说它已被弃用,我们应该放弃它以支持帧缓冲区对象,对吗(我可能错了)。

有没有人有更好的方法或想法?

【问题讨论】:

嗯,是的,渲染缓冲区现在用处不大。 你能详细说明一下吗?渲染缓冲区是什么意思?你有更好的跨平台替代品吗? “渲染缓冲区”可能是什么意思?您的代码正在使用它们。 我希望您能详细说明替代方案,以及为什么您认为它们不是很有用,因为通过小型谷歌搜索,人们说最好的方法之一是不仅使用 fbo用于离屏渲染,也用于渲染到纹理效果。我很想听听你的替代方案。 @BartekBanachewicz 我相信他在谈论像素缓冲区,而不是渲染缓冲区。我正在尝试在 Ubuntu 上使用 GLX 做同样的事情。 OP 提到的链接使用像素缓冲区来生成上下文。但是不推荐使用像素缓冲区,并且首选 FBO。他要问的是,如果我们想使用 FBO,需要做什么。 【参考方案1】:

我不知道这是否是最好的解决方案,但它肯定对我有用。

将函数绑定到我们可以使用的局部变量

typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
typedef Bool (*glXMakeContextCurrentARBProc)(Display*, GLXDrawable, GLXDrawable, GLXContext);
static glXCreateContextAttribsARBProc glXCreateContextAttribsARB = NULL;
static glXMakeContextCurrentARBProc   glXMakeContextCurrentARB   = NULL;

我们的对象作为类属性:

Display *display;
GLXPbuffer pbuffer;
GLXContext openGLContext;

设置上下文:

    glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" );
    glXMakeContextCurrentARB   = (glXMakeContextCurrentARBProc)   glXGetProcAddressARB( (const GLubyte *) "glXMakeContextCurrent");

    display = XOpenDisplay(NULL);
    if (display == NULL)
        std::cout  << "error getting the X display";
    

    static int visualAttribs[] = None;
    int numberOfFrameBufferConfigurations;
    GLXFBConfig *fbConfigs = glXChooseFBConfig(display, DefaultScreen(display), visualAttribs, &numberOfFrameBufferConfigurations);

    int context_attribs[] = 
        GLX_CONTEXT_MAJOR_VERSION_ARB ,3,
        GLX_CONTEXT_MINOR_VERSION_ARB, 2,
        GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
        GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
        None
    ;

    std::cout << "initialising context...";
    this->openGLContext = glXCreateContextAttribsARB(display, fbConfigs[0], 0, True, context_attribs);

    int pBufferAttribs[] = 
        GLX_PBUFFER_WIDTH, (int)this->initialWidth,
        GLX_PBUFFER_HEIGHT, (int)this->initialHeight,
        None
    ;

    this->pbuffer = glXCreatePbuffer(display, fbConfigs[0], pBufferAttribs);
    XFree(fbConfigs);
    XSync(display, False);

使用上下文:

if(!glXMakeContextCurrent(display, pbuffer, pbuffer, openGLContext))
    std::cout << "error with content creation\n";
else
    std::cout << "made a context the current context\n";

之后,人们就可以像在其他任何场合一样正常使用 FBO。直到今天,我的问题实际上没有答案(如果有更好的选择),所以我只是提供一个对我有用的解决方案。在我看来,GLX 不像 OpenGL 那样使用像素缓冲区的概念,因此我感到困惑。渲染离屏的首选方式是 FBO,但要在 Linux 上创建 OpenGL 上下文,必须创建像素缓冲区(GLX 类型)。之后,将 FBO 与我在问题中提供的代码一起使用将按预期工作,就像在 OS X 上一样。

【讨论】:

我的编译器告诉我“glXCreateContextAttribsARBProc”是一个未知的类型名。 (Ubuntu 16.04)

以上是关于使用带有 FBO 的 OpenGL 3.2+ 的 Linux 屏幕外渲染的主要内容,如果未能解决你的问题,请参考以下文章

需要带有 FBO 扩展的 OpenGL 2.0 或更高版本 - LibGDX 错误

将绑定到 FBO 的纹理复制到另一个 OpenGL 上下文

在 CUDA 中修改 OpenGL FBO 纹理附件

在 AMD 上写入非零 FBO 附件时,OpenGL 会降低性能

OpenGL FBO 与 MRT 写入后台缓冲区

OpenGL 渲染到 FBO