如何解决Windows 7上DirectX 7的延迟问题?

6
我们有一款软件,使用DirextX 7 SDK(即代码使用LPDIRECTDRAWSURFACE7等),并且以全屏模式运行。主要任务是以可靠的方式将内容呈现在屏幕上,以响应外部触发器。在Windows XP上表现非常良好:基本上,该软件等待某个触发器,当触发后创建新的帧,将其放入后备缓冲区,然后告诉DX翻转缓冲区。结果是触发器与帧实际显示在屏幕上之间的大约延迟取决于显卡和驱动程序,在60Hz屏幕上为3帧或50mSec。这已经在各种系统上测试过了,所有系统都运行着NVidia显卡。在某些配备高端显卡的系统上,我们甚至获得了2帧。
然而,在Windows 7上运行相同的软件(完全没有安装其他软件)时,我们无法低于5帧。这意味着在管道的某个地方,操作系统或驱动程序或两者都会多吃掉2帧,这对于应用程序来说几乎是不可接受的。我们试过禁用aero /桌面合成/不同的驱动程序版本/不同的显卡,但都没有用。
以下是一些相关的代码:
创建前/后表面:
ddraw7->SetCooperativeLevel( GetSafeHwnd(),
  DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_MULTITHREADED )

DDSURFACEDESC2 desc;
ZeroMemory( &desc, sizeof(desc) );
desc.dwSize = sizeof( desc );
desc.dwFlags =  DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
                      DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE |
                      DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
desc.dwBackBufferCount = 1;
ddraw7->CreateSurface( &desc, &primsurf, 0 )

DDSCAPS2 surfcaps;
ZeroMemory( &surfcaps,sizeof( surfcaps ) );
surfcaps.dwCaps = DDSCAPS_BACKBUFFER;
primsurf->GetAttachedSurface( &surfcaps, &backsurf );

创建用于绘制帧之前渲染的表面:

DDSURFACEDESC2 desc;
ZeroMemory( &desc, sizeof(desc) );
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS ;
desc.dwWidth = w;
desc.dwHeight = h;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
desc.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
desc.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8;

LPDIRECTDRAWSURFACE7 surf;
HRESULT r=ddraw7->CreateSurface( &desc, &surf, 0 )

在`OnIdle`中的渲染循环:
//clear surface
DDBLTFX bltfx;
ZeroMemory( &bltfx, sizeof(bltfx) );
bltfx.dwSize = sizeof( bltfx );
bltfx.dwFillColor = RGBtoPixel( r, g, b );
backsurf->Blt( rect, 0, 0, DDBLT_COLORFILL | DDBLT_WAIT, &bltfx )

//blit some prerendered surface onto it, x/y/rect etc are calculated properly)
backsurf->BltFast( x, y, sourceSurf, s&sourceRect, DDBLTFAST_WAIT );

primsurf->Flip( 0, DDFLIP_WAIT )

primsurf->Blt(&drect,backsurf,&srect,DDBLT_WAIT,0);

2
很可能是驱动程序问题 - 更新的显卡/驱动程序使用DX9/10来模拟DX7,这可能导致延迟。 - Roger Rowland
你确定不是外部触发的处理导致了延迟,而不是DX?触发器是什么,如何处理? - huysentruitw
@Rushyo 锁定什么?你想要具体看哪段代码?就像我说的那样,它基本上只是创建一个DIRECTDRAW7和几个DIRECTDRAWSURFACE7,用像素填充它们,并在主表面上调用Flip()(这是我从一次小研究中得到的结果,它是一个庞大的代码库,不是我的)。 - stijn
@stijn 我想要看到那段代码的确切内容。Blt调用,Flip以及与它们密切相关的任何内容(例如锁定)。 - Rushyo
1
@Rushyo 看一下编辑...我花了将近一个小时来提取这个,这已经是一个很明显的迹象,我们最好从头开始重写。 - stijn
显示剩余12条评论
1个回答

3
我认为Windows XP的问题是一个红鲱鱼。最后一个支持直接运行DirectX 7的Windows版本是Windows 2000。Windows XP只是在DX9中模拟DX7,就像Windows 7一样。
我猜测你的应用程序使用调色板纹理,并且当DX模拟该功能(因为它在DX7之后被删除)时,它会使用索引颜色生成纹理。您可以尝试使用GPUView对应用程序进行分析,以查看将纹理推送到GPU是否有延迟。例如,Win7驱动程序是否首先对其进行了压缩?

我们不使用调色板纹理或任何其他特殊的DX功能:一切都直接按像素写入表面内存。但感谢您提到GPUView,我不知道它,但它似乎非常有趣。 - stijn
@stijn 你正在运行任何着色器吗? - Justin R.
不,我目前没有代码,但据我所知,渲染循环只是在表面上设置一些像素,将表面混合到后备缓冲表面上并调用Flip()。 - stijn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接