Why are bitmaps in GDI+ so sloooooooooow.

[b][red]This message was edited by TheEmotion at 2004-1-12 12:57:16[/red][/b][hr]
[b][red]This message was edited by TheEmotion at 2004-1-12 12:55:49[/red][/b][hr]

.SetPixel and .GetPixel take so long it is unbelievable. I don't understand how Graphics.drawline can calculate the poiints of a line, figure antialiasing and draw those points faster than a loop can do .setpixel(x,y,Color.Whatever)






Attached is some code..
Top two buttons show message box when completed loading a multidimensional array of colors that is the same size as the form.

Bottom two buttons .setpixel() and .GetPixel of Bitmap same size as previous array.


..Paste into blank form.. Make sure subs are attached to respective buttons.






Public Class Form1
Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

Public Sub New()
MyBase.New()

'This call is required by the Windows Form Designer.
InitializeComponent()

'Add any initialization after the InitializeComponent() call

End Sub

'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents PictureBox1 As System.Windows.Forms.PictureBox
Friend WithEvents Button1 As System.Windows.Forms.Button
Friend WithEvents Button2 As System.Windows.Forms.Button
Friend WithEvents Button3 As System.Windows.Forms.Button
Friend WithEvents Button4 As System.Windows.Forms.Button
Private Sub InitializeComponent()
Me.PictureBox1 = New System.Windows.Forms.PictureBox
Me.Button1 = New System.Windows.Forms.Button
Me.Button2 = New System.Windows.Forms.Button
Me.Button3 = New System.Windows.Forms.Button
Me.Button4 = New System.Windows.Forms.Button
Me.SuspendLayout()
'
'PictureBox1
'
Me.PictureBox1.BackColor = System.Drawing.Color.White
Me.PictureBox1.Dock = System.Windows.Forms.DockStyle.Fill
Me.PictureBox1.Location = New System.Drawing.Point(0, 0)
Me.PictureBox1.Name = "PictureBox1"
Me.PictureBox1.Size = New System.Drawing.Size(528, 494)
Me.PictureBox1.TabIndex = 0
Me.PictureBox1.TabStop = False
'
'Button1
'
Me.Button1.Location = New System.Drawing.Point(264, 328)
Me.Button1.Name = "Button1"
Me.Button1.Size = New System.Drawing.Size(240, 23)
Me.Button1.TabIndex = 1
Me.Button1.Text = "How Long it takes to set these coordinates."
'
'Button2
'
Me.Button2.Location = New System.Drawing.Point(0, 328)
Me.Button2.Name = "Button2"
Me.Button2.Size = New System.Drawing.Size(256, 23)
Me.Button2.TabIndex = 2
Me.Button2.Text = "How Long it takes to get these coordinates."
'
'Button3
'
Me.Button3.Location = New System.Drawing.Point(264, 32)
Me.Button3.Name = "Button3"
Me.Button3.Size = New System.Drawing.Size(240, 23)
Me.Button3.TabIndex = 3
Me.Button3.Text = "Set MultiArray of same ssize"
'
'Button4
'
Me.Button4.Location = New System.Drawing.Point(32, 32)
Me.Button4.Name = "Button4"
Me.Button4.Size = New System.Drawing.Size(160, 23)
Me.Button4.TabIndex = 4
Me.Button4.Text = "Get from Multi Array of Same Size"
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(528, 494)
Me.Controls.Add(Me.Button4)
Me.Controls.Add(Me.Button3)
Me.Controls.Add(Me.Button2)
Me.Controls.Add(Me.Button1)
Me.Controls.Add(Me.PictureBox1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.WindowState = System.Windows.Forms.FormWindowState.Maximized
Me.ResumeLayout(False)

End Sub

#End Region

Dim bmpbool(0, 0) As Color


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim x, y As Integer

Dim bmp As New Bitmap(PictureBox1.Width, PictureBox1.Height)


Do Until x >= bmp.Width
y = 0

Do Until y >= bmp.Height


bmp.SetPixel(x, y, Color.Black)


y += 1
Loop
x += 1
Loop

PictureBox1.Image = bmp

MsgBox("Ff")


End Sub

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

End Sub


Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click




Dim x, y As Integer

Dim bmp As New Bitmap(PictureBox1.Width, PictureBox1.Height)
Randomize()

Do Until x >= bmp.Width
y = 0

Do Until y >= bmp.Height


bmp.GetPixel(x, y)

y += 1
Loop
x += 1
Loop


MsgBox("Ff")




End Sub

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim x, y As Integer

ReDim bmpbool(PictureBox1.Width, PictureBox1.Height)



Do Until x >= PictureBox1.Width
y = 0

Do Until y >= PictureBox1.Height


bmpbool(x, y) = Color.Black

y += 1
Loop
x += 1
Loop
MsgBox("ff")


End Sub

Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click



Dim x, y As Integer


Randomize()

Do Until x >= PictureBox1.Width
y = 0

Do Until y >= PictureBox1.Height


Dim newbool As Color = bmpbool(x, y)


y += 1
Loop
x += 1
Loop
MsgBox("ff")





End Sub
End Class














Comments

  • OK, I'm not a VB.NET guy, but I can hopefully offer a little insight...

    : .SetPixel and .GetPixel take so long it is unbelievable. I don't
    : understand how Graphics.drawline can calculate the poiints of a
    : line, figure antialiasing and draw those points faster than a loop
    : can do .setpixel(x,y,Color.Whatever)
    What you're missing is what's going on behind the scenes.

    1) One thing to be acutely aware of is that VB.NET is running on the .NET virtual machine - not native code. So you have extra overhead. Yes, it JITs and stuff, but a JITers real performance boost mostly comes in doing far more mundane stuff, like tight int loops.

    2) .setpixel is a method call. Method calls have overhead - that's a general "feature" of them. When you use Graphics.drawline you have 1 times that overhead. When you call Graphics.setpixel to draw a 300 pixel line you have 300 times that overhead. Ouch.

    3) Stuff is getting mapped through the .NET FCL to GDI APIs, which then write to graphics memory or some other buffer that is flipped into the graphics memory. The drawline method will most likely call a GDI API for drawing a line - inside which it can do the drawing nice and fast 'cus it's all native compiled code in one binary. Setpixel calls have to be passed down this hierachy every time.

    So in reality what is really happening is greatly different from what you think is going on in your code, which probably explains why it is, like you say, so slow.

    Hope this helps you understand,

    Jonathan

    ###
    for(74,117,115,116){$::a.=chr};(($_.='qwertyui')&&
    (tr/yuiqwert/her anot/))for($::b);for($::c){$_.=$^X;
    /(p.{2}l)/;$_=$1}$::b=~/(..)$/;print("$::a$::b $::c hack$1.");

  • Thank you for the response. That makes since. Are there any API's that I could use to give me greater speed over pixel control that you know of, or any suggestions?







    : OK, I'm not a VB.NET guy, but I can hopefully offer a little insight...
    :
    : : .SetPixel and .GetPixel take so long it is unbelievable. I don't
    : : understand how Graphics.drawline can calculate the poiints of a
    : : line, figure antialiasing and draw those points faster than a loop
    : : can do .setpixel(x,y,Color.Whatever)
    : What you're missing is what's going on behind the scenes.
    :
    : 1) One thing to be acutely aware of is that VB.NET is running on the .NET virtual machine - not native code. So you have extra overhead. Yes, it JITs and stuff, but a JITers real performance boost mostly comes in doing far more mundane stuff, like tight int loops.
    :
    : 2) .setpixel is a method call. Method calls have overhead - that's a general "feature" of them. When you use Graphics.drawline you have 1 times that overhead. When you call Graphics.setpixel to draw a 300 pixel line you have 300 times that overhead. Ouch.
    :
    : 3) Stuff is getting mapped through the .NET FCL to GDI APIs, which then write to graphics memory or some other buffer that is flipped into the graphics memory. The drawline method will most likely call a GDI API for drawing a line - inside which it can do the drawing nice and fast 'cus it's all native compiled code in one binary. Setpixel calls have to be passed down this hierachy every time.
    :
    : So in reality what is really happening is greatly different from what you think is going on in your code, which probably explains why it is, like you say, so slow.
    :
    : Hope this helps you understand,
    :
    : Jonathan
    :
    : ###
    : for(74,117,115,116){$::a.=chr};(($_.='qwertyui')&&
    : (tr/yuiqwert/her anot/))for($::b);for($::c){$_.=$^X;
    : /(p.{2}l)/;$_=$1}$::b=~/(..)$/;print("$::a$::b $::c hack$1.");
    :
    :

  • : Thank you for the response. That makes since. Are there any API's
    : that I could use to give me greater speed over pixel control that
    : you know of, or any suggestions?
    You can call into the Win32 API directly. But, as far as I'm aware at least, you have to do a platform invoke (pinvoke) for that. I'm not sure what the syntax for this is in VB.NET, but it's basically where you call out of the .NET framework into some (unmanaged) native API of the system you're running on. I don't have any benchmarks or anything, but I fear it will carry overhead - what I don't know is if that is a one-time library loading and symbol lookup overhead, then re-calling the function is cheap, or if it's going to be almost as (or even more) costly than the .SetPixel method.

    As for other suggestions, would DirectX/DirectDraw be able to offer you better performance? I don't know, somebody else may.

    I guess the least helpful suggestion I can make is not to do this entirely in VB.NET, but that may not be viable. You may be best off using "Managed C++" here. It will allow your code to easily inter-operate with code in other .NET languages, but I *think* you can still call directly into the Win32 API. Do your high-performance work in there. I don't know this will work, but it's an idea. I won't tell you about my friend who said of managed C++ "it's the worst thing ever!". ;-)

    Jonathan

    ###
    for(74,117,115,116){$::a.=chr};(($_.='qwertyui')&&
    (tr/yuiqwert/her anot/))for($::b);for($::c){$_.=$^X;
    /(p.{2}l)/;$_=$1}$::b=~/(..)$/;print("$::a$::b $::c hack$1.");

  • Either use win32 calls within C# or VB.NET or encapsulate win32 calls in C++ Managed Extensions dll library (and get the best of all worlds.) Otherwise your best bet for speed and better functionality geared towards image manipulation is Direct-X api. Fortunately they have a .NET version of the api (Direct-X 9.0). You can begin your quest here:

    http://msdn.microsoft.com/library/default.asp?url=/nhp/default.asp?contentid=28000410

    I've played with direct-x a little and have only manipulated regular bitmaps only. I'm pretty sure you can manipulate other image formats. I must warn you, Direct-X gets real difficult fast and even though Microsoft labels it as a multi-media api, people mainly use it to program sophisticated video games.
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories