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


Использование локальных для контекста дескрипторов DDI

Этот раздел относится только к Windows 7 и более поздним версиям, а также к windows Server 2008 R2 и более поздним версиям операционной системы Windows.

Каждый объект (например, ресурс, шейдер и т. д.) имеет привязанные к контексту DDI-дескрипторы.

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

По-прежнему существует различие между немедленным контекстным дескриптором и отложенным контекстным дескриптором. В частности, дескриптор непосредственного контекста гарантированно является первым дескриптором, выделенным и последним дескриптором, который уничтожается. Соответствующий дескриптор контекста немедленно предоставляется во время открытия каждого отложенного дескриптора контекста, чтобы связать их друг с другом. В настоящее время нет концепции объекта с дескриптором DDI для каждого устройства (т. е. дескриптором, который создается до и уничтожается после текущего дескриптора контекста и будет ссылаться только в порядке их создания контекстных дескрипторов).

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

Организация данных драйвера

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

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

Чтобы обеспечить эффективную совместимость данных драйвера с Direct3D версии 10 и избежать расхождений в реализации, данные, доступные только для чтения, должны находиться рядом (но по-прежнему отделены и следовать за) данными немедленного контекста обработчиков. Если драйвер использует эту конструкцию, драйвер должен знать, что заполнение строк кэша требуется между непосредственным контекстом обработки данных и данными только для чтения. Так как поток может часто управлять данными каждого контекстного дескриптора (если не одновременно), штрафы за ложное совместное использование возникают между данными немедленной и отложенной обработки контекстных дескрипторов при отсутствии заполнения строк кэша. Дизайн драйвера должен быть осведомлен о ложных ограничениях общего доступа, которые манифестируются, если указатели устанавливаются и проходят регулярно между областями памяти обработки контекста.

Среда выполнения Direct3D использует следующий интерфейс DDI Direct3D 11 для локальных дескрипторов отложенного контекста:

  • Функция CheckDeferredContextHandleSizes проверяет размеры выделенных драйвером областей памяти, в которых хранятся данные дескрипторов отложенных контекстов.

  • Функция CalcDeferredContextHandleSize определяет размер области памяти для отложенного контекста.

Чтобы среда выполнения Direct3D извлекла размер дескриптора отложенного контекста, необходимого драйверу, необходимо использовать предыдущие функции DDI. Сразу после создания объекта для немедленного контекста среда выполнения вызывает CalcDeferredContextHandleSize для запроса драйвера объема дискового пространства, необходимого драйверу для удовлетворения отложенных дескрипторов контекста этому объекту. Однако API Direct3D должен настроить свой распределитель памяти CLS, определив количество уникальных размеров дескрипторов и их значений; среда выполнения вызывает функцию CheckDeferredContextHandleSizes драйвера для получения этих сведений. Поэтому во время создания экземпляра устройства API запрашивает массив отложенных размеров контекстных дескрипторов путем двойного опроса. Первый запрос предназначен для определения, сколько размеров возвращается, а второй запрос использует массив для получения значения каждого размера. Драйвер должен указать, сколько памяти требуется для удовлетворения дескриптора вместе с типом дескриптора. Драйвер может возвращать несколько размеров, связанных с определенным типом дескриптора. Тем не менее, он не определен для драйвера, когда-либо возвращающего значение из CalcDeferredContextHandleSize , которое не было также соответствующим образом возвращено в массиве CheckDeferredContextHandleSizes .

Что касается создания дескрипторов DDI, используются методы создания в отложенном контексте. Например, изучите функции CreateBlendState(D3D10_1) и DestroyBlendState . HDEVICE естественно указывает на соответствующий отложенный контекст (в отличие от немедленного контекста); другие указатели структуры CONST имеют значение NULL (если объект не имеет зависимостей); и дескриптор D3D10DDI_HRT* — это дескриптор D3D10DDI_H* к соответствующему объекту контекста немедленного контекста.

Для объектов с зависимостями (например, представления имеют отношение зависимостей к соответствующему ресурсу), указатель структуры, предоставляющий дескриптор зависимостей, не имеет значения NULL. Однако единственным допустимым членом структуры является дескриптор зависимости, тогда как остальные члены заполнены нулями. Например, указатель D3D11DDIARG_CREATESHADERRESOURCEVIEW в вызове функции CreateShaderResourceView(D3D11) драйвера не будет NULL , если среда выполнения вызывает эту функцию в отложенном контексте. В этом вызове CreateShaderResourceView(D3D11) среда выполнения назначает соответствующий контекстно-локальный дескриптор для ресурса элементу hDrvResource D3D11DDIARG_CREATESHADERRESOURCEVIEW. Остальные члены D3D11DDIARG_CREATESHADERRESOURCEVIEW, однако, заполнены нулем.

В следующем примере кода показано, как среда выполнения Direct3D преобразует запрос на создание приложения и первое использование отложенного контекста для вызовов драйвера отображения в пользовательском режиме для создания немедленных и отложенных контекстов. Вызов приложения к ID3D11Device::CreateTexture2D инициирует код среды выполнения в следующем разделе "Создание ресурсов". Вызов приложения к ID3D11Device::CopyResource инициирует код среды выполнения в следующем разделе "Отложенное использование ресурсов контекста".

// Device Create
 IC::pfnCheckDeferredContextHandleSizes( hIC, &u, NULL );
pArray = malloc( u * ... );
IC::pfnCheckDeferredContextHandleSizes( hIC, &u, pArray );

// Resource Create
 s = IC::pfnCalcPrivateResourceSize( hIC, &Args );
pICRHandle = malloc( s );
 IC::pfnCreateResource( hIC, &Args, pICRHandle, hRTResource );
 s2 = IC::pfnCalcDeferredContextHandleSize( hIC, D3D10DDI_HT_RESOURCE, pICRHandle );

// Deferred Context Resource Usage
pDCRHandle = malloc( s2 );
 DC::pfnCreateResource( hDC, NULL, pDCRHandle, pICRHandle );

Проблемы с pfnSetErrorCb

Ни одна из функций создания не возвращает код ошибки, что было бы идеальным для модели потоков Direct3D версии 11. Все функции создания используют pfnSetErrorCb для получения кодов ошибок обратно из драйвера. Для обеспечения максимальной совместимости с моделью драйвера Direct3D версии 10 новые функции DDI, создающие коды ошибок, не были введены. Вместо этого драйвер должен продолжать использовать дескриптор D3D10DDI_HRTCORELAYER для контекста единого устройства или контекста немедленного выполнения с pfnSetErrorCb во время функций создания. Если драйвер поддерживает списки команд, драйвер должен использовать соответствующий pfnSetErrorCb , связанный с соответствующим контекстом. То есть ошибки отложенного контекста должны быть переданы в конкретный отложенный вызов pfnSetErrorCb с соответствующим дескриптором и так далее.

Отложенные контексты могут возвращать E_OUTOFMEMORY с помощью вызова pfnSetErrorCb из функций DDI, которые ранее разрешали только D3DDDIERR_DEVICEREMOVED (например, Draw, SetBlendState и т. д.), так как требования к памяти отложенного контекста постоянно растут при каждом вызове функции DDI. API Direct3D активирует удаление локального контекста, чтобы помочь драйверу в случае такого сбоя, которое эффективно удаляет частично созданный список команд. Приложение продолжает определять, что оно записывает список команд; однако, когда приложение в конечном итоге вызывает функцию FinishCommandList, FinishCommandList возвращает код сбоя E_OUTOFMEMORY.