Поделиться через


Общие сведения о привязке ресурсов

Ключи к пониманию привязки ресурсов в DirectX 12 — это понятия дескрипторов, таблиц дескрипторов, кучи дескрипторов и корневых сигнатур.

Ресурсы и графический конвейер

Ресурсы шейдера (например, текстуры, таблицы констант, изображения, буферы и т. д.) не привязаны непосредственно к конвейеру шейдера; Вместо этого на них ссылается дескриптор. Дескриптор — это небольшой объект, содержащий сведения об одном ресурсе.

Дескрипторы группируются для формирования таблиц дескрипторов. В каждой таблице дескриптора хранятся сведения об одном диапазоне типов ресурсов. Существует множество различных типов ресурсов. Наиболее распространенные ресурсы:

  • Представления буфера констант (CBV)
  • Неупорядоченные представления доступа (UAV)
  • Представления ресурсов шейдера (SRV)
  • Образцы.

Дескрипторы SRV, UAV и CBV можно объединить в одну таблицу дескрипторов.

Графические и вычислительные конвейеры получают доступ к ресурсам, ссылаясь на таблицы дескрипторов по индексу.

Таблицы дескрипторов хранятся в куче дескрипторов. Кучи дескрипторов в идеале будут содержать все дескрипторы (в таблицах дескрипторов) для одного или нескольких кадров для отрисовки. Все ресурсы будут храниться в кучах пользовательского режима.

Еще одна концепция — корневая сигнатура. Корневая сигнатура — это соглашение о привязке, определенное приложением, которое используется шейдерами для поиска ресурсов, к которым им требуется доступ. Корневая сигнатура может хранить:

  • Индексирует таблицы дескрипторов в куче дескрипторов, где макет таблицы дескриптора предварительно определен.
  • Константы, поэтому приложения могут привязывать определяемые пользователем константы (называемые корневыми константами) непосредственно к шейдерам без необходимости проходить через дескрипторы и таблицы дескрипторов.
  • Очень небольшое количество дескрипторов непосредственно внутри корневой сигнатуры, например представление буфера констант (CBV), которое изменяется при каждом рисовании, тем самым избавляя приложение от необходимости помещать эти дескрипторы в кучу дескрипторов.

Другими словами, корневая сигнатура обеспечивает оптимизацию производительности, подходящую для небольших объемов данных, которые изменяются при каждом отрисовке.

Конструкция Direct3D 12 для привязки отделяет ее от других задач, таких как управление памятью, время существования объектов, отслеживание состояния и синхронизация памяти (см. раздел Отличия модели привязки от Direct3D 11). Привязка Direct3D 12 предназначена для небольших затрат и оптимизирована для наиболее частых вызовов API. Он также масштабируется на низком и высоком уровне оборудования и масштабируется от более старых (более линейный конвейер Direct3D 11) до более новых (более параллельных) подходов к программированию графического обработчика.

Типы и представления ресурсов

Типы ресурсов совпадают с Direct3D 11, а именно:

  • Texture1D и Texture1DArray
  • Texture2D и Texture2DArray, Texture2DMS, Texture2DMSArray
  • Texture3D
  • Буферы (типизированные, структурированные и необработанные)

Представления ресурсов похожи, но немного отличаются от Direct3D 11, добавлены представления буфера вершин и индексов.

  • Представление буфер констант (CBV)
  • Представление неупорядоченного доступа (UAV)
  • Представление ресурсов шейдера (SRV)
  • Образцы.
  • Представление целевого объекта отрисовки (RTV)
  • Представление трафарета глубины (DSV)
  • Представление буфера индекса (IBV)
  • Представление буфера вершин (VBV)
  • Представление потокового вывода (SOV)

Только первые четыре из этих представлений фактически видны шейдерам. См. кучи видимого дескриптора шейдера и кучи невидимых дескрипторов шейдера.

Поток управления привязкой ресурсов

