Рекомендации по управлению ресурсами
Управляемые текстуры, также известные как автоматическое управление текстурами, были доступны в DirectX с версии 6, с несколькими редакциями и улучшениями, сделанными в последующих выпусках. С выпуска API Direct3D 9 автоматическое управление ресурсами включает поддержку текстур, буферов вершин и буферов индексов с согласованным общим интерфейсом. С помощью диспетчера ресурсов Direct3D приложения могут значительно упростить обработку ситуаций потери устройств и могут полагаться на систему для обработки разумного объема избыточных ресурсов видеопамяти.
Иногда у разработчиков возникают трудности с использованием управляемых ресурсов, отчасти из-за абстрактного характера системы. Хотя многие распространенные сценарии для ресурсов хорошо подходят для управляемых ресурсов, некоторые случаи лучше работают при использовании неуправляемых ресурсов. В этой статье рассматриваются рекомендации по работе с ресурсами в целом, поведение управляемых и неуправляемых ресурсов, а также приводятся некоторые сведения о том, как ресурсы обычно обрабатываются средой выполнения и драйверами.
В этой статье рассматриваются следующие понятия:
- Видеопамять
- Управляемые ресурсы
- Ресурсы, управляемые драйвером
- Ресурсы по умолчанию
- Ресурсы системной памяти
- Общие рекомендации
- Связанные темы
Видеопамять
Чтобы видеосистема пользовалась ресурсом, она должна находиться в памяти, доступной для GPU. Локальная видеопамять обеспечивает наилучшую производительность gpu, а определенные ресурсы (например, целевые объекты отрисовки и буферы глубины и трафарета) должны находиться в локальной видеопамяти. С появлением AGP GPU также может напрямую обращаться к части системной памяти. Эта область памяти, известная как диафрагма AGP, называется нелокационной видеопамятью и недоступна для других целей. Нелоклационная видеопамяти может считываться из ЦП и записываться в нее, который обычно не имеет высокопроизводительного доступа к локальной видеопамяти и поэтому идеально подходит для использования в качестве ресурса общей памяти. Важно помнить о памяти AGP, так как она, как и локальная видеопамять, становится недействительной в ситуациях с потерянным устройством, и постоянные ресурсы, расположенные в ней, должны быть восстановлены.
Рис. 1. Отношение GPU, ЦП, ОЗУ видео и ОЗУ системы
Некоторые интегрированные решения для видео используют унифицированную архитектуру памяти (UMA), где main память адресуется всеми компонентами систем. Direct3D поддерживает UMA, не требуя каких-либо изменений в приложении, используя те же указания, что и для конфигураций локальной видеопамяти. Для таких систем ресурсы всегда находятся в системной памяти, и драйвер отвечает за обеспечение того, чтобы ресурсы работали так же, как в более традиционной архитектуре, используя при этом свойства UMA и любое конкретное поведение реализации оборудования.
Рис. 2. GPU и ЦП имеют равный доступ к системной ОЗУ в единой архитектуре памяти
Управляемые ресурсы
Большинство ресурсов следует создавать в качестве управляемых ресурсов в POOL_MANAGED. Все ресурсы будут созданы в системной памяти, а затем скопированы по мере необходимости в видеопамяти. Ситуации с потерянными устройствами будут обрабатываться автоматически из копии системной памяти. Так как не все управляемые ресурсы требуются для размещения в видеопамяти одновременно, можно перезафиксировать память, где для отрисовки в любом кадре требуется меньший рабочий набор ресурсов видеопамяти. Обратите внимание, что большая часть этой системной памяти резервного хранилища со временем будет выгружена на диск, поэтому операция сброса может быть медленной из-за необходимости вернуть эти данные для восстановления потерянной видеопамяти.
Среда выполнения сохраняет метку времени для последнего использования ресурса, и при сбое выделения видеопамяти для загрузки необходимого управляемого ресурса она освобождает ресурсы на основе этой метки времени в режиме LRU. Использование SetPriority имеет приоритет над меткой времени, поэтому более часто используемые ресурсы должны иметь более высокий приоритет. Direct3D 9.0 содержит ограниченные сведения о видеопамять, управляемой драйвером, поэтому среде выполнения может потребоваться выселить несколько ресурсов, чтобы создать достаточно большой регион для успешного выделения. Правильные приоритеты могут помочь устранить ситуации, когда что-то вытеснит, а затем снова вскоре после этого. Приложение также может вызвать EvictManagedResources , чтобы принудительно удалить все управляемые ресурсы. Опять же, эта операция может занять много времени для перезагрузки всех ресурсов, необходимых для следующего кадра, но очень полезна для переходов уровня, когда рабочий набор значительно меняется, и для удаления фрагментации видеопамяти.
Количество кадров также сохраняется, чтобы позволить среде выполнения определить, использовался ли ресурс, который она только что выбрала для вытеснения, в начале текущего кадра, что подразумевает ситуацию обтухания, когда в одном кадре используется больше ресурсов, чем помещается в видеопамяти. Это активирует политику замены для переключения на моду MRU, а не LRU для оставшейся части кадра, так как это, как правило, работает немного лучше в таких условиях. Такое поведение обмотки значительно повлияет на производительность отрисовки. Обратите внимание, что понятие текущего кадра связано с EndScene, поэтому любое приложение, использующее управляемые ресурсы, должно регулярно вызывать этот метод.
Разработчики, желающие найти дополнительные сведения о том, как работают управляемые ресурсы в своем приложении, могут использовать запрос событий RESOURCEMANAGER через интерфейс IDirect3DQuery9 . Это работает только при использовании среды выполнения отладки, поэтому эти сведения не могут зависеть от приложения, но предоставляют подробные сведения о ресурсах, управляемых средой выполнения.
Хотя понимание того, как работает диспетчер ресурсов, может помочь при настройке и отладке приложений, важно не связывать приложение слишком тесно со сведениями о реализации текущей среды выполнения или драйверов. Редакции драйвера или изменения в оборудовании могут значительно изменить поведение, а в будущих версиях Direct3D будет значительно улучшено и сложное управление ресурсами.
Ресурсы Driver-Managed
Драйверы Direct3D могут бесплатно реализовать возможности текстур, управляемых драйвером, которые указываются D3DCAPS2_CANMANAGERESOURCE, что позволяет драйверу управлять ресурсами, а не средой выполнения. Для (редкого) драйвера, реализующего эту функцию, точное поведение диспетчера ресурсов драйвера может сильно различаться, и обратитесь к поставщику драйвера для получения сведений о том, как это работает для его реализации. Кроме того, можно убедиться, что диспетчер среды выполнения всегда используется, указав D3DCREATE_DISABLE_DRIVER_MANAGEMENT при создании устройства.
Ресурсы по умолчанию
Хотя управляемые ресурсы просты, эффективны и просты в использовании, бывают случаи, когда использование видеопамяти напрямую является предпочтительным или даже обязательным. Такие ресурсы создаются в категории POOL_DEFAULT. Использование таких ресурсов приводит к дополнительным осложнениям для приложения. Код необходим, чтобы справиться с ситуацией с потерей устройства для всех POOL_DEFAULT ресурсов, и при копировании данных в них необходимо учитывать факторы производительности. Неуказание USAGE_WRITEONLY или блокировка целевого объекта визуализации также может привести к серьезным ограничениям производительности.
Вызов блокировки ресурса POOL_DEFAULT, скорее всего, приведет к остановке GPU, чем работа с ресурсом POOL_MANAGED, если не используются определенные флаги указания. В зависимости от расположения ресурса возвращаемый указатель может находиться во временном буфере системной памяти или быть указателем непосредственно на память AGP. Если это временный буфер системной памяти, данные необходимо передать в видеопамяти после вызова Unlock . Если видеоресурс не предназначен только для записи, во время блокировки данные должны быть переданы во временный буфер. Если это область памяти AGP, временные копии избегаются, но требуемое поведение кэша может привести к снижению производительности.
Следует соблюдать осторожность при записи строки полного кэша данных в любой указатель на память с диафрагмой AGP, чтобы избежать ограничения записи и расчесывания, что вызывает цикл чтения и записи, и предпочтительнее последовательный доступ к области памяти. Если приложению требуется случайный доступ к данным во время создания и вы не хотите использовать управляемый ресурс для буфера, следует работать с копией системной памяти. После создания данных можно выполнить потоковую передачу результата в заблокированную память ресурса, чтобы избежать уплаты большого штрафа за операцию записи в кэше.
Флаг LOCK_NOOVERWRITE можно использовать для эффективного добавления данных для некоторых ресурсов, но в идеале можно избежать нескольких вызовов Lock и Unlock к одному ресурсу. Для оптимальной производительности важно правильное использование различных флагов блокировки, как и использование удобного в кэше шаблона доступа к данным при заполнении заблокированной памяти.
Использование управляемых ресурсов и ресурсов по умолчанию
Перемешивание выделения управляемых и POOL_DEFAULT ресурсов может привести к фрагментации видеопамять и запутать представление среды выполнения о видеопаметь, доступной для управляемых ресурсов. В идеале следует создать все POOL_DEFAULT ресурсы перед использованием POOL_MANAGED ресурсов или использовать вызов EvictManagedResources перед выделением неуправляемых ресурсов. Помните, что все выделения из POOL_DEFAULT, которые находятся в видеопамяти, связывают память для ресурса, который недоступен для использования диспетчером ресурсов или для любых других целей.
Обратите внимание, что в отличие от предыдущих версий Direct3D, среда выполнения версии 9 автоматически вытесняет некоторые управляемые ресурсы, прежде чем отказаться от неуправляемого выделения ресурсов из-за нехватки видеопамяти, но это может привести к дополнительной фрагментации и даже принудительному переходу ресурса в неоптимическое расположение (например, наличие статической текстуры в нелокальной видеопамяти). Опять же, лучше заранее выделить все необходимые неуправляемые ресурсы и перед использованием управляемых ресурсов.
Динамические ресурсы по умолчанию
Данные, которые создаются и обновляются с высокой частотой, не нуждаются в резервном хранилище, так как вся информация будет создана повторно при восстановлении устройства. Такие данные обычно лучше всего создавать в POOL_DEFAULT, указывая USAGE_DYNAMIC подсказку, чтобы драйвер может принимать решения по оптимизации при размещении ресурса, зная, что он будет часто обновляться. Обычно это означает, что ресурс помещается в нелокционную видеопамять, и, следовательно, доступ к gpu обычно выполняется гораздо медленнее, чем к локальной видеопамяти. Для архитектур UMA драйвер может выбрать определенное расположение для динамических ресурсов, чтобы оптимизировать доступ на запись ЦП.
Это типично для программных решений для обрезки и систем частиц на основе ЦП, заполняющих буферы вершин и индексов, а флаг LOCK_DISCARD гарантирует, что остановки не создаются в тех случаях, когда ресурс по-прежнему используется из предыдущего кадра. Использование управляемого ресурса в этом случае приведет к обновлению буфера системной памяти, который затем копируется в видеопамяти, а затем используется только для кадра или двух перед заменой. Для систем с нелокейной видеопамять дополнительная копия исключается при правильном использовании этого динамического шаблона.
Стандартные текстуры не могут быть заблокированы и могут быть обновлены только с помощью UpdateSurface или UpdateTexture. Некоторые системы поддерживают динамические текстуры, которые можно заблокировать и использовать шаблон LOCK_DISCARD, но перед использованием таких ресурсов необходимо проверить бит возможностей (D3DCAPS2_DYNAMICTEXTURES). Для высокодинамовых текстур (видео или процедурных) приложение может создавать соответствующие POOL_DEFAULT и POOL_SYSTEMMEM ресурсы и обрабатывать обновления видеопамяти с помощью UpdateTexture. Для очень частых и частичных обновлений парадигма UpdateTexture , скорее всего, является лучшим выбором.
Будьте осторожны при проектировании систем, которые в значительной степени зависят от динамической отправки. Статические ресурсы следует помещать в POOL_MANAGED, чтобы обеспечить хорошее использование локальной видеопамяти, а также более эффективно использовать ограниченную пропускную способность шины и main памяти. Для полустатических ресурсов может оказаться, что стоимость случайной отправки в локальную видеопамяти гораздо меньше, чем постоянный трафик шины, создаваемый за счет их динамической передачи.
Ресурсы системной памяти
Ресурсы также можно создавать в POOL_SYSTEMMEM. Хотя они не могут использоваться графическим конвейером, их можно использовать в качестве источников для обновления POOL_DEFAULT ресурсов с помощью UpdateSurface или UpdateTexture. Их блокировка является простой, хотя может возникнуть застой, если они используются одним из ранее упомянутых методов.
Хотя они находятся в системной памяти, POOL_SYSTEMMEM ресурсы ограничены теми же форматами и возможностями (например, максимальным размером), которые поддерживаются драйвером устройства. Тип ресурса POOL_SCRATCH — это еще одна форма ресурса системной памяти, которая может использовать все форматы и возможности, поддерживаемые средой выполнения, но недоступна для устройства. Временные ресурсы предназначены в основном для использования средствами содержимого.
Рис. 3. Ресурсы памяти в ОЗУ видео, диафрагме AGP и системном ОЗУ
Основные рекомендации
Правильное получение сведений о технической реализации управления ресурсами будет иметь большое значение для достижения целей производительности приложения. Планирование представления ресурсов в Direct3D и архитектурного проектирования для своевременной загрузки данных является более сложной задачей. Мы рекомендуем использовать ряд рекомендаций при принятии следующих решений для вашего приложения:
- Предварительная обработка всех ресурсов. Полагаться на дорогостоящее преобразование и оптимизацию ресурсов во время загрузки удобно во время разработки, но это ложится большим бременем на производительность компьютеров пользователей. Предварительно обработанные ресурсы быстрее загружаются, быстрее используются и дают возможность выполнять сложные работы вне сети.
- Избегайте создания большого количества ресурсов для каждого кадра. Необходимые взаимодействия с драйвером могут сериализовать ЦП и GPU, а задействованные операции являются тяжелыми, так как для них часто требуются переходы ядра. Распределите создание по нескольким кадрам или повторно используйте ресурсы без их создания или освобождения. В идеале следует подождать несколько кадров, прежде чем блокировать или освобождать ресурсы, которые недавно использовались для отрисовки.
- В конце кадра обязательно отмените привязку всех каналов ресурсов (то есть источников потоков, этапов текстуры и текущих индексов). Это обеспечит удаление висячих ссылок на ресурсы до того, как диспетчер ресурсов сохранит постоянные ресурсы, которые фактически больше не используются.
- Для текстур используйте сжатые форматы (например, DXTn) с MIP-картами и рассмотрите возможность использования атласа текстур. Это значительно снижает требования к пропускной способности и может уменьшить общий размер ресурсов, что делает их более эффективными.
- Для геометрии используйте индексированную геометрию, так как это помогает сжимать ресурсы буфера вершин, а современное видеоустройство значительно оптимизировано для повторного использования вершин. Используя программируемые шейдеры вершин, можно сжимать сведения о вершинах и расширять их во время обработки вершин. Опять же, это помогает снизить требования к пропускной способности и повысить эффективность ресурсов буфера вершин.
- Избегайте чрезмерной оптимизации управления ресурсами. Будущие редакции драйверов, оборудования и операционной системы могут привести к проблемам совместимости, если приложение настроено слишком сильно для конкретного сочетания. Так как большинство приложений привязаны к ЦП, дорогостоящее управление на основе ЦП обычно вызывает больше проблем с производительностью, чем решает.
Связанные темы