C:\RETRO\DOS\TP>type turbop~3.htm
Turbo Pascal BGI Tutorial: Dynamic Drivers, Linked Drivers, and Diagnostic Harnesses
This tutorial gives you a practical BGI workflow that survives deployment:
- dynamic driver loading from filesystem
- linked-driver strategy for lower runtime dependency risk
- a minimal diagnostics harness for startup failures
Preflight: what you need
- Turbo Pascal / Borland Pascal environment with
Graphunit - one known-good BGI driver set and required
.CHRfonts - a test machine/profile where paths are not identical to dev directories
TP5 baseline reminder:
- compile needs
GRAPH.TPU - runtime needs
.BGIdrivers - stroked fonts need
.CHRfiles
Step 1: dynamic loading baseline
Create BGITEST.PAS:
program BgiTest;
uses
Graph, Crt;
var
gd, gm, gr: Integer;
begin
gd := Detect;
InitGraph(gd, gm, '.\BGI');
gr := GraphResult;
Writeln('Driver=', gd, ' Mode=', gm, ' GraphResult=', gr);
if gr <> grOk then
Halt(1);
SetColor(15);
OutTextXY(8, 8, 'BGI OK');
Rectangle(20, 20, 200, 120);
ReadKey;
CloseGraph;
end.Expected outcome:
- with correct path/assets: startup succeeds and simple frame draws
- with missing assets:
GraphResultindicates error and program exits cleanly
Important TP5 behavior: GraphResult resets to zero after being called. Always
store it to a variable once, then evaluate that value.
Path behavior detail: if InitGraph(..., PathToDriver) gets an empty path, the
driver files must be in the current directory.
Step 2: deployment discipline for dynamic model
Package checklist:
- executable
- all required
.BGIfiles for target adapters - all required
.CHRfonts - documented runtime path policy
Most “BGI bugs” are missing files or wrong path assumptions.
Step 3: linked-driver strategy (when you need robustness)
Some Borland-era setups support converting/linking BGI driver binaries into
object modules and registering them before InitGraph (for example through
RegisterBGIdriver and related registration APIs).
General workflow:
- run
BINOBJon.BGIfile(s) to get.OBJ - link
.OBJfile(s) into program - call
RegisterBGIdriverbeforeInitGraph - call
InitGraphand verifyGraphResult
Why teams did this:
- fewer runtime file dependencies
- simpler deployment to constrained/chaotic DOS installations
Tradeoff:
- larger executable and tighter build coupling
Ordering constraint from TP5 docs: calling RegisterBGIdriver after graphics
are already active yields grError (-11).
If you use InstallUserDriver with an autodetect callback, TP5 expects that
callback to be a FAR-call function with no parameters returning an integer mode
or grError.
Step 4: diagnostics harness you should keep forever
Keep a dedicated harness separate from game/app engine:
- prints detected driver/mode and
GraphResult - renders one line, one rectangle, one text string
- exits on keypress
This lets you quickly answer: “is graphics stack alive?” before debugging your full renderer.
Add one negative test here too: intentionally pass wrong mode for a known
driver and verify expected grInvalidMode (-10).
Step 5: test matrix (predict first, then run)
Define expected outcomes before running each case:
- correct BGI path
- missing driver file
- missing font file
- wrong current directory
- TSR-heavy memory profile
For each case, record:
- startup status
- exact error code/output
- whether fallback path triggers correctly
Recommended TP5 error codes to classify in logs:
grNotDetected(-2)grFileNotFound(-3)grInvalidDriver(-4)grNoLoadMem(-5)grFontNotFound(-8)grNoFontMem(-9)grInvalidMode(-10)
Step 6: fallback policy for production-ish DOS apps
Never rely on detect-only logic without fallback:
- try preferred mode
- fallback to known-safe mode
- print actionable error if both fail
A black screen is a product bug, even in retro projects.
About creating custom BGI drivers
Writing full custom BGI drivers is advanced and depends on ABI/tooling details that are often version-specific and poorly documented. Practical teams usually ship stock drivers (dynamic or linked) unless there is a hard requirement for new hardware support.
If you must go custom, treat it as a separate reverse-engineering project with its own test harnesses and compatibility matrix.
Integration notes with overlays and memory strategy
If graphics startup becomes unstable after enabling overlays:
- verify overlay initialization order
- verify memory headroom before
InitGraph - test graphics harness independently from overlayed application paths
This avoids mixing two failure domains during triage.
Memory interaction note from TP5 docs:
- Graph allocates heap memory for graphics buffer/driver/font paths
OvrSetBufalso reshapes memory by shrinking heap- call order matters (
OvrSetBufbeforeInitGraphwhen both are used)
Related reading: