注册 登录
编程论坛 C图形专区

[讨论]讲一下DOS下SVGA视频模式的设置问题

RockCarry 发布于 2007-06-25 12:39, 6725 次点击

最近都在做视频相关的驱动,因此对某些问题的认识又更加深刻了一些。

通常我们使用的PC机显示器,不管是 CRT 还是液晶,基本上都是采用的 VGA 接口。VGA 接口中,有5根最重要的信号线,用于数据和同步信号的传送,他们分别是:3根模拟RGB信号线,和2根行场同步信号线。

不同的显示器,对行场同步信号的要求是不同的,如果主机所提供的同步信号达不到显示器的要求,就有可能在显示器上出现“超出显示范围”或者是“无法支持的显示模式”等提示信息。

一般情况下:场同步(VSYNC)都是设置为60Hz,行同步则是根据点时钟(PCLK)和行总像素点数来进行计算,而通常所说的行场有效像素点数就是我们所熟悉的显示分辨率了。

在嵌入式数码产品中,行场同步信号都可以由CPU内部的显示控制器产生,因此只需要修改相关的代码,设置好显示控制器内部的寄存器,就能够输出正常的行场同步信号。我正在调试的 MP2530 平台上的 VGA 视频信号输出就是已经OK了。

但是在PC机的应用中,事情会变得比较复杂一点,Windows下不用说了,不会有这样的需求,就算是有,人家微软都已经给我们做好了,我们只需要简单的进行调用。在DOS下,可能会遇到设置SVGA视频模式出错的问题。这样的情况下,其实在主机这边,其实已经正确的设置好了视频模式,并且输出了视频信号,但是由于显示器不支持该视频信号,所以导致出现问题。

DOS平台下,虽然说已经很开放,可以操作硬件设备,但是许多基本的操作,还是被封装了,这种封装就是 PC 机的 BIOS。BIOS 的采用有历史原因,一方面是为了提供基本的硬件访问功能,一方面是为了保证兼容性。BIOS在本质上也是一段程序,它封装了对硬件的操作,向上提供一个一致的调用接口,因此上层的程序员,就无需关心下面的硬件细节。简单的讲NVIDA的显卡和ATI的显卡,在硬件上是绝对不一样的,其内部的寄存器也是不一样的,但是通过 BIOS 这一层之后,在其上层的程序员眼中,他们似乎没有什么区别,因为所有的操作都是通过 VBE 进行了。

再回到前面讨论的问题,,如何解决显示器无法正常工作的问题。没有办法,显示器不支持,就只有主机这边改变信号的输出,也就是改变一个显示模式。其实这种显示不正常,多数情况下都是由于行场同步信号不正确所造成。有些 VBE 的实现中,可能将 VSYNC 设置的过高,当分辨率也很高时,导致点时钟(PCLK)过高,许多显示器对PCLK的频率是有限制的,过样就会导致问题。因此如果要正确支持高分辨的视频模式,最好是将 VSYNC 降低,也就是将人们通常所说的刷新率降低,一般降到50左右,都是可以接受的,人眼也不会感觉闪烁。而视频模式的刷新率的设置,在 VBE2.0 中就已经有定义,因此在 DOS 中完全可以实现。这样可以解释为什么 Windows 下可以支持的视频模式,DOS程序中却不能设置,关键是要把 VSYNC 降下来。大家可以用示波器测一下 Windows 下高分辨率视频模式输出的 VSYNC 和我们在 DOS 中使用 VBE 设置的高分辨率视频模式输出的 VSYNC,比较一下其区别,就一切都清楚了。

在早期的DOS时代,VGA的控制器也是可以编程的,所以会出现 Mode-X 等等类型的非标准 VGA 视频模式。目前的PC机BIOS都兼容VGA标准,因此也可以直接操作VGA的控制器。但是VGA的致命弱点在于它所能支持的显存太小,这也限制了其显示分辨率的进一步提升。VESA继承并发展了VGA,但是VESA的显示控制器,即 SVGA Display Controller,在硬件上没有一个标准,因此我们无法直接操作这些 SVGA 的控制器,就算是能操作,也无法保证其兼容性。VBE标准的提出的一个最近基本的目的也是为了解决兼容性和标准化的问题。

因此说,在VESA系统中,我们不可能采用直接对 SVGA Display Controller 进行编程来实现对输出的视频同步信号进行修改。唯一能做的,就是依靠VBE来实现我们想要实现的东西,在这一点上,任何PC的软件都是遵循VBE来实现的,即便是 MS Windows 也不例外。

以上是我的分析,供大家参考,也希望大家参与讨论。


RockCarry
2007-6-25


[此贴子已经被作者于2007-6-25 12:44:31编辑过]

29 回复
#2
jig2007-06-25 14:01
顶~~~

RockCarry兄分析的很有道理,很长一段时间我和董凯都在讨论看能怎样解决DOS下某图形模式有可能无法正常工作,(因为现在他在的工作的需要)可后来才逐渐意识到这个是硬件支持的问题,这个是是依靠个人很难做到全兼容的模式。

呵呵,所以他现在在打歪注意,换平台。

叫他也上来顶一顶~!
#3
一笔苍穹2007-06-26 08:47
恩,是的,我也是这个观点,不过陈凯已经分析的更明确。在主机这边设置分辨率的代码哪怕一点都没错,也会出现和显示器端信号不匹配的情况,比如说垂直刷新率,设置分辨率的时候可能过低或过高,显示器不支持(就如LZ所说的“时钟(PCLK)过高”),所以出现黑屏或超出范围等问题。

另,不知道楼主对VBE的扩展标准VBE DDC是否有研究?
#4
RockCarry2007-06-26 09:29
VBE现在已经到了3.0,各个版本的文档我都看过,但是没有写过代码,所以只是理论上的认识而已。
#5
RockCarry2007-06-26 10:06
VBE3.0中貌似提供了修改点时钟和刷新率的办法,再setmode时就不能单纯的只设置模式号,还要设置刷新率。
不能 Use current default refresh rate,而是需要 Use user specified CRTC value for refresh rate
也就是说,在调用 4702h 功能时,需要传入一个 CRTCInfoBlock。
CRTCInfoBlock提供给了我们丰富的设置,足以满足需求,包括水平总像素点数,垂直总行数,行场同步信号的开始与结束位置,点时钟,刷新率,双扫描模式,隔行扫描模式,同步信号的极性等。只要正确设置这些,应该是可以正常显示的。
其实VBE3.0早就为我们提供了方法,只是我们没有意识到,不知道如何利用而已。

[此贴子已经被作者于2007-6-26 10:09:04编辑过]

#6
RockCarry2007-06-26 10:38
仔细阅读VBE3.0文档中的那一段,就会发现很多。VSYNC一般都是60Hz,也就是说刷新率为60。如果是1024*768的模式,可以设置 HTotal = 1100, VTotal = 800, 那么点时钟为 PCLK = 60 * 1100 * 800 = 52.8 MHz.
HSyncStart, HSyncEnd 和 VSyncStart, VSyncEnd,不知道具体是什么含义,因为文档上没有给出时序图。
至于同步信号的极性,一般的显示器要求都是高电平有效,其他的双扫描和各行扫描模式都需要关闭,使用逐行扫描就可以了。

[此贴子已经被作者于2007-6-26 10:48:36编辑过]

#7
RockCarry2007-06-26 10:58
DDC不太了解,似乎就是我前面讲的信号线的标准,3个模拟RGB,加上2个同步信号。不过似乎在软件上也有DDC的说法,貌似可以用来查询显示器的Capbility.
#8
RockCarry2007-06-26 11:31

又看了下VESA的一些标准,真没想到一些显示器是有支持IIC接口的,在VBE的扩展标准中,也定义了对IIC接口的操作,但是时好像不是很好用,需要自己控制电平的高低来产生IIC的时序。不过这个标准似乎对我们用处不大。

#9
一笔苍穹2007-06-27 13:09
算CRTC的代码可以看看Allegro有源码,不难
#10
kk48682007-07-12 13:08

我是shepherd,呵呵
最近心血来潮,重新钻研CRTC,有点收获,发出来和大家共同讨论。
经过XP的DOS测试,我的redon9550竟然是vbe2.0,郁闷ing
只好请出了sdd,在我的机器上测试通过,成功设置了刷新率

#11
kk48682007-07-12 13:09

测试代码很多人应该都很熟悉的。

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <conio.h>

// SuperVGA CRTCInfoBlock structure
struct
{
short HTotal;
short HSyncStart;
short HSyncEnd;
short VTotal;
short VSyncStart;
short VSyncEnd;
char Flags;
long PixelClock;
short RefreshRate;
char Reserved[40];

} CRTCInfoBlock;
/* Set a VBE video mode */
void setVBEMode()
{
char far *CRTCInfo = (char far *)&CRTCInfoBlock;
union REGS in,out;
struct SREGS segs;


in.x.ax = 0x4F02;
//in.x.bx = mode;
in.x.bx = 0x905;


// 1024*768 @ 60Hz
CRTCInfoBlock.HTotal=1328;
CRTCInfoBlock.HSyncStart=1048;
CRTCInfoBlock.HSyncEnd=1184;
CRTCInfoBlock.VTotal=806;
CRTCInfoBlock.VSyncStart=771;
CRTCInfoBlock.VSyncEnd=777;
CRTCInfoBlock.Flags=0xa;
CRTCInfoBlock.PixelClock=96333120;
CRTCInfoBlock.RefreshRate=6000;

/*// 1024*768 @ 70Hz
CRTCInfoBlock.HTotal=1328;
CRTCInfoBlock.HSyncStart=1048;
CRTCInfoBlock.HSyncEnd=1184;
CRTCInfoBlock.VTotal=806;
CRTCInfoBlock.VSyncStart=771;
CRTCInfoBlock.VSyncEnd=777;
CRTCInfoBlock.Flags=0x8;
CRTCInfoBlock.PixelClock=75000000;
CRTCInfoBlock.RefreshRate=7007;
*/
/*
// 1024*768 @ 75Hz
CRTCInfoBlock.HTotal=1312;
CRTCInfoBlock.HSyncStart=1040;
CRTCInfoBlock.HSyncEnd=1136;
CRTCInfoBlock.VTotal=800;
CRTCInfoBlock.VSyncStart=769;
CRTCInfoBlock.VSyncEnd=772;
CRTCInfoBlock.Flags=0xa;
CRTCInfoBlock.PixelClock=78750000;
CRTCInfoBlock.RefreshRate=75.03;
*/
in.x.di = FP_OFF(CRTCInfo);
segs.es = FP_SEG(CRTCInfo);
int86x(0x10, &in, &out, &segs);
//int86(0x10,&in,&out);
printf("%x : %d", out.h.al, out.h.ah);
}
/* Initialize the specified video mode. Notice how we determine a shift
* factor for adjusting the Window granularity for bank switching. This
* is much faster than doing it with a multiply (especially with direct
* banking enabled).
*/
void main()
{
setVBEMode();
getch();
_AX = 0x4f02;
_BX = 0x13;
geninterrupt(0x10);
}

#12
kk48682007-07-12 13:14

根据VBE3.0的技术文档,这个程序返回0就证明设置成功;其他值说明不成功。
我用WIN-TC编译后直接运行,显示1;
在XP的DOS窗口下先运行SDD,生成DRV文件,然后运行univbe。
最后运行vesa.exe(就是上面那段代码),结果显示0,并且从字体上看,应该是设置成功的

另外,在845g的主板上(我测试用的是nforce2),直接运行后花屏,而且不知道为什么SDD安装失败,郁闷

#13
jig2007-07-12 13:17

定了~~藏了哦,追风兄。

#14
kk48682007-07-12 13:18
需要注意的是,测试的时候要显示器要选择110mhz带宽的,否则超过带宽容易烧显示器的。
我用的是150mhz的
#15
RockCarry2007-07-12 14:04
XP 的 DOS Box 毕竟是软件模拟的东西,声卡、显卡、时钟(8253)、DMA控制器(8237)、中断控制器(8259),等等许多硬件相关的东西,在 DOS Box 里面都是由软件模拟实现的。
从目前的表现看来,微软做的不是很好,声卡似乎只能支持到 SB2.0,时钟不准确并且不能提供真正的中断、DMA控制器似乎也有问题、中断控制器还好,显卡部分的支持也不好。目前主流的显卡都是 VBE3.0 了,但是 XP 的 DOS Box 要告诉你他只支持 VBE2.0,你也是没有办法。
SDD 是何东西,还没有听说过。

[此贴子已经被作者于2007-7-12 14:12:14编辑过]

#16
kk48682007-07-12 14:10
SDD:SciTech Display Doctor 6.53
#17
kk48682007-07-12 14:15

刚才利用电脑公司版GHOST XP附带的DOS系统测试了,跟在XP下测试的结果一样。

#18
RockCarry2007-07-12 14:16
原来如此,搜索了一下,好像有7.0版本的了
#19
kk48682007-07-12 14:20

要找dos版的

#20
RockCarry2007-07-12 15:07

VBE跟主扳有很大关系,因为VBE多数情况下是放在BIOS中的。但是不能排除其他的实现方式,比如说DOS下的TSR,这在VBE3.0的文档中也有指出。
因此,即便是在纯DOS下,也有可能出现问题,这就是因为BIOS中没有实现VBE3.0,或者说VBE3.0是以TSR或其他方式提供的,而我们的机器中却没有安装相应的TSR程序。因此需要向主板厂商或者实显卡厂商寻求技术支持。
为什么Windows就可以呢?因为Windows下装了那么多驱动,说不定某一个就提供了对VBE3.0的支持。如果硬件都是一样的,就是软件实现上的问题。如果微软都能做到,就说明是可以实现的,只是目前我们还没有找到办法。

[此贴子已经被作者于2007-7-12 15:47:28编辑过]

#21
RockCarry2007-07-12 15:48
程序都是人写出来的,微软的程序员也是人,我坚信,别人能做到的,我们也能做到。
#22
一笔苍穹2007-07-12 16:42
哈哈,老追来了,对于不支持VBE 3。0的卡,SDD是个不错的选择,而且有些已经支持3。0却支持的不够好的卡(比如一些集成卡虽然支持到3。0但许多模式不可用),SDD也能派上用场,而且SDD具有一定的加速能力。
#23
kk48682007-07-12 17:34

目前在我的机器上是能改变刷新率了,接着要多找几台显示器试一下。
神啊,保佑我不要烧掉它们吧,呵呵。

#24
kk48682007-07-15 23:37

得到DDC信息(就是EDID吧,我不是太清楚)的方法:
AX=0x4f15
BX=0x1
INT 10
一般是得到128字节的信息,然后就按照EDID规范去分析吧,好像挺复杂的,就像二进制文件的解码一样。
关键的是第七部分:Detailed Timing Section(72Bytes,36h-7Dh)
另外一个是第四部分:Basic Display Parameters(5Bytes,14h-18h)。我对标准文档的该部分描述存有疑问,它和第五部分之间有十个字节的空缺,不知道为什么。

#25
kk48682007-07-15 23:56

另外文献里提到EDID的地址:0xA0很多次了,希望高手解释下它的用法。

#26
gaohaidong2007-07-27 19:38
最近,我有个C语言直接些屏幕的SVGA256色显示模式的程序,在一些老的机器(系统2000或xp,显卡Intel 810)和一些更新的机器上(系统2000,显卡Intel 910)上运行正常!
但是在我的电脑(系统xp,显卡Intel 82865)上却出现一些乱条!
不知道什么原因?
#27
kk48682007-07-28 01:18

从目前的试验结果来看,问题出在INTEL的显示芯片的驱动上。就是INTEL系列的部分显卡(从815到865)驱动,并没有按照默认的标准开发。
1.显存页大小可能不是64K而是16K,从而造成图像完全变花
2.默认的图形模式下刷新频率过高或者过低,导致显示器自动黑屏保护。

#28
kk48682007-07-28 01:24

对于这两个问题,你可以认为是INTEL没有按照默认的标准去做;而实际上,是编程人员对VESA标准研究的不够。比如说,想当然的认为显存页大小是64K(当然多数显卡是64K啦),而实际上应该去读INT 10中断的返回信息,确定显存页面的大小。这个应该就是你碰到的问题所在。
至于黑屏的问题,前面已经讨论过了,是对于EDID和显示器DDC的VESA标准研究不够的问题。

#29
kk48682007-07-28 01:25
一般来说,确定可以正常使用的是320*200*256模式,请在调试的时候尽量使用它。
#30
wangxy2006962007-09-23 12:52

顶....
还要多努力。。

1