什么机制允许双 Nvidia 卡帧缓冲区合并而无需 SLI?

什么机制允许双 Nvidia 卡帧缓冲区合并而无需 SLI?

首先,让我们确保我们都达成共识:

作为背景信息,请注意,当您启动操作系统时——任何操作系统——BIOS(或 UEFI GOP)告诉操作系统应该使用哪个图形适配器作为主帧缓冲区。主帧缓冲区基本上是虚拟内存的一个区域,当写入时,会导致图形驱动程序启动 DMA 传输以将帧数据发送到图形输出设备。显然,在多 GPU 配置中,情况并非如此简单,但一般的想法是,基本级别的操作系统只知道一个帧缓冲区。为了确定什么构成帧缓冲区,插入同一显卡的显示器被视为由同一帧缓冲区驱动。默认情况下,插入不同卡的显示器由不同的帧缓冲区驱动。目前有几种技术技巧可以帮助弥合不同帧缓冲区之间的硬件差距;因此我的问题...

假设您购买的显示器数量多于任何一张显卡上的端口数量。例如,如果您的显卡有一个端口,则您有两个显示器。如果您的显卡有两个端口,则您有三个显示器。依此类推。

还假设你不要想要 Eyefinity 或类似的设置,其中操作系统将所有显示器视为一个“大显示器”。

希望能够在不同的显示器之间无缝地拖动鼠标和窗口。

方法如下:

  1. 物理显卡桥接:Nvidia SLI 或 AMD CrossFire。这些解决方案允许您将“额外显示器”插入第二块独立显卡。两块显卡使用专用桥接硬件相互通信(对于最新一代 AMD Radeons,则使用 PCIe 总线)。

  2. 平台硬件辅助帧缓冲区共享:Nvidia Optimus、AMD Enduro、LucidLogix Virtu MVP……概念是一样的。您将显示器插入一张卡(通常是主板,用于使用处理器的 iGPU),并将显示器插入独立显卡。主板上的某些芯片有助于协调和同步这两个独立的显卡,以便操作系统只有一个帧缓冲区的错觉,这样您就可以拥有多显示器设置。请注意,其中一些解决方案还可以控制帧来自哪个 GPU呈现自,而不仅仅是输出帧的位置栅格化为

  3. 软件?:如果前两种硬件解决方案均不可用,显然仍然一种方法。例如,如果你的主板才不是拥有 Nvidia Optimus 或 LucidLogix Virtu MVP;你的牌是不是在 SLI 中;您仍然可以将 Nvidia GTX 280 和 Nvidia GT 210 插入同一台机器,您将获得相同的多显示器用户体验。您可以在显示器之间无缝移动鼠标和窗口。

我的问题是,在上面的第三个选项“软件?”中,这在 Windows 上是怎么实现的? 另外,那个特定的机制/功能叫什么?

  • 这是特定供应商的图形驱动程序的功能吗?
  • 它是内置于 Windows 本身吗?
  • 这该死的东西叫什么名字?

答案1

我认为您混淆了“帧缓冲区”和“一个大显示器”。您还假设用户空间可以直接访问显卡上的帧缓冲区。

假设最基本的窗口是一张简单的图像。对于操作系统来说,这只是一块主内存,用户空间可以在其中绘制像素。当操作系统/窗口系统发出信号时,图形驱动程序会以正确的空间/顺序将这些像素复制到显卡的帧缓冲区中。

伪代码如下:

int* MAIN_FRAMEBUFFER;
int RESOLUTION_X, RESOLUTION_Y;
struct WINDOW = {
  int x, y;
  int width, height;
  int* pixels; // virtual framebuffer
}
WINDOW[] all_windows;
int nr_of_windows
void draw_all_windows() {
    for(int i=0; i<nr_of_windows; i++) {
       // transfer the virtual framebuffer of every window to the graphics card
       WINDOW w = all_windows[i];
       for(int y=w.y; y<w.y+w.height; y++) {
           memcpy(&w.pixels, &MAIN_FRAMEBUFFER + w.x + y*RESOLUTION_X, w.width);
       }
       // Draw window manager decoration
       ...
    }
}

显卡驱动程序可以让您memcpy更有效地完成此操作,例如,只需将 WINDOW 结构复制到显卡内存中,然后在硬件中执行复杂的逐行复制。

在多显示器设置中,您只需对每个显卡重复该过程,仅复制该特定显示器上显示的窗口部分。

再次,用伪代码来说:

