June 8, 2012

Doom3 Source Code Review: Scripting VM (Part 5 of 6) >>

From idTech1 to idTech3 the only thing that completely changed every time was the scripting system:

idTech4 is no exception, once again everything is different:

A good introduction is to read the Doom3 Scripting SDK notes.

Architecture

Here is the big picture:

Compilation : At loadtime the idCompiler is fed one predetermined.script file. A serie of #include directives will result in a script stack that contains all the scripts string and every functions source code. It is scanned by an idLexer that generates basic tokens. Tokens enter the idParser and one giant bytecode is generated and stored in idProgram singleton: This constitute the Virtual Machine RAM and contains both .text and .data VM segments.


Virtual Machine : At runtime the engine will allocate real CPU time to each idThread (one after an other) until the end of the linked list is reached. Each idThread contains an idInterpreter that saves the state of the Virtual CPU. Unless the interpreter go wild and run for more than 5,000,000 instructions it will not be pre-empted by the CPU: This is collaborative multitasking.

Compiler

The compilation pipeline is similar to what we can find reading any compiler such a V8 from Google or Clang except that there is no preprocessor. Hence functions such as "comment skipping", macro, directive (#include,#if) have to be done in the lexer and the parser.

Since the idLexer is reused all across the engine to parse every text assets (maps, entities, camera path) it is very primitive. As an example it only return five types of tokens:

So the parser actually has to perform much more than in a "standard" compiler pipeline.

At startup the idCompiler load the first script script/doom_main.script, a serie of #include will build a stack of scripts that are combined in one giant one.

The Parser seems to be a standard recursive descent top down parser. The scripting language grammar seems to be LL(1) necessitating 0 backtrack (even though the Lexer has the capability to "unread" up to one token). If you ever got a chance of reading the dragon book you will not be lost...otherwise this is a good reason to get started ;) !

Interpreter

At runtime, events trigger the creation of idThread that are not Operating System threads but Virtual Machine threads. They are given some runtime by the CPU. Each idThread has an idInterpreter that keeps track of the Intruction Pointer and the two stacks (one for the data/parameters and one to keep track of the function calls).

Execution occurs in idInterpreter::Execute until the interpreter relinquish control of the Virtual Machine: This is collaborative multi-tasking.


  idThread::Execute
   bool idInterpreter::Execute(void)
   {
       doneProcessing = false;
       while( !doneProcessing && !threadDying ) 
       {
           instructionPointer++;
       
           st = &gameLocal.program.GetStatement( instructionPointer );
           
           //op is an unsigned short, the VM can have 65,535 opcodes 
           switch( st->op ) {
                   .
                   .
                   .
           }
       }    
   }


Once the idInterpreter relinquish control the next idThread::Execute method is called until no more thread need execution time. The overal architecture reminded me a lot of Another World VM design.

Trivia : The bytecode is never converted to x86 instructions since it was not meant to be heavily used. But in the end too much was done via scripting and Doom3 would probably have benefited immensely from a JIT x86 converted just like Quake3 had.

Recommended readings

Great way to understand more about the virtual machine is to read the classic Compilers: Principles, Techniques, and Tools :




Add a comment



Name Homepage
E-mail
(Will not appear online)
Comment



Comments (75)


#1 - Kel Solaar - 06/09/2012 - 03:31
Awesome and very interesting review! Definitely worth a read!
#2 - Nicolas - 06/09/2012 - 04:29
Hi Fabien,

Very nice article, thanks for sharing your work, I hope you will write a review of id tech 3.
#3 - Rich Jones - 06/09/2012 - 05:07
Excellent! I'm so glad you're doing this for Doom3 - hopefully your insights will help the Doom3 Mod/TC community thrive!
#4 - stef - 06/09/2012 - 05:25
Great article as usually... thanks !!
#5 - Paul - 06/09/2012 - 06:38
I'd to love to read Q3 source review - this game inspired me to start hacking my own little games.
#6 - Hannes - 06/09/2012 - 07:03
Thanks for the analysis and write up.

I cloned repo and tried to find unit and integration tests, but couldn't. Did I miss something?

It's quite amazing that such a big project could be maintained and developed with reasonable velocity without tests.
#7 - Job - 06/09/2012 - 08:21
Nice deconstruction as always!