Если сосредоточиться только на корневых сигнатурах, корневых дескрипторов, корневых константах, таблицах дескрипторов и кучах дескрипторов, поток логики отрисовки для приложения должен выглядеть примерно так:

  • Создайте один или несколько объектов корневой сигнатуры — по одному для каждой конфигурации привязки, необходимой приложению.
  • Создайте шейдеры и состояние конвейера с помощью корневых объектов сигнатуры, с которыми они будут использоваться.
  • Создайте одну кучу дескриптора (или при необходимости больше), которая будет содержать все дескрипторы SRV, UAV и CBV для каждого кадра отрисовки.
  • По возможности инициализируйте кучу дескрипторов дескрипторами для наборов дескрипторов, которые будут повторно использоваться во многих кадрах.
  • Для каждого кадра для отрисовки:
    • Для каждого списка команд:
      • Задайте текущую корневую сигнатуру для использования (и при необходимости измените ее во время отрисовки, что редко требуется).
      • Обновите некоторые константы корневой сигнатуры и (или) дескрипторы корневой подписи для нового представления (например, проекции мира или представления).
      • Для каждого отрисовываемого элемента:
        • Определите все новые дескрипторы в кучах дескрипторов при необходимости для отрисовки для каждого объекта. Для кучи дескрипторов, видимых шейдером, приложение должно использовать пространство кучи дескриптора, на которое еще не ссылается отрисовка, которая может находиться в режиме выполнения, например линейное выделение пространства через кучу дескрипторов во время отрисовки.
        • Обновите корневую сигнатуру указателями на необходимые области кучи дескриптора. Например, одна таблица дескрипторов может указывать на некоторые статические (неизменяемые) дескрипторы, инициализированные ранее, а другая таблица дескрипторов может указывать на некоторые динамические дескрипторы, настроенные для текущей отрисовки.
        • Обновите константы и (или) дескрипторы корневой сигнатуры для отрисовки элемента.
        • Задайте состояние конвейера для рисования элемента (только при необходимости изменения), совместимое с текущей привязанной корневой сигнатурой.
        • Draw
      • Повторить (следующий элемент)
    • Repeat (следующий список команд)
    • Только после завершения работы GPU с любой памятью, которая больше не будет использоваться, его можно освободить. Ссылки дескрипторов на него не нужно удалять, если не отправляется дополнительная отрисовка, использующая эти дескрипторы. Таким образом, последующая отрисовка может указывать на другие области в кучах дескрипторов или устаревшие дескрипторы могут быть перезаписаны допустимыми дескрипторами для повторного использования пространства кучи дескриптора.
  • Повторить (следующий кадр)

Обратите внимание, что другие типы дескрипторов, представления целевых представлений (RTV), представления трафаретов глубины (DSV), представления буфера индекса (IBV), представления буфера вершин (VBV) и представления потокового вывода (SOV) управляются по-разному. Драйвер обрабатывает управление версиями набора дескрипторов, привязанных для каждого отрисовки во время записи списка команд (аналогично тому, как корневые привязки сигнатуры управляются оборудованием или драйвером). Это отличается от содержимого кучи дескрипторов, видимых шейдером, для которых приложение должно вручную выделять данные через кучу, так как оно ссылается на разные дескрипторы между рисованиями. Управление версиями содержимого кучи, видимого для шейдера, остается за приложением, так как оно позволяет приложениям выполнять такие действия, как повторное использование дескрипторов, которые не изменяются, или использовать большие статические наборы дескрипторов и индексирование шейдеров (например, по идентификатору материала) для выбора дескрипторов для использования из кучи дескрипторов или использовать сочетания методов для различных наборов дескрипторов. Оборудование не оснащено для обработки такого типа гибкости для других типов дескрипторов (RTV, DSV, IBV, VBV, SOV).

Подрасположение

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

Освобождение ресурсов

Прежде чем можно будет освободить любую память, привязанную к конвейеру, необходимо завершить работу с gpu.

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