Huge GetDIBits slowdown under Win2K/XP
Author |
Message |
Mark Raishbroo #1 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
On my PIII 600 MHz machine under Win98, I can loop through a listbox containing around 1000 items (PAL or NTSC subtitle text actually), zap each string to a picturebox, mess around with the pixels a little and then save the BMP to disk in around 150 seconds. I have just discovered, however, that under Win2K/XP, on *exactly the same machine*, the code takes **10** times longer to execute, making for some very unhappy Win2K/XP enabled customers. I've tracked down the performance drop to the GetDIBits call in the routine below. It takes almost 1 second to execute! Can anybody tell me why? Thanks in advance, Mark Raishbrook Public Sub Save8BitBMP(fName As String, pBox As PictureBox) Dim BufferSize As Long Dim SaveBits() As Byte Dim lScaleWidth As Long Dim lScaleHeight As Long Dim l as long lScaleWidth = pBox.ScaleWidth lScaleHeight = pBox.ScaleHeight On Error GoTo SaveError With BMFH .bfType = &H4D42 .bfSize = 1078 + (lScaleWidth * lScaleHeight) .bfReserved1 = 0 .bfReserved2 = 0 .bfOffBits = 1078 End With BufferSize = ((lScaleWidth / 8 + 3) And &HFFFC) * lScaleHeight ReDim SaveBits(0 To BufferSize - 1) With SaveBitmapInfo_1.bmiHeader .biSize = 40 .biWidth = lScaleWidth .biHeight = lScaleHeight .biPlanes = 1 .biBitCount = 8 .biCompression = 0 .biSizeImage = BufferSize .biXPel{*filter*}eter = 0 .biYPel{*filter*}eter = 0 .biClrUsed = 0 .biClrImportant = 0 End With For l = 0 To &HFF With SaveBitmapInfo_1.bmiColors(l) .rgbBlue = l .rgbGreen = l .rgbRed = l .rgbReserved = 0 End With Next j% Dim retVal As Long retVal = GetDIBits(pBox.hdc, pBox.Image, 0, lScaleHeight, SaveBits(0), SaveBitmapInfo_1, 0) fFile = FreeFile Open fName For Binary As fFile Put fFile, , BMFH Put fFile, , SaveBitmapInfo_1 Put fFile, , SaveBits() Close fFile If Not blnTiff Then Exit Sub Exit Sub SaveError: MsgBox "Cannot save bitmap files to disk - you may have run out of disk space. Check the space available on the destination drive and try again", vbCritical, "8 bit BMP Save Failure" CancelRender = True Exit Sub End Sub
|
Fri, 25 Feb 2005 04:39:26 GMT |
|
 |
Mike D Sutto #2 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
Quote: > On my PIII 600 MHz machine under Win98, I can loop through a listbox > containing around 1000 items (PAL or NTSC subtitle text actually), zap each > string to a picturebox, mess around with the pixels a little and then save > the BMP to disk in around 150 seconds. I have just discovered, however, that > under Win2K/XP, on *exactly the same machine*, the code takes **10** times > longer to execute, making for some very unhappy Win2K/XP enabled customers. > I've tracked down the performance drop to the GetDIBits call in the routine > below. It takes almost 1 second to execute! Can anybody tell me why?
<snip> Check to make sure that the ScaleMode of the picture box is set to pixels, otherwise the GetDIBits() call will be trying to get 15^2 times the amount of data it needs (!). Also you've got something screwy going on with the palette filling loop I think, however you've put your entire code in an On Error statement (Eugh!!) which has prevented it being detected. Take that out and if you really need it then put it only around the file opening code which is the only place you're likely to get an error as long as your syntax is ok. The palette setting loop should be: '*** For l = 0 To &HFF With SaveBitmapInfo_1.bmiColors(l) .rgbBlue = l .rgbGreen = l .rgbRed = l .rgbReserved = 0 End With Next l ' <-- Not j% '*** Sensible variables names would have solved this one though but that's just cosmetic. You also need to set the number of colours used from the palette in the BMIH (The .biClrUsed and .biClrImportant entries), set these both to 256. Other than that it looks ok, however why retain the return value to GetDIBits() if you're not using it? Try this instead: '*** GetDIBits pBox.hdc, pBox.Image, 0, lScaleHeight, SaveBits(0), _ SaveBitmapInfo_1, 0 '*** Or: '*** If GetDIBits(pBox.hdc, pBox.Image, 0, lScaleHeight, SaveBits(0), _ SaveBitmapInfo_1, 0) = 0 Then MsgBox "GetDIBits() error.." '*** If you still get slowdown then drop using the picture box entirely and use a DIB instead, it's faster and more generic. Hope this helps, Mike -- EDais -- - Microsoft Visual Basic MVP - WWW: Http://EDais.earlsoft.co.uk/
|
Fri, 25 Feb 2005 05:00:52 GMT |
|
 |
