viddriver topic
Writing a custom video driver.
Declaration
viddriverDescription
Writing a custom video driver is not difficult, and generally means implementing a couple of functions, which whould be registered with the SetVideoDriver function. The various functions that can be implemented are located in the TVideoDriver record:
TVideoDriver = Record InitDriver : Procedure; DoneDriver : Procedure; UpdateScreen : Procedure(Force : Boolean); ClearScreen : Procedure; SetVideoMode : Function (Const Mode : TVideoMode) : Boolean; GetVideoModeCount : Function : Word; GetVideoModeData : Function(Index : Word; Var Data : TVideoMode) : Boolean; SetCursorPos : procedure (NewCursorX, NewCursorY: Word); GetCursorType : function : Word; SetCursorType : procedure (NewType: Word); GetCapabilities : Function : Word; end;
Not all of these functions must be implemented. In fact, the only absolutely
necessary function to write a functioning driver is the UpdateScreen
function. The general calls in the Video unit will check which
functionality is implemented by the driver.
The functionality of these calls is the same as the functionality of the calls in the video unit, so the expected behaviour can be found in the previous section. Some of the calls, however, need some additional remarks.
- InitDriver
- Called by
InitVideo, this function should initialize any data structures needed for the functionality of the driver, maybe do some screen initializations. The function is guaranteed to be called only once; It can only be called again after a call toDoneVideo. The variablesScreenWidthandScreenHeightshould be initialized correctly after a call to this function, as theInitVideocall will initialize theVideoBufandOldVideoBufarrays based on their values. - DoneDriver
- This should clean up any structures that have been
initialized in the
InitDriverfunction. It should possibly also restore the screen as it was before the driver was initialized. The VideoBuf andOldVideoBufarrays will be disposed of by the generalDoneVideocall. - UpdateScreen
- This is the only required function of the driver. It
should update the screen based on the
VideoBufarray's contents. It can optimize this process by comparing the values with values in theOldVideoBufarray. After updating the screen, theUpdateScreenprocedure should update theOldVideoBufby itself. If theForceparameter isTrue, the whole screen should be updated, not just the changed values. - ClearScreen
- If there is a faster way to clear the screen than to
write spaces in all character cells, then it can be implemented here. If the
driver does not implement this function, then the general routines will
write spaces in all video cells, and will call
UpdateScreen(True). - SetVideoMode
- Should set the desired video mode, if available. It
should return
Trueif the mode was set,Falseif not. - GetVideoModeCount
- Should return the number of supported video modes. If no modes are supported, this function should not be implemented; the general routines will return 1. (for the current mode)
- GetVideoModeData
- Should return the data for the
Index-th mode;Indexis zero based. The function should return true if the data was returned correctly, false ifIndexcontains an invalid index. If this is not implemented, then the general routine will return the current video mode whenIndexequals 0. - GetCapabilities
- If this function is not implemented, zero (i.e. no capabilities) will be returned by the general function.
The following unit shows how to override a video driver, with a driver
that writes debug information to a file. The unit can be used in any of
the demonstration programs, by simply including it in the uses
clause. Setting DetailedVideoLogging to
True will create a more detailed log (but will also slow down
functioning)
Example: viddbg
unit viddbg;
Interface
uses video;
Procedure StartVideoLogging;
Procedure StopVideoLogging;
Function IsVideoLogging : Boolean;
Procedure SetVideoLogFileName(FileName : String);
Const
DetailedVideoLogging : Boolean = False;
Implementation
uses sysutils,keyboard;
var
NewVideoDriver,
OldVideoDriver : TVideoDriver;
Active,Logging : Boolean;
LogFileName : String;
VideoLog : Text;
Function TimeStamp : String;
begin
TimeStamp:=FormatDateTime('hh:nn:ss',Time());
end;
Procedure StartVideoLogging;
begin
Logging:=True;
Writeln(VideoLog,'Start logging video operations at: ',TimeStamp);
end;
Procedure StopVideoLogging;
begin
Writeln(VideoLog,'Stop logging video operations at: ',TimeStamp);
Logging:=False;
end;
Function IsVideoLogging : Boolean;
begin
IsVideoLogging:=Logging;
end;
Var
ColUpd,RowUpd : Array[0..1024] of Integer;
Procedure DumpScreenStatistics(Force : Boolean);
Var
I,Count : Integer;
begin
If Force then
Write(VideoLog,'forced ');
Writeln(VideoLog,'video update at ',TimeStamp,' : ');
FillChar(Colupd,SizeOf(ColUpd),#0);
FillChar(Rowupd,SizeOf(RowUpd),#0);
Count:=0;
For I:=0 to VideoBufSize div SizeOf(TVideoCell) do
begin
If VideoBuf^[i]<>OldVideoBuf^[i] then
begin
Inc(Count);
Inc(ColUpd[I mod ScreenWidth]);
Inc(RowUpd[I div ScreenHeight]);
end;
end;
Write(VideoLog,Count,' videocells differed divided over ');
Count:=0;
For I:=0 to ScreenWidth-1 do
If ColUpd[I]<>0 then
Inc(Count);
Write(VideoLog,Count,' columns and ');
Count:=0;
For I:=0 to ScreenHeight-1 do
If RowUpd[I]<>0 then
Inc(Count);
Writeln(VideoLog,Count,' rows.');
If DetailedVideoLogging Then
begin
For I:=0 to ScreenWidth-1 do
If (ColUpd[I]<>0) then
Writeln(VideoLog,'Col ',i,' : ',ColUpd[I]:3,' rows changed');
For I:=0 to ScreenHeight-1 do
If (RowUpd[I]<>0) then
Writeln(VideoLog,'Row ',i,' : ',RowUpd[I]:3,' colums changed');
end;
end;
Procedure LogUpdateScreen(Force : Boolean);
begin
If Logging then
DumpScreenStatistics(Force);
OldVideoDriver.UpdateScreen(Force);
end;
Procedure LogInitVideo;
begin
OldVideoDriver.InitDriver();
Assign(VideoLog,logFileName);
Rewrite(VideoLog);
Active:=True;
StartVideoLogging;
end;
Procedure LogDoneVideo;
begin
StopVideoLogging;
Close(VideoLog);
Active:=False;
OldVideoDriver.DoneDriver();
end;
Procedure SetVideoLogFileName(FileName : String);
begin
If Not Active then
LogFileName:=FileName;
end;
Initialization
GetVideoDriver(OldVideoDriver);
NewVideoDriver:=OldVideoDriver;
NewVideoDriver.UpdateScreen:=@LogUpdateScreen;
NewVideoDriver.InitDriver:=@LogInitVideo;
NewVideoDriver.DoneDriver:=@LogDoneVideo;
LogFileName:='Video.log';
Logging:=False;
SetVideoDriver(NewVideoDriver);
end.An experiment, built from development snapshots. Not the official Free Pascal or Lazarus documentation.
