WM模拟器上DirectDraw的BackBuffer问题解决方法

上次在参考研究mobile sdk 6.0中自带的DDraw例子时发现在模拟器上跑到创建后备缓冲时由于不支持DDSCAPS_BACKBUFFER而导致程序不能运行,google了一通发现m$网站和其他一些论坛上也有人问过类似问题,得到的答案貌似是说emlator上不能跑DDraw和D3D的程序,要测只能用device,其实只要自己实现一个创建后备缓冲以及用blit模拟flip的方式就可以在模拟器上跑了,并不是模拟器根本就没有实现DDraw,只是没有实现硬件后备缓冲、翻转等操作(其实在现在的PC模拟器上的这2种方式应该也没有什么效率上的差异吧)。
具体代码:

//************************************
// Method:    InitDDraw 初始化DDraw
// FullName:  InitDDraw
// Access:    public 
// Returns:   BOOL
// Qualifier:
// Parameter: void
//************************************
BOOL InitDDraw( void )
{
	DDSURFACEDESC ddsd;
	HRESULT hRet;
	DDCAPS ddCaps;
	DDCAPS ddHelCaps;
	// DDraw对象
	hRet = DirectDrawCreate(NULL, &g_pDD, NULL);
	if (hRet != DD_OK)
	{
		InitFail(g_hGameWnd,hRet,_T("DDraw failed to create!"));
		return FALSE;
	}
	// 全屏排他模式
	hRet = g_pDD->SetCooperativeLevel(g_hGameWnd, DDSCL_FULLSCREEN);
	if (hRet != DD_OK)
	{
		InitFail(g_hGameWnd,hRet,_T("Failed to set cooperative level!"));
		return FALSE;
	}
	// 取DDraw可用能力
	g_pDD->GetCaps(&ddCaps, &ddHelCaps);
	// flip和backbuffer有1个不支持就启用单缓冲模式
	if (!(ddCaps.ddsCaps.dwCaps & DDSCAPS_BACKBUFFER) || !(ddCaps.ddsCaps.dwCaps & DDSCAPS_FLIP)) 
	{
		// 单缓冲模式
		g_bSingleBuffer = TRUE;
	}
	// 显示模式设置
	memset(&ddsd, 0, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);

	hRet = g_pDD->GetDisplayMode(&ddsd);

	if(hRet != DD_OK)
	{
		InitFail(g_hGameWnd,hRet,_T("GetDisplayMode Failed!"));
		return FALSE;
	}

	g_dwScreenX = ddsd.dwWidth;
	g_dwScreenY = ddsd.dwHeight;
	g_dwScreenBpp = ddsd.ddpfPixelFormat.dwRGBBitCount;

	// color key 硬件能力
	g_dwTransType = DDBLT_KEYSRC;
	ddCaps.dwSize = sizeof(ddCaps);
	if(g_bSingleBuffer)
	{
		ddsd.dwFlags = DDSD_CAPS;
		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
	}
	else
	{
		ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT;
		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP;
		ddsd.dwBackBufferCount = 1;
	}
	// 主缓冲创建
	hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL);

	if (hRet != DD_OK)
	{
		if (hRet = DDERR_NOFLIPHW)
		{
			InitFail(g_hGameWnd,hRet,_T("******** Display driver doesn't support flipping surfaces. ********"));
			return FALSE;
		}
		InitFail(g_hGameWnd,hRet,_T("CreateSurface FrontBuffer Failed!"));
		return FALSE;
	}

	if (g_bSingleBuffer)
	{
		ddsd.dwFlags = DDSD_WIDTH|DDSD_HEIGHT;
		ddsd.dwWidth = g_dwScreenX;
		ddsd.dwHeight = g_dwScreenY;
		hRet = g_pDD->CreateSurface(&ddsd,&g_pDDSBack,NULL);
		if(hRet != DD_OK)
		{
			InitFail(g_hGameWnd,hRet,_T("BackBuffer failed to create!"));
			return FALSE;
		}
	}
	else
	{
		// Get a pointer to the back buffer
		hRet = g_pDDSPrimary->EnumAttachedSurfaces(&g_pDDSBack, EnumFunction);
		if (hRet != DD_OK)
		{
			InitFail(g_hGameWnd,hRet,_T("EnumAttachedSurfaces Failed!"));
			return FALSE;
		}
	}
	return TRUE;
}

在绘图循环的时候这样处理flip:

			HRESULT ddrval;
			RECT src, dest;

			src.left = 0;
			src.top = 0;
			src.right = g_dwScreenX;
			src.bottom = g_dwScreenY;

			dest.left = 0;
			dest.top  = 0;
			dest.right = g_dwScreenX;
			dest.bottom = g_dwScreenY;

			// Flip the surfaces
			while( 1 )
			{
				if (g_bSingleBuffer)
				{
					//copy back buffer to front.
					ddrval = g_pDDSPrimary->Blt(&dest, g_pDDSBack, &src, DDBLT_WAITNOTBUSY, NULL );
				}
				else 
				{
					ddrval = g_pDDSPrimary->Flip(NULL, 0);
				}

				if( ddrval == DD_OK )
				{
					break;
				}
				if( ddrval == DDERR_SURFACELOST )
				{
					if( !RestoreSurfaces() )
					{
						return 0;
					}
				}
				if( ddrval != DDERR_WASSTILLDRAWING )
				{
					break;
				}
			}

博主友情提示:

如在您的评论中需要提及如QQ号、微信号、电子邮件地址或其他隐私敏感信息,欢迎通过>>博主专用加密工具v2<<加密后发布,原文只有博主可以看到。