mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 17:27:32 +00:00
perf(spectrum): full-raw CPU renderer + dword blenders (frame 8.3ms -> 1.7ms)
Canvas на битмапе кадра больше не используется вообще (кроме редкого ADC-overload пути с восстановлением альфы) — убраны все raw<->canvas переходы, каждый из которых синкал весь битмап на Qt6 (~2мс): - RawBegin/RawEnd: прямой доступ к пикселям через RawImage.Data + BytesPerLine (bottom-up DIB win32 учтён отрицательным шагом) - RawVLine/RawHLine (с пунктиром), RawFillRect, RawTriangleDown, RawCurve (кривая = связные вертикальные сегменты по колонкам) - кэш текстовых масок (TRawTextMask, LRU 48): строка рендерится canvas'ом один раз белым-на-чёрном в свой мини-битмап, блитится raw с цветом; все тексты кадра теперь Courier New - конвертированы: маркер (метка без случайной цветной плашки), бикон- маркеры, буквы слайсов, слайс-линии, AGC (пунктир 4/2 и 1/2, подпись с фоном SpecFilter как раньше), края/VFO/TX-курсоры с треугольниками - пофреймовый альфа-OR проход удалён: альфа чинится один раз в кэше СЕТКИ после ребилда (canvas-текст там), кадр наследует её через memcpy Дворд-блендеры (два 16-бит лейна на умножение, /256 вместо /255, расхождение <0.4%) вместо побайтовых с div 255: - BandPlanOverlay.CompositeStrip (~1мс -> ~0.2мс) - SampleRateOverlay.CompositeCache (per-px альфа) - VfoOverlay.BlendBitmapKey (keyed-магента дворд-сравнением) - SpectrumView.DrawSpectrumGradient (source-лейны 1 раз на строку, ~1.6мс -> ~0.8мс) Порог перестройки бэндплана: полпикселя вместо 1 Гц (на QO-100 с decoder-lock центр подтюнивается непрерывно — был canvas-ребилд полоски каждый кадр). Композиты внутри raw-лока (их BeginUpdate вложенные). PerfLog: зона ui.composites отделена от ui.spec_alpha (=RawEnd). Замер на эфире (Pluto, 576k, 52fps): кадр 8.3мс -> 1.67мс (5x), со слайсом 2.1-2.3мс; UI-поток ~45% -> ~26% ядра, из них 15% — блиты paint_spectrum/paint_waterfall (потолок Qt6-вывода). Визуально проверено. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+29
-21
@@ -273,9 +273,13 @@ const
|
||||
DB_S: array[1..9] of Double = (-121,-115,-109,-103,-97,-91,-85,-79,-73);
|
||||
|
||||
procedure BlendBitmapKey(Target, Source: TBitmap; DstX, DstY: Integer; Alpha: Byte);
|
||||
// Дворд-блендинг (два 16-битных лейна на умножение, /256 вместо /255 —
|
||||
// расхождение <0.4%): побайтовый вариант с div 255 на 2 флагах стоил ~0.6мс.
|
||||
// Keyed-пиксели (магента) пропускаются сравнением цветовых байтов дворда.
|
||||
var
|
||||
Y, X, SX0, SY0, SX1, SY1, TY, InvA: Integer;
|
||||
SrcRow, DstRow: PByte;
|
||||
Y, X, SX0, SY0, SX1, SY1, TY: Integer;
|
||||
A256, I256, S, D: LongWord;
|
||||
SrcRow, DstRow: PLongWord;
|
||||
begin
|
||||
if (Target = nil) or (Source = nil) or (Alpha = 0) then Exit;
|
||||
SX0 := 0; SY0 := 0;
|
||||
@@ -286,37 +290,41 @@ begin
|
||||
if DstY + (SY1 - SY0) > Target.Height then SY1 := SY0 + Target.Height - DstY;
|
||||
if (SX1 <= SX0) or (SY1 <= SY0) then Exit;
|
||||
|
||||
InvA := 255 - Alpha;
|
||||
A256 := Alpha + (Alpha shr 7); // 0..256
|
||||
I256 := 256 - A256;
|
||||
Target.BeginUpdate(False);
|
||||
Source.BeginUpdate(False);
|
||||
try
|
||||
for Y := SY0 to SY1 - 1 do
|
||||
begin
|
||||
TY := DstY + (Y - SY0);
|
||||
SrcRow := PByte(Source.ScanLine[Y]);
|
||||
DstRow := PByte(Target.ScanLine[TY]);
|
||||
SrcRow := PLongWord(Source.ScanLine[Y]);
|
||||
DstRow := PLongWord(Target.ScanLine[TY]);
|
||||
if (SrcRow = nil) or (DstRow = nil) then Continue;
|
||||
Inc(SrcRow, SX0 * 4);
|
||||
Inc(DstRow, DstX * 4);
|
||||
Inc(SrcRow, SX0);
|
||||
Inc(DstRow, DstX);
|
||||
for X := SX0 to SX1 - 1 do
|
||||
begin
|
||||
S := SrcRow^;
|
||||
{$IFDEF DARWIN}
|
||||
if not ((SrcRow[1] = $FF) and (SrcRow[2] = $00) and (SrcRow[3] = $FF)) then
|
||||
begin
|
||||
DstRow[1] := Byte((Alpha * SrcRow[1] + InvA * DstRow[1]) div 255);
|
||||
DstRow[2] := Byte((Alpha * SrcRow[2] + InvA * DstRow[2]) div 255);
|
||||
DstRow[3] := Byte((Alpha * SrcRow[3] + InvA * DstRow[3]) div 255);
|
||||
end;
|
||||
if (S and $FFFFFF00) <> $FF00FF00 then // ARGB: R=FF,G=00,B=FF
|
||||
{$ELSE}
|
||||
if not ((SrcRow[0] = $FF) and (SrcRow[1] = $00) and (SrcRow[2] = $FF)) then
|
||||
begin
|
||||
DstRow[0] := Byte((Alpha * SrcRow[0] + InvA * DstRow[0]) div 255);
|
||||
DstRow[1] := Byte((Alpha * SrcRow[1] + InvA * DstRow[1]) div 255);
|
||||
DstRow[2] := Byte((Alpha * SrcRow[2] + InvA * DstRow[2]) div 255);
|
||||
end;
|
||||
if (S and $00FFFFFF) <> $00FF00FF then // BGRA: B=FF,G=00,R=FF
|
||||
{$ENDIF}
|
||||
Inc(SrcRow, 4);
|
||||
Inc(DstRow, 4);
|
||||
begin
|
||||
D := DstRow^;
|
||||
DstRow^ := ((((S and $00FF00FF) * A256 + (D and $00FF00FF) * I256)
|
||||
shr 8) and $00FF00FF)
|
||||
or ((((S shr 8) and $00FF00FF) * A256 +
|
||||
((D shr 8) and $00FF00FF) * I256) and $FF00FF00)
|
||||
{$IFDEF DARWIN}
|
||||
or $000000FF;
|
||||
{$ELSE}
|
||||
or $FF000000;
|
||||
{$ENDIF}
|
||||
end;
|
||||
Inc(SrcRow);
|
||||
Inc(DstRow);
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
|
||||
Reference in New Issue
Block a user