跳转至内容

Aros/开发人员/文档/HIDD/图形

来自维基教科书,开放世界中的开放书籍
Aros 维基教科书的导航栏
Aros 用户
Aros 用户文档
Aros 用户常见问题解答
Aros 用户应用程序
Aros 用户 DOS Shell
Aros/用户/AmigaLegacy
Aros 开发文档
Aros 开发人员文档
从 AmigaOS/SDL 移植软件
Zune 初学者
Zune .MUI 类
SDL 初学者
Aros 开发人员构建系统
特定平台
Aros x86 完整系统 HCL
Aros x86 音频/视频支持
Aros x86 网络支持
Aros Intel AMD x86 安装
Aros 存储支持 IDE SATA 等
Aros Poseidon USB 支持
x86-64 支持
Motorola 68k Amiga 支持
Linux 和 FreeBSD 支持
Windows Mingw 和 MacOSX 支持
Android 支持
Arm Raspberry Pi 支持
PPC Power Architecture
杂项
Aros 公共许可证

所有显示驱动程序操作都已移至 monitorclass。这应该可以作为良好的抽象层。为了完成这个,让我们添加 monitorclass 将是 Intuition 与图形驱动程序对话的唯一地方。所有其他函数将使用 monitorclass 而不是直接调用驱动程序。目前这只是 OpenScreen()。唯一的例外将是 pointerclass,它在精灵的位图中安装一个颜色映射。顺便说一下,实际上我们也可以删除它,我们需要在 AllocSpriteDataA() 中添加另一个标记,类似于 SPRITEA_Palette。

1. 在 GRUB 命令行中指定 gfx= 和 lib= 仍然有效。只要 DEVS:Monitors/Default 文件存在,它就会起作用。

2. 如果你想的话,你可以加载额外的驱动程序。对于新式驱动程序,只需将驱动程序从 Storage/Monitors 移动到 Devs/Monitors。目前只有 SDL 驱动程序是新式的。你也可以使用你的旧驱动程序(NVidia、Radeon、VMWare)。要做到这一点,请在 Devs/Monitors 中复制 Storage/Monitors/Wrapper 文件(名称无关紧要,你可以将副本命名为 "NVidia"、"ATI" - 任何你喜欢的名称)并编辑图标的工具类型(在其中指定库和 HIDD 名称)。请注意,你不能同时拥有多个相同旧式驱动程序的实例 - 它们的设计根本不是为了实现这一点。

3. 不要尝试做一些奇怪的事情,比如通过 Wrapper 同时实例化 VGA 和 VESA。这些驱动程序很特殊,它们只能管理单个显示器,并且它们不能共存,即使在理论上也是如此。这就是硬件的工作方式,而不是软件问题。随着时间的推移,它们将被重写,变得更加健壮,并且对这种强奸具有更强的抵抗力。:)

4. 对于托管:你可以创建多个 GDI 显示器(在 Windows 上),只需编辑 GDI 图标的工具类型。SDL 在设计上不允许这样做(同样,SDL 设计,而不是驱动程序设计)。X11 可以允许这样做,但它太古老了。需要志愿者来修复它。我可以解释如何做。

5. 你可以在运行时添加显示驱动程序。只需双击其文件就可以了!但是请注意,在你运行 VGA 或 VESA 模式时这样做可能会导致问题(如果新的驱动程序尝试从 VGA 驱动程序那里窃取硬件,而 VGA 驱动程序正在显示你的屏幕)。只需重启,一切都会好起来的。正确的引导模式关闭是一个棘手的部分,目前有点设计不足。把它看作一个正在进行的工作。如果你运行针对不同卡的驱动程序,就不会有问题。如果你已经运行了本地驱动程序 - 同样,没有问题,本地模式驱动程序可以完美地共存(例如 NVidia + ATI)。

FindName("hidd.graphics.gc") 可以像属性 ID 一样处理。方法 ID 也按顺序编号。知道第一个方法的 ID(即基本 ID)就足够了,然后将 mo_... 偏移量加到它上面。

将显示驱动程序的初始化移动到 C:LoadMonDrvs。不!它现在处于这个位置是有道理的。加载显示驱动程序意味着卸载引导模式驱动程序。卸载驱动程序在技术上只有在根本没有屏幕的情况下才有可能。因此,从一个没有启动序列的 shell 中执行 C:LoadMonDrvs,甚至由于某些错误而自动打开了 shell,都将导致崩溃。恕我直言,这很不友好。

> 虽然我相信在 PC 架构中(仍然?)存在一些技术原因,需要 AROS 确保在 Intuition 启动之前加载显示驱动程序。这不是 PC 架构的限制。这是 AROS 的限制。如果驱动程序有一些位图,它就不能被卸载。从理论上讲,可以通过强制关闭所有窗口和屏幕来实现安全卸载,但这将很困难,并且可能需要大量的代码。所以,请把它放在这里。并在引导菜单中的 "显示选项" 中添加一个 "不要加载显示驱动程序" 复选框。

目前,AROS 中的每个 HIDD 位图都有一个 Hidd_BitMap_GfxHidd 属性,用于指示创建该位图的驱动程序。通常情况下,涉及此位图的所有操作都应该使用此驱动程序执行。例如,如果我要为某些绘图创建 GC,我应该在位图的驱动程序上调用 HIDD_Gfx_NewGC()。

但是,如果操作涉及两个位图怎么办?例如 CopyBox()?我应该在哪个驱动程序上调用它?这里至少有三种情况


  • 两个位图都属于同一个驱动程序。
  • 这是一个简单明了的案例。
  • 一个位图是内存位图,另一个位图是显示驱动程序的位图。

有点棘手。我应该调用哪个驱动程序?内存驱动程序还是卡驱动程序?内存驱动程序相对较慢,但可以与任何东西一起使用。卡驱动程序怎么样?它有可能使用 DMA 来加速操作。但是,在创建内存位图时,需要考虑位图的一些限制(例如对齐方式)。因为只有卡驱动程序知道这些限制,所以我们应该在它的驱动程序上调用 HIDD_Gfx_NewBitMap() 来创建内存位图。但是,我们现在可能不知道在创建位图时使用哪个驱动程序。好吧,可能的解决方案是查询朋友位图。如果没有朋友 - 抱歉,运气不佳。这意味着我们始终在卡的驱动程序上执行 CopyBox()。卡驱动程序应该检查内存位图,如果可能的话加速操作(它在正确的位置并且具有正确的格式)。否则,调用超类。

both  bitmaps are display bitmaps but belong to different drivers (different displays on different GFX cards).

是问题最大的情况。调用哪个驱动程序?从理论上讲,两张卡有可能执行从一张卡到另一张卡的 DMA 数据传输吗?或者同一张卡的两个独立输出(从机器的角度来看,它们是两个不同的设备 AFAIK)?

下一个大问题是,如何处理两个对象池。其中一个保存 GC,另一个保存临时平面位图对象。从第一点来看,它们应该只是全局的。但只是从第一点来看。如果我们更深入一点,GC 类可能会被子类化(目前还没有人这样做,这就是它仍然有效的原因)。目前,graphics.library 只是创建 CLID_HIDD_GC 类的对象,考虑到子类,这是错误的。GC 应该使用 HIDD_Gfx_NewGC() 在将使用它们的驱动程序上创建。这意味着 GC 缓存应该保持特定于驱动程序。

至于平面位图,情况要复杂得多。上面我们得出结论,如果内存位图符合特定要求,它们可以是 VRAM 位图的朋友。在这种情况下,卡驱动程序可以使用硬件加速来处理它们。但是,这意味着我们不能从缓存中取出任意空对象并将其附加到任意位图。位图是在没有任何东西的情况下创建的,因此尝试附加具有指向 GFX 驱动程序的 GfxHidd 属性的对象是毫无意义的。它很可能不会起作用!即使我们为每个驱动程序都有单独的池,这也无济于事,因为临时对象不会以任何方式与其位图相关联。池变成了污水池。:)

