Huge GetDIBits slowdown under Win2K/XP 
Author Message
 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  
 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  
 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  
 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  
 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  
 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  
 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  
 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  
 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  
 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  
 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  
 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  
 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  
 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  
 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  
 
 [ 15 post ] 

 Relevant Pages 

1. Huge Slowdown While Looping Thru FileFind Procedure

2. GetDIBits works on Win2K not Win98?

3. Windows XP is a huge nuisance!

4. Database Open via DOA Fails in Some Win2K/Office XP Configs

5. Access XP - Reports run under Win2K, not under Win98

6. Using MSCAL.OCX in Visual Basic with Office XP on Win2k Pro platforms

7. Access exits at PCs with Op.Syst.Win2K Prof./Win2k Server

8. Access 97 very strange slowdown

9. VB .Net IDE Slowdown

10. Switch from Jet to SQL - SLOWDOWN

11. SQL Slowdown

12. VB with Access slowdown.

 

 
Powered by phpBB® Forum Software