Обзор DXGI
Инфраструктура графики Microsoft DirectX (DXGI) распознает, что некоторые части графики развиваются медленнее, чем другие. Основной целью DXGI является управление задачами низкого уровня, которые могут быть независимы от среды выполнения графики DirectX. DXGI предоставляет общую платформу для будущих графических компонентов; первым компонентом, который использует DXGI, является Microsoft Direct3D 10.
В предыдущих версиях Direct3D низкоуровневые задачи, такие как перечисление аппаратных устройств, вывод отрисованных кадров на экран, управление гамма-коррекцией и управление переходом в полноэкранный режим, были включены в среду выполнения Direct3D. Теперь эти задачи реализованы в DXGI.
Целью DXGI является взаимодействие с драйвером режима ядра и системным оборудованием, как показано на следующей схеме.
Приложение может обращаться к DXGI напрямую или вызывать API Direct3D в D3D11_1.h, D3D11.h, D3D10_1.h или D3D10.h, которые обрабатывают обмен данными с DXGI. Возможно, вы хотите работать с DXGI напрямую, если приложению необходимо перечислить устройства или управлять тем, как данные отображаются в выходных данных.
В этом разделе содержатся следующие разделы.
- Перечисление адаптеров
-
Презентация
- Создать цепочку обмена
- уход и управление цепочкой обмена
- Обработка изменения размера окна
- Выбор выходов DXGI и их размера
- отладка в режиме Full-Screen
- уничтожение swap-цепочки
- использование вращающегося монитора
- Переключение режимов
- Full-Screen Совет по улучшению производительности
- Вопросы, связанные с многопоточностью
- Ответы от DXGI в DLLMain
- изменения DXGI 1.1
- Изменения в DXGI 1.2
- Сопутствующие темы
Чтобы узнать, какие форматы поддерживаются оборудованием Direct3D 11:
- Поддержка форматов DXGI для аппаратного уровня возможностей Direct3D 12.1
- Поддержка формата DXGI для аппаратного обеспечения уровня возможностей Direct3D 12.0
- Поддержка формата DXGI для аппаратного уровня возможностей Direct3D 11.1
- поддержка формата DXGI для уровня компонентов Direct3D 11.0
- Аппаратная поддержка форматов Direct3D 10Level9
- поддержка оборудования для форматов Direct3D 10.1
- поддержка оборудования для форматов Direct3D 10
Перечисление адаптеров
Адаптер — это абстракция оборудования и возможностей программного обеспечения компьютера. На компьютере обычно много адаптеров. Некоторые устройства реализованы в оборудовании (например, на вашей видеокарте), и некоторые из них реализованы в программном обеспечении (например, в эталонном растризаторе Direct3D). Адаптеры реализуют функциональные возможности, используемые графическим приложением. На следующей схеме показана система с одним компьютером, двумя адаптерами (видеокартками) и тремя мониторами вывода.
схема
При перечислении этих элементов оборудования DXGI создает интерфейс IDXGIOutput1 для каждого вывода (или монитора) и интерфейс IDXGIAdapter2 для каждой видеокарты (даже если это видеокарта, встроенная в системную плату). Перечисление выполняется с помощью вызова интерфейса IDXGIFactory, IDXGIFactory::EnumAdapters, чтобы вернуть набор интерфейсов IDXGIAdapter, представляющих видео оборудование.
DXGI 1.1 добавил интерфейс IDXGIFactory1. IDXGIFactory1::EnumAdapters1 возвращает набор интерфейсов IDXGIAdapter1, представляющих видео оборудование.
Если вы хотите выбрать определенные возможности видеоустройства при использовании API Direct3D, рекомендуется итеративно вызывать функцию D3D11CreateDevice или D3D11CreateDeviceAndSwapChain с каждым дескриптором адаптера и возможным уровнем возможностей оборудования . Эта функция завершается успешно, если уровень функциональности поддерживается указанным адаптером.
Новые сведения о перечислении адаптеров для Windows 8
Начиная с Windows 8, адаптер под названием "Базовый видеодрайвер Microsoft" всегда присутствует. Этот адаптер имеет идентификатор поставщика 0x1414 и идентификатор устройства 0x8c. Этот адаптер также имеет значение DXGI_ADAPTER_FLAG_SOFTWARE в элементе флагов его структуры DXGI_ADAPTER_DESC2. Этот адаптер — это устройство только для отрисовки, не отображающее выходные данные. DXGI никогда не возвращает DXGI_ERROR_DEVICE_REMOVED для этого адаптера.
Если драйвер дисплея компьютера не работает или отключен, основной адаптер компьютера (NULL) также может называться "Драйвер отрисовки Microsoft Basic". Но этот адаптер имеет выходные данные и не имеет набора значений DXGI_ADAPTER_FLAG_SOFTWARE. Операционная система и приложения используют этот адаптер по умолчанию. Если драйвер отображения установлен или включен, приложения могут получать DXGI_ERROR_DEVICE_REMOVED для этого адаптера, а затем повторно перечислить адаптеры.
Если основной адаптер дисплея компьютера — адаптер отображения Microsoft Basic (адаптер WARP), этот компьютер также имеет второй адаптер. Этот второй адаптер — устройство, предназначенное только для рендеринга, не имеющее выходов дисплея и для которого DXGI никогда не возвращает DXGI_ERROR_DEVICE_REMOVED.
Если вы хотите использовать WARP для отрисовки, вычислений или других длительных задач, рекомендуется использовать устройство только для отрисовки. Указатель на устройство для рендеринга можно получить, вызвав метод IDXGIFactory1::EnumAdapters1. Вы также создаете устройство только для отрисовки, когда указываете D3D_DRIVER_TYPE_WARP в параметре DriverType функции D3D11CreateDevice, так как устройство WARP также использует адаптер WARP только для рендеринга.
Представление
Задача вашего приложения — отрисовка кадров и запрос DXGI для вывода этих кадров на экран. Если у приложения есть два буфера, он может отобразить один буфер при отображении другого. Приложению может потребоваться более двух буферов в зависимости от времени, необходимого для отрисовки кадра или требуемой частоты кадров для презентации. Созданный набор буферов называется цепочкой буферов, как показано здесь.
- создание цепочки обмена
- уход и кормление цепочки буферов
- Управление изменением размера окна
- Выбор вывода и размера DXGI
- отладка в режиме Full-Screen
- уничтожение цепочки свопов
- использование вращающегося монитора
- Переключение режимов
- Full-Screen совет по улучшению производительности
- аспекты многопоточности
Цепочка буферов имеет один передний буфер и один или несколько задних буферов. Каждое приложение создает собственную swap цепь. Чтобы увеличить скорость представления данных в выходные данные, цепочка буферов почти всегда создается в памяти подсистемы отображения, которая показана на следующем рисунке.
Подсистема дисплея (которая часто является видеокартой, но может быть реализована на материнской плате) содержит GPU, цифровой аналоговый преобразователь (DAC) и память. Цепочка буферов выделяется в этой памяти, чтобы обеспечить максимальную скорость отображения. Подсистема отображения представляет данные в переднем буфере выходным данным.
Цепочка обмена кадрами настроена для рисования в полноэкранном или оконном режиме, что устраняет необходимость выяснять, идет ли вывод в оконном или полноэкранном формате. Для оптимизации производительности цепочка обмена полноэкранного режима может переключать разрешение дисплея.
Создать цепочку обмена
Различия между Direct3D 9 и Direct3D 10: Direct3D 10 является первым графическим компонентом для использования DXGI. DXGI имеет несколько различных поведения цепочки буферов.
|
Буферы цепочки обмена создаются в определенном размере и в определенном формате. Приложение задает эти значения (или можно унаследовать размер от целевого окна) при запуске и затем, при необходимости, может изменять их по мере изменения размера окна в ответ на пользовательский ввод или события программы.
После создания цепочки буферов, как правило, вы захотите отрисовывать изображения в ее пределах. Ниже приведен фрагмент кода, который настраивает контекст Direct3D для отрисовки в цепочку буферов. Этот код извлекает буфер из цепочки обмена, создает представление объекта render-target из этого буфера, а затем устанавливает его на устройство.
ID3D11Resource * pBB;
ThrowFailure( pSwapChain->GetBuffer(0, __uuidof(pBB),
reinterpret_cast<void**>(&pBB)), "Couldn't get back buffer");
ID3D11RenderTargetView * pView;
ThrowFailure( pD3D11Device->CreateRenderTargetView(pBB, NULL, &pView),
"Couldn't create view" );
pD3D11DeviceContext->OMSetRenderTargets(1, &pView, 0);
После отрисовки кадра в буфер цепочки обмена вызовите IDXGISwapChain1::Present1. Затем приложение может перейти к просмотру следующего изображения.
Уход и управление цепочкой обмена
После отрисовки изображения вызовите IDXGISwapChain1::Present1 и отрисуйте следующее изображение. Это степень вашей ответственности.
Если вы ранее вызывали IDXGIFactory::MakeWindowAssociation, пользователь может нажать сочетание клавиш Alt-Enter, и DXGI переключит ваше приложение между оконным и полноэкранным режимами. рекомендуется IDXGIFactory::MakeWindowAssociation, так как для пользователя настоятельно необходим стандартный механизм управления.
Хотя вам не нужно писать больше кода, чем было описано, несколько простых шагов могут сделать приложение более адаптивным. Наиболее важным фактором является изменение размера буферов цепочки в соответствии с изменением размеров выходного окна. Естественно, лучший маршрут приложения — реагировать на WM_SIZE и вызывать IDXGISwapChain::ResizeBuffers, передав размер, содержащийся в параметрах сообщения. Такое поведение, очевидно, заставляет ваше приложение хорошо реагировать на пользователя, когда он перетаскивает рамки окна, и последовательно обеспечивает плавный переход на полноэкранный режим. Окно получит сообщение WM_SIZE всякий раз, когда происходит такой переход, и вызов IDXGISwapChain::ResizeBuffers дает возможность перераспределить хранилище буферов для оптимальной презентации. Поэтому приложению необходимо освободить все ссылки, имеющиеся в существующих буферах, прежде чем вызывать IDXGISwapChain::ResizeBuffers.
Невыполнение вызова IDXGISwapChain::ResizeBuffers в ответ на переключение в полноэкранный режим (естественным образом, в ответ на WM_SIZE) может препятствовать оптимизации переключения буферов, где DXGI может просто заменить отображаемый буфер, вместо того чтобы копировать всю информацию по экрану.
IDXGISwapChain1::Present1 сообщит вам, полностью ли окно вывода скрыто с помощью DXGI_STATUS_OCCLUDED. В этом случае рекомендуется, чтобы приложение переходило в режим ожидания (с помощью вызова функции IDXGISwapChain1::Present1 с DXGI_PRESENT_TEST), так как ресурсы, используемые для отрисовки кадра, не расходуются. При использовании DXGI_PRESENT_TEST данные не будут отображаться при выполнении проверки окклюзии. После IDXGISwapChain1::Present1 возвращается S_OK, следует выйти из режима ожидания; не используйте код возврата для перехода в режим ожидания, так как это может привести к неспособности цепочки буферов выйти из полноэкранного режима.
Среда выполнения Direct3D 11.1, доступная начиная с Windows 8, предоставляет цепочку буферов с моделью переворота (т. е. цепочку буферов, у которой установлено значение DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL в поле SwapEffect структуры DXGI_SWAP_CHAIN_DESC или DXGI_SWAP_CHAIN_DESC1). При представлении кадров на выход с цепочкой обмена с моделью переворота DXGI отсоединяет обратный буфер от всех местоположений состояния конвейера, таких как целевой объект слияния вывода, которые записывают в обратный буфер 0. Поэтому мы рекомендуем вызвать ID3D11DeviceContext::OMSetRenderTargets непосредственно перед отрисовкой на задний буфер. Например, не вызывайте OMSetRenderTargets, а затем выполняйте работу шейдера вычислений, которая не приводит к отрисовке ресурсу. Дополнительные сведения о цепочках буферов переворотной модели и их преимуществах см. в разделе DXGI Flip Model.
Заметка
В Direct3D 10 и Direct3D 11 не требуется вызывать IDXGISwapChain::GetBuffer, чтобы получить обратный буфер 0 после вызова IDXGISwapChain1::Present1, так как для удобства идентификаторы обратных буферов меняются автоматически. Это не происходит в Direct3D 12, и приложение должно вручную отслеживать индексы буфера.
Обработка изменения размера окна
Для обработки изменения размера окна можно использовать метод IDXGISwapChain::ResizeBuffers. Перед вызовом ResizeBuffersнеобходимо освободить все активные ссылки на буферы цепочки обмена. Объект, который обычно содержит ссылку на буфер цепочки буферов, является представлением render-target-view.
В следующем примере кода показано, как вызывать ResizeBuffers из обработчика WindowProc для сообщений WM_SIZE:
case WM_SIZE:
if (g_pSwapChain)
{
g_pd3dDeviceContext->OMSetRenderTargets(0, 0, 0);
// Release all outstanding references to the swap chain's buffers.
g_pRenderTargetView->Release();
HRESULT hr;
// Preserve the existing buffer count and format.
// Automatically choose the width and height to match the client rect for HWNDs.
hr = g_pSwapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
// Perform error handling here!
// Get buffer and create a render-target-view.
ID3D11Texture2D* pBuffer;
hr = g_pSwapChain->GetBuffer(0, __uuidof( ID3D11Texture2D),
(void**) &pBuffer );
// Perform error handling here!
hr = g_pd3dDevice->CreateRenderTargetView(pBuffer, NULL,
&g_pRenderTargetView);
// Perform error handling here!
pBuffer->Release();
g_pd3dDeviceContext->OMSetRenderTargets(1, &g_pRenderTargetView, NULL );
// Set up the viewport.
D3D11_VIEWPORT vp;
vp.Width = width;
vp.Height = height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pd3dDeviceContext->RSSetViewports( 1, &vp );
}
return 1;
Выбор выходных данных и размера DXGI
По умолчанию DXGI выбирает выходные данные, содержащие большую часть клиентской области окна. Это единственный вариант, доступный для DXGI, когда он переключается в полноэкранный режим в ответ на комбинацию клавиш альт-энтер. Если приложение само переходит в полноэкранный режим, оно может вызвать IDXGISwapChain::SetFullscreenState и явно передать IDXGIOutput1 (или NULL, если приложению довольно, чтобы DXGI решал).
Чтобы изменить размер вывода при полном экране или в оконном режиме, рекомендуется вызвать IDXGISwapChain::ResizeTarget, так как этот метод также изменяет размер целевого окна. Поскольку целевое окно изменяется, операционная система отправляет WM_SIZE, и код естественным образом вызывает IDXGISwapChain::ResizeBuffers в ответ. Таким образом, это трата усилий для изменения размера буферов, а затем последующего изменения размера целевого объекта.
Отладка в полноэкранном режиме
Цепочка буферов DXGI отказывается от полноэкранного режима только в случае крайней необходимости. Это означает, что вы можете отлаживать полноэкранное приложение с помощью нескольких мониторов, если окно отладки не перекрывает целевое окно цепочки обмена. Кроме того, можно полностью запретить переключение режима, не задав флаг DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH.
Если переключение режима разрешено, цепочка буферов будет отказаться от полноэкранного режима всякий раз, когда его выходное окно закрывается другим окном. Проверка окклюзии выполняется во время IDXGISwapChain1::Present1или отдельным потоком, цель которого - проверить, не перестало ли приложение отвечать (и больше не вызывает IDXGISwapChain1::Present1). Чтобы отключить возможность отдельного потока вызвать переключение, задайте для следующего раздела реестра любое ненулевое значение.
HKCU\Software\Microsoft\DXGI\DisableFullscreenWatchdog
Уничтожение цепочки обмена
Вы не можете освободить цепочку обмена в полноэкранном режиме, так как это может создать соревнование потоков (что приведет к тому, что DXGI вызовет неконтинуируемое исключение). Перед освобождением своп-цепочки сначала переключитесь в оконный режим (с помощью IDXGISwapChain::SetFullscreenState( FALSE, NULL )), а затем вызовите IUnknown::Release.
Использование вращающегося монитора
Приложению не нужно беспокоиться об ориентацией монитора: DXGI повернёт буфер своп-цепочки во время презентации при необходимости. Конечно, эта дополнительная смена может повлиять на производительность. Чтобы добиться оптимальной производительности, учтите смену ориентации в вашем приложении, выполнив следующие действия.
- Используйте DXGI_SWAP_CHAIN_FLAG_NONPREROTATED. Это уведомляет DXGI о том, что приложение создаст повернутое изображение (например, путем изменения матрицы проекции). Обратите внимание, что этот флаг действителен только в полноэкранном режиме.
- Выделите каждый буфер цепочки обмена в его повернутом размере. При необходимости используйте IDXGIOutput::GetDesc для получения этих значений.
Выполнив поворот в приложении, DXGI просто сделает копию вместо копирования и поворота.
Среда выполнения Direct3D 11.1, которая доступна начиная с Windows 8, предоставляет цепочку обмена буферов с моделью переверки (т. е. цепочку, в которой установлено значение DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL в элементе SwapEffect структуры DXGI_SWAP_CHAIN_DESC1). Чтобы максимально повысить эффективность оптимизации презентации, доступной с помощью цепочки обмена в переворачивающей модели, рекомендуется ориентировать содержимое приложений так, чтобы оно соответствовало конкретным выходным устройствам, на которых содержимое находится, когда оно полностью их заполняет. Дополнительные сведения о цепочках обмена flip-моделей и их преимуществах см. в разделе DXGI Flip Model.
Переключение режимов
Цепочка буферов DXGI может изменить режим отображения выхода при переходе в полноэкранный режим. Чтобы включить автоматическое изменение режима отображения, необходимо указать DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH в описании цепочки буферов. Если режим отображения автоматически изменяется, DXGI выберет самый скромный режим (размер и разрешение не изменится, но глубина цвета может быть изменена). Изменение размера буферов цепи обмена не приведет к переключению режима. Цепочка буферов дает неявное обещание, что если выбрать задний буфер, который точно соответствует режиму отображения, поддерживаемому целевым устройством вывода, то оно переключится в этот режим отображения при переходе в полноэкранный режим на этом устройстве вывода. Следовательно, вы выбираете режим отображения, выбирая размер и формат заднего буфера.
Совет по улучшению производительности в полноэкранном режиме
При вызове IDXGISwapChain1::Present1 в полноэкранном приложении цепочка буферов переключает содержимое обратного буфера в передний буфер (в отличие от копирований). Для этого требуется, чтобы цепочка обмена была создана с использованием перечисленного режима отображения (указанного в DXGI_SWAP_CHAIN_DESC1). Если вы не можете перечислить режимы отображения или неправильно указать режим отображения в описании, цепочка переключения может выполнять передачу битовых блоков (bitblt). Bitblt вызывает дополнительное растянутое копирование и более высокое использование видеопамяти, что трудно обнаружить. Чтобы избежать этой проблемы, перечислите режимы отображения и инициализируйте описание цепочки буферов перед ее созданием. Это обеспечит максимальную производительность при переворачивании в полноэкранном режиме и избегает дополнительных затрат на память.
Многопоточные аспекты
При использовании DXGI в приложении с несколькими потоками необходимо быть осторожным, чтобы избежать создания взаимоблокировки, где два разных потока ожидают завершения друг друга. Существует две ситуации, когда это может произойти.
- Поток отрисовки не является потоком обработки сообщений.
- Поток, выполняющий API DXGI, не является тем же потоком, который создал окно.
Будьте осторожны, чтобы поток обработки сообщений никогда не дожидался завершения потока отрисовки при использовании полноэкранных цепочек обмена. Например, вызов IDXGISwapChain1::Present1 (из потока отрисовки) может привести к ожиданию потока отрисовки в потоке обработки сообщений. При изменении режима этот сценарий возможен, если Present1 вызывает ::SetWindowPos() или ::SetWindowStyle() и один из этих методов вызывает ::SendMessage(). В этой ситуации, если поток обмена сообщениями защищён критической секцией или если поток отрисовки заблокирован, то два потока окажутся во взаимоблокировке.
Дополнительные сведения об использовании DXGI с несколькими потоками см. раздел Многопоточность и DXGI.
Ответы DXGI из DLLMain
Так как функция DllMainне может гарантировать порядок загрузки и выгрузки библиотек DLL, рекомендуется, чтобы функция DllMain не вызывала функции или методы Direct3D или DXGI, включая те, которые создают или освобождают объекты. Если функция DllMain приложения вызывает определенный компонент, этот компонент может вызвать другую библиотеку DLL, которая отсутствует в операционной системе, что приводит к сбою операционной системы. Direct3D и DXGI могут загружать набор DLL, обычно включающий драйверы, который может различаться на разных компьютерах. Таким образом, даже если ваше приложение не завершает работу на компьютерах разработки и тестирования, когда его функция DllMain вызывает функции Direct3D или DXGI, оно может завершиться сбоем при запуске на другом компьютере.
Чтобы предотвратить создание приложения, которое может привести к сбою операционной системы, DXGI предоставляет следующие ответы в указанных ситуациях:
- Если функция DllMain приложения освобождает последнюю ссылку на фабрику DXGI, DXGI вызывает исключение.
- Если функция DllMainприложениясоздает фабрику DXGI, DXGI возвращает код ошибки.
Изменения DXGI 1.1
Мы добавили следующие функции в DXGI 1.1.
Поддержка синхронизированных общих поверхностей
Синхронизированные общие поверхности для Direct3D 10.1 и Direct3D 11 позволяют эффективно читать и записывать поверхности между несколькими устройствами Direct3D (возможно совместное использование устройств Direct3D 10 и Direct3D 11). См. раздел IDXGIKeyedMutex::AcquireSync и IDXGIKeyedMutex::ReleaseSync.
Поддержка высокого цвета
Поддерживает формат DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM.
IDXGIDevice1::SetMaximumFrameLatency и IDXGIDevice1::GetMaximumFrameLatency
IDXGIFactory1::EnumAdapters1 перечисляет локальные адаптеры без каких-либо мониторов или выходных данных, а также адаптеров с подключенными выходными данными. Первый возвращённый адаптер будет локальным адаптером, на котором отображается основная рабочая область рабочего стола.
Поддержка формата BGRA
DXGI_FORMAT_B8G8R8A8_UNORM и DXGI_FORMAT_B8G8R8A8_UNORM_SRGB см. раздел IDXGISurface1::GetDC и IDXGISurface1::ReleaseDC.
Изменения DXGI 1.2
Мы добавили следующие функции в DXGI 1.2.
- Стерео буферная цепочка
- цепочка обмена моделью Flip
- Оптимизированная презентация (прокрутка, грязные прямоугольники и поворот)
- Улучшены общие ресурсы и синхронизация
- дублирование экрана рабочего стола
- Оптимизированное использование памяти видео
- Поддержка форматов 16 бит на пиксель (bpp) (DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, DXGI_FORMAT_B4G4R4A4_UNORM)
- Отладка API
Дополнительные сведения о DXGI 1.2 см. в Улучшения DXGI 1.2.