【问题标题】:OpenGL window not responding when performing computation on GPU在 GPU 上执行计算时,OpenGL 窗口没有响应
【发布时间】:2019-04-12 00:48:14
【问题描述】:

这是一个执行光线追踪的 CUDA 代码。 OpenGL 窗口用于显示执行的光线追踪的输出。由于 RayTrace 很慢,所以我并不特别关心 OpenGL 性能等。

但是当调用光线追踪 (startRayTrace()) 时,OpenGL 窗口只是进入“无响应”状态,并在光线追踪完成后显示输出。

我不知道如何防止它进入无响应状态。当它进入无响应状态时,我无法最小化窗口等,但渲染的图像仍按原样显示。

void display(void) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glLoadIdentity();

    float image[768][1024][3] = { 0 };

    for (int i = 0; i < 768; ++i) {
        for (int j = 0; j < 1024; ++j) {
            int idx = (767 - i) * 1024 + j;
            image[i][j][0] = host_c[idx].x;
            image[i][j][1] = host_c[idx].y;
            image[i][j][2] = host_c[idx].z;
        }
    }

    glRasterPos2i(-1, -1);
    glDrawPixels(1024, 768, GL_RGB, GL_FLOAT, image);
    glEnd();
    glutSwapBuffers();
}

void winResize(int w, int h) {
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glViewport( (w>1024)?((w-1024)/2):(0), (h>768)?((h-768)/2):(0), w, h);
    glMatrixMode(GL_MODELVIEW);
}

void startRayTrace() {
    cudaMemcpyToSymbol(cam_offset, &cam_offset_global, sizeof(double), 0, cudaMemcpyHostToDevice);

    init <<< 1, 1 >>> ();
    cudaDeviceSynchronize();

    char title[35];

    //rayTrace <<<48, 16 >>> ();
    //cudaDeviceSynchronize();

    for (int i = 0; i < 24; ++i) {
        rayTrace <<< 1, 32 >>> ();      //Overcome Watchdog timer on Windows without disabling TDR
        cudaDeviceSynchronize();
        sprintf(title, "Ray Tracing | Rendering %.2f%%...", ((i + 1) / 24.f) * 100);
        glutSetWindowTitle(title);
    }

    copyToHost <<< 1, 1 >>> (dev_c);
    cudaMemcpy(host_c, dev_c, WIDTH * HEIGHT * sizeof(vector), cudaMemcpyDeviceToHost);
}

void keyPress(unsigned char key, int x, int y) {
    if (key == 'd') {
        cam_offset_global += 10;
    }
    if (key == 'a') {
        cam_offset_global -= 10;
    }
}

void keyUp(unsigned char key, int x, int y) {
    if (key == 'd' || key == 'a') {
        startRayTrace();
    }
    //cudaDeviceSynchronize();
    glutPostRedisplay();
}

int main(int argc, char * argv[]) {

    cudaMalloc(&dev_c, WIDTH * HEIGHT * sizeof(vector));

    //OpenGL Window
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(1024, 768);
    glutCreateWindow("Ray Tracing | Rendering 0%...");

    //Ray Tracing
    startRayTrace();
    cudaDeviceSynchronize();

    const GLubyte* ren = glGetString(GL_RENDERER);
    printf("\n\n\n OpenGL Renderer : %s \n\n", ren);

    //Register Callbacks
    glutDisplayFunc(display);
    glutReshapeFunc(winResize);
    glutKeyboardFunc(keyPress);
    glutKeyboardUpFunc(keyUp);
    glutMainLoop();

    delete[] host_c;
    cudaFree(dev_c);

    return 0;
}

一旦光线追踪完成,host_c[] 就会存储图像数据,我用它来在 glWindow 上显示输出。 glutPostRedisplay() 应该在光线跟踪完成并更新 host_c[] 后重新渲染输出,但 glWindow 会挂起,直到光线跟踪完成。

【问题讨论】:

  • 我唯一能说的是,openGL 在 Nvidia GPU 上运行,该 GPU 目前用于光线追踪。我不确定这是否是问题所在,如果是这样,我也不知道任何解决方法。
  • 目前,当使用相同的 GPU 进行计算操作(例如内核调用)和图形操作(例如 OpenGL)时,这是预期的行为。当内核运行时,GPU 不会为图形任务提供服务。
  • 您正在为整个场景启动 1 个带有 1 个线程的块,然后调用 cudaDeviceSynchronize();,这将阻塞直到内核完成。我相信你正在经历的是预期的行为

标签: c++ visual-studio opengl cuda glut


【解决方案1】:

GLUT 不会读取更多事件,而它就在事件hand.er 中。您正在从键盘回调中调用startRayTrace。然而startRayTrace 不只是启动光线追踪,它还等待完成。正因为如此,GLUT 将被卡住,直到光线追踪完成。

CUDA 内核是异步执行的。要注意内核何时完成,请在 CUDA 流中的内核之后添加cudaEvent。然后注册一个 GLUT idle 回调函数。在该函数中,轮询事件是否完成,当事件完成时,发出glutPostRedisplay。

不要在键盘函数里面cudaSync…,因为那样会卡住。

【讨论】:

    猜你喜欢
    • 2016-01-06
    • 2011-12-01
    • 2011-04-27
    • 2018-10-16
    • 2021-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多