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


функция обратного вызова PFND3DDDI_LOCKCB (d3dumddi.h)

Функция pfnLockCb блокирует выделение и получает указатель на выделение из драйвера мини-порта дисплея или диспетчера видеопамять.

Синтаксис

PFND3DDDI_LOCKCB Pfnd3dddiLockcb;

HRESULT Pfnd3dddiLockcb(
  HANDLE hDevice,
  D3DDDICB_LOCK *unnamedParam2
)
{...}

Параметры

hDevice

Дескриптор устройства отображения (графический контекст).

unnamedParam2

pData [in, out]

Указатель на структуру D3DDDICB_LOCK , описывающую выделение для блокировки.

Возвращаемое значение

pfnLockCb возвращает одно из следующих значений:

Код возврата Описание
S_OK Выделение было успешно заблокировано.
D3DERR_NOTAVAILABLE Диафрагма недоступна.
D3DERR_WASSTILLDRAWING Выделение по-прежнему используется для отрисовки.
D3DDDIERR_CANTEVICTPINNEDALLOCATION Выделение не удалось заблокировать из-за недоступности диафрагмы дескриптуры и невозможности вытеснить выделение, так как оно было закреплено.
E_OUTOFMEMORY pfnLockCb не удалось завершить из-за нехватки памяти (эта ситуация возникает, когда система находится в крайне низкой памяти и недостаточно места для выделения массива страниц).
E_INVALIDARG Параметры были проверены и определены как неверные.
D3DDDIERR_DEVICEREMOVED pfnLockCb не может привести к выполнению соответствующих действий диспетчером видеопамяти и драйвером отображаемого мини-порта, так как произошла остановка Plug and Play (PnP) или событие обнаружения и восстановления времени ожидания (TDR). Функция драйвера отображения пользовательского режима, вызывающая pfnLockCb (обычно это функция Lock или ResourceMap ), должна вернуть этот код ошибки обратно в среду выполнения Direct3D.
Direct3D версии 9 Примечание. Дополнительные сведения о возврате кодов ошибок см. в разделе Возвращение кодов ошибок, полученных от функций среды выполнения.
Direct3D версий 10 и 11 Примечание. Если функция драйвера не возвращает значение (то есть имеет VOID для возвращаемого типа параметра), функция драйвера вызывает функцию pfnSetErrorCb для отправки кода ошибки обратно в среду выполнения. Дополнительные сведения об обработке кодов ошибок см. в разделе Обработка ошибок.

Эта функция также может возвращать другие значения HRESULT.

Комментарии

Драйвер отображения пользовательского режима может вызвать функцию pfnLockCb среды выполнения Microsoft Direct3D, чтобы заблокировать выделение и получить указатель на выделение из драйвера минипорта дисплея или диспетчера видеопамяти. Драйвер отображения пользовательского режима обычно вызывает pfnLockCb в ответ на вызов его функции Lock или ResourceMap (или других вариантов ResourceMap , таких как DynamicIABufferMapDiscard), чтобы заблокировать ресурс или поверхность в пределах ресурса. Перед возвращением из вызова Lock или ResourceMap драйвер отображения пользовательского режима должен сначала сопоставить ресурс или поверхность с соответствующим выделением, а затем вызвать pfnLockCb , чтобы заблокировать выделение. Выделение должно быть заблокировано, прежде чем его можно будет прочитать из или записать в, так как блокировка:

  • Гарантирует, что диапазон виртуальных адресов для выделения остается неизменным, допустимым, доступным для чтения и записи на протяжении всего периода блокировки. Диспетчер видеопамять обеспечивает такую гарантию.
  • Предоставляет способ синхронизации операций чтения и записи выделения с графическим оборудованием доступа к выделению. Диспетчер видеопамяли и драйвер мини-порта дисплея выполняют синхронизацию.
Direct3D версии 9 Примечание.

Драйвер отображения пользовательского режима обычно вызывает функции pfnLockCb и pfnUnlockCb , соответствующие каждому вызову функций Lock и Unlock соответственно, за исключением случаев, когда драйвер обрабатывает ресурсы, в которых флаг динамического битового поля был установлен в элементе Flags структуры D3DDDIARG_CREATERESOURCE при создании ресурсов. Среда выполнения часто запрашивает блокировку драйвера этих типов ресурсов, часто с флагом битового поля NoOverwrite , установленным в элементе Flags структуры D3DDDIARG_LOCK . Так как данные в таких ресурсах не следует изменять (как указано в NoOverwrite), вызов pfnLockCb для каждого запроса на блокировку занимает слишком много времени. Чтобы предотвратить вызов pfnLockCb для каждого запроса на блокировку, драйвер может кэшировать указатель виртуальной памяти, возвращаемый в элементе pSurfData D3DDDIARG_LOCK при вызове функции Lock с установленным флагом битового поля NoOverwrite . Однако драйвер может продолжать вызывать pfnLockCb всякий раз, когда его функция Lock вызывается с набором флагов битового поля Отмена или без набора флагов.

