关于Quake引擎,有很多好的文献:书籍,互联网上的无数文章,博客和Wiki。 其中,我最喜欢的是Michael Abrash于1997年出版
的《图形编程黑皮书》和David L.Crddock(2018)出版的《
Rocket Jump:Quake and First-Person Shooters的黄金时代》 。
不幸的是,您几乎找不到有关1996年左右开发的设备的信息,这使得改进3D渲染,尤其是革命性的游戏ID软件的图形成为可能。 这些芯片的体系结构和设计中包含Rendition V1000和3dfx Interactive Voodoo之间的技术对决历史。
在1996年12月上旬发布vQuake之后,Rendition似乎已经接管了。 V1000是一种能够通过硬件加速启动Quake的快速卡,据开发人员称,该卡提供25兆像素/秒的填充率
[1] 。 在圣诞节即将来临之前,Rendition占领了市场,使玩家能够以高分辨率,帧频和16位彩色
[2]推出游戏。 但是,正如历史所证明的那样,Vérité1000的设计缺陷对创新型公司来说是致命的。
正确选择时间和杀手级应用
图形加速专用设备的想法并没有突然出现。 早在1954年,美联航就设有用于训练飞行员的飞行模拟器。 该领域最大的厂商,Silicon Graphics,Inc.。 (SGI)出现在1982年,当时提供了功能强大的工作站,例如Indy,O2和Indigo²。 但是,这些机器的价格不允许普通消费者购买(1993 SGI Infinite Reality的价格为100,000美元,相当于2019年的177,262美元)。 在90年代后期出现这种情况的原因是三个因素的综合。
首先,RAM的价格已大大降低。 即使在1995年出现了严重的RAM短缺(主要是因为Microsoft Windows 95建议使用8 MB的内存),但一年以来RAM的价格下降了近90%。 这为具有惊人的巨大帧缓冲区(640x480,具有16位RGB颜色)的卡打开了前景,这些缓冲区可以在本地存储纹理。
其次,提高了RAM性能。 与DRAM相比,FastPage RAM向前迈了一大步,但是在EDO RAM发布之后,延迟减少了30%,对RAM的访问时间为50 ns
[3] 。
难题的第三个也是最后一个是杀手级应用程序。 PC具有功能强大的CPU,例如Intel Pentium,频率为166 MHz,开发人员用来创建高质量的3D游戏。 1996年,每个人都在谈论两个游戏:Core Design的《古墓丽影》和id Software的Quake。
渲染和V1000
Rendition Inc成立于1993年。两年后的1995年,该公司宣布创建V1000体系结构,该体系结构很快得到了四个OEM的许可。 Creative Labs 3D Blaster PCI,Sierra Screamin'3D,Canopus Total 3D和Intergraph Reactor最早出现在市场上,不久MiRO接手了。
鹰图反应堆。 图片来自vgamuseum.ru。Creative Labs 3D Blaster。 “复古图形卡”俱乐部的图像。注意,第一个V1000-E芯片后来被功耗更低,速度提高20%的V1000L-P所取代
[4] 。
MiroCrystal VRX。 图片来自vgamuseum.info。Canopus Total3D。 图片来自vgamuseum.ru。卡的名称已更改,但其中使用的芯片相同。 制造商必须在价格和性能之间取得平衡的唯一参数是RAM卡上安装的质量。
- VGA端口,用于连接CRT显示器。
- Ramdac,通常来自Bt,但有时来自AT&T芯片。
- 卡的核心是V1000-E,V1000-P或v1000-L芯片。
- 八个512 kb DRAM / EDO芯片(总计4兆字节),用于存储帧缓冲区和纹理。
- 包含BIOS的64 kb EEPROM。
V1000具有两个值得注意的固有属性,因为3dfx Voodoo(我将在后面讨论)使用了一种截然不同的方法。
首先,该卡应该是购买者已经安装的卡的替代品。 该芯片支持在VGA中渲染2D和3D,并且由于上下文切换,它具有令人印象深刻的“ 3D in window”模式。 因此,该卡具有单个输出VGA端口。
第二个功能是“大铁”架构,该架构基于可访问所有4个内存字节的单个Mips CPU。 它们之间的64位数据总线没有特殊属性。 这种标准化的设计使使用可引导微代码对卡进行编程变得容易(这在Nvidia提出这个定义之前很久就将卡变成了PC的第一个GPU)。
V1000编程
SDK
[5]带有一组与C语言进行交互的头文件(Windows上的RRedline和DOS上的Speedy3D)。 带纹理的三角形的渲染类似于如今带有手动VRAM的Vulkan所提供的。 该API能够渲染基于角度的纹理三角形,还支持alpha测试,alpha混合和雾化。
#include <string.h> #include <windows.h> #include <redline.h> WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine, int cmdShow){ int WIDTH=640, HEIGHT = 480; HWND hWndMain = ... ; // Setup Verite board and resolution/refresh rate v_handle verite; VL_OpenVerite(hWndMain, &verite); V_SetDisplayType(verite, V_FULLSCREEN_APP); V_SetDisplayMode(verite, WIDTH, HEIGHT, 16, 75); // Copy texture to VRAM bmp_info bmp = loadBMP("data\\rlogo.bmp"); v_memory memObj = V_AllocLockedMem(verite, bmp.linebytes*bmp.height); memcpy(V_GetMemoryObjectAddress(memObj), bmp.addr, bmp.linebytes*bmp.height); v_surface *display, *texture; VL_CreateSurface(verite, &display, V_SURFACE_PRIMARY, 2, V_PIXFMT_565, WIDTH, HEIGHT); VL_CreateSurface(verite, &texture, 0, 1, V_PIXFMT_565, bmp.width, bmp.height); v_cmdbuffer cmdbuffer = V_CreateCmdBuffer(verite, 0, 0); VL_LoadBuffer(&cmdbuffer, texture, 0, bmp.linebytes, bmp.width, bmp.height, memObj, 0); VL_InstallDstBuffer(&cmdbuffer, display); VL_InstallTextureMap(&cmdbuffer, texture); VL_SetSrcFunc(&cmdbuffer, V_SRCFUNC_REPLACE) // Clear screen to black VL_FillBuffer(&cmdbuffer, display, 1, 0, 0, display->width, display->height,0); // Populate cmd with triangle coo and textCoo v_kaxyzuvq vertex[3] = ... ; VL_Triangle(&cmdbuffer, V_FIFO_KAXYZUVQ, &vertex[0], &vertex[1], &vertex[2]); V_IssueCmdBuffer(verite, cmdbuffer); VL_SwapDisplaySurface(&cmdbuffer, display); }
RRedline将128 KB的微代码加载到Vérité中,并将C调用转换为V1000汇编器函数调用。
一个有趣的事实: API
的名称“ RRedline”胜过“ Rendition Ready”,很可能是集体选择的。 但是,名称Speedy3D是Walt Donovan的想法。
实际上,v1000只是一个慢速的CPU(25 MHz),具有32 * 32单周期乘法(占芯片的很大一部分!),用于计算近似反值的单周期指令(即两周期近似整数除法)以及通常的RISC指令集。 哦,还有“双线性加载”指令,它读取2x2线性存储块,并根据传递给指令的u和v的分数值执行双线性滤波。 地图上似乎只有一个很小的缓存,只有4个像素。 因此,如果出现了一个完全匹配的2x2块,我们将减少内存带宽的负载。
Z缓冲区没有硬件支持。 因此,在v1000中运行的软件必须读取Z,进行比较,然后决定是否写入。
-Walt Donovan(算法设计师)
为了向卡发送纹理和微码,驱动程序使用DMA通过PCI传输数据,而无需CPU干预。 实际上,许多主板没有正确的总线控制,因此游戏必须返回PCI FIFO模式,这会对性能产生负面影响
[6] 。 在卡内部,所有操作均以32位定点整数执行。
开发人员认为Rendition将是完全可编程的,但没有使用任何智能管道或快速同步。 因此,如果需要25条指令来记录一个像素,那么我们只能得到1兆像素/秒。 如果使用功能固定的设备,则可以创建相当于这25条指令的传送带,并达到25兆像素/秒。 3dfx员工来自SGI,因此他们选择了正确的方法-创建一个具有固定功能和OpenGL功能子集的三角形处理引擎,用于设备管理。 V1000开发人员拥有完全不同的体验,他们不了解OpenGL,因此决定创建一个CPU更正确。
-Walt Donovan(算法设计师)
除了所有这些功能之外,该卡还具有创新的抗混叠系统,具有令人讨厌的副作用。
vQuake中使用的抗锯齿算法已获得专利(专利号6005580)。 关于这个算法有一个有趣的笑话。 它仅适用于三角形,不适用于间隔。 Quake使用了“完美的z缓冲”的概念,其中将图形划分为间隔,并使用BSP / PVS(二进制空间分区/一组潜在的可见元素)进行可视排序。 因此,引擎创建了一组间隔,这些间隔理想地覆盖了屏幕,而没有覆盖和像素丢失,并且为了进行渲染,需要在显示内存中执行一次写操作(没有z缓冲!)。 但是,这些间隔的初始数据是三角形。 抗锯齿算法会寻找轮廓的边缘并将其平滑。 (有关此想法的更多信息,请参见humus.name,从2011年3月开始的几何后处理抗锯齿条目-作者再次发明了这项技术!)但是由于抗锯齿是在渲染屏幕之后执行的(所有间隔都已绘制),因此概念算法显然有没有肋骨。 他还是画了它。 (如果使用z缓冲区,则仅重绘可见边缘!)实际上,这不是什么大问题,因为BSP通常会很好地切掉不可见的三角形。
但是角色模型不行! 因此,vquake允许玩家看到隐藏在门和墙壁后面的人,从而在纹理中产生微小的移动失真!
-Walt Donovan(算法设计师)
vQuake
在发行卡片时,他们支持一些出色的游戏。 是的,Descent II,大奖赛传奇,IndyCar Racing II,Myst,Nascar Racing,EF2000和Tomb Raider都是不错的游戏,但Quake是真正的钻石,是要求最高和促销最成功的钻石。 游戏ID Software于1996年12月2日发行了自己的Vérité端口,称为vQuake。 它是由Vérité的Walt Donovan和Stefan Share与id Abrash Michael合作编写的。
这项工作非常艰苦,但是港口运作良好。 奔腾166Mhz能够以每秒26帧的速度以320x200的分辨率渲染Quake,通过双线性过滤可以跳至640x480,仍然以每秒22帧的速度渲染
[8] 。 在实践中,玩家选择了512x384的分辨率,看起来很漂亮,并且可以在P166上每秒提供32帧。 短时间内,vQuake无疑是玩Quake的最佳方式。
软件渲染VéritéV1000非常感谢来自vogons.org论坛的用户@swaaye,他们提供了V1000和Fruit Of Dojo的屏幕截图,这些屏幕截图是MacOSX上高质量且易于破解的Quake端口[9] 。软件渲染VéritéV1000Z缓冲区缺陷
V1000缺乏(间接地是其后继产品V2200)是z缓冲区的硬件加速。 开发人员进行深度测试后,填充率下降到12.5兆像素/秒,帧速率减半。 正如Stefan Podell随后解释的
[10] ,vQuake(和所有其他游戏)以最小化z缓冲区读取的方式移植到V1000。
开发人员发现,确保必要速度的唯一方法是将工作的主要部分转移到CPU。 对于vQuake,这意味着该地图将用作始终写入z缓冲区的超快速水平间隔渲染器,但仅在渲染敌人时才读取和比较z。 尽管开发人员设法创造出了不错的产品,但是这种架构选择的后果却徘徊了很长时间。
3dfx拖放渲染
id Software在1997年1月22日发布了GLQuake。 它基于miniGL(OpenGL 1.0标准的子集,其中缺少GL_LIGHT和GL_FOG)实现。 该二进制文件为所有硬件加速的PC卡打开了大门。 在这方面,3dfx Interactive的Voodoo卡特别出色,其惊人的性能(在512x384分辨率下为41fps,在P166上为16位彩色
[11] )已成为3D加速器的事实上的标准。 V1000的填充速度为25兆像素/秒,曾经可以与奔腾的软件渲染相提并论,现在在Voodoo卡的50兆像素/秒的背景下显得平庸,甚至没有受到z测试的影响。
Rendition响应是更强大的V2x00,这自相矛盾地使情况恶化了。 公告称,由于有了硬件z缓冲区,V2x00的速度提高了两倍,但是,即使在vQuake中,它也无法提高帧速率。 这种异常破坏了客户的信心,并对vQuake开发人员Stefan Sharele产生了负面影响,他认为他需要解释为什么vQuake的性能受到CPU而非GPU的限制
[12] 。
……事实证明,我的声誉受VQuake和VHexen2在V2x00上无法更快运行的事实的影响,所以我必须解释为什么会这样。
[...]
Walt和Michael决定,由于Verite 1000在使用Z缓冲的像素中表现不佳,因此让Pentium进行这种间隔排序将减少Verite需要绘制的像素数量。 此外,我们可以在Verite中禁用Z比较功能。
[...]
...无论使用Verite芯片如何,CPU都需要大量工作。
-Stefan Podell
此外,硬件体系结构中存在重大问题,最初导致
[13] V2x00失败。 解决这个问题花了几个月的时间,甚至在那之后,该板仍然以50 MHz的频率工作,而NVidia NV3和Voodoo2已经达到100 MHz。
基于V3300的第三代产品可以改变历史进程,但它来得太迟了。 在Rendition被美光科技收购之后,该项目于1998年被取消。
在Rendition工作时,我们犯了很多错误。 如果我们自己开发方案而不转移到工厂,则有可能在几个月前发布v1000(在这几个月中没有竞争对手)。 另外,芯片的质量控制引起了疑问。 我们公司的一个人花了几个月的时间以V1000汇编语言实施mpeg解压缩,但由于无法预测的芯片错误而无法使其正常工作。
vQuake运作良好只是因为v1000并没有做很多工作。 “渲染间隔列表”,“平滑边缘”-这几乎是他所做的一切。 我和Mike Abrash花了太多时间使Quake与V1000兼容,因此该型号不适合长期使用。
-Walt Donovan(算法设计师)
在Rendition崩溃后,3dfx加倍努力推广Voodoo2,其出色的特性使所有竞争对手都扫地出门。 PC上的3D图形之王已经统治了市场一段时间。 然后游戏继续进行,新的竞争者出现在现场,其中包括加拿大的ATI和当时几乎不为人知的Nvidia公司。
参考文献
[1]来源:
VGA博物馆,V1000的Texel填充率(MTexel / s)报告为25[2]资料来源:
约翰·卡马克(John Carmack)。plan,1996年8月22日“在512 * 384倍,几乎快了一倍”[3]资料来源:
3dfx VOODOO1参考修订版。 1.0[4]资料来源:
V1000的评论[5]来源:
Rendition Verite V1000 SDK[6]资料来源:
由于DMA错误而导致的PCI总线不成熟[7]来源:
RRedline编程指南[8]资料来源:
比较RéitionVéritéV1000-E和V1000L-P的基准[9]来源:
github.com上的MacOSX X Quake端口源代码[10]来源:
Stephan Podell BSS帖子[11]资料来源:
使用Voodoo1比较GLQuake中的帧速率[12]来源:
Stephan Podell BSS帖子[13]资料来源:
Wikipedia.com,“失败”部分