是的,我们始终可以使用内存驱动程序创建平面位图(CLID_HIDD_Gfx 类的对象)。但是,在这种情况下,我们应该准备好,因为与平面位图一起工作始终很慢,因为它始终使用 CPU 执行。

1. nvidia 或 ati hidds(或任何其他 hidds)都不允许直接戳 gfx.hidd 的私有平面 bm 数据。2. 给定字体的平面位图只创建 *一次*,并被多次使用。3. nvidia 和 ati hidds 可能会在其中存储以最佳方式优化字体绘制的平面数据。

graphics.library 不会直接戳此位图,因此 nvidia 和 ati hidds 有它们自己的平面位图,它们 *被允许* 直接戳。看看那里定义的 BlitColorExpansion 方法。

像素格式

[编辑 | 编辑源代码]

在 HIDD_BM_GetImage() 和 HIDD_BM_PutImage() 调用中使用 vHidd_StdPixFmt_ARGB32 而不是 vHidd_StdPixFmt_Native32。

这真是奇怪的行为。首先,你设置了 aHidd_Gfx_SupportsHWCursor 为 TRUE 吗?如果没有,你会得到未定义的行为,因为 fakegfx.hidd 会插入,而它依赖于帧缓冲区的存在。

屏幕拖动

[编辑 | 编辑源代码]

你可以实现屏幕拖动。注意两个属性:

aHidd_BitMap_LeftEdge

aHidd_BitMap_TopEdge。

ScrollVPort() 只设置它们。在代码中做你需要做的任何事情。它们也应该可以获取(超类总是返回 0)。这用于为驱动程序提供修复无效偏移的能力。设置这些属性后,ScrollVPort() 会获取它们,只有在获取它们之后才会进入 ViewPort。这样你就可以限制滚动。

偏移量从物理屏幕角落到位图角落(即,如果你在比屏幕大的位图周围平移,它将为负值)。

为了告诉 Intuition 屏幕可能比显示器更大或更小,还有额外的同步属性:Sync_VMin、Sync_VMax、Sync_HMin、Sync_HMax。默认情况下,它们分别等于 HDisp 和 VDisp,但如果你显式设置它们,它将被覆盖。

帧缓冲区

[编辑 | 编辑源代码]

首先,我可以解释当你调用 DoSuperMethod() 时为什么它以这种方式工作。看看基类中的 Show() 实现。如果帧缓冲区不存在,它将返回 NULL。这意味着 SDD(GfxBase)->frontbm(参见 rom/graphics/grtaphics_driver.c,SDD(GfxBase)->driver_LoadView())将始终保持 NULL。在比较之前,这样 Show() 就不会对同一个位图调用两次。

我想你需要在 driver_LoadView() 中添加一些调试输出,以便查看发生了什么以及为什么。记住,当你始终在你的 Show() 中返回 msg->bitMap 时,事情应该能够正常工作。

对 driver_LoadView() 中实际做了什么的一些解释

当系统使用帧缓冲区时,只有一个帧缓冲区位图是真正可显示的,它总是显示在屏幕上。graphics.hidd 基类在它的 Show() 中只是将要显示的位图复制到帧缓冲区,并返回帧缓冲区指针。然后 driver_LoadView() 中的代码获取正在显示的 struct BitMap 并交换其中的对象。原始对象保存在 SDD(GfxBase)->bm_bak 中。另外还有两个保存的东西是颜色模型编号和颜色映射对象。从 Show() 中返回原始指针使这段代码实际上什么也不做(对象被交换为自身)。

以下方法和属性已添加到我们的图形类中:

1. HIDD_Gfx_GetGamma() 和 HIDD_Gfx_SetGamma() - 在自动文档中解释。它们的设计方式使得可以在它的基础上实现 MorphOS API(如果我们想要的话)。

2. 更改显示频率。为了使它们可更改,你必须:- 为你的同步对象提供 aHidd_Sync_Variable = TRUE。- 你的同步对象应包含完整数据(aHidd_Sync_HSyncStart、aHidd_Sync_HSyncEnd、aHidd_Sync_VSyncStart 和 aHidd_Sync_VSyncEnd 不应为零)。

Implement  HIDD_Gfx_SetMode()  method  in your graphics driver.

此方法现在接收指向已修改的同步对象的指针。你没有切换屏幕,所以你保留当前位图。你只是收到通知,表明此同步已更改。驱动程序预计会检查给定的同步是否当前显示,并在需要时重建显示。

Show gets called with bitmap
From bitmap I extract ModeID
Using ModeID I get Sync from moHidd_Gfx_GetMode
This sync is stored

我应该将传递的 Sync 与我在 Show() 期间存储的 Sync 进行比较吗?如果是,比较应该如何进行 - 通过检查指针(它是同一个对象)还是通过检查两个同步之间的 aoHidd_Sync_HDisp/aoHidd_Sync_VDisp?另外,如果我传递的同步具有与当前同步不同的 hdisp/vdisp(意味着我需要新的位图)怎么办?

为了尝试 (2),MonED 程序可以做到。它可以作为 Prefs/Monitor 构建。它默认情况下不会被构建,因为目前它非常实验性。

P.S. MonitorSpec 中 total_color_clocks 的修改会导致 aHidd_Sync_PixelClock 的修改,而 aHidd_Sync_HTotal 保持不变。我不知道它是否正确,如果需要,请修改它。但是,如果这两个参数都需要更改,也许需要直接访问同步对象。同步对象指针被放置到 SpecialMonitor->reserved1 中,我认为它将永远保留在那里。

首先,现在获取对象并对其使用 OOP 调用完全没问题。相应的 MonitorSpec 将被自动维护。

其次,同步对象变得非常智能,它不允许修改不应该修改的东西(例如 VDisp/HDisp、Variable、Description 等)。

第三,现在你将收到通知,如果某些东西真的发生了变化(某个计时属性被提供给了 OOP_SetAttrs())。

第四,do_monitor() 仍然存在,它仍然有效。但是我将其更改为修改 HTotal 而不是 PixelClock。我认为它接近原始行为。我同意它不适合我们的视频硬件,所以你可以随意从头开始编写你自己的显示模式编辑器。:)

一个关联的同步对象可以在 MonitorSpec->ms_Object 中找到(这是从未使用过的 DisplayInfoDatabase 列表的别名字段)。你可以简单地获取此对象,并对其使用 OOP_GetAttr() 和 OOP_SetAttrs()。你的图形驱动程序将被同步对象自动通知,你不需要自己调用 SetMode()。

HIDD_Gfx_NewOverlay() 只为叠加保留内存。保留内存与当前屏幕模式无关。接下来需要将叠加显示在屏幕上。我建议会有一个 HIDD_Overlay_Show() 方法。

由于叠加对象是由图形驱动程序对象创建的,因此驱动程序可以使用叠加类实现的私有属性传递对任何所需数据的引用。

驱动程序根据给定的矩形和当前可见显示的分辨率准备缩放。

这也通过从驱动程序对象传递数据到叠加对象来实现。

我会将此留给驱动程序。许多卡支持 *任何* 关键颜色,但是假设所有图形芯片都符合这种说法将是一个错误的决定。让图形驱动程序自行决定。

嗯... 我在这里看到一个大问题... 正如我所理解的,颜色键用于启用具有附加叠加层的深度排列窗口。叠加层的区域被关键颜色填充,叠加层仅通过此颜色可见。

但让我们想象一下这样的情况...

