Как вызвать glReadPixels в другом потоке? - PullRequest
1 голос
/ 09 сентября 2011

Когда я вызываю glReadPixels в другом потоке, он не возвращает мне никаких данных. Я где-то читал, предлагая мне создать новый контекст в вызывающем потоке и скопировать память. Как именно я это делаю?

Это код glReadPixels, который я использую:

pixels = new BYTE[ 3 * width * height];
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
image = FreeImage_ConvertFromRawBits(pixels, width, height, 3 * width, 24, 0xFF0000, 0x00FF00, 0x0000FF, false);
FreeImage_Save(FIF_PNG, image, pngpath.c_str() , 0);

В качестве альтернативы я читаю из этой темы они предлагают использовать другой фрагмент кода (см. Конец), но я не понимаю, что такое origX, origY, srcOrigX, srcOrigY?

Ответы [ 3 ]

3 голосов
/ 09 сентября 2011

Вы можете создавать общие контексты, и это будет работать так, как вы хотели. См. wglShareLists (имя выбрано неправильно, оно имеет больше, чем просто списки). Или используйте WGL_ARB_create_context, который также напрямую поддерживает контексты совместного использования (вы пометили вопрос "windows", но аналогичная функциональность существует и для не-WGL).

Однако гораздо проще использовать объект пиксельного буфера, который будет иметь тот же чистый эффект, что и многопоточность (передача будет выполняться асинхронно, без блокировки потока рендеринга), и это во много раз менее сложно.

3 голосов
/ 10 сентября 2011

У вас есть разные варианты.

Вы вызываете ReadPixel , конвейеризованный с потоком рендеринга.В этом случае возвращаемые данные должны храниться в буфере, который может быть помещен в очередь для потока, который предназначен для сохранения изображений.Это можно легко сделать с помощью очереди буфера, мьютекса и семафора: поток рендеринга получает данные, используя ReadPixel , блокирует мьютекс, ставит в очередь (память системы) пиксельный буфер, разблокирует мьютекс, увеличивает семафор;рабочий поток (заблокированный на семафоре) будет сигнализирован потоком рендеринга, заблокирует мьютекс, освободит буфер пикселов, разблокирует мьютекс и сохранит изображение.

В противном случае вы можете скопировать текущий кадровый буфер натекстура или пиксельный буферный объект.В этом случае у вас должно быть два разных потока, каждый из которых имеет текущий контекст OpenGL (через MakeCurrent ) и совместно использует свое пространство объектов друг с другом (как предлагает user771921 ).Когда первый поток рендеринга вызывает ReadPixels (или CopyPixels ), уведомляет второй поток об операции (например, с использованием семафора);второй поток рендеринга отобразит буферный объект пикселя (или получит данные текстуры).Этот метод имеет то преимущество, что позволяет драйверу передавать первую операцию чтения потока, но он фактически удваивает операции копирования памяти, вводя дополнительный вспомогательный буфер.Более того, операция ReadPixel сбрасывается, когда второй поток отображает буфер, который выполняется (наиболее вероятно) сразу после сигнализации второго потока.

Я бы предложил первый вариант, поскольку оннамного чище и проще.Второй вариант слишком сложен, и я сомневаюсь, что вы можете воспользоваться его преимуществами: операция сохранения изображений выполняется намного медленнее, чем ReadPixel .

Даже если ReadPixel не передается по конвейеру, делает ли этоFPS действительно тормозит?Не оптимизируйте, прежде чем вы сможете профилировать.

В приведенном вами примере используются функции GDI, которые не связаны с OpenGL.Я думаю, что код вызовет repaint событие формы и затем захватит содержимое клиентской области окна.Это выглядит намного медленнее по сравнению с ReadPixel , даже если я фактически не выполнял профилирование по этой проблеме.

1 голос
/ 09 сентября 2011

Что ж, использование opengl в многопоточной программе - плохая идея, особенно если вы используете функции opengl в потоке, у которого нет контекста.

Кроме того, в вашем примере кода нет ничего плохого.

...