Compartir a través de


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

API 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 para que los sombreadores se 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 comandos a la canalización de gráficos para un contexto de representación específico.
  • Crear y administrar recursos del sombreador y asociarlos con un contenido de representación.
  • Representación en destinos de representación específicos (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 él, así como admitir características de aplicación de 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 el objeto EGL básico en la asignación de la interfaz de Direct3D:

Abstracción de EGL Representación similar de Direct3D
EGLDisplay En Direct3D (para aplicaciones para UWP), el identificador de pantalla se obtiene a través de la API 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 e IDXGIDevice1, respectivamente.
EGLSurface En Direct3D, los búferes y otros recursos de ventana (visibles o desactivados) se crean y configuran mediante interfaces DXGI específicas, como IDXGIFactory2 (una implementación de patrón de fábrica que se usa para adquirir recursos DXGI comoIDXGISwapChain1 (búferes de visualización). 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, configurará y emitirá 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, galerías de símbolos y sombreadores con 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 para UWP, adquiera una cadena de intercambio de IDXGIAdapter2 con IDXGIFactory2::CreateSwapChainForCoreWindow y pásela la referencia de CoreWindow que obtuvo en el paso 1. Obtendrá una instancia IDXGISwapChain1 a cambio. Consítelo al objeto de representador y a su subproceso de representación.
  3. Obtenga las instancias ID3D11Device1 y ID3D11DeviceContext1 llamando al método D3D11Device::CreateDevice. Consíquelos también al objeto del representador.
  4. Cree sombreadores, texturas y otros recursos mediante métodos en el objeto ID3D11Device1 del representador.
  5. Defina búferes, ejecute sombreadores y administre las fases de canalización mediante métodos en el objeto ID3D11DeviceContext1 del representador.
  6. Cuando se ha ejecutado la canalización y se dibuja un marco en el búfer de reserva, presentándolo a la pantalla con IDXGISwapChain1::P resent1.

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 diferentes API para obtener una cadena de intercambio de Direct3D, como D3D11Device::CreateDeviceAndSwapChain y no usan un objeto CoreWindow.

 

Obtención de una ventana para mostrar

En este ejemplo, eglGetDisplay se pasa un HWND 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, inicializa, establece la configuración preferida y crea una superficie con un búfer de reserva 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 usas la interoperabilidad direct3D-XAML, usas el proveedor de vistas del marco XAML). El proceso para crear un proveedor de vistas de Direct3D se describe en Configuración de la aplicación para mostrar una vista.

Obtener 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 un id3D11Device1 y un id3D11DeviceContext1 y úselos para obtener el IDXGIDevice1 subyacente e IDXGIAdapter para poder obtener un objeto IDXGIFactory2 para crear un recurso de cadena de intercambio basado en la configuración de DXGI_SWAP_CHAIN_DESC1.

Configuración y configuración 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::P resent1 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 de reserva en el que se dibujará nuestra canalización de sombreador.

Configuración del búfer de copia de seguridad 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 mediante la creación de ese contexto y el enlace a la superficie y a la pantalla.

El flujo de llamadas suele ser similar al siguiente:

  • Llame a eglGetDisplay con el identificador a un recurso de visualización o ventana y obtenga un objeto display.
  • 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 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 para él, puede proporcionarlo con un contexto de representación y ejecutar la canalización del sombreador 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::D raw (o una operación Draw* similar en el contexto del dispositivo) mediante este destino de representació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 eglSwapBuffers.

Abra 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::P resent1. A continuación, llama a uno de los métodos ID3D11DeviceContext1::D raw* para ejecutar los sombreadores y dibujar los resultados en un destino de representación configurado como búfer de reserva para la cadena de intercambio. Después, simplemente presenta el búfer de reserva a la pantalla llamando a IDXGISwapChain::P resent1.

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.

Terminación de 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, el sistema operativo ha expirado. 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/D
eglBindTexImage Llame a ID3D11Device::CreateTexture2D para establecer una textura 2D.
eglChooseConfig Direct3D no proporciona un conjunto de configuraciones de búfer de fotogramas predeterminadas. 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 (objeto ID3D11DeviceContext1). También puede crear un contexto diferido de Direct3D llamando a ID3D11Device2::CreateDeferredContext en el objeto ID3D11Device1 devuelto.
eglCreatePbufferFromClientBuffer Todos los búferes se leen y escriben como un subrecurso direct3D, como id3D11Texture2D. Copie de uno a otro tipo de subrecurso compatible con métodos 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 Entenda un IDXGISwapChain1 (para los búferes de visualización) y un ID3D11Device1 (una interfaz virtual para el dispositivo gráfico y sus recursos). Use id3D11Device1 para definir un ID3D11RenderTargetView que puede usar para crear el búfer de fotogramas que proporcione al IDXGISwapChain1.
eglDestroyContext N/D Use ID3D11DeviceContext::D iscardView1 para deshacerse de una vista de destino de representación. Para cerrar el id3D11DeviceContext1 primario, establezca la instancia en null y espere a que la plataforma recupere sus recursos. No se puede destruir el contexto del dispositivo directamente.
eglDestroySurface N/D Los recursos gráficos se limpian cuando la plataforma cierra CoreWindow de la aplicación para UWP.
eglGetCurrentDisplay Llame a CoreWindow::GetForCurrentThread para obtener una referencia a la ventana de la aplicación principal actual.
eglGetCurrentSurface Este es el id3D11RenderTargetView actual. Normalmente, esto tiene como ámbito el objeto de representador.
eglGetError Los errores se obtienen como HRESULT devueltos por la mayoría de los métodos en interfaces 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/D Sin embargo, puede adquirir destinos de representación de una instancia ID3D11Device1 , así como algunos datos de configuración. (Consulte el vínculo para obtener la lista de métodos disponibles).
eglQuerySurface N/D Sin embargo, puede adquirir datos sobre las ventanillas y el hardware gráfico actual de los métodos en una instancia ID3D11Device1. (Consulte el vínculo para obtener la lista de métodos disponibles).
eglReleaseTexImage N/D
eglReleaseThread Para la multithreading general de GPU, lea Multithreading.
eglSurfaceAttrib Use D3D11_RENDER_TARGET_VIEW_DESC para configurar una vista de destino de representación de Direct3D,
eglSwapBuffers Use IDXGISwapChain1::P resent1.
eglSwapInterval Consulte IDXGISwapChain1.
eglTerminate CoreWindow usado para mostrar la salida de la canalización de gráficos se administra mediante el sistema operativo.
eglWaitClient Para las superficies compartidas, use IDXGIKeyedMutex. Para la multithreading general de GPU, lea Multithreading.
eglWaitGL Para las superficies compartidas, use IDXGIKeyedMutex. Para la multithreading general de GPU, lea Multithreading.
eglWaitNative Para las superficies compartidas, use IDXGIKeyedMutex. Para la multithreading general de GPU, lea Multithreading.