zyl910

优化技巧、硬件体系、图像处理、图形学、游戏编程、国际化与文本信息处理。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

File:      VGASpeed.txt
Name:      测试VGA12H模式的速度
Author:    zyl910
Blog:      http://blog.csdn.net/zyl910/
Version:   V1.0
Updata:    2006-11-14

下载(注意修改下载后的扩展名)


简介
~~~~
  DOS下直接写屏的代码写过不少了,但一直没有想过一个问题——操作VGA的速度有多块。因此,我写了个小程序来测试VGA的速度。
  图形模式:VGA 12h,640*480*16色。
  三个测试项目:
    1.读测试。使用VGA读模式0,逐扫描行逐位平面的将显存数据复制到系统内存。
    2.写测试。使用VGA写模式0,逐扫描行逐位平面的将系统内存数据复制到显存。
    3.在等待垂直回扫情况下的写测试。
  四种访问方式:用C语言远指针、movsb、movsw、movsd

 

测试结果
~~~~~~~~

CPU   : AMD Athlon XP 1700+(实际频率:1463 MHz (11 x 133))
内存  : DDR266 256MB
显卡  : NVIDIA GeForce2 MX/MX 400(AGP 4X)
显存带宽: 125MHz * 128bit = 2000MB/s
操作系统: Windows XP SP2
[FPS]
R_C    :         11.7646
W_C    :         51.5834
R_BYTE :         12.0000
W_BYTE :         86.4751
R_WORD :         23.6298
W_WORD :        124.8862
R_DWORD:         44.7459
W_DWORD:        156.8619
WaitW_B:         60.0298
WaitW_W:         59.9293
WaitW_D:         59.9293
124.8862 /  86.4751 = 144.42%
156.8619 / 124.8862 = 125.60%

 

CPU   : AMD Athlon XP 1700+(实际频率:1463 MHz (11 x 133))
内存  : DDR266 256MB
显卡  : NVIDIA GeForce2 MX/MX 400(AGP 4X)
显存带宽: 125MHz * 128bit = 2000MB/s
操作系统: Windows 98SE
[FPS]
R_C    :         11.6641
W_C    :         60.7337
R_BYTE :         11.9657
W_BYTE :         98.8431
R_WORD :         23.4287
W_WORD :        173.9558
R_DWORD:         44.4442
W_DWORD:        267.9724
WaitW_B:         59.9293
WaitW_W:         59.9293
WaitW_D:         60.0298
173.9558 /  98.8431 = 175.99%
267.9724 / 173.9558 = 154.05%


CPU   : AMD Athlon XP 1700+(实际频率:1463 MHz (11 x 133))
内存  : DDR266 256MB
显卡  : NVIDIA GeForce2 MX/MX 400(AGP 4X)
显存带宽: 125MHz * 128bit = 2000MB/s
操作系统: DOS实模式
[FPS]
R_C    :         11.7646
W_C    :         61.2365
R_BYTE :         12.0663
W_BYTE :        107.9934
R_WORD :         23.6298
W_WORD :        190.6475
R_DWORD:         44.9470
W_DWORD:        279.1337
WaitW_B:         60.0298
WaitW_W:         59.9293
WaitW_D:         60.0298
190.6475 / 107.9934 = 176.54%
279.1337 / 190.6475 = 146.41%

 

CPU   : Intel Celeron 2.53GHz
内存  : Dual DDR333 512MB
显卡  : NVIDIA RIVA TNT2 Model 64(AGP 4X)
显存带宽: 110MHz * 64bit = 880MB/s
操作系统: Windows XP SP2
[FPS]
R_C    :          8.4464
W_C    :         37.5061
R_BYTE :          8.4000
W_BYTE :         46.1536
R_WORD :         16.2895
W_WORD :         64.1525
R_DWORD:         31.1713
W_DWORD:         78.9337
WaitW_B:         29.8641
WaitW_W:         59.3260
WaitW_D:         59.5271
64.1525 / 46.1536 = 138.99%
78.9337 / 64.1525 = 123.04%

 

