Compartir a través de


Comparación del código EGL con DXGI y Direct3D

Las APIs importantes

La interfaz de gráficos de DirectX (DXGI) y varias API de Direct3D tienen el mismo rol que EGL. Este tema le ayuda a comprender DXGI y Direct3D 11 desde la perspectiva de EGL.

DXGI y Direct3D, como EGL, proporcionan métodos para configurar recursos gráficos, obtener un contexto de representación en el que los sombreadores dibujen y muestren los resultados en una ventana. Sin embargo, DXGI y Direct3D tienen muchas más opciones y requieren más esfuerzo para configurar correctamente al migrar desde EGL.

Nota Esta guía se basa en la especificación abierta de Khronos Group para EGL 1.4, que se encuentra aquí: Khronos Native Platform Graphics Interface (EGL versión 1.4 - 6 de abril de 2011) [PDF]. Las diferencias en la sintaxis específica de otras plataformas y lenguajes de desarrollo no se tratan en esta guía.

 

¿Cómo se compara DXGI y Direct3D?

La gran ventaja de EGL sobre DXGI y Direct3D es que es relativamente sencillo empezar a dibujar en una superficie de ventana. Esto se debe a que OpenGL ES 2.0(y, por tanto, EGL) es una especificación implementada por varios proveedores de plataformas, mientras que DXGI y Direct3D son una sola referencia a la que deben cumplir los controladores del proveedor de hardware. Esto significa que Microsoft debe implementar un conjunto de API que permitan el conjunto más amplio posible de características del proveedor, en lugar de centrarse en un subconjunto funcional ofrecido por un proveedor específico, o mediante la combinación de comandos de configuración específicos del proveedor en API más sencillas. Por otro lado, Direct3D proporciona un único conjunto de API que cubren una amplia gama de plataformas de hardware gráfico y niveles de características, y ofrecen más flexibilidad para los desarrolladores experimentados con la plataforma.

Al igual que EGL, DXGI y Direct3D proporcionan API para los comportamientos siguientes:

  • Obtener y leer y escribir en un búfer de fotogramas (denominado "cadena de intercambio" en DXGI).
  • Asociación del búfer de fotogramas con una ventana de interfaz de usuario.
  • Obtención y configuración de contextos de representación en los que se va a dibujar.
  • Emitir órdenes al canal de gráficos para un contexto de renderizado específico.
  • Crear y administrar recursos de sombreador y asociarlos con contenido de renderizado.
  • Representación en objetivos específicos de renderizado (como texturas).
  • Actualizando la superficie de visualización de la ventana con los resultados de la representación con los recursos gráficos.

Para ver el proceso básico de Direct3D para configurar la canalización de gráficos, consulte la plantilla Aplicación DirectX 11 (Universal Windows) en Microsoft Visual Studio 2015. La clase de representación base en ella proporciona una buena línea base para configurar la infraestructura de gráficos de Direct3D 11 y configurar recursos básicos en ella, así como admitir características de la aplicación para la Plataforma universal de Windows (UWP), como la rotación de pantalla.

EGL tiene muy pocas API relativas a Direct3D 11 y navegar por este último puede ser un desafío si no está familiarizado con la nomenclatura y la jerga en particular para la plataforma. Esta es una introducción sencilla que le ayudará a orientarse.

En primer lugar, revise la asignación de interfases del objeto EGL básico a Direct3D.

