在Windows上创建并行的屏幕外OpenGL上下文
Creating parallel offscreen OpenGL contexts on Windows
我正在尝试设置并行多GPU屏幕外渲染上下文。我使用"OpenGL Insights"书,第27章,"NVIDIA Quadro上的多gpu渲染",我也查看了wglCreateAffinityDCNV文档,但仍然无法确定。
我的机器有2个NVidia Quadro 4000卡(无SLI)。运行在Windows 7 64位。我的工作流程如下:
- 使用GLFW创建默认的窗口上下文
- 映射GPU设备
- 销毁默认的GLFW上下文。
- 为每个设备创建新的GL上下文(当前只尝试一个)
- 为每个上下文设置boost线程并使其在该线程中当前。
- 在每个线程上分别运行渲染过程。(无资源共享)
一切都没有错误地创建并运行,但是一旦我尝试从屏幕外FBO读取像素,我在这里得到一个空指针:
GLubyte* ptr = (GLubyte*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
同时glError返回"UNKNOWN ERROR"
我认为可能是多线程是问题,但相同的设置在单线程上运行时给出相同的结果。所以我认为这与语境的创造有关。
我是这样做的:
////Creating default window with GLFW here .
.....
.....
创建屏幕外上下文:
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags
PFD_TYPE_RGBA, //The kind of framebuffer. RGBA or palette.
24, //Colordepth of the framebuffer.
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
24, //Number of bits for the depthbuffer
8, //Number of bits for the stencilbuffer
0, //Number of Aux buffers in the framebuffer.
PFD_MAIN_PLANE,
0,
0, 0, 0
};
void glMultiContext::renderingContext::createGPUContext(GPUEnum gpuIndex){
int pf;
HGPUNV hGPU[MAX_GPU];
HGPUNV GpuMask[MAX_GPU];
UINT displayDeviceIdx;
GPU_DEVICE gpuDevice;
bool bDisplay, bPrimary;
// Get a list of the first MAX_GPU GPUs in the system
if ((gpuIndex < MAX_GPU) && wglEnumGpusNV(gpuIndex, &hGPU[gpuIndex])) {
printf("Device# %d:n", gpuIndex);
// Now get the detailed information about this device:
// how many displays it's attached to
displayDeviceIdx = 0;
if(wglEnumGpuDevicesNV(hGPU[gpuIndex], displayDeviceIdx, &gpuDevice))
{
bPrimary |= (gpuDevice.Flags & DISPLAY_DEVICE_PRIMARY_DEVICE) != 0;
printf(" Display# %d:n", displayDeviceIdx);
printf(" Name: %sn", gpuDevice.DeviceName);
printf(" String: %sn", gpuDevice.DeviceString);
if(gpuDevice.Flags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
{
printf(" Attached to the desktop: LEFT=%d, RIGHT=%d, TOP=%d, BOTTOM=%dn",
gpuDevice.rcVirtualScreen.left, gpuDevice.rcVirtualScreen.right, gpuDevice.rcVirtualScreen.top, gpuDevice.rcVirtualScreen.bottom);
}
else
{
printf(" Not attached to the desktopn");
}
// See if it's the primary GPU
if(gpuDevice.Flags & DISPLAY_DEVICE_PRIMARY_DEVICE)
{
printf(" This is the PRIMARY Display Devicen");
}
}
///======================= CREATE a CONTEXT HERE
GpuMask[0] = hGPU[gpuIndex];
GpuMask[1] = NULL;
_affDC = wglCreateAffinityDCNV(GpuMask);
if(!_affDC)
{
printf( "wglCreateAffinityDCNV failed");
}
}
printf("GPU context created");
}
glMultiContext::renderingContext *
glMultiContext::createRenderingContext(GPUEnum gpuIndex)
{
glMultiContext::renderingContext *rc;
rc = new renderingContext(gpuIndex);
_pixelFormat = ChoosePixelFormat(rc->_affDC, &pfd);
if(_pixelFormat == 0)
{
printf("failed to choose pixel format");
return false;
}
DescribePixelFormat(rc->_affDC, _pixelFormat, sizeof(pfd), &pfd);
if(SetPixelFormat(rc->_affDC, _pixelFormat, &pfd) == FALSE)
{
printf("failed to set pixel format");
return false;
}
rc->_affRC = wglCreateContext(rc->_affDC);
if(rc->_affRC == 0)
{
printf("failed to create gl render context");
return false;
}
return rc;
}
//Call at the end to make it current :
bool glMultiContext::makeCurrent(renderingContext *rc)
{
if(!wglMakeCurrent(rc->_affDC, rc->_affRC))
{
printf("failed to make context current");
return false;
}
return true;
}
//// init OpenGL objects and rendering here :
..........
............
正如我所说的,我在设备和上下文创建的任何阶段都没有错误。我做错了什么?
更新:
好吧,看来我找到bug了。在调用wglmakecurcurrent()之后,我调用glfwTerminate(),因此看起来最新的"uncurrent"也是新的上下文。虽然它是连接的,因为OpenGL命令不断被执行。所以它在一个线程中工作。
但是现在,如果我使用boost线程生成另一个线程,我就会得到初始错误。下面是我的线程类:
GPUThread::GPUThread(void)
{
_thread =NULL;
_mustStop=false;
_frame=0;
_rc =glMultiContext::getInstance().createRenderingContext(GPU1);
assert(_rc);
glfwTerminate(); //terminate the initial window and context
if(!glMultiContext::getInstance().makeCurrent(_rc)){
printf("failed to make current!!!");
}
// init engine here (GLEW was already initiated)
engine = new Engine(800,600,1);
}
void GPUThread::Start(){
printf("threaded view setup ok");
///init thread here :
_thread=new boost::thread(boost::ref(*this));
_thread->join();
}
void GPUThread::Stop(){
// Signal the thread to stop (thread-safe)
_mustStopMutex.lock();
_mustStop=true;
_mustStopMutex.unlock();
// Wait for the thread to finish.
if (_thread!=NULL) _thread->join();
}
// Thread function
void GPUThread::operator () ()
{
bool mustStop;
do
{
// Display the next animation frame
DisplayNextFrame();
_mustStopMutex.lock();
mustStop=_mustStop;
_mustStopMutex.unlock();
} while (mustStop==false);
}
void GPUThread::DisplayNextFrame()
{
engine->Render(); //renders frame
if(_frame == 101){
_mustStop=true;
}
}
GPUThread::~GPUThread(void)
{
delete _view;
if(_rc != 0)
{
glMultiContext::getInstance().deleteRenderingContext(_rc);
_rc = 0;
}
if(_thread!=NULL)delete _thread;
}
最后我自己解决了这个问题。第一个问题是,我调用glfwTerminate后,我设置另一个设备上下文是当前的。这可能也卸载了新的背景。第二个问题是我对boost线程的"无知"。我未能在自定义线程中初始化所有与渲染相关的对象,因为我在设置线程之前调用了rc init对象过程,如上面的例子所示。
相关文章:
- OpenGL ES 2.0将纹理绘制到屏幕上是行不通的
- OpenGL - 添加第二个着色器属性会导致空白屏幕
- 如何使用 openGL 在屏幕上显示加载的纹理
- 如何在OpenGL中自动选择屏幕大小
- Qt,openGL,小部件和屏幕外渲染
- OpenGL屏幕坐标到世界坐标
- 当对象在屏幕空间中较小时,OpenGL 更新缓慢
- 如何使用OpenGL在屏幕上显示三角形
- OpenGL多个带有独特着色器的呼叫可提供空白屏幕
- OpenGL 检查屏幕边界
- OpenGL 屏幕外渲染
- OpenGL:MESA3D屏幕上的软件渲染性能问题
- 我试图运行OpenGL,但Glut屏幕只是呈现一个白色屏幕
- QT QML 中的 OpenGL,无法更新屏幕上的图像
- OpenGL在非方形屏幕上绘制线条
- OpenGL 3 Qt 渲染空白屏幕
- OpenGL使用glfw通过HIDDEN窗口进行屏幕外渲染和读取像素值
- OpenGL显示空白屏幕.可能是因为着色器
- 即使没有发生错误,三角形也不会在屏幕openGL上绘制
- 空白屏幕OpenGL