CPU   : Intel Celeron, 1800 MHz (18 x 100)
内存  : DDR266 256MB
显卡  : nVIDIA GeForce4 MX 440(AGP 8X)
显存带宽: 405MHz * 64bit = 3240MB/s
操作系统: Windows XP SP2
[FPS]
R_C    :          7.7425
W_C    :         33.1823
R_BYTE :          7.8000
W_BYTE :         42.9359
R_WORD :         15.0829
W_WORD :         56.5105
R_DWORD:         28.8586
W_DWORD:         68.5768
WaitW_B:         28.6575
WaitW_W:         49.2707
WaitW_D:         55.2033
56.5105 / 42.9359 = 131.62%
68.5768 / 56.5105 = 121.35%

 

分析
~~~~

一、刷新率是60帧
  “在等待垂直回扫情况下的写测试”的测试结果都差不多,这表示VGA12H模式下的刷新率为60帧。


二、读的速度比写的慢的多
  可能是因为在设计VGA硬件时,考虑到显存一般是用来输出的,所以专门为写操作优化的。
  由于读速度过慢,所以VGA的一些需要读显存的硬件加速特性——循环移位、位图合并模式——并不能提高性能,反而有可能拖后腿。


三、movsw/movsd对性能的提升没有想象中得那么高
  对于读测试,movsw/movsd能使性能翻倍。
  可对于写测试,movsw/movsd虽然能提高性能,但并没翻倍。
  但是我们为了追求速度,还是坚持使用movsd方式吧。
  注意写模式1只支持movsb。


四、为什么速度这么慢
  VGA12H模式的分辨率是640*480*16色,所以每帧图像大小为:640*480*4/8 = 153600(Byte)
  AGP总线的频率为66Mhz,如果每个时钟复制一个字节,那么理论上的帧率为:66Mhz * 1BytePerHz / 153600 = 429.6875fps
  而实际的movsb的测试结果是100帧左右,只有理论值的1/4。若再考虑AGP 4X使频率提高4倍,那么差距更大。
  可能是因为:当显卡将帧数据发送到显示器时,不可访问主表面的显存。但是VGA12H下只有一个主表面(VGA显存是256KB),放不下离屏表面,无法利用双缓冲加速。


测试代码
~~~~~~~~

 

/*
File:      VGASpeed.c
Name:      测试VGA12H模式的速度
Author:    zyl910
Blog:      http://blog.csdn.net/zyl910/
Version:   V1.0
Updata:    2006-11-14
*/
#include <stdio.h>
#include <conio.h>
#include <mem.h>
#include <dos.h>

typedef unsigned char BYTE;
typedef unsigned int  WORD;
typedef unsigned long DWORD;
typedef void far* LPVOID;