Abstracción de EGL Representación similar de Direct3D
EGLDisplay En Direct3D (para aplicaciones para UWP), el identificador de ventana se obtiene a través de la API de Windows::UI::CoreWindow (o la interfaz ICoreWindowInterop que expone el HWND). La configuración del adaptador y el hardware se establecen con las interfaces COM IDXGIAdapter de y IDXGIDevice1 de , respectivamente.
EGLSurface En Direct3D, los búferes y otros recursos de ventana (visibles o no visibles) se crean y configuran mediante interfaces específicas de DXGI, incluidos IDXGIFactory2 (una implementación del patrón de fábrica que se usa para adquirir recursos de DXGI, comoIDXGISwapChain1 (búferes de pantalla). El ID3D11Device1 que representa el dispositivo gráfico y sus recursos, se adquiere con D3D11Device::CreateDevice. Para destinos de representación, use la interfaz ID3D11RenderTargetView.
EGLContext En Direct3D, configuras y emites comandos en la canalización de gráficos con la interfaz ID3D11DeviceContext1.
EGLConfig En Direct3D 11, se crean y configuran recursos gráficos como búferes, texturas, plantillas y sombreadores, utilizando métodos en la interfaz ID3D11Device1.

 

Ahora, este es el proceso más básico para configurar una pantalla gráfica sencilla, recursos y contexto en DXGI y Direct3D para una aplicación para UWP.

  1. Obtenga un identificador del objeto CoreWindow para el subproceso de interfaz de usuario principal de la aplicación llamando a CoreWindow::GetForCurrentThread.
  2. Para las aplicaciones UWP, adquiera una cadena de intercambio (swap chain) de la IDXGIAdapter2 con IDXGIFactory2::CreateSwapChainForCoreWindowy pásele la referencia CoreWindow que obtuvo en el paso 1. Recibirá una instancia de IDXGISwapChain1 a cambio. Limitalo al objeto renderizador y a su subproceso de renderización.
  3. Obtenga las instancias ID3D11Device1 y ID3D11DeviceContext1 llamando al método D3D11Device::CreateDevice . Asígnelos también a su objeto renderizador.
  4. Cree sombreadores, texturas y otros recursos mediante métodos en el ID3D11Device1 del representador objeto.
  5. Defina búferes, ejecute sombreadores y administre las fases de tubería mediante métodos en el objeto ID3D11DeviceContext1 de su renderizador.
  6. Cuando la tubería se ha ejecutado y se dibuja un fotograma en el búfer de reserva, preséntelo en la pantalla con IDXGISwapChain1::Present1.

Para examinar este proceso con más detalle, consulte Introducción a los gráficos directX. En el resto de este artículo se describen muchos de los pasos comunes para la configuración y administración básicas de la canalización de gráficos.

Nota, Las aplicaciones de escritorio de Windows tienen distintas API para obtener una cadena de intercambio de Direct3D, como D3D11Device::CreateDeviceAndSwapChainy no usan un objeto CoreWindow.

 

Obtención de una ventana para mostrar

En este ejemplo, se pasa un HWND a la función eglGetDisplay para un recurso de ventana específico de la plataforma Microsoft Windows. Otras plataformas, como iOS (Cocoa) de Apple y Android de Google, tienen diferentes identificadores o referencias a recursos de ventana, y pueden tener una sintaxis de llamada diferente por completo. Después de obtener una pantalla, tú la inicializas, estableces una configuración preferida y creas una superficie con un búfer de fondo en el que puedes dibujar.

Obtener una pantalla y configurarla con 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;
}

En Direct3D, la ventana principal de una aplicación para UWP se representa mediante el objeto CoreWindow , que se puede obtener del objeto de aplicación llamando a CoreWindow::GetForCurrentThread como parte del proceso de inicialización del "proveedor de vistas" que construyes para Direct3D. (Si utilizas la interoperabilidad con Direct3D-XAML, empleas el proveedor de vistas del marco XAML). El proceso para crear un proveedor de vistas de Direct3D está cubierto en Cómo configurar tu aplicación para mostrar una vista.

Obtener un CoreWindow para Direct3D.

CoreWindow::GetForCurrentThread();

Una vez que se obtiene la referencia de CoreWindow , la ventana debe activarse, que ejecuta el método Run del objeto principal y comienza el procesamiento de eventos de ventana. Después, cree una ID3D11Device1 y un ID3D11DeviceContext1y úselos para obtener el IDXGI subyacente. y IDXGIAdapter para poder obtener un objeto IDXGIFactory 2 para crear un recurso de cadena de intercambio en función de la configuración de DXGI_SWAP_CHAIN_DESC1.

Configuración y ajuste de la cadena de intercambio DXGI en CoreWindow para 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);
}

Llame al método IDXGISwapChain1::Present1 después de preparar un fotograma para mostrarlo.

Tenga en cuenta que en Direct3D 11, no hay una abstracción idéntica a EGLSurface. (Hay IDXGISurface1, pero se usa de forma diferente). La aproximación conceptual más cercana es el objeto ID3D11RenderTargetView que usamos para asignar una textura (ID3D11Texture2D) como el búfer trasero en el que se dibujará nuestra canalización de sombreador.

Configuración del búfer trasero para la cadena de intercambio en 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);

Un procedimiento recomendado es llamar a este código cada vez que se crea o cambia el tamaño de la ventana. Durante la representación, establezca la vista de destino de representación con ID3D11DeviceContext1::OMSetRenderTargets antes de configurar cualquier otro subrecurso como búferes de vértices o sombreadores.

// Set the render target for the draw operation.
m_d3dContext->OMSetRenderTargets(
        1,
        d3dRenderTargetView.GetAddressOf(),
        nullptr);

Creación de un contexto de representación

