【问题标题】:Delphi / C++ builder Windows 10 1709 bitmap operations extremely slowDelphi / C++ builder Windows 10 1709 位图操作极慢
【发布时间】:2018-07-30 17:19:05
【问题描述】:

有人遇到过这个问题吗? :

它出现在 Windows 10 更新至 build 1709 之后。 经过一些系统启动时间 - 几个小时 - 位图加载,图像列表项添加变得非常缓慢。一个 256x256 的 BMP 加载时间超过 10 秒……在执行此操作时,它会 100% 占用一个 CPU 内核。 因此,可以在几秒钟内正常启动的已编译应用程序现在可以在几分钟内启动!

我经常使用休眠/恢复。 显示驱动程序已经使用了一年多,所以这不是问题。

对此有何评论?

更新: 我发现使用 Canvas.Pixels 的代码会发生这种情况,因此可以对其进行更改,但速度仍然非常慢。

更新 2: 用 Scanline 操作替换可以加快速度。最近的 Windows 补丁一定让 Canvas.Pixels 在大量使用时真的很慢。

【问题讨论】:

  • "显示驱动程序已有一年多的历史,所以这不是问题。"你现在越新越好,对吧? (特别是如果操作系统升级!)
  • 没有较新的驱动可用,而且问题是最近才出现的,所以我认为这不是系统变化的原因。
  • 哦,是的,问题一定出在 Delphi 而不是您的代码中……即使您没有生成 MCVE。
  • 使用TBitmap.Canvas.Pixels 属性通常会很慢。对于快速像素访问,请改用TBitmap.ScanLine 属性。见Reading and Setting Pixels

标签: delphi c++builder tbitmap timagelist


【解决方案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] 一样慢,但如果你的位图没有改变它的像素格式,也没有调整大小,那么指针仍然是一样的。

    这可用于直接像素访问,而不会影响性能。你只记得每个位图上的所有行都调整大小/重新加载到自己的数组中。然后使用它。如果使用得当,这通常比 Pixels[x][y] 快高达 ~10000x 倍。

    我通常在 C++ 中将 ScanLine 指针复制到我自己的数组,如下所示:

    // 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 颜色顺序(尤其是预定义的)。

    由于没有检查,所以不要访问位图之外的像素它很可能会引发访问冲突。

    最后不要忘记在不再需要时(或在新分配之前)释放 pyx 数组

【讨论】:

  • 我没有费心去检查这个,但我很好奇Pixels 在内核隔离补丁之后是否变得特别慢。
  • @J... 我不这么认为,因为像素总是太慢,但我只是在猜测。我敢打赌,应用程序的计时行为随着新补丁的改变(即使进程调度的微小变化也会产生很大影响,尤其是对多线程应用程序),这很可能已经非常接近甚至略高于断点。我会先检查计时器代码持续时间。如果它超过了它们的间隔,那么尝试将计时器间隔更改为安全的大值来测试它是不好的。最安全的是测量时间并绘制我使用QueryPerformanceCounter 的图表。但你的观点是可能的
  • @J... 我也是这么想的,Pixels 使用关键部分,所以最近的一些 Windows 补丁可能会减慢速度。
  • @kgz 好吧,我刚刚测试了一个打过补丁和没有打过补丁的 Win7 系统,除了两个系统之间的预期性能差异(相同的 i7 代,不同的时钟)之外,并没有真正可衡量的差异。 Pixels 以前很慢,现在仍然很慢,但似乎并没有比以前慢。可能Win10不一样,没测试过。
  • Pixels[] 一直很慢。 ScanLine 非常快,也可以进行优化,因此您不必在循环中调用它(对于每个位图行),但所获得的性能增益通常很小。
猜你喜欢
  • 2018-05-25
  • 1970-01-01
  • 2017-01-21
  • 2015-09-14
  • 1970-01-01
  • 2018-06-14
  • 2021-08-17
  • 2018-04-06
  • 2017-08-10
相关资源
最近更新 更多