yang131

导航

openGL之多线程渲染

随着Vulkan的引入,我们的图形技术的发展到达了一个新的顶点,但是呢,我们的老干爹OpenGL作为落日余晖,他在一些Vulkan才有的新功能上,也提供了一些支持,现在我们来讨论一下OpenGL之多线程渲染。

 

这里要补一补课:

 windows上调用openGL最原始的原始方式

大概流程是这样的详情请见:https://gitee.com/GProReat/codes/bjptwd3hglozmi25esn4v31

1.获取句柄, 在win32或者MFC里面可以直接获取HWND,但是在glut,glfw,sdl等可以通过GetActiveWindow来获取HWND。

2.GetDC,这个是获取窗口的DC,  HDC ( Handle To Device Context)是图像的设备描述表,窗口显示上下文句柄,其中可以进行图形显示。

3.PixelFormat的支持,这里可以看刚才代码段里面PixelFormat的设置 

4.创建OpenGL的上下文wglCreateContext, 以及切换到当前的上下文,wglMakeCurrent,传入HGLRC类型的object。

5.初始化操作  各种开关比如: depthTest,AlphaTest,DepthFunc,Texture2等操作。

6.在窗口的绘制的时候,也就是WM_PAINT相应的时候处理绘制。

  这里关键一点是,调用OpenGL绘制之后使用SwapBuffers,还有glFlush。

7.资源释放。

note:windows上使用openGL来渲染,大家可以找MFC或者win32上的OpenGL绘制。

 

接下来开始我们的主题:openGL多线程渲染

根据我的测试,HGLRC 的创建与线程无关,也就是说目前HGLRC可以在另外一个线程创建(需要在当前线程wglShareLists),也可以在当前线程创建,

下面为核心代码:  

this->hGLRC2 = wglCreateContext(hDC);
wglShareLists(hGLRC2, hGLRC);
std::thread th([this]() {
    wglMakeCurrent(hDC, hGLRC2);
    texAnotherThread.LoadFromFile1("1.jpg");
    });
th.join();

当然我们根据测试,也能发现,HGLRC在shared之前或者之后加载资源,都能做到共享

    hGLRC = wglGetCurrentContext();
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    std::thread th([this]() {
        hGLRC2 = wglCreateContext(hDC);
        wglMakeCurrent(hDC, hGLRC2);
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_DEPTH);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LESS);
                texAnotherThread.LoadFromFile1("1.jpg");
        }
    th.join();
    wglShareLists(hGLRC, hGLRC2);

还有根据我的测试wglShareLists(hGLRC, hGLRC2); 他实际上这两个参数顺序是有讲究的,如果在创建完上下文之后,直接共享,那么这俩参数顺序没有影响,如果在hGLRC2里加载完tetxure,那么只能wglShareLists(hGLRC2,hGLRC)

代码如下:(顺序无关的)

void MultiThreadTexture_App::Init()
{
    hWnd = GetActiveWindow();
    hDC = GetDC(hWnd);
    hGLRC = wglGetCurrentContext();    
    hGLRC2 = wglCreateContext(hDC);
    wglShareLists(hGLRC, hGLRC2);  //顺序无关
    isRunning = true;
    std::thread th([this]() {
        wglMakeCurrent(hDC, hGLRC2);
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_DEPTH);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LESS);
        texAnotherThread.LoadFromFile1("1.jpg");
        });
    th.join();   
} 
void MultiThreadTexture_App::Init()
{
    hWnd = GetActiveWindow();
    hDC = GetDC(hWnd);
    hGLRC = wglGetCurrentContext();
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    hGLRC2 = wglCreateContext(hDC);
    
    isRunning = true;
    std::thread th([this]() {
        wglMakeCurrent(hDC, hGLRC2);
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_DEPTH);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LESS);
        texAnotherThread.LoadFromFile1("1.jpg");
        });
    th.join();
    //这两个参数顺序是和渲染结果有关系的
    wglShareLists(hGLRC2, hGLRC);  //只能这样子。

}

使用线程2来渲染,代码如下:  结果是可以显示

