Запросы (Direct3D 9)
Существует несколько типов запросов, предназначенных для запроса состояния ресурсов. Состояние данного ресурса включает состояние графического модуля обработки (GPU), состояние драйвера или состояние среды выполнения. Чтобы понять разницу между различными типами запросов, необходимо понимать состояния запроса. На следующей схеме перехода состояния объясняется каждое из состояний запроса.
На схеме показаны три состояния, каждое из которых определяется кругами. Каждая из сплошных линий является управляемыми приложением событиями, которые вызывают переход состояния. Пунктирная линия — это управляемое ресурсами событие, которое переключает запрос из выданного состояния в состояние сигнала. Каждое из этих состояний имеет разные цели:
- Состояние сигнала похоже на состояние простоя. Объект запроса создан и ожидает отправки запроса приложением. После завершения запроса и перехода обратно в состояние сигнала можно получить ответ на запрос.
- Состояние сборки похоже на промежуточную область для запроса. Из состояния сборки запрос был выдан (путем вызова D3DISSUE_BEGIN), но еще не перемещен в состояние выдано. Когда приложение выдает конец запроса (путем вызова D3DISSUE_END), запрос переходит в состояние выдано.
- Состояние выдачи означает, что запрашиваемый ресурс управляет запросом. После завершения работы ресурс переводит конечный автомат в состояние сигнального. Во время выданного состояния приложение должно выполнить опрос, чтобы обнаружить переход в состояние сигнала. После перехода в состояние сигнала GetData возвращает приложению результат запроса (через аргумент).
В следующей таблице перечислены доступные типы запросов.
Тип запроса | Событие issue | Буфер GetData | Среда выполнения | Неявное начало запроса |
---|---|---|---|---|
BANDWIDTHTIMINGS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9BANDWIDTHTIMINGS | Розничная торговля и отладка | Н/Д |
КЭШИРОВАНИЕИСПОЛЬЗОВАНИЕ | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9CACHEUTILIZATION | Розничная торговля и отладка | Н/Д |
СОБЫТИЕ | D3DISSUE_END | BOOL | Розничная торговля и отладка | CreateDevice |
INTERFACETIMINGS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9INTERFACETIMINGS | Розничная торговля и отладка | Н/Д |
ОККЛЮЗИИ | D3DISSUE_BEGIN, D3DISSUE_END | DWORD | Розничная торговля и отладка | Н/Д |
PIPELINETIMINGS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9PIPELINETIMINGS | Розничная торговля и отладка | Н/Д |
RESOURCEMANAGER | D3DISSUE_END | D3DDEVINFO_ResourceManager | Только отладка | Настоящее время |
timestamp | D3DISSUE_END | UINT64 | Розничная торговля и отладка | Н/Д |
TIMESTAMPDISJOINT | D3DISSUE_BEGIN, D3DISSUE_END | BOOL | Розничная торговля и отладка | Н/Д |
TIMESTAMPFREQ | D3DISSUE_END | UINT64 | Розничная торговля и отладка | Н/Д |
VCACHE | D3DISSUE_END | D3DDEVINFO_VCACHE | Розничная торговля и отладка | CreateDevice |
VERTEXSTATS | D3DISSUE_END | D3DDEVINFO_D3DVERTEXSTATS | Только отладка | Настоящее время |
VERTEXTIMINGS | D3DISSUE_BEGIN, D3DISSUE_END | D3DDEVINFO_D3D9STAGETIMINGS | Розничная торговля и отладка | Н/Д |
Для некоторых запросов требуется событие begin и end, а для других — только событие end. Запросы, требующие только события завершения, начинаются при возникновении другого неявного события (которое указано в таблице). Все запросы возвращают ответ, за исключением запроса события, ответ которого всегда имеет значение TRUE. Приложение использует состояние запроса или код возврата GetData.
Создание запроса
Перед созданием запроса можно проверка, чтобы узнать, поддерживает ли среда выполнения запросы, вызвав CreateQuery с указателем NULL следующим образом:
IDirect3DQuery9* pEventQuery;
// Create a device pointer m_pd3dDevice
// Create a query object
HRESULT hr = m_pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, NULL);
Этот метод возвращает код успешного выполнения, если запрос может быть создан; В противном случае возвращается код ошибки. После успешного выполнения CreateQuery можно создать объект запроса следующим образом:
IDirect3DQuery9* pEventQuery;
m_pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);
Если этот вызов выполняется успешно, создается объект запроса. Запрос, по сути, находится в состоянии сигнала (с неинициализированным ответом), ожидая выдачи. Завершив выполнение запроса, отпустите его, как и любой другой интерфейс.
Выдача запроса
Приложение изменяет состояние запроса, выдавая запрос. Ниже приведен пример выдачи запроса:
IDirect3DQuery9* pEventQuery;
m_pD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);
// Issue a Begin event
pEventQuery->Issue(D3DISSUE_BEGIN);
or
// Issue an End event
pEventQuery->Issue(D3DISSUE_END);
При выполнении запрос в состоянии сигнала будет переходить следующим образом:
Тип проблемы | Переходы запросов к . . . |
---|---|
D3DISSUE_BEGIN | Состояние здания. |
D3DISSUE_END | Состояние выдачи. |
При выдаче запрос в состоянии сборки будет переходить следующим образом:
Тип проблемы | Переходы запросов к . . . |
---|---|
D3DISSUE_BEGIN | (Без перехода, остается в состоянии здания. Перезапускает скобку запроса.) |
D3DISSUE_END | Состояние выдачи. |
При выдаче запрос в выданном состоянии будет переходить следующим образом:
Тип проблемы | Переходы запросов к . . . |
---|---|
D3DISSUE_BEGIN | Создание состояния и перезапускает квадратные скобки запроса. |
D3DISSUE_END | Состояние выдано после отказа от существующего запроса. |
Проверка состояния запроса и получение ответа на запрос
GetData выполняет два действия:
- Возвращает состояние запроса в коде возврата.
- Возвращает ответ на запрос в pData.
В каждом из трех состояний запроса приведены коды возврата GetData :
Состояние запроса | Код возврата GetData |
---|---|
Сигнал | S_OK |
Сборка | Код ошибки |
Выдано | S_FALSE |
Например, если запрос находится в состоянии выдачи, а ответ на запрос недоступен, GetData возвращает S_FALSE. Когда ресурс завершит свою работу и приложение выпустит конец запроса, ресурс переводит запрос в состояние сигнала. Из состояния сигнала GetData возвращает S_OK что означает, что ответ на запрос также возвращается в pData. Например, ниже приведена последовательность событий, возвращаемых числом пикселей (или выборок при включенной множественной выборке), отрисованными в последовательности отрисовки:
- создание запроса;
- Выдача события begin.
- Нарисуйте что-нибудь.
- Выдача события завершения.
Ниже приведена соответствующая последовательность кода:
IDirect3DQuery9* pOcclusionQuery;
DWORD numberOfSamplesDrawn;
m_pD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery);
// Add an end marker to the command buffer queue.
pOcclusionQuery->Issue(D3DISSUE_BEGIN);
// API render loop
...
Draw(...)
...
// Add an end marker to the command buffer queue.
pOcclusionQuery->Issue(D3DISSUE_END);
// Force the driver to execute the commands from the command buffer.
// Empty the command buffer and wait until the GPU is idle.
while(S_FALSE == pOcclusionQuery->GetData( &numberOfSamplesDrawn,
sizeof(DWORD), D3DGETDATA_FLUSH ))
;
// To get the number of pixels drawn when multisampling is enabled,
// divide numberOfSamplesDrawn by the sample count of the render target.
Эти строки кода выполняют несколько действий:
- Вызовите Метод GetData , чтобы получить количество пикселей и примеров.
- Укажите D3DGETDATA_FLUSH , чтобы ресурс мог перевести запрос в состояние сигнала.
- Опрос ресурса запроса путем вызова GetData из цикла. Пока GetData возвращает S_FALSE, это означает, что ресурс еще не вернул ответ.
Возвращаемое значение GetData , по сути, указывает, в каком состоянии находится запрос. Возможные значения: S_OK, S_FALSE и ошибка. Не вызывайте GetData для запроса, который находится в состоянии сборки.
- S_OK означает, что ресурс (GPU, драйвер или среда выполнения) завершен. Запрос возвращается в состояние сигнала. Ответ (если таковой имеется) возвращается GetData.
- S_FALSE означает, что ресурс (GPU, драйвер или среда выполнения) пока не может вернуть ответ. Это может быть связано с тем, что GPU не завершен или еще не видел работу.
- Ошибка означает, что запрос вызвал ошибку, из которой он не может восстановиться. Это может быть в случае потери устройства во время запроса. После того как запрос создаст ошибку (кроме S_FALSE), запрос необходимо повторно создать, что приведет к перезапуску последовательности запроса из состояния сигнала.
Вместо указания D3DGETDATA_FLUSH, который предоставляет более актуальные сведения, можно указать ноль, который является более легким проверка, если запрос находится в состоянии выдачи. Если задать ноль, getData не будет очищать буфер команд. По этой причине необходимо соблюдать осторожность, чтобы избежать бесконечных циклов (дополнительные сведения см. в разделе GetData ). Так как среда выполнения помещает в очередь работу в буфере команд, D3DGETDATA_FLUSH является механизмом очистки буфера команд в драйвере (и, следовательно, в GPU; см . раздел Точное профилирование вызовов API Direct3D (Direct3D 9)). Во время очистки буфера команд запрос может перейти в состояние сигнала.
Пример: запрос на событие
Запрос события не поддерживает событие begin.
- создание запроса;
- Выдача события завершения.
- Опрашивай, пока GPU не будет бездействуем.
- Выдача события завершения.
IDirect3DQuery9* pEventQuery = NULL;
m_pD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);
// Add an end marker to the command buffer queue.
pEventQuery->Issue(D3DISSUE_END);
// Empty the command buffer and wait until the GPU is idle.
while(S_FALSE == pEventQuery->GetData( NULL, 0, D3DGETDATA_FLUSH ))
;
... // API calls
// Add an end marker to the command buffer queue.
pEventQuery->Issue(D3DISSUE_END);
// Force the driver to execute the commands from the command buffer.
// Empty the command buffer and wait until the GPU is idle.
while(S_FALSE == pEventQuery->GetData( NULL, 0, D3DGETDATA_FLUSH ))
;
Это последовательность команд, которые запрос событий использует для профилирования вызовов API (см. раздел Точное профилирование вызовов API Direct3D (Direct3D 9)). Эта последовательность использует маркеры для управления объемом работы в буфере команд.
Обратите внимание, что приложения должны уделять особое внимание большим затратам, связанным с очисткой буфера команд, так как это приводит к переключу операционной системы в режим ядра, что приводит к значительному снижению производительности. Приложения также должны учитывать, что циклы ЦП станут тратиться, ожидая завершения запросов.
Запросы — это оптимизация, используемая во время отрисовки для повышения производительности. Поэтому не стоит тратить время на ожидание завершения запроса. Если запрос выдан и результаты еще не готовы к тому времени, когда приложение проверяет их, попытка оптимизации не увенчалась успехом, и отрисовка должна продолжаться в обычном режиме.
Классическим примером этого является отбраковка окклюзии. Вместо цикла while, приведенного выше, приложение, использующее запросы, может реализовать отбраковку окклюзии для проверка, чтобы узнать, был ли запрос завершен к тому времени, когда ему нужен результат. Если запрос не был завершен, продолжайте (в худшем случае), как будто объект, для которого выполняется проверка, не является occluded (т. е. он виден) и отрисовывает его. Код будет выглядеть примерно так:
IDirect3DQuery9* pOcclusionQuery = NULL;
m_pD3DDevice->CreateQuery( D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery );
// Add a begin marker to the command buffer queue.
pOcclusionQuery->Issue( D3DISSUE_BEGIN );
... // API calls
// Add an end marker to the command buffer queue.
pOcclusionQuery->Issue( D3DISSUE_END );
// Avoid flushing and letting the CPU go idle by not using a while loop.
// Check if queries are finished:
DWORD dwOccluded = 0;
if( S_FALSE == pOcclusionQuery->GetData( &dwOccluded, sizeof(DWORD), 0 ) )
{
// Query is not done yet or object not occluded; avoid flushing/wait by continuing with worst-case scenario
pSomeComplexMesh->Render();
}
else if( dwOccluded != 0 )
{
// Query is done and object is not occluded.
pSomeComplexMesh->Render();
}
Связанные темы