1

我正在 Windows 上的 C++ 中的第 3 方程序中实现插件。

第 3 方程序有一个使用 OpenGL 显示 3D 图形的窗口。但是,我需要该插件来创建另一个窗口,该窗口也使用 OpenGL 显示 3D 图形。

我是否需要为我的窗口创建一个新的 OpenGL 渲染上下文,或者有什么方法可以“重用”第 3 方程序使用的 OpenGL 渲染上下文?

我假设我必须创建一个新的 OpenGL 渲染上下文并尝试了以下操作:

// create a rendering context  
hglrc = wglCreateContext (hdc); 

// make it the calling thread's current rendering context 
wglMakeCurrent (hdc, hglrc);

但是最后一个函数失败了。阅读wglMakeCurrent 的文档我注意到

一个线程可以有一个当前渲染上下文。通过多线程,一个进程可以拥有多个渲染上下文。

这是否意味着我的窗口需要在与第 3 方程序不同的线程中运行?

4

2 回答 2

1

您没有发布 wglMakeCurrent() 生成的错误代码,所以我不会猜测原因。然而,这不是绑定本身。句子“一个线程可以有一个当前的渲染上下文”的意思是,新的上下文将“替换”旧的上下文并成为当前的。我不知道您为什么要尝试将两个上下文设置为当前(或运行另一个线程),但这不是要走的路。除非绝对必要,否则避免在渲染中使用多线程。所以,回答你的问题:

是的,您可以“重用”OpenGL 渲染上下文。

为什么,你可能会问?渲染上下文是为特定设备上下文 (HDC) 创建的,这是每个窗口 (HWND) 的专有属性!那这怎么可能?!

好吧,由于函数原型,这似乎是不可能的:

    HWND my_window = CreateWindow(...);
    HDC my_dc = GetDC(my_new_window);

    //设置'my_dc'的像素格式...

    HGLRC my_rc = wglCreateContext(my_dc);
    wglMakeCurrent(my_dc, my_rc);

这真的让你认为渲染上下文绑定到这个特定的设备上下文并且只对它有效。但事实并非如此。关键部分是注释(设置像素格式)。渲染上下文是为特定CLASS 的 DC创建的,更准确地说:对于具有相同像素格式的 DC。所以下面的代码是完全有效的:

    //window_1 = 主窗口,window_2 = 你的窗口

    HDC dc_1 = GetDC(window_1);
    Set_pixel_format_for_dc_1(); //普通的东西
    HGLRC rc = wglCreateContext(dc_1);

    wglMakeCurrent(dc_1, rc);
    超超画();

    //.....

    HDC dc_2 = GetDC(window_2);

    //获取dc_1的PF以确保它与rc兼容。
    int pf_index = GetPixelFormat(dc_1);
    像素格式描述符 pfd;
    ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
    DescribePixelFormat(dc_1, pf_index, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

    SetPixelFormat(dc_2, pf_index, &pfd);

    wglMakeCurrent(dc_2, rc);
    another_awesome_render();

    wglMakeCurrent(NULL, NULL);

如果您仍然不相信,MSDN

wglMakeCurrent(hdc, hglrc): hdc参数必须引用OpenGL支持的绘图表面。它不必与创建 hglrc 时传递给 wglCreateContext 的 hdc 相同,但它必须位于同一设备上并具有相同的像素格式。

我猜你已经熟悉这些电话了。现在,我不知道你的渲染必须满足什么条件,但是没有额外的要求,从这一点上我看不出有什么困难:

    HDC my_dc = Create_my_DC();

    //...

    无效 my_new_render
    {
        //可能你想保存当前绑定:
        HDC current_dc = wglGetCurrentDC();
        HGLRC current_context = wglGetCurrentContext();

        wglMakeCurrent(my_dc, current_context);

        MyUltraSuperRender(...);

        wglMakeCurrent(current_dc, current_context);
    }

希望这可以帮助 :)

于 2013-09-24T22:12:13.360 回答
1

首先,您实际上应该为您的插件创建一个单独的 OpenGL 上下文,原因很简单,它为您提供了一个不会干扰主程序 OpenGL 上下文的单独状态空间。

不过,您误解了关于多个渲染上下文的部分。一个进程完全有可能拥有任意数量的 OpenGL 上下文。但是进程的每个线程一次只能绑定一个上下文。该绑定还包括上下文绑定到的窗口 DC。然而,随时更改上下文绑定是完全合法的。要么更改给定上下文绑定到的窗口,要么切换上下文,或者同时进行这两项操作。

因此,在您的情况下,我建议您为插件创建一个自定义上下文,用于插件创建的所有窗口。

您的简单上下文“创建”代码失败有一个简单的原因:您的窗口很可能没有像素格式描述符集。

我建议您使用以下方法来创建新的窗口和上下文:

/* first get hold of the HDC/HRC of the parent */
HDC parentDC = wglGetCurrentDC();
HRC parentRC = wglGetCurrentContext();
int pixelformatID = GetPixelFormat(parentDC);

/* we use the same PFD as the parent */
PIXELFORMATDESCRIPTOR pixelformat;
memset(pixelformat, 0, sizeof(pixelformat);
DescribePixelFormat(parentDC, pixelformatID, sizeof(pixelformat), &pixelformat);

/* create a window and set it's pixelformat to the parent one's */
HWND myWND = create_my_window();
HDC  myDC = GetDC(myWND);
SetPixelFormat(myDC, pixelformatID, &pixelformat);

/* finally we can create a rendering context
 * it doesn't matter if we create it against
 * the parent or our own DC.
 */
HRC myRC = wglCreateContext(myDC);

/* we're done here... */

现在,每当您的插件想要渲染某些东西时,它应该绑定自己的上下文,做它的事情并绑定之前绑定的上下文:

HDC prevDC = wglGetCurrentDC();
HRC prevRC = wglGetCurrentContext();

wglMakeCurrent(myDC, myRC);

/* do OpenGL stuff */

wglMakeCurrent(prevDC, prevRC);
于 2013-09-24T22:15:20.470 回答