Mark Raishbroo #3 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
The j% inclusion was just a typo - I copied and pasted, then changed the loop and forget to change the j%. I know my loops, Mike, fear not. Quote: > Check to make sure that the ScaleMode of the picture box is set to pixels, > otherwise the GetDIBits() call will be trying to get 15^2 times the amount > of data it needs (!).
Yep, set to pixels. Quote: > Other than that it looks ok, however why retain the return value to > GetDIBits() if you're not using it?
I'm using it for debugging - just checking it's not returning 0. Quote: > If you still get slowdown then drop using the picture box entirely and use a > DIB instead, it's faster and more generic.
OK, I can try that, (and am doing it in the pixel processing routine thanks to your help some months back) although I'm not sure how to save the DIB to disk. However, that still doesn't explain the fact that *identical code on an identical machine* runs 10 times slower under Win2k. Any ideas?
|
Fri, 25 Feb 2005 05:12:44 GMT |
|
 |
Mark Raishbroo #4 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
Re-checked and double re-checked and it is this and only this call that is ten-fold slower: GetDIBits(pBox.hdc, pBox.Image, 0, lScaleHeight - 1, SaveBits(0), SaveBitmapInfo_1, 0) It's retrieving the handle to the bitmap which is slowing everything down -- not on 98, just 2K and XP remember. I've also tried a standard 24 bit pBox.SavePicture call -- same result: 10 times slower on 2K and XP.
|
Fri, 25 Feb 2005 05:23:30 GMT |
|
 |
Mike D Sutto #5 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
Quote: > Re-checked and double re-checked and it is this and only this call that is > ten-fold slower: > GetDIBits(pBox.hdc, pBox.Image, 0, lScaleHeight - 1, SaveBits(0), > SaveBitmapInfo_1, 0) > It's retrieving the handle to the bitmap which is slowing everything down -- > not on 98, just 2K and XP remember. I've also tried a standard 24 bit > pBox.SavePicture call -- same result: 10 times slower on 2K and XP.
Try this: '*** Dim PicDC As Long, PicBMP As Long PicDC = pBoc.hDC PicBMP = pBox.Image.Handle GetDIBits PicDC, PicBMP, 0, lScaleHeight - 1, _ SaveBits(0), SaveBitmapInfo_1, 0 '*** Other than that I don't see anything here that should make it slow down considerably, it could be something else in your code though that you've not mentioned here. You're not running the exact same code on both platforms either, the API's are re-written for each platform but shouldn't be that different. Are the two systems you're testing on (One system dual boot) both set up and configured properly, equal hardware, recently been rebooted and have no GDI leaks or anything of the sort? NT is far more stringent on using API's than on the more lightweight OS' so it could be something else you've missed. Mike -- EDais -- - Microsoft Visual Basic MVP - WWW: Http://EDais.earlsoft.co.uk/
|
Fri, 25 Feb 2005 05:49:43 GMT |
|
 |
Mark Raishbroo #6 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
Thanks for the continued help, Mike. Quote: > Try this: > PicDC = pBoc.hDC > PicBMP = pBox.Image.Handle
I'd already cached just about everything to variables and still no change. Quote: > Are the two systems you're testing on (One system dual boot) > both set up and configured properly, equal hardware, recently been rebooted > and have no GDI leaks or anything of the sort?
Yep, it's a dual boot 98/2000 system. Everything else runs fine. No hardware probs, no memory leaks. If it's of any help, the mouse refuses to respond under 2000 during the GetDIBits call: it just stutters around as the code executes. If I were to do everything in a DIB, how would I save the resultant bmp to disk?
|
Fri, 25 Feb 2005 06:09:06 GMT |
|
 |
Mark Raishbroo #7 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
Just had this tested on 2 other Win98 SE machines (600 and 800 MHZ): code runs as it should - a 1000 item loop takes 130-150 seconds. On 2 other WinXP machines (1800 MHz!): code takes 900 seconds. On 2 other Win2K machines (800 MHz): code takes 1100 seconds.
|
Fri, 25 Feb 2005 06:15:19 GMT |
|
 |
