跨越OpenGL和D3D的鸿沟(三):交集?并集?
转载请注明出处为KlayGE游戏引擎,本文地址为http://www.klayge.org/2011/07/20/%e8%b7%a8%e8%b6%8aopengl%e5%92%8cd3d%e7%9a%84%e9%b8%bf%e6%b2%9f%ef%bc%88%e4%b8%89%ef%bc%89%ef%bc%9a%e4%ba%a4%e9%9b%86%ef%bc%9f%e5%b9%b6%e9%9b%86%ef%bc%9f/
上一篇讲到了如何填平OpenGL和D3D之间一些原本被认为位于底层的区别。本篇将剖析两个API在功能上的异同,以及直接相互访问的可能性。
功能
D3D9的功能早已被OpenGL 2.0所覆盖,网上可以找到很多资料,这里就不提了。本文注重的是新的GPU特性。下表列出了D3D10+的新功能,以及实现该功能所需要的OpenGL扩展或核心。
D3D 10的功能 | OpenGL所对应的 |
---|---|
Geomrtry shader | GL_ARB_geometry_shader4或OpenGL 3 |
Stream output | GL_EXT_transform_feedback或OpenGL 3 |
State对象 | 无,需要在上层封装GL_EXT_direct_state_access |
Constant buffer | GL_ARB_uniform_buffer_object或OpenGL 3 |
Texture array和新的资源格式 | GL_EXT_texture_array +GL_ARB_texture_compression_rgtc +GL_ARB_texture_rg +GL_ARB_texture_rgb10_a2ui +GL_EXT_texture_integer或OpenGL 3 |
texture和sampler解偶 | GL_ARB_sampler_objects或OpenGL 3 |
在shader里进行整数和位操作 | GL_ARB_shader_bit_encoding或OpenGL 3 |
Multisampled alpha-to-coverage | GL_NV_multisample_coverage或OpenGL 3 |
D3D 10.1的功能 | OpenGL所对应的 |
读取multisample depth/stencil纹理 | GL_ARB_texture_multisample或OpenGL 3 |
Cubemap array | GL_ARB_texture_cube_map_array或OpenGL 4 |
gather4 | GL_ARB_texture_gather或OpenGL 4 |
D3D 11的功能 | OpenGL所对应的 |
Compute Shader | GL_ARB_cl_event + OpenCL |
Dynamic Shader Linkage | GL_ARB_gpu_shader5或OpenGL 4 |
Multithreading | 无 |
Tessellation | GL_ARB_tessellation_shader或OpenGL 4 |
这些都是DX SDK文档里提到的功能,其他一些比较小的功能,也可以很容易找到OpenGL的对应。从上表可以看出,几乎所有D3D的功能都可以直接用相应的OpenGL功能代替,同时没有性能损失。需要重点讨论的是一些例外:
State对象
D3D 10新增了State对象,可以极大地减少由于改变渲染状态所需的系统调用次数。OpenGL中目前还没有State对象,所以只能在上层自行封装。虽然 有些 性能损失,但接口可以和D3D统一起来。ARB针对OpenGL的State对象进行过旷日持久的讨论,还最终各大厂商没有达成一致。不过这是个趋势,相 信不久的将来就会出个相关的扩展。到时候这个区别就能被完美地填平。
Compute Shader
D3D 11引入了compute shader,在D3D中直接提供了GPGPU的能力。OpenGL没有因此增加一种shader,而是增强和同门师弟OpenCL的互操作能力。 OpenGL和OpenCL能直接共享texture和buffer等,起到了和compute shader等价的功能。与GLSL和HLSL的关系一样,这里存在着shader语言不同的问题,而且没有Cg可以作为桥梁,目前只能写两份代码。
Multithreading
D3D 11的multithreading能力允许多个context都调用D3D11 API,每个context保存下来的API调用流可以在主context执行依次执行。OpenGL目前也没有引入该机制,需要在上层自行实现。话说回 来了,目前的所有显卡 驱动都没有实现multithreading,所以所有多context都是由D3D runtime软件实现的,没有达到应有的提速效果。自己实现一个command list也能达到那样的性能。仍然希望某一天multithreading能成为OpenGL的功能 之一,简化上层的工作。
总结
所以说,OpenGL和D3D功能的交集几乎就是它们的并集,并不会因为需要兼容两者而失去很多功能。从功能上说,OpenGL和D3D之间的分歧甚至小于OpenGL和OpenGL ES。破解了第一篇说的流言4。
互操作
神奇扩展WGL_NV_DX_interop的 出现,使得OpenGL可以正式与D3D进行互操作。(严格来说,互操作能力源自它的前身WGL_NVX_DX_interop,但鉴于他是个NVX实验 性质的扩展,最好小心点用。)该扩展的目的是,在D3D中建立资源,而在 OpenGL中访问它。目前可以支持的是D3D9的纹理、render target和VB的读写。D3D10+的支持将在未来加入。两个API之间所需的同步也是自动完成的。
使用WGL_NV_DX_interop进行相互渲染的范例如下:
d3d->CreateDevice(..., &d3dDevice);
d3dDevice->CreateRenderTarget(width, height, D3DFMT_A8R8G8B8,
D3DMULTISAMPLE_4_SAMPLES, 0,
FALSE, &dxColorBuffer, NULL);
d3dDevice->CreateDepthStencilSurface(width, height, D3DFMT_D24S8,
D3DMULTISAMPLE_4_SAMPLES, 0,
FALSE, &dxDepthBuffer, NULL);
// 把D3D设备注册给OpenGL
HANDLE gl_handleD3D = wglDXOpenDeviceNV(d3dDevice);
// 把D3Drender target注册成OpenGL纹理对象
GLuint names[2];
HANDLE handles[2];
handles[0] = wglDXRegisterObjectNV(gl_handleD3D, dxColorBuffer,
names[0], GL_TEXTURE_2D_MULTISAMPLE, WGL_ACCESS_READ_WRITE_NV);
handles[1] = wglDXRegisterObjectNV(gl_handleD3D, dxDepthBuffer,
names[0], GL_TEXTURE_2D_MULTISAMPLE, WGL_ACCESS_READ_WRITE_NV);
// 现在纹理就可以当成普通的OpenGL纹理来用了
// D3D和OpenGL渲到同一个render target
direct3d_render_pass(); // 和平常一样进行D3D渲染
// 锁定render target,交给OpenGL
wglDXLockObjectsNV(handleD3D, 2, handles);
opengl_render_pass(); // 和平常一样进行OpenGL渲染
wglDXUnlockObjectsNV(handleD3D, 2, handles);
direct3d_swap_buffers(); // D3D present
这样两个API可以和谐共处了,但这个扩展目前仅限于NV的卡。
本篇讨论了两个API在功能上的交集和并集,以及互操作的方法。下一篇是本系列的结局,将讨论一些平台相关的问题,并进行系统性的总结。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库