En EGL 1.4, una "visualización" representa un conjunto de recursos de ventana. Normalmente, se configura una "superficie" para la pantalla proporcionando un conjunto de atributos al objeto de visualización y obteniendo una superficie de retorno. Se crea un contexto para mostrar el contenido de la superficie creando ese contexto y vinculándolo a la superficie y a la pantalla.

El flujo de llamadas suele ser similar al siguiente:

  • Llame a eglGetDisplay con el identificador de un recurso de pantalla o ventana y obtenga un objeto de pantalla.
  • Inicialice la presentación con eglInitialize.
  • Obtenga la configuración de visualización disponible y seleccione una con eglGetConfigs y eglChooseConfig.
  • Cree una superficie de ventana con eglCreateWindowSurface.
  • Cree un contexto de visualización para dibujar con eglCreateContext.
  • Enlace el contexto de visualización a la pantalla y la superficie con eglMakeCurrent.

n la sección anterior, creamos EGLDisplay y EGLSurface, y ahora usamos EGLDisplay para crear un contexto y asociar ese contexto a la pantalla, mediante el EGLSurface configurado para parametrizar la salida.

Obtención de un contexto de representación con 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;
}

Un contexto de representación en Direct3D 11 se representa mediante un objeto ID3D11Device1 , que representa el adaptador y le permite crear recursos de Direct3D, como búferes y sombreadores; y por el objeto ID3D11DeviceContext1 , que permite administrar la canalización de gráficos y ejecutar los sombreadores.

Tenga en cuenta los niveles de características de Direct3D. Se usan para admitir plataformas de hardware de Direct3D anteriores, desde DirectX 9.1 a DirectX 11. Muchas plataformas que usan hardware gráfico de baja potencia, como tabletas, solo tienen acceso a las características de DirectX 9.1 y el hardware gráficos compatible anterior podría ser de 9.1 a 11.

Creación de un contexto de representación con DXGI y 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.
);

Dibujar en un recurso de textura o pixmap

Para dibujar en una textura con OpenGL ES 2.0, configure un búfer de píxeles o PBuffer. Después de configurar y crear correctamente un EGLSurface, puede proveerlo de un contexto de representación y ejecutar el pipeline de sombreado para dibujar en la textura.

Dibujar en un búfer de píxeles con 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); 

En Direct3D 11, se crea un recurso ID3D11Texture2D y se convierte en un destino de representación. Configure el destino de representación mediante D3D11_RENDER_TARGET_VIEW_DESC. Al llamar al método ID3D11DeviceContext::Draw (o una operación similar de Draw* en el contexto del dispositivo) usando este destino de renderización, los resultados se dibujan en una textura.

Dibujar en una textura con 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);

Esta textura se puede pasar a un sombreador si está asociada a un ID3D11ShaderResourceView.

Dibujar en la pantalla

Una vez que haya usado EGLContext para configurar los búferes y actualizar los datos, ejecute los sombreadores enlazados a él y dibuje los resultados en el búfer de reserva con glDrawElements. Para mostrar el búfer de reserva, llame a la función eglSwapBuffers.

Open GL ES 2.0: Dibujar en la pantalla.

glDrawElements(GL_TRIANGLES, renderer->numIndices, GL_UNSIGNED_INT, 0);

eglSwapBuffers(drawContext->eglDisplay, drawContext->eglSurface);

En Direct3D 11, configura los búferes y enlaza sombreadores con IDXGISwapChain::Present1. A continuación, llama a uno de los métodos ID3D11DeviceContext1::Draw* para ejecutar los sombreadores y dibujar los resultados en un destino de representación configurado como búfer trasero para la cadena de intercambio. Después, simplemente presenta el búfer de reserva en la pantalla llamando a IDXGISwapChain::Present1.

Direct3D 11: Dibujar en la pantalla.


m_d3dContext->DrawIndexed(
        m_indexCount,
        0,
        0);

// ...

m_swapChainCoreWindow->Present1(1, 0, &parameters);

Liberar recursos gráficos

En EGL, libera los recursos de la ventana pasando EGLDisplay a eglTerminate.

Cerrar una pantalla con EGL 1.4

EGLBoolean eglTerminate(eglDisplay);

En una aplicación para UWP, puedes cerrar CoreWindow con CoreWindow::Close, aunque solo se puede usar para las ventanas secundarias de la interfaz de usuario. No se puede cerrar el subproceso de interfaz de usuario principal y su CoreWindow asociado; en su lugar, son finalizados por el sistema operativo. Sin embargo, cuando se cierra una instancia secundaria de CoreWindow, se genera el evento CoreWindow::Closed .

Asignación de referencia de API para EGL a Direct3D 11

