上次在参考研究mobile sdk 6.0中自带的DDraw例子时发现在模拟器上跑到创建后备缓冲时由于不支持DDSCAPS_BACKBUFFER而导致程序不能运行,google了一通发现m$网站和其他一些论坛上也有人问过类似问题,得到的答案貌似是说emlator上不能跑DDraw和D3D的程序,要测只能用device,其实只要自己实现一个创建后备缓冲以及用blit模拟flip的方式就可以在模拟器上跑了,并不是模拟器根本就没有实现DDraw,只是没有实现硬件后备缓冲、翻转等操作(其实在现在的PC模拟器上的这2种方式应该也没有什么效率上的差异吧)。
具体代码:
1 //************************************
2 // Method: InitDDraw 初始化DDraw
3 // FullName: InitDDraw
4 // Access: public
5 // Returns: BOOL
6 // Qualifier:
7 // Parameter: void
8 //************************************
9 BOOL InitDDraw( void )
10 {
11 DDSURFACEDESC ddsd;
12 HRESULT hRet;
13 DDCAPS ddCaps;
14 DDCAPS ddHelCaps;
15 // DDraw对象
16 hRet = DirectDrawCreate(NULL, &g_pDD, NULL);
17 if (hRet != DD_OK)
18 {
19 InitFail(g_hGameWnd,hRet,_T("DDraw failed to create!"));
20 return FALSE;
21 }
22 // 全屏排他模式
23 hRet = g_pDD->SetCooperativeLevel(g_hGameWnd, DDSCL_FULLSCREEN);
24 if (hRet != DD_OK)
25 {
26 InitFail(g_hGameWnd,hRet,_T("Failed to set cooperative level!"));
27 return FALSE;
28 }
29 // 取DDraw可用能力
30 g_pDD->GetCaps(&ddCaps, &ddHelCaps);
31 // flip和backbuffer有1个不支持就启用单缓冲模式
32 if (!(ddCaps.ddsCaps.dwCaps & DDSCAPS_BACKBUFFER) || !(ddCaps.ddsCaps.dwCaps & DDSCAPS_FLIP))
33 {
34 // 单缓冲模式
35 g_bSingleBuffer = TRUE;
36 }
37 // 显示模式设置
38 memset(&ddsd, 0, sizeof(ddsd));
39 ddsd.dwSize = sizeof(ddsd);
40
41 hRet = g_pDD->GetDisplayMode(&ddsd);
42
43 if(hRet != DD_OK)
44 {
45 InitFail(g_hGameWnd,hRet,_T("GetDisplayMode Failed!"));
46 return FALSE;
47 }
48
49 g_dwScreenX = ddsd.dwWidth;
50 g_dwScreenY = ddsd.dwHeight;
51 g_dwScreenBpp = ddsd.ddpfPixelFormat.dwRGBBitCount;
52
53 // color key 硬件能力
54 g_dwTransType = DDBLT_KEYSRC;
55 ddCaps.dwSize = sizeof(ddCaps);
56 if(g_bSingleBuffer)
57 {
58 ddsd.dwFlags = DDSD_CAPS;
59 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
60 }
61 else
62 {
63 ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT;
64 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP;
65 ddsd.dwBackBufferCount = 1;
66 }
67 // 主缓冲创建
68 hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL);
69
70 if (hRet != DD_OK)
71 {
72 if (hRet = DDERR_NOFLIPHW)
73 {
74 InitFail(g_hGameWnd,hRet,_T("******** Display driver doesn't support flipping surfaces. ********"));
75 return FALSE;
76 }
77 InitFail(g_hGameWnd,hRet,_T("CreateSurface FrontBuffer Failed!"));
78 return FALSE;
79 }
80
81 if (g_bSingleBuffer)
82 {
83 ddsd.dwFlags = DDSD_WIDTH|DDSD_HEIGHT;
84 ddsd.dwWidth = g_dwScreenX;
85 ddsd.dwHeight = g_dwScreenY;
86 hRet = g_pDD->CreateSurface(&ddsd,&g_pDDSBack,NULL);
87 if(hRet != DD_OK)
88 {
89 InitFail(g_hGameWnd,hRet,_T("BackBuffer failed to create!"));
90 return FALSE;
91 }
92 }
93 else
94 {
95 // Get a pointer to the back buffer
96 hRet = g_pDDSPrimary->EnumAttachedSurfaces(&g_pDDSBack, EnumFunction);
97 if (hRet != DD_OK)
98 {
99 InitFail(g_hGameWnd,hRet,_T("EnumAttachedSurfaces Failed!"));
100 return FALSE;
101 }
102 }
103 return TRUE;
104 }
在绘图循环的时候这样处理flip:
1 HRESULT ddrval;
2 RECT src, dest;
3
4 src.left = 0;
5 src.top = 0;
6 src.right = g_dwScreenX;
7 src.bottom = g_dwScreenY;
8
9 dest.left = 0;
10 dest.top = 0;
11 dest.right = g_dwScreenX;
12 dest.bottom = g_dwScreenY;
13
14 // Flip the surfaces
15 while( 1 )
16 {
17 if (g_bSingleBuffer)
18 {
19 //copy back buffer to front.
20 ddrval = g_pDDSPrimary->Blt(&dest, g_pDDSBack, &src, DDBLT_WAITNOTBUSY, NULL );
21 }
22 else
23 {
24 ddrval = g_pDDSPrimary->Flip(NULL, 0);
25 }
26
27 if( ddrval == DD_OK )
28 {
29 break;
30 }
31 if( ddrval == DDERR_SURFACELOST )
32 {
33 if( !RestoreSurfaces() )
34 {
35 return 0;
36 }
37 }
38 if( ddrval != DDERR_WASSTILLDRAWING )
39 {
40 break;
41 }
42 }