Использование Context-Local дескрипторов 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.