Является ли компиляция шейдера во время рендеринга хорошей/допустимой практикой в ​​OpenGL ES?

Система: Android 4.03, OpenGL ES 2.0

Проблема: когда glAttachShader вызывается после того, как первый кадр уже был обработан другой программой/шейдером, некоторые устройства (Galaxy S3) аварийно завершают работу с ошибкой "GL_INVALID_VALUE" (дополнительные сведения в стеке ошибок отсутствуют). ). Другие устройства (Asus eee TF101) прекрасно с этим справляются. Ошибка возникает не всегда, а иногда это также «GL_INVALID_ENUM». Если я принудительно компилирую все шейдеры сразу при первом вызове onDrawFrame, он работает на всех (моих) устройствах.

Вопросы. Существуют ли состояния, в которых машина openGL(ES) не может скомпилировать шейдер? Возможно ли, что связанные буферы, текстуры или активные массивы атрибутов мешают присоединению шейдера к программе? Если да, то какое идеальное состояние необходимо обеспечить перед подключением шейдеров и компоновкой программы? Можно ли вообще компилировать шейдеры после того, как другие объекты уже были обработаны другими шейдерами?

Предыстория: я разрабатываю библиотеку для Android, которая позволит мне использовать графику openGL более объектно-ориентированным способом (используя такие объекты, как «сцена», «материал», «модель» и т. д.), максимально легко писать игры. Сцены, модели и т. д. создаются в потоке, отличном от контекста GL. Только когда onDrawFrame встречает один из этих объектов, он выполняет привязку объекта буфера, привязку текстуры и компиляцию шейдера в правильном потоке. Я хотел бы избежать компиляции всех шейдеров в начале моего кода. Исходный код шейдера собирается в зависимости от требований материала, модели и сцены (например: Материал: включить бамп-мэппинг, Модель: включить матричный-палитровый скимминг, сцена: включить туман). Когда модель удаляется из сцены, я снова удаляю шейдер, а если я добавляю другую модель, новый шейдер должен быть скомпилирован ad-hoc.

На этом этапе я стараюсь быть максимально кратким, не публикуя код — вы можете себе представить, как сложно извлечь соответствующие части из этой библиотеки.


person Jan_K    schedule 22.01.2013    source источник


Ответы (2)


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

СОВЕТ: Обязательно «используйте» все переменные, юниформы и атрибуты, объявленные в вашем шейдере, иначе драйвер Mali удалит их во время компиляции, и когда вы попытаетесь получить юниформное местоположение, местоположение атрибута и сын, драйверы вернут GL_INVALID_VALUE.

Надеюсь, это поможет.

person Trax    schedule 22.01.2013
comment
Звучит интересно — правильно ли я понял, что драйвер будет автоматически перекомпилировать шейдеры при срабатывании определенных состояний/событий, даже если они были скомпилированы ранее? Где я могу узнать больше об этом поведении? - person Jan_K; 22.01.2013
comment
Это прозрачно для вас, но понимание последствий является ключом к хорошей производительности. Посмотрите, например, документацию по Tegra здесь: docs.nvidia.com/tegra/data/ - person Trax; 22.01.2013
comment
AMD предоставляет исполняемый файл Windows под названием MakeBinaryShader.exe, который компилирует текстовые шейдеры в двоичные файлы. AMD также предоставляет интерфейс на основе библиотеки BinaryShader.lib, который предоставляет функции, которые вы можете вызывать для компиляции шейдеров непосредственно из приложения. Imagination Technologies также предоставляет собственный инструмент компиляции бинарных шейдеров под названием PVRUniSCo вместе с редактором под названием PVRUniSCo Editor. - person Patt Mehta; 22.01.2013
comment
Это уловка-22 для меня. Признание того, что то, что я делаю, правильно, не решит мою проблему, а предположение о том, что я делаю неправильно, превратит 200 КБ кода в цифровой мусор. Прежде чем я приму ваш ответ, я попытаюсь создать код postable, который должен выявить проблему. Вернусь! - person Jan_K; 22.01.2013
comment
Даже я хотел создать библиотеку и создавать двоичные файлы шейдеров в автономном режиме, но я мог управлять парсерами obj только с помощью Perl, которые работали в автономном режиме. Обработку GPU можно значительно сэкономить, если бы был простой способ компилировать шейдеры в автономном режиме. Если это 200 КБ, не выбрасывайте его :D - person Patt Mehta; 23.01.2013

Если вы скопируете пример кода BasicGLSurfaceView, поставляемый с комплектом разработки для Android, чтобы начать свой проект, то первый вызов

checkGlError

находится после присоединения вершинного шейдера. Однако вы могли использовать недопустимое значение или перечисление намного раньше или в другом месте кода. Но это будет подхвачено только этим вызовом после glAttachShader.

В моем случае я удалил текстуру, которая все еще была связана как цель рендеринга для фреймбуфера. Мое старое устройство Android, которое работает медленнее, скомпилировало шейдер перед удалением, моему новому устройству каким-то образом удалось вызвать

glFramebufferTexture2D

перед компиляцией шейдера. Все это каким-то образом связано с queueEvent и моим плохим пониманием потокобезопасности.

Спасибо за ваши усилия, TraxNet и Prateek Nina.

person Jan_K    schedule 26.01.2013