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;
StartupVfoA, StartupVfoB: Double;
begin
SetExceptionMask(GetExceptionMask + [exZeroDivide, exInvalidOp]);
FVfoA := 14200000;
FVfoB := 7100000;
FActiveVfo := 0;
@@ -1933,6 +1934,7 @@ begin
PanelRight.Parent := Self;
PanelRight.Align := alClient;
PanelRight.BevelOuter := bvNone;
PanelRight.DoubleBuffered := True;
PanelRight.OnResize := RightPanelResize;
FSampleRateOverlay := TSampleRateOverlay.Create(Self);
+26 -64
View File
@@ -19,7 +19,7 @@ interface
uses
Classes, SysUtils, Graphics, ExtCtrls, Controls, Math,
IntfGraphics, FPImage, LCLIntf, LCLType, GraphType, AppTheme,
LCLIntf, LCLType, AppTheme,
AlertOverlay, SampleRateOverlay, VfoOverlay,
WaterfallView, SMeterView, RulerView;
@@ -37,8 +37,6 @@ type
FFMGridLastCenter: Double;
FFMGridLastStepHz: Double;
FFMGridLastSpan: Double;
FSpecGradImg: TLazIntfImage;
FSpecGradBmp: TBitmap;
FSpPts: array of TPoint;
FSpPtsLen: Integer;
// ── Тема ─────────────────────────────────────────────────────────────────
@@ -248,23 +246,6 @@ begin
Result := Format('%d.%3.3d.%3.3d', [Mhz, KHz, Rest]);
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;
var
@@ -301,8 +282,6 @@ begin
FSpectrumBitmap := TBitmap.Create;
FSpectrumBitmap.PixelFormat := pf32bit;
FGridBitmap := TBitmap.Create;
FSpecGradBmp := TBitmap.Create;
FSpecGradImg := nil;
FGridBitmapW := 0; FGridBitmapH := 0;
FFMGridLastCenter := -1.0; FFMGridLastStepHz := -1.0; FFMGridLastSpan := -1.0;
FFMGridStepHz := 0.0;
@@ -334,8 +313,6 @@ destructor TSpectrumView.Destroy;
begin
FSpectrumBitmap.Free;
FGridBitmap.Free;
FSpecGradBmp.Free;
FreeAndNil(FSpecGradImg);
FWaterfall.Free;
FSMeter.Free;
FRuler.Free;
@@ -550,9 +527,9 @@ end;
procedure TSpectrumView.DrawSpectrumGradient(const SpPts: array of TPoint; W, H: Integer);
var
Row, Col: Integer; YMin, Alpha: Integer;
RowPtr: PByte; BPPg: Integer; RG, GG: Byte;
Desc: TRawImageDescription;
Row, Col, Alpha, YMin, Off: Integer;
RowPtr: PByte;
GradB, GradG, GradR: Byte;
begin
if FSpectrumBitmap = nil then Exit;
if (W <= 0) or (H <= 0) then Exit;
@@ -560,45 +537,27 @@ begin
for Col := 0 to W - 1 do
if SpPts[Col].Y < YMin then YMin := SpPts[Col].Y;
if YMin >= H then Exit;
if (FSpecGradImg = nil) or (FSpecGradImg.Width <> W) or (FSpecGradImg.Height <> H) then
begin
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;
FSpectrumBitmap.BeginUpdate(False);
for Row := YMin to H - 1 do
begin
Alpha := Round((1.0 - Sqr((Row - YMin) / Max(1.0, H - YMin - 1.0))) * 200);
if Alpha <= 0 then Continue;
if Alpha > 200 then Alpha := 200;
GG := Byte(FTheme.SpecGradB * Alpha div 200);
RG := Byte(FTheme.SpecGradG * Alpha div 200);
RowPtr := FSpecGradImg.GetDataLineStart(Row);
if RowPtr = nil then Continue;
GradB := Byte(FTheme.SpecGradB * Alpha div 200);
GradG := Byte(FTheme.SpecGradG * Alpha div 200);
GradR := Byte(FTheme.SpecGradR * Alpha div 200);
RowPtr := PByte(FSpectrumBitmap.ScanLine[Row]);
for Col := 0 to W - 1 do
begin
if SpPts[Col].Y <= Row then
begin
RowPtr[0] := GG;
RowPtr[1] := RG;
RowPtr[2] := Byte(FTheme.SpecGradR * Alpha div 200);
if BPPg >= 4 then RowPtr[3] := Byte(Alpha);
end else begin
RowPtr[0] := 0; RowPtr[1] := 0; RowPtr[2] := 0;
if BPPg >= 4 then RowPtr[3] := 0;
end;
Inc(RowPtr, BPPg);
Off := Col * 4;
RowPtr[Off] := (GradB * Alpha + RowPtr[Off] * (200 - Alpha)) div 200;
RowPtr[Off+1] := (GradG * Alpha + RowPtr[Off+1] * (200 - Alpha)) div 200;
RowPtr[Off+2] := (GradR * Alpha + RowPtr[Off+2] * (200 - Alpha)) div 200;
end;
end;
FSpecGradBmp.LoadFromIntfImage(FSpecGradImg);
LCLIntf.BitBlt(FSpectrumBitmap.Canvas.Handle, 0, 0, W, H,
FSpecGradBmp.Canvas.Handle, 0, 0, $CC0020);
FSpectrumBitmap.EndUpdate(False);
end;
// ────────────────────────────────────────────────────────────────────────────
@@ -629,7 +588,6 @@ begin
FSpectrumBitmap.SetSize(W, H);
FSpectrumBitmap.Canvas.Brush.Color := FTheme.BG;
FSpectrumBitmap.Canvas.FillRect(Rect(0, 0, W, H));
FreeAndNil(FSpecGradImg);
InvalidateGridCache;
FSpPtsLen := 0;
end;
@@ -663,7 +621,6 @@ procedure TSpectrumView.SetTheme(const T: TAppTheme);
begin
FTheme := T;
FLightTheme := T.BG > TColor($00808080);
FreeAndNil(FSpecGradImg);
InvalidateGridCache;
FWaterfall.SetTheme(T);
FSMeter.SetTheme(T);
@@ -716,6 +673,7 @@ procedure TSpectrumView.DrawSpectrum;
var
C, GC: TCanvas;
i, Yp, W, H, GX: Integer;
AlphaRow: PCardinal;
DBmin, DBmax, dB: Double;
VfoX, X1, X2: Integer;
TXVfoX, TXX1, TXX2: Integer;
@@ -922,6 +880,15 @@ begin
FSampleRateOverlay.DrawOverlay(FSpectrumBitmap, C, W, H);
if Assigned(FVfoOverlay) then
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;
// ────────────────────────────────────────────────────────────────────────────
@@ -946,12 +913,7 @@ procedure TSpectrumView.PaintSpectrum(Sender: TObject);
var PB: TPaintBox;
begin
PB := TPaintBox(Sender);
if (FSpectrumBitmap.Width > 0) and (FSpectrumBitmap.Height > 0) then
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;
PB.Canvas.Draw(0, 0, FSpectrumBitmap);
end;
procedure TSpectrumView.PaintWaterfall(Sender: TObject);