How DMDX works
In the interests of enabling people to write better scripts here are some of the details of the way in which DMDX gets things done.
Also, please check the notes section as
many non-obvious things are elucidated upon there.
Before the tachistoscopic routines are fired up DMDX performs a certain amount of text file manipulation. DMDX first parses the rich text
item file to a new temporary file called rtfparsed.txt, parsing out all RTF control codes not between quotes. Next if the item file calls for
scrambling the scrambling routines produce another file scrambled.itm. DMDX reads whatever the final result of that process is, be it rtfparsed.itm (if no scrambling) or scrambled.itm
(or one of the multiscramble
Following file parsing the various processes that make up DMDX proper are begun.
First DirectX is instructed to switch the screen to whatever display mode has been requested in the item file.
Unless you're using the modern Auto mode
shortcut that display mode must have been setup with TimeDX beforehand
as unless auto mode is used DMDX reads various values relevant to keeping track of the retrace from the registry that TimeDX puts there.
Using the classic DirectDraw renderer it also requests that as many screen buffers as can be contained in video memory be created, these are called DirectDraw Surfaces.
If you're using Windows 8 (or later) or you have asked TimeDX to use the
Direct3D renderer it won't be doing that
because DirectDraw is emulated under Windows 8. You might choose to use
Direct3D because your video card drivers freak out when DMDX makes it's
DirectDraw requests. Using DirectDraw beside the primary surface that is always displayed there can be a large number of these back surfaces that DMDX uses for buffering, up to 24 of them.
When using Direct3D video memory is used as textures that contain the DMDX
Then the millisecond callback from the OS is initiated. I recommend you read all of TimeDX's
help file if you want a full understanding of what's going on.
A thread is created to keep track of the retrace. A thread is another task running in parallel with the original program (itself just another thread). The retrace thread spends most of it's time sleeping (ie, letting the other threads execute). Once each retrace period it wakes up and waits for a number of milliseconds until it either finds the retrace or it decides that it has missed it, in either event counters are updated and DMDX gets to decide what should happen. In most cases if a retrace is missed it is no big deal, what DMDX requires is done by the hardware at the next retrace anyway, so as long as DMDX gets control back before the next retrace things are fine. Unfortunately this is not always the case, see TimeDX's help file for myriad details.
A thread is also created for each input device requested in the item file or just the keyboard if no requests were made. Threads for keyboards and mice and any other interrupt driven devices (TimeDX will tell you whether a device is interrupt driven or not) lie in wait for input data, all other polled devices have threads that are woken up periodically by the millisecond callback to go and check if a key is being pressed (and therefore represent a greater load on the system).
Another thread can exist to handle requests to play sound files, however this thread is not created until DMDX finds a request to play a sound. At that time the sound system as a whole is initiated and the sound thread created. The thread creation is not likely to take much time, however setting the sound system going could take quite a number of milliseconds. Also once the sound system is initiated it is running all the time till that item file finishes, meaning the machine is pumping 22050 16 bit samples per second in stereo (so times 2) to the sound card -- which is why it's not done unless it's needed. Not that this represents a significant load to a Pentium running at 133 Mhz, it's just another load and the less of load the better. If DMDX is going to be used primarily to present audio stimuli the priority of the audio thread can be bumped up.
Prior to the request beginning any given item DMDX performs all disk related tasks. This means that for request scheduled displays and low value D parameters care must be taken to ensure that unrealistic timing requests are not made. In DMTG (and DM I suppose, although most of it's processing was so trivial that I don't think anyone that ever used it had much concern) you had to ascertain just how fast you could go by attempting to go faster than possible and backing off, DMDX on the other hand provides the time taken to prepare items in it's Preparation A and B times, A being disk stuff and B being drawing stuff (see Errors you might encounter. below).
Disk related tasks include writing diagnostics to disk, writing result files to disk, reading the item to be displayed (although this is likely to have been buffered in memory as DMDX uses file mapping), and reading the bitmaps and sound files used in the item and preparing their in-memory analogues. If a sound file is used for the first time this is when the sound system is initiated.
Once the request has been received DMDX prepares each individual frame in a separate main memory (as opposed to screen memory) surface,
when using DirectDraw it ascertains which screen surface that frame will be displayed in and what in that screen surface from a previous item's display needs to be overwritten or erased. Having done that it creates a surface (that will be
released at the item's completion) just big enough to contain the region that will change on the screen surface and copies the corresponding region of the memory surface to this new temporary surface.
When using Direct3D it simply copies the relevant section of that memory surface
to a texture for rendering at display time. Because Direct3D erases the
screen for free we don't have to worry about doing it. Once the item is
complete the textures are released.
Once everything is drawn DMDX schedules the frames for display and adds them to the display queue.
DMDX's main thread watches the display queue to see if any of the screen surfaces become empty (or are already empty at the item's commencement) and moves the display queue surfaces onto the screen surfaces a portion at a time -- it moves only portions because the process of moving data to the video display memory usually locks out all other threads, a bad thing.
The retrace thread decides when screen surfaces should be flipped
for DirectDraw or presented in Direct3D, when sounds should be commenced, when output bytes should be output, when the clock should be turned on and so forth. These requests are calculated ahead of time, usually only a portion of a retrace interval but sometimes in the case of a sound quite some time earlier, and passed off to the millisecond callback.
The millisecond callback then has this list of things that should be done at various times and it dispatches them as needed.