int* MAIN_FRAMEBUFFER1;
int RESOLUTION_X, RESOLUTION_Y;
// assume FRAMEBUFFER2 is to the right of FRAMEBUFFER1, and they have the same resolution
// the pseudo-code can be extended to allow a different resolution and orientation
int* MAIN_FRAMEBUFFER2;
struct WINDOW = {
  int x, y;
  int width, height;
  int* pixels; // virtual framebuffer
}
WINDOW[] all_windows;
int nr_of_windows
void draw_all_windows() {
    for(int i=0; i<nr_of_windows; i++) {
       // transfer the virtual framebuffer of every window to the graphics card
       WINDOW w = all_windows[i];
       for(int y=w.y; y<w.y+w.height; y++) {
           if(w.x + w.width < RESOLUTION_X) {
               // fully on monitor 1
               memcpy(&w.pixels, &MAIN_FRAMEBUFFER1 + w.x + y*RESOLUTION_X, w.width);
           } else if (w.x > RESOLUTION_X) {
               // fully on monitor 2
               memcpy(&w.pixels, &MAIN_FRAMEBUFFER2 + (w.x - RESOLUTION_X) + y*RESOLUTION_X, w.width);
           } else {
               // split between monitor1 and monitor2
               int monitor1_w_width = RESOLUTION_X - w.x;
               memcpy(&w.pixels, &MAIN_FRAMEBUFFER1 + w.x + y*RESOLUTION_X, monitor1_w_width);
               memcpy(&w.pixels + monitor1_w_width, &MAIN_FRAMEBUFFER2 + monitor1_w_width + (w.x - RESOLUTION_X) + y*RESOLUTION_X, w.width - monitor1_w_width);
           }
       }
       // Draw window manager decoration
       ...
    }
}

您可能会说这个系统很复杂。事实上,它已经通过使用 而简化DirectDraw,它允许您立即在显卡的帧缓冲区中分配一个内存块。但是,这个块与一个显卡绑定,这就是为什么当您使用 DirectDraw 将媒体播放器拖到第二台显示器时,您会看到绿屏。

注意:我不知道这在 Windows 7 或其他 3D 窗口环境中是如何工作的。我知道他们在纹理中写入窗口帧缓冲区并以 3D 形式渲染它。也许当您移动窗口时,纹理会被复制到另一张显卡?

最后,您参考 SLI 或其他系统。这与 2D 渲染无关。发生的事情是您将两张卡的内存集中在一起。然后,您指示每个 GPU 仅渲染屏幕的一部分。第二张显卡(未连接显示器)将其计算结果(像素!)写入主显卡的帧缓冲区,之后 VGA 或 DVI 芯片将其推送到显示器。需要桥接的原因是 1) 仅复制一次纹理和模型数据,即使两个 GPU 都使用它;2) 允许第二个 GPU 将像素写入第一个 GPU 的帧缓冲区。

您还提到了 Nvidia Optimus ea。该系统实际上与 SLI 非常相似。但是,桥接仅用于允许第二个 GPU 将像素写入帧缓冲区。芯片不共享任何纹理或顶点数据,并且无法协作渲染 3D 场景。

答案2

Parasietje 的回答是正确的,但也许是从某人认为你可以填补许多空白的角度来看待的。

2D 中的 Windows 不处理多台显示器。Windows 处理单个表面或多个离散表面,但完全忽略显示器,因为帧缓冲区完全由 GPU 处理,无需 Windows 的输入或干预。Windows 所做的只是将 2d 位图转储到内存中的特定位置,该位置已预先指定为“热区”,供完全不相关的帧缓冲区芯片从中获取屏幕刷新。这就是为什么即使没有驱动程序,您仍然可以看到显示的原因。您的 BIOS 将配置 VESA 模式,定义内存中要转储的位置,而不是其他位置。这是因为现代 GPU 对 Windows 来说是多个设备。一个或多个显示适配器 + 一个渲染加速器 + 一个计算核心。

问题就出在你的问题上。Windows 除了向适配器发出“启动 SLI”命令外,并未参与示例 1 或 2。

说得更明确一点。Windows 有“虚拟显示器”和“虚拟显示适配器”。前者可以是 VNC 或 RDP 连接,因为它们除了在创建图像后传递数据外什么都不做。对于 Windows 来说,这相当于写入该内存地址,并用于最终图像。

后者只是一种驱动程序定义的方法,用于将图像转储到屏幕上,但可以像通过软件渲染将模拟帧缓冲区输出到 SCSI 端口一样复杂,也可以像简单的“移动到此地址”命令一样简单。大多数情况下,它只不过是后者。这是为了将最终图像从内存传输到屏幕上。

3D 很重要,因为这就是它在 2D 中的工作方式,因此您的显卡无需驱动程序即可工作。Windows 在 2D 中工作,因此得名。如果留给 Windows 输出子系统,您的 GPU 将永远不会处理任何渲染,就像没有线程,您的 CPU 永远不会使用第二个核心一样……Windows 根本不知道要向它发送什么工作,甚至不知道它接受工作。即使是 2D 渲染也必须以这种方式完成。

3D 更为复杂,并且是每张卡的专有技术,通过 DirectX/OpenGL 或 directDraw(我现在主要使用 DX)工作,而对于 Windows 来说,它是一个黑匣子。这就是为什么所有卡都必须在内部支持这些 API 才能玩游戏的原因……Windows 只是将它无法理解的命令传递给驱动程序。这两个 3D API 都将 GPU 的处理部分“插入”在 Windows 2D 渲染器和 Windows 的虚拟显示器之间,然后通过包含专有命令的驱动程序将虚拟显示器桥接到 GPU。顺便说一句,当我说专有时,我的意思是 VLIW/GCN/Geforce 生成特定代码。

这就是您的 GPU 一旦有了驱动程序,就能够直接渲染到它自己的帧缓冲区的方式,而在此之前,当处于 VESA 模式时,您的 CPU 正在渲染并写入 RAM,然后您的 BIOS/EFI 将其从 RAM 传递到输出。

这也是为什么您的设备在设备管理器中显示为 1 而不是 3。

相关内容