#define _CRT_SECURE_NO_WARNINGS #define INITGUID //#define FULLHEXDUMP #include #include #include "dxwnd.h" #include "dxhook.h" #include "ddrawi.h" #include "dxwcore.hpp" #include "stdio.h" #include "hddraw.h" #include "dxhelper.h" #include "syslibs.h" #define MAXBACKBUFFERS 4 extern void SetPixFmt(LPDDSURFACEDESC2); extern void GetPixFmt(LPDDSURFACEDESC2); extern CHAR *LogSurfaceAttributes(LPDDSURFACEDESC2, char *, int); extern void DumpPixFmt(LPDDSURFACEDESC2); extern void DescribeSurface(LPDIRECTDRAWSURFACE, int, char *, int); extern void HookDDSurface(LPDIRECTDRAWSURFACE *, int, BOOL); extern void RegisterPixelFormat(int, LPDIRECTDRAWSURFACE); extern void SetVSyncDelays(int, LPDIRECTDRAW); extern char *DumpPixelFormat(LPDDSURFACEDESC2); extern void FixSurfaceCaps(LPDDSURFACEDESC2, int); extern SetPalette_Type pSetPaletteMethod(int); extern ReleaseS_Type pReleaseSMethod(int); extern CreatePalette_Type pCreatePaletteMethod(int); extern GetGDISurface_Type pGetGDISurfaceMethod(int); extern int iBakBufferVersion; extern LPDIRECTDRAWSURFACE lpDDSEmu_Prim; extern LPDIRECTDRAWSURFACE lpDDSEmu_Back; extern LPDIRECTDRAWSURFACE lpDDZBuffer; extern DDSURFACEDESC2 DDSD_Prim; extern LPDIRECTDRAWPALETTE lpDDP; extern LPDIRECTDRAWCLIPPER lpddC; extern LPDIRECTDRAW lpPrimaryDD; extern int iDDPExtraRefCounter; extern DWORD dwBackBufferCaps; extern BOOL bFlippedDC; extern PALETTEENTRY DefaultSystemPalette[]; extern GetGDISurface_Type pGetGDISurface1, pGetGDISurface2, pGetGDISurface3, pGetGDISurface4, pGetGDISurface7; extern GetAttachedSurface_Type pGetAttachedSurface1, pGetAttachedSurface2, pGetAttachedSurface3, pGetAttachedSurface4, pGetAttachedSurface7; extern CreateSurface1_Type pCreateSurface1, pCreateSurface2, pCreateSurface3, pCreateSurface4, pCreateSurface7; extern ReleaseS_Type pReleaseS1, pReleaseS2, pReleaseS3, pReleaseS4, pReleaseS7; extern GetPixelFormat_Type pGetPixelFormat1, pGetPixelFormat2, pGetPixelFormat3, pGetPixelFormat4, pGetPixelFormat7; void InitDSScreenParameters(int dxversion, LPDIRECTDRAWSURFACE lpdds) { HRESULT res; DDPIXELFORMAT p; DDSURFACEDESC2 ddsd; GetPixelFormat_Type pGetPixelFormat; switch(dxversion){ case 1: pGetPixelFormat=pGetPixelFormat1; break; case 2: pGetPixelFormat=pGetPixelFormat2; break; case 3: pGetPixelFormat=pGetPixelFormat3; break; case 4: pGetPixelFormat=pGetPixelFormat4; break; case 7: pGetPixelFormat=pGetPixelFormat7; break; } //OutTrace("dxversion=%d pGetPixelFormat=%x\n", dxversion, pGetPixelFormat); p.dwSize=sizeof(DDPIXELFORMAT); if(res=(*pGetPixelFormat)(lpdds, &p)){ OutTraceE("GetPixelFormat: ERROR res=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); return; } ddsd.ddpfPixelFormat = p; OutTraceDW("InitDSScreenParameters: version=%d Actual %s\n", dxversion, DumpPixelFormat(&ddsd)); dxw.ActualPixelFormat = p; SetBltTransformations(dxversion); return; } static void ClearSurfaceDesc(void *ddsd, int dxversion) { int size; size = (dxversion < 4) ? sizeof(DDSURFACEDESC) : sizeof(DDSURFACEDESC2); memset(ddsd, 0, size); // Clean all ((LPDDSURFACEDESC)ddsd)->dwSize = size; } static void BuildRealSurfaces(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurface, int dxversion) { HRESULT res; DDSURFACEDESC2 ddsd; OutTraceDW("BuildRealSurfaces: lpdd=%x pCreateSurface=%x version=%d\n", lpdd, pCreateSurface, dxversion); if(lpDDSEmu_Prim==NULL){ ClearSurfaceDesc((void *)&ddsd, dxversion); ddsd.dwFlags = DDSD_CAPS; // try DDSCAPS_SYSTEMMEMORY first, then suppress it if not supported // no, DDSCAPS_SYSTEMMEMORY cause screen flickering while moving the window (and other troubles?) ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; OutTraceDW("BuildRealSurfaces: %s\n", LogSurfaceAttributes(&ddsd, "[EmuPrim]", __LINE__)); res=(*pCreateSurface)(lpdd, &ddsd, &lpDDSEmu_Prim, 0); if(res==DDERR_PRIMARYSURFACEALREADYEXISTS){ OutTraceDW("BuildRealSurfaces: ASSERT DDSEmu_Prim already exists\n"); if(dxw.Windowize){ // in Windowize mode, the desktop properties are untouched, then the current primary surface can be recycled res=(*pGetGDISurfaceMethod(dxversion))(lpdd, &lpDDSEmu_Prim); } else { // in non-Windowized mode, the primary surface must be released and rebuilt with the proper properties res=(*pGetGDISurfaceMethod(dxversion))(lpdd, &lpDDSEmu_Prim); if (lpDDSEmu_Prim) while((*pReleaseSMethod(dxversion))(lpDDSEmu_Prim)); res=(*pCreateSurface)(lpdd, &ddsd, &lpDDSEmu_Prim, 0); } } if(res){ OutTraceE("BuildRealSurfaces: CreateSurface ERROR on DDSEmu_Prim res=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); if(res==DDERR_INVALIDPIXELFORMAT) DumpPixFmt(&ddsd); return; } OutTraceDW("BuildRealSurfaces: created new DDSEmu_Prim=%x\n",lpDDSEmu_Prim); if(IsDebug) DescribeSurface(lpDDSEmu_Prim, dxversion, "DDSEmu_Prim", __LINE__); InitDSScreenParameters(dxversion, lpDDSEmu_Prim); dxwss.PopSurface(lpDDSEmu_Prim); if (dxw.dwFlags3 & FORCECLIPPER){ OutTraceDW("BuildRealSurfaces: FORCE SetClipper on primary hwnd=%x lpdds=%x\n", dxw.GethWnd(), lpDDSEmu_Prim); res=lpdd->CreateClipper(0, &lpddC, NULL); if (res) OutTraceE("BuildRealSurfaces: CreateClipper ERROR res=%x(%s)\n", res, ExplainDDError(res)); res=lpddC->SetHWnd(0, dxw.GethWnd()); if (res) OutTraceE("BuildRealSurfaces: SetHWnd ERROR res=%x(%s)\n", res, ExplainDDError(res)); res=lpDDSEmu_Prim->SetClipper(lpddC); if (res) OutTraceE("BuildRealSurfaces: SetClipper ERROR res=%x(%s)\n", res, ExplainDDError(res)); } // can't hook lpDDSEmu_Prim as generic, since the Flip method is unimplemented for a PRIMARY surface! // better avoid it or hook just useful methods. //if (dxw.dwTFlags & OUTPROXYTRACE) HookDDSurfaceGeneric(&lpDDSEmu_Prim, dxw.dwDDVersion); } if(lpDDSEmu_Back==NULL){ ClearSurfaceDesc((void *)&ddsd, dxversion); ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; ddsd.ddsCaps.dwCaps = dwBackBufferCaps; ddsd.dwWidth = dxw.GetScreenWidth(); ddsd.dwHeight = dxw.GetScreenHeight(); if(dxw.dwFlags4 & BILINEAR2XFILTER){ // double backbuffer size ddsd.dwWidth = dxw.GetScreenWidth() << 1; ddsd.dwHeight = dxw.GetScreenHeight() << 1; } OutTraceDW("BuildRealSurfaces: %s\n", LogSurfaceAttributes(&ddsd, "[EmuBack]", __LINE__)); res=(*pCreateSurface)(lpdd, &ddsd, &lpDDSEmu_Back, 0); if(res) { ddsd.ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY; OutTraceDW("BuildRealSurfaces: %s\n", LogSurfaceAttributes(&ddsd, "[EmuBack]", __LINE__)); res=(*pCreateSurface)(lpdd, &ddsd, &lpDDSEmu_Back, 0); } if(res){ OutTraceE("BuildRealSurfaces: CreateSurface ERROR on DDSEmuBack : res=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); if(res==DDERR_INVALIDPIXELFORMAT) DumpPixFmt(&ddsd); return; } OutTraceDW("BuildRealSurfaces: created new DDSEmu_Back=%x\n", lpDDSEmu_Back); if(IsDebug) DescribeSurface(lpDDSEmu_Back, dxversion, "DDSEmu_Back", __LINE__); dxwss.PopSurface(lpDDSEmu_Back); //if (dxw.dwTFlags & OUTPROXYTRACE) HookDDSurfaceGeneric(&lpDDSEmu_Back, dxversion); } } void RestoreDDrawSurfaces() { // if it's a ddraw game .... if(lpPrimaryDD){ OutTraceDW("RestoreDDrawSurfaces: rebuilding surfaces for dd session %x\n", lpPrimaryDD); ReleaseS_Type pReleaseS; CreateSurface_Type pCreateSurface; switch(iBakBufferVersion){ case 1: pCreateSurface=(CreateSurface_Type)pCreateSurface1; pReleaseS=pReleaseS1; break; case 2: pCreateSurface=(CreateSurface_Type)pCreateSurface2; pReleaseS=pReleaseS2; break; case 3: pCreateSurface=(CreateSurface_Type)pCreateSurface3; pReleaseS=pReleaseS3; break; case 4: pCreateSurface=(CreateSurface_Type)pCreateSurface4; pReleaseS=pReleaseS4; break; case 7: pCreateSurface=(CreateSurface_Type)pCreateSurface7; pReleaseS=pReleaseS7; break; } if(lpDDSEmu_Back) while((*pReleaseS)(lpDDSEmu_Back)); lpDDSEmu_Back=0; if(lpDDSEmu_Prim) while((*pReleaseS)(lpDDSEmu_Prim)); lpDDSEmu_Prim=0; BuildRealSurfaces(lpPrimaryDD, pCreateSurface, iBakBufferVersion); } } static HRESULT BuildPrimaryEmu(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurface, LPDDSURFACEDESC2 lpddsd, int dxversion, LPDIRECTDRAWSURFACE *lplpdds, void *pu) { DDSURFACEDESC2 ddsd; HRESULT res; OutTraceDW("BuildPrimaryEmu: lpdd=%x pCreateSurface=%x lpddsd=%x version=%d\n", lpdd, pCreateSurface, lpddsd, dxversion); // emulated primary surface memcpy((void *)&ddsd, lpddsd, lpddsd->dwSize); // handle the surface attributes before the ddsd.dwFlags gets updated: // if a surface desc is NOT specified, build one if(!(ddsd.dwFlags & DDSD_PIXELFORMAT)) SetPixFmt((LPDDSURFACEDESC2)&ddsd); // then save it dxw.VirtualPixelFormat = ddsd.ddpfPixelFormat; OutTraceDW("BuildPrimaryEmu: DDSD_PIXELFORMAT color=%d flags=%x\n", dxw.VirtualPixelFormat.dwRGBBitCount, dxw.VirtualPixelFormat.dwFlags); ddsd.dwFlags &= ~(DDSD_BACKBUFFERCOUNT|DDSD_REFRESHRATE); ddsd.dwFlags |= (DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT); ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_COMPLEX|DDSCAPS_VIDEOMEMORY|DDSCAPS_LOCALVIDMEM); // DDSCAPS_OFFSCREENPLAIN seems required to support the palette in memory surfaces ddsd.ddsCaps.dwCaps |= (DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY); // on WinXP Fifa 99 doesn't like DDSCAPS_SYSTEMMEMORY cap, so better to leave a way to unset it.... if(dxw.dwFlags6 & NOSYSMEMPRIMARY) ddsd.ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY; ddsd.dwWidth = dxw.GetScreenWidth(); ddsd.dwHeight = dxw.GetScreenHeight(); // create Primary surface OutTraceDW("BuildPrimaryEmu: %s\n", LogSurfaceAttributes(&ddsd, "[Primary]" , __LINE__)); res=(*pCreateSurface)(lpdd, &ddsd, lplpdds, 0); if(res){ OutTraceE("BuildPrimaryEmu: CreateSurface ERROR on DDSPrim res=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); if(res==DDERR_INVALIDPIXELFORMAT) DumpPixFmt(&ddsd); return res; } iBakBufferVersion=dxversion; // v2.03.01 OutTraceDW("BuildPrimaryEmu: created PRIMARY DDSPrim=%x\n", *lplpdds); if(IsDebug) DescribeSurface(*lplpdds, dxversion, "DDSPrim", __LINE__); HookDDSurface(lplpdds, dxversion, TRUE); // "Hoyle Casino Empire" opens a primary surface and NOT a backbuffer .... // build a default System palette and apply it to primary surface if((ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) && (dxw.dwFlags6 & SYNCPALETTE)){ if(lpDDP == NULL){ res=(*pCreatePaletteMethod(dxversion))(lpdd, DDPCAPS_8BIT|DDPCAPS_ALLOW256, DefaultSystemPalette, &lpDDP, NULL); if(res) OutTrace("BuildPrimaryEmu: CreatePalette ERROR err=%x at %d\n", res, __LINE__); } // this must be done after hooking - who knows why? res=(*pSetPaletteMethod(dxversion))(*lplpdds, lpDDP); if(res) { OutTraceE("BuildPrimaryEmu: SetPalette ERROR err=%x at %d\n", res, __LINE__); } else iDDPExtraRefCounter++; } // set a global capability value for surfaces that have to blit to primary // DDSCAPS_OFFSCREENPLAIN seems required to support the palette in memory surfaces // DDSCAPS_SYSTEMMEMORY makes operations faster, but it is not always good... dwBackBufferCaps = (DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY); // on WinXP Fifa 99 doesn't like DDSCAPS_SYSTEMMEMORY cap, so better to leave a way to unset it.... // this is important to avoid that certain D3D operations will abort - see "Forsaken" problem if(dxw.dwFlags6 & NOSYSMEMBACKBUF) dwBackBufferCaps = DDSCAPS_OFFSCREENPLAIN; if(dxw.dwFlags6 & SHAREDDC) bFlippedDC = TRUE; if(dxw.dwFlags5 & GDIMODE) return DD_OK; BuildRealSurfaces(lpdd, pCreateSurface, dxversion); return DD_OK; } static HRESULT BuildPrimaryFlippable(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurface, LPDDSURFACEDESC2 lpddsd, int dxversion, LPDIRECTDRAWSURFACE *lplpdds, void *pu) { DDSURFACEDESC2 ddsd; HRESULT res; OutTraceDW("BuildPrimaryFlippable: lpdd=%x pCreateSurface=%x lpddsd=%x version=%d\n", lpdd, pCreateSurface, lpddsd, dxversion); // emulated primary surface memcpy((void *)&ddsd, lpddsd, lpddsd->dwSize); // handle the surface attributes before the ddsd.dwFlags gets updated: // if a surface desc is NOT specified, build one if(!(ddsd.dwFlags & DDSD_PIXELFORMAT)) SetPixFmt((LPDDSURFACEDESC2)&ddsd); // then save it dxw.VirtualPixelFormat = ddsd.ddpfPixelFormat; OutTraceDW("BuildPrimaryFlippable: DDSD_PIXELFORMAT color=%d flags=%x\n", dxw.VirtualPixelFormat.dwRGBBitCount, dxw.VirtualPixelFormat.dwFlags); // dwFlags ddsd.dwFlags &= ~(DDSD_REFRESHRATE); ddsd.dwFlags |= (DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT|DDSD_BACKBUFFERCOUNT); // DDSCAPS_OFFSCREENPLAIN seems required to support the palette in memory surfaces ddsd.ddsCaps.dwCaps |= (DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY); // dwBackBufferCount: set to at least 1 if(!(lpddsd->dwFlags & DDSD_BACKBUFFERCOUNT) || (lpddsd->dwBackBufferCount == 0)) ddsd.dwBackBufferCount = 1; // dwCaps ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_PRIMARYSURFACE|DDSCAPS_VIDEOMEMORY|DDSCAPS_LOCALVIDMEM|DDSCAPS_FRONTBUFFER); ddsd.ddsCaps.dwCaps |= (DDSCAPS_COMPLEX|DDSCAPS_FLIP|DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY); // on WinXP Fifa 99 doesn't like DDSCAPS_SYSTEMMEMORY cap, so better to leave a way to unset it.... if(dxw.dwFlags6 & NOSYSMEMPRIMARY) ddsd.ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY; // dwWidth & dwHeight ddsd.dwWidth = dxw.GetScreenWidth(); ddsd.dwHeight = dxw.GetScreenHeight(); // create Primary surface OutTraceDW("BuildPrimaryFlippable: %s\n", LogSurfaceAttributes(&ddsd, "[Primary]" , __LINE__)); res=(*pCreateSurface)(lpdd, &ddsd, lplpdds, 0); if(res){ OutTraceE("BuildPrimaryFlippable: CreateSurface ERROR on DDSPrim res=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); if(res==DDERR_INVALIDPIXELFORMAT) DumpPixFmt(&ddsd); return res; } iBakBufferVersion=dxversion; // v2.03.01 OutTraceDW("BuildPrimaryFlippable: created PRIMARY DDSPrim=%x\n", *lplpdds); if(IsDebug) DescribeSurface(*lplpdds, dxversion, "DDSPrim", __LINE__); HookDDSurface(lplpdds, dxversion, TRUE); // "Hoyle Casino Empire" opens a primary surface and NOT a backbuffer .... // build a default System palette and apply it to primary surface if((ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) && (dxw.dwFlags6 & SYNCPALETTE)){ if(lpDDP == NULL){ res=(*pCreatePaletteMethod(dxversion))(lpdd, DDPCAPS_8BIT|DDPCAPS_ALLOW256, DefaultSystemPalette, &lpDDP, NULL); if(res) OutTrace("BuildPrimaryFlippable: CreatePalette ERROR err=%x at %d\n", res, __LINE__); } // this must be done after hooking - who knows why? res=(*pSetPaletteMethod(dxversion))(*lplpdds, lpDDP); if(res) { OutTraceE("BuildPrimaryFlippable: SetPalette ERROR err=%x at %d\n", res, __LINE__); } else iDDPExtraRefCounter++; } // set a global capability value for surfaces that have to blit to primary dwBackBufferCaps = (DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY); // on WinXP Fifa 99 doesn't like DDSCAPS_SYSTEMMEMORY cap, so better to leave a way to unset it.... // this is important to avoid that certain D3D operations will abort - see "Forsaken" problem if(dxw.dwFlags6 & NOSYSMEMBACKBUF) dwBackBufferCaps = DDSCAPS_OFFSCREENPLAIN; if(dxw.dwFlags6 & SHAREDDC) bFlippedDC = TRUE; if(dxw.dwFlags5 & GDIMODE) return DD_OK; BuildRealSurfaces(lpdd, pCreateSurface, dxversion); return DD_OK; } static HRESULT BuildPrimaryFullscreen(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurface, LPDDSURFACEDESC2 lpddsd, int dxversion, LPDIRECTDRAWSURFACE *lplpdds, void *pu) { DDSURFACEDESC2 ddsd; HRESULT res; OutTraceDW("BuildPrimaryFullscreen: lpdd=%x pCreateSurface=%x lpddsd=%x version=%d\n", lpdd, pCreateSurface, lpddsd, dxversion); // genuine primary surface memcpy((void *)&ddsd, lpddsd, lpddsd->dwSize); // create Primary surface OutTraceDW("BuildPrimaryFullscreen: %s\n", LogSurfaceAttributes(&ddsd, "[Primary]", __LINE__)); res=(*pCreateSurface)(lpdd, &ddsd, lplpdds, 0); if(res){ if (res==DDERR_PRIMARYSURFACEALREADYEXISTS){ LPDIRECTDRAWSURFACE lpPrim; GetGDISurface_Type pGetGDISurface; pGetGDISurface = pGetGDISurfaceMethod(dxversion); OutTraceE("BuildPrimaryFullscreen: CreateSurface DDERR_PRIMARYSURFACEALREADYEXISTS workaround\n"); (*pGetGDISurface)(lpPrimaryDD, &lpPrim); while ((*pReleaseSMethod(dxversion))(lpPrim)); res = (*pCreateSurface)(lpdd, &ddsd, lplpdds, 0); } /* fall through */ if(res){ OutTraceE("BuildPrimaryFullscreen: CreateSurface ERROR on DDSPrim res=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); if(res==DDERR_INVALIDPIXELFORMAT) DumpPixFmt(&ddsd); return res; } } OutTraceDW("BuildPrimaryFullscreen: created PRIMARY DDSPrim=%x\n", *lplpdds); if(IsDebug) DescribeSurface(*lplpdds, dxversion, "DDSPrim", __LINE__); iBakBufferVersion=dxversion; HookDDSurface(lplpdds, dxversion, TRUE); if(dxw.dwFlags1 & CLIPCURSOR) dxw.SetClipCursor(); return DD_OK; } static HRESULT BuildPrimaryDir(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurface, LPDDSURFACEDESC2 lpddsd, int dxversion, LPDIRECTDRAWSURFACE *lplpdds, void *pu) { DDSURFACEDESC2 ddsd; HRESULT res; OutTraceDW("BuildPrimaryDir: lpdd=%x pCreateSurface=%x lpddsd=%x version=%d\n", lpdd, pCreateSurface, lpddsd, dxversion); // genuine primary surface memcpy((void *)&ddsd, lpddsd, lpddsd->dwSize); // v2.03.98 - when going to fullscreen mode and no emulation do not alter the capability masks, or in other words ... // if doing emulation or in window mode, fix the capability masks (De Morgan docet) ddsd.dwFlags &= ~(DDSD_WIDTH|DDSD_HEIGHT|DDSD_BACKBUFFERCOUNT|DDSD_REFRESHRATE|DDSD_PIXELFORMAT); ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_FLIP|DDSCAPS_COMPLEX); // v2.02.93: don't move primary / backbuf surfaces on systemmemory when 3DDEVICE is requested // this impact also on capabilities for temporary surfaces for AERO optimized handling // v2.04.08: this seems not always true, so it can be bypassed by ALLOWSYSMEMON3DDEV, just in case. // should be tested with "Tomb Raider 3" in no emulation mode if(!(dxw.dwFlags8 & ALLOWSYSMEMON3DDEV)){ if ((lpddsd->dwFlags & DDSD_CAPS) && (lpddsd->ddsCaps.dwCaps & DDSCAPS_3DDEVICE)) ddsd.ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY; } // create Primary surface OutTraceDW("BuildPrimaryDir: %s\n", LogSurfaceAttributes(&ddsd, "[Primary]", __LINE__)); res=(*pCreateSurface)(lpdd, &ddsd, lplpdds, 0); if(res){ if (res==DDERR_PRIMARYSURFACEALREADYEXISTS){ LPDIRECTDRAWSURFACE lpPrim; GetGDISurface_Type pGetGDISurface; pGetGDISurface = pGetGDISurfaceMethod(dxversion); OutTraceE("BuildPrimaryDir: CreateSurface DDERR_PRIMARYSURFACEALREADYEXISTS workaround\n"); (*pGetGDISurface)(lpPrimaryDD, &lpPrim); while ((*pReleaseSMethod(dxversion))(lpPrim)); res = (*pCreateSurface)(lpdd, &ddsd, lplpdds, 0); } /* fall through */ if(res){ OutTraceE("BuildPrimaryDir: CreateSurface ERROR on DDSPrim res=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); if(res==DDERR_INVALIDPIXELFORMAT) DumpPixFmt(&ddsd); return res; } } OutTraceDW("BuildPrimaryDir: created PRIMARY DDSPrim=%x\n", *lplpdds); if(IsDebug) DescribeSurface(*lplpdds, dxversion, "DDSPrim", __LINE__); if(dxw.dwFlags1 & EMULATEBUFFER){ lpDDSEmu_Prim = *lplpdds; dxwss.PopSurface(lpDDSEmu_Prim); ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; // warning: can't create zero sized backbuffer surface !!!! ddsd.dwWidth = dxw.GetScreenWidth(); ddsd.dwHeight = dxw.GetScreenHeight(); ddsd.ddsCaps.dwCaps = 0; if (dxversion >= 4) ddsd.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN; OutTraceDW("BuildPrimaryDir: %s\n", LogSurfaceAttributes(&ddsd, "[Dir FixBuf]", __LINE__)); res=(*pCreateSurface)(lpdd, &ddsd, lplpdds, 0); if(res){ OutTraceE("BuildPrimaryDir: CreateSurface ERROR on DDSPrim res=%x(%s) at %d\n",res, ExplainDDError(res), __LINE__); return res; } OutTraceDW("BuildPrimaryDir: created FIX DDSPrim=%x\n", *lplpdds); if(IsDebug) DescribeSurface(*lplpdds, dxversion, "DDSPrim(2)", __LINE__); } iBakBufferVersion=dxversion; // v2.03.37 HookDDSurface(lplpdds, dxversion, TRUE); if(dxw.dwFlags1 & CLIPCURSOR) dxw.SetClipCursor(); return DD_OK; } static HRESULT BuildBackBufferEmu(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurface, LPDDSURFACEDESC2 lpddsd, int dxversion, LPDIRECTDRAWSURFACE *lplpdds, void *pu) { DDSURFACEDESC2 ddsd; HRESULT res; OutTraceDW("BuildBackBufferEmu: lpdd=%x pCreateSurface=%x lpddsd=%x version=%d\n", lpdd, pCreateSurface, lpddsd, dxversion); // create BackBuffer surface memcpy(&ddsd, lpddsd, lpddsd->dwSize); ddsd.dwFlags &= ~(DDSD_BACKBUFFERCOUNT|DDSD_REFRESHRATE); ddsd.dwFlags |= (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT); ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_BACKBUFFER|DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_COMPLEX|DDSCAPS_VIDEOMEMORY|DDSCAPS_LOCALVIDMEM); // v2.03.75: if a surface desc is NOT specified, build one. This will allow ZBUF attach. if(!(lpddsd->dwFlags & DDSD_PIXELFORMAT)) SetPixFmt((LPDDSURFACEDESC2)&ddsd); // DDSCAPS_OFFSCREENPLAIN seems required to support the palette in memory surfaces ddsd.ddsCaps.dwCaps |= (DDSCAPS_SYSTEMMEMORY|DDSCAPS_OFFSCREENPLAIN); // necessary: Martian Gotic crashes otherwise // v2.04.08: this seems no longer true in some cases, so ALLOWSYSMEMON3DDEV will bypass it. // Should be tested with "Martian Gotic" and "Dominant Species" SW mode in emulation modes if(!(dxw.dwFlags8 & ALLOWSYSMEMON3DDEV)){ if((ddsd.dwFlags & DDSD_CAPS) && (ddsd.ddsCaps.dwCaps & DDSCAPS_3DDEVICE)) ddsd.ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY; } // on WinXP Fifa 99 doesn't like DDSCAPS_SYSTEMMEMORY cap, so better to leave a way to unset it.... if(dxw.dwFlags6 & NOSYSMEMBACKBUF) ddsd.ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY; ddsd.dwWidth = dxw.GetScreenWidth(); ddsd.dwHeight = dxw.GetScreenHeight(); GetPixFmt(&ddsd); OutTraceDW("BuildBackBufferEmu: %s\n", LogSurfaceAttributes(&ddsd, "[Backbuf]", __LINE__)); res=(*pCreateSurface)(lpdd, &ddsd, lplpdds, 0); if(res) { OutTraceE("BuildBackBufferEmu: CreateSurface ERROR res=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); if(res==DDERR_INVALIDPIXELFORMAT) DumpPixFmt(&ddsd); return res; } OutTraceDW("BuildBackBufferEmu: created BACK DDSBack=%x\n", *lplpdds); if(IsDebug) DescribeSurface(*lplpdds, dxversion, "DDSBack", __LINE__); HookDDSurface(lplpdds, dxversion, FALSE); // added !!! iBakBufferVersion=dxversion; // v2.02.31 if((ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) && (dxw.dwFlags6 & SYNCPALETTE)){ if(lpDDP == NULL){ res=(*pCreatePaletteMethod(dxversion))(lpdd, DDPCAPS_8BIT|DDPCAPS_ALLOW256, DefaultSystemPalette, &lpDDP, NULL); if(res) OutTrace("BuildBackBufferEmu: CreatePalette ERROR err=%x at %d\n", res, __LINE__); } // this must be done after hooking - who knows why? res=(*pSetPaletteMethod(dxversion))(*lplpdds, lpDDP); if(res) { OutTraceE("BuildBackBufferEmu: SetPalette ERROR err=%x at %d\n", res, __LINE__); } else iDDPExtraRefCounter++; } // V2.1.85/V2.2.34: tricky !!!! // When a real backbuffer is created, it has a reference to its frontbuffer. // some games (Monopoly 3D) may depend on this setting - i.e. they could close // the exceeding references - so this is better be replicated adding an initial // reference to the zero count. But you don't have to do this if the backbuffer // is created independently by the primary surface. (*lplpdds)->AddRef(); // should it be repeated BBCount times???? return DD_OK; } static HRESULT BuildBackBufferFlippable(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurface, LPDDSURFACEDESC2 lpddsd, int dxversion, LPDIRECTDRAWSURFACE *lplpdds, void *pu) { DDSURFACEDESC2 ddsd; HRESULT res; OutTraceDW("BuildBackBufferFlippable: lpdd=%x pCreateSurface=%x lpddsd=%x version=%d\n", lpdd, pCreateSurface, lpddsd, dxversion); //MessageBox(NULL, "BuildBackBufferFlippable", "DxWnd", MB_OK); // create BackBuffer surface memcpy(&ddsd, lpddsd, lpddsd->dwSize); ddsd.dwFlags &= ~(DDSD_BACKBUFFERCOUNT|DDSD_REFRESHRATE); ddsd.dwFlags |= (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT); ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_PRIMARYSURFACE|DDSCAPS_FRONTBUFFER|DDSCAPS_BACKBUFFER|DDSCAPS_VIDEOMEMORY|DDSCAPS_LOCALVIDMEM); ddsd.ddsCaps.dwCaps |= (DDSCAPS_SYSTEMMEMORY|DDSCAPS_OFFSCREENPLAIN); ddsd.dwWidth = dxw.GetScreenWidth(); ddsd.dwHeight = dxw.GetScreenHeight(); GetPixFmt(&ddsd); OutTraceDW("BuildBackBufferFlippable: %s\n", LogSurfaceAttributes(&ddsd, "[Backbuf]", __LINE__)); res=(*pCreateSurface)(lpdd, &ddsd, lplpdds, 0); if(res) { OutTraceE("BuildBackBufferFlippable: CreateSurface ERROR res=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); if(res==DDERR_INVALIDPIXELFORMAT) DumpPixFmt(&ddsd); return res; } OutTraceDW("BuildBackBufferFlippable: created BACK DDSBack=%x\n", *lplpdds); if(IsDebug) DescribeSurface(*lplpdds, dxversion, "DDSBack", __LINE__); HookDDSurface(lplpdds, dxversion, FALSE); // added !!! iBakBufferVersion=dxversion; // v2.02.31 if((ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) && (dxw.dwFlags6 & SYNCPALETTE)){ if(lpDDP == NULL){ res=(*pCreatePaletteMethod(dxversion))(lpdd, DDPCAPS_8BIT|DDPCAPS_ALLOW256, DefaultSystemPalette, &lpDDP, NULL); if(res) OutTrace("BuildBackBufferFlippable: CreatePalette ERROR err=%x at %d\n", res, __LINE__); } // this must be done after hooking - who knows why? res=(*pSetPaletteMethod(dxversion))(*lplpdds, lpDDP); if(res) { OutTraceE("BuildBackBufferFlippable: SetPalette ERROR err=%x at %d\n", res, __LINE__); } else iDDPExtraRefCounter++; } return DD_OK; } static HRESULT AttachBackBufferFlippable(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurface, LPDDSURFACEDESC2 lpddsd, int dxversion, LPDIRECTDRAWSURFACE *lplpdds, void *pu) { HRESULT res; LPDIRECTDRAWSURFACE lpDDSPrim; OutTraceDW("AttachBackBufferFlippable: lpdd=%x pCreateSurface=%x lpddsd=%x version=%d\n", lpdd, pCreateSurface, lpddsd, dxversion); // retrieve the attached backbuffer surface and hook it if(lpddsd->dwBackBufferCount == 0) return DD_OK; // nothing to retrieve GetAttachedSurface_Type pGetAttachedSurface; DDSCAPS2 caps; switch(dxversion){ case 1: pGetAttachedSurface = pGetAttachedSurface1; break; case 2: pGetAttachedSurface = pGetAttachedSurface2; break; case 3: pGetAttachedSurface = pGetAttachedSurface3; break; case 4: pGetAttachedSurface = pGetAttachedSurface4; break; case 7: pGetAttachedSurface = pGetAttachedSurface7; break; } memset(&caps, 0, sizeof(caps)); caps.dwCaps = DDSCAPS_BACKBUFFER; lpDDSPrim = dxwss.GetPrimarySurface(); res = (*pGetAttachedSurface)(lpDDSPrim, (LPDDSCAPS)&caps, lplpdds); if(res){ OutTraceE("AttachBackBufferFlippable: GetAttachedSurface ERROR on DDSPrim res=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); return res; } OutTraceDW("AttachBackBufferFlippable: retrieved BACK DDSBack=%x\n", *lplpdds); if(IsDebug) DescribeSurface(*lplpdds, dxversion, "DDSBack", __LINE__); HookDDSurface(lplpdds, dxversion, FALSE); // added !!! iBakBufferVersion=dxversion; // v2.02.31 return DD_OK; } static HRESULT BuildBackBufferFullscreen(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurface, LPDDSURFACEDESC2 lpddsd, int dxversion, LPDIRECTDRAWSURFACE *lplpdds, void *pu) { OutTraceDW("BuildBackBufferFullscreen: lpdd=%x pCreateSurface=%x lpddsd=%x version=%d\n", lpdd, pCreateSurface, lpddsd, dxversion); return DD_OK; } static HRESULT AttachBackBufferFullscreen(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurface, LPDDSURFACEDESC2 lpddsd, int dxversion, LPDIRECTDRAWSURFACE *lplpdds, void *pu) { OutTraceDW("AttachBackBufferFullscreen: lpdd=%x pCreateSurface=%x lpddsd=%x version=%d\n", lpdd, pCreateSurface, lpddsd, dxversion); return DD_OK; } static HRESULT BuildBackBufferDir(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurface, LPDDSURFACEDESC2 lpddsd, int dxversion, LPDIRECTDRAWSURFACE *lplpdds, void *pu) { DDSURFACEDESC2 ddsd; HRESULT res; OutTraceDW("BuildBackBufferDir: lpdd=%x pCreateSurface=%x lpddsd=%x version=%d\n", lpdd, pCreateSurface, lpddsd, dxversion); // create BackBuffer surface // ClearSurfaceDesc((void *)&ddsd, dxversion); memcpy(&ddsd, lpddsd, lpddsd->dwSize); if(dxw.IsEmulated || dxw.Windowize){ ddsd.dwFlags &= ~(DDSD_WIDTH|DDSD_HEIGHT|DDSD_BACKBUFFERCOUNT|DDSD_REFRESHRATE|DDSD_PIXELFORMAT); ddsd.dwFlags |= (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH); ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_COMPLEX); // v2.02.93: don't move primary / backbuf surfaces on systemmemory when 3DDEVICE is requested // v2.04.08: possibly no longer true ... to test with "Tomb Raider 3" non emulated modes if(dxw.dwFlags8 & ALLOWSYSMEMON3DDEV){ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; if (dxversion >= 4) ddsd.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN; ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_VIDEOMEMORY|DDSCAPS_LOCALVIDMEM); } else { if(lpddsd->ddsCaps.dwCaps & DDSCAPS_3DDEVICE) { ddsd.ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY; } else { ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; if (dxversion >= 4) ddsd.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN; ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_VIDEOMEMORY|DDSCAPS_LOCALVIDMEM); } } } if(dxw.dwFlags6 & NOSYSMEMBACKBUF) ddsd.ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY; ddsd.dwWidth = dxw.GetScreenWidth(); ddsd.dwHeight = dxw.GetScreenHeight(); if (dxw.dwFlags2 & BACKBUFATTACH) { LPDIRECTDRAWSURFACE lpPrim; DDSURFACEDESC2 prim; GetGDISurface_Type pGetGDISurface; pGetGDISurface = pGetGDISurfaceMethod(dxversion); (*pGetGDISurface)(lpPrimaryDD, &lpPrim); memset(&prim, 0, sizeof(DDSURFACEDESC2)); prim.dwSize = (dxversion >= 4) ? sizeof(DDSURFACEDESC2) : sizeof(DDSURFACEDESC); res=lpPrim->GetSurfaceDesc((DDSURFACEDESC *)&prim); (*pReleaseSMethod(dxversion))(lpPrim); ddsd.dwWidth = prim.dwWidth; ddsd.dwHeight = prim.dwHeight; OutTraceDW("BuildBackBufferDir: BMX FIX res=%x(%s) wxh=(%dx%d)\n", res, ExplainDDError(res),ddsd.dwWidth, ddsd.dwHeight); } OutTraceDW("BuildBackBufferDir: %s\n", LogSurfaceAttributes(&ddsd, "[Backbuf]", __LINE__)); res=(*pCreateSurface)(lpdd, &ddsd, lplpdds, 0); if(res) { if ((dxw.dwFlags1 & SWITCHVIDEOMEMORY) && (res==DDERR_OUTOFVIDEOMEMORY)){ OutTraceDW("BuildBackBufferDir: CreateSurface DDERR_OUTOFVIDEOMEMORY ERROR at %d, retry in SYSTEMMEMORY\n", __LINE__); ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY; ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; res=(*pCreateSurface)(lpdd, &ddsd, lplpdds, 0); } if(res){ OutTraceE("BuildBackBufferDir: CreateSurface ERROR res=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); return res; } } OutTraceDW("BuildBackBufferDir: created BACK DDSBack=%x\n", *lplpdds); if(IsDebug) DescribeSurface(*lplpdds, dxversion, "DDSBack", __LINE__); HookDDSurface(lplpdds, dxversion, FALSE); // added !!! iBakBufferVersion=dxversion; // v2.02.31 return DD_OK; } static HRESULT BuildGenericEmu(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurface, LPDDSURFACEDESC2 lpddsd, int dxversion, LPDIRECTDRAWSURFACE *lplpdds, void *pu) { DDSURFACEDESC2 ddsd; HRESULT res; OutTraceDW("BuildGenericEmu: lpdd=%x pCreateSurface=%x lpddsd=%x version=%d\n", lpdd, pCreateSurface, lpddsd, dxversion); memcpy(&ddsd, lpddsd, lpddsd->dwSize); // Copy over .... FixSurfaceCaps(&ddsd, dxversion); // It looks that DDSCAPS_SYSTEMMEMORY surfaces can perfectly be DDSCAPS_3DDEVICE as well. // For "Risk II" it is necessary that both the primary surface and the offscreen surfaces are generated // with the same type, so that assuming an identical lPitch and memcopy-ing from one buffer to the // other is a legitimate operation. if(dxw.dwFlags6 & POWER2WIDTH){ // v2.03.28: POWER2WIDTH to fix "Midtown Madness" in surface emulation mode if(((ddsd.dwFlags & (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH)) == (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH)) && (ddsd.ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN) ){ DWORD dwWidth; dwWidth = ((ddsd.dwWidth + 3) >> 2) << 2; if(dwWidth != ddsd.dwWidth) OutTraceDW("BuildGenericEmu: POWER2WIDTH fix surface width %d->%d\n", ddsd.dwWidth, dwWidth); ddsd.dwWidth = dwWidth; } } res=(*pCreateSurface)(lpdd, &ddsd, lplpdds, pu); // v2.04.05: error condition found & fixed on certain platforms for "Dominant Species" only (so far). if (((res == DDERR_UNSUPPORTED) || (res == DDERR_UNSUPPORTEDMODE)) && (ddsd.ddsCaps.dwCaps & DDSCAPS_TEXTURE)){ OutTraceDW("BuildGenericEmu: CreateSurface ERROR res=%x(%s) at %d, TEXTURE->OFFSCREENPLAIN retry\n", res, ExplainDDError(res), __LINE__); ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_TEXTURE|DDSCAPS_ALLOCONLOAD); ddsd.ddsCaps.dwCaps |= (DDSCAPS_OFFSCREENPLAIN); res=(*pCreateSurface)(lpdd, &ddsd, lplpdds, pu); } if ((dxw.dwFlags1 & SWITCHVIDEOMEMORY) && (res!=DD_OK)){ OutTraceDW("BuildGenericEmu: CreateSurface ERROR res=%x(%s) at %d, retry\n", res, ExplainDDError(res), __LINE__); ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY; ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; res=(*pCreateSurface)(lpdd, &ddsd, lplpdds, pu); } if (res) { OutTraceE("BuildGenericEmu: CreateSurface ERROR res=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); return res; } OutTraceDW("BuildGenericEmu: CREATED lpddsd=%x version=%d %s\n", *lplpdds, dxversion, LogSurfaceAttributes(&ddsd, "[Emu Generic]", __LINE__)); // v2.02.66: if 8BPP paletized surface and a primary palette exixts, apply. // fixes "Virtua Fighter PC" palette bug if(lpDDP && (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)){ res=(*pSetPaletteMethod(dxversion))(*lplpdds, lpDDP); if(res) OutTraceE("BuildGenericEmu: SetPalette ERROR lpdds=%x res=%x(%s) at %d\n", *lplpdds, res, ExplainDDError(res), __LINE__); else { OutTraceDW("BuildGenericEmu: applied palette lpddp=%x to lpdds=%x\n", lpDDP, *lplpdds); iDDPExtraRefCounter++; } } // diagnostic hooks .... HookDDSurface(lplpdds, dxversion, FALSE); return DD_OK; } static HRESULT BuildGenericFlippable(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurface, LPDDSURFACEDESC2 lpddsd, int dxversion, LPDIRECTDRAWSURFACE *lplpdds, void *pu) { DDSURFACEDESC2 ddsd; HRESULT res; OutTraceDW("BuildGenericFlippable: lpdd=%x pCreateSurface=%x lpddsd=%x version=%d\n", lpdd, pCreateSurface, lpddsd, dxversion); memcpy(&ddsd, lpddsd, lpddsd->dwSize); // Copy over .... FixSurfaceCaps(&ddsd, dxversion); if(dxw.dwFlags6 & POWER2WIDTH){ // v2.03.28: POWER2WIDTH to fix "Midtown Madness" in surface emulation mode if(((ddsd.dwFlags & (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH)) == (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH)) && (ddsd.ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN) ){ DWORD dwWidth; dwWidth = ((ddsd.dwWidth + 3) >> 2) << 2; if(dwWidth != ddsd.dwWidth) OutTraceDW("BuildGenericFlippable: POWER2WIDTH fix surface width %d->%d\n", ddsd.dwWidth, dwWidth); ddsd.dwWidth = dwWidth; } } res=(*pCreateSurface)(lpdd, &ddsd, lplpdds, pu); if ((dxw.dwFlags1 & SWITCHVIDEOMEMORY) && (res!=DD_OK)){ OutTraceDW("BuildGenericFlippable: CreateSurface ERROR res=%x(%s) at %d, retry\n", res, ExplainDDError(res), __LINE__); ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY; ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; res=(*pCreateSurface)(lpdd, &ddsd, lplpdds, pu); } if (res) { OutTraceE("BuildGenericFlippable: CreateSurface ERROR res=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); return res; } OutTraceDW("BuildGenericFlippable: CREATED lpddsd=%x version=%d %s\n", *lplpdds, dxversion, LogSurfaceAttributes(&ddsd, "[Emu Generic]", __LINE__)); // v2.02.66: if 8BPP paletized surface and a primary palette exixts, apply. // fixes "Virtua Fighter PC" palette bug if(lpDDP && (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)){ res=(*pSetPaletteMethod(dxversion))(*lplpdds, lpDDP); if(res) OutTraceE("BuildGenericFlippable: SetPalette ERROR on lpdds=%x res=%x(%s) at %d\n", *lplpdds, res, ExplainDDError(res), __LINE__); else { OutTraceDW("BuildGenericFlippable: applied palette lpddp=%x to lpdds=%x\n", lpDDP, *lplpdds); iDDPExtraRefCounter++; } } // diagnostic hooks .... HookDDSurface(lplpdds, dxversion, FALSE); return DD_OK; } static HRESULT BuildGenericDir(LPDIRECTDRAW lpdd, CreateSurface_Type pCreateSurface, LPDDSURFACEDESC2 lpddsd, int dxversion, LPDIRECTDRAWSURFACE *lplpdds, void *pu) { HRESULT res; OutTraceDW("BuildGenericDir: lpdd=%x pCreateSurface=%x lpddsd=%x version=%d\n", lpdd, pCreateSurface, lpddsd, dxversion); OutTraceDW("BuildGenericDir: %s\n", LogSurfaceAttributes(lpddsd, "[Dir Generic]", __LINE__)); res = (*pCreateSurface)(lpdd, lpddsd, lplpdds, 0); if(res){ // v2.02.60: Ref. game Incoming GOG release, post by Marek, error DDERR_UNSUPPORTED while trying to create ZBUFFER surface if ((dxw.dwFlags1 & SWITCHVIDEOMEMORY) && ((res==DDERR_OUTOFVIDEOMEMORY)||(res==DDERR_UNSUPPORTED))){ OutTraceDW("BuildGenericDir: CreateSurface ERROR res=%x(%s) at %d, retry\n", res, ExplainDDError(res), __LINE__); lpddsd->ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY; lpddsd->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; res = (*pCreateSurface)(lpdd, lpddsd, lplpdds, 0); } if(res){ OutTraceE("BuildGenericDir: CreateSurface ERROR res=%x(%s) at %d\n", res, ExplainDDError(res), __LINE__); return res; } } OutTraceDW("BuildGenericDir: CREATED lpddsd=%x version=%d %s\n", *lplpdds, dxversion, LogSurfaceAttributes(lpddsd, "[Dir Generic]", __LINE__)); // hooks .... HookDDSurface(lplpdds, dxversion, FALSE); return DD_OK; } HRESULT WINAPI extCreateSurface(int dxversion, CreateSurface_Type pCreateSurface, LPDIRECTDRAW lpdd, DDSURFACEDESC2 *lpddsd, LPDIRECTDRAWSURFACE *lplpdds, void *pu) { HRESULT res; DDSURFACEDESC2 ddsd; LPDIRECTDRAWSURFACE lpDDSPrim; LPDIRECTDRAWSURFACE lpDDSBack = NULL; DWORD CurFlags; int TargetSize; typedef HRESULT (*BuildSurface_Type)(LPDIRECTDRAW, CreateSurface_Type, LPDDSURFACEDESC2, int, LPDIRECTDRAWSURFACE *, void *); static BuildSurface_Type BuildPrimary = 0; static BuildSurface_Type BuildBackBuffer = 0; static BuildSurface_Type AttachBackBuffer = 0; static BuildSurface_Type BuildGeneric = 0; static enum { PRIMARY_FULLSCREEN = 0, PRIMARY_DIRECT, PRIMARY_FLIPPABLE, PRIMARY_EMULATED } SurfaceMode; OutTraceDDRAW("CreateSurface(%d): lpdd=%x %s\n", dxversion, lpdd, LogSurfaceAttributes(lpddsd, "[CreateSurface]", __LINE__)); // v2.03.95.fx1 - deleted: some texture handling REQUIRES a proper FourCC codec. // maybe it could be suppressed by a dedicated config. flag and on primary surfaces only? //lpddsd->ddpfPixelFormat.dwFourCC = 0; // if not initialized yet .... if(BuildPrimary == 0){ char *sLabel; SurfaceMode = PRIMARY_FULLSCREEN; if(dxw.IsEmulated || dxw.Windowize){ SurfaceMode = (dxw.dwFlags1 & EMULATESURFACE) ? ((dxw.dwFlags6 & FLIPEMULATION) ? PRIMARY_EMULATED : PRIMARY_FLIPPABLE) : PRIMARY_DIRECT; } switch(SurfaceMode) { case PRIMARY_FULLSCREEN: BuildPrimary = BuildPrimaryFullscreen; BuildBackBuffer = BuildBackBufferFullscreen; AttachBackBuffer = AttachBackBufferFullscreen; BuildGeneric = BuildGenericDir; sLabel="FULLSCR"; break; case PRIMARY_DIRECT: BuildPrimary = BuildPrimaryDir; BuildBackBuffer = BuildBackBufferDir; AttachBackBuffer = BuildBackBufferDir; BuildGeneric = BuildGenericDir; sLabel="DIRECT"; break; case PRIMARY_FLIPPABLE: BuildPrimary = BuildPrimaryFlippable; BuildBackBuffer = BuildBackBufferFlippable; AttachBackBuffer = AttachBackBufferFlippable; BuildGeneric = BuildGenericFlippable; sLabel="FLIPPABLE"; break; case PRIMARY_EMULATED: BuildPrimary = BuildPrimaryEmu; BuildBackBuffer = BuildBackBufferEmu; AttachBackBuffer = BuildBackBufferEmu; BuildGeneric = BuildGenericEmu; sLabel="EMULATED"; break; } OutTraceDW("CreateSurface: MODE INITIALIZED mode=%d(%s)\n", SurfaceMode, sLabel); } // check for lpddsd->dwSize value TargetSize=(dxversion<4)?sizeof(DDSURFACEDESC):sizeof(DDSURFACEDESC2); if(lpddsd->dwSize != TargetSize){ char sMsg[81]; sprintf_s(sMsg,80, "CreateSurface: ASSERT bad dwSize=%d dxversion=%d\n", lpddsd->dwSize, dxversion); OutTraceDW(sMsg); if(IsAssertEnabled) MessageBox(0, sMsg, "CreateSurface", MB_OK | MB_ICONEXCLAMATION); return DDERR_INVALIDPARAMS; } //GHO workaround (needed for WarWind, Rogue Spear): if (lpddsd->dwFlags && !(lpddsd->dwFlags & 0x1)){ OutTraceDW("CreateSurface: fixing illegal dwFlags value: %x -> %x\n", lpddsd->dwFlags, (lpddsd->dwFlags | DDSD_CAPS)); lpddsd->dwFlags |= DDSD_CAPS; } memcpy(&ddsd, lpddsd, lpddsd->dwSize); // Copy // v2.02.38: this is odd: in "Star Force Deluxe" there is no PRIMARY surface, but a surface with // 0 flags and 0 capabilities serves for this purpose. Is it a side-effect of old ddraw releases? if((dxversion == 1) && ((ddsd.dwFlags & ~DDSD_BACKBUFFERCOUNT) == 0)){ // Star Force Deluxe ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; //if(dxw.VirtualPixelFormat.dwRGBBitCount == 8) ddsd.ddsCaps.dwCaps |= DDSCAPS_PALETTE; } // creation of the primary surface.... if(ddsd.dwFlags & DDSD_CAPS && ddsd.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE){ dxwss.ClearSurfaceList(); // v2.03.83: "Daytona USA" would saturate the list otherwise SetVSyncDelays(dxversion, lpdd); GetHookInfo()->Height=(short)dxw.GetScreenHeight(); GetHookInfo()->Width=(short)dxw.GetScreenWidth(); GetHookInfo()->ColorDepth=(short)dxw.VirtualPixelFormat.dwRGBBitCount; GetHookInfo()->DXVersion=dxversion; lpPrimaryDD = lpdd; // v2.1.87 memcpy(&DDSD_Prim, lpddsd, sizeof(DDSD_Prim)); // v2.02.37 // beware of the different behaviour between older and newer directdraw releases... if(dxversion >= 4){ if (lpDDSEmu_Back) while(lpDDSEmu_Back->Release()); if (lpDDSEmu_Prim) while(lpDDSEmu_Prim->Release()); if (ddsd.dwFlags & DDSD_BACKBUFFERCOUNT) { // Praetorians !!!! lpDDSBack = dxwss.GetBackBufferSurface(); if (lpDDSBack) { if(dxw.dwFlags6 & FLIPEMULATION) while(lpDDSBack->Release()); dxwss.PopSurface(lpDDSBack); lpDDSBack = NULL; } } } lpDDSEmu_Back=NULL; lpDDSEmu_Prim=NULL; int BBCount=0; // or 1 ?? if (ddsd.dwFlags & DDSD_BACKBUFFERCOUNT) BBCount=ddsd.dwBackBufferCount; if ((BBCount > 0) && (iBakBufferVersion < 4)){ lpDDSBack=NULL; OutTraceDW("CreateSurface: backbuffer cleared - BackBufferCount=%d\n", BBCount); } if (BBCount > MAXBACKBUFFERS){ char sMsg[81]; sprintf_s(sMsg, 80, "CreateSurface: BackBufferCount=%d\n", BBCount); OutTraceDW(sMsg); if (IsAssertEnabled) MessageBox(0, sMsg, "CreateSurface", MB_OK | MB_ICONEXCLAMATION); // recover ... BBCount = MAXBACKBUFFERS; } // build emulated primary surface, real primary and backbuffer surfaces CurFlags=ddsd.dwFlags; res=BuildPrimary(lpdd, pCreateSurface, lpddsd, dxversion, lplpdds, NULL); if(res) return res; lpDDSPrim = *lplpdds; dxwss.PushPrimarySurface(lpDDSPrim, dxversion, lpddsd->ddsCaps.dwCaps); RegisterPixelFormat(dxversion, lpDDSPrim); if (BBCount){ DWORD dwCaps; // build emulated backbuffer surface res=AttachBackBuffer(lpdd, pCreateSurface, lpddsd, dxversion, &lpDDSBack, NULL); if(res) return res; // here we try to guess what sort of capabilities would expose a built-in backbuffer surface dwCaps = lpddsd->ddsCaps.dwCaps; dwCaps &= ~DDSCAPS_PRIMARYSURFACE; dwCaps |= (DDSCAPS_BACKBUFFER|DDSCAPS_VIDEOMEMORY); dxwss.PushBackBufferSurface(lpDDSBack, dxversion, dwCaps); } if(IsTraceDDRAW){ char sInfo[256+1]; sprintf(sInfo, "CreateSurface: created DDSPrim=%x DDSBack=%x", lpDDSPrim, lpDDSBack); if(dxw.IsEmulated) sprintf(sInfo, "%s DDSEmu_Prim=%x", sInfo, lpDDSEmu_Prim); if(dxw.dwFlags1 & EMULATESURFACE) sprintf(sInfo, "%s DDSEmu_Back=%x", sInfo, lpDDSEmu_Back); strcat(sInfo, "\n"); OutTrace(sInfo); } // rebuild the clipper area if(dxw.dwFlags1 & CLIPCURSOR) dxw.SetClipCursor(); // v2.2.64: added extra ref needed to preserve ddraw session for later use. Is it a ddraw1 legacy? // seems to fix problems in "Warhammer 40K Rites Of War" that uses a ddraw session after reaching 0 refcount. // v2.2.84: avoid the extra referenced in non windowed mode since it causes the window shift reported by gsky916 // for Wind Fantasy SP. // v2.3.59: same extra reference is needed by "Wahammer Chaos Gate" that uses ddraw interface release 2 // v2.3.72: fixed previous fix: condition is <=2, not >=2 ! // Be aware that it may perhaps become <=3, if we get the same problem elsewhere // v2.3.96: deleted the if(Windowized) condition: AddRef is needed also in fullscreen mode. if(dxw.dwDDVersion<=2) lpdd->AddRef(); return DD_OK; } // a request for a separate (not complex) backbuffer to attach later on, maybe. if ((ddsd.dwFlags & DDSD_CAPS) && (ddsd.ddsCaps.dwCaps & DDSCAPS_BACKBUFFER)){ if (lpDDSBack) { OutTraceDW("CreateSurface: returning current DDSBack=%x\n", lpDDSBack); *lplpdds = lpDDSBack; return DD_OK; } res=BuildBackBuffer(lpdd, pCreateSurface, lpddsd, dxversion, lplpdds, NULL); if(res == DD_OK) dxwss.PushBackBufferSurface(*lplpdds, dxversion, lpddsd->ddsCaps.dwCaps); return res; } // if nothing else, it's a generic/zbuffer surface // Note: should DxWnd trace a memory 3D surface that will be used as reference surface for D3D CreateDevice? res=BuildGeneric(lpdd, pCreateSurface, lpddsd, dxversion, lplpdds, pu); if(!res) { dxwss.PopSurface(*lplpdds); if(lpddsd->ddsCaps.dwCaps & DDSCAPS_ZBUFFER) { // v2.03.82: save ZBUFFER capabilities for later fix in D3D CreateDevice OutTraceDW("CreateSurface: lpDDZBuffer=%x save ZBUFFER caps=%x(%s)\n", *lplpdds, lpddsd->ddsCaps.dwCaps, ExplainDDSCaps(lpddsd->ddsCaps.dwCaps)); lpDDZBuffer = *lplpdds; // save surface size expressed in bytes extern int ZBufferSize; ZBufferSize = lpddsd->dwWidth * lpddsd->dwHeight * (lpddsd->ddpfPixelFormat.dwZBufferBitDepth >> 3); dxwss.PushZBufferSurface(*lplpdds, dxversion, lpddsd->ddsCaps.dwCaps); OutTraceDW("CreateSurface: ZBufferSize=%d\n", ZBufferSize); } else { if(lpddsd->ddsCaps.dwCaps & DDSCAPS_3DDEVICE) { OutTraceDW("CreateSurface: lpDD3DRef=%x save 3DREF caps=%x(%s)\n", *lplpdds, lpddsd->ddsCaps.dwCaps, ExplainDDSCaps(lpddsd->ddsCaps.dwCaps)); dxwss.Push3DRefSurface(*lplpdds, dxversion, lpddsd->ddsCaps.dwCaps); } } } return res; }