I found the way Doom 3 did the interfaces on the screens very impressive and immersive - maybe even more than the lighting effects. Can you elaborate a bit on how they did that?)
#8 - Sha - 06/09/2012 - 08:40
Very interesting read!

Of the many forks you mentioned. Can you name some that are actively improving the code and adding features?
#9 - frostyNinja - 06/09/2012 - 09:10
Interesting compilation. Thought I should let you know about a typo:
"...Carmack and we was nice..."
I believe you meant to say "he was nice"

Great article, nonetheless!
#10 - daniel - 06/09/2012 - 11:10
Hi Fabian,
Great read... again!
It is really astonishing that there is one render-pass per light and still run so fluid on 2004 graphics hardware.

Definitely looking forward to a review of idTech3. Besides from the write-up and nice graphics it might be a an "easy" job for you compared to anyone else. With the knowledge of Quake 1 and 2 this will also make it possible to set everything into perspective nicely.

Cheers,
Daniel
#11 - Tom Campbell - 06/09/2012 - 12:24
Love these. Of course I'd be delighted if you did an idTech3 review.
#12 - Shawn - 06/09/2012 - 12:34
A wonderful article!

I've enjoyed your past code reviews so much I've gone back and read them more than once; I'm certain I will read this at least a few times!

I sincerely appreciate the time you took to write this. I hope that you have the time to review iDTech3 as well, especially since it will provide an opportunity to compare and contrast how the codebase has progressed since then.
#13 - Brian Cardarella - 06/09/2012 - 13:13
Awesome, amazingly well done!
#14 - J - 06/09/2012 - 14:30
Vancouver? Cool! Nice views. Thanks for the article.
#15 - Amir Masoud Abdol - 06/09/2012 - 15:31
Such an interesting thing to do :) Thanks for the notes.
#16 - Indloon - 06/09/2012 - 15:50
Please,review the Id Tech 3 engine :)

You ill get a cookie for that ^^
#17 - Los Puerco Lobos - 06/09/2012 - 16:26
I felt the love so hard
#18 - Neil - 06/09/2012 - 16:55
Great article!

Can you explain how the use of statically instantiated instances of system level objects and the use of a pointer to their abstract base classes avoids the usual vtable lookup overhead?
#19 - Will Lam - 06/09/2012 - 18:35
Nice write up! Didn't know you're leaving in Toronto - awesome!
#20 - Gaffer - 06/09/2012 - 19:02
Fantastic work. Thanks!
#21 - Venser - 06/09/2012 - 19:39
Quake 3 please
#22 - Kaiyi Li - 06/10/2012 - 01:38
Fabien, I spotted this on hacker news. You effort in this article is incredible and impressive, very clear and easy to understand. If you remember, we've worked together briefly in 2009, and I am happy to see that you're doing well in Toronto. Hope all the best.
#23 - Albert1 - 06/10/2012 - 07:27
Good work, Fabien!
However, id's Trinity is named after the Dallas Trinity River, as Carmack explained in this interview http://www.firingsquad.com/features/carmack/
#24 - Ralph Schaafsma - 06/10/2012 - 08:09
Very interesting read. I'd like to see a ID-T3 code review from you as well.
#25 - Nikita - 06/10/2012 - 08:12
That's so awesome! I've been waiting for id Tech 4 review for ages!
You've got some very interesting stuff here :)
#26 - Emmanuel Astier - 06/10/2012 - 08:26
Hi,

Great job for this very interesting article.

One question, you said :
"Abstraction and polymorphism are used a lot across the code. But a nice trick avoids the vtable performance hit on some objects."

Can you tell us a little more about this 'nice trick' ?

Thanks !
#27 - Harley - 06/10/2012 - 15:16
+1 for idTech3 review
#28 - Volker - 06/10/2012 - 15:43
Really great article. In-depth explanations like this is what a lot of open source projects would need to attract more developers.

A Quake3 review would also be very nice (or even ioquake3?).
#29 - cristaloleg - 06/11/2012 - 02:25
Great work! Thank's.
#30 - Keith Kaisershot - 06/11/2012 - 03:17
From your notes in renderer.txt:

// the following is Mr.E's code
// Note from FAB WHO is Mr.E ?

