使用OpenGL / Direct3D编写像素操纵密集型应用程序的最佳方法

最近,我一直在做一些类似于老式Wolfenstein 3D,Doom和Build引擎的小型实验,其中3D渲染完全是用软件完成的,因此您需要完全访问像素级的屏幕缓冲区。

在DOS的时代,在我们拥有当前的GPU之前,获取曲面来绘制像素是相对直接的。 你必须devise最快的方式来做你的计算和更新framebuffer的最快方法。 实际上,通过使用像SDL这样的库仍然是可能的,当您在像素级别上操作表面时,仍然可以提供合理的速度。

所以我想知道哪种处理象素密集型应用程序的最好方法,就像我建议的使用当前GPU的应用程序,使用OpenGL或Direct3D。

我明白这听起来很荒唐,但我一直在寻找API文档,似乎这是一个function,我们在目前的硬件有些失落。 我看到使用glDrawPixels或使用像素着色器的建议,但没有可以帮助我做出正确决定的可靠解释或理论。

我知道你不知所措 我还喜欢在年轻的时候破解像素,并且在计算器设备上做了一些游戏,或者用dos的方式做这个游戏。

这仍然可以在今天完成,但是,由于各种硬件的发展历史,它已经变得更加涉及。

CPU像素推动

值得注意的是,我们仍然可以一个一个地推像素,但是它会非常慢,因为前缓冲是当今非常遥远的记忆。 在目前的PC体系结构中,由于硬件原因,我们不能只写入某个内存区域并显示像素。 我们有双重缓冲,我们有写入组合缓冲区,我们有芯片之间的同步问题,我们有总线频率和宽度问题,司机介入…

现在你需要做的事情就是接受这个事实或者硬件的生命,并且在你的进程的一般堆内存中绘制你自己的个人表面,使它成为一个新的纹理,并将其上传到显卡。 这是如何电影播放作品,它运作得很好。

如果你使用OpenGL 3+核心,或者Direct3D 10+,你将被迫使用硬件开发技术,这意味着,写入结合安全和可管理。
它采取多重缓冲的forms,将RAM中的表面复制到某个特定VRAM位置上的“共享”表面,CPU可以locking该位置以访问当前或前一帧的GPU( D3D10_USAGE_DYNAMIC )渲染而不影响渲染( glMap/glUnmap )。 在下一帧中,希望数据副本完成,并且GPU将刷新新的帧命令缓冲区,其中将包含将共享区域复制到硬区以便用作纹理的d3dcontext::CopyResourced3dcontext::CopyResourceglCopyTexSubImage2D )。 其中,纹理单元将在GPU上stream入屏幕四边形(像素着色器中的tex2d )。

一些链接要仔细考虑: http : //eatplayhate.me/2013/09/29/d3d11-texture-update-costs/ 。

这是你如何创建一个纹理stream传输管道,不占用太多的资源,你的CPU能力可以用来推动像素。 实际上它会受RAM总线速度的限制,现在大约是20/30 GiB / s,所以你可以推动4k * 3k的分辨率在670 FPS左右。

有关于如何优化软件渲染器的创建,特别是光栅器,其迷人的精彩文章。 随着扫描线技术和视角矫正问题的历史(分割是一个缓慢的硬件操作,仍然在一定程度上)。 在阅读完所有内容后,您将成为一名更好的graphics工程师: https : //fgiesen.wordpress.com/2013/02/17/optimizing-sw-occlusion-culling-index/
那个男人是来自Farbrausch的大个子Fabian Giesen。

GPU像素拉动

你可以在这里应用的第二个范例是完全忘记了Amiga500绘制东西的方式,并且使用GPU来实现它们的全部处理能力,并将所有东西都编码为像素着色器的一部分。 如果你不使用无序访问写入,你将被迫进入“并行聚集”的集体操作模式。 ( MPI术语)

这是一个非常强大的范例,因为它不依赖于邻居,这意味着硬件可以是并行的,并且可以自由地将单元安排到像素上。 (当然在深入的时候有一些devise的细节(比如使用ddx ddy进行的片段间的近似交stream),但是基本上你会得到一个mainfunction,你可以决定给你的像素的颜色,但是你不会决定在哪里写这个像素,它有固定的坐标,所以你要收集你周围的数据来决定这个颜色,相反,你不能做一个迭代的Bresenhamalgorithm,而是画一条线,你必须确定你的像素是否在线,写入黑色是的,如果没有,就discard 。)

这有它的限制,但它是一个快乐的沙场上游乐园。 我建议 :)

计算

最后,您可以使用compute,在computeland中,您可以使用GPU作为多核CPU,并在您想要的地方编写代码,以互锁操作为代价,如果没有并发计算方面的严重经验,这将变得非常难以理解。 这就是为什么先着色是逐步习惯的好主意。

与着色器相比,您将获得的自由度可以访问未经过滤的内存,并且可以在低级别访问更多的硬件控制。 你把数据,寄存器,单位,全球…

我也是从像素打击的背景。 PEEK和POKE的人?

使用GPU是完全不同的思维模式。 (嗯,它仍然是代码,所以只是“更多相同的…)

GPU在某些方面真的很棒:处理单个像素(通过纹理和片段着色器),并用像素填充三角形。

需要很大的努力(在程序员的一部分)来建立事情。 大部分代码都涉及创建缓冲区和纹理以发送到GPU。

一个简单的开始步骤将是继续绘制像素,并将其作为一个大的带纹理的矩形推向GPU,或者更确切地说是两个三角形。

在围绕片段着色器(推送单个像素)和顶点着色器(在屏幕上围绕math转换三角形)的过程中,您将会看到将一些渲染工作转移到这些着色器中的机会。

开放GL有很多示例代码; 这里有一套教程:

http://www.opengl-tutorial.org

要通过OpenGL在屏幕上获得第一个矩形像素,您将使用“绘制三角形”和“绘制纹理立方体”的组合。

OpenGL有一个很长的跑道,但是一旦你在空中飞行,它是非常有趣和强大的。

希望有所帮助!