SuperRT – SNES上的实时光线追踪

2020-12-16 02:03:33

我很高兴能为过去大约一年的业余时间里正在从事的项目显示一些结果。

这个想法起源于我试图为一个旨在帮助我学习Verilog和FPGA设计的项目想到一个有趣的想法时,我想到了构建一个简单的raytracer的想法(部分灵感来自于我一个聪明的聪明朋友,他正在构建他的自己的GPU)。过了一会儿-因为有时我的大脑讨厌我,并且高兴地提出一些愚蠢的事情-这变成“尝试让SNES进行射线追踪是否有趣吗?”,因此SuperRT芯片的想法诞生了。

我想尝试做的事情类似于在Star Fox等游戏中使用的Super FX芯片,SNES在其中运行游戏逻辑并将场景描述交给盒中的芯片以生成视觉效果。为此,我故意限制自己仅使用单个定制芯片进行设计,而不使用DE10板上可用的ARM内核或任何其他外部处理资源。

遗憾的是,由于屏幕截图质量差而致歉-出于某种原因,从我的SNES进行捕获时,我的捕获卡会产生可怕的结果,因此我不得不求助于旧的“在暗室中拍摄屏幕”的方法。

此处看到的超级任天堂(从技术上讲是超级家族)已将机箱移开,以便为电缆腾出空间,但除此之外,它完全没有修改。上面附有一张糟糕的Pachinko游戏副本的PCB,我在当地一家二手商店以100日元的价格购买了该游戏,删除了游戏ROM,并用电缆接头代替了该游戏。然后,它通过一组电平转换器将SNES的5v转换为3.3v,然后转换为带有Cyclone V FPGA的DE10-Nano FPGA开发板。电平转换器板绝不是什么漂亮的东西-组装它们是一场噩梦,这归功于仅表面贴装封装中提供了必要的IC-但它们确实可以完成工作。

SuperRT芯片使用专门的命令语言来构建场景,该命令语言由芯片上的三个并行执行单元之一(本质上是专门的CISC处理器)执行,以执行射线相交测试。场景描述允许使用CSG操作的子集来构造对象,使用球体和平面作为基本构建块,然后使用它们执行“或”,“与”和减法运算以构建所需的几何形状。还支持AABB,尽管它主要用于剔除测试(如果需要,可以渲染它们,但是它们的位置精度比其他基元低,因此,除调试目的外,这通常不是很有用)。

渲染器每个屏幕像素最多投射四束光线,从而计算来自定向光源的直接阴影和单次反射反弹。每个表面都具有漫反射的颜色和反射特性,可以根据CSG结果或特殊功能对这些表面应用修改器-用于在地板上生成棋盘格图案。

每个像素的射线颜色由“射线引擎”计算,“射线引擎”处理整个射线生命周期,并使用“执行引擎”模块运行描述场景的命令程序,以解决射线所需的次数。命令程序本身是从SNES上载并存储在本地4K RAM缓冲区中的-通过根据需要将修改后的命令写入此缓冲区来执行动画。反汇编的命令缓冲区如下所示:

0000起始0001平面0,-1,0,Dist = -20002 SphereSub OH 2,1,5,Rad = 50003 SphereSub OH 4,1,4,Rad = 40004 SphereSub OH 5,1,9,Rad = 90005 SphereSub OH 2 ,1、2,Rad = 20006 SphereSub OH -0.5、1、2,Rad = 20007 RegisterHitNoReset 0、248、0,反射率= 00008棋盘ORH 48、152、48,反射率= 00009 ResetHitState0010平面0,-1、0, Dist = -2.1501460011 RegisterHit 0、0、248,反射率1530012 AABB 4,-2.5、11、8、3.5、130013 ResetHitStateAndJump NH 440014 Origin 6,2,120015 Plane -0.2929688,0,-0.9570313,Dist = 0.24975590016 PlaneAnd OH 0.2919922,0,0.9560547,Dist = 0.250017 PlaneAnd OH 0,1,0,Dist = 10018 PlaneAnd OH 0,-1,0,Dist = 40019 PlaneAnd OH -0.9570313,0,0.2919922,Dist = -10020 PlaneAnd OH 0.9560547,0 ,-0.2929688,Dist = 1.4997560021 RegisterHit 248,0,0,Reflectivity = 0

每个执行引擎都是具有14个循环流水线的处理器模块,通常每个循环仅退回一条指令,因此每个执行单元每秒可计算约5000万个球,平面或AABB交点。唯一的例外是分支操作必须刷新整个流水线,因此有16个周期的开销(刷新流水线的14个周期+ 2个周期的指令提取延迟)。为了尽量避免这种情况,使用了分支预测系统-幸运的是,很多时候附近光线的空间相干性意味着可以实现较高的预测命中率。

执行引擎中的交叉由两条管道执行,一条处理AABB,另一条处理球体和平面。整个系统专门使用18.14定点格式的32位整数数学,使用16位(2.14)格式,其中值已知在+ -1范围内,并且球体/平面相交管线有两个专用的附加数学单元,用于计算倒数和平方根运算。

渲染完帧后,PPU转换器模块将帧缓冲区转换为可以直接通过DMA直接传输到SNES VRAM进行显示的格式,将其减少为256色,然后将其转换为字符图块位平面。屏幕分辨率为200x160-整个帧的结果为正好32000字节的图像数据,由于带宽限制,该图像数据在连续的帧中以两个16000字节的块传输到VRAM。因此,整个图像只能每两帧刷新一次,从而有效地将最大帧速率限制为30FPS-尽管测试场景的运行速度接近20FPS(主要是由于目前SNES方面的逻辑存在瓶颈)。

非常感谢SNESdev中此线程的参与者,他们对全屏扩展芯片DMA提出了许多有用的想法,这些想法启发了此处使用的解决方案。

该芯片还实现了许多其他基本功能-有一个SNES盒式总线接口,以及一个小程序ROM,其中包含用于SNES的32K代码(这受以下事实的限制:接口板当前仅连接SNES地址总线A线,因此有效的可用地址空间仅为64K,其中32K用于内存映射的IO寄存器以与SuperRT芯片进行通信)。还有一个乘法加速器单元,可让SNES快速执行16x16bit乘法运算。

为了进行调试,我使用了DE10板上的HDMI接口将数据输出到第二个监视器,以及连接到GPIO引脚的Megadrive游戏手柄来操纵调试系统。 资源限制意味着,如果启用了所有三个射线引擎核心,则必须禁用此功能。 因此,这是该系统的广泛概述-我打算发表一些文章,详细介绍各个组件在不久的将来如何工作。 同时,如果您有任何疑问或想法,请与我们取得联系,我们将竭尽所能! 非常感谢Matt,Jaymin,Rick以及其他提供建议,灵感和支持的人! “ SNES”和“ Super Nintendo”是Nintendo Co Ltd的商标。这是一个业余项目,与Nintendo完全无关。