Изменения по версии Direct3D 10
Этот раздел относится только к 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, pfnDescapeContextCb, pfnWaitForSynchronizationObjectCb и pfnSignalSynchronizationObjectCb. Таким образом, если несколько потоков вызывают эти функции обратного вызова и используют один и тот же HCONTEXT, драйвер должен синхронизировать вызовы с функциями обратного вызова. Выполнение этого требования вполне естественно, так как эти функции обратного вызова, скорее всего, будут вызываться только из потока, который управляет непосредственным контекстом.
Драйвер должен вызывать следующие функции обратного вызова только во время вызовов следующих функций драйвера, используя те же потоки, которые вызвали эти функции драйвера:
pfnAllocateCb: драйвер должен вызывать pfnAllocateCb в потоке, который вызывал функцию CreateResource(D3D11) драйвера при создании общих ресурсов. Обычные выделения, не являющиеся общими для устройства, полностью предоставляются в свободном потоке.
pfnPresentCb. Драйвер должен вызывать pfnPresentCb только во время вызовов функции PresentDXGI драйвера.
pfnSetDisplayModeCb: драйвер должен вызывать pfnSetDisplayModeCb только во время вызовов функции SetDisplayModeDXGI драйвера.
pfnRenderCb: драйвер должен вызвать pfnRenderCb в потоке, который вызвал функцию Flush(D3D10) драйвера. Это ограничение вполне естественно из-за ограничений HCONTEXT.
Функция обратного вызова pfnDeallocateCb заслуживает особого упоминание, так как драйверу не требуется вызывать pfnDeallocateCb, прежде чем драйвер возвращается из функции DestroyResource(D3D10) для большинства типов ресурсов. Так как DestroyResource(D3D10) является функцией со свободным потоком, драйвер должен отложить уничтожение объекта до тех пор, пока драйвер не сможет эффективно гарантировать отсутствие существующей непосредственной ссылки на контекст (то есть драйвер должен вызвать pfnRenderCb перед pfnDeallocateCb). Это ограничение применяется даже к общим ресурсам или любой другой функции обратного вызова, которая использует HRESOURCE для дополнения использования HRESOURCE с помощью pfnAllocateCb. Однако это ограничение не применяется к первичным службам. Дополнительные сведения об основных исключениях см. в разделе Основные исключения. Так как для некоторых приложений может потребоваться синхронное уничтожение, драйвер должен убедиться, что он вызывает pfnDeallocateCb для всех ранее уничтоженных общих ресурсов во время вызова функции Flush(D3D10). Драйвер также должен очистить все ранее уничтоженные объекты (только те, которые не застопорят конвейер) во время вызова функции Flush(D3D10); драйвер должен сделать это, чтобы среда выполнения вызвала Flush(D3D10) в качестве официального механизма для очистки отложенных уничтоженных объектов для тех немногих приложений, которым может потребоваться такой механизм. Дополнительные сведения об этом механизме см. в разделах Deferred Destruction and Flush(D3D10). Драйвер также должен убедиться, что все объекты, для которых было отложено уничтожение, полностью уничтожены до возврата функции DestroyDevice(D3D10) драйвера во время очистки.
Нерекомендуемая возможность разрешить изменение Free-Threaded DIS
Для Direct3D версии 11 концепция отображаемого устройства на уровне API и непосредственный контекст по-прежнему объединяются на уровне DDI в рамках устаревшей концепции устройства отображения. Такое объединение устройств отображения и непосредственного контекста обеспечивает максимальную совместимость с более ранними версиями DDI (например, Direct3D версии 10 DDI) и сокращает отток драйверов при поддержке нескольких версий API с помощью нескольких версий DDI. Однако такое объединение устройства отображения и непосредственного контекста приводит к более запутанности DDI, так как потоковые домены не являются очень явными. Вместо этого, чтобы понять требования к потоку для нескольких интерфейсов и функций в этих интерфейсах, разработчики драйверов должны обратиться к документации.
Основная функция API Direct3D версии 11 заключается в том, что он позволяет нескольким потокам одновременно входить в функции создания и уничтожения. Такая функция несовместима с разрешением драйвера переключать указатели таблицы функций для создания и уничтожения, так как семантика Direct3D версии 10 DDI для функций, указанных в D3D10DDI_DEVICEFUNCS и D3D10_1DDI_DEVICEFUNCS разрешена. Поэтому после того, как драйвер передает указатели функций для создания (CreateDevice(D3D10)), драйвер не должен пытаться изменить поведение путем изменения этих конкретных указателей функций, когда драйвер выполняется в Direct3D версии 11 DDI и в то время как драйвер поддерживает потоки DDI. Это ограничение применяется ко всем функциям устройства, которые начинаются с pfnCreate, pfnOpen, pfnDeкистрать, 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, уровень отладки определяет, что приложение неисправно.
Ретроактивное требование Free-Threaded DDIs CalcPrivate
Direct3D версии 11 задним числом требует, чтобы функции драйвера, начинающиеся с pfnCalcPrivate в функциях Direct3D версии 10 DDI, были свободно потоковыми. Это ретроактивное требование соответствует поведению Direct3D версии 11 DDI, так как функции pfnCalcPrivate* и pfnCalcDeferredContextHandleSize должны быть свободными потоками, даже если драйвер указывает, что они не поддерживают потоки DDI. Дополнительные сведения об этом обратном требовании см. в разделе Ретроактивное требование Free-Threaded CalcPrivate DDIs.
Отложенное уничтожение и очистка D3D10
Так как все функции destroy теперь являются свободными, среда выполнения Direct3D не может очистить буфер команд во время уничтожения. Поэтому функции destroy должны отложить фактическое уничтожение объекта до тех пор, пока драйвер не сможет гарантировать, что поток, который управляет непосредственным контекстом, больше не зависит от этого объекта. Каждый дискретный метод непосредственного контекста не может эффективно использовать синхронизацию для решения этой проблемы уничтожения; Поэтому драйвер должен использовать синхронизацию только при очистке буфера команд. Среда выполнения 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 и pfnDe, включая CreateResource(D3D11) и DestroyResource(D3D10). Однако параллелизм не может существовать с CreateResource(D3D11) и DestroyResource(D3D10) для первичных источников. Например, драйвер может обнаружить, что вызов его функции CreateResource(D3D11) или DestroyResource(D3D10) предназначен для основной функции, и тем самым определить, что он может безопасно использовать или касаться непосредственной контекстной памяти на протяжении всего вызова функции.
Основное уничтожение не может быть отложено средой выполнения Direct3D, и драйвер должен соответствующим образом вызвать функцию pfnDeallocateCb в вызове функции DestroyResource(D3D10) драйвера.