Что произойдет, если вы вызовете glBufferData для отображаемого буфера?

Что произойдет, если вы вызовете glBufferData для буфера, сопоставленного с glMapBufferRange? Я предполагаю, что это было бы незаконно, но я ничего не могу найти в спецификации:

https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glBufferData.xhtml

Это незаконно в спецификации glDrawArrays.

Хорошо, дополнительная задача:

Что, если у нас есть контекстное совместное использование ресурсов, и буфер в настоящее время отображается в потоке A с контекстом A, тогда поток B в контексте B вызывает для него glBufferData?


person Desperado17    schedule 26.07.2019    source источник


Ответы (1)


Для сценария с одним контекстом, когда вызывается glBufferData(), существующий объект буфера удаляется, любые активные привязки этого ресурса в этом контексте будут развязаны, а все активные сопоставления будут удалены. Если вы вызовете glUnmapBuffer() после glBufferData() из того же контекста, вы получите ошибку GL_INVALID_OPERATION, потому что состояние новой версии буфера изначально не отображается.

Для многоконтекстного сценария все становится сложнее. OpenGL ES определяет слабо согласованную модель управления состоянием (чтобы избежать дорогостоящих требований к блокировке на критичных для производительности путях вызовов).

  • Состояние рендеринга, принадлежащее контексту (например, информация о привязке, разрешающие биты), никогда не может быть изменено другим контекстом (может быть реализовано без блокировки).
  • Состояние ресурса, которое принадлежит объекту (например, буферы, сэмплеры, текстуры), слабо когерентно. Контекст немедленно увидит свои собственные изменения, но подхватит изменения, записанные другим контекстом, только при привязке ресурса (требуется блокировка только при изменениях привязки).
  • Полезная нагрузка данных ресурсов вообще не согласованна. Если вы хотите, чтобы данные были доступны из одного контекста в другом, вы должны включить ручную синхронизацию между потоками.

Поток. Вызов glMapBuffer() создаст копию основного состояния буфера "версия 1", включая локальную настройку состояния, указывающую на то, что буфер "сопоставлен".

Поток B, вызывающий glBufferData(), создаст новую версию ресурса буфера «версия 2», но это не повлияет на состояние, удерживаемое потоком A, которое будет продолжать отражать состояние на момент, когда буфер был связан в потоке A (версия 1). ).

Поток A, вызывающий glUnmapBuffer(), будет работать нормально, потому что он отменяет сопоставление буфера «версии 1» (отображенное состояние является локальным для контекста потока A, и это все еще говорит, что буфер «сопоставлен»).

Обратите внимание, что содержимое данных буфера, которое поток A видит после того, как поток B вызывает glBufferData(), непредсказуем (это могут быть старые данные, это могут быть новые данные), в соответствии с дизайном, что данные вообще не связаны. Если не было ожидающих операций отрисовки, то для драйвера допустимо просто повторно использовать память, которая была поддержана «версией 1» буфера, чтобы содержать содержимое, которое было загружено для «версии 2». Если вам нужны гарантии согласованности данных в разных контекстах, вам нужна ручная синхронизация (концептуально это похоже на то, как два потока вызывают glBufferData() в одном и том же буфере в одно и то же время).

Я бы рекомендовал прочитать главу 5 спецификации OpenGL ES 3.2.

person solidpixel    schedule 26.07.2019
comment
Итак, предположим, что поток A вызывает glMapBufferRange, предполагая, что отображаемая область имеет определенный размер. Затем поток B вызывает glBufferData, но с меньшим размером, чем раньше. Может ли это означать, что указатель сопоставления из потока A теперь указывает на область меньше запрошенной, что приводит к segfault при доступе? - person Desperado17; 27.07.2019
comment
Нет, страницы должны быть подсчитаны операцией сопоставления. - person solidpixel; 28.07.2019
comment
... но если вы столкнетесь с этой ситуацией, вы уже находитесь в неопределенном поведении, поэтому он не сработает, но может отобразить мусор. - person solidpixel; 28.07.2019
comment
Когда именно мы перешли к неопределенному поведению? Выдает ли одна из функций код ошибки? - person Desperado17; 29.07.2019
comment
Обратите внимание, что содержимое данных буфера, которое поток A видит после того, как поток B вызывает glBufferData(), непредсказуем (это могут быть старые данные, это могут быть новые данные), в соответствии с дизайном, что данные вообще не связаны - person solidpixel; 29.07.2019
comment
Вылетать не собирается, но содержимое памяти на тот момент времени уже плохо определяется при отсутствии дополнительной синхронизации. Это не относится к мапбуферу — любое параллельное обновление одной и той же памяти (например, два конфликтующих одновременных обновления с использованием glBufferSubData()) будет иметь ту же проблему). Отсутствие сбоев - наименьшая из ваших проблем, если у вас есть дизайн, который может пытаться одновременно обновлять одну и ту же память из двух потоков без синхронизации... - person solidpixel; 29.07.2019