Преобразование обратной связи: объедините несколько отзывов
Цель: OpenGL ES >= 3.0.
Вот что делает мое приложение:
generateSeveralMeshes()
setupStuff();
for (each Mesh)
{
glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, myBuf);
glBeginTransformFeedback( GLES30.GL_POINTS);
callOpenGLToGetTransformFeedback();
glMapBufferRange(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, ...) // THE PROBLEM
computeStuffDependantOnVertexAttribsGottenBack();
glUnmapBuffer(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER);
glEndTransformFeedback();
glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
renderTheMeshAsNormal();
}
то есть для каждой сетки, он сначала использует вершинный шейдер для вычисления некоторого материала для каждой вершины, возвращает материал обратно в ЦП, основываясь на том, что он принимает некоторые решения, и только затем визуализирует сетку.
Это работает, проблема в скорости. Мы тестировали на нескольких устройствах на базе OpenGL ES 3.0, 3.1, 3.2, и на каждом из них история выглядит одинаково: вызов glMapBufferRange() сокращает FPS примерно до половины!
Я подозреваю, что без glMapBufferRange() OpenGL может рендерить 'лениво', то есть объединять несколько рендеров вместе и делать их по своему усмотрению, в то время как если мы вызываем glMapBufferRange(), он действительно должен рендериться сейчас, что, вероятно, замедляет его количество данных, которые мы получаем, довольно мало, я действительно не думаю, что это проблема).
Таким образом, я хотел бы также объединить мою обратную связь с Transform, например:
generateSeveralMeshes()
setupStuff();
for (each Mesh)
{
glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, myLargerBuf);
glBeginTransformFeedback( GLES30.GL_POINTS);
setupOpenGLtoSaveTransformFeedbackToSpecificOffset();
callOpenGLToGetTransformFeedback();
advanceOffset();
glEndTransformFeedback();
glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
renderTheMeshAsNormal();
}
glMapBufferRange(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, ...)
computeStuffDependantOnVertexAttribsGottenBackInOneBatch();
glUnmapBuffer(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER);
Проблема в том, что я не знаю, как сказать OpenGL сохранять выходные данные Transform Feedback не в начало, а в конкретное смещение в TRANSFORM_FEEDBACK_BUFFER (чтобы позже я мог, после цикла, возложить руки на все TF данные вернулись за один раз).
Любой совет?
1 ответ
Проблема с производительностью заключается в конвейерной обработке - вы в основном заставляете GPU зависать с процессором, потому что glMapBufferRange()
должен блокировать, пока результат не будет доступен. Это "очень плохо" - все графические процессоры (особенно графические графические процессоры в мобильных устройствах) полагаются на то, что драйвер создает очередь работы, которая асинхронно запускается для приложения и, таким образом, поддерживает давление, чтобы поддерживать аппаратную занятость. Все, что приложение делает для принудительной синхронизации и опустошения конвейера, снижает производительность.
Хороший блог об этом здесь:
В общем, если вы читаете данные с ЦП, считывайте данные только на один или два кадра после того, как вы поставили в очередь вызовы отрисовки, которые их сгенерировали. (Использование результатов на GPU не имеет этой проблемы - это приведет к конвейеру).
Чтобы связать смещения буфера в буфере обратной связи преобразования, согласно комментарию используйте glBindBufferRange()
,