Производительность взаимодействия OpenGL/OpenCL в glBindTexture(), glBegin()

Я работаю над приложением OS X в настройке с несколькими графическими процессорами (Mac Pro, конец 2013 г.), которая использует OpenCL (на вторичном графическом процессоре) для создания текстуры, которая позже отображается на экране с помощью OpenGL (на основной графический процессор) . Приложение загружает ЦП из-за вызовов glBindTexture() и glBegin(), которые тратят практически все свое время на:

_platform_memmove$VARIANT$Ivybridge

который является частью видеодрайвера:

AMDRadeonX4000GLDriver

Настройка: создает текстуру OpenGL (glPixelBuffer), а затем ее аналог OpenCL (clPixelBuffer).

cl_int clerror = 0;
GLuint glPixelBuffer = 0;
cl_mem clPixelBuffer = 0;

glGenTextures(1, &glPixelBuffer);
glBindTexture(GL_TEXTURE_2D, glPixelBuffer);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2048, 2048, 0, GL_RGBA, GL_FLOAT, NULL);
glBindTexture(GL_TEXTURE_2D, 0);

clPixelBuffer = clCreateFromGLTexture(_clShareGroupContext, CL_MEM_WRITE_ONLY, GL_TEXTURE_2D, 0, glPixelBuffer, &clerror);

Код отрисовки: сопоставляет текстуру OpenGL с областью просмотра. Весь NSOpenGLView — это всего лишь одна текстура.

glClear(GL_COLOR_BUFFER_BIT);

glBindTexture(GL_TEXTURE_2D, _glPixelBuffer);  // <- spends cpu time here,
glBegin(GL_QUADS);                             // <- and here
glTexCoord2f(0., 0.); glVertex3f(-1.f,  1.f, 0.f);
glTexCoord2f(0., hr); glVertex3f(-1.f, -1.f, 0.f);
glTexCoord2f(wr, hr); glVertex3f( 1.f, -1.f, 0.f);
glTexCoord2f(wr, 0.); glVertex3f( 1.f,  1.f, 0.f);
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);

glFlush();

Получив контроль над памятью текстуры (через clEnqueueAcquireGLObjects()), ядро ​​OpenCL записывает данные в текстуру, а затем освобождает контроль над ней (через clEnqueueReleaseGLObjects()). Данные текстуры никогда не должны существовать в основной памяти (если я все это правильно понимаю).

Мой вопрос: ожидается ли, что так много процессорного времени тратится на memmove()? Указывает ли это на проблему в моем коде? Или ошибка в драйвере, возможно? Мое (необоснованное) подозрение состоит в том, что данные текстуры перемещаются через: GPUx -> CPU/RAM -> GPUy, чего я хотел бы избежать.


person senojsitruc    schedule 02.10.2014    source источник
comment
У вас есть соединение crossfire/sli? Какая у вас версия PCI-E и пропускная способность? Насколько велика ваша текстура?   -  person huseyin tugrul buyukisik    schedule 03.10.2014
comment
Это Mac OS X, поэтому нет поддержки Crossfire или SLI. Каждый графический процессор имеет пропускную способность PCIe 3.0 15,7 ГБ/с (по 16 линий каждый). И мое приложение работает с (в зависимости от конфигурации) от одной до трех текстур в разрешении 2048x2048.   -  person senojsitruc    schedule 03.10.2014


Ответы (1)


Прежде чем я коснусь передачи памяти, мое первое наблюдение состоит в том, что вы используете clBegin(), которая не станет вашим лучшим другом, потому что

1) Этот прямой рисунок плохо работает с драйвером. Вместо этого используйте VBO и т. д., чтобы эти данные могли жить на графическом процессоре.

2) В OS X это означает, что вы находитесь в их старом контексте совместимости, а не в новом основном контексте. Поскольку (я понимаю) новый контекст является полностью переписанным, именно здесь будущие оптимизации закончатся, в то время как используемый вами контекст (вероятно) просто поддерживается.

Итак, что касается передачи памяти.... на стороне GL вы добавляете сюда glCreateSyncFromCLeventARB() и glWaitSync()? Не должно быть необходимости в glFlush(), которую я вижу в вашем коде. После того, как вы избавились от отрисовки непосредственного режима (как упоминалось выше) и используете объекты синхронизации между двумя API, ваш хост-код не должен ничего делать (кроме того, как попросить драйвер сказать GPU что-то делать). Это даст вам наилучшие шансы на получение быстрых буферных копий....

Да, копии :( Поскольку ваша текстура CL физически находится в другом фрагменте памяти графического процессора по сравнению с текстурой GL, должна быть копия по шине PCIe, которая будет медленной (er). Это то, что вы видите в своем профилировании. На самом деле происходит то, что ЦП отображает память графического процессора A и память графического процессора B в закрепленную память хоста, а затем копирует между ними (надеюсь) с помощью прямого доступа к памяти.

Попробуйте поместить свои контексты CL и GL на один и тот же графический процессор, и я думаю, вы увидите, что время передачи исчезнет.

Заключительная мысль: если ваши вычисления CL затмеваются временем передачи, вероятно, лучше всего разместить контексты на одном и том же процессоре. У вас есть классическая проблема разделения задач CPU/GPU.

person user2746401    schedule 24.10.2014
comment
Спасибо за ответ. Я попробую, как только смогу! - person senojsitruc; 24.10.2014