Direct3D версии 10 и 11 Примечание.

Драйвер отображения пользовательского режима обычно вызывает функции pfnLockCb и pfnUnlockCb , соответствующие каждому вызову функций ResourceMap и ResourceUnmap (или других вариантов этих функций). Это не происходит, когда драйвер обрабатывает ресурсы, в которых значение D3D10_DDI_USAGE_DYNAMIC было задано в элементе Usageструктуры D3D10DDIARG_CREATERESOURCE или D3D11DDIARG_CREATERESOURCE при создании ресурсов. Среда выполнения часто запрашивает блокировку драйвера этих типов ресурсов, часто передавая значение D3D10_DDI_MAP_WRITE_NOOVERWRITE параметру DDIMap в вызове ResourceMap. Так как данные в таких ресурсах не следует изменять (как указано в D3D10_DDI_MAP_WRITE_NOOVERWRITE), вызов pfnLockCb для каждого запроса на блокировку занимает слишком много времени. Чтобы предотвратить вызов pfnLockCb для каждого запроса на блокировку, драйвер может кэшировать указатель виртуальной памяти, возвращаемый в параметре pMappedSubResource при вызове функции ResourceMap с D3D10_DDI_MAP_WRITE_NOOVERWRITE. Однако драйвер может продолжать вызывать pfnLockCb всякий раз, когда его функция ResourceMap вызывается со значением D3D10_DDI_MAP_WRITE_DISCARD или 0, переданным параметру DDIMap .

Хотя приложение не удерживает незавершенную блокировку ресурса, связанного с указателем виртуальной памяти, драйвер обычно откажет указатель виртуальной памяти, вызывая функцию pfnUnlockCb , прежде чем драйвер вызовет функцию pfnRenderCb . Если блокировка не кеширована или блокировка не может быть откэширована, так как приложение по-прежнему заблокировано ресурсом, оборудование может отрисовывать из заблокированного выделения. Диспетчер видеопамять не может поддерживать этот режим работы, если выделение находится в локальной видеопамять; Таким образом, диспетчер памяти вытеснит выделение памяти в системе или памяти AGP, когда диспетчер памяти обнаруживает эту ситуацию. Если выделение не поддерживается в системном или сегменте памяти AGP, диспетчер памяти завершает вызов pfnRenderCb с D3DDDIERR_CANTRENDERLOCKEDALLOCATION. Поэтому выделения буфера вершин и индексов, выделенные в ответ на создание ресурсов, в которых флаг динамического битового поля установлен в элементе Flags D3DDDIARG_CREATERESOURCE (или значение D3D10_DDI_USAGE_DYNAMIC задано в элементе Usage D3D10DDIARG_CREATERESOURCE или D3D11DDIARG_CREATERESOURCE), должны поддерживаться в сегментах системы или AGP.

Установка флага "Отменить битовое поле" в элементе FlagsD3DDDICB_LOCK в вызове pfnLockCb приводит к тому, что диспетчер видеопамяти создаст новый экземпляр выделения, который блокируется. Диспетчер видеопамяти представляет новый экземпляр, возвращая новый дескриптор в драйвер отображения пользовательского режима в элементе hAllocation D3DDDICB_LOCK.

Примечание Функция DxgkDdiCreateAllocation драйвера мини-порта дисплея не вызывается при создании нового экземпляра выделения. Экземпляры отображаются в драйвере мини-порта дисплея как выделения, которые одновременно выстраивается в несколько разных расположений.
 
Диспетчер видеопамять может завершиться сбоем блокировки, в которой установлен флаг Отменить битовое поле, так как диспетчер видеопамять не может создать новый экземпляр или повторно использовать существующий экземпляр выделения. При возникновении этой ошибки драйвер отображения пользовательского режима должен вызвать функцию pfnRenderCb для очистки текущего буфера команд в ядро. Эта очистка буфера команд может привести к прекращению использования некоторых экземпляров выделения, которые не удалось заблокировать с помощью флага Отменить битовое поле.

