내 파형 차트의 렌더링 성능을 향상시킬 수있는 방법을 찾고 있습니다. (내가 가능한 생각만큼) 현재 내가 일상적인 렌더링 최적화 된 GDI 기반을 사용하고 있습니다 :많은 양의 선 그리기.
Private Sub Calculate2(ByVal aData()() As Double)
'aData size: 1000 traces with 200k points each -> Dim aData(1000, 200000)
'Some data preparations doing roughly the same as they would in the real app
Dim PS_Y As Double = 1
Dim Origin As PointF = New PointF(Rnd() * 100, Rnd() * 100)
PS_Y = Rnd() + 0.1
Dim Data(), ST As Double
Dim lPoints As New List(Of PointF)
Dim PS_X As Double = Rnd() + 0.1
'Graphics initialisation
Dim Img As New Bitmap(900, 600)
Dim ImgGR As Graphics = Graphics.FromImage(Img)
ImgGR.Clear(Color.White)
Dim WFPen As New Pen(Brushes.Black, 1)
'Cache property values for faster access:
Dim l As Integer = 100 'ChartRect.Left
Dim r As Integer = 1000 'ChartRect.Right
'Process trace by trace:
For i = 0 To aData.Length - 1
ST = Rnd() 'x distance of the points
Data = aData(i) 'y values, 1 per x value
If Data.Length = 0 Then Continue For
'scale precalculations, first & last displayed points:
Dim ScaleX As Double = ST * PS_X
Dim OrigX As Single = Origin.X
Dim iStart As Integer = (l - OrigX)/ScaleX
Dim iEnd As Integer = (r - OrigX)/ScaleX
If iStart < 0 Then iStart = 0
If iEnd < 0 Then iEnd = 0
If iEnd > Data.Length - 1 Then iEnd = Data.Length - 1
If iStart > Data.Length - 1 Then iStart = Data.Length - 1
'Make sure that for benchmarking purposes all points are displayed, next 2 lines do not exist in real code:
iStart = 0
iEnd = Data.Length - 1
If iEnd < iStart Then Continue For
'point calculations using the pecalculated values:
Dim APT(iEnd - iStart) As PointF
For j = iStart To iEnd
APT(j - iStart) = Origin + New SizeF(j * ScaleX, -(Data(j) * PS_Y))
Next
ImgGR.DrawLines(WFPen, APT)
'Commenting out this line reduces the time needed for executing this whole routine from 42.4s to 4.76s
'Hence most of the time spent even with all the scaling is still in rendering the spline.
Next
내가 Direct2D의와 접근 방식을 시도하지만 GDI에서 "DrawLines"방법보다 훨씬 느렸다 :
를'Imports D2D = Microsoft.WindowsAPICodePack.DirectX.Direct2D1
'Imports DX = Microsoft.WindowsAPICodePack.DirectX
Dim TGT As D2D.RenderTarget
Private Sub initd2d()
Dim fac As D2D.D2DFactory = D2D.D2DFactory.CreateFactory(Microsoft.WindowsAPICodePack.DirectX.Direct2D1.D2DFactoryType.SingleThreaded)
Dim imgf As DX.WindowsImagingComponent.ImagingFactory
imgf = DX.WindowsImagingComponent.ImagingFactory.Create
'Dim pf As New D2D.PixelFormat(DX.Graphics.Format.B8G8R8A8UNorm, D2D.AlphaMode.Ignore)
Dim pf As New D2D.PixelFormat(DX.Graphics.Format.Unknown, D2D.AlphaMode.Unknown)
Dim bmp As DX.WindowsImagingComponent.ImagingBitmap
bmp = imgf.CreateImagingBitmap(CUInt(900), CUInt(600), DX.WindowsImagingComponent.PixelFormats.Pbgra32Bpp, DX.WindowsImagingComponent.BitmapCreateCacheOption.CacheOnLoad)
Dim rtp As New D2D.RenderTargetProperties(D2D.RenderTargetType.Default, pf, 0, 0, D2D.RenderTargetUsages.None, Microsoft.WindowsAPICodePack.DirectX.Direct3D.FeatureLevel.Default)
TGT = fac.CreateWicBitmapRenderTarget(bmp, rtp)
TGT.Clear(New D2D.ColorF(Color.White.ToArgb))
End Sub
'104,7s execution time:
Private Sub drawd2d()
Dim p1 As New D2D.Point2F(1, 10.5)
Dim p2 As New D2D.Point2F(1.01, 10)
Dim b As D2D.Brush = TGT.CreateSolidColorBrush(New D2D.ColorF(0, 0, 255))
TGT.BeginDraw()
For i = 0 To 200000 * 1000
TGT.DrawLine(p1, p2, b, 1)
Next
End Sub
데이터 크기가이 응용 프로그램에서 일반적으로 사용되므로 제발 내가 필요한 이유를 묻지 마십시오.
또한 데이터를 생성하는 응용 프로그램이 대략 3 초 내에 50M 포인트로 4 개의 추적을 렌더링하는 것처럼 관리하기 때문에 훨씬 빠르게 표시 할 수 있어야합니다. 이는 대략 동일한 데이터입니다.
누군가 비슷한 것을 한 적이 있다면 올바른 방향으로 나를 가리킬 수 있다면 매우 감사 할 것입니다. 또는 가능한 경우 나에게 PointF-Array 또는 유사한 구조를 렌더링 할 수있는 대안을 제공하십시오. 비트 맵.
편집 : 나머지 프로그램을로드 할 필요없이 원본 소프트웨어와 동일한 계산을 수행하기위한 벤치마킹 루틴입니다. Data()() 배열은 소프트웨어에 의해 동적으로 생성되므로 치수를 확인하고 조치해야합니다.
데이터로드 및 그림 표시 기능, 그리드 및 문제와 관련없는 다른 코드와 함께 정리 기능이 제거되었습니다.
EDIT2 : 데이터 생성 루틴을 포함 코드 샘플 :
Sub Main()
Dim T As New HiResTimer
Dim StartTime, StopTime As Long
'initd2d()
PrepareData(10, 200000)
StartTime = T.Value
For i = 1 To 1
'drawd2d()
Calculate2(100, 0, 200000)
Next
StopTime = T.Value
Dim Elapsed As Double = (StopTime - StartTime)/T.Frequency
Debug.Print("Time: " & Elapsed)
End Sub
Dim aData()() As Double
Private Sub PrepareData(ByVal WaveformCount As Integer, ByVal Length As Integer)
Dim Offset As Double = 0
Dim Amplitude As Double = 100
Dim SineCount As Double = 4
Dim SineBase As Double = 2 * Math.PI/Length * SineCount
ReDim aData(WaveformCount - 1)
For i = 0 To WaveformCount - 1
ReDim aData(i)(Length - 1)
For j = 0 To Length - 1
aData(i)(j) = Amplitude * Math.Sin(SineBase * j) + Offset + Rnd() * Amplitude * 0.05
Next
Next
End Sub
Private Sub Calculate2(ByVal AmplitudeUsed As Double, ByVal OffsetUsed As Double, ByVal LengthUsed As Integer)
Dim PS_Y As Double
'Instead of making this random, here a real calculation for the scale (chartheight/biggest waveform amplitude) :
PS_Y = 600/(AmplitudeUsed * 2 + AmplitudeUsed * 0.1) ' Rnd() + 0.1
'Since our calculation method oscillates around zero with the same amplitude we can predict that we need the following offset:
Dim Origin As PointF = New PointF(0, 300)
Dim Data(), ST As Double
Dim lPoints As New List(Of PointF)
'set the x axis scale to make our waveform fit exactly:
Dim PS_X As Double = 900/LengthUsed
Dim Img As New Bitmap(900, 600)
Dim ImgGR As Graphics = Graphics.FromImage(Img)
ImgGR.Clear(Color.White)
Dim WFPen As New Pen(Brushes.Black, 1)
'theese 2 values simply define an area in the picture where the waveforms are actually visible to not overlap with the axis/legend, set it to something that makes sense
Dim l As Integer = 20 'ChartRect.Left
Dim r As Integer = 700 'ChartRect.Right
For i = 0 To aData.Length - 1
'Set sampletime to 1 second to keep the predefined scale from above, but still do the calculation as it would be needed with real data:
ST = 1 ' Rnd()
Data = aData(i)
If Data.Length = 0 Then Continue For
Dim ScaleX As Double = ST * PS_X
Dim OrigX As Single = Origin.X
Dim iStart As Integer = (l - OrigX)/ScaleX
Dim iEnd As Integer = (r - OrigX)/ScaleX
If iStart < 0 Then iStart = 0
If iEnd < 0 Then iEnd = 0
If iEnd > Data.Length - 1 Then iEnd = Data.Length - 1
If iStart > Data.Length - 1 Then iStart = Data.Length - 1
iStart = 0
iEnd = Data.Length - 1
If iEnd < iStart Then Continue For
Dim APT(iEnd - iStart) As PointF
For j = iStart To iEnd
APT(j - iStart) = Origin + New SizeF(j * ScaleX, -(Data(j) * PS_Y))
Next
ImgGR.DrawLines(WFPen, APT)
Next
PictureBox1.Image = Img
End Sub
혼란스러운 코드. 난 당신이 거기에 많은 불필요한 코드를 가지고 있다고 생각하고, 당신은'Data' 값을주고'Length'를 확인합니다 - 코드를 단순화하는 작업. 또한 당신은 그래픽 객체 인'Pens','Graphics' 등을 처분하지 않습니다. – OneFineDay
@DonA 코드는 benchmaring 목적으로 만 사용합니다. 세부 사항을 편집하십시오. – Chris
50M = 50,000,000 포인트입니까? 얼마나 많은 선들을 시각화 할 수 있습니까? – OneFineDay