Delphi / C++ builder Windows 10 1709 bitmap operations extremely slow
Asked Answered
S

1

1

Anyone experienced this problem? :

It appeared after Windows 10 update to build 1709. After some system up time - a few hours -, bitmap loadings, imagelist item adding gets extremely slow. A 256x256 BMP loads in more than 10 seconds...while doing this, it occupies one CPU core 100%. So compiled applications that start up normally in seconds now start up in minutes!

I use hibernation/resume regularly. Display drivers are more than a year old, so that can't be the problem.

Any comment on this?

Update: I found that this happens with code that use Canvas.Pixels, so that can be changed, still it slowed down very much.

Update 2: Replacing with Scanline operations speeded up things. Recent Windows patch must have made Canvas.Pixels really slow on larger amount use.

Spann answered 20/2, 2018 at 10:57 Comment(8)
"Display drivers are more than a year old, so that can't be the problem." You now that newer is better, right? (Especially if the OS is upgraded!)Frances
There's no newer driver available, and the problem occurs only recently, so I thought this could not be the cause for the change in the system.Spann
minimal reproducible example please...Paralytic
Oh yeah, the problem must be in Delphi and not in your code... even when you've not produced a MCVE.Grasping
Using the TBitmap.Canvas.Pixels property is inherently slow in general. For fast pixel access, use the TBitmap.ScanLine property instead. See Reading and Setting Pixels.Subatomic
PS: If your application is using 100% CPU, you probably have a bug in your code where you go into an infinite loop. And yes.... that will slow everything down!Grasping
Comments converted to answer (they where not much readable as comments) dealing with Pixels which is 99% the problem. There still might by also another problem related to synchronization of your App (as Craig Young suggests) but for that we would need to know the architecture of your App and its code. The usual problem is doing something in timer with duration bigger or close to the Timer Period property ... And also not processing messages for bigger portion of time could lead to problems ... In case you use OnIdle it is a good idea to add some Sleep in itOconnor
Thanks for the comments, take it easy, it's not against Delphi - It's still the fastest IDE around imho. These were just simple loops through all pixels on a bitmap in the main thread. Also in some 3rd party code. Replaced them with scanline memory operations, so it's OK now. Maybe you'll experience this slowness in the future, though I know that only lazy developers use Canvas.Pixels!Spann
O
4
  1. GDI Canvas Pixels[x][y] is slow.

    It performs many checks and color conversions you have no idea (it is literally tens of subcalls if not hundreds). That is why it is so slow it is not matter of Win10. this behavior is there all the time from windows start at least to my knowledge it is matter of GDI not VCL (it has nothing to do with Borland/Embarcadero VCL). So do not use Pixels[x][y] heavily. Even clearing 1024x1024 image this way can be a matter of around second on some machines...

  2. VCL/GDI Bitmap ScanLine[y]

    This is Borland/Embarcadero specific (on pure GDI you need to use bits locking instead). Each bitmap has this property/function which return pointer to raw data of the bitmap for any y. It is as slow as Pixels[y][x] but if your bitmap does not change its pixel format nor it is resized then the pointer is still the same.

    This can be used for direct pixel access without any performance hits. You just remember all lines at each bitmap resize/reload into own array like. And afterwards use just that. That is usually up to ~10000x times faster then Pixels[x][y] if used properly.

    I usually copy ScanLine pointers to my own array in C++ like this:

    // ok lests have some bitmap
    Graphics::TBitmap *bmp=new Graphics::TBitmap;
    bmp->Width=100;
    bmp->Height=100;
    // this is needed for direct pixel access after any LoadFromFile, Assign or resize 
    bmp->HandleType=bmDIB;    // allows use of ScanLine
    bmp->PixelFormat=pf32bit; // 32bit the same as int so we can use int* for pixels pointer
    
    DWORD **pyx=new DWORD*[bmp->Height];
    for (int y=0;y<bmp->Height;y++) pyx[y]=(DWORD*)bmp->ScanLine[y];
    
    // now we can render pixels fast like this:
    pyx[10][20]=0x0000FF00; // green dot at x=20, y=10
    // and also read it back fast:
    DWORD col=pyx[10][20];
    

    So port it to Delphi. Just beware that on some pixel formats the colors are RGB instead of BGR (or vice versa) so in some cases you need to reverse R,G,B order of colors (especially the predefined ones).

    As there are no checks so DO NOT ACCESS PIXELS OUTSIDE BITMAP it would most likely throw an access violation.

    And lastly do not forget to release the pyx array when not needed anymore (or before new allocation)

Oconnor answered 21/2, 2018 at 8:42 Comment(5)
I haven't bothered to check this, but I'm curious whether Pixels has become particularly slow following the kernel isolation patches for meltdown.Paralytic
@Paralytic I do not think so as Pixels was always too slow but I am just guessing. My bet is that the timing behavior of the app changed with the new patch (even a small change in scheduling of processes can have a large impact especially on multi threading apps) which was most likely already very near or even slightly above breaking point. I would check timers code duration first. If it exceeds they interval its not good trying to change timer intervals to safe big value to test it. Safest is to measure the time and plot graph I use QueryPerformanceCounter for that. But your point is possibleOconnor
@Paralytic I was thinking the same, Pixels uses critical sections so this may have slowed down with some recent windows patch.Spann
@Spann Well, I just tested a patched and unpatched Win7 system and there wasn't really a measurable difference beyond the expected performance difference between the two systems (same gen i7, different clock). Pixels was slow before and it's still slow now, but doesn't seem any slower than it always was. Maybe Win10 is different, haven't tested.Paralytic
Pixels[] has always been slow. ScanLine is very fast and can also be optimized so you don't have to call it in a loop (for every bitmap row) but the performance gain achieved is usually small.Hampstead

© 2022 - 2024 — McMap. All rights reserved.