文档

Java™ 教程-Java Tutorials 中文版
双缓冲和页面翻转
Trail: Bonus
Lesson: Full-Screen Exclusive Mode API

双缓冲和页面翻转

假设你必须逐个像素或逐行在屏幕上绘制整个图片。如果你要将这样的东西直接绘制到屏幕上(使用,例如,Graphics.drawLine),你可能会非常失望地注意到需要花费一些时间。你甚至可能会注意到图片绘制方式的可见瑕疵。大多数程序员使用一种名为 double-buffering (双缓冲) 的技术,而不是按照这种方式并以这种速度观看事物。

Java 应用程序中传统的双缓冲概念非常简单:创建一个屏幕外图像,使用图像的图形对象绘制到该图像,然后,一步,使用目标窗口的图形对象和屏幕外的图像调用 drawImage。你可能已经注意到 Swing 在其许多组件中使用此技术,通常默认情况下使用 setDoubleBuffered 方法启用。

屏幕表面通常被称为 primary surface (主表面),并且用于双缓冲的屏幕外图像通常被称为 back buffer (后缓冲器)。将内容物从一个表面复制到另一个表面的行为通常被称为块线转移,或 blitting(blt 通常发音为“blit”并且不应与 BLT 三明治混淆)。

双缓冲

主表面通常通过任何显示组件的图形对象进行操作;在全屏模式下,使用全屏窗口图形的任何操作都是对屏幕内存的直接操作。因此,你可以利用全屏独占模式中的其他功能,否则由于窗口系统的开销而无法使用这些功能。仅在全屏独占模式下可用的一种这样的技术是称为 page-flipping (页面翻转) 的双缓冲形式。

页面翻转

许多显卡都有 video pointer (视频指针) 的概念,它只是视频内存中的一个地址。该指针告诉显卡在下一个刷新周期中在哪里查找要显示的视频内容。在某些显卡和某些操作系统中,甚至可以通过编程方式操作此指针。假设你创建了一个具有精确宽度,高度和位深度的后缓冲区(在视频内存中),然后以与使用双缓冲相同的方式绘制到该缓冲区。现在想象一下,如果不是像双缓冲那样将图像模糊到屏幕上,而是将视频指针改为后缓冲区,会发生什么。在下一次刷新期间,显卡现在将使用你的图像显示。这种切换称为页面翻转,基于 blt 的双缓冲的性能提升是只需要在内存中移动一个指针,而不是将整个内容从一个缓冲区复制到另一个缓冲区。

当页面翻转发生时,指向旧后缓冲区的指针现在指向主表面,而指向旧主表面的指针现在指向后缓冲区内存。这会自动为下一次绘制操作设置。

页面翻转

有时在 flip chain (翻转链) 中设置多个后缓冲区是有利的。当绘图所花费的时间大于显示器的刷新率时,这尤其有用。翻转链只是两个或多个后缓冲区(有时称为 intermediary buffers (中间缓冲区))加上主表面(这有时称为三级缓冲,四级缓冲等)。在翻转链中,下一个可用的后缓冲区变为主表面等,一直到最后面的后缓冲区,用于绘制。

双缓冲和页面翻转的好处

如果你的性能指标只是双缓冲或页面翻转的速度与直接渲染相比,你可能会感到失望。你可能会发现直接渲染的数字远远超过双缓冲的数字,并且这些数字远远超过页面翻转的数字。这些技术中的每一种都用于改善 perceived performance (感知性能),这在图形应用中比 numerical performance (数值性能) 更重要。

双缓冲主要用于消除可见的绘制,这可能使应用程序看起来像业余,缓慢或看起来闪烁。页面翻转主要用于消除 tearing (撕裂),当绘制到屏幕时发生的分裂效果比显示器的刷新率更快。更平滑的绘图意味着更好的感知性能和更好的用户体验。


Previous page: Passive vs. Active Rendering
Next page: BufferStrategy and BufferCapabilities