Mike D Sutto #8 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
Quote: > Yep, it's a dual boot 98/2000 system. Everything else runs fine. No hardware > probs, no memory leaks. If it's of any help, the mouse refuses to respond > under 2000 during the GetDIBits call: it just stutters around as the code > executes. > If I were to do everything in a DIB, how would I save the resultant bmp to > disk?
Exactly the same way as you are now, you'd just have your own DC and DIB rather than using the Picture box's .hDC and .Image objects. I can't see anything in the code posted that should slow things down to this extent though, I can only guess it's something elsewhere causing the problems and it's only showing up at this stage. Does it run slowly all the time or progressively slower as it iterates through the images? Have you tried the call in a bare-bones application on it's own to see if it causes problems there too? It could also be your graphics drivers if this is the case. Try this one: Http://EDais.Earlsoft.co.uk/TempFiles/frmDIBitsTest.frm Hope this helps, Mike -- EDais -- - Microsoft Visual Basic MVP - WWW: Http://EDais.earlsoft.co.uk/
|
Fri, 25 Feb 2005 07:37:00 GMT |
|
 |
Richard Maso #9 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
So what size is "Huge" Quote: >I've tracked down the performance drop to the GetDIBits call in the routine >below. It takes almost 1 second to execute! Can anybody tell me why?
DDB to DIB conversion takes time. Quote: >Public Sub Save8BitBMP(fName As String, pBox As PictureBox) > BufferSize = ((lScaleWidth / 8 + 3) And &HFFFC) * lScaleHeight
This is an equation for a monochrome image Quote: > For l = 0 To &HFF > With SaveBitmapInfo_1.bmiColors(l) > .rgbBlue = l > .rgbGreen = l > .rgbRed = l > .rgbReserved = 0 > End With > Next j%
What is the purpose of this? Quote: > Dim retVal As Long > retVal = GetDIBits(pBox.hdc, pBox.Image, 0, lScaleHeight, SaveBits(0), >SaveBitmapInfo_1, 0)
Use .Picture and Not .Image to avoid DDB to DIB conversion -- Richard Mason
|
Fri, 25 Feb 2005 12:00:37 GMT |
|
 |
Mark Raishbroo #10 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
Oops, sorry, Mike. Replied to you instead of to the group. Quote: > Exactly the same way as you are now, you'd just have your own DC and DIB > rather than using the Picture box's .hDC and .Image
objects. Right, I shall give this a whirl, Mike. Thanks. However... Quote: > I can't see anything in the code posted that should slow > things down to this > extent though, I can only guess it's something elsewhere > causing the problems and it's only > showing up at this stage.
...this is just my point. If the code is this slow, it would also be this slow under Win98, wouldn't it? It's the speed difference between the two OS which is bugging me. Quote: > Does it run slowly all the > time or progressively slower as it iterates through the
images? Slowly all the time, zero variation. Quote: > Have you tried the call in a bare-bones application on
it's own to see if it Quote: > causes problems there too?
Yes, I've tried a test app simply using a form and a picturebox. The contents of the picturebox gets saved to disk 1000 times using SavePicture. Fast on Win98, slow on Win2k. I'm sure I'm not going mad -- if you have a Win98 machine wherever you are, why not give it a try and see if you can spot the difference? I'm certain you will.
|
Fri, 25 Feb 2005 23:16:03 GMT |
|
 |
Mike D Sutto #11 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
Quote: > ...this is just my point. If the code is this slow, it would > also be this slow under Win98, wouldn't it? It's the speed > difference between the two OS which is bugging me. <snip> > Slowly all the time, zero variation. <snip> > Yes, I've tried a test app simply using a form and a > picturebox. The contents of the picturebox gets saved to disk > 1000 times using SavePicture. Fast on Win98, slow on Win2k. > I'm sure I'm not going mad -- if you have a Win98 machine > wherever you are, why not give it a try and see if you can > spot the difference? I'm certain you will.
Unfortunately the only Win98 machine I have here is very low spec so testing it against a higher spec Win2K machine wouldn't really be a fair test, however I've been using Get/SetDIBits() all the way through from Win95 to Win2K and haven't noticed huge differences in speed, not like you're experiencing at least. Have you tried my demo across multiple Win2K machines? I've tested it on a number of machines around here and it rarely takes longer than a couple of milliseconds to get or set the data on machines ranging from 450Mhz to 1.9Ghz (All Win2K) It's also worth mentioning that if you use a DIBSection rather than a normal Bitmap object then you have direct access to the DIB data at any stage and can bypass the costly GetDIBits() call. They're slightly annoying to work with in VB (But possible with some array decriptor hacks) however if you migrate your rendering code to C++ then it would most likely fly, this may be a better solution if none others arise. Hope this helps, Mike -- EDais -- - Microsoft Visual Basic MVP - WWW: Http://EDais.earlsoft.co.uk/
|
Fri, 25 Feb 2005 23:27:17 GMT |
|
 |