+------------------+
|                  |
|  video window    |
|          +--------------+
|          |     some     |
+----------|     fancy    |
           |    painting  |
           +--------------+

如果关键颜色恰好在“一些花哨的绘画”中出现,那么视频将在那里而不是它出现的地方可见,在它覆盖视频窗口的部分。该怎么办?我怎么知道关键颜色永远不会出现在桌面上?它是谁生成的并不重要。第二个窗口甚至可以在颜色生成时未打开。

顺便说一句,不要忘记实现 SwapVLayerBuffer() 和 VOA_DoubleBuffer/VOA_MultiBuffer 标签。使用 mplayer 及其字幕,尤其是在三缓冲叠加层时,效果要好得多。:)

关于深度,它遵循 Intuition 窗口,但要实现这一点,你需要在创建 vlayer 时设置 VOA_ColorKey 标签(我认为这将默认情况下用某种特定填充色填充 Intuition)。使用此颜色键,cgxvideo 知道在窗口的哪个地方显示叠加视频,在哪个地方不显示。因此,如果窗口被部分或全部覆盖,vlayer 将相应地进行处理,遵循深度排列。

颜色键将是下一个问题。因此,我理解正确吗?

1. 如果你将 VOA_ColorKey 指定为 TRUE,系统将拾取一些用于键控的颜色,并在窗口中的叠加层区域用此颜色填充。2. 我可以在任何时候使用 VOA_ColorKey 和 VOA_ColorKeyPen 的 GetVLayerAttr() 获取颜色值和笔号。3. 之后,视频叠加层将根据用关键颜色填充的显示部分进行裁剪。

驱动程序应该提供关键颜色值(因为硬件可能对其施加一些限制)还是库应该拾取它并提供给驱动程序。

如果(理论上)一个显示器上可能存在多个叠加层?对于少于两块显卡来说,多个真正的叠加层听起来非常不可能——实际上,cgxvideo 的 API 允许这样做,但是这从未在 AOS 下实现(至少在公开可用的卡上是这样)。

通常情况下,应用程序希望获得单个的快速叠加层——如果有多个叠加层,并且所有额外的叠加层速度较慢,那么这就会引发一个问题,为什么在这种情况下不直接对位图进行 blit 操作。

因此,如果存在多个叠加层——其中一些是模拟的,并且可能模拟速度很慢——那么也应该有一种方法让应用程序确定当前锁定的叠加层是否是真正的叠加层。这样,它们就可以在这两种方法之间进行选择(例如,使用自己的 AltiVec 代码并直接 blit)。

这取决于硬件,实际上也取决于驱动程序。视频叠加层可以以两种方式实现:

1. 作为 gfx 卡支持的真正的叠加层。在这里,允许一、二或三个叠加层对象同时共存(尽管一个叠加层是最常见的情况)。2. 叠加层可以是 3D 引擎 blit 的 2D 表面。在这里,可用叠加层的数量仅受可用内存的限制。

实现一个类似于位图类的视频叠加层类。这将允许创建多个叠加层(如果某些硬件支持的话)。顺便说一句,也许位图和叠加层没有什么区别?没有必要为位图和叠加层都提供相同的设置?在这种情况下,我们将不得不扩展像素格式类以适应新的格式(如 YUV 或 YPbPr)。通常情况下,人们不会对叠加层对象使用任何像线/矩形绘制这样的方法。直接访问 YUV 数据更有可能。你可能已经检查过了,但是关于 cgxvideo,以下几点需要牢记:

SRCFMT_YUV16
(not recommended, use YCbCr16 instead)
SRCFMT_YCbCr16
SRCFMT_RGB15PC
SRCFMT_RGB16PC

即,需要支持四种格式,而 YUV 不是推荐的一种格式。

