如何在应用程序中使用多个 openGL 状态?

Posted

技术标签:

【中文标题】如何在应用程序中使用多个 openGL 状态?【英文标题】:How to use more than one openGL state in an application? 【发布时间】:2020-08-06 22:36:13 【问题描述】:

我知道 openGL 是一个状态机,我不知道状态是如何存储的。

我有一个项目,我必须在 c++ dll/动态库中将屏幕外的东西渲染到内存中,并将最终图像传递给 c# 应用程序,该应用程序也使用 openGL 状态来做任何可以想象的事情(渲染任何应用程序想要以任何方式)。这显然使得无法区分用于在屏幕外(在 dll/动态库中)绘制的 openGL 状态和用于在应用程序中绘制的 openGL 状态。

我将如何在 C++ 中为我的屏幕外渲染器创建/使用单独的 openGL 状态? c++ std::threads 在其中使用 openGL 时会使用/创建单独的 openGL 状态吗?

最后(我不需要回答最后一部分,但要完整),有没有办法在一个应用程序中处理多个 openGL 状态(并在这些状态之间交替)而不使用多个线程?

【问题讨论】:

我认为您将 state 的两种不同含义混为一谈。 @AluanHaddad 我问如果我想在两个单独的实例中使用openGL,是否必须使用线程。我相信对于 openGL,实际术语是“上下文”,而不是我猜你是对的状态。 我只是在评论“openGL 是一个状态机”的说法。任何程序都是状态机。但图书馆本身可能没有这样描述。 【参考方案1】:

如果您想将最终的渲染图像传递给另一个应用程序,您可以使用 PBO 传递它,并使用 glMapBuffer 传递指向像素数据的指针。

这是我将像素数据传递给其他应用程序的代码。

glReadBuffer(GL_COLOR_ATTACHMENT0);
writeIndex = (writeIndex + 1) % 2;
readIndex = (readIndex + 1) % 2;
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[writeIndex]);
                    // copy from framebuffer to PBO asynchronously. it will be ready in the NEXT frame
glReadPixels(0, 0, SCR_WIDTH, SCR_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
                    // now read other PBO which should be already in CPU memory
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[readIndex]);
unsigned char* downsampleData = (unsigned char *)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
float Time1 = bm.GetTime();
blueOut.RenderOut(downsampleData, FieldNumber); // Pass it to the other application
                
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);

您必须为 c# 应用程序编写驱动程序,它将数据指针实时传递给应用程序。

【讨论】:

我目前正在将图像传递给 ram,然后将其复制到另一个图像,最后将其传递回 gpu;这有多慢?如果它是唯一的瓶颈,它会相对较快地工作吗?这种方法是否相同/相似? @MatiasChara 通常 DMA 是此类传输的首选,我正在做一个非常快的 DMA。【参考方案2】:

这很像 CPU 进行线程调度的上下文切换。

假设你在一个线程中有两个管道 M 和 N 并且 M 先运行,当你想切换到 N 时,你可以先保存 M 的上下文,然后启动 N 的管道,在 N 运行的某个时刻你可以保存N 的上下文并恢复 M 的上下文。所以问题是如何显式保存OpenGL的上下文。

实际上 OpenGL 提供了很多查询/获取方法(或几个方法但很多参数),如glGetIntegervglGetVertexAttribivglGetVertexAttribPointerv(glGet),您可以查询并将结果保存到某个地方并恢复它们在某个时候。

这是一个简单的包装类示例:

class GLStateSaver 
    GLuint framebuffer;
    GLint activeTexture;
    GLint boundedTextures[MAX_USED_TEXTURES];
    // ... add more fields if you need, like programID, memory object id etc.
public:
    void Save() 
        glGetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer);
        glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture);
        // ...
    
    void Restore() 
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
        glActiveTexture(activeTexture);
        // ...
    

【讨论】:

以上是关于如何在应用程序中使用多个 openGL 状态?的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL - 如何使用弹出菜单绘制多个不同的 2D 形状?

Metal:在一个渲染过程中使用多个 MTLRenderCommandEncoder

如何在 OpenGL 中将多个纹理分配到单个网格中?

在 Windows XP 中使用多个视频卡进行 OpenGL 渲染

OpenGL 无效的纹理或状态

如何向我的 openGL 程序添加多个纹理?