Mark Raishbroo #12 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
Hmmm, I still think your low spec 98 machine would win hands down if you tried a simple SavePicture test. A bottle of Portuguese wine to you if I'm wrong! :-) Anyway, I'll try doing everything within a DIB. Just one question, though: if I want to create an 8 bit DIB using your cDIBSection class, aside from changing m_tBI.bmiHeader.biBitCount to 8, what changes do I make to the BytesPerScanLine property? With an 8 bit DIB, this is just Width * Height, no?
|
Fri, 25 Feb 2005 23:39:21 GMT |
|
 |
Mike D Sutto #13 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
Quote: > Hmmm, I still think your low spec 98 machine would win hands down if you > tried a simple SavePicture test. A bottle of Portuguese wine to you if I'm > wrong! :-)
Ok, I'll test it out at some point and let you know, shall I just give you my mailing address now? ;) Quote: > Anyway, I'll try doing everything within a DIB. Just one question, though: > if I want to create an 8 bit DIB using your cDIBSection class, aside from > changing m_tBI.bmiHeader.biBitCount to 8, what changes do I make to the > BytesPerScanLine property? With an 8 bit DIB, this is just Width * Height, > no?
I presume you mean the DIBSection class by Warren Galyen on my site? If so then you'll have to ask him about the specifics since it's only hosted by me, not written. As far as the bytes per scan-line goes then it has to be DWord aligned so it will be: '*** BytesPerScanLine = ((OldWidth + 3) \ 4 ) * 4 '*** Hope this helps, Mike -- EDais -- - Microsoft Visual Basic MVP - WWW: Http://EDais.earlsoft.co.uk/
|
Sat, 26 Feb 2005 00:13:31 GMT |
|
 |
Mike D Sutto #14 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
Quote: > Hmmm, I still think your low spec 98 machine would win hands down if you > tried a simple SavePicture test. A bottle of Portuguese wine to you if I'm > wrong! :-)
Appologies for the delay, it seems Win98 machines are few and far between these days, so I had to make a couple! I tested my app on three machines (Only two were dual booted with Win98 though) and here's the results: ---------- Machine 1: 450Mhz P3 256Mb RAM 1280*1024*32 ATI Rage fury 128 /w 32Mb RAM Win98: (Drivers don't support 24-bit)
Win2K: (Drivers support 24-bit)
---------- ---------- Machine 2 Dell 1.4Ghz P4 1024Mb RDRAM 1600*1200*32 GeForce4 Ti 4400 /w 128Mb RAM Win2K: (Drivers don't support 24-bit)
---------- ---------- Machine 3 Dell 1.9Ghz P4 512Mb RAM 1600*1200*32 GeForce4 Go /w 64Mb RAM laptop Win98: (Graphics drivers not installed - running in 16-colour mode..)
Win2K: (Drivers don't support 24-bit)
---------- It looks from this that as long as the graphics drivers support 24-bit then it will run faster on Win2K however a lot of modern 3D derrived cards (Such as the nVidia GeForce series) don't support 32-bit since neither does DirectX and as such the bit-depth conversion has to be done by the software which is slow. To get the best performance mache sure that the drivers and display can support the bit-depth you're running at. Hope this helps, Mike -- EDais -- - Microsoft Visual Basic MVP - WWW: Http://EDais.earlsoft.co.uk/
|
Mon, 28 Feb 2005 22:23:57 GMT |
|
 |
Mark Raishbroo #15 / 15
|
 Huge GetDIBits slowdown under Win2K/XP
Apologies for the late reply too, Mike. I've been away for a while. [snip] Quote: > It looks from this that as long as the graphics drivers support 24-bit then > it will run faster on Win2K
Bottle of wine to you then! :-) Quote: > To get the best performance mache sure that the drivers and > display can support the bit-depth you're running at.
I hadn't even considered this. Hugely sincere thanks for the help! Zap me your snail mail address and I'll zap you back a bottle of Portugal's finest. Mark
|
Sun, 06 Mar 2005 05:16:26 GMT |
|
|
|