【问题标题】:Only glClear(..) color is displayed, nothing else rendered (CUDA/OpenGL interop)仅显示 glClear(..) 颜色,没有其他渲染(CUDA/OpenGL 互操作)
【发布时间】:2015-09-29 17:38:16
【问题描述】:

我有一个带有面板(500x500 像素)的 WinForms 应用程序,我想在其中渲染一些东西。此时我只是想用特定的颜色填充它。我想使用 OpenGL/CUDA 互操作来做到这一点。

我将面板配置为渲染内容的区域,但是当我运行我的代码时,面板只被 glClear(..) 颜色填充,并且没有显示内核分配的任何内容。今天早上它有点工作(不一致),在我试图整理 SwapBuffers() 混乱时,我想我搞砸了。

这里是 OpenGL 的像素格式初始化。它似乎工作正常,我有两个缓冲区,并且上下文是正确的:

static  PIXELFORMATDESCRIPTOR pfd=              
{
    sizeof(PIXELFORMATDESCRIPTOR),              // Size Of This Pixel Format Descriptor
    1,                                          // Version Number
    PFD_DRAW_TO_WINDOW |                        // Format Must Support Window
    PFD_SUPPORT_OPENGL |                        // Format Must Support OpenGL
    PFD_DOUBLEBUFFER,                           // Must Support Double Buffering
    PFD_TYPE_RGBA,                              // Request An RGBA Format
    16,                                         // Select Our Color Depth
    0, 0, 0, 0, 0, 0,                           // Color Bits Ignored
    0,                                          // No Alpha Buffer
    0,                                          // Shift Bit Ignored
    0,                                          // No Accumulation Buffer
    0, 0, 0, 0,                                 // Accumulation Bits Ignored
    16,                                         // 16Bit Z-Buffer (Depth Buffer) 
    0,                                          // No Stencil Buffer
    0,                                          // No Auxiliary Buffer
    PFD_MAIN_PLANE,                             // Main Drawing Layer
    0,                                          // Reserved
    0, 0, 0                                     // Layer Masks Ignored
};

GLint  iPixelFormat; 

// get the device context's best, available pixel format match 
if((iPixelFormat = ChoosePixelFormat(hdc, &pfd)) == 0)
{
    MessageBox::Show("ChoosePixelFormat Failed");
    return 0;
}

// make that match the device context's current pixel format 
if(SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE)
{
    MessageBox::Show("SetPixelFormat Failed");
    return 0;
}

if((m_hglrc = wglCreateContext(m_hDC)) == NULL)
{
    MessageBox::Show("wglCreateContext Failed");
    return 0;
}

if((wglMakeCurrent(m_hDC, m_hglrc)) == NULL)
{
    MessageBox::Show("wglMakeCurrent Failed");
    return 0;
}   

完成后,我将 ViewPort 设置为:

glViewport(0,0,iWidth,iHeight);                     // Reset The Current Viewport
glMatrixMode(GL_MODELVIEW);                         // Select The Modelview Matrix
glLoadIdentity();                                   // Reset The Modelview Matrix
glEnable(GL_DEPTH_TEST);

然后我设置清除颜色并进行清除:

glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);  

现在我设置了 CUDA/OpenGL 互操作:

cudaDeviceProp prop; int dev;
memset(&prop, 0, sizeof(cudaDeviceProp));
prop.major = 1; prop.minor = 0;

checkCudaErrors(cudaChooseDevice(&dev, &prop));
checkCudaErrors(cudaGLSetGLDevice(dev));

glBindBuffer    = (PFNGLBINDBUFFERARBPROC)GET_PROC_ADDRESS("glBindBuffer");
glDeleteBuffers = (PFNGLDELETEBUFFERSARBPROC)GET_PROC_ADDRESS("glDeleteBuffers");
glGenBuffers    = (PFNGLGENBUFFERSARBPROC)GET_PROC_ADDRESS("glGenBuffers");
glBufferData    = (PFNGLBUFFERDATAARBPROC)GET_PROC_ADDRESS("glBufferData");

GLuint bufferID;
cudaGraphicsResource * resourceID;

glGenBuffers(1, &bufferID);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, bufferID);
glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, fWidth*fHeight*4, NULL, GL_DYNAMIC_DRAW_ARB);

checkCudaErrors(cudaGraphicsGLRegisterBuffer( &resourceID, bufferID, cudaGraphicsMapFlagsNone ));

现在我尝试调用我的内核(它只是将每个像素绘制成特定的颜色)并显示它。

uchar4* devPtr;
size_t size;

// First clear the back buffer:
glClearColor(1.0f, 0.5f, 0.0f, 0.0f); // orange
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

checkCudaErrors(cudaGraphicsMapResources(1, &resourceID, NULL));
checkCudaErrors(cudaGraphicsResourceGetMappedPointer((void**)&devPtr, &size, resourceID));

animate(devPtr); // This will call the kernel and do a sync (see later)

checkCudaErrors(cudaGraphicsUnmapResources(1, &resourceID, NULL));

// Swap buffers to bring back buffer forward:
SwapBuffers(m_hDC);

此时我希望在屏幕上看到内核颜色,但没有!我看到了橙色,这是我刚刚设置的清晰颜色。

这是对内核的调用:

void animate(uchar4* dispPtr)
{
    checkCudaErrors(cudaDeviceSynchronize());
    animKernel<<<blocks, threads>>>(dispPtr, envdim);;
    checkCudaErrors(cudaDeviceSynchronize());
}