EGL API Comportamiento o API de Direct3D 11 similares
eglBindAPI N/A.
eglBindTexImage Llame a ID3D11Device::CreateTexture2D para establecer una textura 2D.
eglChooseConfig Direct3D no ofrece un conjunto de configuraciones predeterminadas para el búfer de fotogramas. Configuración de la cadena de intercambio
eglCopyBuffers Para copiar datos de búfer, llame a ID3D11DeviceContext::CopyStructureCount. Para copiar un recurso, llame a ID3DDeviceCOntext::CopyResource.
eglCreateContext Cree un contexto de dispositivo Direct3D llamando a D3D11CreateDevice, que devuelve un identificador a un dispositivo Direct3D y un contexto inmediato predeterminado de Direct3D (id3D11DeviceContext1 objeto). También puede crear un contexto diferido de Direct3D llamando a ID3D11Device2::CreateDeferredContext sobre el objeto ID3D11Device1 devuelto.
eglCreatePbufferFromClientBuffer Todos los búferes se leen y escriben como un subrecurso Direct3D, como un ID3D11Texture2D. Copie de un tipo de subrecurso compatible a otro con un método como ID3D11DeviceContext1:CopyResource.
eglCreatePbufferSurface Para crear un dispositivo Direct3D sin cadena de intercambio, llame al método estático D3D11CreateDevice . Para una vista de destino de representación de Direct3D, llame a ID3D11Device::CreateRenderTargetView.
eglCreatePixmapSurface Para crear un dispositivo Direct3D sin cadena de intercambio, llame al método estático D3D11CreateDevice . Para una vista de destino de representación de Direct3D, llame a ID3D11Device::CreateRenderTargetView.
eglCreateWindowSurface Obtenga un IDXGISwapChain1 (para los búferes de visualización) y un ID3D11Device1 (una interfaz virtual para el dispositivo gráfico y sus recursos). Use el ID3D11Device1 de para definir un ID3D11RenderTargetView que se puede usar para crear el búfer de fotogramas que proporcione al IDXGISwapChain1 .
eglDestroyContext N/A. Use ID3D11DeviceContext::DiscardView1 para deshacerse de una vista de objetivo de renderizado. Para cerrar el elemento padre ID3D11DeviceContext1, establezca la instancia a null y espere a que la plataforma recupere sus recursos. No se puede destruir el contexto del dispositivo directamente.
eglDestroySurface N/A. Los recursos gráficos se limpian cuando la plataforma cierra la "CoreWindow" de la aplicación UWP.
eglGetCurrentDisplay Llame a CoreWindow::GetForCurrentThread para obtener una referencia a la ventana de la aplicación principal actual.
eglGetCurrentSurface Este es el actual ID3D11RenderTargetView. Normalmente, esto se aplica al objeto renderizador.
eglGetError Los errores se obtienen como HRESULT devueltos por la mayoría de los métodos de las interfaces de DirectX. Si el método no devuelve un HRESULT, llame a GetLastError. Para convertir un error del sistema en un valor HRESULT, use la macro HRESULT_FROM_WIN32 .
eglInitialize Llame a CoreWindow::GetForCurrentThread para obtener una referencia a la ventana de la aplicación principal actual.
eglMakeCurrent Establezca un destino de representación para dibujar en el contexto actual con ID3D11DeviceContext1::OMSetRenderTargets.
eglQueryContext N/A. Sin embargo, puede adquirir objetivos de renderización de una instancia de ID3D11Device1, así como algunos datos de configuración. (Consulte el vínculo para obtener la lista de métodos disponibles).
eglQuerySurface N/A. Sin embargo, puede adquirir datos sobre los viewports y el hardware gráfico actual a partir de métodos en una instancia de ID3D11Device1. (Consulte el vínculo para obtener la lista de métodos disponibles).
eglReleaseTexImage N/A.
eglReleaseThread Para el uso general de multihilo en GPU, lea multihilo.
eglSurfaceAttrib Use D3D11_RENDER_TARGET_VIEW_DESC para configurar un objetivo de renderizado de Direct3D,
eglSwapBuffers Use IDXGISwapChain1::P resent1.
eglSwapInterval Consulte IDXGISwapChain1.
eglTerminate El CoreWindow usado para mostrar el resultado de la canalización gráfica es gestionado por el sistema operativo.
eglWaitClient Para las superficies compartidas, use IDXGIKeyedMutex. Para el uso general de multihilo en GPU, lea multihilo.
eglWaitGL Para las superficies compartidas, use IDXGIKeyedMutex. Para el uso general de multihilo en GPU, lea multihilo.
eglWaitNative Para las superficies compartidas, use IDXGIKeyedMutex. Para el uso general de multihilo en GPU, lea multihilo.