Fix spectrum invisible on win32 and mask WDSP FPU exceptions

SpectrumView: rewrite DrawSpectrumGradient to blend directly into
FSpectrumBitmap via ScanLine instead of TLazIntfImage+BitBlt (stale DC
on win32). Add alpha=$FF fixup pass so pf32bit Canvas.Draw renders via
StretchBlt not AlphaBlend. Remove FSpecGradImg/FSpecGradBmp fields.

MainForm: mask exZeroDivide/exInvalidOp in FormCreate so WDSP DLL
divide-by-zero does not crash the DSP thread on win32 (Qt6 already
masks FPU exceptions globally).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-24 13:51:13 +03:00
co-authored by Claude Sonnet 4.6
parent c5f225332b
commit 3bfd9adf0d
2 changed files with 29 additions and 65 deletions
+2
View File
@@ -1160,6 +1160,7 @@ var
WebCfg: TWebSettings; WebCfg: TWebSettings;
StartupVfoA, StartupVfoB: Double; StartupVfoA, StartupVfoB: Double;
begin begin
SetExceptionMask(GetExceptionMask + [exZeroDivide, exInvalidOp]);
FVfoA := 14200000; FVfoA := 14200000;
FVfoB := 7100000; FVfoB := 7100000;
FActiveVfo := 0; FActiveVfo := 0;
@@ -1933,6 +1934,7 @@ begin
PanelRight.Parent := Self; PanelRight.Parent := Self;
PanelRight.Align := alClient; PanelRight.Align := alClient;
PanelRight.BevelOuter := bvNone; PanelRight.BevelOuter := bvNone;
PanelRight.DoubleBuffered := True;
PanelRight.OnResize := RightPanelResize; PanelRight.OnResize := RightPanelResize;
FSampleRateOverlay := TSampleRateOverlay.Create(Self); FSampleRateOverlay := TSampleRateOverlay.Create(Self);
+26 -64
View File
@@ -19,7 +19,7 @@ interface
uses uses
Classes, SysUtils, Graphics, ExtCtrls, Controls, Math, Classes, SysUtils, Graphics, ExtCtrls, Controls, Math,
IntfGraphics, FPImage, LCLIntf, LCLType, GraphType, AppTheme, LCLIntf, LCLType, AppTheme,
AlertOverlay, SampleRateOverlay, VfoOverlay, AlertOverlay, SampleRateOverlay, VfoOverlay,
WaterfallView, SMeterView, RulerView; WaterfallView, SMeterView, RulerView;
@@ -37,8 +37,6 @@ type
FFMGridLastCenter: Double; FFMGridLastCenter: Double;
FFMGridLastStepHz: Double; FFMGridLastStepHz: Double;
FFMGridLastSpan: Double; FFMGridLastSpan: Double;
FSpecGradImg: TLazIntfImage;
FSpecGradBmp: TBitmap;
FSpPts: array of TPoint; FSpPts: array of TPoint;
FSpPtsLen: Integer; FSpPtsLen: Integer;
// ── Тема ───────────────────────────────────────────────────────────────── // ── Тема ─────────────────────────────────────────────────────────────────
@@ -248,23 +246,6 @@ begin
Result := Format('%d.%3.3d.%3.3d', [Mhz, KHz, Rest]); Result := Format('%d.%3.3d.%3.3d', [Mhz, KHz, Rest]);
end; end;
procedure InitRawDesc32(var Desc: TRawImageDescription; AWidth, AHeight: Integer);
begin
FillChar(Desc, SizeOf(Desc), 0);
Desc.Format := ricfRGBA;
Desc.Width := AWidth;
Desc.Height := AHeight;
Desc.Depth := 32;
Desc.BitOrder := riboBitsInOrder;
Desc.ByteOrder := riboLSBFirst;
Desc.LineOrder := riloTopToBottom;
Desc.BitsPerPixel := 32;
Desc.LineEnd := rileDWordBoundary;
Desc.BlueShift := 0; Desc.BluePrec := 8;
Desc.GreenShift := 8; Desc.GreenPrec := 8;
Desc.RedShift := 16; Desc.RedPrec := 8;
Desc.AlphaShift := 24; Desc.AlphaPrec := 8;
end;
function MixColorBGR(C1, C2: TColor; T: Double): TColor; function MixColorBGR(C1, C2: TColor; T: Double): TColor;
var var
@@ -301,8 +282,6 @@ begin
FSpectrumBitmap := TBitmap.Create; FSpectrumBitmap := TBitmap.Create;
FSpectrumBitmap.PixelFormat := pf32bit; FSpectrumBitmap.PixelFormat := pf32bit;
FGridBitmap := TBitmap.Create; FGridBitmap := TBitmap.Create;
FSpecGradBmp := TBitmap.Create;
FSpecGradImg := nil;
FGridBitmapW := 0; FGridBitmapH := 0; FGridBitmapW := 0; FGridBitmapH := 0;
FFMGridLastCenter := -1.0; FFMGridLastStepHz := -1.0; FFMGridLastSpan := -1.0; FFMGridLastCenter := -1.0; FFMGridLastStepHz := -1.0; FFMGridLastSpan := -1.0;
FFMGridStepHz := 0.0; FFMGridStepHz := 0.0;
@@ -334,8 +313,6 @@ destructor TSpectrumView.Destroy;
begin begin
FSpectrumBitmap.Free; FSpectrumBitmap.Free;
FGridBitmap.Free; FGridBitmap.Free;
FSpecGradBmp.Free;
FreeAndNil(FSpecGradImg);
FWaterfall.Free; FWaterfall.Free;
FSMeter.Free; FSMeter.Free;
FRuler.Free; FRuler.Free;
@@ -550,9 +527,9 @@ end;
procedure TSpectrumView.DrawSpectrumGradient(const SpPts: array of TPoint; W, H: Integer); procedure TSpectrumView.DrawSpectrumGradient(const SpPts: array of TPoint; W, H: Integer);
var var
Row, Col: Integer; YMin, Alpha: Integer; Row, Col, Alpha, YMin, Off: Integer;
RowPtr: PByte; BPPg: Integer; RG, GG: Byte; RowPtr: PByte;
Desc: TRawImageDescription; GradB, GradG, GradR: Byte;
begin begin
if FSpectrumBitmap = nil then Exit; if FSpectrumBitmap = nil then Exit;
if (W <= 0) or (H <= 0) then Exit; if (W <= 0) or (H <= 0) then Exit;
@@ -560,45 +537,27 @@ begin
for Col := 0 to W - 1 do for Col := 0 to W - 1 do
if SpPts[Col].Y < YMin then YMin := SpPts[Col].Y; if SpPts[Col].Y < YMin then YMin := SpPts[Col].Y;
if YMin >= H then Exit; if YMin >= H then Exit;
if (FSpecGradImg = nil) or (FSpecGradImg.Width <> W) or (FSpecGradImg.Height <> H) then
begin FSpectrumBitmap.BeginUpdate(False);
FreeAndNil(FSpecGradImg);
FSpecGradImg := TLazIntfImage.Create(W, H);
InitRawDesc32(Desc, W, H);
FSpecGradImg.DataDescription := Desc;
FSpecGradImg.CreateData;
end;
if FSpecGradImg.PixelData <> nil then
FillChar(FSpecGradImg.PixelData^, W * H * 4, 0);
BPPg := FSpecGradImg.DataDescription.BitsPerPixel div 8;
if BPPg < 3 then BPPg := 4;
for Row := YMin to H - 1 do for Row := YMin to H - 1 do
begin begin
Alpha := Round((1.0 - Sqr((Row - YMin) / Max(1.0, H - YMin - 1.0))) * 200); Alpha := Round((1.0 - Sqr((Row - YMin) / Max(1.0, H - YMin - 1.0))) * 200);
if Alpha <= 0 then Continue; if Alpha <= 0 then Continue;
if Alpha > 200 then Alpha := 200; if Alpha > 200 then Alpha := 200;
GG := Byte(FTheme.SpecGradB * Alpha div 200); GradB := Byte(FTheme.SpecGradB * Alpha div 200);
RG := Byte(FTheme.SpecGradG * Alpha div 200); GradG := Byte(FTheme.SpecGradG * Alpha div 200);
RowPtr := FSpecGradImg.GetDataLineStart(Row); GradR := Byte(FTheme.SpecGradR * Alpha div 200);
if RowPtr = nil then Continue; RowPtr := PByte(FSpectrumBitmap.ScanLine[Row]);
for Col := 0 to W - 1 do for Col := 0 to W - 1 do
begin
if SpPts[Col].Y <= Row then if SpPts[Col].Y <= Row then
begin begin
RowPtr[0] := GG; Off := Col * 4;
RowPtr[1] := RG; RowPtr[Off] := (GradB * Alpha + RowPtr[Off] * (200 - Alpha)) div 200;
RowPtr[2] := Byte(FTheme.SpecGradR * Alpha div 200); RowPtr[Off+1] := (GradG * Alpha + RowPtr[Off+1] * (200 - Alpha)) div 200;
if BPPg >= 4 then RowPtr[3] := Byte(Alpha); RowPtr[Off+2] := (GradR * Alpha + RowPtr[Off+2] * (200 - Alpha)) div 200;
end else begin
RowPtr[0] := 0; RowPtr[1] := 0; RowPtr[2] := 0;
if BPPg >= 4 then RowPtr[3] := 0;
end;
Inc(RowPtr, BPPg);
end; end;
end; end;
FSpecGradBmp.LoadFromIntfImage(FSpecGradImg); FSpectrumBitmap.EndUpdate(False);
LCLIntf.BitBlt(FSpectrumBitmap.Canvas.Handle, 0, 0, W, H,
FSpecGradBmp.Canvas.Handle, 0, 0, $CC0020);
end; end;
// ──────────────────────────────────────────────────────────────────────────── // ────────────────────────────────────────────────────────────────────────────
@@ -629,7 +588,6 @@ begin
FSpectrumBitmap.SetSize(W, H); FSpectrumBitmap.SetSize(W, H);
FSpectrumBitmap.Canvas.Brush.Color := FTheme.BG; FSpectrumBitmap.Canvas.Brush.Color := FTheme.BG;
FSpectrumBitmap.Canvas.FillRect(Rect(0, 0, W, H)); FSpectrumBitmap.Canvas.FillRect(Rect(0, 0, W, H));
FreeAndNil(FSpecGradImg);
InvalidateGridCache; InvalidateGridCache;
FSpPtsLen := 0; FSpPtsLen := 0;
end; end;
@@ -663,7 +621,6 @@ procedure TSpectrumView.SetTheme(const T: TAppTheme);
begin begin
FTheme := T; FTheme := T;
FLightTheme := T.BG > TColor($00808080); FLightTheme := T.BG > TColor($00808080);
FreeAndNil(FSpecGradImg);
InvalidateGridCache; InvalidateGridCache;
FWaterfall.SetTheme(T); FWaterfall.SetTheme(T);
FSMeter.SetTheme(T); FSMeter.SetTheme(T);
@@ -716,6 +673,7 @@ procedure TSpectrumView.DrawSpectrum;
var var
C, GC: TCanvas; C, GC: TCanvas;
i, Yp, W, H, GX: Integer; i, Yp, W, H, GX: Integer;
AlphaRow: PCardinal;
DBmin, DBmax, dB: Double; DBmin, DBmax, dB: Double;
VfoX, X1, X2: Integer; VfoX, X1, X2: Integer;
TXVfoX, TXX1, TXX2: Integer; TXVfoX, TXX1, TXX2: Integer;
@@ -922,6 +880,15 @@ begin
FSampleRateOverlay.DrawOverlay(FSpectrumBitmap, C, W, H); FSampleRateOverlay.DrawOverlay(FSpectrumBitmap, C, W, H);
if Assigned(FVfoOverlay) then if Assigned(FVfoOverlay) then
FVfoOverlay.DrawOverlay(FSpectrumBitmap, W, H); FVfoOverlay.DrawOverlay(FSpectrumBitmap, W, H);
FSpectrumBitmap.BeginUpdate(False);
for i := 0 to H - 1 do
begin
AlphaRow := PCardinal(FSpectrumBitmap.ScanLine[i]);
for Yp := 0 to W - 1 do
AlphaRow[Yp] := AlphaRow[Yp] or $FF000000;
end;
FSpectrumBitmap.EndUpdate(False);
end; end;
// ──────────────────────────────────────────────────────────────────────────── // ────────────────────────────────────────────────────────────────────────────
@@ -946,12 +913,7 @@ procedure TSpectrumView.PaintSpectrum(Sender: TObject);
var PB: TPaintBox; var PB: TPaintBox;
begin begin
PB := TPaintBox(Sender); PB := TPaintBox(Sender);
if (FSpectrumBitmap.Width > 0) and (FSpectrumBitmap.Height > 0) then PB.Canvas.Draw(0, 0, FSpectrumBitmap);
PB.Canvas.Draw(0, 0, FSpectrumBitmap)
else begin
PB.Canvas.Brush.Color := SV_CLR_BG;
PB.Canvas.FillRect(Rect(0, 0, PB.Width, PB.Height));
end;
end; end;
procedure TSpectrumView.PaintWaterfall(Sender: TObject); procedure TSpectrumView.PaintWaterfall(Sender: TObject);