Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Этот раздел относится только к Windows 7 и более поздним версиям, а также к windows Server 2008 R2 и более поздним версиям операционной системы Windows.
В следующих разделах описывается, как Direct3D 11 изменился с Direct3D 10.
Функции обратного вызова драйвера для служб Kernel-Mode
Функции обратного вызова, специфичные для устройства, которые среда выполнения Direct3D версии 11 предоставляет в структуре D3DDDI_DEVICECALLBACKS когда вызывает функцию CreateDevice(D3D10) драйвера пользовательского режима, изолируют драйвер от дескрипторов ядра и сигнатур функций ядра. Среда выполнения Direct3D версии 11 изменяет семантику обратного вызова и, следовательно, реализацию функций обратного вызова для поддержки режима работы со свободным потоком, в то время как предыдущие среды выполнения версии Direct3D не поддерживали режим работы со свободным потоком. Правила для операции в режиме свободного потока применяются после того, как драйвер указывает, что он поддерживает режим свободного потока (D3D11DDICAPS_FREETHREADED); в противном случае применяются предыдущие строго ограниченные правила. Сведения о том, как драйвер указывает на поддержку режима свободного потока, см. в разделах "Потоки" и "Списки команд". Следующие ограничения по-прежнему существуют для Direct3D версии 11:
Одновременно с HCONTEXT может работать только один поток. Существующие функции обратного вызова, которые в настоящее время используют HCONTEXT: pfnPresentCb, pfnRenderCb, pfnEscapeCb, pfnDestroyContextCb, pfnWaitForSynchronizationObjectCb, и pfnSignalSynchronizationObjectCb. Таким образом, если несколько потоков вызывают эти функции обратного вызова и используют тот же HCONTEXT, драйвер должен синхронизировать вызовы с функциями обратного вызова. Удовлетворение этому требованию вполне естественно, так как эти функции обратного вызова, скорее всего, будут вызываться только из потока, который управляет непосредственным контекстом.
Драйвер должен вызывать следующие функции обратного вызова только во время вызовов следующих функций драйвера, используя те же потоки, которые называются этими функциями драйвера:
pfnAllocateCb: драйвер должен вызывать pfnAllocateCb в потоке, который называется функцией CreateResource(D3D11) драйвера при создании общих ресурсов. Обычные неразделяемые выделения на устройстве полностью свободно потоковых.
pfnPresentCb: драйвер должен вызывать pfnPresentCb только во время вызовов функции PresentDXGI драйвера.
pfnSetDisplayModeCb: драйвер должен вызывать pfnSetDisplayModeCb только во время вызовов функции SetDisplayModeDGI драйвера.
pfnRenderCb: драйвер должен вызвать pfnRenderCb в потоке, который вызвал функцию Flush(D3D10) драйвера. Это ограничение довольно естественно из-за ограничений HCONTEXT.
Функция обратного вызова pfnDeallocateCb заслуживает особого упоминания, так как драйверу не требуется вызывать pfnDeallocateCb перед возвратом из функции DestroyResource(D3D10) для большинства типов ресурсов. Так как DestroyResource(D3D10) является функцией, не зависящей от потока, драйвер должен отложить уничтожение объекта, пока не сможет эффективно гарантировать отсутствие существующих ссылок на непосредственный контекст (то есть драйвер должен вызвать pfnRenderCb до pfnDeallocateCb). Это ограничение применяется даже к общим ресурсам, общим первичным ресурсам или к любой другой функции обратного вызова, которая использует HRESOURCE для дополнения использования HRESOURCE с pfnAllocateCb. Это ограничение не применяется к первичным. Дополнительные сведения об основных исключениях см. в разделе "Основные исключения". Так как для некоторых приложений может потребоваться синхронное уничтожение, драйвер должен обеспечить вызов pfnDeallocateCb для всех ранее уничтоженных разделяемых ресурсов во время вызова функции Flush(D3D10). Драйвер также должен очистить все ранее уничтоженные объекты (только те, которые не застопорят конвейер) во время вызова функции Flush(D3D10); Драйвер должен сделать это, чтобы гарантировать, что среда выполнения вызывает Flush(D3D10) в качестве официального механизма очистки отложенных разрушенных объектов для тех немногих приложений, которые могут потребовать такого механизма. Дополнительные сведения об этом механизме см. в разделе "Отложенное уничтожение" и "Flush(D3D10)". Драйвер также должен гарантировать, что все объекты, для которых было отложено уничтожение, полностью уничтожены до того, как функция DestroyDevice(D3D10) драйвера возвращается во время очистки.
Нерекомендуемая возможность разрешить изменение Free-Threaded DDIs
Для версии Direct3D 11 концепция устройства отображения и непосредственного контекста на уровне API по-прежнему объединены на уровне DDI в соответствии с устаревшей концепцией устройства отображения. Это объединение устройств отображения и непосредственного контекста обеспечивает максимальную совместимость с более ранними версиями DDIs (например, DDI для Direct3D версии 10) и снижает частоту обновления драйверов при поддержке нескольких версий API через несколько версий DDIs. Однако это объединение устройств отображения и непосредственного контекста приводит к более запутанной DDI, так как потоковые домены не являются очевидными. Чтобы вместо этого понять требования многопоточности нескольких интерфейсов и функций в этих интерфейсах, разработчики драйверов должны ссылаться на документацию.
Основная функция API Direct3D версии 11 заключается в том, что он позволяет нескольким потокам одновременно вводить и уничтожать функции. Такая функция несовместима с возможностью драйвера изменить указатели таблицы функций для создания и уничтожения, как это предусмотрено семантикой Direct3D версии 10 для функций, указанных в D3D10DDI_DEVICEFUNCS и D3D10_1DDI_DEVICEFUNCS. Поэтому после того, как драйвер передает указатели функций для создания (CreateDevice(D3D10)), драйвер не должен пытаться изменить поведение, изменив эти конкретные указатели функций, когда драйвер работает в среде Direct3D версии 11 DDI и поддерживает потокобезопасность DDI. Это ограничение применяется ко всем функциям устройств, начинающимся с pfnCreate, pfnOpen, pfnDestroy, pfnCalcPrivate и pfnCheck. Все остальные функции устройства тесно связаны с непосредственным контекстом. Поскольку один поток управляет непосредственным контекстом в каждый момент времени, это хорошо определено, чтобы позволить драйверу выполнять горячую замену записей таблицы функций в непосредственном контексте.
pfnRenderCb против pfnPerformAmortizedProcessingCb
Функции API Direct3D версии 10 перехватывали функцию обратного вызова ядра pfnRenderCb среды выполнения Direct3D для осуществления амортизированной обработки. Это означает, что вместо выполнения некоторых операций при каждом вызове API функции, драйвер выполнял амортизированные операции через несколько вызовов API функций. API обычно использует эту возможность для обрезки высоких уровней и очистки очереди для отложенного уничтожения объектов, помимо прочего.
Чтобы функции обратного вызова ядра были как можно более свободными для драйвера, API Direct3D больше не использует pfnRenderCb , когда драйвер поддерживает Direct3D версии 11 DDI. Таким образом, драйверы, поддерживающие Direct3D версии 11 DDI, должны вручную вызывать функцию обратного вызова ядра pfnPerformAmortizedProcessingCb из того же потока, который вошел в функцию DDI драйвера после отправки буфера команд в немедленном контексте (или аналогичной частоте). Поскольку операция должна обрезать верхние отметки, имеет смысл сделать это, прежде чем драйвер формирует преамбулы буфера команд, используя функции обратного вызова DDI с обновлением состояния.
Кроме того, драйвер должен учитывать проблему амортизации API и пытаться сбалансировать частоту использования функции обратного вызова ядра pfnPerformAmortizedProcessingCb . На одном из крайних случаев драйвер может привести к чрезмерной обработке. Например, если драйвер всегда вызывает pfnPerformAmortizedProcessingCb дважды (последовательно), возможно, из-за использования нескольких ядер, более эффективно будет вызывать pfnPerformAmortizedProcessingCb только один раз. С другой стороны, драйвер может не позволить API Direct3D выполнять какую-либо работу в течение всего кадра, если драйвер никогда не вызывал pfnPerformAmortizedProcessingCb, возможно, из-за перемежающегося дизайна отрисовки кадров. Драйверу не требуется вызывать pfnPerformAmortizedProcessingCb чаще, чем это необходимо, так как это излишне (например, если драйвер не вызывал pfnPerformAmortizedProcessingCb в течение 1 миллисекунды, это значит, что пришло время задействовать API). От драйвера требуется только определить, какие из существующих вызовов pfnRenderCb должны сопровождаться pfnPerformAmortizedProcessingCb и, естественно, соблюдать семантику потоков операции.
Для драйверов, поддерживающих списки команд, необходимо также вызывать pfnPerformAmortizedProcessingCb из отложенных контекстов всякий раз, когда исчерпается доступное пространство (с такой же частотой, как и очистка каждого немедленного контекста). Среда выполнения Direct3D версии 11 предполагает, как минимум, уменьшение своих максимальных показателей во время такой операции. Так как семантика потоков, связанная с pfnRenderCb, была ослаблена для Direct3D версии 11, проблемы параллелизма должны быть решены, чтобы разрешить Direct3D версии 11 продолжать подключать pfnRenderCb без ограничений.
Новый код ошибки DDI
Код ошибки D3DDDIERR_APPLICATIONERROR создается для того, чтобы драйверы могли участвовать в проверке в тех случаях, когда API Direct3D версии 11 этого не делает. Ранее, если драйвер вернул код ошибки E_INVALIDARG, это приводило к возникновению исключения API. Наличие слоя отладки приведет к созданию отладочного вывода и укажет на то, что драйвер вернул внутреннюю ошибку. Выходные данные отладки могут предложить разработчику, что драйвер имел ошибку. Если драйвер возвращает D3DDDIERR_APPLICATIONERROR, уровень отладки определяет, что приложение неисправно.
Ретроактивное введение требования о поддержке многопоточности для CalcPrivate DDIs
Direct3D версии 11 ретроактивно требует, чтобы функции драйвера, начинающиеся с pfnCalcPrivate в функциях DDI для Direct3D версии 10, поддерживали многопоточность. Это ретроактивное требование соответствует поведению версии 11 DDI Direct3D, при котором всегда требуется, чтобы функции pfnCalcPrivate* и pfnCalcDeferredContextHandleSize работали в многопоточном режиме, даже если драйвер указывает, что он не поддерживает многоядерную обработку DDI. Дополнительные сведения об этом ретроактивном требовании см. в разделе Ретроактивные требования Free-Threaded DDI для CalcPrivate.
Отложенное уничтожение и очистка D3D10
Поскольку все функции уничтожения теперь являются свободнопоточными, среда выполнения Direct3D не может очистить буфер команд при уничтожении. Таким образом, функции уничтожения должны отложить реальное уничтожение объекта до тех пор, пока драйвер не может убедиться, что поток, управляющий непосредственным контекстом, больше не зависит от этого объекта. Каждый дискретный метод непосредственного контекста не может эффективно использовать синхронизацию для решения этой проблемы уничтожения; Таким образом, драйвер должен использовать синхронизацию только при очистке буфера команд. Среда выполнения Direct3D также использует этот же дизайн, если он должен иметь дело с аналогичными проблемами.
Из-за утверждения отложенного уничтожения среда выполнения Direct3D выступает за то, что эти приложения, которые не могут допускать обходные пути отложенного уничтожения, вместо этого используют явные механизмы. Таким образом, драйвер должен обработать очередь отложенного уничтожения во время вызовов функции Flush(D3D10) (даже если буфер команды пуст), чтобы убедиться, что эти механизмы фактически работают.
Эти приложения, требующие синхронного уничтожения, должны использовать один из следующих шаблонов в зависимости от того, насколько тяжелое разрушение они требуют:
После того как приложение гарантирует, что все зависимости от этого объекта освобождаются (т. е. списки команд, представления, ПО промежуточного слоя и т. д.), приложение использует следующий шаблон:
Object::Release(); // Final release ImmediateContext::ClearState(); // Remove all ImmediateContext references as well. ImmediateContext::Flush(); // Destroy all objects as quickly as possible.
Следующий шаблон является более тяжелым разрушением:
Object::Release(); // Final release ImmediateContext::ClearState(); // Remove all ImmediateContext references as well. ImmediateContext::Flush(); ImmediateContext::End( EventQuery ); while( S_FALSE == ImmediateContext::GetData( EventQuery ) ) ; ImmediateContext::Flush(); // Destroy all objects, completely.
Основные исключения
Основное — это ресурсы, создаваемые средой выполнения при вызовах функции CreateResource(D3D11) драйвера. Среда выполнения создает основной ресурс, задав элемент pPrimaryDesc структуры D3D11DDIARG_CREATERESOURCE как допустимый указатель на структуру DXGI_DDI_PRIMARY_DESC. Общие первичные ресурсы следуют правилам для всех общих ресурсов. Общие первичные элементы имеют следующие важные исключения в отношении предыдущих изменений с Direct3D 10 на Direct3D 11:
Функции CreateResource(D3D11) и DestroyResource(D3D10) драйвера для первичных ресурсов не поддерживают многопоточность и совместно используют домен потоков немедленного контекста. Параллелизм по-прежнему может существовать с функциями, начинающимися с pfnCreate и pfnDestroy, к которым относятся CreateResource(D3D11) и DestroyResource(D3D10). Однако конкурентность не может существовать с созданием ресурса (D3D11) и уничтожением ресурса (D3D10) для первичных источников. Например, драйвер может обнаружить, что вызов функции CreateResource(D3D11) или DestroyResource(D3D10) предназначен для основной функции, и таким образом определяет, что она может безопасно использовать или касаться немедленной памяти контекста в течение длительности вызова функции.
Основное уничтожение не может быть отложено средой выполнения Direct3D, и драйвер должен вызвать функцию pfnDeallocateCb соответствующим образом в вызове функции DestroyResource(D3D10) драйвера.