Неожиданная задержка при обработке нескольких изображений с помощью SharpDX / Direct2D перед рендерингом в приложении NET WinForms - PullRequest
0 голосов
/ 28 мая 2020

Я разрабатываю приложение. NET WinForms, и мне нужно масштабировать множество больших изображений и отображать их как маленькие значки в форме. У меня проблемы с производительностью особенно на указанных c машинах. Профили показывают, что больше всего времени занимает GDI + при масштабировании этих изображений. Таким образом, моя цель сейчас - использовать SharpDX для масштабирования этих изображений с помощью Direct2D и рисовать их с помощью GDI + после этого как есть. Теперь у меня есть тестовый класс, в котором я генерирую устройства и контекст только один раз. Затем я передаю источник и цель. NET Растровые изображения в метод Scale.

Public Sub ScaleImage(pBaseImage As System.Drawing.Bitmap, pTargetImage As System.Drawing.Bitmap)
   FillSourceBitmap(pBaseImage)
   Dim cropEffect = New d2.Effects.Crop(d2dContext)
   cropEffect.SetInput(0, d2SourceBitmap, True)
   cropEffect.Rectangle = New Mathematics.Interop.RawVector4(0, 0, pBaseImage.Width, pBaseImage.Height)
   Dim scaleEffect = New d2.Effects.Scale(d2dContext)
   scaleEffect.SetInput(0, cropEffect.Output, True)
   scaleEffect.ScaleAmount = New SharpDX.Mathematics.Interop.RawVector2(pTargetImage.Width / pBaseImage.Width, pTargetImage.Height / pBaseImage.Height)

   Dim d2TargetBitmapProps = New d2.BitmapProperties1(d2PixelFormat, 96, 96, d2.BitmapOptions.Target)
   Dim d2TargetBitmap = New d2.Bitmap1(d2dContext, New Size2(pTargetImage.Width, pTargetImage.Height), d2TargetBitmapProps)
   d2dContext.Target = d2TargetBitmap
   d2dContext.BeginDraw()
   d2dContext.DrawImage(scaleEffect,)
   d2dContext.EndDraw()

   CopyBitmapFromDxToGDI(d2TargetBitmap, pTargetImage)
End Sub

Private Sub FillSourceBitmap(bmp As Drawing.Bitmap)
   Dim bmpData As Imaging.BitmapData = bmp.LockBits(New Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), Imaging.ImageLockMode.ReadWrite, Imaging.PixelFormat.Format32bppPArgb)
   d2SourceBitmap.CopyFromMemory(bmpData.Scan0, bmpData.Stride,
                           New Mathematics.Interop.RawRectangle(0, 0, bmpData.Width, bmpData.Height))
   bmp.UnlockBits(bmpData)
End Sub

Private Sub CopyBitmapFromDxToGDI(bitmap As d2.Bitmap1, bmp As Drawing.Bitmap)
   Dim d2TempBitmapProps = New d2.BitmapProperties1(d2PixelFormat, 96, 96, BitmapOptions.CpuRead Or BitmapOptions.CannotDraw)
   Dim d2TempBitmap = New d2.Bitmap1(d2dContext, New Size2(bmp.Width, bmp.Height), d2TempBitmapProps)      
   d2TempBitmap.CopyFromRenderTarget(d2dContext)
   
   Dim surface = d2TempBitmap.Surface
   Dim dataStream As DataStream = Nothing
   Dim dataRectangle As DataRectangle = surface.Map(dxgi.MapFlags.Read, dataStream)
   Dim bmpData As Imaging.BitmapData = bmp.LockBits(New Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), Imaging.ImageLockMode.ReadWrite, Imaging.PixelFormat.Format32bppPArgb)

   Dim offset = bmpData.Reserved
   Dim buffer(4) As Byte
   For y As Integer = 0 To surface.Description.Height - 1
      For x As Integer = 0 To surface.Description.Width - 1            
         dataStream.Seek((y * dataRectangle.Pitch) + (x * 4), SeekOrigin.Begin)
         dataStream.Read(buffer, 0, 4)           
         
         Marshal.WriteByte(bmpData.Scan0, offset, buffer(3))            
         Marshal.WriteByte(bmpData.Scan0, offset+1, buffer(0))
         Marshal.WriteByte(bmpData.Scan0, offset+2, buffer(1))
         Marshal.WriteByte(bmpData.Scan0, offset+3, buffer(2))
         offset += 4
      Next
   Next
   bmp.UnlockBits(bmpData)
   surface.Unmap()
   dataStream.Dispose()
   d2TempBitmap.Dispose()
End Sub

Полный код можно найти здесь https://github.com/Drreamer/Direct2DImageProcessing

Теперь код работает, но все еще недостаточно быстро. Профиль показывает, что большая часть временного кода не работает, но выполняются некоторые другие операции: введите описание изображения здесь

Вы можете видеть, что рендеринг одного изображения занимает 10 мс. После этого другой поток приложения работает в течение 10 мс, а после этого приложение ничего не делает в течение 20 мс. Кто-нибудь знает, в чем причина проблемы и как нужно переписать решение, чтобы решить проблему?

...