图形模式的显示速度分析 原理跟文本模式一样,如果我们用for循环语句将屏幕用putchar语句填满"A"和使用puts语句填满"A"速度是不一样的。如果你没有进行过文本模式速度分析也无所谓,接下来往下看。 使用基本的写点函数 VESA BIOS 提供了一个通用的图形模式的基本写点函数 videodot,函数形式如下: videodot(int x, int y, int color) { union REGS r; r.h.ah = 12; r.h.al = color; r.x.cx = x; r.x.dx = y; int86(0x10,&r,&r); } 然后,使用该函数我们在屏幕上先画一个200*200的正方形,程序如下 main() { int i,j; init256();/*初始化屏幕为640*480 256色模式,详见-256色模式写屏*/ for(j=100;j<300;j++) for(i=100;i<300;i++) videodot(i,j,100); getch();/*暂停以观察屏幕*/ close256();/*恢复屏幕为文本模式,参考文章-256色模式写屏*/ } 也可以借用256色图形系统的初始化函数(已去掉DAC色表设置)<点击此处>。 怎么样,速度很慢吧,可以说慢得出奇。如果帝国时代或是星际争霸也使用这种显示方法的话,早就没人玩了。所以,还得另寻其它方法。 使用直接写显存的方法 大多数软件和游戏均使用这种方法,这种方法的优势是速度快,缺点是实现比较麻烦。使用这种方法,由于无法直接寻址所有显存,因此要使用换页机制。而在何处换页,换页是如何对写入数据截断处理,是使用该方法的难点和重点。 在这里我采取直接计算点位置的方法。原理是显示点前按照要显示的位置先计算出所在页,然后再换页显示。程序如下: main() { int i,j; long position; init256(); for(j=100;j<300;j++) for(i=100;i<300;i++) {position=640l*j+i; selectpage(position/65536);/*映射到相应的显示页*/ pokeb(0xa000,position%65536,100);/*在相应点处显示*/ } getch(); close256(); } 速度是不是快了一些?其实速度的潜力还可以继续挖掘,请接着往下看。 写显存的加速方法 其实在上一个写屏方法中,有一个瓶颈制约了显示速度。因为每写一个点都要依次调用换页中断,而中断的速度又比较慢,所以拖了显示的后腿。 因而在写点时不必每写一点就换页,可以在写点位置不在原来页上时,再开始换页,这样又可以节约一大部分时间。因此在每页最后一个像素点要进行跳页。我采取的方法是用一变量记录下前一页的页号,当计算后的页号不等于前一页号时再进行换页。程序如下:
main() { unsigned char nowpage,lastpage=8; int i,j; long position; init256(); for(j=100;j<300;j++) for(i=100;i<300;i++) {position=640l*j+i; nowpage=position/65536; if(nowpage!=lastpage) {selectpage(nowpage); lastpage=nowpage; } position%=65536; pokeb(0xa000,position,100); } getch(); close256(); } 速度是不是又快了些?然而我还不满足,我要“榨干”电脑的潜力。前面都是以点为单位读取数据的,我把它们改用块复制,同时使用寄存器变量,将速度作了最后一步提升。在使用块复制时,因为显示行可能跨页,因此必需估计复制块的长度,在0xa000ffff的位置必需要做截断处理。截断数据时,要记录下跨显示页的扫描线的换页点,也就是内存中显存映射的65535位置点在屏幕上的位置。程序如下: main() { register int j,n[4]=;/*第0、1、2、3页换页列位置*/ register char page_new,page_old,page_end, *p=MK_FP(0xa000,0000),buffer[640]; register long position; page_old=8; init256(); selectpage(page_old); memset(buffer,100,640);/*将要复制块置为要拷贝的颜色*/ for(j=100;j<300;j++) {position=640l*j+100; page_new=position/65536; page_end=(position+200)/65536; if(page_new!=page_old) /*处理跳行跨页*/ if(page_new!=page_end) /*处理显示行跨页*/ {memcpy(p+position%65536,buffer,n[page_new]-100); selectpage(page_new+1); memcpy(p,buffer,300-n[page_new]); selectpage(page_new); } else memcpy(p+position%65536,buffer,200); } lastpage=page_new; getch(); close256(); } 经过上面一段“演练”后,对显存写屏你是不是更加了解了些呢?归纳起来,可以得到这样一个结论:在速度上 BIOS写点 < 显存单个写点 < 块复制写点,同时注意少用换页函数。
|