Сравнение кода EGL с DXGI и Direct3D
Важные API
Графический интерфейс DirectX (DXGI) и несколько API Direct3D служат той же ролью, что и EGL. Этот раздел поможет вам понять DXGI и Direct3D 11 с точки зрения EGL.
DXGI и Direct3D, например EGL, предоставляют методы для настройки графических ресурсов, получения контекста отрисовки для шейдеров для рисования и отображения результатов в окне. Однако DXGI и Direct3D имеют довольно много дополнительных параметров и требуют больше усилий для правильной настройки при переносе из EGL.
Обратите внимание , что это руководство основано на открытой спецификации Группы Хроноса для EGL 1.4, приведенной здесь: Хронос Native Platform Graphics Interface (EGL версии 1.4 – 6 апреля 2011 г.) [PDF]. Различия в синтаксисе, относящиеся к другим платформам и языкам разработки, не рассматриваются в этом руководстве.
Как сравниваются DXGI и Direct3D?
Большое преимущество EGL над DXGI и Direct3D заключается в том, что относительно просто начать рисование на поверхности окна. Это связано с тем, что OpenGL ES 2.0 (и, следовательно, EGL) — это спецификация, реализованная несколькими поставщиками платформ, в то время как DXGI и Direct3D являются одной ссылкой на то, что драйверы поставщиков оборудования должны соответствовать требованиям. Это означает, что корпорация Майкрософт должна реализовать набор API,которые позволяют максимально широкому набору функций поставщика, а не сосредоточиться на функциональном подмножестве, предлагаемом определенным поставщиком, или объединить команды установки конкретного поставщика в более простые API. С другой стороны, Direct3D предоставляет единый набор API, охватывающий очень широкий спектр графических аппаратных платформ и уровней функций, и обеспечивает большую гибкость для разработчиков, опытных с платформой.
Например, EGL, DXGI и Direct3D предоставляют API для следующих действий:
- Получение и чтение и запись в буфер кадра (называется "цепочкой буферов" в DXGI).
- Связывание буфера кадра с окном пользовательского интерфейса.
- Получение и настройка контекстов отрисовки, в которых необходимо нарисовать.
- Выдача команд в графический конвейер для определенного контекста отрисовки.
- Создание ресурсов шейдера и управление ими и связывание их с содержимым отрисовки.
- Отрисовка для определенных целевых объектов отрисовки (например, текстур).
- Обновление области отображения окна с результатами отрисовки с помощью графических ресурсов.
Чтобы просмотреть базовый процесс Direct3D для настройки графического конвейера, ознакомьтесь с шаблоном приложения DirectX 11 (универсальная версия Windows) в Microsoft Visual Studio 2015. Базовый класс отрисовки в нем предоставляет хороший базовый план для настройки графической инфраструктуры Direct3D 11 и настройки базовых ресурсов на нем, а также поддержки функций приложения универсальная платформа Windows (UWP), таких как поворот экрана.
EGL имеет очень мало API относительно Direct3D 11, и навигация по последнему может быть проблемой, если вы не знакомы с именованием и jargon конкретной платформы. Вот простой обзор, который поможет вам получить ориентацию.
Сначала просмотрите базовый объект EGL для сопоставления интерфейса Direct3D:
Абстракция EGL | Аналогичное представление Direct3D |
---|---|
EGLDisplay | В Direct3D (для приложений UWP) дескриптор отображения получается через API Windows::UI::CoreWindow (или интерфейс ICoreWindowInterop, предоставляющий HWND). Адаптер и конфигурация оборудования задаются с помощью интерфейсов COM IDXGIAdapter и IDXGIDevice1 соответственно. |
EGLSurface | В Direct3D буферы и другие ресурсы окна (видимые или внеэкранные) создаются и настраиваются определенными интерфейсами DXGI, включая IDXGIFactory2 (реализация шаблона фабрики, используемая для получения ресурсов DXGI, таких какIDXGISwapChain1 (буферы отображения). Идентификатор ID3D11Device1, представляющий графическое устройство и его ресурсы, получается с помощью D3D11Device::CreateDevice. Для целевых объектов отрисовки используйте интерфейс ID3D11RenderTargetView . |
EGLContext | В Direct3D вы настраиваете и выдаете команды в графическом конвейере с интерфейсом ID3D11DeviceContext1 . |
EGLConfig | В Direct3D 11 вы создаете и настраиваете графические ресурсы, такие как буферы, текстуры, наборы элементов и шейдеры с методами в интерфейсе ID3D11Device1 . |
Теперь вот самый простой процесс настройки простого графического отображения, ресурсов и контекста в DXGI и Direct3D для приложения UWP.
- Получите дескриптор объекта CoreWindow для основного потока пользовательского интерфейса приложения, вызвав CoreWindow::GetForCurrentThread.
- Для приложений UWP получите цепочку буферов из IDXGIAdapter2 с IDXGIFactory2::CreateSwapChainForCoreWindow и передайте ее ссылку CoreWindow, полученную на шаге 1. Вы получите экземпляр IDXGISwapChain1. Область действия объекта отрисовщика и его потока отрисовки.
- Получение экземпляров ID3D11Device1 и ID3D11DeviceContext1 путем вызова метода D3D11Device::CreateDevice. Также обведите их область для объекта отрисовщика.
- Создайте шейдеры, текстуры и другие ресурсы с помощью методов в объекте ID3D11Device1 отрисовщика.
- Определите буферы, шейдеры запуска и управляйте этапами конвейера с помощью методов в объекте ID3D11DeviceContext1 средства отрисовки.
- Когда конвейер выполнен и кадр рисуется в буфер обратной части, доведите его на экран с идентификатором IDXGISwapChain1::P resent1.
Дополнительные сведения об этом процессе см. в статье "Начало работы с графикой DirectX". В остальной части этой статьи рассматриваются многие распространенные шаги по настройке и управлению графическим конвейером.
Обратите внимание, что классические приложения Windows имеют разные API для получения цепочки буферов Direct3D, например D3D11Device::CreateDeviceAndSwapChain, и не используйте объект CoreWindow.
Получение окна для отображения
В этом примере eglGetDisplay передает HWND для ресурса окна, относяющегося к платформе Microsoft Windows. Другие платформы, такие как iOS Apple (Какао) и Android Google, имеют разные дескриптора или ссылки на ресурсы окна, и могут иметь другой синтаксис вызова в целом. После получения дисплея вы инициализируете его, задайте предпочтительную конфигурацию и создадите поверхность с буфером задней части, в который можно нарисовать.
Получение дисплея и его настройка с помощью EGL..
// Obtain an EGL display object.
EGLDisplay display = eglGetDisplay(GetDC(hWnd));
if (display == EGL_NO_DISPLAY)
{
return EGL_FALSE;
}
// Initialize the display
if (!eglInitialize(display, &majorVersion, &minorVersion))
{
return EGL_FALSE;
}
// Obtain the display configs
if (!eglGetConfigs(display, NULL, 0, &numConfigs))
{
return EGL_FALSE;
}
// Choose the display config
if (!eglChooseConfig(display, attribList, &config, 1, &numConfigs))
{
return EGL_FALSE;
}
// Create a surface
surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)hWnd, NULL);
if (surface == EGL_NO_SURFACE)
{
return EGL_FALSE;
}
В Direct3D основное окно приложения UWP представлено объектом CoreWindow, который можно получить из объекта приложения, вызвав CoreWindow::GetForCurrentThread в рамках процесса инициализации поставщика представления, созданного для Direct3D. (Если вы используете взаимодействие Direct3D-XAML, используйте поставщик представлений платформы XAML.) Процесс создания поставщика представления Direct3D рассматривается в статье "Настройка приложения для отображения представления".
Получение CoreWindow для Direct3D.
CoreWindow::GetForCurrentThread();
После получения ссылки CoreWindow окно должно быть активировано, которое выполняет метод Run основного объекта и начинает обработку событий окна. После этого создайте идентификатор ID3D11Device1 и ID3D11DeviceContext1 и используйте их для получения базового объекта IDXGIDevice1 и IDXGIAdapter, чтобы получить объект IDXGIFactory2 для создания ресурса цепочки буферов на основе конфигурации DXGI_SWAP_CHAIN_DESC1.
Настройка и настройка цепочки буферов DXGI в CoreWindow для Direct3D.
// Called when the CoreWindow object is created (or re-created).
void SimpleDirect3DApp::SetWindow(CoreWindow^ window)
{
// Register event handlers with the CoreWindow object.
// ...
// Obtain your ID3D11Device1 and ID3D11DeviceContext1 objects
// In this example, m_d3dDevice contains the scoped ID3D11Device1 object
// ...
ComPtr<IDXGIDevice1> dxgiDevice;
// Get the underlying DXGI device of the Direct3D device.
m_d3dDevice.As(&dxgiDevice);
ComPtr<IDXGIAdapter> dxgiAdapter;
dxgiDevice->GetAdapter(&dxgiAdapter);
ComPtr<IDXGIFactory2> dxgiFactory;
dxgiAdapter->GetParent(
__uuidof(IDXGIFactory2),
&dxgiFactory);
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
swapChainDesc.Width = static_cast<UINT>(m_d3dRenderTargetSize.Width); // Match the size of the window.
swapChainDesc.Height = static_cast<UINT>(m_d3dRenderTargetSize.Height);
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
swapChainDesc.Stereo = false;
swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency.
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All UWP apps must use this SwapEffect.
swapChainDesc.Flags = 0;
// ...
Windows::UI::Core::CoreWindow^ window = m_window.Get();
dxgiFactory->CreateSwapChainForCoreWindow(
m_d3dDevice.Get(),
reinterpret_cast<IUnknown*>(window),
&swapChainDesc,
nullptr, // Allow on all displays.
&m_swapChainCoreWindow);
}
Вызовите метод IDXGISwapChain1::P resent1 после подготовки кадра для отображения.
Обратите внимание, что в Direct3D 11 нет абстракции, идентичной EGLSurface. (Существует IDXGISurface1, но используется по-другому.) Ближайшее концептуальное приближение — это объект ID3D11RenderTargetView, который мы используем для назначения текстуры (ID3D11Texture2D) в качестве обратного буфера, в который будет рисовать конвейер шейдеров.
Настройка резервного буфера для цепочки буферов в Direct3D 11
ComPtr<ID3D11RenderTargetView> m_d3dRenderTargetViewWin; // scoped to renderer object
// ...
ComPtr<ID3D11Texture2D> backBuffer2;
m_swapChainCoreWindow->GetBuffer(0, IID_PPV_ARGS(&backBuffer2));
m_d3dDevice->CreateRenderTargetView(
backBuffer2.Get(),
nullptr,
&m_d3dRenderTargetViewWin);
Рекомендуется вызывать этот код всякий раз, когда окно создается или изменяет размер. Во время отрисовки задайте целевое представление отрисовки с идентификатором ID3D11DeviceContext1::OMSetRenderTargets перед настройкой других подресурсов, таких как буферы вершин или шейдеры.
// Set the render target for the draw operation.
m_d3dContext->OMSetRenderTargets(
1,
d3dRenderTargetView.GetAddressOf(),
nullptr);
Создание контекста отрисовки
В EGL 1.4 "display" представляет набор ресурсов окна. Как правило, вы настраиваете "surface" для отображения, предоставляя набор атрибутов отображаемого объекта и получая поверхность в обратном виде. Вы создаете контекст для отображения содержимого поверхности путем создания этого контекста и привязки его к поверхности и отображению.
Поток вызовов обычно выглядит примерно так:
- Вызовите eglGetDisplay с дескриптором к ресурсу отображения или окна и получите отображаемый объект.
- Инициализировать отображение с помощью eglInitialize.
- Получите доступную конфигурацию отображения и выберите ее с помощью eglGetConfigs и eglChooseConfig.
- Создайте поверхность окна с помощью eglCreateWindowSurface.
- Создайте контекст отображения для рисования с помощью eglCreateContext.
- Привязка контекста отображения к экрану и поверхности с помощью eglMakeCurrent.
n предыдущего раздела мы создали EGLDisplay и EGLSurface, и теперь мы используем EGLDisplay для создания контекста и связывания этого контекста с отображением, используя настроенный EGLSurface для параметризации выходных данных.
Получение контекста отрисовки с помощью EGL 1.4
// Configure your EGLDisplay and obtain an EGLSurface here ...
// ...
// Create a drawing context from the EGLDisplay
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
if (context == EGL_NO_CONTEXT)
{
return EGL_FALSE;
}
// Make the context current
if (!eglMakeCurrent(display, surface, surface, context))
{
return EGL_FALSE;
}
Контекст отрисовки в Direct3D 11 представлен объектом ID3D11Device1, который представляет адаптер и позволяет создавать ресурсы Direct3D, такие как буферы и шейдеры; и объектом ID3D11DeviceContext1, который позволяет управлять графическим конвейером и выполнять шейдеры.
Помните о уровнях функций Direct3D! Они используются для поддержки старых аппаратных платформ Direct3D с DirectX 9.1 до DirectX 11. Многие платформы, использующие оборудование с низкой мощностью графики, такие как планшеты, имеют доступ только к функциям DirectX 9.1, а более старое поддерживаемое графическое оборудование может быть от 9.1 до 11.
Создание контекста отрисовки с помощью DXGI и Direct3D
// ...
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
ComPtr<IDXGIDevice> dxgiDevice;
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};
// Create the Direct3D 11 API device object and a corresponding context.
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> d3dContext;
D3D11CreateDevice(
nullptr, // Specify nullptr to use the default adapter.
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
creationFlags, // Set debug and Direct2D compatibility flags.
featureLevels, // List of feature levels this app can support.
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for UWP apps.
&device, // Returns the Direct3D device created.
&m_featureLevel, // Returns feature level of device created.
&d3dContext // Returns the device immediate context.
);
Рисование в ресурс текстуры или pixmap
Чтобы нарисовать текстуру с помощью OpenGL ES 2.0, настройте буфер пикселей или PBuffer. После успешной настройки и создания EGLSurface для него можно указать контекст отрисовки и выполнить конвейер шейдера для рисования в текстуру.
Рисование в буфер пикселей с помощью OpenGL ES 2.0
// Create a pixel buffer surface to draw into
EGLConfig pBufConfig;
EGLint totalpBufAttrs;
const EGLint pBufConfigAttrs[] =
{
// Configure the pBuffer here...
};
eglChooseConfig(eglDsplay, pBufConfigAttrs, &pBufConfig, 1, &totalpBufAttrs);
EGLSurface pBuffer = eglCreatePbufferSurface(eglDisplay, pBufConfig, EGL_TEXTURE_RGBA);
В Direct3D 11 вы создаете ресурс ID3D11Texture2D и делаете его целевым объектом отрисовки. Настройте целевой объект отрисовки с помощью D3D11_RENDER_TARGET_VIEW_DESC. При вызове метода ID3D11DeviceContext::D raw (или аналогичной операции Draw* в контексте устройства) с помощью этого целевого объекта отрисовки результаты извлекаются в текстуру.
Рисование в текстуру с помощью Direct3D 11
ComPtr<ID3D11Texture2D> renderTarget1;
D3D11_RENDER_TARGET_VIEW_DESC renderTargetDesc = {0};
// Configure renderTargetDesc here ...
m_d3dDevice->CreateRenderTargetView(
renderTarget1.Get(),
nullptr,
&m_d3dRenderTargetViewWin);
// Later, in your render loop...
// Set the render target for the draw operation.
m_d3dContext->OMSetRenderTargets(
1,
d3dRenderTargetView.GetAddressOf(),
nullptr);
Эта текстура может быть передана шейдеру, если она связана с ID3D11ShaderResourceView.
Рисование на экране
После использования EGLContext для настройки буферов и обновления данных выполните шейдеры, привязанные к нему, и нарисуйте результаты обратному буферу с помощью glDrawElements. Вы отображаете задний буфер путем вызова eglSwapBuffers.
Откройте GL ES 2.0: рисование на экране.
glDrawElements(GL_TRIANGLES, renderer->numIndices, GL_UNSIGNED_INT, 0);
eglSwapBuffers(drawContext->eglDisplay, drawContext->eglSurface);
В Direct3D 11 вы настраиваете буферы и привязываете шейдеры с идентификатором IDXGISwapChain::P resent1. Затем вы вызываете один из методов ID3D11DeviceContext1::D raw* для запуска шейдеров и рисования результатов в целевой объект отрисовки, настроенный в качестве обратного буфера для цепочки буферов. После этого вы просто представляете задний буфер для отображения путем вызова IDXGISwapChain::P resent1.
Direct3D 11: рисование на экране.
m_d3dContext->DrawIndexed(
m_indexCount,
0,
0);
// ...
m_swapChainCoreWindow->Present1(1, 0, ¶meters);
Освобождение графических ресурсов
В EGL вы освобождаете ресурсы окна, передав EGLDisplay в eglTerminate.
Завершение отображения с помощью EGL 1.4
EGLBoolean eglTerminate(eglDisplay);
В приложении UWP можно закрыть CoreWindow с CoreWindow::Close, хотя это можно использовать только для дополнительных окон пользовательского интерфейса. Основной поток пользовательского интерфейса и связанный с ним CoreWindow не может быть закрыт; скорее, срок действия истек операционной системой. Однако при закрытии вторичного CoreWindow событие CoreWindow::Closed вызывается.
Сопоставление справочника по API для EGL с Direct3D 11
EGL API | Аналогичный API Direct3D 11 или поведение |
---|---|
eglBindAPI | Недоступно |
eglBindTexImage | Вызовите ID3D11Device::CreateTexture2D , чтобы задать трехмерную текстуру. |
eglChooseConfig | Direct3D не предоставляет набор конфигураций буфера кадров по умолчанию. Конфигурация цепочки буферов |
eglCopyBuffers | Чтобы скопировать данные буфера, вызовите ID3D11DeviceContext::CopyStructureCount. Чтобы скопировать ресурс, вызовите ID3DDeviceCOntext::CopyResource. |
eglCreateContext | Создайте контекст устройства Direct3D, вызвав D3D11CreateDevice, который возвращает дескриптор устройству Direct3D и контекст direct3D по умолчанию (объект ID3D11DeviceContext1). Вы также можете создать отложенный контекст Direct3D, вызвав id3D11Device2::CreateDeferredContext для возвращаемого объекта ID3D11Device1. |
eglCreatePbufferFromClientBuffer | Все буферы считываются и записываются в виде подресурса Direct3D, например ID3D11Texture2D. Скопируйте из одного в другой совместимый подресурс тип с такими методами, как ID3D11DeviceContext1:CopyResource. |
eglCreatePbufferSurface | Чтобы создать устройство Direct3D без цепочки буферов, вызовите статический метод D3D11CreateDevice . Для целевого представления отрисовки Direct3D вызовите id3D11Device::CreateRenderTargetView. |
eglCreatePixmapSurface | Чтобы создать устройство Direct3D без цепочки буферов, вызовите статический метод D3D11CreateDevice . Для целевого представления отрисовки Direct3D вызовите id3D11Device::CreateRenderTargetView. |
eglCreateWindowSurface | Ontain an IDXGISwapChain1 (для буферов отображения) и ID3D11Device1 (виртуальный интерфейс для графического устройства и его ресурсов). Используйте id3D11Device1 для определения идентификатора ID3D11RenderTargetView, который можно использовать для создания буфера кадров, который вы предоставляете IDXGISwapChain1. |
eglDetextContext | Недоступно Используйте ID3D11DeviceContext::D iscardView1 , чтобы избавиться от целевого представления отрисовки. Чтобы закрыть родительский идентификатор 3D11DeviceContext1, задайте экземпляру значение NULL и дождитесь освобождения ресурсов платформы. Вы не можете напрямую уничтожить контекст устройства. |
eglDefcSurface | Недоступно Графические ресурсы очищаются при закрытии платформой приложения UWP CoreWindow. |
eglGetCurrentDisplay | Вызов CoreWindow::GetForCurrentThread , чтобы получить ссылку на текущее главное окно приложения. |
eglGetCurrentSurface | Это текущий идентификатор ID3D11RenderTargetView. Как правило, это ограничивается объектом отрисовщика. |
eglGetError | Ошибки получаются в виде HRESULTs, возвращаемых большинством методов в интерфейсах DirectX. Если метод не возвращает HRESULT, вызовите GetLastError. Чтобы преобразовать системную ошибку в значение HRESULT, используйте макрос HRESULT_FROM_WIN32 . |
eglInitialize | Вызов CoreWindow::GetForCurrentThread , чтобы получить ссылку на текущее главное окно приложения. |
eglMakeCurrent | Задайте целевой объект отрисовки для рисования текущего контекста с идентификатором ID3D11DeviceContext1::OMSetRenderTargets. |
eglQueryContext | Недоступно Однако вы можете получить целевые объекты отрисовки из экземпляра ID3D11Device1 , а также некоторые данные конфигурации. (См. ссылку для списка доступных методов.) |
eglQuerySurface | Недоступно Однако вы можете получить данные о портах просмотра и текущем графическом оборудовании из методов экземпляра ID3D11Device1 . (См. ссылку для списка доступных методов.) |
eglReleaseTexImage | Недоступно |
eglReleaseThread | Для общего многопоточного графического процессора считывает многопоточность. |
eglSurfaceAttrib | Используйте D3D11_RENDER_TARGET_VIEW_DESC для настройки целевого представления отрисовки Direct3D, |
eglSwapBuffers | Используйте IDXGISwapChain1::P resent1. |
eglSwapInterval | См. раздел IDXGISwapChain1. |
eglTerminate | CoreWindow, используемый для отображения выходных данных графического конвейера, управляется операционной системой. |
eglWaitClient | Для общих поверхностей используйте IDXGIKeyedMutex. Для общего многопоточного графического процессора считывает многопоточность. |
eglWaitGL | Для общих поверхностей используйте IDXGIKeyedMutex. Для общего многопоточного графического процессора считывает многопоточность. |
eglWaitNative | Для общих поверхностей используйте IDXGIKeyedMutex. Для общего многопоточного графического процессора считывает многопоточность. |