После очистки буфера команд драйвер отображения пользовательского режима должен попытаться снова заблокировать поверхность с помощью флагов битовых полей Отменить и NoExistingReference . Флаг битового поля NoExistingReference указывает диспетчеру видеопамяти, что драйвер в настоящее время не имеет ссылки на какой-либо экземпляр выделения, который блокируется в очереди в буфере команд. Затем диспетчер видеопамяти может повторно использовать любой экземпляр выделения для обработки блокировки, включая текущий экземпляр.

После вызова pfnLockCb, в котором установлен флаг Отменить битовое поле, драйвер отображения пользовательского режима всегда должен проверка для обновленного значения дескриптора в элементе hAllocationD3DDDICB_LOCK. Если указан новый дескриптор выделения, драйвер отображения пользовательского режима должен обновить свою внутреннюю структуру данных для ссылки на новый дескриптор выделения. Драйвер отображения пользовательского режима также должен добавить перепрограммированную версию заблокированного базового адреса выделения в текущий буфер команд (так как экземпляры выделения содержат разные базовые адреса). Диспетчер видеопамяти проверяет использование экземпляров выделения, используемых драйвером, и отклоняет буферы DMA, которые неправильно используют экземпляры выделения (то есть вызовы pfnPresentCb и pfnRenderCb завершаются сбоем, если они неправильно используют экземпляры выделения). После того как драйвер ссылается на конкретный экземпляр выделения, драйвер больше не может ссылаться на предыдущий экземпляр того же выделения. Например, если в буфере команд используется выделение A и в настоящее время используются экземпляры A0 и A1, то, как только используется A1 (то есть отображается в списке расположений исправлений), A0 становится недействительным. Драйвер мини-порта дисплея может создать список расположения исправлений, который ссылается как на A0, так и на A1. Однако ссылки должны быть упорядочены (то есть сначала можно использовать A0; A0 становится недействительным после использования A2; A1 становится недопустимым при использовании A2 и т. д.).

Драйвер дисплея в пользовательском режиме может вызывать pfnLockCb для выделения системной памяти, даже если память не была предварительно выделена, так как драйвер мини-порта дисплея может фактически находиться в процессе отправки, через DMA или асинхронной передачи этих выделений графическому оборудованию. Таким образом, прежде чем приложению будет разрешено выполнять запись на поверхность, необходимо уведомить о драйвере минипорта дисплея и диспетчере видеопамяти, чтобы они могли заблокировать блокировку при необходимости.

Драйвер отображения в пользовательском режиме также может блокировать выделение. Этот тип блокировки, как правило, не требуется при наличии аппаратной диафрагмы с распаковкой или линеаризации, так как в этой ситуации драйвер отображения пользовательского режима может преобразовать блокировку всего выделения в подобласти путем смещения указателя. Однако при сбое pfnLockCb с помощью D3DERR_NOTAVAILABLE для указания недоступности диафрагмы диспетчер памяти запрашивает у драйвера отображения пользовательского режима копирование содержимого видеопамять. Драйвер отображения пользовательского режима распаковывает или линеализирует содержимое видеопамяти при его копировании в другую область памяти. В этой ситуации драйвер отображения пользовательского режима может предоставить список страниц для копирования, чтобы сэкономить большие объемы копирования при блокировке небольших регионов в большом выделении. Обратите внимание, что диспетчер памяти не вызывает pfnLockCb с D3DERR_NOTAVAILABLE, если драйвер отображения пользовательского режима не установил флаг битового поля LockEntire в элементе Flags структуры D3DDDICB_LOCK и не указал список страниц в элементе pPages D3DDDICB_LOCK. Если драйвер отображения пользовательского режима устанавливает флаг битового поля LockEntire , он также должен задать для членов NumPages и pPages D3DDDICB_LOCK равные 0 и NULL соответственно. Драйвер отображения пользовательского режима всегда должен предоставлять список страниц в pPages при блокировке выделения, созданного с помощью постоянного резервного хранилища. В этом случае диспетчер памяти использует список страниц, чтобы пометить как грязное только определенные страницы, и не требуется копировать все выделение из резервного хранилища, когда оно используется для отрисовки.

Драйвер отображения пользовательского режима может вызывать pfnLockCb , чтобы получить несколько диапазонов свертывания для одного выделения (например, один диапазон поворота для каждого уровня MIP). Если драйвер не может получить ни один из диапазонов, среда выполнения Direct3D вытесняет все выделение для обработки блокировки (все уровни MIP) и освобождает все диапазоны поворота.

