Асинхронное программирование (DirectX и C++)
В этом разделе рассматриваются различные моменты, которые следует учитывать при использовании асинхронного программирования и потоков в DirectX.
Асинхронное программирование и DirectX
Если вы просто узнаете о DirectX или даже если вы столкнулись с ним, рассмотрите возможность размещения всего конвейера обработки графики в одном потоке. В любой конкретной сцене в игре существуют общие ресурсы, такие как растровые изображения, шейдеры и другие ресурсы, требующие эксклюзивного доступа. Эти же ресурсы требуют синхронизации доступа к этим ресурсам в параллельных потоках. Отрисовка — это сложный процесс параллелизации между несколькими потоками.
Однако если ваша игра достаточно сложна или если вы хотите повысить производительность, можно использовать асинхронное программирование для параллелизации некоторых компонентов, которые не относятся к конвейеру отрисовки. Современные аппаратные функции имеют несколько основных и гиперпоточных ЦП, и ваше приложение должно воспользоваться этим преимуществом! Это можно обеспечить с помощью асинхронного программирования для некоторых компонентов игры, которые не нуждаются в прямом доступе к контексту устройства Direct3D, например:
- операции ввода-вывода файлов
- физика
- ИИ
- networking
- audio
- controls
- Компоненты пользовательского интерфейса на основе XAML
Приложение может обрабатывать эти компоненты в нескольких параллельных потоках. Операции ввода-вывода файлов, особенно загрузка ресурсов, значительно отличаются от асинхронной загрузки, так как ваша игра или приложение может находиться в интерактивном состоянии, а несколько (или несколько сотен) мегабайт ресурсов загружаются или передаются в поток. Самый простой способ создания и управления этими потоками — использование библиотеки параллельных шаблонов и шаблона задачи, как указано в пространстве имен параллелизма, определенном в PPLTasks.h. Использование библиотеки параллельных шаблонов использует прямое преимущество нескольких ядер и гиперпоточных ЦП, а также может улучшить все, начиная от предполагаемого времени загрузки и отстающих от задержек, которые приходят с интенсивными вычислениями ЦП или сетевой обработкой.
Примечание. В приложении универсальная платформа Windows (UWP) пользовательский интерфейс полностью выполняется в однопоточной квартире (STA). Если вы создаете пользовательский интерфейс для игры DirectX с помощью взаимодействия XAML, вы можете получить доступ только к элементам управления с помощью STA.
Многопоточность с устройствами Direct3D
Многопоточность для контекстов устройств доступна только на графических устройствах, поддерживающих уровень функций Direct3D 11_0 или более поздней версии. Однако может потребоваться максимальное использование мощного GPU на многих платформах, таких как выделенные игровые платформы. В самом простом случае может потребоваться разделить отрисовку наложения отображения головы (HUD) от отрисовки и проекции трехмерной сцены, а оба компонента используют отдельные параллельные конвейеры. Оба потока должны использовать один и тот же идентификатор ID3D11DeviceContext для создания объектов ресурсов (текстур, сеток, шейдеров и других ресурсов), однако, который является однопоточным, и что требует реализации какого-либо механизма синхронизации (например, критически важных разделов) для безопасного доступа к нему. И, хотя вы можете создать отдельные списки команд для контекста устройства в разных потоках (для отложенной отрисовки), эти списки команд нельзя воспроизводить одновременно в одном экземпляре ID3D11DeviceContext .
Теперь приложение также может использовать ID3D11Device, который является безопасным для многопоточности для создания объектов ресурсов. Поэтому почему не всегда используйте ID3D11Device вместо ID3D11DeviceContext? В настоящее время поддержка драйверов для многопоточности может быть недоступна для некоторых графических интерфейсов. Вы можете запросить устройство и узнать, поддерживает ли она многопоточность, но если вы хотите достичь самой широкой аудитории, вы можете придерживаться однопоточного id3D11DeviceContext для управления объектами ресурсов. Тем не более того, когда драйвер графического устройства не поддерживает многопоточность или списки команд, Direct3D 11 пытается обрабатывать синхронизированный доступ к контексту устройства внутри системы; и если списки команд не поддерживаются, она предоставляет реализацию программного обеспечения. В результате можно написать многопоточный код, который будет выполняться на платформах с графическими интерфейсами, которые не поддерживают поддержку драйвера для доступа к контексту многопоточного устройства.
Если приложение поддерживает отдельные потоки для обработки списков команд и для отображения кадров, вероятно, вы хотите сохранить графический процессор активным, обрабатывая списки команд во время своевременного отображения кадров без заметного заикания или задержки. В этом случае можно использовать отдельный идентификатор ID3D11DeviceContext для каждого потока и совместно использовать ресурсы (например, текстуры), создав их с помощью флага D3D11_RESOURCE_MISC_SHARED. В этом сценарии необходимо вызвать идентификатор ID3D11DeviceContext::Flush в потоке обработки, чтобы завершить выполнение списка команд перед отображением результатов обработки объекта ресурса в потоке отображения.
Отложенная отрисовка
Отложенные команды отрисовки записей графики в списке команд, чтобы их можно было воспроизвести в другое время, и предназначен для поддержки отрисовки в одном потоке во время записи команд для отрисовки на дополнительных потоках. После завершения этих команд их можно выполнить в потоке, который создает окончательный отображаемый объект (буфер кадра, текстура или другие графические выходные данные).
Создайте отложенный контекст с помощью ID3D11Device::CreateDeferredContext (вместо D3D11CreateDevice или D3D11CreateDeviceAndSwapChain, создающего немедленный контекст). Дополнительные сведения см. в разделе "Интерпретация" и "Отложенная отрисовка".
См. также