Delphi / C++ Builder Операции с растровыми изображениями Windows 10 1709 чрезвычайно медленные

Кто-нибудь испытывал эту проблему?:

Он появился после обновления Windows 10 до сборки 1709. После некоторого времени загрузки системы - нескольких часов - загрузки растровых изображений, добавление элементов списка изображений становится чрезвычайно медленным. BMP 256x256 загружается более чем за 10 секунд... при этом он занимает одно ядро ​​процессора на 100%. Таким образом, скомпилированные приложения, которые обычно запускаются за считанные секунды, теперь запускаются за считанные минуты!

Я регулярно использую спящий режим / резюме. Драйверы дисплея старше года, так что это не может быть проблемой.

Любой комментарий по этому поводу?

Обновление: я обнаружил, что это происходит с кодом, который использует Canvas.Pixels, так что его можно изменить, но при этом он сильно замедлился.

Обновление 2: замена операций Scanline ускорила работу. Недавний патч Windows, должно быть, сделал Canvas.Pixels действительно медленным при большем использовании.

1 ответ

  1. GDI Canvas Pixels[x][y] медленный.

    Он выполняет много проверок и преобразований цветов, о которых вы даже не подозреваете (это буквально десятки промежуточных вызовов, если не сотни). Вот почему это так медленно, это не имеет значения, Win10. Такое поведение существует все время с момента запуска Windows, по крайней мере, насколько мне известно, это вопрос GDI, а не VCL (это не имеет никакого отношения к Borland/Embarcadero VCL). Так что не используйте Pixels[x][y] сильно. Даже очистка 1024x1024 На некоторых машинах этот способ может занять считанные секунды...

  2. VCL / GDI Bitmap ScanLine[y]

    Это специфично для Borland/Embarcadero (на чистом GDI вместо этого вам нужно использовать битовую блокировку). Каждое растровое изображение имеет это свойство / функцию, которые возвращают указатель на необработанные данные растрового изображения для любого y, Это так медленно, как Pixels[y][x] но если ваше растровое изображение не меняет свой пиксельный формат и размер не изменяется, указатель остается прежним.

    Это может быть использовано для прямого пиксельного доступа без каких-либо потерь производительности. Вы просто помните, все строки в каждом растровом изображении изменяют размер / перезагружают в собственный массив как. И потом используйте именно это. Это обычно до ~10000x в разы быстрее Pixels[x][y] если используется правильно.

    Я обычно копирую ScanLine указатели на мой собственный массив в C++, например:

    // 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];
    

    Так что перенесите его в Delphi. Просто имейте в виду, что в некоторых пиксельных форматах цвета - это RGB, а не BGR (или наоборот), поэтому в некоторых случаях вам необходимо изменить порядок цветов R,G,B (особенно предопределенных).

    Поскольку нет никаких проверок, поэтому НЕ ДОПУСКАЙТЕ ПИКСЕЛЕЙ ВНЕ BITMAP, это, скорее всего, вызовет нарушение прав доступа.

    И, наконец, не забудьте выпустить pyx массив, когда он больше не нужен (или перед новым распределением)

Другие вопросы по тегам