Когда драйвер отображения пользовательского режима запрашивает назначение диапазона поворота для выделения, драйвер фактически запрашивает доступ к несвертанным битам выделения. Для таких запросов диспетчер видеопамятки либо страниц в выделении в сегмент памяти, и настраивает диапазон поворота для доступа к выделению или страницам в выделении в сегмент памяти, а затем вытеснит выделение в системную память, запрашивая, чтобы драйвер расчистить выделение на пути к системной памяти. Выделение, которое было отменено в системной памяти, перенастраивается (путем перекачки в видеопамяти), прежде чем GPU снова использует выделение. В результате драйвер не может запросить блокировку типа без перезаписи (установив флаг битового поля DonotWait ) при получении диапазона свертки. Аналогичным образом драйвер не может ссылаться на блокировку выделения таким образом в буфере DMA, который отправляется в GPU (так как буфер DMA будет отклонен).

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

Драйвер отображения пользовательского режима должен передать флаг Отменить битовое поле в элементе Flags D3DDDICB_LOCK в вызове pfnLockCb в следующих ситуациях:

  • Когда среда выполнения Direct3D передает флаг "Отменить битовое поле" в элементе Flags структуры D3DDDIARG_LOCK в вызове функции блокировки драйвера отображения пользовательского режима
  • Когда среда выполнения передает значение D3D10_DDI_MAP_WRITE_DISCARD параметру DDIMap в вызове функции ResourceMap драйвера.
Установка флага Отменить битовое поле приводит к тому, что диспетчер памяти определяет, следует ли переименовывать выделение или поток приложения зависает до тех пор, пока выделение не будет простаивать. Дополнительные сведения о переименовании выделения см. в разделе Запрос на переименование выделения. Драйвер может использовать собственную поддержку переименования или поддержку переименования диспетчера памяти. Чтобы использовать собственную поддержку переименования, драйвер устанавливает флаг битового поля DonotWait в ответ на вызов Lock с установленным флагом битового поля Отменить или в ответ на вызов ResourceMap с заданным значением D3D10_DDI_MAP_WRITE_DISCARD. Установка флага битового поля DonotWait приводит к тому, что диспетчер памяти не сможет вызвать pfnLockCb с D3DERR_WASSTILLDRAWING, если графическое оборудование по-прежнему использует выделение. Такой сбой указывает драйверу отображения пользовательского режима на переименование или несколько буферизации выделения.
Примечание Флаг битового поля DonotWait не влияет на диспетчер памяти, если также установлен флаг отменить битовое поле.
 
Драйвер отображения пользовательского режима должен установить флаг битового поля IgnoreSync в элементе Flags D3DDDICB_LOCK, если диспетчер памяти не требует проверка, использует ли графическое оборудование выделение. Затем драйвер отображения пользовательского режима должен правильно синхронизировать доступ к выделению. Если флаг битового поля DonotWait не указан с флагом битового поля IgnoreSync , диспетчер памяти игнорирует флаг битового поля IgnoreSync .
Примечание Флаг битового поля IgnoreSync не влияет на диспетчер памяти, если также установлен флаг отменить битовое поле.
 
Пример

В следующем примере кода показано, как флаг битового поля "Отменить " используется в вызове pfnLockCb.

HRESULT hr;
D3DDDICB_LOCK LockData;
LockData.hAllocation = AllocationToLock;
LockData.Flags.Discard = TRUE;
hr = pfnLockCb(&LockData)
if (FAILED(hr)) {
    FlushAccumulatedCommandBufferToKernel();
    LockData.Flags.Discard = TRUE;
    LockData.Flags.NoExistingReference = TRUE;
    hr = pfnLockCb(&LockData);
    if (FAILED(hr)) {
        // Fails the lock to the application
    }
}
UpdateAllocationHandleInUMDDataStructure(LockData.hAllocation);
ProgramSurfaceBaseAddressInCurrentCommandBuffer(LockData.hAllocation);

Требования

Требование Значение
Минимальная версия клиента Доступно в Windows Vista и более поздних версиях операционных систем Windows.
Целевая платформа Персональный компьютер
Верхняя часть d3dumddi.h (включая D3dumddi.h)

См. также раздел

D3D10DDIARG_CREATERESOURCE

D3D11DDIARG_CREATERESOURCE

D3DDDIARG_LOCK

D3DDDICB_LOCK

D3DDDI_DEVICECALLBACKS

Блокировка

ResourceMap

ResourceUnmap