2016-10-02 4 views
1

Мне нужно взять sceenshots в каждом кадре, и мне нужна очень высокая производительность (я использую freeGlut). То, что я понял, что это может быть сделано, как это внутри glutIdleFunc(thisCallbackFunction)Почему glReadPixels настолько медленный и есть альтернатива?

GLubyte *data = (GLubyte *)malloc(3 * m_screenWidth * m_screenHeight); 
glReadPixels(0, 0, m_screenWidth, m_screenHeight, GL_RGB, GL_UNSIGNED_BYTE, data); 
// and I can access pixel values like this: data[3*(x*512 + y) + color] or whatever 

Это делает работу действительно, но у меня есть огромная проблема с этим, это очень медленно. Когда мое окно 512x512, он работает не быстрее, чем 90 кадров в секунду, когда отображается только куб, без этих двух строк он работает на 6500 FPS! Если сравнить его с Irrlicht графического движка, там я могу это сделать

// irrlicht code 
video::IImage *screenShot = driver->createScreenShot(); 
const uint8_t *data = (uint8_t*)screenShot->lock(); 
// I can access pixel values from data in a similar manner here 

и 512x512 окно работает на 400 FPS даже с огромной сеткой (Quake 3 карты) нагруженной! Учтите, что я использую openGL в качестве драйвера внутри irrlicht. Для моего неопытного глаза кажется, что glReadPixels копирует каждый пиксельный файл из одного места в другое, а (uint8_t*)screenShot->lock() просто копирует указатель на уже существующий массив. Можно ли сделать что-то подобное последнему с помощью freeGlut? Я ожидаю, что это будет быстрее, чем irrlicht.

Обратите внимание, что Irrlicht использует OpenGL тоже (ну предлагает DiRectX и другие варианты, как хорошо, но в этом примере я дал выше я использовал OPENGL и, кстати, это был самый быстрый по сравнению с другими вариантами)

+1

Look up Pixel Buffer Объекты, которые позволяют делать это асинхронно. – immibis

+2

Если вы поместите этот код в незанятую функцию, его можно вызвать более одного раза за кадр. Кроме того, вы теряете память, если вы никогда не освобождаете данные, которые вы выделяете. –

+0

@RetoKoradi хорошо, нет, я буквально не выполняю эти строки каждый раз, когда вызывается 'idle'. 'data' выделяется только один раз в конструкторе, и я использую его снова и снова. Теперь я смотрю в PBO .... –

ответ

2

методы OpenGL являются используемый для управления рендерингом трубопровод. По своей природе, пока графическая карта показывает изображение для зрителя, выполняются вычисления следующего кадра. Когда вы звоните glReadPixels; графическая карта ждет выполнения текущего кадра, считывает пиксели и затем начинает вычислять следующий кадр. Поэтому конвейер застопоривается и становится последовательным.

Если вы можете удерживать два буфера и сообщать графической карте для чтения данных в эти буферы, заменяя каждый кадр; то вы можете вернуться назад из своего буфера 1-кадром, но без остановки трубопровода. Это называется двойной буферизацией. Вы также можете сделать тройную буферизацию с 2-мя кадрами с обратным отсчетом и т. Д.

Существует довольно старая веб-страница с описанием явления и реализации здесь: http://www.songho.ca/opengl/gl_pbo.html

Также есть много учебных пособий о фреймбуферов и рендеринга в текстуру в Интернете. Один из них находится здесь: http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/

+0

Итак, я выяснил, как визуализировать текстуру, но я не знаю, как перенести эту текстуру в основной буфер, чтобы она отображалась на экране, а самое главное, как для доступа к значениям пикселей из этой текстуры с использованием индексов (как я показал в вопросе). Что мне делать? –

+0

Вы можете использовать 'glBlitFramebuffer', привязывая задний буфер как' DRAW_BUFFER' и привязывая ваш фреймбуфер текстуры как 'READ_BUFFER' apriori. Это для размещения изображения на экране. Чтобы прочитать значения пикселей, вы используете пиксельный буферный объект (a.k.a. PBO). – zahir

+0

Мне удалось переместить изображение из объекта буфера кадра (где я отобразил мою сцену) в основной буфер, чтобы он отображался на экране, но я все еще не могу получить доступ к значениям пикселей. Я не совсем понимаю, куда должен войти PBO. Этот учебник (http://www.songho.ca/opengl/gl_pbo.html) для меня не кажется таким легким, исходный код длится 600 строк и выглядит действительно запутанным. Что мне делать? Задайте другой вопрос об этом? Я даже не знаю, что именно спросить.Любой совет будет принят во внимание. –