mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
perf(tr): устранение GUI-фриза ~100мс на TX→RX (живой TX-DSP поток)
TX-DSP поток (TTXDSPThread) больше не пересоздаётся на каждом T/R — он
создаётся один раз и живёт весь сеанс, на приём/передачу переключается
флагом FTXActive (поток при False просто Continue, не трогает канал/ring).
Тердаун перенесён в TWDSPEngine.Close. Раньше Terminate+WaitFor+Free на
каждом отпускании PTT давал фиксированные ~100мс пустого join-оверхеда
pthread_join, блокируя GUI-поток. Итог: 206→106мс, крупные фризы ушли.
Остаток ~106мс = плавный WDSP fade-out TXA (SetChannelState dmode=1) —
оставлен как есть (dmode=0 дал бы trailing key-click в эфир).
Попутно:
- MainForm: убраны прямые PbSpectrum.Invalidate из drag/wheel VFO/центра —
кадр рисует таймер по FSpectrumDirty (FPS-гейт; прямой Invalidate давал
GL-кадр на каждое событие мыши мимо гейта → треск в HDMI-звуке AMD APU).
- AudioOutput: const-секция после {$ENDIF} блока PA-констант.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -189,6 +189,7 @@ const
|
|||||||
);
|
);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
const
|
||||||
PA_NO_ERROR = 0;
|
PA_NO_ERROR = 0;
|
||||||
PA_FLOAT32 = LongWord(1);
|
PA_FLOAT32 = LongWord(1);
|
||||||
PA_NO_FLAG = LongWord(0);
|
PA_NO_FLAG = LongWord(0);
|
||||||
|
|||||||
+9
-13
@@ -1155,18 +1155,16 @@ begin
|
|||||||
rfVfoA:
|
rfVfoA:
|
||||||
begin
|
begin
|
||||||
FreqDispA.Frequency := Round(FController.FVfoA);
|
FreqDispA.Frequency := Round(FController.FVfoA);
|
||||||
// Не рисуем синхронно из wheel/drag: частые события забивают UI-поток.
|
// Не рисуем синхронно из wheel/drag: частые события забивают UI-поток,
|
||||||
// Invalidate лишь планирует; DrawSpectrum откладываем (FSpectrumDirty).
|
// а мгновенный Invalidate давал GL-кадр на КАЖДОЕ событие мыши (при
|
||||||
// Линейку дёргаем сразу — её рендер дешёвый, иначе отстаёт от спектра.
|
// драге рендер упирался в vsync и обходил FPS-гейт — на AMD APU это
|
||||||
|
// трещало в HDMI-звуке того же GPU). Кадр отрисует ближайший тик
|
||||||
|
// FSpectrumTimer по FSpectrumDirty. Линейка дешёвая — её сразу.
|
||||||
SyncSpecViewFreq;
|
SyncSpecViewFreq;
|
||||||
FSpectrumDirty := True;
|
FSpectrumDirty := True;
|
||||||
PbSpectrum.Invalidate;
|
|
||||||
if PbRuler <> nil then PbRuler.Invalidate;
|
if PbRuler <> nil then PbRuler.Invalidate;
|
||||||
if FController.FLastVfoScrolled then
|
if FController.FLastVfoScrolled then
|
||||||
begin
|
|
||||||
FWaterfallDirty := True;
|
FWaterfallDirty := True;
|
||||||
if PbWaterfall <> nil then PbWaterfall.Invalidate;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
rfActiveVfo:
|
rfActiveVfo:
|
||||||
begin
|
begin
|
||||||
@@ -1182,11 +1180,11 @@ begin
|
|||||||
rfCenterFreq:
|
rfCenterFreq:
|
||||||
begin
|
begin
|
||||||
// CTUN-скролл центра (drag/web): ruler-метки сдвинулись → инвалидируем
|
// CTUN-скролл центра (drag/web): ruler-метки сдвинулись → инвалидируем
|
||||||
// кэш; спектр откладываем (FSpectrumDirty) — drag шлёт много событий.
|
// кэш; спектр откладываем (FSpectrumDirty) — drag шлёт много событий,
|
||||||
|
// кадр отрисует таймер (FPS-гейт, см. rfVfoA).
|
||||||
FSpecView.InvalidateRulerCache;
|
FSpecView.InvalidateRulerCache;
|
||||||
SyncSpecViewFreq;
|
SyncSpecViewFreq;
|
||||||
FSpectrumDirty := True;
|
FSpectrumDirty := True;
|
||||||
PbSpectrum.Invalidate;
|
|
||||||
if PbRuler <> nil then PbRuler.Invalidate;
|
if PbRuler <> nil then PbRuler.Invalidate;
|
||||||
end;
|
end;
|
||||||
rfVfoB:
|
rfVfoB:
|
||||||
@@ -1196,8 +1194,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
FSpecView.InvalidateRulerCache;
|
FSpecView.InvalidateRulerCache;
|
||||||
SyncSpecViewFreq;
|
SyncSpecViewFreq;
|
||||||
FSpectrumDirty := True;
|
FSpectrumDirty := True; // кадр — по таймеру (FPS-гейт, см. rfVfoA)
|
||||||
PbSpectrum.Invalidate;
|
|
||||||
if PbRuler <> nil then PbRuler.Invalidate;
|
if PbRuler <> nil then PbRuler.Invalidate;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@@ -4568,8 +4565,7 @@ begin
|
|||||||
FController.SetSliceTarget(FSliceDragId, NewHz);
|
FController.SetSliceTarget(FSliceDragId, NewHz);
|
||||||
PushSliceFlagState(FSliceDragId); // обновить частоту во флаге
|
PushSliceFlagState(FSliceDragId); // обновить частоту во флаге
|
||||||
PositionSliceFlags;
|
PositionSliceFlags;
|
||||||
FSpectrumDirty := True;
|
FSpectrumDirty := True; // кадр — по таймеру (FPS-гейт, как при drag VFO)
|
||||||
PbSpectrum.Invalidate;
|
|
||||||
end;
|
end;
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
|||||||
+22
-18
@@ -1259,6 +1259,17 @@ begin
|
|||||||
FreeAndNil(FDSPThread);
|
FreeAndNil(FDSPThread);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// TX-DSP поток живёт весь сеанс (не пересоздаётся на T/R) — гасим его здесь,
|
||||||
|
// до закрытия WDSP-каналов (он зовёт fexchange0 на TXA_CHAN).
|
||||||
|
FTXActive := False;
|
||||||
|
if Assigned(FTXThread) then
|
||||||
|
begin
|
||||||
|
FTXThread.Terminate;
|
||||||
|
RTLEventSetEvent(FTXMicSem);
|
||||||
|
FTXThread.WaitFor;
|
||||||
|
FreeAndNil(FTXThread);
|
||||||
|
end;
|
||||||
|
|
||||||
// Закрываем WDSP-каналы слайсов (записи FSlices сохраняем — переоткроются в Open).
|
// Закрываем WDSP-каналы слайсов (записи FSlices сохраняем — переоткроются в Open).
|
||||||
FSliceLock.Enter;
|
FSliceLock.Enter;
|
||||||
try
|
try
|
||||||
@@ -2130,37 +2141,30 @@ end;
|
|||||||
|
|
||||||
procedure TWDSPEngine.SetTXRun(Run: Boolean);
|
procedure TWDSPEngine.SetTXRun(Run: Boolean);
|
||||||
begin
|
begin
|
||||||
FTXActive := Run;
|
|
||||||
FDispPos := 0;
|
FDispPos := 0;
|
||||||
FTXDispPos := 0;
|
FTXDispPos := 0;
|
||||||
if Run then
|
|
||||||
FActiveDisplayID := TX_DISP_ID
|
|
||||||
else
|
|
||||||
FActiveDisplayID := RX_DISP_ID;
|
|
||||||
|
|
||||||
if Run then
|
if Run then
|
||||||
begin
|
begin
|
||||||
if FInitialized then
|
FActiveDisplayID := TX_DISP_ID;
|
||||||
SetChannelState(TXA_CHAN, 1, 0); // run, no delay
|
// Сброс mic ring ДО активации, чтобы простаивавший поток не прочитал старое.
|
||||||
// Сброс mic ring buffer и запуск TX потока
|
|
||||||
FTXMicHead := 0;
|
FTXMicHead := 0;
|
||||||
FTXMicTail := 0;
|
FTXMicTail := 0;
|
||||||
|
if FInitialized then
|
||||||
|
SetChannelState(TXA_CHAN, 1, 0); // run, no delay
|
||||||
|
// TX-DSP поток создаётся ОДИН раз и живёт весь сеанс. НЕ пересоздаём на каждом
|
||||||
|
// T/R: join (WaitFor) давал фиксированные ~100 мс фриза GUI на отпускании PTT.
|
||||||
|
// При FTXActive=False поток простаивает (см. TTXDSPThread.Execute: Continue).
|
||||||
if not Assigned(FTXThread) then
|
if not Assigned(FTXThread) then
|
||||||
begin
|
begin
|
||||||
FTXThread := TTXDSPThread.Create(Self);
|
FTXThread := TTXDSPThread.Create(Self);
|
||||||
FTXThread.Priority := tpHighest;
|
FTXThread.Priority := tpHighest;
|
||||||
end;
|
end;
|
||||||
|
FTXActive := True; // активируем последним
|
||||||
end else begin
|
end else begin
|
||||||
|
FTXActive := False; // поток уходит в простой (не трогает канал/ring)
|
||||||
|
FActiveDisplayID := RX_DISP_ID;
|
||||||
if FInitialized then
|
if FInitialized then
|
||||||
SetChannelState(TXA_CHAN, 0, 1); // stop, with slew
|
SetChannelState(TXA_CHAN, 0, 1); // stop, with slew (поток уже idle)
|
||||||
// Останавливаем TX поток
|
|
||||||
if Assigned(FTXThread) then
|
|
||||||
begin
|
|
||||||
FTXThread.Terminate;
|
|
||||||
RTLEventSetEvent(FTXMicSem);
|
|
||||||
FTXThread.WaitFor;
|
|
||||||
FreeAndNil(FTXThread);
|
|
||||||
end;
|
|
||||||
FTXMicHead := 0;
|
FTXMicHead := 0;
|
||||||
FTXMicTail := 0;
|
FTXMicTail := 0;
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
<UseVersionInfo Value="True"/>
|
<UseVersionInfo Value="True"/>
|
||||||
<AutoIncrementBuild Value="True"/>
|
<AutoIncrementBuild Value="True"/>
|
||||||
<MinorVersionNr Value="9"/>
|
<MinorVersionNr Value="9"/>
|
||||||
<BuildNr Value="245"/>
|
<BuildNr Value="246"/>
|
||||||
</VersionInfo>
|
</VersionInfo>
|
||||||
<MacroValues Count="63">
|
<MacroValues Count="64">
|
||||||
<Macro1 Name="LCLWidgetType" Value="qt6"/>
|
<Macro1 Name="LCLWidgetType" Value="qt6"/>
|
||||||
<Macro2 Name="LCLWidgetType" Value="qt6"/>
|
<Macro2 Name="LCLWidgetType" Value="qt6"/>
|
||||||
<Macro3 Name="LCLWidgetType" Value="qt6"/>
|
<Macro3 Name="LCLWidgetType" Value="qt6"/>
|
||||||
@@ -83,6 +83,7 @@
|
|||||||
<Macro61 Name="LCLWidgetType" Value="qt6"/>
|
<Macro61 Name="LCLWidgetType" Value="qt6"/>
|
||||||
<Macro62 Name="LCLWidgetType" Value="qt6"/>
|
<Macro62 Name="LCLWidgetType" Value="qt6"/>
|
||||||
<Macro63 Name="LCLWidgetType" Value="qt6"/>
|
<Macro63 Name="LCLWidgetType" Value="qt6"/>
|
||||||
|
<Macro64 Name="LCLWidgetType" Value="qt6"/>
|
||||||
</MacroValues>
|
</MacroValues>
|
||||||
<BuildModes>
|
<BuildModes>
|
||||||
<Item Name="Debug" Default="True"/>
|
<Item Name="Debug" Default="True"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user