YcbCr16 工作良好,并且明显比 RGB 更适合像 mplayer 这样的应用程序,它提供 YUV 数据。但是你的 cgxvideo 文档有点过时了。几年来还有一种额外的像素格式:SRCFMT_YCbCr420(YV420,平面叠加层),当 gfx 卡支持它时,它非常有趣,因为它只需要 12 个位/像素,而不是 16 个位/像素,在复制时可以带来不错的速度提升。

ScreenDepth()

[编辑 | 编辑源代码]

Screendepth() 始终调用 RethinkDisplay(),即使屏幕顺序没有改变。如果您查看 ScreenDepth() 代码,您会发现它会检查屏幕是否已经是第一个/最后一个。您可以尝试将 RethinkDisplay() 移到这些条件中。

另一方面,据我所知,原始的 MrgCop() 不会在已经激活的视图上覆盖屏幕。因此,实际的问题可能是您的驱动程序中的实现不正确。

我建议使用以下模型:每个位图包含两种状态:实际状态和待处理状态。待处理状态在 PrepareViewPorts 期间重新计算,在 ShowViewPorts 期间待处理状态变为活动状态。只有当新状态与旧状态不同时,才会发生实际的硬件更新。是的,ShowViewPorts 在活动视图上紧随 PrepareViewPorts 之后。

多显示器/卡简介

[编辑 | 编辑源代码]

使用不同的驱动程序实例比引入像单元这样的新概念更容易。此外,它完美地契合了 OOP 范式。

驱动程序 = 类,实例 = 对象。同一卡上的多个输出 = 多个类似卡 = 一个类的多个对象。

首先,DEVS:Monitors 和 SYS:Storage/Monitors 目录出现了。目前 Storage/Monitors 是空的(除了托管端口),DEVS:Monitors 只包含单个 Wrapper 文件。现在显示驱动程序可以以新形式出现 - 作为放置在 DEVS:Monitors 目录中的普通可执行文件。构建此类驱动程序的示例是 arch/all-hosted/hidd/sdl 中的 SDL 驱动程序。注意 startup.c 文件及其注释。

为了编写一个启动时驱动程序(可用于启动系统),需要在驱动程序中添加一个简单的 struct Resident,它将调用其启动代码。无需构建库或类似的东西。

Wrapper 程序的功能是加载以旧方式指定(在内核命令行或 S:hidd.prefs 文件中)的显示驱动程序。注意,它完全忽略了输入驱动程序,它们现在完全分离了。这允许使用旧的显示驱动程序,直到它们被重写。

我强烈建议显示驱动程序作者将他们的代码转换为新形式。一段时间后,对 S:hidd.prefs 和命令行参数的支持将被完全移除。

显示驱动程序启动代码应执行以下操作

1. 打开所需的库,获取 OOP 属性基类,创建 OOP 类。类不必是公开的,没有人会通过名称引用它们。

2. 扫描可用硬件(PCI 总线、OF 树,等等)并为每个支持的设备创建图形驱动程序对象。

3. 对每个创建的对象调用 graphics.library/AddDisplayDriver()。该函数在成功时返回零,在失败时返回非零值。在出现双启动(如果用户双击您的驱动程序图标,只是为了好玩  :))的情况下,驱动程序作者应该做什么完全取决于驱动程序作者。通常,驱动程序不应重新添加已经使用的硬件。我们当前的 PCI 子系统不支持设备所有权,也许需要更改这一点。您可以自由地发明任何东西。例如,SDL 驱动程序通过将它的 OOP 类注册为公开的,并在每次启动时尝试找到这个类来做到这一点。如果该类已经存在,则我们已经在运行。

注意,当前 AddDisplayDriver() 是一个 HACK!它关闭并销毁之前安装的显示驱动程序,并将其从数据库中删除。所以现在不要创建超过一个对象。在您的代码中实现一些 #define。当 graphics.library 完全支持多显示环境时,需要删除此 #define。客户端唯一知道的是“我们有一个显示器,这里就是它的实例”。AddDisplayDriver() 函数执行此操作。它将驱动程序插入数据库并为其分配监视器 ID(模式 ID 的上半部分)。仅此而已。之后,用户可以在哪个显示器上打开他们的屏幕。所有显示器的工作方式类似。