FWIW I'm going to hazard a guess and say that Mr.E is "Mr. Elusive" a.k.a. Jon Paul van Waveren. =)
#31 - Carsten Holtkamp - 06/11/2012 - 09:20
Haven't read this article yet. Just a quick overview, but it looks good. I am quite interested in static source code analysis, especially with nice helping graphics. Just wanted to add as a note, there was a overview of the id3tech source already started:
http://element61.blogspot.de/2005/08/looking-at-quake-3-source-part-1.html
http://element61.blogspot.de/2005/08/looking-at-quake-3-source-part-2.html
http://element61.blogspot.de/2005/09/looking-at-quake-3-source-part-3.html

A lot of work was done on ioquake, and there is a nice improve code aswell (normal maps, png textures and so on):
http://www.moddb.com/mods/etxreal
#32 - Yiming Qian - 06/11/2012 - 10:07
LOL,in the second last picture, I can see the background was Ryerson University
#33 - Jean-Francois Moy - 06/11/2012 - 11:24
Great post, thank you for your in-depth analysis.
#34 - Vikram - 06/11/2012 - 11:34
You made me cry.. Thanks for this
#35 - Viktor Liehr - 06/11/2012 - 12:09
Thanks Fabian for your Review, it was a great read! I would be really interested in if you complete your review of idTech3.
#36 - Jonathan - 06/11/2012 - 16:49
Thanks for this! I found it very interesting to read! I happen to have the Doom 3 cds laying around so I installed it and played it a little (brings back memories). I was able to compile the Doom 3 source code successfully but when I transferred it to where the original Doom 3 exec is(and where the Base dir is) I got the following error. It seems to find the pak files okay but then exits out.

