Fix input lag: add PM_NOYIELD, skip idle GetDC, eliminate redundant renders
PeekMessage without PM_NOYIELD surrenders the timeslice on every empty queue check (~55ms per yield in Win16). Adding pm_NoYield keeps the polling loop hot so keystrokes and serial echoes are processed without scheduler delays. FlipToScreen was calling GetDC/ReleaseDC on every loop iteration even with zero dirty rows. Added early-exit scan before acquiring a DC. TickBlink was calling FlipToScreen redundantly (main loop also calls it). Removed the FlipToScreen from TickBlink and reordered the main loop to TickBlink (dirty only) then FlipToScreen (single render pass). Also: removed FBlinkOn := True reset from ParseData (was dirtying the cursor row on every incoming chunk), added WriteDeferred for parse-only without render, moved FlipToScreen from private to public, added Show call before entering the polling loop. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ec0ec8f074
commit
fbf4ed7c40
2 changed files with 36 additions and 14 deletions
|
|
@ -134,7 +134,6 @@ type
|
|||
procedure EraseLine(Mode: Integer);
|
||||
procedure ExecuteCSI(FinalCh: Char);
|
||||
procedure ExecuteMusic;
|
||||
procedure FlipToScreen;
|
||||
procedure FreeLineList(List: TList);
|
||||
function GetCursorCol: Integer;
|
||||
function GetCursorRow: Integer;
|
||||
|
|
@ -166,8 +165,10 @@ type
|
|||
destructor Destroy; override;
|
||||
procedure Clear;
|
||||
procedure Reset;
|
||||
procedure FlipToScreen;
|
||||
procedure TickBlink;
|
||||
procedure Write(const S: string);
|
||||
procedure WriteDeferred(const S: string);
|
||||
property CursorCol: Integer read GetCursorCol;
|
||||
property CursorRow: Integer read GetCursorRow;
|
||||
published
|
||||
|
|
@ -1222,6 +1223,7 @@ procedure TKPAnsi.FlipToScreen;
|
|||
var
|
||||
DC: HDC;
|
||||
Row: Integer;
|
||||
HasDirty: Boolean;
|
||||
begin
|
||||
if not HandleAllocated then
|
||||
Exit;
|
||||
|
|
@ -1251,6 +1253,22 @@ begin
|
|||
FLastCursorRow := FCursorRow;
|
||||
end;
|
||||
|
||||
{ Early exit: skip GetDC/ReleaseDC when nothing needs rendering }
|
||||
if not FAllDirty then
|
||||
begin
|
||||
HasDirty := False;
|
||||
for Row := 0 to FRows - 1 do
|
||||
begin
|
||||
if FDirtyRow[Row] then
|
||||
begin
|
||||
HasDirty := True;
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
if not HasDirty then
|
||||
Exit;
|
||||
end;
|
||||
|
||||
{ Interleaved render + blast: single buffer is reused per row }
|
||||
DC := GetDC(Handle);
|
||||
for Row := 0 to FRows - 1 do
|
||||
|
|
@ -1570,8 +1588,6 @@ begin
|
|||
FAllDirty := True;
|
||||
end;
|
||||
|
||||
{ Reset cursor blink to visible on new data }
|
||||
FBlinkOn := True;
|
||||
end;
|
||||
|
||||
|
||||
|
|
@ -2315,7 +2331,6 @@ begin
|
|||
FBlinkOn := not FBlinkOn;
|
||||
FTextBlinkOn := not FTextBlinkOn;
|
||||
DirtyBlinkRows;
|
||||
FlipToScreen;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
@ -2371,6 +2386,13 @@ begin
|
|||
end;
|
||||
|
||||
|
||||
procedure TKPAnsi.WriteDeferred(const S: string);
|
||||
begin
|
||||
if Length(S) > 0 then
|
||||
ParseData(S);
|
||||
end;
|
||||
|
||||
|
||||
{ ----------------------------------------------------------------------- }
|
||||
{ Component registration }
|
||||
{ ----------------------------------------------------------------------- }
|
||||
|
|
|
|||
|
|
@ -169,11 +169,12 @@ var
|
|||
Msg: TMsg;
|
||||
S: string;
|
||||
begin
|
||||
Show;
|
||||
FDone := False;
|
||||
while not FDone do
|
||||
begin
|
||||
{ Process all pending Windows messages (keyboard, paint, scrollbar) }
|
||||
while PeekMessage(Msg, 0, 0, 0, pm_Remove) do
|
||||
while PeekMessage(Msg, 0, 0, 0, pm_Remove or pm_NoYield) do
|
||||
begin
|
||||
if Msg.message = wm_Quit then
|
||||
begin
|
||||
|
|
@ -187,18 +188,17 @@ begin
|
|||
if FDone then
|
||||
Break;
|
||||
|
||||
{ Poll serial data directly -- no WM_COMMNOTIFY, no events }
|
||||
{ Poll serial data -- read one chunk, then yield to messages }
|
||||
if FComm.PortOpen then
|
||||
begin
|
||||
repeat
|
||||
S := FComm.Input;
|
||||
if Length(S) > 0 then
|
||||
FAnsi.Write(S);
|
||||
until Length(S) = 0;
|
||||
FAnsi.WriteDeferred(S);
|
||||
end;
|
||||
|
||||
{ Tick blink state (uses GetTickCount, no WM_TIMER) }
|
||||
{ Tick blink (dirties rows if interval elapsed), then render }
|
||||
FAnsi.TickBlink;
|
||||
FAnsi.FlipToScreen;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue