- 1993년 고성능 PC급인 IBM PS/1 486-DX2 66MHz에서 원본 DOOM은
demo1기준 21.5fps였고, fastDOOM은 같은 조건에서 30.1fps까지 올라 DOS 포트 최적화의 차이를 보여줌 - fastDOOM은 Linux DOOM 코어, Heretic I/O, APODMX,
DOOM.EXE역어셈블 기반 Mode Y 그래픽 I/O를 조합한 PCDOOM v2에서 출발함 - 52개 릴리스와 3,042개 커밋을 빌드·벤치마크한 결과, 성능 향상은 현대 컴파일러 하나가 아니라 작은 최적화의 누적에서 나왔음
- 큰 폭의 개선에는 상태 표시줄 렌더링 생략,
FixedDiv인라인화, BSP 순회 최적화, visplane 렌더링 생략, 포인터 간접 참조 제거, 렌더러별 실행 파일 분리가 포함됨 - 그래픽 모드는 CPU와 버스에 따라 유불리가 갈리며, 느린 CPU에서는 Mode Y가 유리하고 빠른 CPU·VLB/PCI 환경에서는 Mode 13h나 VESA direct가 나을 수 있지만 VESA 2.0 같은 제약이 남음
486-DX2에서 드러난 성능 차이
- IBM PS/1 486-DX2 66MHz “Mini-Tower” 모델 2168에서 원본 DOOM을
doom.exe -timedemo demo1로 실행하면1710 gametics in 2783 realtics가 나옴- DOOM은 fps를 직접 출력하지 않아
1710/2783*35로 계산해야 하며, 결과는 21.5fps임
- DOOM은 fps를 직접 출력하지 않아
- 같은 머신에서
fdoom.exe -timedemo demo1을 실행하면1710 gametics in 1988 realtics, 30.1fps가 확인됨 doom2의demo1처럼 더 무거운 맵에서는 원본 16.8fps에서 fastDOOM 24.9fps로 올라 48% 빨라짐- 다만 joystick과 network gameplay 지원은 제거되어, 모든 기능을 그대로 보존한 포트는 아님
fastDOOM이 나온 코드 계보
- DOOM은 원래 NeXT Workstation에서 개발됐고, 대부분의 코어 코드와 작은 I/O 하위 시스템으로 나뉘어 포팅하기 쉬운 구조를 가졌음
- 상용 DOS 버전은 id Software가 작성한 DOS I/O를 사용했지만, proprietary sound library인 DMX 의존성 때문에 1997년에 그대로 오픈소스화될 수 없었음
- 공개된 코드는 Bernd Kreimeier가 엔진 설명용 책 프로젝트를 진행하며 정리한 Linux 버전임
- DOS 버전 PCDOOM v2는 다음 조합으로 재구성됨
- Linux DOOM의 코어
- Heretic의 I/O
- DMX를 흉내 내기 위한 APODMX
DOOM.EXE역어셈블에서 역공학한i_ibm.c그래픽 I/O
- fastDOOM은 이 PCDOOM v2를 출발점으로 삼음
릴리스와 커밋으로 추적한 성능 변화
- Victor “Viti95” Nieto는 fastDOOM을 자주 릴리스하고 각 릴리스에 태그를 붙였으며, 하나의 커밋이 하나의 일을 하도록 관리함
- fastDOOM의 Git 이력은 3,042개 커밋으로 구성되어 커밋별 성능 변화를 추적할 수 있었음
- 52개 fastDOOM 릴리스, PCDOOM v2, 원본
DOOM.EXE를 내려받아-timedemo demo1을 실행하는RUN.BAT을 Go 프로그램으로 생성하고, mTCPNETDRIVE로 마운트해 테스트함- 조건은
DOOM.WAD, sound on, screen size 10임 - 전체 스위트를 5번 실행해 평균 fps를 그래프로 그림
- 조건은
- PCDOOM v2는 OpenWatcom 2로 빌드됐는데도 원본
DOOM.EXE대비 개선 폭이 크지 않아, fastDOOM의 향상은 현대 컴파일러 사용만으로 설명하기 어려움 - 파일 크기 그래프에서는 초기 작업이 코드 정리와 삭제를 통해 더 가볍게 만드는 방향이었음
성능을 끌어올린 릴리스별 변경
- 전체 3,042개 빌드를 모두 timedemo하면 약 9일이 걸릴 수 있어, 속도 향상이 컸던
v0.1,v0.6,v0.8,v0.9.2,v0.9.7을 중심으로 커밋 단위 벤치마크가 진행됨 -
fastDOOM v0.1
v0.1은 220개 커밋으로 구성됨- 가장 큰 패치는 build 36의 e16bab8임
- “Crispy optimization”은 상태 표시줄 퍼센트가 바뀌지 않았을 때 렌더링을 no-op으로 만들어 scrap buffer 렌더링과 화면 blit을 피함
- 이 변경 하나로 2fps 상승이 확인됨
- build 167의 a9359d5는
FixedDiv를 매크로로 인라인화함 - build 207의 9bd3f20는 PSX Doom 최적화를 가져와 BSP 순회 방식을 개선함
- build 212의 dc0f48e는 수평 표면 렌더링 함수
R_MakeSpans를 인라인화함 - 전체 커밋 중 삭제 커밋이 100개로, 약 절반이 코드 삭제였음
-
fastDOOM v0.6
-
fastDOOM v0.8
v0.8은 282개 커밋으로 구성됨- sound system이 불안정해 sound 없이 timedemo를 수행한 뒤 fps를 보정함
- 이 릴리스는 text-mode renderer에 초점이 있었고, build 670과 build 730에서 Crispy optimization이 빠지며 회귀가 발생함
- 주요 개선은 다음과 같음
-
fastDOOM v0.9.2와 v0.9.7
v0.9.2는 110개 커밋이며, skyflatnum 비교 최적화, Mode Y용R_DrawColumn최적화,R_DrawSpan코드 정리가 주요 변경임v0.9.7은 293개 커밋으로 소개됐지만 명령 출력은 294개를 보임- 이 릴리스는 여러 번 벤치마크해도 노이즈를 줄이지 못함
- 주요 변경은 x86 ASM 변경 테스트, 386SX용 CPU 선택과 CR2 최적화,
R_DrawSpan386SX용 ESP 최적화, ASM fuzz column 렌더링 기반 코드, 루프당 CMP 비교 제거 등임
Mode 13h, Mode Y, VESA direct의 선택 기준
- fastDOOM은 386, 486, Pentium, Cyrix와 ISA, VLB, PCI 같은 다양한 CPU·비디오 버스 조합을 대상으로 여러 최적화를 탐색함
- IBM PS/1 486-DX2 66MHz에서는 Mode Y 대신 Mode 13h를 쓰는 최적화가 더 느렸음
-
Mode 13h
- VGA의 네 VRAM bank로 데이터를 분배하는 작업을 하드웨어가 처리해, CPU에는 단일 선형 320x200 framebuffer처럼 보임
- VRAM에서 double buffering을 할 수 없어 RAM에서 버퍼링한 뒤 VRAM으로 다시 복사해야 하므로 바이트를 두 번 씀
- 엔진은 VSYNC에서 block되어야 함
-
Mode Y
- VGA bank를 개별적으로 접근할 수 있어 VRAM triple buffering이 가능하고, 바이트를 VRAM에 한 번만 직접 쓸 수 있음
- bank 선택에는 느린
OUT명령이 필요함 - latch를 통해 두 VGA bank에 동시에 쓰면 수평 픽셀 복제가 가능해 low-detail mode를 얻을 수 있음
- invisible Specter 렌더링은 VRAM readback이 필요해 훨씬 느림
- John Carmack의 설명에서 DOOM은 320×200×256 VGA 모드에서 Mode X와 유사한 interleaved planar mode를 사용했고, 세 개의 display page를 순환함
- video memory에 직접 texture mapping을 하면 많은 비디오 카드에서 10%~15% 추가 속도를 얻을 수 있었음
- main memory buffering보다 tearing 없는 page flip도 가능했음
- Heretic은 1994년에 출시됐고, 당시 하드웨어 변화로 Mode 13h가 더 매력적인 선택이 되어 Raven은 DOOM 엔진을 이 방향으로 수정함
- fastDOOM은 사용자에게 여러 실행 파일을 제공함
FDOOM.EXEFDOOM13H.EXEFDOOMVBD.EXE
-
fastDOOM의 Mode 13h와 VESA direct
- fastDOOM의 Mode 13h는 RAM의 단일 framebuffer에 렌더링한 뒤 장면 전체가 끝나면 VRAM으로 복사함
- VSYNC를 강제하지 않아 flickering이 생길 수 있음
- 느린 8-bit ISA bus에서는 변경된 픽셀만 전송하는 differential copy가 사용됨
- 16-bit ISA, VLB, PCI 등 더 빠른 bus에서는
REP MOVS로 전체 backbuffer를 복사함 - Viti95의 테스트 기준 486 CPU에 가장 좋은 모드는 320×200용 VESA direct mode인
FDOOMVBD.EXE임- Mode Y의 장점과 Heretic의 최적화된 렌더링 코드를 결합함
- 버퍼 전환 시 프레임당 한 번의
OUT을 제외하면OUT명령을 피함 - LFB가 활성화된 VLB 또는 PCI 그래픽 카드와 VESA 2.0 지원이 필요하며, low-detail과 potato-detail mode에서는 느림
- IBM 2168은 VESA 2.0을 지원하지 않아
FDOOMVBP.EXE와FDOOMVBD를 실행하면 오류가 발생함
작동하지 않은 시도와 전체 인상
- OpenWatcom의 프로세서별 플래그인
4r/4s와3r/3s도 시도됐지만 중단됨- wcc386의 386 플래그와 486 플래그가 모두 시도됐고, 결과적으로 386 버전이 항상 더 빨라 보였음
- Viti95는 fastDOOM의 컴파일러를 OpenWatcom v2에서 DJGPP, 즉 GCC로 바꾸는 목표도 갖고 있음
- 같은 소스에서 GCC가 더 빠른 코드를 생성하는 것으로 나타났기 때문임
- 또는 OpenWatcom v2가 성능 격차를 줄이도록 개선되는 것도 바람직한 선택으로 남아 있음
- fastDOOM의 성능은 Crispy, PSX, GBA, Lee Killough의 기존 개선을 활용하고 새 최적화를 대량으로 추가한 결과임
- Ken Silverman의 아이디어와 코드 일부도 UMC Green CPU용 렌더링 함수에 들어가 해당 하드웨어에서 큰 속도 향상을 냄
- fastDOOM은 하나의 마법 같은 변경이 아니라, 수천 개의 작은 최적화가 쌓여 원본 DOOM보다 빠른 DOS 포트가 된 사례임