操作系统如何在屏幕上绘制窗口?

Posted

技术标签:

【中文标题】操作系统如何在屏幕上绘制窗口?【英文标题】:How does an operating system draw windows on the screen? 【发布时间】:2016-12-14 08:12:40 【问题描述】:

经过多年使用和编程计算机后,我意识到实际在屏幕上绘制的软件堆栈对我来说大多是个谜。

我曾开发过一些嵌入式 LCD GUI 应用程序,我认为这为简化堆栈提供了一些线索,但 Windows 操作系统之类的整体情况仍然模糊不清。

据我所知:

最低级别 0 是电子硬件(集成电路),它提供数字接口以将屏幕上的像素变为某种颜色或灰度阴影。该接口记录在数据表中,因此您知道如何切换数字线以按照您想要的方式转动任何像素。 下一级是硬件驱动程序。这通常将硬件抽象为一个通用接口。像 SetPixel() 之类的东西。

下一级 2 是 2D/3D 图形库(我对它的小部件/单屏体验有限)。较低的级别似乎提供了表示屏幕上像素的缓冲区或内存范围。图形库对此进行了抽象,因此您可以调用 DrawText("text", 10, 10, "font") 之类的函数,它会以正确的方式为您设置像素。

下一级将是操作系统的魔力。 windows/buttons/forms/WPF/etc 在内存中创建,然后路由到适当的驱动程序,同时也被定向到屏幕的某个部分?

但是像 Windows 这样的东西到底是如何工作的呢?

我假设 GPU 介于 0 级和 1 级之间。GPU 直接驱动显示器上的像素,现在 1 级驱动程序是 GPU 驱动程序。有更多功能可用于启用 GPU 提供的附加功能。 (这会是什么?操作系统是否在 3D 空间中传递一组三角形,GPU 将其处理成 3D 透视图,然后将其放到屏幕上?)

但对我来说最大的谜团是当你进入窗户部分时。您可以同时运行 Sketch Up、Visual Studio 和 FPS 游戏,并能够在它们之间切换,或者在某些情况下将它们平铺在屏幕上或然后分布在多个屏幕上。这是如何跟踪和渲染的?这些中的每一个都必须在后台运行,并且操作系统必须说明哪个图形管道应该连接到屏幕的哪个部分。 Windows 怎么会说这部分屏幕是 3D 游戏而这部分是 2D WPF 应用等?

最重要的是,您在一个应用程序中使用了 DirectX,而在另一个应用程序中使用了 Qt。我记得有多个游戏或应用程序运行使用相同的技术,那么它是如何工作的呢?据我所知,您将拥有 Application->Graphics library (DirectX, WPF etc)->Frame Buffer->Windows director(该帧缓冲区应该缩放到屏幕的哪个位置和哪个部分)->Driver?

最后,它只是位切换来指示哪个像素应该是什么颜色,但在到达那里的过程中它是一个地狱般的切换位。

如果我启动 Visual Studio 并创建一个基本的 WPF 应用程序,当我在屏幕上放置一个按钮并点击开始时,后台会发生什么?我已经看到 VS 设计人员将它放在上面,在 XAML 中创建它,我什至在嵌入式系统中逐个像素地手动绘制了东西,但在这两者之间会发生什么,即所谓的三明治肉?

我使用过 androidios、Windows 和 Linux,这似乎是一种常见的功能,但我从未见过或听过关于我上面概述的内容背后的解释,我只是有一个稍微有根据的猜测。

有人能解释一下这是如何工作的吗?

【问题讨论】:

【参考方案1】:

VGA

假设 x86,VGA 内存映射到最低 1 MiB 的标准视频缓冲区地址(文本模式为 0x000B8000,图形模式为 0x000A0000)。还有许多控制卡行为的 VGA 寄存器。有两种广泛使用的视频模式,模式 0x12(16 色 640x480)和模式 0x13(256 色 320x200)。模式 0x12 涉及使用 VGA 寄存器切换平面(蓝、绿、红、白),而模式 0x13 涉及使用 VGA 寄存器可以修改的 256 色调色板。

通常,依赖 VGA 的操作系统会在启动时使用 BIOS 设置模式,或者在运行时写入适当的 VGA 寄存器(如果它知道自己在做什么)。要绘制到屏幕上,视频驱动程序要么简单地写入视频内存(模式 0x13),要么将其与写入 VGA 寄存器结合起来(模式 0x12)。

当今使用的大多数卡仍然(部分)兼容 VGA。

VBE

几年后,VESA 发明了“VESA BIOS 扩展”,它是视频卡的标准接口,可实现更高的分辨率和更大的色深。显存通过两种不同的方式暴露出来:banked 模式和线性帧缓冲。 banked 模式会将一小部分视频内存暴露给低地址(0x000A0000),并且视频驱动程序几乎每次屏幕更新时都需要切换 bank。线性帧缓冲区是一种更方便的解决方案,它将整个视频内存映射到一个非标准的高地址。

在启动期间,操作系统会调用 VBE 接口来查询支持的模式并设置最方便的模式,或者它会绕过 VBE 接口并直接写入所需的视频硬件寄存器(如果它知道它在做什么) )。在分组模式和线性帧缓冲区之间,视频驱动程序将写入视频内存映射到的指定内存地址。

当今使用的大多数卡仍然(部分)兼容 VBE。

现代视频界面

最现代的视频接口通常不像 VGA 和/或 VBE 那样广泛记录。然而,视频内存仍然映射到一个地址,而硬件寄存器和/或缓冲区包含有关图形卡行为的可修改信息。不同之处在于接口不再标准化,现在高级操作系统需要为每个显卡提供不同的驱动程序。

【讨论】:

感谢 glauxosdever!据我所知,这听起来像我上面描述的 0 级/1 级。不过,仍然不确定这在更高层次上的表现如何。在 Linux 或 Windows 本身中的“窗口管理器”之前,它相当容易理解。非窗口操作系统看起来很简单,但是当您开始运行带有/不带有显卡的窗口管理器时,我无法找到有关幕后情况的信息。 Windows 内部是否只看到一个图形 API,其底层驱动程序系统处理图形是否通过管道传输到哪个图形控制器硬件? 通常,窗口管理器调用底层图形 API,然后调用(内核,然后调用)图形驱动程序。括号内的文字是否相关取决于内核是单体内核还是微内核。

以上是关于操作系统如何在屏幕上绘制窗口?的主要内容,如果未能解决你的问题,请参考以下文章

如何从python中的小部件在任何窗口上绘制

在没有窗口的windows桌面上绘制OpenGL

为啥在 GLFW 窗口中使用此代码在我的屏幕上没有绘制立方体?

OpenGL-坐标系

如何在没有窗口的情况下绘制文本

在 c(linux) 中绘制一个点的系统调用