void MultiThreadTexture_App::Init()
{
    hWnd = GetActiveWindow();
    hDC = GetDC(hWnd);
    hGLRC = wglGetCurrentContext();
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    hGLRC2 = wglCreateContext(hDC);
    wglShareLists(hGLRC, hGLRC2);
    isRunning = true;
    std::thread th([this]() {
        wglMakeCurrent(hDC, hGLRC2);
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_DEPTH);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LESS);
        texAnotherThread.LoadFromFile1("1.jpg");while (isRunning)  //使用程序来控制 isRunning在线程运行之前为true,程序退出为false
        {
            if (isRenderBegin)   //在调用Render的时候为true。
            {
                Render(-10);
                AfterRender();
            }
        }
        });
    th.detach();
}

void MultiThreadTexture_App::Render(int deltaMillionSeconds)
{
    if (!isRenderBegin)
        isRenderBegin = true;
    if (deltaMillionSeconds != -10) return;
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60, width / height, 0.1, 1000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0, 0, 100, 0, 0, 0, 0, 1, 0);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0, 0, 0, 1);
    glClearDepth(1000);
    glEnable(GL_FILL);
    glBindTexture(GL_TEXTURE_2D, texAnotherThread.texId);
    glBegin(GL_QUADS);
    glTexCoord2f(0, 0); glVertex3f(0, 0, 0);
    glTexCoord2f(1, 0); glVertex3f(100, 0, 0);
    glTexCoord2f(1, 1); glVertex3f(100, 100, 0);
    glTexCoord2f(0, 1); glVertex3f(0, 100, 0);
    glEnd();

}

 

最后,做了一个交替渲染, 每1s为间隔,线程1,线程2交替渲染,而且他们使用对方的资源,比如第1s线程1渲染用的是线程2加载的纹理,第2s线程2渲染用的是线程1加载的纹理,如此循环...

代码如下:

void MultiThreadTexture_App::Init()
{
    hWnd = GetActiveWindow();
    hDC = GetDC(hWnd);
    hGLRC = wglGetCurrentContext();
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    hGLRC2 = wglCreateContext(hDC);
    wglShareLists(hGLRC, hGLRC2);
    tex.LoadFromFile1("2.png");
    isRunning = true;
    lastRenderThreadID = -1;//默认值
    std::thread th([this]() {
        wglMakeCurrent(hDC, hGLRC2);
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_DEPTH);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LESS);
        texAnotherThread.LoadFromFile1("1.jpg");
        while (isRunning)  //使用程序来控制 isRunning在线程运行之前为true,程序退出为false
        {
            if (isRenderBegin)   //在调用Render的时候为true。
            {
                Render(-10);
                AfterRender();
            }
        }
        });
    th.detach();

}
//deltaMillionSeconds是根据时间变化的,每一帧的间隔
void MultiThreadTexture_App::Render(int deltaMillionSeconds)
{
    mtx.lock();
    if (!isRenderBegin)
        isRenderBegin = true;

    isRenderBegin = true;
    if (deltaMillionSeconds == -10)
        RenderThreadID = 2;
    else
        RenderThreadID = 1;

    if (lastRenderThreadID != -1 && lastRenderThreadID == RenderThreadID)
    {//和之前的线程一致
        ::Sleep(1000); //保证1s调用1次
        mtx.unlock();
        return;
    }

    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60, width / height, 0.1, 1000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0, 0, 100, 0, 0, 0, 0, 1, 0);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0, 0, 0, 1);
    glClearDepth(1000);
    glEnable(GL_FILL);
    //这里互相使用对方的资源
    if (RenderThreadID == 1)
        glBindTexture(GL_TEXTURE_2D, texAnotherThread.texId);
    else
        glBindTexture(GL_TEXTURE_2D, tex.texId);

    glBegin(GL_QUADS);
    glTexCoord2f(0, 0); glVertex3f(0, 0, 0);
    glTexCoord2f(1, 0); glVertex3f(100, 0, 0);
    glTexCoord2f(1, 1); glVertex3f(100, 100, 0);
    glTexCoord2f(0, 1); glVertex3f(0, 100, 0);
    glEnd();
    lastRenderThreadID = RenderThreadID;
    //休息1秒钟然后
    ::Sleep(1000);
    mtx.unlock();
}

void MultiThreadTexture_App::Release()
{
    isRunning = false;
}

线程1用的是游戏截图,线程2用的是狗头。而渲染使用对方的资源,效果图如下:

 

posted on 2022-10-04 11:40  NoNight  阅读(2485)  评论(0编辑  收藏  举报