这里 envdim 只是尺寸(所以 500x500)。内核本身:

__global__ void animKernel(uchar4 *optr, dim3 matdim)
{
    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;
    int offset = x + y * matdim.x;

    if (x < matdim.x && y < matdim.y)
    {
        // BLACK:
        optr[offset].x = 0; optr[offset].y = 0; optr[offset].z = 0;
    }
}

我做过的事情:

  • cudaGraphicsResourceGetMappedPointer的size返回的值为1000000,对应uchar4的500x500矩阵,这样就好了。
  • 每个内核都打印了它正在写入的值和位置,这似乎没问题。
  • 使用透明颜色的 alpha 值,但这似乎没有任何作用(还没有?)
  • 多次运行 animate() 函数。不知道为什么我认为这会有所帮助,但我试过了......

所以我想我错过了一些东西,但我有点疯狂地寻找它。有什么建议吗?帮忙?

【问题讨论】:

  • 哦,对了,我忘记了接近投票是多么触发快乐。这实际上是演示问题的最少代码量。我在这段代码和问题上付出了努力。我错过了一些东西,我不知道什么了。我搜索了 SO 和 Google 的答案,但我没有找到任何东西。我已经用代码和 cmets 解释了我的思考过程。
  • 您能否将所有不同的代码 sn-ps 组合成一个带有具体问题的实际完整重现案例?
  • 我觉得MCVE的描述很清楚。您的代码不完整。如果您不想提供 MCVE,那是您的决定。事情是这样的:如果我想帮助你,我想做的第一件事就是运行你的代码。如果您的代码已完成 80%,我必须填写 20%,使用我梦想但您已经编写但选择不显示的代码。我觉得这不是获得帮助的最佳方式。为什么不提供一些我可以复制、粘贴、编译和运行的东西?你已经写了代码,对吧?最小并不意味着小于完整
  • 因为如果你这样做了,那么这个例子就不是M初始的。您已经包含了不需要查看问题的额外垃圾。举个例子,如果你对threads 做了一些奇怪的事情,你的内核可能根本没有运行并且你的内核错误检查碰巧被破坏了,所以它不会捕捉到那个错误。所以我当然可以要求你展示你对threads 的定义。然后我们继续下一件事。你想让别人和你一起玩 20 个问题来梳理你的代码细节吗?它效率低下,编写 MCVE 描述是为了帮助解决这个问题。
  • 从一个大型项目创建一个 MCVE 很难。你必须把事情提炼出来,基本上写一个新的应用程序,然后自己测试。如果你不这样做,它可能既不C完整也不V可验证。是的!!!这需要你的努力。如果没有努力写出一个好问题,你就更有可能被否决。如果您的问题要求调试帮助,但显然不包含 MCVE,那么我认为 MCVE 接近投票是可以预期的。

标签: c++ opengl cuda


【解决方案1】:

这是我自己回答的另一个问题!嗯,正如我所想,这是一个单行问题。问题在于渲染调用本身。

配置很好,我对上面代码的一个问题是: 我从未调用过glDrawPixels(),这是 OpenGL 驱动程序将共享缓冲区 (GL_PiXEL_UNPACK_BUFFER_ARB) 源复制到显示缓冲区所必需的。那么正确的渲染顺序是:

uchar4* devPtr;
size_t size;

// First clear the back buffer:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

checkCudaErrors(cudaGraphicsMapResources(1, &resourceID, NULL));
checkCudaErrors(cudaGraphicsResourceGetMappedPointer((void**)&devPtr, &size, resourceID));

animate(devPtr); // This will call the kernel and do a sync (see later)

checkCudaErrors(cudaGraphicsUnmapResources(1, &resourceID, NULL));

// This is necessary to copy the shared buffer to display
glDrawPixels(fWidth, fHeight, GL_RGBA, GL_UNSIGNED_BYTE, 0);

// Swap buffers to bring back buffer forward:
SwapBuffers(m_hDC);

我要感谢 Acade ——呃,CUDA By Example,再次感谢我的帮助。尽管书中的示例代码使用了 GLUT(对此完全没用......),但本书引用了普通的 gl 函数。

【讨论】:

  • 请注意,glDrawPixels() 是一个已弃用的函数,在 OpenGL 核心配置文件中不再可用。它非常过时,我不会指望它在当前系统上有效。如果您关心性能,您可能需要寻找另一种方式来呈现您的数据。
  • @RetoKoradi,感谢您的建议。我从书中得到了信息,所以只要它适用于我的项目,我可能会很好。不过,我很想听听其他建议,我会自己寻找一些。
  • @RetoKoradi,哦,我明白了,看起来我应该只使用带纹理的四边形。我明天试试这个。
  • @RetoKoradi,我今天做了带纹理的四边形,在时间上真的没有任何区别。事实上,带纹理的四边形比 glDrawPixels() 慢一点。
  • 我会吃我的话,纹理四边形会更快一些。每帧大约 3.3 毫秒,而 glDrawPixels() 每帧 4.5 毫秒。
猜你喜欢
  • 1970-01-01
  • 2022-01-08
  • 2011-09-22
  • 1970-01-01
  • 2014-05-11
  • 1970-01-01
  • 2011-12-03
  • 2014-10-20
相关资源
最近更新 更多