【问题标题】:Why doesn't microsoft change the implementation of SetPixel() to an implementation that's faster?为什么微软不将 SetPixel() 的实现更改为更快的实现?
【发布时间】:2011-05-06 19:30:16
【问题描述】:

我有一个关于 Bitmap 类的问题。如果要在位图上设置很多像素,那么可以使用SetPixel的方法,但是速度很慢。有很多关于如何使用LockBits 方法等来加速它的文档,所以我创建了一个方法:SetFastPixel来加快速度。

但是,我真的对此感到困惑:为什么微软不将 SetPixel() 的实现更改为更快的实现? 换句话说,使用 @ 是否有优势? 987654325@ 代替LockBits 方法?

【问题讨论】:

  • 您如何确定您的实施速度更快? MS 实现几乎是直接调用GDI+ Flat API
  • 我很确定。我使用 StopWatch 类来测量两个执行时间。在我的情况下,lockbits 方法快 5 倍(重绘整个位图 (265*265)。
  • 您能否链接这些“有关如何使用 LockBits 方法加快速度的大量文档”?
  • @Timo 我在任何这些链接中都看不到 SetFastPixel 函数。那些锁定整个位图并立即更改它。您如何实现比 SetPixel 更快地锁定/更改/解锁的 SetFastPixel?
  • @Timo,我认为人们发现很难想象“SetFastPixel”会更快,因为 lockbits 旨在允许以像素数组的形式访问图像。加速是一次写入多个像素的能力。如果您使用相同的参数实现了“SetFastPixel”,则您的循环正在执行“锁定->写入 1 个像素->解锁->重复”,这基本上是 setpixel 无论如何都会执行的操作,因此您不会从使用 lockbits 中受益以任何方式

标签: c# .net bitmap pixel


【解决方案1】:

他们不在乎,因为大多数人不会那样使用它。 C# 通常不用于渲染视频 - 如果您需要类似的东西,还有更快的替代方案。

【讨论】:

  • 我很难相信。他们是 .net 框架的开发者。我可以假设他们会考虑它的设计和实现。我的问题是,如果他们知道如何更快地实现,为什么他们会选择较慢的实现方式。
  • 除此之外,有一个SetFastPixel 实现(或类似的东西)会让 API 的用户感到困惑。
  • 我并不是说他们应该创建一个 SetFastPixel 方法。我是说他们为什么不将 SetPixel 方法的实现更改为 SetFastPixel 实现。
【解决方案2】:

调用方法来设置单个像素本质上很慢,无论你如何实现它,因为对于每次调用,你必须计算和检查索引,转换像素格式等。

【讨论】:

  • 但是使用lockbits的方法更快。我的问题是,他们为什么不实施更快的方法而不是更慢的方法。
【解决方案3】:

实现处理特定位图格式很容易,但是可以通过多种不同方式将图像存储在内存中,因此实现处理所有格式的解决方案要复杂得多。

例如,位图可以正面朝上或倒置存储在内存中,行之间有或没有填充,每个像素有许多不同的位数。

实现这只是更多的工作,值得让方法更快一点。一次设置一个像素本来就很慢,所以如果你想提高速度,无论如何都不应该使用这种方法。

【讨论】:

  • 我找不到这方面的参考资料,但我记得读过 SetPixel 在内核中实现为 1x1 像素的 BitBlt 调用。这保证了它适用于所有驱动程序,因为它利用了 BitBlt 已经存在的管道,但代价是速度很慢。
【解决方案4】:

System.Drawing 中的类只是GDI+ 中使用的 C++ 类的一个薄层。 Microsoft 不会公开一个通用接口(System.Drawing 和 GDI+),并且有两个应该行为相同的类执行不同的操作。

【讨论】:

    【解决方案5】:

    SetFastPixel 可能不起作用的情况:

    • 单色设备(八个像素打包成一个字节)
    • Planar devices(16 色 VGA 卡的内存布局很奇怪,需要硬件协助)
    • 索引调色板设备(SetPixel 处理 RGB 到调色板索引的映射)
    • 打印机(我不知道这将如何通过LockBits 工作)
    • 多显示器配置,每张卡都有不同的像素格式

    SetPixel 旨在处理上述所有问题,但代价是速度很慢。如果您愿意牺牲以上几点,或者您乐于在应用程序中处理它们,那么您可以通过LockBits 绘制图像。

    【讨论】:

    • 我不确定我是否完全买了这个,当我们通过位图类访问时,位图存储在 RAM 中,我会想象一种格式更接近 bmp 文件格式而不是潜在的输出设备格式。
    • 对:这是设备相关位图和设备无关位图的区别。我不确定.NET 中的Bitmap 类是否假定为DIB; GDI 中的底层 SetPixel 函数早于 DIB 的存在,因此它支持您可以在其上创建 HDC 的任何内容。
    • 无论哪种方式,与实际执行工作的逻辑相比,确定我们正在处理的内存格式的逻辑将相对快速(且恒定)。这同样适用于“setfastpixel”。 Lockbits 的速度优势不是与支持的格式的权衡,而是与您一次性写入的像素数量的权衡。如果您使用锁定位一次写入一个像素,它们的性能将相同。
    • 假设 Bitmap 类只支持 DIB(因此不需要通过显示驱动程序),那么我不明白为什么它不能支持 SetFastPixel 方法。在这种情况下,“为什么 microsoft 不更改实现”的答案可能与许多类似问题相同,即功能请求的数量与实现和测试它们的资源之间的权衡。
    【解决方案6】:

    Direct3D 就是为此目的而创建的。尽管它的名字,它仍然可以进行原始的 2D 像素操作。一般来说,你这样做:

    • 创建 Direct3D 上下文和设备
    • 创建屏幕外表面
    • 锁定屏幕外表面,渲染到其显示缓冲区,解锁
    • 将屏幕外缓冲区复制到设备。

    是的,它比 GDI 复杂得多,但它与硬件和驱动程序紧密耦合,因此您可以准确控制渲染发生的位置以及渲染到屏幕的方式。你再也不想用 GDI 做任何高性能图形了。

    【讨论】:

    • 好吧,这看起来很有趣。我目前正在使用 Bitmap 类对小图像(256*256、512*512)进行图像转换。但是,它也应该适用于较大的图像。我会调查一下。您可能有一个在线示例吗?
    • 碰巧我今天写了一篇关于这个的博客文章,里面有一些示例代码。 explodingcoder.com/blog/content/…
    猜你喜欢
    • 2020-03-18
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    • 2014-03-12
    • 2014-03-29
    • 2021-10-12
    相关资源
    最近更新 更多