- rewrite DirectDraw implementation (now it correctly works in Win7 HW mode);
This commit is contained in:
mtabachenko 2009-12-23 13:45:09 +00:00
parent a9d76cb8c5
commit c762cdf95d
1 changed files with 192 additions and 146 deletions

View File

@ -199,13 +199,41 @@ Lock::Lock() : m_cs(&win_execute_sync) { EnterCriticalSection(m_cs); }
Lock::Lock(CRITICAL_SECTION& cs) : m_cs(&cs) { EnterCriticalSection(m_cs); }
Lock::~Lock() { LeaveCriticalSection(m_cs); }
//===================== DirectDraw vars
LPDIRECTDRAW7 lpDDraw=NULL;
LPDIRECTDRAWSURFACE7 lpPrimarySurface=NULL;
LPDIRECTDRAWSURFACE7 lpBackSurface=NULL;
DDSURFACEDESC2 ddsd;
LPDIRECTDRAWCLIPPER lpDDClipPrimary=NULL;
LPDIRECTDRAWCLIPPER lpDDClipBack=NULL;
//====================== DirectDraw
const char *DDerrors[] = { "no errors",
"Unable to initialize DirectDraw",
"Unable to set DirectDraw Cooperative Level",
"Unable to create DirectDraw primary surface",
"Unable to set DirectDraw clipper"};
struct DDRAW
{
DDRAW():
handle(NULL), clip(NULL)
{
surface.primary = NULL;
surface.back = NULL;
memset(&surfDesc, 0, sizeof(surfDesc));
memset(&surfDescBack, 0, sizeof(surfDescBack));
}
u32 create(HWND hwnd);
bool release();
bool createSurfaces(HWND hwnd);
bool lock();
bool unlock();
bool blt(LPRECT dst, LPRECT src);
LPDIRECTDRAW7 handle;
struct
{
LPDIRECTDRAWSURFACE7 primary;
LPDIRECTDRAWSURFACE7 back;
} surface;
DDSURFACEDESC2 surfDesc;
DDSURFACEDESC2 surfDescBack;
LPDIRECTDRAWCLIPPER clip;
} ddraw;
//===================== Input vars
#define WM_CUSTKEYDOWN (WM_USER+50)
@ -800,42 +828,6 @@ static void PopulateLuaSubmenu()
}
}
int CreateDDrawBuffers()
{
Lock lock (win_backbuffer_sync);
if (lpDDClipPrimary!=NULL) { IDirectDraw7_Release(lpDDClipPrimary); lpDDClipPrimary = NULL; }
if (lpPrimarySurface != NULL) { IDirectDraw7_Release(lpPrimarySurface); lpPrimarySurface = NULL; }
if (lpBackSurface != NULL) { IDirectDraw7_Release(lpBackSurface); lpBackSurface = NULL; }
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
ddsd.dwFlags = DDSD_CAPS;
if (IDirectDraw7_CreateSurface(lpDDraw, &ddsd, &lpPrimarySurface, NULL) != DD_OK) return -1;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
if(GetStyle()&DWS_DDRAW_SW) ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
ddsd.dwWidth = video.rotatedwidth();
ddsd.dwHeight = video.rotatedheight();
if (IDirectDraw7_CreateSurface(lpDDraw, &ddsd, &lpBackSurface, NULL) != DD_OK) return -2;
if (IDirectDraw7_CreateClipper(lpDDraw, 0, &lpDDClipPrimary, NULL) != DD_OK) return -3;
if (IDirectDrawClipper_SetHWnd(lpDDClipPrimary, 0, MainWindow->getHWnd()) != DD_OK) return -4;
if (IDirectDrawSurface7_SetClipper(lpPrimarySurface, lpDDClipPrimary) != DD_OK) return -5;
backbuffer_invalidate = false;
return 1;
}
template<typename T> static void doRotate(void* dst)
{
u8* buffer = (u8*)dst;
@ -843,7 +835,8 @@ template<typename T> static void doRotate(void* dst)
u32* src = (u32*)video.finalBuffer();
int width = video.width;
int height = video.height;
int pitch = ddsd.lPitch;
int pitch = ddraw.surfDescBack.lPitch;
switch(video.rotation)
{
case 0:
@ -1286,62 +1279,32 @@ static void DD_FillRect(LPDIRECTDRAWSURFACE7 surf, int left, int top, int right,
//the directdraw final presentation portion of display, including rotating
static void DD_DoDisplay()
{
if(backbuffer_invalidate)
goto CREATE;
if (!ddraw.lock()) return;
char* buffer = (char*)ddraw.surfDescBack.lpSurface;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags=DDSD_ALL;
int res = lpBackSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if(FAILED(res))
switch(ddraw.surfDescBack.ddpfPixelFormat.dwRGBBitCount)
{
if (res==DDERR_SURFACELOST)
{
LOG("DirectDraw buffers is lost\n");
if (FAILED(IDirectDrawSurface7_Restore(lpPrimarySurface))
|| FAILED(IDirectDrawSurface7_Restore(lpBackSurface)))
case 32:
doRotate<u32>(ddraw.surfDescBack.lpSurface);
break;
case 24:
doRotate<pix24>(ddraw.surfDescBack.lpSurface);
break;
case 16:
if(ddraw.surfDescBack.ddpfPixelFormat.dwGBitMask != 0x3E0)
doRotate<pix16>(ddraw.surfDescBack.lpSurface);
else
doRotate<pix15>(ddraw.surfDescBack.lpSurface);
break;
default:
{
CREATE:
CreateDDrawBuffers();
return;
if(ddraw.surfDescBack.ddpfPixelFormat.dwRGBBitCount != 0)
INFO("Unsupported color depth: %i bpp\n", ddraw.surfDescBack.ddpfPixelFormat.dwRGBBitCount);
//emu_halt();
}
}
else
return;
break;
}
//res = lpBackSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
//if(FAILED(res))
// return;
char* buffer = (char*)ddsd.lpSurface;
switch(ddsd.ddpfPixelFormat.dwRGBBitCount)
{
case 32:
doRotate<u32>(ddsd.lpSurface);
break;
case 24:
doRotate<pix24>(ddsd.lpSurface);
break;
case 16:
if(ddsd.ddpfPixelFormat.dwGBitMask != 0x3E0)
doRotate<pix16>(ddsd.lpSurface);
else
doRotate<pix15>(ddsd.lpSurface);
break;
default:
{
if(ddsd.ddpfPixelFormat.dwRGBBitCount != 0)
INFO("Unsupported color depth: %i bpp\n", ddsd.ddpfPixelFormat.dwRGBBitCount);
//emu_halt();
}
break;
}
lpBackSurface->Unlock((LPRECT)ddsd.lpSurface);
if (!ddraw.unlock()) return;
RECT* dstRects [2] = {&MainScreenRect, &SubScreenRect};
RECT* srcRects [2];
@ -1385,14 +1348,14 @@ static void DD_DoDisplay()
int bottom = r.bottom;
//printf("%d %d %d %d / %d %d %d %d\n",fullScreen.left,fullScreen.top,fullScreen.right,fullScreen.bottom,left,top,right,bottom);
//printf("%d %d %d %d / %d %d %d %d\n",MainScreenRect.left,MainScreenRect.top,MainScreenRect.right,MainScreenRect.bottom,SubScreenRect.left,SubScreenRect.top,SubScreenRect.right,SubScreenRect.bottom);
DD_FillRect(lpPrimarySurface,0,0,left,top,RGB(255,0,0)); //topleft
DD_FillRect(lpPrimarySurface,left,0,right,top,RGB(128,0,0)); //topcenter
DD_FillRect(lpPrimarySurface,right,0,fullScreen.right,top,RGB(0,255,0)); //topright
DD_FillRect(lpPrimarySurface,0,top,left,bottom,RGB(0,128,0)); //left
DD_FillRect(lpPrimarySurface,right,top,fullScreen.right,bottom,RGB(0,0,255)); //right
DD_FillRect(lpPrimarySurface,0,bottom,left,fullScreen.bottom,RGB(0,0,128)); //bottomleft
DD_FillRect(lpPrimarySurface,left,bottom,right,fullScreen.bottom,RGB(255,0,255)); //bottomcenter
DD_FillRect(lpPrimarySurface,right,bottom,fullScreen.left,fullScreen.bottom,RGB(0,255,255)); //bottomright
DD_FillRect(ddraw.surface.primary,0,0,left,top,RGB(255,0,0)); //topleft
DD_FillRect(ddraw.surface.primary,left,0,right,top,RGB(128,0,0)); //topcenter
DD_FillRect(ddraw.surface.primary,right,0,fullScreen.right,top,RGB(0,255,0)); //topright
DD_FillRect(ddraw.surface.primary,0,top,left,bottom,RGB(0,128,0)); //left
DD_FillRect(ddraw.surface.primary,right,top,fullScreen.right,bottom,RGB(0,0,255)); //right
DD_FillRect(ddraw.surface.primary,0,bottom,left,fullScreen.bottom,RGB(0,0,128)); //bottomleft
DD_FillRect(ddraw.surface.primary,left,bottom,right,fullScreen.bottom,RGB(255,0,255)); //bottomcenter
DD_FillRect(ddraw.surface.primary,right,bottom,fullScreen.left,fullScreen.bottom,RGB(0,255,255)); //bottomright
}
for(int i = 0; i < 2; i++)
@ -1400,12 +1363,7 @@ static void DD_DoDisplay()
if(i && video.layout == 2)
break;
if(lpPrimarySurface->Blt(dstRects[i], lpBackSurface, srcRects[i], DDBLT_WAIT, 0) == DDERR_SURFACELOST)
{
LOG("DirectDraw buffers is lost\n");
if(IDirectDrawSurface7_Restore(lpPrimarySurface) == DD_OK)
IDirectDrawSurface7_Restore(lpBackSurface);
}
if (!ddraw.blt(dstRects[i], srcRects[i])) return;
}
if (video.layout == 1) return;
@ -1859,21 +1817,11 @@ DWORD WINAPI run()
osd->setRotate(video.rotation);
//doLCDsLayout();
if (DirectDrawCreateEx(NULL, (LPVOID*)&lpDDraw, IID_IDirectDraw7, NULL) != DD_OK)
{
MessageBox(hwnd,"Unable to initialize DirectDraw","Error",MB_OK);
return -1;
}
if (IDirectDraw7_SetCooperativeLevel(lpDDraw,hwnd, DDSCL_NORMAL) != DD_OK)
u32 res = ddraw.create(hwnd);
if (res != 0)
{
MessageBox(hwnd,"Unable to set DirectDraw Cooperative Level","Error",MB_OK);
return -1;
}
if (CreateDDrawBuffers()<1)
{
MessageBox(hwnd,"Unable to set DirectDraw buffers","Error",MB_OK);
MessageBox(hwnd,DDerrors[res],EMU_DESMUME_NAME_AND_VERSION(),MB_OK | MB_ICONERROR);
return -1;
}
@ -2816,10 +2764,7 @@ int _main()
delete MainWindow;
if (lpDDClipPrimary!=NULL) IDirectDraw7_Release(lpDDClipPrimary);
if (lpPrimarySurface != NULL) IDirectDraw7_Release(lpPrimarySurface);
if (lpBackSurface != NULL) IDirectDraw7_Release(lpBackSurface);
if (lpDDraw != NULL) IDirectDraw7_Release(lpDDraw);
ddraw.release();
UnregWndClass("DeSmuME");
@ -3012,22 +2957,6 @@ void SetRotate(HWND hwnd, int rot, bool user)
MainWindowToolbar->ChangeButtonID(6, ccwid);
MainWindowToolbar->ChangeButtonID(7, cwid);
/* Recreate the DirectDraw back buffer */
if (lpBackSurface!=NULL)
{
IDirectDrawSurface7_Release(lpBackSurface);
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
if(GetStyle()&DWS_DDRAW_SW) ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
ddsd.dwWidth = video.rotatedwidth();
ddsd.dwHeight = video.rotatedheight();
IDirectDraw7_CreateSurface(lpDDraw, &ddsd, &lpBackSurface, NULL);
}
WritePrivateProfileInt("Video","Window Rotate",video.rotation,IniName);
if(user)
{
@ -3185,7 +3114,7 @@ static BOOL OpenCore(const char* filename)
{
romloaded = TRUE;
if(movieMode == MOVIEMODE_INACTIVE)
Unpause();
Unpause();
// Update the toolbar
MainWindowToolbar->EnableButton(IDM_PAUSE, true);
@ -5061,7 +4990,7 @@ DOKEYDOWN:
Lock lock (win_backbuffer_sync);
SetStyle(GetStyle()&~DWS_DDRAW_SW);
WritePrivateProfileInt("Video","Display Method", DISPMETHOD_DDRAW_HW, IniName);
backbuffer_invalidate = true;
ddraw.createSurfaces(hwnd);
}
break;
@ -5070,7 +4999,7 @@ DOKEYDOWN:
Lock lock (win_backbuffer_sync);
SetStyle(GetStyle()|DWS_DDRAW_SW);
WritePrivateProfileInt("Video","Display Method", DISPMETHOD_DDRAW_SW, IniName);
backbuffer_invalidate = true;
ddraw.createSurfaces(hwnd);
}
break;
@ -6203,4 +6132,121 @@ void WIN_InstallCFlash()
CFlash_Mode = ADDON_CFLASH_MODE_RomPath;
}
}
}
// ================================================================= DDraw
u32 DDRAW::create(HWND hwnd)
{
if (handle) return 0;
if (FAILED(DirectDrawCreateEx(NULL, (LPVOID*)&handle, IID_IDirectDraw7, NULL)))
return 1;
if (FAILED(handle->SetCooperativeLevel(hwnd, DDSCL_NORMAL)))
return 2;
createSurfaces(hwnd);
return 0;
}
bool DDRAW::release()
{
if (!handle) return true;
if (clip !=NULL)
clip->Release();
if (surface.primary != NULL)
surface.primary->Release();
if (FAILED(handle->Release())) return false;
return true;
}
bool DDRAW::createSurfaces(HWND hwnd)
{
if (!handle) return true;
if (clip) clip->Release();
if (surface.back) surface.back->Release();
if (surface.primary) surface.primary->Release();
// primary
memset(&surfDesc, 0, sizeof(surfDesc));
surfDesc.dwSize = sizeof(surfDesc);
surfDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
surfDesc.dwFlags = DDSD_CAPS;
if (FAILED(handle->CreateSurface(&surfDesc, &surface.primary, NULL)))
return false;
memset(&surfDescBack, 0, sizeof(surfDescBack));
surfDescBack.dwSize = sizeof(surfDescBack);
surfDescBack.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
surfDescBack.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
if(GetStyle()&DWS_DDRAW_SW)
surfDescBack.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
else
surfDescBack.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
surfDescBack.dwWidth = 384;
surfDescBack.dwHeight = 384;
if (FAILED(handle->CreateSurface(&surfDescBack, &surface.back, NULL))) return false;
if (FAILED(handle->CreateClipper(0, &clip, NULL))) return false;
if (FAILED(clip->SetHWnd(0, hwnd))) return false;
if (FAILED(surface.primary->SetClipper(clip))) return false;
backbuffer_invalidate = false;
return true;
}
bool DDRAW::lock()
{
if (!handle) return true;
if (!surface.back) return false;
memset(&surfDescBack, 0, sizeof(surfDescBack));
surfDescBack.dwSize = sizeof(surfDescBack);
surfDescBack.dwFlags = DDSD_ALL;
HRESULT res = surface.back->Lock(NULL, &surfDescBack, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if (FAILED(res))
{
//INFO("DDraw failed: Lock %i\n", res);
if (res == DDERR_SURFACELOST)
{
res = surface.back->Restore();
if (FAILED(res)) return false;
}
}
return true;
}
bool DDRAW::unlock()
{
if (!handle) return true;
if (!surface.back) return false;
if (FAILED(surface.back->Unlock((LPRECT)surfDescBack.lpSurface))) return false;
return true;
}
bool DDRAW::blt(LPRECT dst, LPRECT src)
{
if (!handle) return true;
if (!surface.primary) return false;
if (!surface.back) return false;
HRESULT res = surface.primary->Blt(dst, surface.back, src, DDBLT_WAIT, 0);
if (FAILED(res))
{
//INFO("DDraw failed: Blt %i\n", res);
if (res == DDERR_SURFACELOST)
{
res = surface.primary->Restore();
if (FAILED(res)) return false;
}
}
return true;
}