OpenCL / OpenGL тратит впустую процессор - PullRequest
5 голосов
/ 23 июня 2019

Я генерирую кадры в OpenCL 60 раз в секунду, используя каждый раз один вызов ядра OpenCL, и записываю их в текстуру OpenGL, чтобы я мог отобразить их на экране.Нет проблем с производительностью, частота кадров соответствует ожидаемой, однако проблема в том, что она очень расточительна, она полностью занята хотя бы одним ядром ЦП, даже когда ему мало что нужно сделать, например, вывести пустой кадр с очень низким разрешением,Для сравнения, когда я не использую взаимодействие OpenGL, а вместо этого записываю из ядра CL в общий буфер, а затем копирую этот буфер обратно на хост, чтобы затем отобразить его другим способом, частота кадров немного падает (из-заЧетвертая часть накладных расходов, которую взаимодействие делает ненужным), но тогда загрузка ЦП намного ниже, когда мало что сделать.

Это означает, что с тем, как я выполняю взаимодействие, что-то не так, что, как я полагаю, должно создать какую-то занятостьподождите.

Вот соответствующий код, который является кодом, который присутствует, когда я использую взаимодействие, и не существует, когда я его не использую.В одном месте моего цикла я очищаю текстуру GL и заставляю OpenCL получить ее:

    uint32_t z = 0;
    glClearTexImage(fb.gltex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &z);
    glFlush();
    glFinish();

    clEnqueueAcquireGLObjects(fb.clctx.command_queue, 1,  &fb.cl_srgb, 0, 0, NULL);

Затем я ставлю в очередь выполнение моего ядра OpenCL, которое записывает в текстуру как объект cl_mem fb.cl_srgb ипозже я возвращаю управление OpenGL, чтобы отобразить текстуру на дисплее:

    clEnqueueReleaseGLObjects(fb.clctx.command_queue, 1, &fb.cl_srgb, 0, 0, NULL);
    clFinish(fb.clctx.command_queue);   // this blocks until the kernel is done writing to the texture and releasing the texture

    // setting GL texture coordinates, probably not relevant to this question
    float hoff = 2. * (fb.h - fb.maxdim.y) / (double) fb.maxdim.y;
    glLoadIdentity();             // Reset the projection matrix
    glViewport(0, 0, fb.maxdim.x, fb.maxdim.y);

    glBegin(GL_QUADS);
    glTexCoord2f(0.f, 0.f); glVertex2f(-1., 1.+hoff);
    glTexCoord2f(1.f, 0.f); glVertex2f(1., 1.+hoff);
    glTexCoord2f(1.f, 1.f); glVertex2f(1., -1.+hoff);
    glTexCoord2f(0.f, 1.f); glVertex2f(-1., -1.+hoff);
    glEnd();

    SDL_GL_SwapWindow(fb.window);

Мне трудно сказать, что является причиной этого, поскольку высокая загрузка ЦП находится в другом потоке, выполняемом nvopencl64.dll(когда я запускаю его на своем компьютере с Windows 10 с графическим процессором nVidia, но у меня похожая проблема с ноутбуком с Intel iGPU, также на Windows 10).

Профилирование говорит мне, что большая часть времени процессораWaitForSingleObjectEx (исключая 42% процессорного времени) вызывается из nvopencl64.dll, WaitForMultipleObjects (21%) вызывается из DrvPresentBuffers nvoglv64.dll и RtlUserThreadStart (16%) вызовов, которые инициируют вышеупомянутыеWaitForMultipleObjects звонки.Это для моей машины с графическим процессором nVidia, но ситуация выглядит довольно похоже на машине с Intel HD 5000 iGPU.Очевидно, что происходит что-то очень неэффективное, возможно, слишком много потоков запускается слишком часто.

1 Ответ

2 голосов
/ 01 июля 2019

Кажется, что когда CL_DEVICE_PREFERRED_INTEROP_USER_SYNC равно false, ручная синхронизация с clEnqueueAcquireGLObjects и clEnqueueReleaseGLObjects не требуется, за исключением одного вызова clEnqueueAcquireGLObjects после инициализации текстуры OpenGL.В этом случае кажется, что glFinish является единственной необходимой формой синхронизации.

...