用户只需要将显示驱动程序从 Storage/Monitors 移动到 DEVS:Monitors 就可以激活它。如果它找到硬件,它将自动安装到系统中。如果没有可用的硬件,它将不做任何事情。

显示驱动程序可能有图标。加载程序代码查看 STARTPRI 工具类型并使用它的值作为优先级级别。这样做是为了使显示模式 ID 分配在未来更可预测(ID 按驱动程序加载的顺序分配)。

注意,SDL 驱动程序不能再从 S:hidd.prefs 加载,因为它不再是库了!只需将其放置到 DEVS:Monitors 并重启,其余操作将自动完成。

注意,目前不能动态添加显示驱动程序。尝试这样做会导致不可预知的结果。这是 graphics.library 的问题,支持不完整。所以,现在不要尝试手动运行显示驱动程序!特别是 Wrapper,它目前在设计上无法进行双启动保护(好吧,可以,但我不想麻烦代码,这些代码过一段时间就会消失)。

第 2 部分。输入子系统。

为了透明地处理(可能是多个)输入源,设计了两个新的 HIDD:keyboard.hidd 和 mouse.hidd。它们与 PCI“主类”的作用相同。它们负责驱动程序和客户端之间的通信。

为了开始与输入子系统对话,程序(或驱动程序)需要创建一个 CLID_Hidd_Kbd(键盘)或 CLID_Hidd_Mouse(鼠标)的实例。程序可以在对象创建期间提供回调函数,在这种情况下,程序将充当客户端并接收输入事件。回调在中断上下文中执行,与以前一样。目前,唯一的客户端是 keyboard.device 和 gameport.device。lowlevel.library 欢迎加入他们  :)。

为了注册输入驱动程序,需要在“主”对象上调用 AddHardwareDriver() 方法。此调用的参数是驱动程序类指针(而不是 ID!)和可选的附加标签列表。您不需要提供预先制作的对象,因为主类需要为每个驱动程序提供自己的回调函数。

可以在任何时刻注册驱动程序,没有任何限制。

来自多个驱动程序的输入流只是合并成一个单一的流。

AddHardwareDriver() 返回指向驱动程序实例的指针。它可以随时使用 RemHardwareDriver() 移除。无需在上面调用 OOP_DisposeObject(),因为 RemHardwareDriver() 会自行执行此操作。

!!! 我需要帮助  !!!

其他架构需要进行一些清理。需要将启动代码添加到 PC 原生鼠标和键盘驱动程序中。他们需要学习如何自行注册。目前,它们由 dosboot resident 使用向后兼容的 kludge 代码注册,该代码依赖于旧式的 struct BootConfig。我知道,Michal 讨厌它,它确实需要被移除(目前 X11 和 PC 原生输入依赖于它,我认为我很快就会自己更新 X11)。此领域的其他一些任务是

1. 在 bootmenu 中实现启动选项和显示选项屏幕。启动选项屏幕可能会呈现与原始 AmigaOS 类似的选择。显示选项屏幕至少可以包含一个取消选中标记,它会禁用加载显示驱动程序(这就是我决定将加载程序放在 dosboot 中而不是放在 Startup-sequence 中的原因)。也许它甚至可以做一些更高级的事情,比如列出可用的驱动程序并允许禁用其中一些(可以通过更多 dosboot 大修来实现)。2. 将串行鼠标驱动程序与 PS/2 鼠标驱动程序分离。新的输入子系统允许它们共存,甚至同时协同工作。3. 在 lowlevel.library 中实现更多功能(因为目前可能存在多个输入事件监听器)。4. 为 Monitors 抽屉和显示驱动程序绘制图标  :)。

华夏公益教科书