mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 17:27:32 +00:00
perf: zone CPU profiler (PerfLog) + phase-restructured CPU spectrum render
Инструментация (ВРЕМЕННАЯ, не мержить в main): - PerfLog.pas: зонные таймеры, отчёт раз в 5с в stderr (core% = доля ядра), EWSDR_PERF=0 выкл, EWSDR_PERF_FILE=путь — дублировать в файл - Замеры // PERF: сеть (DDC IQ/wideband), Pluto (rx_conv/tx_resamp/tx_fill), DSP (push_iq/fexchange/slices/tx), аудио, UI (тики/draw/paint/gl_swap, разбивка draw_spectrum по фазам) - doc/PERF_PROFILING.md: карта зон, методика, выводы Оптимизация CPU-рендера спектра (по результатам замеров на эфире): диагноз — дорога не пиксельная работа, а чередование raw(ScanLine)/ canvas(QPainter) доступа к битмапу на Qt6 (~6 переходов за кадр, каждый синкает весь битмап; полоса фильтра в тысячи пикселей стоила 4x дороже полного memcpy кадра). DrawSpectrum перестроен в фазы calc->raw->canvas->raw (2 перехода): FillBandRaw вместо Canvas.FillRect, DrawSliceFilterMarkers разделён на raw-полосы + canvas-линии, композиты флагов и альфа-OR в финальной raw-фазе. Кадр 8.3мс -> 6.1мс; spec_bands 1.87мс -> 0.03мс. Альфа-OR проход на Qt6 подтверждён нужным (без него canvas-пиксели теряют альфу и пропадают при блите), сам цикл ~0.08мс — оставлен; тумблер EWSDR_ALPHA_FIX=0 только для экспериментов. Кисть перед AGC-подписями теперь ставится явно (была остаточной после перестройки фаз). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+198
-75
@@ -21,7 +21,8 @@ uses
|
||||
Classes, SysUtils, Graphics, ExtCtrls, Controls, Math,
|
||||
AppTheme,
|
||||
AlertOverlay, SampleRateOverlay, VfoOverlay, BandPlanOverlay,
|
||||
WaterfallView, SMeterView, RulerView;
|
||||
WaterfallView, SMeterView, RulerView,
|
||||
PerfLog; // ВРЕМЕННО (perf/cpu-profiling): зонные CPU-таймеры
|
||||
|
||||
const
|
||||
SV_CLR_BG = TColor($00101010);
|
||||
@@ -109,10 +110,15 @@ type
|
||||
procedure SetFillSpectrum(V: Boolean);
|
||||
procedure DrawSpectrumGradient(const SpPts: array of TPoint; W, H: Integer);
|
||||
procedure DrawMarkerLine(C: TCanvas; W, H: Integer);
|
||||
procedure DrawSliceFilterMarkers(C: TCanvas; W, H: Integer);
|
||||
// Слайс-маркеры разделены на raw-часть (полосы, ScanLine) и canvas-часть
|
||||
// (линии/буквы): DrawSpectrum группирует raw- и canvas-операции, чтобы
|
||||
// не гонять Qt6-битмап между режимами доступа (дорогая синхронизация).
|
||||
procedure DrawSliceFilterBands(W, H: Integer);
|
||||
procedure DrawSliceFilterLines(C: TCanvas; W, H: Integer);
|
||||
procedure DrawBandLetter(C: TCanvas; X1, X2: Integer; L: Char; Clr: TColor);
|
||||
procedure DrawBeaconMarkers(C: TCanvas; W, H: Integer);
|
||||
procedure BlendBand(X1, X2, H: Integer; R, G, B, Alpha: Byte);
|
||||
procedure FillBandRaw(X1, X2, H: Integer; Color: TColor);
|
||||
procedure CopyGridToSpectrum(W, H: Integer);
|
||||
procedure DrawADCOverloadOverlay(C: TCanvas; W, H: Integer);
|
||||
procedure CalcFilterBandX(VfoFreq: Double; W: Integer;
|
||||
@@ -267,6 +273,11 @@ type
|
||||
|
||||
implementation
|
||||
|
||||
var
|
||||
// ВРЕМЕННО (perf/cpu-profiling): EWSDR_ALPHA_FIX=0 → пропустить альфа-OR
|
||||
// проход в DrawSpectrum (проверка, нужен ли он на Qt6).
|
||||
GSkipAlphaFix: Boolean = False;
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Вспомогательные функции
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
@@ -618,13 +629,53 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// Непрозрачная вертикальная полоса через raw-доступ (ScanLine) — замена
|
||||
// Canvas.FillRect для полосы фильтра в DrawSpectrum: полоса рисуется в
|
||||
// raw-фазе (между memcpy сетки и градиентом), а FillRect дёргал бы Canvas
|
||||
// и форсил лишнюю синхронизацию битмапа на Qt6.
|
||||
procedure TSpectrumView.FillBandRaw(X1, X2, H: Integer; Color: TColor);
|
||||
var
|
||||
Y, W: Integer;
|
||||
Row: PLongWord;
|
||||
Px: LongWord;
|
||||
R, G, B: Byte;
|
||||
begin
|
||||
if FSpectrumBitmap = nil then Exit;
|
||||
W := FSpectrumBitmap.Width;
|
||||
if X1 < 0 then X1 := 0;
|
||||
if X2 > W then X2 := W;
|
||||
if X2 <= X1 then Exit;
|
||||
R := Color and $FF; G := (Color shr 8) and $FF; B := (Color shr 16) and $FF;
|
||||
{$IFDEF DARWIN}
|
||||
// ARGB в памяти (см. BlendBand): байт 0 = альфа, дальше R,G,B.
|
||||
Px := LongWord($FF) or (LongWord(R) shl 8) or (LongWord(G) shl 16) or
|
||||
(LongWord(B) shl 24);
|
||||
{$ELSE}
|
||||
// BGRA в памяти: байты B,G,R,A.
|
||||
Px := LongWord(B) or (LongWord(G) shl 8) or (LongWord(R) shl 16) or $FF000000;
|
||||
{$ENDIF}
|
||||
FSpectrumBitmap.BeginUpdate(False);
|
||||
try
|
||||
for Y := 0 to H - 1 do
|
||||
begin
|
||||
Row := PLongWord(FSpectrumBitmap.ScanLine[Y]);
|
||||
if Row = nil then Continue;
|
||||
Inc(Row, X1);
|
||||
FillDWord(Row^, X2 - X1, Px);
|
||||
end;
|
||||
finally
|
||||
FSpectrumBitmap.EndUpdate(False);
|
||||
end;
|
||||
end;
|
||||
|
||||
// Маркер фильтра каждого слайса (B+) на спектре — полупрозрачная полоса
|
||||
// пропускания + края + центральная несущая. Янтарный цвет, как в GL-вьюхе
|
||||
// (SpectrumViewOpengl.DrawSliceFilterMarkers). Рисуется под кривой спектра.
|
||||
procedure TSpectrumView.DrawSliceFilterMarkers(C: TCanvas; W, H: Integer);
|
||||
// (SpectrumViewOpengl.DrawSliceFilterMarkers). Полосы (raw ScanLine-блендинг)
|
||||
// и линии/буквы (canvas) разнесены по разным процедурам — их зовут из разных
|
||||
// фаз DrawSpectrum, чтобы не чередовать режимы доступа к битмапу.
|
||||
procedure TSpectrumView.DrawSliceFilterBands(W, H: Integer);
|
||||
const
|
||||
SLICE_R = $F0; SLICE_G = $A8; SLICE_B = $10; // янтарный (совпадает с SLICE_CLR в GL)
|
||||
SLICE_CLR = TColor($0010A8F0);
|
||||
var
|
||||
i, SX1, SX2, SVfoX: Integer;
|
||||
O: TVfoOverlay;
|
||||
@@ -635,6 +686,21 @@ begin
|
||||
if (O = nil) or (not O.Visible) then Continue;
|
||||
CalcFilterBandXFor(O.DisplayVfoHz, O.DisplayMode, O.DisplayBW, W, SX1, SX2, SVfoX);
|
||||
if SX2 > SX1 then BlendBand(SX1, SX2, H, SLICE_R, SLICE_G, SLICE_B, 60);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSpectrumView.DrawSliceFilterLines(C: TCanvas; W, H: Integer);
|
||||
const
|
||||
SLICE_CLR = TColor($0010A8F0);
|
||||
var
|
||||
i, SX1, SX2, SVfoX: Integer;
|
||||
O: TVfoOverlay;
|
||||
begin
|
||||
for i := 0 to FSliceOverlays.Count - 1 do
|
||||
begin
|
||||
O := TVfoOverlay(FSliceOverlays[i]);
|
||||
if (O = nil) or (not O.Visible) then Continue;
|
||||
CalcFilterBandXFor(O.DisplayVfoHz, O.DisplayMode, O.DisplayBW, W, SX1, SX2, SVfoX);
|
||||
C.Pen.Color := SLICE_CLR; C.Pen.Width := 1; C.Pen.Style := psSolid;
|
||||
C.MoveTo(SX1, 0); C.LineTo(SX1, H);
|
||||
C.MoveTo(SX2, 0); C.LineTo(SX2, H);
|
||||
@@ -901,8 +967,11 @@ var
|
||||
LabelBandW, SrcCount: Integer;
|
||||
GridFreqS, GridLine, pixPerStep: Double;
|
||||
N, gridMult: Integer;
|
||||
PerfT0, PerfTz: Int64; // PERF
|
||||
begin
|
||||
if FSpectrumBitmap = nil then Exit;
|
||||
PerfT0 := PerfNow; // PERF
|
||||
PerfTz := PerfT0; // PERF
|
||||
W := FSpectrumBitmap.Width; H := FSpectrumBitmap.Height;
|
||||
if (W <= 0) or (H <= 0) then Exit;
|
||||
C := FSpectrumBitmap.Canvas;
|
||||
@@ -978,68 +1047,27 @@ begin
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
CopyGridToSpectrum(W, H);
|
||||
PerfAdd(pzUiSpecGrid, PerfTz); // PERF: ребилд кэша сетки (обычно 0)
|
||||
PerfTz := PerfNow; // PERF
|
||||
|
||||
// ── 2. Полоса фильтра ─────────────────────────────────────────────────────
|
||||
// ═══ Фаза 0: чистые вычисления — битмап не трогаем ═══════════════════════
|
||||
// Дальше битмап обрабатывается тремя непрерывными фазами: raw (ScanLine) →
|
||||
// canvas (QPainter) → raw. Чередование режимов доступа на Qt6 форсит
|
||||
// дорогую синхронизацию всего битмапа на каждом переходе (замерено: полоса
|
||||
// фильтра в пару тысяч пикселей стоила 4× дороже полного memcpy кадра),
|
||||
// поэтому порядок операций здесь важнее «логичной» группировки по смыслу.
|
||||
|
||||
// Полоса фильтра (X-координаты главного и TX-VFO)
|
||||
if FActiveVfo = 0 then CalcFilterBandX(FVfoA, W, X1, X2, VfoX)
|
||||
else CalcFilterBandX(FVfoB, W, X1, X2, VfoX);
|
||||
if FTXOverlay then
|
||||
TXX1 := 0; TXX2 := 0; TXVfoX := 0;
|
||||
if FTXOverlay and (FTXVfoIndex <> FActiveVfo) then
|
||||
begin
|
||||
if FTXVfoIndex <> FActiveVfo then
|
||||
begin
|
||||
if X2 > X1 then BlendBand(X1, X2, H, $30, $C0, $30, 100);
|
||||
if FTXVfoIndex = 0 then CalcFilterBandX(FVfoA, W, TXX1, TXX2, TXVfoX)
|
||||
else CalcFilterBandX(FVfoB, W, TXX1, TXX2, TXVfoX);
|
||||
if TXX2 > TXX1 then BlendBand(TXX1, TXX2, H, $E0, $30, $30, 100);
|
||||
end else
|
||||
if X2 > X1 then BlendBand(X1, X2, H, $E0, $30, $30, 100);
|
||||
end else
|
||||
begin
|
||||
C.Brush.Color := FTheme.SpecFilter; C.Brush.Style := bsSolid; C.Pen.Style := psClear;
|
||||
if X2 > X1 then C.FillRect(Rect(X1, 0, X2, H));
|
||||
C.Pen.Style := psSolid;
|
||||
if FTXVfoIndex = 0 then CalcFilterBandX(FVfoA, W, TXX1, TXX2, TXVfoX)
|
||||
else CalcFilterBandX(FVfoB, W, TXX1, TXX2, TXVfoX);
|
||||
end;
|
||||
|
||||
// Буква главного флага (A) на его полосе — только когда есть слайсы,
|
||||
// иначе одиночный приём не засоряем.
|
||||
if (FSliceOverlays <> nil) and (FSliceOverlays.Count > 0) and
|
||||
(FActiveVfo = 0) and Assigned(FVfoOverlay) then
|
||||
DrawBandLetter(C, X1, X2, FVfoOverlay.SliceLetter, SliceColor(FVfoOverlay.SliceLetter));
|
||||
|
||||
// Полосы фильтра слайсов (B+) — под кривой спектра, как в GL-вьюхе.
|
||||
DrawSliceFilterMarkers(C, W, H);
|
||||
|
||||
// ── 3. AGC линии ──────────────────────────────────────────────────────────
|
||||
if FWDSPReady then
|
||||
begin
|
||||
AGCy := Round((DBmax - FAGCThresh) * InvRange * H);
|
||||
if (AGCy >= 0) and (AGCy < H) then
|
||||
begin
|
||||
C.Pen.Color := FTheme.SpecAgcColor; C.Pen.Width := 1; C.Pen.Style := psDash;
|
||||
C.MoveTo(0, AGCy); C.LineTo(W, AGCy);
|
||||
C.Pen.Style := psSolid; C.Font.Color := FTheme.SpecAgcColor; C.Font.Size := 6;
|
||||
C.TextOut(4, AGCy - 9, 'AGC T');
|
||||
end;
|
||||
AGCHangY := Round((DBmax - FAGCHangLevel) * InvRange * H);
|
||||
if (AGCHangY >= 0) and (AGCHangY < H) and (Abs(AGCHangY - AGCy) > 4) then
|
||||
begin
|
||||
C.Pen.Color := FTheme.SpecAgcHangColor; C.Pen.Width := 1; C.Pen.Style := psDot;
|
||||
C.MoveTo(0, AGCHangY); C.LineTo(W, AGCHangY);
|
||||
C.Pen.Style := psSolid; C.Font.Color := FTheme.SpecAgcHangColor; C.Font.Size := 6;
|
||||
C.TextOut(4, AGCHangY + 2, 'AGC H');
|
||||
end;
|
||||
end else begin
|
||||
AGCy := Round((DBmax - (-FAGCTop)) * InvRange * H);
|
||||
if (AGCy >= 0) and (AGCy < H) then
|
||||
begin
|
||||
C.Pen.Color := FTheme.SpecAgcColor; C.Pen.Width := 1; C.Pen.Style := psDash;
|
||||
C.MoveTo(0, AGCy); C.LineTo(W, AGCy);
|
||||
C.Pen.Style := psSolid; C.Font.Color := FTheme.SpecAgcColor; C.Font.Size := 6;
|
||||
C.TextOut(4, AGCy - 9, Format('AGC -%ddB', [FAGCTop]));
|
||||
end;
|
||||
end;
|
||||
|
||||
// ── 4. Кривая спектра ─────────────────────────────────────────────────────
|
||||
// Точки кривой спектра
|
||||
if FSpPtsLen <> W + 2 then
|
||||
begin SetLength(FSpPts, W + 2); FSpPtsLen := W + 2; end;
|
||||
SrcCount := EnsureRange(FSpectrumBufCount, 2, 1024);
|
||||
@@ -1073,18 +1101,86 @@ begin
|
||||
end;
|
||||
FSpPts[W] := Point(W-1, H); FSpPts[W+1] := Point(0, H);
|
||||
|
||||
// ── 5. Градиент (заливка под кривой) ──────────────────────────────────────
|
||||
if FFillSpectrum then
|
||||
PerfAdd(pzUiSpecCurve, PerfTz); // PERF: расчёт точек кривой
|
||||
PerfTz := PerfNow; // PERF
|
||||
|
||||
// ═══ Фаза 1: raw (ScanLine) — сетка, полосы, градиент ════════════════════
|
||||
CopyGridToSpectrum(W, H);
|
||||
PerfAdd(pzUiSpecGrid, PerfTz); // PERF: += полный memcpy сетки в битмап
|
||||
PerfTz := PerfNow; // PERF
|
||||
|
||||
if FTXOverlay then
|
||||
begin
|
||||
C.Brush.Style := bsSolid; C.Pen.Style := psClear;
|
||||
if FTXVfoIndex <> FActiveVfo then
|
||||
begin
|
||||
if X2 > X1 then BlendBand(X1, X2, H, $30, $C0, $30, 100);
|
||||
if TXX2 > TXX1 then BlendBand(TXX1, TXX2, H, $E0, $30, $30, 100);
|
||||
end else
|
||||
if X2 > X1 then BlendBand(X1, X2, H, $E0, $30, $30, 100);
|
||||
end else
|
||||
if X2 > X1 then FillBandRaw(X1, X2, H, FTheme.SpecFilter);
|
||||
|
||||
// Полосы фильтра слайсов (B+) — под градиентом/кривой, как в GL-вьюхе.
|
||||
DrawSliceFilterBands(W, H);
|
||||
|
||||
PerfAdd(pzUiSpecBands, PerfTz); // PERF: полосы фильтра (raw-заливки)
|
||||
PerfTz := PerfNow; // PERF
|
||||
|
||||
// Градиент (заливка под кривой)
|
||||
if FFillSpectrum then
|
||||
DrawSpectrumGradient(FSpPts, W, H);
|
||||
|
||||
PerfAdd(pzUiSpecCurve, PerfTz); // PERF: += градиент под кривой
|
||||
PerfTz := PerfNow; // PERF
|
||||
|
||||
// ═══ Фаза 2: canvas (QPainter) — линии, текст, кривая, маркеры ═══════════
|
||||
// Буква главного флага (A) на его полосе — только когда есть слайсы,
|
||||
// иначе одиночный приём не засоряем.
|
||||
if (FSliceOverlays <> nil) and (FSliceOverlays.Count > 0) and
|
||||
(FActiveVfo = 0) and Assigned(FVfoOverlay) then
|
||||
DrawBandLetter(C, X1, X2, FVfoOverlay.SliceLetter, SliceColor(FVfoOverlay.SliceLetter));
|
||||
|
||||
// Края/несущие/буквы слайсов (raw-полосы уже нарисованы в фазе 1).
|
||||
DrawSliceFilterLines(C, W, H);
|
||||
|
||||
// AGC линии. Кисть выставляем явно: TextOut подписей рисует фон кистью, и
|
||||
// до перестройки фаз здесь всегда была bsSolid/SpecFilter (от FillRect
|
||||
// полосы) — сохраняем тот же вид, не полагаясь на остаточное состояние.
|
||||
C.Brush.Color := FTheme.SpecFilter; C.Brush.Style := bsSolid;
|
||||
if FWDSPReady then
|
||||
begin
|
||||
AGCy := Round((DBmax - FAGCThresh) * InvRange * H);
|
||||
if (AGCy >= 0) and (AGCy < H) then
|
||||
begin
|
||||
C.Pen.Color := FTheme.SpecAgcColor; C.Pen.Width := 1; C.Pen.Style := psDash;
|
||||
C.MoveTo(0, AGCy); C.LineTo(W, AGCy);
|
||||
C.Pen.Style := psSolid; C.Font.Color := FTheme.SpecAgcColor; C.Font.Size := 6;
|
||||
C.TextOut(4, AGCy - 9, 'AGC T');
|
||||
end;
|
||||
AGCHangY := Round((DBmax - FAGCHangLevel) * InvRange * H);
|
||||
if (AGCHangY >= 0) and (AGCHangY < H) and (Abs(AGCHangY - AGCy) > 4) then
|
||||
begin
|
||||
C.Pen.Color := FTheme.SpecAgcHangColor; C.Pen.Width := 1; C.Pen.Style := psDot;
|
||||
C.MoveTo(0, AGCHangY); C.LineTo(W, AGCHangY);
|
||||
C.Pen.Style := psSolid; C.Font.Color := FTheme.SpecAgcHangColor; C.Font.Size := 6;
|
||||
C.TextOut(4, AGCHangY + 2, 'AGC H');
|
||||
end;
|
||||
end else begin
|
||||
AGCy := Round((DBmax - (-FAGCTop)) * InvRange * H);
|
||||
if (AGCy >= 0) and (AGCy < H) then
|
||||
begin
|
||||
C.Pen.Color := FTheme.SpecAgcColor; C.Pen.Width := 1; C.Pen.Style := psDash;
|
||||
C.MoveTo(0, AGCy); C.LineTo(W, AGCy);
|
||||
C.Pen.Style := psSolid; C.Font.Color := FTheme.SpecAgcColor; C.Font.Size := 6;
|
||||
C.TextOut(4, AGCy - 9, Format('AGC -%ddB', [FAGCTop]));
|
||||
end;
|
||||
end;
|
||||
|
||||
// ── 6. Линия спектра ──────────────────────────────────────────────────────
|
||||
// Линия спектра
|
||||
C.Pen.Style := psSolid; C.Pen.Color := FTheme.SpecLine; C.Pen.Width := 1;
|
||||
C.Polyline(Slice(FSpPts, W));
|
||||
|
||||
// ── 7. Края фильтра + VFO ─────────────────────────────────────────────────
|
||||
// Края фильтра + VFO
|
||||
C.Pen.Color := FTheme.SpecFilterEdge; C.Pen.Width := 1; C.Pen.Style := psSolid;
|
||||
C.MoveTo(X1, 0); C.LineTo(X1, H);
|
||||
C.MoveTo(X2, 0); C.LineTo(X2, H);
|
||||
@@ -1106,6 +1202,11 @@ begin
|
||||
if FMarkerActive then DrawMarkerLine(C, W, H);
|
||||
if FBeaconMarkActive or FBeaconDecActive then DrawBeaconMarkers(C, W, H);
|
||||
DrawADCOverloadOverlay(C, W, H);
|
||||
|
||||
PerfAdd(pzUiSpecOverlays, PerfTz); // PERF: canvas-фаза (линии/текст/кривая)
|
||||
PerfTz := PerfNow; // PERF
|
||||
|
||||
// ═══ Фаза 3: raw — композиты оверлеев + альфа-проход ═════════════════════
|
||||
// Бэндплан QO-100 — полоска внизу спектра (над ruler), под панелями оверлеев.
|
||||
if Assigned(FBandPlanOverlay) then
|
||||
FBandPlanOverlay.DrawOverlay(FSpectrumBitmap, W, H);
|
||||
@@ -1121,20 +1222,29 @@ begin
|
||||
// (Canvas-операции сохраняют альфу $FF), поэтому там его не делаем.
|
||||
// На Qt6/win32 бэкенд другой и сглаженные края могут занулять альфу —
|
||||
// оставляем быстрый dword-OR до проверки на этих платформах.
|
||||
// ВРЕМЕННО (perf/cpu-profiling): EWSDR_ALPHA_FIX=0 пропускает проход —
|
||||
// для визуальной проверки, нужен ли он на Qt6 вообще (подозрение: нет,
|
||||
// SourceOver поверх непрозрачного фона альфу не занижает). Если артефактов
|
||||
// не будет — проход можно удалить совсем.
|
||||
{$IFNDEF DARWIN}
|
||||
FSpectrumBitmap.BeginUpdate(False);
|
||||
for i := 0 to H - 1 do
|
||||
if not GSkipAlphaFix then
|
||||
begin
|
||||
RowLW := PLongWord(FSpectrumBitmap.ScanLine[i]);
|
||||
if RowLW = nil then Continue;
|
||||
for Yp := 0 to W - 1 do
|
||||
FSpectrumBitmap.BeginUpdate(False);
|
||||
for i := 0 to H - 1 do
|
||||
begin
|
||||
RowLW^ := RowLW^ or $FF000000; // BGRA: альфа в байте 3
|
||||
Inc(RowLW);
|
||||
RowLW := PLongWord(FSpectrumBitmap.ScanLine[i]);
|
||||
if RowLW = nil then Continue;
|
||||
for Yp := 0 to W - 1 do
|
||||
begin
|
||||
RowLW^ := RowLW^ or $FF000000; // BGRA: альфа в байте 3
|
||||
Inc(RowLW);
|
||||
end;
|
||||
end;
|
||||
FSpectrumBitmap.EndUpdate(False);
|
||||
end;
|
||||
FSpectrumBitmap.EndUpdate(False);
|
||||
{$ENDIF}
|
||||
PerfAdd(pzUiSpecAlpha, PerfTz); // PERF: композиты флагов + альфа-OR проход
|
||||
PerfAdd(pzUiDrawSpectrum, PerfT0); // PERF: CPU-рендер кадра спектра
|
||||
end;
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
@@ -1142,8 +1252,11 @@ end;
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
procedure TSpectrumView.DrawWaterfall;
|
||||
var T0: Int64; // PERF
|
||||
begin
|
||||
T0 := PerfNow; // PERF
|
||||
FWaterfall.DrawWaterfall;
|
||||
PerfAdd(pzUiDrawWaterfall, T0); // PERF: CPU-рендер строк водопада
|
||||
end;
|
||||
|
||||
procedure TSpectrumView.DrawRuler;
|
||||
@@ -1156,15 +1269,22 @@ end;
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
procedure TSpectrumView.PaintSpectrum(Sender: TObject);
|
||||
var PB: TPaintBox;
|
||||
var
|
||||
PB: TPaintBox;
|
||||
T0: Int64; // PERF
|
||||
begin
|
||||
T0 := PerfNow; // PERF
|
||||
PB := TPaintBox(Sender);
|
||||
PB.Canvas.Draw(0, 0, FSpectrumBitmap);
|
||||
PerfAdd(pzUiPaintSpectrum, T0); // PERF: блит битмапа спектра (Qt6 canvas)
|
||||
end;
|
||||
|
||||
procedure TSpectrumView.PaintWaterfall(Sender: TObject);
|
||||
var T0: Int64; // PERF
|
||||
begin
|
||||
T0 := PerfNow; // PERF
|
||||
FWaterfall.PaintWaterfall(Sender);
|
||||
PerfAdd(pzUiPaintWaterfall, T0); // PERF: блит битмапа водопада (Qt6 canvas)
|
||||
end;
|
||||
|
||||
procedure TSpectrumView.PaintRuler(Sender: TObject);
|
||||
@@ -1177,4 +1297,7 @@ begin
|
||||
FSMeter.PaintSMeterRight(Sender);
|
||||
end;
|
||||
|
||||
initialization
|
||||
GSkipAlphaFix := GetEnvironmentVariable('EWSDR_ALPHA_FIX') = '0';
|
||||
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user