DOOM 1.3.1.1304 win-x86 Jun 11 2012 15:14:43
4081 MHz AMD CPU with MMX & SSE & SSE2 & SSE3 & HTT
15840 MB System Memory
0 MB Video Memory
Winsock Initialized
Found interface: {53C6CF71-C4AA-4430-9C4C-DAF112BEA668} Intel(R) 82583V Gigabit Network Connection - 192.168.1.130/255.255.255.0
Found interface: {2B7C12A1-7F58-4FAE-B3EA-1A35703E9055} VirtualBox Host-Only Ethernet Adapter - 192.168.56.1/255.255.255.0
Found interface: {0D903444-3D1B-4028-850D-2058C798DBBF} VMware Virtual Ethernet Adapter for VMnet1 - 192.168.88.1/255.255.255.0
Found interface: {4EB006CA-2A77-4C41-9349-05E7EDCEE56B} VMware Virtual Ethernet Adapter for VMnet8 - 192.168.109.1/255.255.255.0
Sys_InitNetworking: adding loopback interface
doom using MMX & SSE & SSE2 & SSE3 for SIMD processing
enabled Flush-To-Zero mode
enabled Denormals-Are-Zero mode
------ Initializing File System ------
Loaded pk4 C:\Program Files (x86)\DOOM 3\base\game00.pk4 with checksum 0xf07eb555
Loaded pk4 C:\Program Files (x86)\DOOM 3\base\pak000.pk4 with checksum 0x28d208f1
Loaded pk4 C:\Program Files (x86)\DOOM 3\base\pak001.pk4 with checksum 0x40244be0
Loaded pk4 C:\Program Files (x86)\DOOM 3\base\pak002.pk4 with checksum 0xc51ecdcd
Loaded pk4 C:\Program Files (x86)\DOOM 3\base\pak003.pk4 with checksum 0xcd79d028
Loaded pk4 C:\Program Files (x86)\DOOM 3\base\pak004.pk4 with checksum 0x765e4f8b
Current search path:
C:\Program Files (x86)\DOOM 3/base
C:\Program Files (x86)\DOOM 3\base\pak004.pk4 (5137 files)
C:\Program Files (x86)\DOOM 3\base\pak003.pk4 (4676 files)
C:\Program Files (x86)\DOOM 3\base\pak002.pk4 (6120 files)
C:\Program Files (x86)\DOOM 3\base\pak001.pk4 (8972 files)
C:\Program Files (x86)\DOOM 3\base\pak000.pk4 (2698 files)
C:\Program Files (x86)\DOOM 3\base\game00.pk4 (2 files)
game DLL: 0x0 in pak: 0x0
Addon pk4s:
file system initialized.
--------------------------------------
----- Initializing Decls -----
------------------------------
------- Initializing renderSystem --------
using ARB renderSystem
renderSystem initialized.
--------------------------------------
4966 strings read from strings/english.lang
Couldn't open journal files
execing editor.cfg
execing default.cfg
execing DoomConfig.cfg
"\\" isn't a valid key
couldn't exec autoexec.cfg
4966 strings read from strings/english.lang
----- Initializing Sound System ------
sound system initialized.
--------------------------------------
found DLL in pak file: C:\Program Files (x86)\DOOM 3\base\game00.pk4/gamex86.dll
copy gamex86.dll to C:\Program Files (x86)\DOOM 3\base\gamex86.dll
idRenderSystem::Shutdown()
Shutting down OpenGL subsystem
...shutting down QGL
wrong game DLL API version
#37 - Jonathan - 06/11/2012 - 20:07
Ok..got this fixed. Updated to the latest patch (1.3.1) and now it works now with the compiled code!
#38 - Pavel Shevaev - 06/12/2012 - 00:01
Fabien, many thanks. It's an amazing amount of priceless information. id should hire you, seriously :D
#39 - Dominik - 06/12/2012 - 03:56
Thanks a lot Fabien for your great work here! This is so damn interesting. Keep it on! :)
#40 - abitofcode - 06/12/2012 - 04:15
Great write up!
#41 - vanhelgen - 06/12/2012 - 06:21
Great article, as for the tool support: I recommend using a vector drawing program (e.g. Inkscape) the svg markup can be embedded into the html document and you can even style the svg elements with css. If you prefer something more geeky you could use some charting library with an svg renderer like Raphael.js to implement a tool by yourself.
Hope this helps, have fun!
#42 - Joe Garret - 06/12/2012 - 06:56
nice what you are doing. Anything in plan for android?
#43 - Kirill - 06/12/2012 - 12:04
Man, thats great work !!! Thank you very much!
#44 - Nick - 06/12/2012 - 18:38
Thank you!!! I appreciate it to nth degree! Keep being awesome!
#45 - Gustavo De Micheli - 06/13/2012 - 10:09
Great reading!! Its awesome how the article explains the insides of the engine.
I think that it would be super cool that you do the review on idTech3 (for the sake of completitude? he).
#46 - Edouard - 06/14/2012 - 05:16
Amazing, as usual !
And yes, a Quake 3 code review would be awesome ;)
Keep going, you rock.
#47 - bijup - 06/14/2012 - 08:38
for those who want to compile iodoom3 source in visual c++ express editions, please follow this guide http://icculus.org/~riot/doom3_vcpp_express.txt
#48 - bijup - 06/14/2012 - 08:40
yes please, could u review idtech3 as well? tyvm for this
#49 - Lelala - 06/14/2012 - 10:50
Fabien, WOW! Thanks for that great article.
Nice to see someone actually took down some deep steps into Johns system.
Just inspirating :-)
#50 - Den - 06/24/2012 - 22:10
Wow cool. thanks man. very thanks for review.
#51 - slaj - 06/25/2012 - 19:34
really awesome article!
#52 - Tigrou - 07/06/2012 - 08:01
Hi Fabien, very nice review as usual. I already figured out a lot of things a long time ago while looking at code by myself but some things remained a mystery and your review cleared them out.

There is still one thing i don't not understand : network update code (idAsyncNetwork::RunFrame()) seems to be called only once in main loop.

Thats means someone with a pretty slow graphic card (eg : only capable of 10 fps) will only send packets to server at same rate.
Other players would see him with "laggy movement" while it could be a lot better.

Why idAsyncNetwork::RunFrame() could not be placed in a separate thread (like input and sound mixing) and thus packets would be send to server independently from updating the world and rendering ?

IMAO mostly user commands are send to server, so there is no need to have world updated (using game->runframe()) before sending this information.
#53 - Fabien Sanglard - 07/06/2012 - 08:09
@tigrou:

1. Shaggy movement are avoided via client position prediction.
2. There is little value in sending commands at 60Hz is the player cannot even see the result of its actions.
#54 - Prashant - 07/07/2012 - 00:59
the link to id tech 4 coding standard work:
ftp://ftp.idsoftware.com/idstuff/doom3/source/CodeStyleConventions.doc

is there any other place this can be downloaded from?
#55 - Fabien Sanglard - 07/07/2012 - 15:28
@Prashant: I uploaded a mirror in pdf version:

http://fd.fabiensanglard.net/doom3/CodeStyleConventions.pdf
#56 - Viktor - 08/17/2012 - 11:09
Another little GEM of a review.

