Aros/平台/68k 支持/开发者/HIDD
第一阶段:支持具有自定义引导块的程序,可能使用 trackdisk.device 加载更多轨道,然后其余部分使用硬件敲击加载器。
第二阶段:支持使用启动序列引导至 CLI 的程序。
cia.resource(rom/cia)似乎是一种特殊情况(mmakefile.src 中的注释,它包含 ciaa 和 ciab.resources)。我无法编译它,甚至不能编译原始的框架版本。如果我尝试编译它,我会收到“<path>/build/bin/amiga-m68k/gen/rom/cia/include/cia_deflibdefs.h: 没有此文件或目录”错误,我认为某些东西需要“正常”库?问题很可能是因为 rom/cia 使用 build_module_simple 将 ciaa/ciab 弄成一个模块。build_archspecific 很可能假设 build_module 用于通用文件(或者更清楚地说,genmodule 应用程序被使用)。
解决方法是,你需要一个包含 ciaa 和 ciab 的物理模块 cia.resource -> 将 rom/cia 复制到 arch/m68k-amiga/cia,将目标名称更改为类似 kernel-cia-amiga-m68k 的名称,只使用它(不要使用 %build_archspecific)。也许只是修复 %build_archspecific?这绝对是一个缺陷。在工作日,我会看看是否有人解决了这个问题。应该不会太难。也许 %build_module_simple 只是缺少使用 %build_archspecific 的能力。我记得我为 %build_prog 修复了这个问题。但是如何将它添加到 kernel-link-amiga-m68k 最终的 rom 映像中?尝试 make kernel-cia-amiga-m68k-kobj -> 有一个由 %build_module_simple 宏创建的自动化的 something-kobj 目标
顺便说一句,addicrvector.c 在成功添加新中断后缺少 AbleICR(resource, 0x80 | (1 << iCRBit));
现在 cia 资源存在了,我尝试创建键盘 hidd。我拿了 PC 键盘 hidd 驱动程序,删除了所有 PC 特定的代码,添加了 Amiga 键盘处理(CIA 中断 + 握手)。在你的 %build_module_simple 调用中添加 uselibs="rom"(查看例如 arch/i386-pc/drivers/keyboard/mmakefile.src)(你可能需要的其他库是:oop amiga)。再次感谢,“rom”解决了问题。“oop”已经包含了。(我实际上使用了 i386-pc 键盘驱动程序作为基础,它没有“rom”)。现在它在初始化期间出现在驻留列表中,但 kbd.hidd 似乎没有初始化。我肯定错过了一些简单的东西,再次.. 你的键盘 hidd 类需要在模块启动期间明确地在主键盘类中注册自己(至少在 pc-i386 中是这样,请参见 i386-pc/drivers/keyboard/startup.c)。但是要做到这一点,主键盘类必须已经启动并运行,从你的日志来看,你的 kdb.hidd 在 keyboard.hidd 之前初始化。顺便说一句,在 pc-i386 中,键盘类的优先级很低(10),因此它即使在 intuition.library 之后也会初始化 - 这意味着你遇到的 input.device 崩溃可能不是由缺少键盘类触发的。正是如此。只需将它的优先级降低 1/10。键盘 hidd 现在加载了(和优先级太高一样简单..)。完全可以不使用 input HIDD 来工作,你只是不会收到事件,仅此而已。EFIKA 就是这样工作的(它没有 PS/2 硬件)。我还实现了虚拟的 amigamouse.hidd(目前不做任何事情)。input.device 不再调用 alert()。
来自 KickStart 3.0 的“card.resource”想要调用 Exec #136(紧随 TaggedOpenLibrary,#135),但 AROS 没有实现。或者任何地方有文档提到它。在 3.9 SDK 中,它被列为 'ExecReserved12'。函数的名称是 ReadGayle()。如果 Gayle 芯片在板上,它将返回 Gayle 芯片的 ID,否则如果不存在此类芯片,则返回零。它首先检查是否在 DE1000 处也镜像了正常的自定义芯片,如果是,则没有 gayle。然后,它将一个零写入 gayle ID 寄存器(上面的地址),然后从同一地址执行八次连续读取。每次读取的位 7 贡献一个位到整体 ID。将第一次读取的位 7 放入位 7,第二次读取的位 7 放入位 6 等……给出 gayle 芯片的完整 ID。如果结果是 0xff,则此地址没有芯片,函数返回零。否则,它将返回读取的数据。显然,card.resource 需要 gayle ID 来知道 pcmcia 端口的接口是否可用 - 并且这由 gayle 控制。只需创建一个返回 0 的空函数,并在 Amiga 端口中覆盖它。
鼠标光标通过驱动程序类的 Get 方法支持硬件光标,你需要返回它(其中一个就足够了)
case aoHidd_Gfx_SupportsHWCursor: *msg->storage = (IPTR)TRUE; return; case aoHidd_Gfx_HWSpriteTypes: *msg->storage = vHidd_SpriteType_DirectColor;
你需要实现以下方法
SetCursorShape SetCursorPos SetCursorVisible
如果你需要示例,请查看 nouveau 驱动程序:AROS/workbench/hidd/hidd.nouveau
你是否检查了位平面和铜 DMA 是否已启用,以及铜列表是否看起来正常?(在 UAE 调试器中使用 O 命令)
我现在有一个非常有趣的行为,如果我在 WinUAE(使用最快可能的模式)中正常运行它,软件会失败并重置。如果我启用调试器的“跟踪”模式(任何断点都处于活动状态,并且它开始收集可以使用 H 和 HH 命令查看的跟踪数据),它可以正常运行。
最快的可能模式下的调试器可能会将中断检测延迟一个 CPU 指令。循环精确模式也可以正常工作。你可以在遇到意外异常后禁用自动重启(start.c/Exec_FatalException)?它使调试变得令人讨厌(我用无限循环替换它)
gallium 的维护者查看过这个吗?我不知道我们是否可以在 gallium 中安全地使用 Disable()/Enable()。这很可能会杀死或严重影响性能。我假设 gallium 给 m68k 带来问题。你可以做两件事
a) 禁用为 m68k 架构构建 libgalliumauxiliary、gallium.library、mesa.library、gallium.hidd 和 softpipe.hidd(例如,使用你自己的 workbench-libs 和 workbench-hidds 目标)
b) ifdef 你的补丁,使其仅在 m68k 架构上应用(因此它将是 PIPE_ATOMIC_OS_AROS_M68K),而其他架构继续使用默认方法(GCC 指令)
你也可以尝试在真实自动配置快速 RAM 中获得 exec(在 ConfigChain() 调用之后),如果你还有太多空闲时间:) 你是在说移动“引导任务”堆栈,还是将所有 Exec 从 ROM 移动到 RAM?
如果是前者,它应该在第一个 CLI 程序的 CreateProcess() 期间自动发生。我只需要修复内存分配指针,这样 'old' Boot Task 堆栈就可以在 RemTask(NULL) 上被正确地释放
如何为模式标签列表设置正确的本机模式 ID?(hires、lace、pal、ntsc 等)。请参见 AddDisplayDriverA() 的 DDRV_MonitorID 标签。然后你可能需要对 graphics.hidd 的 ModeID 处理进行子类化,因为你会得到另一个 ModeID 结构。我建议你每个显示器模式都同步一次(我的意思是 PAL 是一个同步,NTSC 是另一个同步,多扫描是第三个同步,等等)。只会有一个像素格式,ModeID 中的其他位将是同步修饰符。
zzzz xx yy
zzzz 实际上是驱动程序编号。它们按顺序分配,从 0x0010 开始。这样,最多 0x000F 的数字将被保留。我专门为 Amiga 驱动程序这样做。
xx 和 yy 是同步编号和像素格式编号。我现在不记得哪个是哪个,但实际上并不重要。
因此 zzzz 由 graphics.library 处理,而 xx yy 由 graphics.hidd 处理。
Amiga 芯片组驱动程序需要占用保留区域(如果我记得正确的话,是 0x0000 - 0x000A)。可以使用 DDRV_MonitorID 标签显式请求驱动程序编号。现在你需要将 zzzz 转换为 zzzW,其中 W 也是特定于模式的东西。如果你查看 AddDisplayDriverA(),你会看到 AROS_MONITOR_ID_MASK 硬编码值。其中一个变体是实现 DDRV_IDMask 标签,它将允许覆盖掩码值。
好的,这已经完成了。现在让我们处理 xx 和 yy。
你可能需要在你的驱动程序中覆盖 ModeID 例程。说实话,我完全没有查看过这部分,所以我无法告诉你将此功能合并到使用附加属性的基本类中是否有效。
现在关于另一种可能的方法…
如果你检查 graphics.library 代码,你会看到一个内存驱动程序实例。目前它是“hidd.graphics.graphics”的实例,它表示存储在 RAM 中的不可显示位图。所有临时平面位图对象都由这个驱动程序拥有。
也许在这里实例化芯片组驱动程序会非常有效。由于芯片组驱动程序仍然是 graphics.hidd 的子类,它仍然支持 RAM 中的块状位图。但它将为平面位图添加缺少的功能。
这种变体的第二个要点:由于 graphics.library 知道这个特定的驱动程序,它可以以特定的方式添加它的模式,你不需要为 AddDisplayDriverA() 引入新的标签。事实上,我还没有实现这个标签,因为它很容易通过不正确使用它来破坏整个 GFX 系统,并且除了芯片组驱动程序之外,任何人都不需要它。
我相信它们各有优缺点。由你决定如何实际处理它。也许你会发明你自己的方法。无论如何,我相信你需要以某种方式扩展 GFX 子系统。我注意到 graphics 在这里和那里内部检查 aros modeid 部分是否有效(xx 和 yy 部分必须小于总同步和像素格式)这会变得很混乱…
{ aHidd_PixFmt_ColorModel , vHidd_ColorModel_Palette }, // is following maximum or do I need to have multiple pixformat/depth pairs? { aHidd_PixFmt_Depth , 4 }, What does following tags mean in planar mode? (they need to be included or pixformat gets rejected) They don't make much sense if bitmap is planar. { aHidd_PixFmt_BytesPerPixel, 1 }, { aHidd_PixFmt_BitsPerPixel , 1 }, { aHidd_PixFmt_StdPixFmt, vHidd_StdPixFmt_Native }, { aHidd_PixFmt_BitMapType, vHidd_BitMapType_Planar },
它们的意思就是它们的意思。当然,BytesPerPixel 携带的是虚拟值。实际上,StdPixFmt 将始终为 vHidd_StdPixFmt_Plane。
由于某种原因,引导菜单在 intuition.library OpenScreen() 内部的某个地方崩溃了。似乎发生在 intuition_mis.c 中的深处,DoMethodA() 调用..(jsr 到不存在的地址)
D(bug("[intuition] RenderScreenBar: ScrDecorObj @ %p, DecorUserBuffer @ %p\n", ((struct IntScreen *)(scr))->ScrDecorObj, ((struct IntScreen *)(scr))->DecorUserBuffer)); DoMethodA(((struct IntScreen *)(scr))->ScrDecorObj, (Msg)&msg); } D(bug("[intuition] RenderScreenBar: Update gadgets .. \n"));
gfx hidd 更新已提交,现在看起来好多了。
- 支持 24 位 AGA 颜色(如果检测到 AGA)
- 显示大小的硬件值不再硬编码。
- 使用隔行扫描模式(默认屏幕尺寸为 640x480+,更准确的纵横比)。
但是
- 没有 shres/hires/lores 和 lace/non-lace 的自动选择。
- 仅使用软件blitting(= 缓慢)。
基于块的驱动程序(内存中的块阴影位图,使用 chunkytoplanar 转换为 CHIPRAM 中的真实位图)会更快,除了在最慢的真实 Amiga(如 A500)上。芯片 RAM 很慢。blitting 很慢。
据我所知,一些游戏在 040 或更高版本上的 c2p 例程可以以复制速度(芯片 RAM 写入带宽)进行转换。
由于 AROS 或 graphics.library 中没有任何内容依赖于直接位图访问,因此你甚至可以拥有一个真彩色模式(驱动程序使用真正的 ARGB32 或类似的块缓冲区作为阴影位图),该模式在进行 c2p 的同时实时抖动到 256 或 16(或任何)种颜色。对于驱动程序之外的所有内容,它都是一个真正的真彩色模式。不过,使用平面定制芯片组图形作为虚拟块 C2P 帧缓冲区对我来说不够 Amiga 风格,而且在任何真实的 Amiga 上都太慢了)。
如何安装这个监视器?monitorclass.c 说你不应该碰它。我在现有的 PC hidd 中也没有找到任何有趣的东西。没有奇怪的地方。基本上 monitorclass 允许处理多显示器输入。此外,它还处理鼠标精灵,因为 graphics.library 函数并不非常适合多监视器环境。其他东西只是 MorphOS API 的重新实现(为了与某些东西兼容)。所以,如果没有 monitorclass 对象,Intuition 就不知道你的监视器(而 graphics 仍然知道),并且无法在其上处理输入。平面数增加到 5(如果为 AGA),因为如果显示器平面数少于此,则默认精灵颜色(17-19)不会更新。如何正确处理?(光标位图是否有调色板?) OpenScreen() 应该处理这个问题。没有人用 Amiga 硬件测试过它,所以检查一下。据我所知,我对鼠标精灵部分进行了很好的注释。
一些私有依赖项已被删除,并且在 intuition 中更改了 monitorclass 对象查找。由于它们知道监视器 ID 和掩码,因此可以通过 ModeID 找到描述符。
- 第一个问题:为什么它们的掩码范围如此广 (0xF00000000)?我假设芯片组驱动程序的掩码为 0xFFF00000。
- 为什么你为 UAE 驱动程序使用自定义 ID?实际上,我认为这就是原因。也许两个驱动程序碰巧具有相同的监视器 ID(ModeID 部分,掩码中有 1)。因此,Intuition 中的 FindMonitor() 函数找到了错误的监视器对象,并且 Intuition 的输入处理程序无法查找正确的屏幕。
在设计 ID 分配方案时,不同的驱动程序获得不同的 ID。自动分配测试得很好,但从未打算拥有如此广泛的掩码。这就是 RTG ID 以 0x00100000 开头的理由。在芯片组模式下,最右边的五个数字会变化,第六到第八个数字始终为 0,这就是保留基于此的原因。它从未打算拥有 0xF0000000 掩码。
我在 openscreen.c 中添加了这一点,现在 Intuition 分配了颜色 17 到 19,但 SetColors 位图方法没有获得任何 >15 的调色板条目。
#if (AROS_FLAVOUR & AROS_FLAVOUR_BINCOMPAT) spritebase = 16; #else spritebase = (ns.Depth < 5) ? (1 << ns.Depth) - 8 : 16; #endif
你说的所有事情都完成了。那是简单的一部分。(它有很好的文档记录,例如 vesa.hidd 做了与预期相同的操作) 问题是 graphics 或 intuition 内部的东西。
intuition/misc.c: this calls HIDD SetCursorPos() normally.
static void SetPointerPos(struct MonitorData *data, struct IntuitionBase *IntuitionBase) { ULONG x = data->mouseX; ULONG y = data->mouseY; DB2(bug("[monitorclass] SetPointerPos(%d, %d), pointer 0x%p\n", x, y, data->pointer)); if (data->pointer) { /* Take HotSpot into account */ x += data->pointer->xoffset; y += data->pointer->yoffset; /* Update sprite position, just for backwards compatibility */ data->pointer->sprite->es_SimpleSprite.x = x; data->pointer->sprite->es_SimpleSprite.y = y; } DB2(bug("[monitorclass] Physical coordinates: (%d, %d)\n", x, y)); HIDD_Gfx_SetCursorPos(data->handle->gfxhidd, x, y); } void MonitorClass__MM_SetPointerPos(Class *cl, Object *obj, struct msSetPointerPos *msg) { struct MonitorData *data = INST_DATA(cl, obj); data->mouseX = msg->x; data->mouseY = msg->y; SetPointerPos(data, IntuitionBase); } Above is called from intuition/misc.c: void MySetPointerPos(struct IntuitionBase *IntuitionBase) { Object *mon = GetPrivIBase(IntuitionBase)->ActiveMonitor; if (mon) DoMethod(mon, MM_SetPointerPos, IntuitionBase->MouseX, IntuitionBase->MouseY); }
IntuitionBase->ActiveMonitor 始终为 NULL。所有 SetCursorXXX() 函数也存在相同的问题,NULL ActiveMonitor -> 不调用任何鼠标例程。
如果我在此函数中添加 "bug("x=%d y=%d);"(在 if (mon) 之外),当我移动鼠标时,我将按预期获得调试消息。
好的,也许这对你有所帮助:当驱动程序调用 AddDisplayDriver 时,graphics.library 注册一个新的驱动程序,并通知 intuition.library 新驱动程序已注册。这样,intuition.library 就可以创建一个新的监视器对象。但是,为了获得此通知,intuition.library 必须首先向 graphics.library 注册。
也许你的初始化顺序如下
graphics.library amiga.hidd intuition.library
我认为在这种情况下,Intuition 可能不会收到通知,并且可能不知道已加载了驱动程序。
每个 graphics hidd 函数都在超类中以 "通用" 方式实现,使用来自具体实现的 PutPixel/GetPixel,你需要在 hidd 中实现所有绘图函数以摆脱使用 PutPixel 的 "超类"。(我建议从 "改进" CopyBox 开始,然后继续使用 PutImage 和 PutImageAlpha)。CopyBox 不在位图类中。
光标有两种工作方式
- 在 fakehidd 上进行仿真
- 原生模式
据我所知,为了使仿真正常工作,你的驱动程序需要是帧缓冲区驱动程序(aHidd_Gfx_NoFrameBuffer = FALSE),并且你需要实现 Show 方法来调用超级方法。这种仿真只是在你屏幕上为你绘制光标(恢复旧的备份的 64x64 图块,备份新的 64x64 图块,绘制光标)。
对于原生模式,你需要实现 SetCursorVisible、SetCursorPos 和 SetCursorShape,并在 SetCursorPos 中自己进行 "绘制"。你需要将你的驱动程序标记为 NoFrameBuffer = TRUE,并告诉系统你支持硬件光标 aHidd_Gfx_SupportsHWCursor = TRUE。此外,在 show 方法中,你必须返回接收到的位图,并且不要调用超级方法。永远不要触碰 gfx 驱动程序(hidd 类)以上的任何内容,以使光标正常工作。
Picasso96 支持以下高色模式
RGBFB_R5G6B5PC, /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: gggbbbbbrrrrrggg */ RGBFB_R5G5B5PC, /* HiColor15 (5 bit each), format: gggbbbbb0rrrrrgg */ RGBFB_R5G6B5, /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: rrrrrggggggbbbbb */ RGBFB_R5G5B5, /* HiColor15 (5 bit each), format: 0rrrrrgggggbbbbb */ RGBFB_B5G6R5PC, /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: gggrrrrrbbbbbggg */ RGBFB_B5G5R5PC, /* HiColor15 (5 bit each), format: gggrrrrr0bbbbbbgg */
UAE 默认值为 RGBFB_R5G6B5PC(无需转换,与正常的低端 16 位模式匹配),我认为大多数 UAE 端口甚至不支持其他高色模式。
是否可以在大端 CPU(如 68k)上定义此模式?(我不知道单个颜色分量移位和掩码如何工作。我知道这不是必需的,8 位和 32 位已经足够了,但我希望拥有完整的实现:)。
我还有另一个问题:BitMap_GetImage 和 PutImage(+LUT 变体),"pixels" 数组的格式是什么?始终与位图相同,还是始终为 32 位或 8 位?我没有找到足够好的示例或文档。这些是最后剩下的未实现的方法。传入/请求的像素缓冲区的格式在消息中可用:msg->pixFmt。
你可以获得两种伪格式:Native 和 Native32。据我了解,gfx 系统 Native 意味着 "与调用该方法的位图对象相同",而 Native32 意味着 "与调用该方法的位图对象相同,但打包在 4 字节的 "像素" 中"。
如果我们有 8 位(256 色)位图,并且请求了 Native32,如何填充像素数组?(1 字节数据 + 3 个零?3 个零 + 1 个字节?某些颜色转换?) 基类中已经存在你可以使用的方法
GetMem32Image8 ConvertPixels PutMem32Image8
检查 /workbench/hidds/hidd.nouveau/nouveau_accel.c
HiddNouveauWriteFromRAM HiddNouveauReadIntoRAM
我认为你在这些函数中看到的 switch/case 级联对于每个驱动程序的 GetImage/PutImage 都是通用的。例如,让我们以 GetImage 方法为例。它在位图对象上调用,请求将此位图对象的指定框 (msg->x, msg->y, msg->width, msg->height) 传输到内存缓冲区 (msg->pixels),该缓冲区具有给定的步长 (msg->modulo) 和给定的像素格式 (msg->pixFmt)。为此,你首先检查给定的(请求的)像素格式,看它是否是 Native、Native32 还是其他。在前两种情况下,你随后检查输入 bytesperpixel 值,并根据此值决定使用哪个现有的 CopyMemBoxXXX 或 GetMemXXXImageYYY 方法。如果请求的格式不同于 Native 或 Native32,你需要使用 ConvertPixels 方法,该方法将为你进行转换。实现你的驱动程序时,你不必担心格式在转换期间的内存组织方式,因为这已经在 CopyMemBox/GetMemImage/ConvertPixels 方法中实现了。
请注意,ConvertPixels 中使用的通用转换方法有点慢。还有更具体的、更快的 method。你可以通过运行 tests/patchrgbconv 来切换到这些 method。你也可以像我在 nouveau 中做的那样,在驱动程序本身中修补这些方法,这样用户就不必担心这个问题。
既然我们正在谈论补丁,我知道你不想为第三方 Amiga 硬件编写驱动程序,但你是否认为在 AROS m68k 上使用 Picasso96 驱动程序有解决方案?我不是要你做,只是想知道是否可以在上面安装 Picasso96,或者你编写的代码是否允许使用 .chip/.card 文件,以便 RTG 可以用在真实的 Amiga 上。我知道 Deneb、scsi 等的原始驱动程序应该在 AROS m68k 中开箱即用。Uaegfx hidd 在内部使用 .card API 与 UAE 端通信。修改它以使用 "真实的" Picasso96 驱动程序和卡应该相当容易。(我可以做到这一点,我有一台 A3000,但没有扩展卡。从未真正关心显示卡..) 大多数驱动程序应该可以正常工作。
屏幕位图在可见时被锁定 (bm->locked 变量)(以防止它们被交换),但后来即使某些其他屏幕位图已变为可见位图,也从未被解锁。因此,所有屏幕位图永远保留在 VRAM 中。据我所知。
速度
如果有一些 gfx 函数,驱动程序本身没有处理,那么回退函数通常会很慢或非常慢。对于 RAM/VRAM 可交换位图来说更是如此,因为需要位图锁定。回退没有优化,而且它们永远不可能超级快,因为 AROS gfx 系统的设计方式是不依赖于直接访问 gfx 驱动程序位图(或其他位图)的像素数据。它可以尝试在回退函数中获取直接访问权限,但目前它主要不这样做,因此仅使用间接访问像素数据,例如通过 putpixel/getpixel 或 putimage/getimage。
目前 uaegfx 驱动程序本身没有处理的一件事是,源位图 pixfmt 与目标 pixfmt 不同,并且至少一个位图位于 RAM 而不是 VRAM 中的 blit。对于 COPY drawmode/minterm,至少应该可以使用 HIDD_BM_ConvertPixels(如果两个位图都是 uaegfx 位图)或 HIDD_BM_PutImage/GetImage(如果其中一个位图是外部位图)来处理/实现它。说到 drawmode,至少应该处理 INVERT 和 CLEAR(使用 BMF_CLEAR 分配的位图可能会触发此操作)。
像素 fmt 转换例程:据我所知,AROS 68k 只内置了一些改进的例程(以前在 SYS:tests/patchrgbconv 中的内容)(ROM 中的空间限制)。
graphics.library/Text(): 将单个字体字符放入临时位平面中的代码非常没有优化。这个模板位平面然后使用 BltTemplate() 渲染到屏幕上。如果有人想改进这个,他可以尝试在 AmigaOS(也许甚至 AOS4 或 MorphOS)上使用一个小程序编译/优化这个(rom/graphics/text.c),该程序使用 SetFunction() 将它修补到系统中。不依赖于 AROS 内部,所以没有问题(在 AOS3 上禁用抗锯齿相关的功能)。然后比较这比原始 AOS 函数慢多少。然后优化,直到它不再糟糕... 然后贡献回 AROS。
平面位图:在内部,大多数 AROS 位图是位图对象(像 boopsi 一样),但并非所有都是。手工制作的(比如使用 InitBitMap() 的)不是,据我所知,即使使用 AllocBitMap() 分配的平面位图也不是位图对象。因此,在图形函数期间,这些会在运行时被包装成位图对象,因为图形系统只使用这些位图对象,而不是使用 graphics.library 中已知的“struct BitMap *”。我注意到的一件在包装中很愚蠢/很慢的事情是,planarbm 类在 SetbitMap() 方法中总是调用 RegisterPixFmt 来注册包装的平面位图的 pixfmt。因此,在每个涉及平面位图的图形函数中,都会重新注册一个 pixfmt。应该更改为仅在先前尚未注册匹配的 pixfmt 时才这样做。
图标:在 AROS 中,加载像这样的东西(以及字体)很慢,因为 AROS 可以是 32 位、64 位、大端序、小端序,并且所有可能的变体都使用相同的代码。在 AOS(或 AOS4 或 MOS)中,他们的字节序固定为“大端序”,系统固定为 32 位。因此,他们基本上可以像内存中一个结构一样,以一个块的形式读取这些内容。AROS m68k-amiga 也可能已经优化了加载(#if AROS_BIG_ENDIAN 等像他们在 AOS68k 环境中那样做),但目前没有。
也许我错过了一些重要的东西,但似乎 gfx hidds 需要指定每个支持的深度值。例如,如果你想完全支持 AGA,hidd 应该有 8 种不同的像素格式(而 OCS/ECS 则有 4 或 5 种,具体取决于水平分辨率)。它不应该自动生成所有较低深度的像素格式吗?
这真的会减慢真实 Amiga 上的图形速度,特别是在非 AGA 机器上,因为它现在总是强制使用 4 平面高分辨率,这会消耗所有芯片 RAM 带宽并占用太多内存。
另一个很大的兼容性问题是错误的模式 ID。这需要一个有效的解决方案。我也希望有一个针对模式 ID 问题的解决方案,我真的不明白由某个外部实体动态生成模式 ID 的意义。关键在于:同一个驱动程序可以被实例化多次。例如,你可以有两张类似的显卡,每张显卡都可以有多个输出。这样,对于两张 Radeon 显卡,你将有四个相同驱动程序的实例。你会分配什么模式 ID?以及如何分配?在 CyberGraphX 中,你使用首选项程序手动创建模式 ID。我决定这不是很方便,并实现了对监视器 ID(模式 ID 的最高位字)的动态生成。其余的(像素格式和同步数字)实际上来自旧实现。我在这里没有发明任何新东西。也许它仍然有一些缺点,但我认为它是可以接受的。无论如何,程序员不必手动分配 ID。
在 RTG 驱动程序中添加了更多模式,突然所有其他模式都获得了新的 ID... 显然,至少一些 m68k RTG 程序认为“太小”的模式 ID 数字 = 本地平面模式。什么是“太小”?
现在关于你想要知道的事情... 当我实现新的 ID 方案时,我实际上留出了空间用于 Amiga ID(即,用于你)。为了说明:显示模式 ID 分为两半:最高位一半是“监视器 ID”,最低位一半是原始模式 ID 本身(同步 + 像素格式)。HIDD 只知道后一半,监视器 ID 由 graphics.library 维持。
如果你仔细查看代码,你会发现 ID 编号从 0x0010 开始。没有 RTG 驱动程序以小于此 ID 的 ID 添加。你的驱动程序需要占用这个保留的空间。此外,它需要为其模式指定 0xFFF00000 掩码,因为 Amiga 模式 ID 可以表示为 0x000X XXXX。
目前 AddDisplayDriverA() 缺少指定掩码的可能性。但是,你可以指定起始 ID(使用 DDRV_MonitorID 标签)。有以下可能的解决方案
- a 实现 DDRV_IDMask 标签。
- b 实现一个类似 DDRV_AmigaModes 的单个布尔标签,它会自动将 Amiga 模式分配给驱动程序。
- c 使 m68k 上的 graphics.library 明确实例化芯片组驱动程序,而不是像其默认驱动程序一样使用虚拟内存驱动程序。
我不喜欢 (a),因为不恰当地使用这个标签很容易破坏 graphics.library。我只会考虑 (b) 或 (c) 选项。也许 (c) 甚至更好,因为它会自动使所有属于芯片组驱动程序的平面位图成为平面位图。实际上,由你决定该怎么做以及如何实现它。但请不要破坏整个 ID 方案。我对此思考了很多。我在实现它之前询问了其他人,但没有人提出任何替代方案。
模式 ID 由“其他人”生成,对支持模式的任何修改都会重新编号模式 ID。(这在仿真中尤其是一个问题,因为用户可以选择启用哪些位深度,或者是否想要 BGR 或 RGB 等。)
关于 rtg 和非 rtg 模式(我认为他指的是模式 ID)
everything below monitor-id $00100000 is an amigamode all other ids are standing for rtg if you found anything over $00100000 use the cgfx-functions to identify the gfxcard p96 supports the functions of cgfx
我自己,我以为 cgx 提供静态模式 ID,但在 p96 上定义分辨率的前四位数字取决于模式声明的顺序,因此它们是半随机的,最后描述深度/位顺序的四位数字是硬编码到它们代表的模式的。以下是我在我 voodoo3 系统上找到的代表特定位顺序的 p96 模式 ID 最后四位数字的值。
xxxx1000 = 8bit xxxx1100 = 16bit pc xxxx1102 = 16 bit xxxx1201 = 24bit xxxx1300 = 32bit argb xxxx1303 = 32bit bgra
0x8000100e,即 DIPF_IS_HAM | DIPF_IS_PF2PRI | DIPF_IS_DUALPF | DIPF_IS_EXTRAHALFBRITE(+ 位 31 设置,这显然是一个游戏错误。)
不幸的是,这意味着即使使用 RTG 显示,也需要以某种方式仿真 AOS 原始模式 ID(在这种情况下,所有本机芯片组特殊位都需要归零)。
如何添加 AROS 图形系统可以提升为标准 hidd 模式的“标准”监视器模式 ID?(就像真实 m68k-amiga RTG 硬件在启用模式提升时所做的那样)。请参阅更新后的 AddDisplayDriverA() 文档。我为此添加了 DDRV_ID_Mask 标签。“请注意,要使此功能正常工作,你还需要覆盖驱动程序类中的模式 ID 处理。hidd.graphics.graphics 基本类提供的默认方法假定模式 ID 的整个低位字指定了显示模式。”
覆盖模式 ID 处理究竟意味着什么?重载 GetMode、GetSync、NextMode 等方法。
例如,PowerPacker 这样做
- 调用 QueryOverscan(0x29000, &rect, OSCAN_TEXT);,这会导致失败。
- PP 忽略返回值,rect 包含随机内存内容。
- 将垃圾 rect 内容复制到 NewScreen 结构的屏幕位置和大小。
- 添加一些 OpenScreenTags() 标签,包括模式 ID 标签 = 0x29000
- 当然,屏幕无法打开(不存在的模式 ID,完全错误的屏幕宽度和高度)。
0x29000 = PAL_MONITOR_ID | HIRES_KEY.
至少 PAL_MONITOR_ID、NTSC_MONITOR_ID、HIRES_KEY 和 LORES_KEY 组合应始终受支持并返回匹配的分辨率。OpenScreen() 中有一些提升代码(从 MorphOS 遗留下来的),检查它并在需要时修复(参见 openscreen.c,第 597 行)。我猜这很容易,将一个驱动程序标记为“首选”(驱动程序可以有优先级吗?)。它们可以。但是,目前它们没有。
如果询问“其他”驱动程序的模式 ID,只需从首选驱动程序模式列表中找到足够相似的模式?目前,BestModeIDA() 会遍历所有驱动程序,也许我们应该真的拥有一个“默认”驱动程序,由用户指定。然后,我们应该为用户关于监视器的首选项开发一些概念。这可以包括指定首选监视器、高级模式提升、描述监视器放置等。
显然,你需要为所有平面数量定义像素格式,而不仅仅是描述最大支持平面数量的像素格式。这意味着例如,需要为单个 AGA 分辨率提供 8 个不同的模式 ID。(320x256x1、320x256x2... 320x256x8 以及所有其他分辨率的相同模式 ID)
将 8 个模式 ID(或 OCS/ECS 上的 4/5 个模式 ID)放入单个官方文档模式 ID 位中是相当困难的。也许可以添加到 AROS 代码中,使自动 ID 生成仅创建高于 0x10000000 的 ID?所有低于此 ID 的 ID 可以通过手动 ID 创建。如果仅定义了 320x256x8,则所有较低平面模式请求始终“提升”为 8 平面。
另一个需要在本地模式能够工作之前修复的问题。需要 aoHidd_BitMap_Depth(出于某种原因,它被注释掉了,并且没有在所有地方处理,比如在 AllocBitmap() 中)。AllocBitMap() 将宽度、高度、像素格式发送到 HIDD,但没有发送深度。这对支持 m68k-amiga 芯片组模式来说非常必要。它需要每个分辨率一个像素格式/模式 ID,而不是每个(分辨率 * 可用深度)一个像素格式。如果你查看 allocbitmap.c 中的第 392 行,你会看到深度实际上是从像素格式(* 或从位图对象 - 我不理解这一部分)复制的。根据我的理解,驱动程序的作用是正确地处理这种情况。
AllocBitmap(depth=1 bit, friend bitmap depth=2)
它应该分配一个深度为 2 的位图,完全忽略传递的深度。这段代码位于根 GraphicsClass(第 1177 行)。我将其放在 allocbitmap 中,因为模式 ID 也从那里(而不是在驱动程序中)的 friend 位图复制,因为从技术上讲,块状模式 ID 也包含深度。我还比较了你和 nouveau 的 bitmap New 方法,我注意到你使用了
OOP_GetAttr(o, aHidd_BitMap_Depth, &depth);
而我使用了
OOP_GetAttr(o, aHidd_BitMap_PixFmt, (APTR)&pf); OOP_GetAttr(pf, aHidd_PixFmt_Depth, &depth);
这意味着你正在使用传递的深度(参见根 BitMap 类 New 方法),而我正在使用从 friend 位图的像素格式中获取的深度。这是因为处理平面模式和块状模式的方式不同吗?是的。平面模式的深度与像素格式(模式 ID)分开。平面模式的 pixfmt_depth = 像素格式的最大支持深度(在 OCS/ECS 和 AGA 上有所不同)。
任何假定 pixfmt_depth = 位图的当前深度的非驱动程序代码都不能与平面模式一起正常工作。我在这个 ML 中多次抱怨过这个与 AOS 不兼容的设计问题,直到我重新添加了注释掉的 aHidd_BitMap_Depth 等等,你错过了吗?:)
我做错什么了吗,还是这个 gfx hidd 功能缺失?顺便说一句,据我所知,至少 rastport 中的位平面掩码字段应该被传递给 hidd rectfill() 及其朋友,如果我们要处理所有低位平面技巧,在最坏的情况下,需要最小项数组(它将在复杂情况下取代 drawmode 和 mask),如果 dpaint 屏幕模式请求器要正常工作。
HIDD_BM_ConvertPixels() - 它似乎没有完全从块状转换为平面。即 vHidd_StdPixFmt_ARGB32 -> vHidd_StdPixFmt_Plane 执行 LUT 变换,但没有将像素重新打包到平面模式中。这是 HIDD_BM_ConvertPixels() 的工作吗?如果是,在 AROS 中是否有任何我可以重复使用的“众所周知的”块状 -> 平面例程?
aHidd_PixFmt_BitsPerPixel:显然应该为每个像素的位数,但似乎只被设置,从未使用。aHidd_PixFmt_BytesPerPixel:对于平面格式,应该将其设置为多少?1?0?(- 深度)?aHidd_PixFmt_Depth:这应该是平面的平面数。对于块状模式,这应该为 0 吗?
事实上,这可能是一个不完整的实现。历史上,vHidd_StdPixFmt_Plane 仅指单平面单色位图,它用于渲染字体。后来它被扩展,大约一年前,我删除了原始的字体绘制例程。
建议...
块状格式
aHidd_PixFmt_Depth == 1 aHidd_PixFmt_BytesPerPixel == Number of bytes to store a pixel, if
像素是字节对齐的。0 表示“打包像素”(即非平面的 2 色位图)。
aHidd_PixFmt_BitsPerPixel == Number of valid bits per pixel chunk.
如果 BytesPerPixel == 0,则表示打包像素的打包。
示例
- Hercules 单色:Depth = 1, BytesPerPixel = 0, BitsPerPixel = 1
- CGA 4 色模式:深度 = 1,每像素字节数 = 0,每像素位数 = 2
- VGA 256 色模式:深度 = 1,每像素字节数 = 1,每像素位数 = 8
- RGB 15 位模式:深度 = 1,每像素字节数 = 2,每像素位数 = 15
平面格式遵循相同的规则,但请注意,每个平面每个像素可能有多个位。
aHidd_PixFmt_Depth = 1..8 (Number of planes) aHidd_PixFmt_BytesPerPixel == Number of bytes to store a pixel, if
像素按字节对齐,0 表示“打包像素”(例如 2 色位图非平面)
aHidd_PixFmt_BitsPerPixel == Number of valid bits per pixel chunk.
如果 BytesPerPixel == 0,则表示打包像素的打包。
示例
- Amiga 4 色模式:深度 = 4,每像素字节数 = 1,每像素位数 = 1
- Amiga 256 色模式:深度 = 8,每像素字节数 = 1,每像素位数 = 1
- 有些人将 24+8 位 RGBA 组成,每个平面有 8 位单色或 alpha:深度 = 4,每像素字节数 = 1,每像素位数 = 8
ConvertPixels 用于平面格式,我对某些字段的含义有点困惑。也许列表不完整,但是有没有像“每行字节数”或“包含填充的宽度”这样的东西?有可获取的 aHidd_BitMap_BytesPerRow。但是,不支持填充。我以前在平面位图中需要这个,我引入了 aHidd_BitMap_Align。对齐不影响 BytesPerRow 值,该值始终返回为 Width * BytesPerPixel(取自位图的(pixelformat))。这可能是错误的,应该考虑对齐。此外,BytesPerRow 将为平面位图计算错误,该属性需要在 planarbm 类中重载。我看来,ConvertPixels 从来不适合平面到块状的转换。但只适用于 LUT 到 LUT。或者 LUT 到 TRUECOLOR。或者 TRUECOLOR 到 TRUECOLOR。其中 LUT 基本上意味着块状像素布局。ConvertPixels 存在是为了支持像 WritePixelArray()、WriteLUTPixelArray()、ReadPixelArray()、WriteChunkyPixels() 这样的函数。
所以,如果我理解正确,GetImage/PutImage 用于平面应该处理块状/平面转换,并将当前 ConvertPixels 作为助手,而不是调用根类的 GetImage/PutImage 及其对 ConvertPixels 的使用。目前,PlanarBM 正在为 PutImage 上的非本机 PixFmt 类型调用根类。你暗示 PlanarBM 应该自己处理所有传入类型的转换,对吗?
所有代码都可以保持原样,内部位图的外观不应该有任何影响(或者有什么不起作用?),因为图形库和 hidd 东西不依赖于它的外观。当代码需要查看位图像素时,所有操作都使用像素缓冲区 == 像素数组 == 块状数组以及像 PutImage/GetImage 这样的函数,即使对于平面位图和 pixfmt == Native 或 Native32 也会写入/读取块状像素数组/缓冲区。(参见 rom/hidds/graphics/planarbm.c)
所以,如果有人使用平面位图类编写图形驱动程序,那么 PutImage/GetImage 和 pixfmt==Native|Native32 不应该使用/返回平面数据,而是块状数据。
理论上也不存在单一的平面格式。例如交错与否。MSBFirst/LSBFirst(参见 X11)。类似 Atari 的平面格式。隐式对齐是一种选择,但如果 API 是无遗留的,确实更方便将 BytesPerRow 和 Pad 分开。从位图复制到位图时,填充通常只是浪费的空间。此外,单独声明它可以避免计算错误。
这也有助于区分平面与块状/真彩色格式。aHidd_PixFmt_BitsPerPixel:应该是每个像素的位数,显然,但似乎只设置,从未使用。真的吗?它至少可以在注册新的像素格式时用于比较。除非你确信自己研究了所有代码,否则不要删除任何东西。我记得我在那里更改过代码后遇到了问题,花了很长时间才解决。
aHidd_PixFmt_BytesPerPixel:对于平面格式,这应该设置为多少?1?0?(- 深度)?我认为这对平面位图来说是未定义的。让我们将其设置为 0。我们只需要确保它不会破坏任何东西。
aHidd_PixFmt_Depth:这应该是平面的平面数。对于块状,这应该是 0 吗?不,它在很多地方被用来确定颜色数量。我以前看到过另一种方式 - 结构体 BitMap 中的 Depth 是有效的 Plane[] 数组元素的数量。在块状中,只有第一个是有效的,因此 Depth = 1。
当我调用 RTG(在本例中为任何非自定义芯片组驱动程序)Hidd_Gfx__Show(FALSE) 时,如何调用自定义芯片组驱动程序 Hidd_Gfx__Show(TRUE)?(反之亦然)。没有这种关系。驱动程序彼此完全独立。你可以同时使用两个显示器,一个在芯片组上,另一个在 GFX 板上。问题是,当选择自定义芯片组模式时,必须有东西告诉 RTG 驱动程序变为闲置并启用芯片组模式直通。这不是模拟特有的。
这需要在模拟中(以及无需在真正的 Amiga 上切换电缆)切换自定义/RTG 模式。好吧,你可以在加载任何其他驱动程序时让 AROS 卸载芯片组驱动程序。在添加它时将 DDRV_BootMode 设置为 TRUE,你就完成了。芯片组驱动程序绝不能卸载,如果用户运行专门需要芯片组模式的程序(例如旧游戏或 whdload 或其他任何程序),它必须始终可用。
或者也许我们需要比 Show() 更强大的东西,这样可能非显示 RAM 位图也会被释放以降低内存使用量?Show() 仅显示一个位图。其他位图会移出屏幕。有 ShowViewPorts(),它接受一个位图列表。跟踪其状态取决于驱动程序。但是,你不能释放任何位图,AROS 可能会使用它们。只有创建者可以释放位图。芯片组显示隐藏在“RTG 后面”(不可见),因为硬件(模拟或不模拟)认为 RTG 是当前活动的模式。
目前,任何尝试打开自定义芯片组模式都会在“RTG 模式”后面打开它。你的意思是模拟问题吗?模拟器是否尝试在同一个窗口中显示两种模式?好吧,模拟很糟糕。为了克服这一点,你可以教驱动程序在没有显示任何内容时关闭模拟硬件(调用 Show(NULL))。这将告诉 UAE 关闭模拟的 RTG 显示器。Windows 托管驱动程序在为了避免空窗口时也会做同样的事情 - 它只是在窗口中没有显示任何内容时关闭显示窗口。在真正的硬件上,这不是问题,反而是一个优势。你可以使用两种显示器,并在它们上显示不同的屏幕(由于不同的模式 ID)。问题是缺少 Show(NULL)。如果你的真实物理显示器在你调用 Show(NULL) 时消失了,我会在 WinUAE 中实现它。事实上,在 LoadView() 期间,如果发生变化,每个驱动程序都将获得 Show()。如果以前有内容在显示,而现在消失了,驱动程序将获得 Show(NULL)。它仍然与我的问题无关。RTG 和本机被视为不同的物理显示器。(至少我们对此达成一致!)= 当本机屏幕上打开某些内容(Native.Show(BitMap))时,没有人会调用 RTG.Show(NULL)。我只想知道如何从另一个驱动程序的 Show() 方法(间接或直接)调用另一个驱动程序的(至少知道名称)Show() 方法,以便两者永远不会同时处于活动状态。干净地。如果我们想要某种愚蠢的类比,让我们称之为空白显示而不是禁用它或关闭它:)
顺便说一下,自定义芯片组驱动程序的 ModeID 现在是正确的(不再生成假 ID)。那些具有自定义芯片组直通线缆和中继或电子开关的真实物理 RTG 卡怎么样?这是 UAE 模拟的内容。不是两个物理显示器。换句话说:我们有一个共享两个显示器的单一显示器,如果最上面的屏幕 = RTG 屏幕 -> RTG 启用,如果最上面的屏幕 = 芯片组屏幕 -> RTG 禁用,芯片组屏幕直通被启用。这(完全)不支持。这是一个 hack,但这应该是这种情况下工作方式。我不在乎今天的设计方式是否奇怪或愚蠢,但 Picasso96 被设计为通过软件自动支持直通,而某些卡(以及 UAE)支持并期望它。
可能存在“干净地”的问题。我能想到的 hack 是
a) 将两个驱动程序代码放入一个 hidd 中,并执行大量的“if (native) else”
b) 添加一些两个驱动程序都知道的虚拟模块,该模块将进行仲裁
graphics -> native.hidd (Show) -> module
模块检查 rgt.hidd 是否之前已注册
如果是
module-> rgt.hidd(Show(NULL))
然后
native.hidd-> module (注册为已显示)
native.hidd -> 继续使用 Show
但是,我不确定从这个模块调用 Show(NULL) 是否安全
PS。对于屏幕拖动,你必须无论如何实现 ShowViewPorts
太难看了:)
你不能简单地枚举所有显示器并向除与当前 modeid 匹配的显示器以外的所有显示器发送某种“节能”/“空白”信号吗?(然后在内部转换为 Show(NULL)?)还是有某种 LoadView(MonitorID, NULL) 调用?我所知没有 - 你的用例与系统设计有点冲突。到目前为止,假设是每个驱动程序实例将其“信号”输出到单独的物理显示设备,并且驱动程序不知道彼此的存在,而在你的情况下,两个独立的驱动程序需要输出到一个物理显示设备,但永远不会同时输出。除非你想要重新设计图形驱动程序系统的运行方式,否则你必须使用类似 b) 的“方法”。
难道不能在 intuition.library/graphics.library 中实现,让它们跟踪同一个显示器和不同显示器上的显示器,并在同一个显示器上的一个驱动程序优先于另一个驱动程序时发送 Show(NULL) 吗?这可能是“正确”的解决方案,但我不会请求(可能是复杂的)新核心功能,该功能只有 (?) m68k-amiga(使用 RTG)需要。
Amiga 硬件上的自动显示器切换是一个正常功能,应该由 AROS 正确支持;而不是 hack。
我们有两类显示设备:驱动程序和显示器。显示器描述允许的显示模式时序(但不包括颜色深度)。驱动程序连接到显示器,并使用显示器的时序列表来确定其所有可能模式中的哪些模式有效。多个驱动程序可以连接到单个显示器实例,以表示直通系统。
让我们想象一台 A4000,它配备了一张 Picasso96 风格的卡,以及一张独立的(ATI Mach64)卡,位于 PCI 总线板上,还有两个显示器,一个 1084 和一个标准 VGA
Driver 1 (P96) \ ---> Monitor 1 (Commodore 1084) Driver 2 (AGA) / Driver 3 (ATI) ----> Monitor 2 (VGA)
在这种情况下,我们需要Toni提到的P96和AGA的“blanking”行为。现在,假设有人(比如我)为Voodoo 1 3D卡编写了一个驱动程序,该卡具有VGA直通功能,并将它放入A4000中。
Driver 1 (P96) \ ---> Monitor 1 (Commodore 1084) Driver 2 (AGA) / Driver 3 (ATI) \ ---> Monitor 2 (VGA) Driver 4 (Voodoo) /
在这种情况下,我们也需要blanking行为。顺便说一下,Voodoo的情况也适用于i386。
当某个程序在本地屏幕上打开时(Native.Show(BitMap)),没有人会调用RTG.Show(NULL)。
这是错误的。所有驱动程序在LoadView()期间都会得到一些东西。当驱动程序拥有一个屏幕,并且这个屏幕关闭时,驱动程序会得到Show(NULL)。至少应该如此。如果这种情况没有发生,那就是一个bug。参见driver_LoadView()例程。
或者你指的是你拥有两个屏幕,一个在主板上,另一个在芯片组上,然后试图对它们进行深度排列的情况?嗯……系统并不真正支持这种情况。看起来驱动程序需要以某种方式知道它的屏幕在芯片组的屏幕后面。没错。(或者反过来,选择具有当前最上面屏幕的“显示器”很重要)。
可以在不进行hack的情况下实现它。但是,要做到这一点,必须满足两个条件
1. 驱动程序需要知道正在显示的ViewPort。
2. 芯片组驱动程序需要为其ViewPort填充铜列表指针。
我想,(2) 可以通过向图形HIDD添加MakeVPort方法来完成。(1)... 还不确定。也许ShowViewPort()不好。如果满足这两个条件,RTG驱动程序可以检查GfxBase->View,并检查其ViewPort是否在芯片组ViewPort的后面或前面。只有芯片组ViewPort的铜列表指针非零。
r38178 "如果回调返回错误,立即中断" 测试会导致使用UAEGFX时,m68k-amiga上的空白屏幕,因为芯片组mdd先运行,fn()返回零,然后导致后续驱动程序(UAEGFX)始终被跳过。移除测试可以让UAEGFX再次工作。(错误测试?成功 == 0,而不是错误,至少driver_LoadViewPorts()在成功时返回零)。当然,0 代表没有错误,这是一个bug。移除感叹号。
当RTG可用时,我希望为引导菜单和初始WB屏幕选择一个漂亮的640x480x8或类似的模式(而不是无聊的640x256x2,OCS/ECS上的hires和4平面非常慢)。
可能过于丑陋的方法是屏蔽模式ID中的显示器ID部分,并检查它是否非零。不幸的是,DPIF_IS标志似乎没有用。
你可以看看cgx中IsCyberModeId()是如何实现的。OOP_Object *pf = (OOP_Object *)info.reserved[1]; 是的,我认为这也不是正确的方法。但是,我认为这并不是一个合适的方法。这并不能阻止BestModeID()选择芯片组模式。需要发明一些东西。“其他”类似Amiga的操作系统是否有某种DPIF_CHUNKY或类似的标志?令人讨厌的是,有DPIF_AA和DPIF_ECS,但没有DPIF_OCS或类似的标志。我希望在ROM代码中有一种快速简洁的方式来检测模式ID类型。(用于选择“最佳”引导菜单和初始外壳模式,早期预警?在屏幕打开之前)。
/* * Set the propertyflags, * Note that we enforce some flags because we emulate these features by software * DIPF_IS_FOREIGN is actually set only by Picasso96 and only for modes that are * not graphics.library compatible. Many m68k RTG games rely on this flag not being * set. */ di->PropertyFlags = DIPF_IS_WB | DIPF_IS_SPRITES | DIPF_IS_DBUFFER | HIDDProps.DisplayInfoFlags;
我认为这应该移到HIDD_Gfx_ModeProperties()中,这样就可以被自定义芯片组驱动程序覆盖。这些标志是故意强制用于由graphics.library模拟的功能的。SPRITES被设置,因为graphics.library可以模拟鼠标精灵。WB被设置... 为什么不呢?DBUFFER被设置,因为我模拟了它。我知道,模拟很糟糕,实际上应该在驱动程序中处理它。
不应该在特殊的自定义芯片组模式(HAM等)中设置DIPF_IS_WB。(HAM,等等)。另外,似乎在Amiga RTG本机模式中,DIPF_IS_DBUFFER没有被设置。我还没有 100% 确认,但是如果这是真的,那么一些(愚蠢的)软件肯定会假设 DIPF_IS_DBUFFER 设置 = 始终是芯片组模式。
- 移除DBUFFER强制。
- 向ModeProperties添加一个字段,例如ResetFlags。它将包含在默认标志集中需要重置的位。如果在那里设置了DIPF_IS_WB,它将在结果标志集中被取消设置。这将提供与已完成工作的良好的向后兼容性。
你怎么看,如果我们不按ID号排序驱动程序,而是按优先级排序?如果我们为芯片组驱动程序分配-128,为其他驱动程序分配0,那么在两个参数相同的模式中,BestModeID()将选择优先级更高的那个。但是,如果我们请求320x256,它不会被提升到RTG,即使RTG驱动程序只提供320x200和640x480。PAL 320x256 仍然是最匹配的。Amiga本机模式提升非常简单,BestModeID()只返回RTG模式。它永远不会返回芯片组模式(至少在不使用一些配置程序的情况下)。这样,不带模式ID的OpenScreen()始终获得RTG模式,唯一获得所需模式(包括芯片组模式)的方法是指定所需的ModeID。320x256将返回一个更大的东西(在最坏的情况下可能是320x400)。这仍然是预期的结果。
因此,简单的优先级无法完全解决这个问题。一种可能的选项是向AddDisplayDriverA()添加一个“不要自动选择我”标志。另一个选项是允许用户在首选项中选择一个首选显示器,BestModeIDA()应该首先尝试这个显示器,并且只有在没有找到任何东西的情况下才尝试其他显示器。
BestModeID()选项可能是最好的,至少对于共享显示器的情况来说是最好的。
模式提升无论如何都需要可配置,因此首选显示器可能是最符合Amiga兼容性的方式。我不确定它是否非常适合AROS设计。m68k-amiga 目前已经覆盖了 BestModeID()(直到有更好的解决方案),它简单地首先查找 RTG 模式,并且只有在 RTG 模式扫描没有返回任何结果的情况下才会检查芯片组模式。似乎工作正常。
我认为我们有略微不同的用例,应该由驱动程序代码处理
- 单个显示器,单个驱动程序。始终按预期工作。
- 单个显示器,多个驱动程序。这里应该将一个配置为“主驱动程序”,BestModeID()只返回它为主驱动程序模式的模式。
- 多个显示器,每个显示器一个驱动程序。在这种情况下需要优先级吗?BestModeID()应该从任何显示器返回模式,还是只从某种“首选显示器”返回模式?
- 多个显示器,每个显示器一个或多个驱动程序。(这是存在的吗?也许是m68k-amiga和两张RTG卡,只有一张有直通功能?)不确定在这里该怎么做,或者这是否值得麻烦。
但这需要将图形驱动程序和显示器分开。也许这变得太复杂了。
对RTG驱动程序进行快速hack,允许RTG/本机切换,可能过于丑陋,但至少似乎有效,并且允许更容易测试。我注意到在RTG/芯片组屏幕之间切换时,存在奇怪的副作用。仅对块状驱动程序强制执行上述标志。对于平面驱动程序,它们需要由驱动程序提供。背后的理念:任何RTG屏幕都与WB兼容。但并非每个平面屏幕都兼容。
启动到Wanderer(RTG模式),运行任何专门需要PAL或NTSC自定义芯片组屏幕的程序。模式按预期切换(RTG芯片组直通激活),但芯片组屏幕的菜单栏和鼠标光标不见了,输入(鼠标和键盘)仍然发送到Wanderer的窗口。缺少自动屏幕激活。当屏幕上的某个窗口被激活时,输入将被切换。ActiveScreen 在 ActivateWindow() 中,但为什么这个问题只发生在“显示器”之间切换时?如果只使用RTG或只使用芯片组屏幕,屏幕切换工作正常。活动窗口不会改变。它只会在你点击最前面屏幕上的另一个窗口时才会改变。鼠标精灵只在活动显示器上可见。活动显示器是显示活动屏幕的显示器。活动显示器只有在屏幕设置为最上面时才会被设置(快捷键和深度小部件只将屏幕设置为底部),而 OpenScreen() 只有在没有设置显示器时才会设置活动显示器。Intuition 跟踪当前活动显示器。当屏幕被发送到底部时,新的活动屏幕不是列表的首部。它是第一个与当前显示器匹配的屏幕。活动显示器在以下情况下会改变
1. Some screen is explicitly set frontmost by some software. 2. There was no active monitor at all (all screens blank). 3. Hosted driver calls a special activation callback (see monitorclass source). 4. Mouse pointer crosses screen borders and spatial linkage for the current monitor is set up in monitorclass.
(4) 是一个TODO,还没有实现,但应该实现。
我是否只需在构建m68k版本时添加临时#ifdef来始终设置活动显示器?(缺少ActiveMonitor()调用使得开发和测试非常烦人,因此任何形式的临时hack都比没有好)。如果你想,你可以玩激活回调。它们在原生驱动程序上可以完美运行。RTG驱动程序需要在关闭直通时调用它。唯一的瓶颈 - 芯片组驱动程序需要在RTG驱动程序释放直通时调用它。它们需要以某种方式进行通信。另一种方法:向monitorclass属性添加描述共享相同显示器的驱动程序的属性(类似于当前空间链接,类似于当前空间链接)。让Intuition跟踪它。
如果我通过按下Amiga+N/M或点击Wanderer的屏幕深度小部件来切换屏幕,也会发生相同的事情。
整个getdisplayinfodata.c应该扩展以支持自定义芯片组的特殊功能(最重要的功能是过扫描和精灵分辨率与显示分辨率不同)。还有很多东西缺失。这就是我们在ModeProperties结构中添加size的原因。它可以扩展。
在任何图形操作(文本输出、滚动、对话框)等期间,都会有大量FindName("hidd.graphics.gc")调用。这是由于OOP存根的工作方式造成的。在非ROMmable库中(AROS_CREATE_ROM未定义),它们将该查找的结果缓存在.bss中。在ROMmable库中,没有.bss。确实需要找到一种方法,让它在ROMmable库中工作,而不会出现所有这些开销。
实现了一个MakeVPort()和MrgCop()的API。
- MrgCop()在构建ViewPortData链后调用PrepareViewPorts。该方法还会获取View指针。你可以在那里进行任何准备工作。
- ShowViewPort的工作只是提交计算出的更改。
由于你获得了View,你可以检测你的ViewPortData在它中的位置。你也可以在这两个方法中管理AmigaOS铜列表指针。fakegfxhidd(软件鼠标光标)是否也可以支持ShowViewPorts()?不需要合成/多个ViewPort,只需要获取View信息。
因为fakegfxhidd只支持Show(),所以没有办法(至少在不进行非常丑陋的hack的情况下)处理RTG/芯片组直通,而且大多数UAE版本没有Picasso96(UAEGFX)硬件鼠标光标模拟。(据我所知,它没有从WinUAE移植,而WinUAE只在Direct3D模式下支持它,而Direct3D模式并不意味着与太旧的PC兼容)。
也许我可以向uaegfx驱动程序添加软件光标模拟,但我不知道是否值得麻烦。(或者这是正确的做法?)
今天,我让planarbm更快更好了。现在它只在内部包含struct BitMap。不再有平面数组等复制,你可以随时获取指向它的指针,以便进行直接修改,现在我正在研究软件合成层。想要将其泛化。它将是一个独立的模块,位于DEVS:Monitors中。它将热插拔到graphics.library。你可以更新Amiga显示驱动程序以支持它。而不是调用GetBitMap(它会复制结构),只需获取aHidd_PlanarBM_BitMap属性即可。这类似于aHidd_ChunkyBM_Buffer。它是可点燃和可设置的,所以你可以将自己的位图包装到对象中。我还发明了一个用于镜像显示驱动程序(如VESA和VGA)的框架。基类将自行支持所有功能。你只需要向它提供一个单帧缓冲区位图。它会自行镜像,消除代码重复。
当请求Amiga驱动程序创建新的位图时,就会发生这种情况,我不明白它与GetBitMap/SetBitMap及其同类函数有什么关系。(至少这个问题不是这样)。AmigaVideoBM__Root__New() 被调用,然后立即调用 OOP_DoSuperMethod -> BM_New -> PBM_New -> 失败。
Amiga驱动程序不是很干净,而且对于任何有用的事情来说,它仍然太慢了。例如,PutImage() 需要汇编C2P和GetImage() P2C例程,目前它们太慢了^10。
添加RTG驱动程序支持,但芯片组对于软件合成来说太慢了。正常的全硬件屏幕拖动将在某一天完成(目前,拖动时只有最前面的屏幕可见)。
为什么许多图形例程使用 LONG 坐标?是否有可能用 WORD 或平台特定的 16/32 位 typedef 来代替它们?这会导致在 68000 兼容的构建中出现不必要的减速,因为它可能会强制使用更慢的 32 位乘法(32x32=32)和除法(32/32=32),而这些操作不受 68000/010 的直接支持。(68000/010 只有 16x16=32 乘法和 32/16=16:16 除法指令),此外,在这些 CPU 上,所有 LONG 操作始终比 WORD 操作慢(68000/010 ALU 是 16 位的)。
所有图形例程 :)(例如,包括 hidds/graphics/BM_Class.c)Graphics.library 函数参数文档没有太多意义.. clib/protos 将大多数函数列为接受 LONG(即使 Move 和 Draw 使用 RastPort WORD 字段来存储最后位置!)Autodocs 将大多数函数列为接受 WORD。
在内部,AOS graphics.library 似乎总是使用 WORD(忽略高 16 位,因此对于寄存器参数来说很容易)。这可能太迟了,但我不知道为什么 AROS 从未定义 "虚拟寄存器",这将允许调用者将 <小于寄存器宽度的任何内容> 写入 <该体系结构上具有预定义宽度的任何寄存器>,然后在库函数端提取 <任何预期的宽度> 用于本地使用。
- 虚拟寄存器是 64 位宽
- 调用代码写入一个无符号的 32 位值
- 被调用代码获取低 16 位
- 被调用代码将它放入本地无符号的 16 位副本中并使用它
在 68k 上,它可能大多是无操作的,而在其他体系结构上则是其他操作。
graphics.library API 声明与 OS3.1 兼容。如果问题涉及它们,我会在内部将它们强制转换为 WORD。至于 graphics.hidd... 好吧,我个人不反对更改为 WORD(不过,据我所知,坐标在那里是 WORD)。
amiga-m68k 最大的游戏兼容性问题是 "错误的"(类似 RTG 的)结构位图格式用于平面屏幕,许多系统友好的(即不接管系统)游戏会以正常方式打开屏幕,然后直接写入屏幕的位图。如何解决这个问题?我注意到已经有了支持(至少是部分支持),例如 IS_HIDD_BM 和 OBTAIN_HIDD_BM 之类的宏。
graphics.hidd 中没有一个 PlanarBM 类,它基本上是一个内存中的位图实现,允许访问其数据行吗?可能,但应用程序可见的结构位图仍然是 BMF_SPECIALFMT。我的测试是 Dune II 游戏,它只显示红色鼠标光标和空白屏幕。(它还会在正确调用 LoadRGB4() 之前,用 NULL 视窗调用 LoadRGB4()。)只需检查屏幕的结构位图标志字段和平面指针吗?与真正的平面指针相比,BMF_SPECIALFMT "平面指针" 显得相当随机,并没有指向芯片 RAM(如果可用的话)。