Программное создание текстур DirectX 11, плюсы и минусы трех разных методов

В документации msdn объясняется, что в DirectX 11 существует несколько способов программного заполнения текстуры DirectX 11:

(1) Создайте текстуру с использованием текстуры по умолчанию и инициализируйте ее данными из памяти

(2) Создайте текстуру с динамическим использованием, используйте DeviceContext Map, чтобы получить указатель на память текстур, запишите ее, затем используйте Unmap, чтобы указать, что вы сделали (в этот момент я думаю, что она скопирована в GPU)

(3) Создайте текстуру с использованием поэтапного использования и выполните те же шаги, что и для динамической текстуры, но выполните это с вызовом ID3D11DeviceContext.CopyResource, чтобы использовать эту промежуточную текстуру для того, чтобы в свою очередь заполнить (неизменяемую) текстуру по умолчанию или динамическую текстуру.

Однако документация не объясняет плюсы и минусы каждого метода, и я все еще довольно новичок в DirectX, так что мне это не совсем понятно.

Каковы плюсы и минусы каждого из этих способов программного создания текстуры в DirectX 11?

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

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

1 ответ

Решение

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

Итак, если у вас есть данные в памяти приложения, которые вы хотите поместить в текстуру:

Если это просто статическая текстура (я имею в виду, что текстура читается из гораздо большего, чем записывается), то вам нужна текстура USAGE_DEFAULT или USAGE_IMMUTABLE. Они обычно оптимизированы для производительности чтения GPU по сравнению с USAGE_DYNAMIC. Если у вас есть данные, удобные при создании текстуры, тогда опция (1) является самой простой, использует наименьшую промежуточную память, а в DX11 передача данных в графический процессор может выполняться в отдельном потоке от вашего потока рендеринга. Если у вас нет данных во время создания текстуры, используйте UpdateSubresource() или option (3), чтобы предоставить данные, когда они у вас есть.

Если это динамическая текстура, это означает, что вы часто предоставляете новое содержимое из ЦП (каноническим случаем является воспроизведение видео на основе ЦП: данные предоставляются ЦП один раз за кадр, а затем считываются ГП один раз за кадр), тогда вы, вероятно, захотите используйте USAGE_DYNAMIC и параметр (2). Текстуры USAGE_DYNAMIC оптимизированы для потоковой передачи данных из ЦП в ГП, а не просто для чтения ГП. Детали (и последствия для производительности) различаются у разных поставщиков оборудования, но обычно вы хотите использовать USAGE_DYNAMIC, только если вы действительно передаете данные с ЦП на GPU, а не просто потому, что это удобный способ загрузки статических данных заранее.

Опция (3) является более специализированной и может использоваться либо для начальной загрузки данных в статическую текстуру (повторное использование промежуточной поверхности (поверхностей) для загрузки данных для многих текстур), либо для потоковой передачи данных для относительно динамического использования. Это дает вам точный контроль над синхронизацией GPU/CPU и промежуточной памяти, используемой для передачи. Обычно вы используете кольцо промежуточных буферов и D3D11_MAP_FLAG_DO_NOT_WAIT, чтобы проверить, используется ли каждый буфер предыдущим CopyResource. Я считаю, что это вариант эксперта - если вы не будете осторожны, вы можете сильно повредить производительности, не допуская асинхронной работы процессора и графического процессора.

Полное раскрытие: я работаю над драйвером D3D на Nvidia, но это мое личное мнение.

Другие вопросы по тегам