Big Thx
#57 - Caveau - 09/20/2012 - 10:59
Hi, This is a very great article. Nice deconstruction as always.
Thank you for sharing with us !
#58 - M. Sponholz - 10/06/2012 - 22:32
You inspire me good sir!!
#59 - Pesarak - 10/15/2012 - 00:53
I don't get this part "The engine was developed with Visual Studio .NET (source). But the code does not feature a single line of C#" ... hearing this from -you- is really strange since you seem to be an experienced professional ! it gives me the impression that you think VS can/should only be used when C# is needed, am I right?!

anyways... like it or not, good or bad, when your main target platform is MS Windows, your best option is Visual Studio !
#60 - Pesarak - 10/15/2012 - 01:56
I'm going through this review and your notes and I have to say THESE ARE GREAT ! thanks for posting them
#61 - fabien sanglard - 10/16/2012 - 19:10
@Pesarak

Of course you can use C and C++ with VS.NET.

But when the .NET framework and associated Visual Studio were released, there were strongly associated with C#, VB and J++ (see CLI Infrastructure). Developers were strongly encouraged to use things that would have tied the codebase to Windows but the id software dev team did no use any of those Microsoft only features and I found it amusing.
#62 - Pesarak - 10/17/2012 - 11:44
@Fabien

Hi there, thanks for the reply :)

I do agree with your statement, Microsoft naturally intended VS to be used mainly for Windows-only purposes, but as I said in my first comment, in general, if your main target platform is MS Windows (or Xbox) or even if it is not, but you're developing on an MS Windows machine (personally I've been doing iOS and Android development on VS2010), your best option in terms of both the IDE and the C/C++ compiler is Visual Studio. In particular Visual Studio's profiler, performance analyzer, code analysis, and even debugger -at least on MS Windows- is truly unmatched.

I'm not saying it is the best option that could exist, of course people with another mindset than Microsoft's could come up with something much better, but the truth is that at least on the MS Windows front this hasn't happened yet. VS is the best option that does exist at the moment until someone or some company comes up with something better.

So I still don't get your point but that doesn't really matter :)

I'm truly amazed by this review and your notes, believe it or not I have made this page as one of my many browser's home pages ! again, thanks for posting your notes and this review. I really needed it and it has helped me a lot.
#63 - john Smith - 10/17/2012 - 13:26
Great work Fabien, thanks!
#64 - Judd - 10/26/2012 - 15:42
Holy cow! my friend sent me this link knowing that I was such a huge Doom and Quake nut. Such memories.. ahh.. the LAN parties.

Thanks for digging into the source code to write this. I wish I took up programming in my earlier years to understand the more technical aspects of this post :)
#65 - FipS - 12/21/2012 - 11:32
Good reading! Thanks for your effort.
#66 - Alistair - 01/15/2013 - 16:04
I'm not sure I would have done anything with that view from the window! Great review, very helpful. Thanks.
#67 - Latorie - 01/17/2013 - 21:45
Great game, great article - thanks!
#68 - nitrofurano - 01/18/2013 - 15:25
i wonder why Linux and others are not being cited in this article? :S
#69 - André Taiar - 01/25/2013 - 13:13
Wow... That's a cool article!

Congratulations!
#70 - Eli - 01/29/2013 - 07:17
Well done Fabien! Another masterpiece article.
#71 - Arman - 02/17/2013 - 13:37
Awesome job, this helps immensely the programmers, to learn about a huge project's architecture. The notes you made are priceless! Can't thank you enough, keep it up :]
#72 - Robert - 02/21/2013 - 21:22
Does anybody know why the Game is a DLL and the Engine is an EXE file? It looks counter-intuitive as we normal see it the other way around. Is it for modding? Or does it have some inner design decision that I can't understand?
#73 - Jay McGavren - 02/27/2013 - 23:11
Here's the game footage from my first couple experiments (bouncy barrels, enemies attack each other): http://www.youtube.com/watch?v=fjs8FHtrxf0
#74 - stephen - 03/12/2013 - 00:03
Thanks for your work! I plan on starting my study of this well documented site!
#75 - Xiaoming Nan - 05/16/2013 - 05:47
Awesome! you are from Ryerson U? Great! I'm at Ryerson, too. Just start studying cloud gaming. Maybe we can find a time to chat.

 

@2012