#define SCR_W 640
#define SCR_H 480
#define SCR_PLANES 4
#define SCANSIZE_DIB ((SCR_W)/2)
#define SCANSIZE_VGA ((SCR_W)/8)
#define SEG_VIDEO 0xA000
#define WaitVR() while(!(inportb(0x3da)&0x08))
static volatile DWORD far* const pbiosclock = MK_FP(0x0040, 0x6C);
#define BIOSCLOCK_F ((double)18.2)
void repmovsb(LPVOID lpD, LPVOID lpS, WORD cBytes)
{
 _asm{
  push ds
  push es
  mov cx, cBytes
  les di, lpD
  lds si, lpS
  rep movsb
  pop es
  pop ds;
 }
}
void repmovsw(LPVOID lpD, LPVOID lpS, WORD cWords)
{
 _asm{
  push ds
  push es
  mov cx, cWords
  les di, lpD
  lds si, lpS
  rep movsw
  pop es
  pop ds;
 }
}
void repmovsd(LPVOID lpD, LPVOID lpS, WORD cDWords)
{
 _asm{
  push ds
  push es
  mov cx, cDWords
  les di, lpD
  lds si, lpS
  db 0x66; rep movsw; /* rep movsd */
  pop es
  pop ds
 }
}
int main(void)
{
 BYTE byVGA[SCR_PLANES][SCANSIZE_VGA];
 DWORD cntF;
 int iX, iY;
 BYTE iP;
 WORD pscan;
 BYTE far *pbyV;
 BYTE *pbyM;
 BYTE bymask;
 DWORD tmrold, tmrcur, tmrover;
 double fpsR_C, fpsR_BYTE, fpsR_WORD, fpsR_DWORD;
 double fpsW_C, fpsW_BYTE, fpsW_WORD, fpsW_DWORD;
 double fpsWaitW_BYTE, fpsWaitW_WORD, fpsWaitW_DWORD;
 /* init VGA 12h: 640*480*4bit */
 _asm{
  mov ax, 0x0012;
  int 0x10;
  cld;
 }
 printf("Testing...");
 /* R:C */
 do{
  cntF = 0;
  tmrold = *pbiosclock;
  tmrover = tmrold + (DWORD)(BIOSCLOCK_F * 10); /* 10s */
  do{
   pscan = 0;
   for(iY=0; iY<SCR_H; iY++)
   {
    for(iP=0; iP<SCR_PLANES; iP++)
    {
     _asm{
      mov dx, 0x3CE; /* gc[4]:Read Map Select */
      mov al, 4;
      out dx, al;
      inc dx;
      mov al, iP;
      out dx, al;
     }
     pbyM = byVGA[iP];
     pbyV = MK_FP(SEG_VIDEO, pscan);
     for(iX=0; iX<SCANSIZE_VGA; iX++)
     {
      *pbyM++ = *pbyV++;
     }
    }
    pscan += SCANSIZE_VGA;
   }
   cntF++;
   tmrcur = *pbiosclock;
  }while((tmrcur<tmrover)&&(tmrcur>=tmrold));
  if (tmrcur < tmrold) continue;
 }while(0);
 fpsR_C = cntF / ((tmrcur-tmrold)/BIOSCLOCK_F);
 /* W:C */
 do{
  cntF = 0;
  tmrold = *pbiosclock;
  tmrover = tmrold + (DWORD)(BIOSCLOCK_F * 10); /* 10s */
  do{
   memset(byVGA[0], -(1&(((int)cntF)>>0)), SCANSIZE_VGA);
   memset(byVGA[1], -(1&(((int)cntF)>>1)), SCANSIZE_VGA);
   memset(byVGA[2], -(1&(((int)cntF)>>2)), SCANSIZE_VGA);
   memset(byVGA[3], -(1&(((int)cntF)>>3)), SCANSIZE_VGA);
   pscan = 0;
   for(iY=0; iY<SCR_H; iY++)
   {
    bymask = 1;
    for(iP=0; iP<SCR_PLANES; iP++)
    {
     _asm{
      mov dx, 0x3C4; /* sc[2]:Map Mask */
      mov al, 2;
      out dx, al;
      inc dx;
      mov al, bymask;
      out dx, al;
     }
     pbyM = byVGA[iP];
     pbyV = MK_FP(SEG_VIDEO, pscan);
     for(iX=0; iX<SCANSIZE_VGA; iX++)
     {
      *pbyV++ = *pbyM++;
     }
     bymask <<= 1;
    }
    pscan += SCANSIZE_VGA;
   }
   cntF++;
   tmrcur = *pbiosclock;
  }while((tmrcur<tmrover)&&(tmrcur>=tmrold));
  if (tmrcur < tmrold) continue;
 }while(0);
 fpsW_C = cntF / ((tmrcur-tmrold)/BIOSCLOCK_F);
 /* R:Byte */
 do{
  cntF = 0;
  tmrold = *pbiosclock;
  tmrover = tmrold + (DWORD)(BIOSCLOCK_F * 10); /* 10s */
  do{
   pscan = 0;
   for(iY=0; iY<SCR_H; iY++)
   {
    for(iP=0; iP<SCR_PLANES; iP++)
    {
     _asm{
      mov dx, 0x3CE; /* gc[4]:Read Map Select */
      mov al, 4;
      out dx, al;
      inc dx;
      mov al, iP;
      out dx, al;
     }
     repmovsb(byVGA[iP], MK_FP(SEG_VIDEO, pscan), SCANSIZE_VGA);
    }
    pscan += SCANSIZE_VGA;
   }
   cntF++;
   tmrcur = *pbiosclock;
  }while((tmrcur<tmrover)&&(tmrcur>=tmrold));
  if (tmrcur < tmrold) continue;
 }while(0);
 fpsR_BYTE = cntF / ((tmrcur-tmrold)/BIOSCLOCK_F);
 /* W:BYTE */
 do{
  cntF = 0;
  tmrold = *pbiosclock;
  tmrover = tmrold + (DWORD)(BIOSCLOCK_F * 10); /* 10s */
  do{
   memset(byVGA[0], -(1&(((int)cntF)>>0)), SCANSIZE_VGA);
   memset(byVGA[1], -(1&(((int)cntF)>>1)), SCANSIZE_VGA);
   memset(byVGA[2], -(1&(((int)cntF)>>2)), SCANSIZE_VGA);
   memset(byVGA[3], -(1&(((int)cntF)>>3)), SCANSIZE_VGA);
   pscan = 0;
   for(iY=0; iY<SCR_H; iY++)
   {
    bymask = 1;
    for(iP=0; iP<SCR_PLANES; iP++)
    {
     _asm{
      mov dx, 0x3C4; /* sc[2]:Map Mask */
      mov al, 2;
      out dx, al;
      inc dx;
      mov al, bymask;
      out dx, al;
     }
     repmovsb(MK_FP(SEG_VIDEO, pscan), byVGA[iP], SCANSIZE_VGA);
     bymask <<= 1;
    }
    pscan += SCANSIZE_VGA;
   }
   cntF++;
   tmrcur = *pbiosclock;
  }while((tmrcur<tmrover)&&(tmrcur>=tmrold));
  if (tmrcur < tmrold) continue;
 }while(0);
 fpsW_BYTE = cntF / ((tmrcur-tmrold)/BIOSCLOCK_F);
 /* R:Word */
 do{
  cntF = 0;
  tmrold = *pbiosclock;
  tmrover = tmrold + (DWORD)(BIOSCLOCK_F * 10); /* 10s */
  do{
   pscan = 0;
   for(iY=0; iY<SCR_H; iY++)
   {
    for(iP=0; iP<SCR_PLANES; iP++)
    {
     _asm{
      mov dx, 0x3CE; /* gc[4]:Read Map Select */
      mov al, 4;
      out dx, al;
      inc dx;
      mov al, iP;
      out dx, al;
     }
     repmovsw(byVGA[iP], MK_FP(SEG_VIDEO, pscan), SCANSIZE_VGA/2);
    }
    pscan += SCANSIZE_VGA;
   }
   cntF++;
   tmrcur = *pbiosclock;
  }while((tmrcur<tmrover)&&(tmrcur>=tmrold));
  if (tmrcur < tmrold) continue;
 }while(0);
 fpsR_WORD = cntF / ((tmrcur-tmrold)/BIOSCLOCK_F);
 /* W:WORD */
 do{
  cntF = 0;
  tmrold = *pbiosclock;
  tmrover = tmrold + (DWORD)(BIOSCLOCK_F * 10); /* 10s */
  do{
   memset(byVGA[0], -(1&(((int)cntF)>>0)), SCANSIZE_VGA);
   memset(byVGA[1], -(1&(((int)cntF)>>1)), SCANSIZE_VGA);
   memset(byVGA[2], -(1&(((int)cntF)>>2)), SCANSIZE_VGA);
   memset(byVGA[3], -(1&(((int)cntF)>>3)), SCANSIZE_VGA);
   pscan = 0;
   for(iY=0; iY<SCR_H; iY++)
   {
    bymask = 1;
    for(iP=0; iP<SCR_PLANES; iP++)
    {
     _asm{
      mov dx, 0x3C4; /* sc[2]:Map Mask */
      mov al, 2;
      out dx, al;
      inc dx;
      mov al, bymask;
      out dx, al;
     }
     repmovsw(MK_FP(SEG_VIDEO, pscan), byVGA[iP], SCANSIZE_VGA/2);
     bymask <<= 1;
    }
    pscan += SCANSIZE_VGA;
   }
   cntF++;
   tmrcur = *pbiosclock;
  }while((tmrcur<tmrover)&&(tmrcur>=tmrold));
  if (tmrcur < tmrold) continue;
 }while(0);
 fpsW_WORD = cntF / ((tmrcur-tmrold)/BIOSCLOCK_F);
 /* R:DWord */
 do{
  cntF = 0;
  tmrold = *pbiosclock;
  tmrover = tmrold + (DWORD)(BIOSCLOCK_F * 10); /* 10s */
  do{
   pscan = 0;
   for(iY=0; iY<SCR_H; iY++)
   {
    for(iP=0; iP<SCR_PLANES; iP++)
    {
     _asm{
      mov dx, 0x3CE; /* gc[4]:Read Map Select */
      mov al, 4;
      out dx, al;
      inc dx;
      mov al, iP;
      out dx, al;
     }
     repmovsd(byVGA[iP], MK_FP(SEG_VIDEO, pscan), SCANSIZE_VGA/4);
    }
    pscan += SCANSIZE_VGA;
   }
   cntF++;
   tmrcur = *pbiosclock;
  }while((tmrcur<tmrover)&&(tmrcur>=tmrold));
  if (tmrcur < tmrold) continue;
 }while(0);
 fpsR_DWORD = cntF / ((tmrcur-tmrold)/BIOSCLOCK_F);
 /* W:DWORD */
 do{
  cntF = 0;
  tmrold = *pbiosclock;
  tmrover = tmrold + (DWORD)(BIOSCLOCK_F * 10); /* 10s */
  do{
   memset(byVGA[0], -(1&(((int)cntF)>>0)), SCANSIZE_VGA);
   memset(byVGA[1], -(1&(((int)cntF)>>1)), SCANSIZE_VGA);
   memset(byVGA[2], -(1&(((int)cntF)>>2)), SCANSIZE_VGA);
   memset(byVGA[3], -(1&(((int)cntF)>>3)), SCANSIZE_VGA);
   pscan = 0;
   for(iY=0; iY<SCR_H; iY++)
   {
    bymask = 1;
    for(iP=0; iP<SCR_PLANES; iP++)
    {
     _asm{
      mov dx, 0x3C4; /* sc[2]:Map Mask */
      mov al, 2;
      out dx, al;
      inc dx;
      mov al, bymask;
      out dx, al;
     }
     repmovsd(MK_FP(SEG_VIDEO, pscan), byVGA[iP], SCANSIZE_VGA/4);
     bymask <<= 1;
    }
    pscan += SCANSIZE_VGA;
   }
   cntF++;
   tmrcur = *pbiosclock;
  }while((tmrcur<tmrover)&&(tmrcur>=tmrold));
  if (tmrcur < tmrold) continue;
 }while(0);
 fpsW_DWORD = cntF / ((tmrcur-tmrold)/BIOSCLOCK_F);
 /* WaitW:BYTE */
 do{
  cntF = 0;
  tmrold = *pbiosclock;
  tmrover = tmrold + (DWORD)(BIOSCLOCK_F * 10); /* 10s */
  do{
   memset(byVGA[0], -(1&(((int)cntF)>>0)), SCANSIZE_VGA);
   memset(byVGA[1], -(1&(((int)cntF)>>1)), SCANSIZE_VGA);
   memset(byVGA[2], -(1&(((int)cntF)>>2)), SCANSIZE_VGA);
   memset(byVGA[3], -(1&(((int)cntF)>>3)), SCANSIZE_VGA);
   pscan = 0;
   WaitVR();
   for(iY=0; iY<SCR_H; iY++)
   {
    bymask = 1;
    for(iP=0; iP<SCR_PLANES; iP++)
    {
     _asm{
      mov dx, 0x3C4; /* sc[2]:Map Mask */
      mov al, 2;
      out dx, al;
      inc dx;
      mov al, bymask;
      out dx, al;
     }
     repmovsb(MK_FP(SEG_VIDEO, pscan), byVGA[iP], SCANSIZE_VGA);
     bymask <<= 1;
    }
    pscan += SCANSIZE_VGA;
   }
   cntF++;
   tmrcur = *pbiosclock;
  }while((tmrcur<tmrover)&&(tmrcur>=tmrold));
  if (tmrcur < tmrold) continue;
 }while(0);
 fpsWaitW_BYTE = cntF / ((tmrcur-tmrold)/BIOSCLOCK_F);
 /* WaitW:WORD */
 do{
  cntF = 0;
  tmrold = *pbiosclock;
  tmrover = tmrold + (DWORD)(BIOSCLOCK_F * 10); /* 10s */
  do{
   memset(byVGA[0], -(1&(((int)cntF)>>0)), SCANSIZE_VGA);
   memset(byVGA[1], -(1&(((int)cntF)>>1)), SCANSIZE_VGA);
   memset(byVGA[2], -(1&(((int)cntF)>>2)), SCANSIZE_VGA);
   memset(byVGA[3], -(1&(((int)cntF)>>3)), SCANSIZE_VGA);
   pscan = 0;
   WaitVR();
   for(iY=0; iY<SCR_H; iY++)
   {
    bymask = 1;
    for(iP=0; iP<SCR_PLANES; iP++)
    {
     _asm{
      mov dx, 0x3C4; /* sc[2]:Map Mask */
      mov al, 2;
      out dx, al;
      inc dx;
      mov al, bymask;
      out dx, al;
     }
     repmovsw(MK_FP(SEG_VIDEO, pscan), byVGA[iP], SCANSIZE_VGA/2);
     bymask <<= 1;
    }
    pscan += SCANSIZE_VGA;
   }
   cntF++;
   tmrcur = *pbiosclock;
  }while((tmrcur<tmrover)&&(tmrcur>=tmrold));
  if (tmrcur < tmrold) continue;
 }while(0);
 fpsWaitW_WORD = cntF / ((tmrcur-tmrold)/BIOSCLOCK_F);
 /* WaitW:DWORD */
 do{
  cntF = 0;
  tmrold = *pbiosclock;
  tmrover = tmrold + (DWORD)(BIOSCLOCK_F * 10); /* 10s */
  do{
   memset(byVGA[0], -(1&(((int)cntF)>>0)), SCANSIZE_VGA);
   memset(byVGA[1], -(1&(((int)cntF)>>1)), SCANSIZE_VGA);
   memset(byVGA[2], -(1&(((int)cntF)>>2)), SCANSIZE_VGA);
   memset(byVGA[3], -(1&(((int)cntF)>>3)), SCANSIZE_VGA);
   pscan = 0;
   WaitVR();
   for(iY=0; iY<SCR_H; iY++)
   {
    bymask = 1;
    for(iP=0; iP<SCR_PLANES; iP++)
    {
     _asm{
      mov dx, 0x3C4; /* sc[2]:Map Mask */
      mov al, 2;
      out dx, al;
      inc dx;
      mov al, bymask;
      out dx, al;
     }
     repmovsd(MK_FP(SEG_VIDEO, pscan), byVGA[iP], SCANSIZE_VGA/4);
     bymask <<= 1;
    }
    pscan += SCANSIZE_VGA;
   }
   cntF++;
   tmrcur = *pbiosclock;
  }while((tmrcur<tmrover)&&(tmrcur>=tmrold));
  if (tmrcur < tmrold) continue;
 }while(0);
 fpsWaitW_DWORD = cntF / ((tmrcur-tmrold)/BIOSCLOCK_F);
 /* Exit VGA */
 _asm{
  mov ax, 0x0003;
  int 0x10;
 }
 /* out */
 printf("[FPS]/n");
 printf("R_C    :%16.4f/n", fpsR_C);
 printf("W_C    :%16.4f/n", fpsW_C);
 printf("R_BYTE :%16.4f/n", fpsR_BYTE);
 printf("W_BYTE :%16.4f/n", fpsW_BYTE);
 printf("R_WORD :%16.4f/n", fpsR_WORD);
 printf("W_WORD :%16.4f/n", fpsW_WORD);
 printf("R_DWORD:%16.4f/n", fpsR_DWORD);
 printf("W_DWORD:%16.4f/n", fpsW_DWORD);
 printf("WaitW_B:%16.4f/n", fpsWaitW_BYTE);
 printf("WaitW_W:%16.4f/n", fpsWaitW_WORD);
 printf("WaitW_D:%16.4f/n", fpsWaitW_DWORD);
 return 0;
}

posted on 2006-11-14 22:49  zyl910  阅读(398)  评论(0编辑  收藏  举报