将 EGL 代码与 DXGI 和 Direct3D 进行比较
DirectX Graphics Interface (DXGI) 以及若干个 Direct3D API 所起的作用与 EGL 相同。本主题帮助你从 EGL 的角度了解 DXGI 和 Direct3D。
和 EGL 一样,DXGI 和 Direct3D 提供配置图形资源、获取你的着色器要绘制到的呈现上下文以及在窗口中显示结果的方法。但是,DXGI 和 Direct3D 具有更多选项,因此从 EGL 移植时需要花费更多精力才能获得正确设置。
DXGI 和 Direct3D 如何进行比较?
和 EGL 一样,DXGI 和 Direct3D 都提供用于以下行为的 API:
- 获取、读取并写入到帧缓冲区(在 DXGI 中称为“交换链”)。
- 将帧缓冲区与 UI 窗口相关联。
- 获取并配置要在其中进行绘制的呈现上下文。
- 向特定呈现上下文的图形管道发出命令。
- 创建和管理着色器资源,并将这些资源与呈现内容相关联。
- 呈现到特定呈现目标(如纹理)。
- 用图形资源更新具有呈现结果的窗口显示图面。
与 Direct3D 11 相比,EGL 提供的 API 相对较少,如果你不熟悉特定于该平台的命名和行话,那么导航 EGL 可能会有很大难度。下面这个简单概述可帮助你应对这种挑战。
首先,查看基本的 EGL 对象到 Direct3D 接口的映射:
EGL 抽象 | 类似的 Direct3D 表示 |
---|---|
EGLDisplay | 在 Direct3D(对于 Windows 应用商店应用)中,通过 Windows::UI::CoreWindow API(或显示 HWND 的 ICoreWindowInterop 接口)获取显示句柄。适配器和硬件配置分别通过IDXGIAdapter 和 IDXGIDevice1 COM 接口进行设置。 |
EGLSurface | 在 Direct3D 中,缓冲区和其他窗口资源(可见资源或屏幕外资源)是由特定的 DXGI 接口创建和配置的,其中包括 IDXGIFactory2,它是用于获取 DXGI 资源(如 IDXGISwapChain1(显示缓冲区))的工厂模式实现。表示图形设备及其资源的 ID3D11Device1 是通过D3D11Device::CreateDevice 获取的。对于呈现目标,使用 ID3D11RenderTargetView 接口。 |
EGLContext | 在 Direct3D 中,使用 ID3D11DeviceContext1 接口配置命令并向图形管道发出命令。 |
EGLConfig | 在 Direct3D 11 中,通过在 ID3D11Device1 接口上使用方法创建和配置图形资源,如缓冲区、纹理、模具以及着色器。 |
现在,这里有在 Windows 应用商店应用中设置简单图形显示的最基本的过程、DXGI 中的资源和内容以及适用于 Windows 应用商店应用的 Direct3D。
- 通过调用 CoreWindow::GetForCurrentThread 来为应用的核心 UI 线程获取 CoreWindow 对象的句柄。
- 对于 Windows 应用商店应用,使用 IDXGIFactory2::CreateSwapChainForCoreWindow 从 IDXGIAdapter2 获取交换链,并向其传递在步骤 1 中获取的 CoreWindow 引用。反过来,你将获得 IDXGISwapChain1 实例。将其范围设置为呈现器对象及其呈现线程。
- 通过调用 D3D11Device::CreateDevice 方法获取 ID3D11Device1 和 ID3D11DeviceContext1 实例。还要将它们的范围设置为呈现器对象。
- 使用呈现器的 ID3D11Device1 对象上的方法创建着色器、纹理和其他资源。
- 使用呈现器的 ID3D11DeviceContext1 对象上的方法定义缓冲区、运行着色器并管理管道阶段。
- 当管道已执行且已将框架绘制到后台缓冲区时,使用 IDXGISwapChain1::Present1 将其显示到屏幕。
要更详细地检查此过程,请查看 DirectX 图形入门 。本文的其余部分介绍许多基本图形管道设置和管理的常见步骤。
获取用于显示的窗口
// 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 中,Windows 应用商店应用的主窗口由 CoreWindow 对象表示,作为你为 Direct3D 构造的“视图提供程序”初始化过程的一部分,可以通过调用 CoreWindow::GetForCurrentThread 来获得该对象。(如果你使用 Direct3D-XAML 互操作,则应使用 XAML 框架的视图提供程序。)如何设置应用以显示视图中介绍了创建 Direct3D 视图提供程序的过程。
获取用于 Direct3D 的 CoreWindow。
CoreWindow::GetForCurrentThread();
获取 CoreWindow 参考之后,必须激活窗口,该窗口执行主对象的 Run 方法并开始进行窗口事件处理。这之后,创建一个 ID3D11Device1 和一个 ID3D11DeviceContext1,并使用它们获取基础 IDXGIDevice1 和 IDXGIAdapter 以便你可以获取一个 IDXGIFactory2 对象来根据你的 DXGI_SWAP_CHAIN_DESC1 配置创建一个交换链资源。
在用于 Direct3D 的 CoreWindow 上配置并设置 DXGI 交换链。
// 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 Windows Store 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::Present1 方法以便显示该帧。
请注意,在 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);
创建呈现上下文
- 使用显示或窗口资源句柄调用 eglGetDisplay 并获取显示对象。
- 使用 eglInitialize 初始化显示。
- 使用 eglGetConfigs 和 eglChooseConfig 获取可用的显示配置并选择一个配置。
- 使用 eglCreateWindowSurface 创建一个窗口图面。
- 使用 eglCreateContext 创建一个用于绘制的显示上下文。
- 使用 eglMakeCurrent 将显示上下文绑定到显示和图面。
在上一部分中,我们创建了 EGLDisplay 和 EGLSurface,现在我们使用 EGLDisplay 创建一个上下文并使用配置的 EGLSurface 将输出参数化从而将该上下文与显示关联。
// 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。有关 Direct3D 功能级别的详细信息,请阅读针对不同的 Direct3D 功能级别进行开发。
使用 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 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 Windows Store 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 之后,你可以为其提供呈现上下文并执行着色器管道来绘制到纹理。
// 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::Draw 方法(或在设备上下文上执行类似的 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 显示后台缓冲区。
glDrawElements(GL_TRIANGLES, renderer->numIndices, GL_UNSIGNED_INT, 0);eglSwapBuffers(drawContext->eglDisplay, drawContext->eglSurface);
在 Direct3D 11 中,配置缓冲区并使用 IDXGISwapChain::Present1 绑定着色器。然后,调用一个ID3D11DeviceContext1::Draw* 方法来运行着色器并将结果绘制到配置为交换链的后台缓冲区的呈现目标。这之后,你只需通过调用 IDXGISwapChain::Present1 将后台缓冲区呈现给显示。
Direct3D 11:绘制到屏幕。
m_d3dContext->DrawIndexed(m_indexCount,0,0);// ...m_swapChainCoreWindow->Present1(1, 0, ¶meters);
释放图形资源
在 EGL 中,通过将 EGLDisplay 传递给 eglTerminate 释放窗口资源。
EGLBoolean eglTerminate(eglDisplay);
在 Windows 应用商店应用中,你可以使用 CoreWindow::Close 关闭 CoreWindow,但它仅用于辅助的 UI 窗口。不能关闭主 UI 线程及其关联的 CoreWindow;它们由操作系统来终止。但是,当关闭辅助 CoreWindow 时,会引发CoreWindow::Closed 事件。
EGL 到 Direct3D 11 的 API 参考映射
EGL API | 类似的 Direct3D 11 API 或行为 |
---|---|
eglBindAPI | N/A。 |
eglBindTexImage | 调用 ID3D11Device::CreateTexture2D 来设置 2D 纹理。 |
eglChooseConfig | Direct3D 未提供一组默认的帧缓冲区配置。交换链的配置 |
eglCopyBuffers | 若要复制缓冲区数据,请调用ID3D11DeviceContext::CopyStructureCount。若要复制资源,请调用ID3DDeviceCOntext::CopyResource。 |
eglCreateContext | 通过调用 D3D11CreateDevice(它会返回 Direct3D 设备的句柄以及默认的 Direct3D 即时上下文(ID3D11DeviceContext1 对象))创建一个 Direct3D 设备上下文。还可以通过在返回的 ID3D11Device1 对象上调用ID3D11Device2::CreateDeferredContext 来创建 Direct3D 延迟上下文。 |
eglCreatePbufferFromClientBuffer | 所有缓冲区都作为 Direct3D 子资源进行读取和写入,如ID3D11Texture2D。使用一个方法(如ID3D11DeviceContext1:CopyResource)从一种兼容的子资源类型复制到另一种兼容的子资源类型。 |
eglCreatePbufferSurface | 若要创建没有交换链的 Direct3D 设备,请调用静态的 D3D11CreateDevice方法。对于 Direct3D 呈现目标视图,请调用ID3D11Device::CreateRenderTargetView。 |
eglCreatePixmapSurface | 若要创建没有交换链的 Direct3D 设备,请调用静态的 D3D11CreateDevice方法。对于 Direct3D 呈现目标视图,请调用ID3D11Device::CreateRenderTargetView。 |
eglCreateWindowSurface | 获取一个 IDXGISwapChain1(对于显示缓冲区)和一个ID3D11Device1(用于图形设备及其资源的虚拟接口)。使用ID3D11Device1 定义一个你可以用来创建帧缓冲区(提供给IDXGISwapChain1)的 ID3D11RenderTargetView。 |
eglDestroyContext | N/A。使用 ID3D11DeviceContext::DiscardView1 去除呈现目标视图。若要关闭父 ID3D11DeviceContext1,请将该实例设置为 null 并等待平台回收其资源。不能直接破坏设备上下文。 |
eglDestroySurface | N/A。当平台关闭 Windows 应用商店应用的 CoreWindow 时,会清除图形资源。 |
eglGetCurrentDisplay | 调用 CoreWindow::GetForCurrentThread 来获取对当前主应用窗口的引用。 |
eglGetCurrentSurface | 这是当前的 ID3D11RenderTargetView。通常,它的作用域设置为你的呈现器对象。 |
eglGetError | 以 DirectX 接口上大多数方法返回的 HRESULT 形式获取错误。如果该方法未返回 HRESULT,请调用 GetLastError。若要将系统错误转换为 HRESULT 值,请使用 HRESULT_FROM_WIN32 宏。 |
eglInitialize | 调用 CoreWindow::GetForCurrentThread 来获取对当前主应用窗口的引用。 |
eglMakeCurrent | 使用 ID3D11DeviceContext1::OMSetRenderTargets 设置用于在当前上下文上绘制的呈现目标。 |
eglQueryContext | N/A。但是,你可能会从 ID3D11Device1 实例以及某些配置数据中获取呈现目标。(有关可用方法的列表,请参阅该链接。) |
eglQuerySurface | N/A。但是,你可能会通过 ID3D11Device1 实例上的方法来获取有关视区和当前图形硬件的数据。(有关可用方法的列表,请参阅该链接。) |
eglReleaseTexImage | N/A。 |
eglReleaseThread | 有关常规的 GPU 多线程,请阅读多线程。 |
eglSurfaceAttrib | 使用 D3D11_RENDER_TARGET_VIEW_DESC 配置 Direct3D 呈现目标视图。 |
eglSwapBuffers | 使用IDXGISwapChain1::Present1 。 |
eglSwapInterval | 请参阅 IDXGISwapChain1。 |
eglTerminate | 用于显示图形管道输出的 CoreWindow 由操作系统进行管理。 |
eglWaitClient | 对于共享图面,请使用 IDXGIKeyedMutex。有关常规的 GPU 多线程,请阅读多线程。 |
eglWaitGL | 对于共享图面,请使用 IDXGIKeyedMutex。有关常规的 GPU 多线程,请阅读多线程。 |
eglWaitNative | 对于共享图面,请使用 IDXGIKeyedMutex。有关常规的 GPU 多线程,请阅读多线程。 |
将 EGL 代码与 DXGI 和 Direct3D 进行比较相关推荐
- 【Visual C++】游戏开发笔记二十七 Direct3D 11入门级知识介绍
游戏开发笔记二十七 Direct3D 11入门级知识介绍 作者:毛星云 邮箱: happylifemxy@163.com 期待着与志同道合的朋友们相互交流 上一节里我们介绍了在迈入Dire ...
- DirectX11 Direct3D初始化
Direct3D初始化 1. Direct3D初始化步骤 下面将讲解如何初始化Direct3D.我们将Direct3D的初始化过程分为如下几个步骤: 1.使用D3D11CreateDevice方法创建 ...
- 【Visual C++】游戏开发笔记二十七 Direct3D 11入门级知识介绍
本系列文章由zhmxy555(毛星云)编写,转载请注明出处. http://blog.csdn.net/zhmxy555/article/details/7707628 作者:毛星云 邮箱: happ ...
- EGL接口介绍-----Android OpenGL ES底层开发
引自:http://www.cnitblog.com/zouzheng/archive/2011/05/30/74326.html EGL 是 OpenGL ES 和底层 Native 平台视窗系统之 ...
- EGL接口介绍(转)
http://www.cnitblog.com/zouzheng/archive/2011/05/30/74326.html EGL 是 OpenGL ES 和底层 Native 平台视窗系统之间的接 ...
- 初始化Direct3D
一.Direct3D概述 DirectX是微软公司开发的一套功能丰富的底层API,其功能涵盖了: 2D/3D图形加速的支持. 各种输入设备的控制. ...
- 从I4GL迁移到EGL
作者:金发华 Informix的I4GL一度非常流行,现今在很多行业中依然有许多I4GL的应用,但是I4GL在很长时间内没有做版本升级.不过好消息是IBM推出了EGL(Enterprise Gener ...
- DirectX11 With Windows SDK--08 Direct2D与Direct3D互操作性以及利用DWrite显示文字
前言 注意:从这一章起到后面的所有项目无一例外都利用了Direct2D与Direct3D互操作性,但系统要求为Win10, Win8.x 或 Win7 SP1且安装了KB2670838补丁以支持Dir ...
- Android OpenGL ES 学习(十) – GLSurfaceView 源码解析GL线程以及自定义 EGL
OpenGL 学习教程 Android OpenGL ES 学习(一) – 基本概念 Android OpenGL ES 学习(二) – 图形渲染管线和GLSL Android OpenGL ES 学 ...
最新文章
- 免除重装系统的烦恼,为SSD做系统移植,并从光驱位SSD启动系统
- 大数据和高并发的解决方案汇总
- C# 多线程读取数据并保存在DataGridView中,如果操作?代码是什么?谢谢
- 【laravel5.4】laravel5.4系列之生成_ide_helper.php文件
- hibernate jpa_JPA /Hibernate刷新策略初学者指南
- 现代软件工程 第十一章 【软件设计与实现】 练习与讨论
- Google 发布最新 IDC 能源消耗报告
- Pytest之重运行及生成测试报告
- 马斯克宣布退出OpenAI,全身心投入特斯拉与SpaceX
- 黄聪:Linq初级班 Linq To XML体验(编程篇)
- 3dmax加载las数据
- 绘制折线图分析股票涨跌
- 通过frp穿透实现rdp远程电脑桌面
- win10浏览器闪退_win10 ie浏览器闪退
- html 导出 word 调整页边距
- 一年外包经验入职字节
- 使用echarts加载地图
- 生物信息百Jia软件(七):glimmer
- PMP备考错题集-强化习题二
- idea debug 第二次进不去断点问题