Merge pull request #2059 from CookiePLMonster/d3d-create-fixes

Refactor D3D device creation
This commit is contained in:
PatrickvL 2020-12-09 16:46:42 +01:00 committed by GitHub
commit 4d4f6dd681
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 316 additions and 473 deletions

View File

@ -71,6 +71,7 @@
#include <assert.h> #include <assert.h>
#include <process.h> #include <process.h>
#include <clocale> #include <clocale>
#include <functional>
#include <unordered_map> #include <unordered_map>
#include <thread> #include <thread>
@ -86,23 +87,15 @@ bool g_bClipCursor = false; // indicates that th
IDirect3DDevice *g_pD3DDevice = nullptr; // Direct3D Device IDirect3DDevice *g_pD3DDevice = nullptr; // Direct3D Device
// Static Variable(s) // Static Variable(s)
static IDirectDrawSurface7 *g_pDDSPrimary = nullptr; // DirectDraw7 Primary Surface static bool g_bSupportsFormatSurface[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1]; // Does device support surface format?
static IDirectDrawClipper *g_pDDClipper = nullptr; // DirectDraw7 Clipper static bool g_bSupportsFormatSurfaceRenderTarget[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1]; // Does device support surface format?
static IDirectDraw7 *g_pDD7 = nullptr; // DirectDraw7 static bool g_bSupportsFormatSurfaceDepthStencil[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1]; // Does device support surface format?
static HMONITOR g_hMonitor = NULL; // Handle to DirectDraw monitor static bool g_bSupportsFormatTexture[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1]; // Does device support texture format?
static GUID g_ddguid = { 0 }; // DirectDraw driver GUID static bool g_bSupportsFormatTextureRenderTarget[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1]; // Does device support texture format?
static DDCAPS g_DriverCaps = { 0 }; static bool g_bSupportsFormatTextureDepthStencil[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1]; // Does device support texture format?
static bool g_bSupportsFormatVolumeTexture[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1]; // Does device support surface format?
static bool g_bSupportsFormatSurface[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1] = { false };// Does device support surface format? static bool g_bSupportsFormatCubeTexture[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1]; // Does device support surface format?
static bool g_bSupportsFormatSurfaceRenderTarget[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1] = { false };// Does device support surface format?
static bool g_bSupportsFormatSurfaceDepthStencil[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1] = { false };// Does device support surface format?
static bool g_bSupportsFormatTexture[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1] = { false }; // Does device support texture format?
static bool g_bSupportsFormatTextureRenderTarget[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1] = { false };// Does device support texture format?
static bool g_bSupportsFormatTextureDepthStencil[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1] = { false };// Does device support texture format?
static bool g_bSupportsFormatVolumeTexture[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1] = { false }; // Does device support surface format?
static bool g_bSupportsFormatCubeTexture[xbox::X_D3DFMT_LIN_R8G8B8A8 + 1] = { false }; // Does device support surface format?
static HBRUSH g_hBgBrush = NULL; // Background Brush static HBRUSH g_hBgBrush = NULL; // Background Brush
static volatile bool g_bRenderWindowActive = false;
static BOOL g_bIsFauxFullscreen = FALSE; static BOOL g_bIsFauxFullscreen = FALSE;
static DWORD g_OverlaySwap = 0; // Set in D3DDevice_UpdateOverlay static DWORD g_OverlaySwap = 0; // Set in D3DDevice_UpdateOverlay
static int g_iWireframe = 0; // wireframe toggle static int g_iWireframe = 0; // wireframe toggle
@ -121,7 +114,6 @@ static Settings::s_video g_XBVideo;
// D3D based variables // D3D based variables
static IDirect3D *g_pDirect3D = nullptr; static IDirect3D *g_pDirect3D = nullptr;
D3DCAPS g_D3DCaps = {}; // Direct3D Caps D3DCAPS g_D3DCaps = {}; // Direct3D Caps
static IDirect3DVertexBuffer *g_pDummyBuffer = nullptr; // Dummy buffer, used to set unused stream sources with
static IDirect3DIndexBuffer *g_pClosingLineLoopHostIndexBuffer = nullptr; static IDirect3DIndexBuffer *g_pClosingLineLoopHostIndexBuffer = nullptr;
static IDirect3DIndexBuffer *g_pQuadToTriangleHostIndexBuffer = nullptr; static IDirect3DIndexBuffer *g_pQuadToTriangleHostIndexBuffer = nullptr;
@ -193,14 +185,10 @@ float g_Xbox_BackbufferScaleY = 1;
/* Unused : /* Unused :
static xbox::dword_xt *g_Xbox_D3DDevice; // TODO: This should be a D3DDevice structure static xbox::dword_xt *g_Xbox_D3DDevice; // TODO: This should be a D3DDevice structure
static DWORD g_dwVertexShaderUsage = 0; // Unused. If needed, move to XbVertexShader.cpp
*/ */
// Static Function(s) // Static Function(s)
static BOOL WINAPI EmuEnumDisplayDevices(GUID FAR *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID lpContext, HMONITOR hm);
static DWORD WINAPI EmuRenderWindow(LPVOID); static DWORD WINAPI EmuRenderWindow(LPVOID);
static DWORD WINAPI EmuCreateDeviceProxy(LPVOID);
static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
static DWORD WINAPI EmuUpdateTickCount(LPVOID); static DWORD WINAPI EmuUpdateTickCount(LPVOID);
static inline void EmuVerifyResourceIsRegistered(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTextureStage, DWORD dwSize); static inline void EmuVerifyResourceIsRegistered(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTextureStage, DWORD dwSize);
@ -254,17 +242,10 @@ struct EmuD3D8CreateDeviceProxyData
// Set by EmuD3DInit() // Set by EmuD3DInit()
xbox::uint_xt Adapter; xbox::uint_xt Adapter;
D3DDEVTYPE DeviceType; D3DDEVTYPE DeviceType;
HWND hFocusWindow;
// Set byt EMUPATCH(Direct3D_CreateDevice)
xbox::X_D3DPRESENT_PARAMETERS XboxPresentationParameters;
volatile bool bReady;
volatile bool bCreate; // false : release
// Set by EmuCreateDeviceProxy() // Set by EmuCreateDeviceProxy()
xbox::dword_xt BehaviorFlags;
D3DPRESENT_PARAMETERS HostPresentationParameters; D3DPRESENT_PARAMETERS HostPresentationParameters;
volatile HRESULT hRet;
} }
g_EmuCDPD = {0}; g_EmuCDPD;
// Declare trampolines // Declare trampolines
#define XB_TRAMPOLINES(XB_MACRO) \ #define XB_TRAMPOLINES(XB_MACRO) \
@ -558,6 +539,16 @@ const char *CxbxGetErrorDescription(HRESULT hResult)
return nullptr; return nullptr;
} }
static constexpr UINT WM_CXBXR_RUN_ON_MESSAGE_THREAD = WM_USER+0;
// A helper function to run any code on a window message thread
// Used for those D3D9 function which *must* be ran on this particular thread
static void RunOnWndMsgThread(const std::function<void()>& func)
{
const void* param = &func;
SendMessage(g_hEmuWindow, WM_CXBXR_RUN_ON_MESSAGE_THREAD, reinterpret_cast<WPARAM>(param), 0);
}
const char *D3DErrorString(HRESULT hResult) const char *D3DErrorString(HRESULT hResult)
{ {
@ -590,13 +581,12 @@ void CxbxInitWindow(bool bFullInit)
// create timing thread // create timing thread
if (bFullInit) if (bFullInit)
{ {
DWORD dwThreadId; HANDLE hThread = CreateThread(nullptr, 0, EmuUpdateTickCount, nullptr, 0, nullptr);
HANDLE hThread = CreateThread(nullptr, 0, EmuUpdateTickCount, nullptr, 0, &dwThreadId);
// We set the priority of this thread a bit higher, to assure reliable timing : // We set the priority of this thread a bit higher, to assure reliable timing :
SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL); SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
CxbxKrnlRegisterThread(hThread); CxbxKrnlRegisterThread(hThread);
CloseHandle(hThread); // CxbxKrnlRegisterThread duplicates the handle so we can close this one
} }
/* TODO : Port this Dxbx code : /* TODO : Port this Dxbx code :
@ -608,11 +598,8 @@ void CxbxInitWindow(bool bFullInit)
*/ */
// create window message processing thread // create window message processing thread
{ {
DWORD dwThreadId; HANDLE hStartEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
HANDLE hRenderWindowThread = CreateThread(nullptr, 0, EmuRenderWindow, &hStartEvent, 0, nullptr);
g_bRenderWindowActive = false;
HANDLE hRenderWindowThread = CreateThread(nullptr, 0, EmuRenderWindow, nullptr, 0, &dwThreadId);
if (hRenderWindowThread == NULL) { if (hRenderWindowThread == NULL) {
char szBuffer[1024] = { 0 }; char szBuffer[1024] = { 0 };
@ -621,11 +608,12 @@ void CxbxInitWindow(bool bFullInit)
EmuShared::Cleanup(); EmuShared::Cleanup();
ExitProcess(0); ExitProcess(0);
} }
SetThreadAffinityMask(hRenderWindowThread, g_CPUOthers);
while(!g_bRenderWindowActive) // Wait for the window to create
Sleep(0); WaitForSingleObject(hStartEvent, INFINITE);
CloseHandle(hStartEvent);
Sleep(0); CloseHandle(hRenderWindowThread);
} }
SetFocus(g_hEmuWindow); SetFocus(g_hEmuWindow);
@ -1616,21 +1604,10 @@ void EmuD3DInit()
{ {
HLE_init_pgraph_plugins(); // TODO : Hook more nv_dma_map() result uses in EmuNV2A_PGRAPH.cpp HLE_init_pgraph_plugins(); // TODO : Hook more nv_dma_map() result uses in EmuNV2A_PGRAPH.cpp
// create the create device proxy thread
{
HANDLE thread = CreateThread(nullptr, 0, EmuCreateDeviceProxy, nullptr, 0, nullptr);
// Ported from Dxbx :
// If possible, assign this thread to another core than the one that runs Xbox1 code :
SetThreadAffinityMask(thread, g_CPUOthers);
CloseHandle(thread);
}
// Initialise CreateDevice Proxy Data struct // Initialise CreateDevice Proxy Data struct
{ {
g_EmuCDPD = {0};
g_EmuCDPD.Adapter = g_XBVideo.adapter; g_EmuCDPD.Adapter = g_XBVideo.adapter;
g_EmuCDPD.DeviceType = (g_XBVideo.direct3DDevice == 0) ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF; g_EmuCDPD.DeviceType = (g_XBVideo.direct3DDevice == 0) ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF;
g_EmuCDPD.hFocusWindow = g_hEmuWindow;
} }
// create Direct3D8 and retrieve caps // create Direct3D8 and retrieve caps
@ -1663,35 +1640,10 @@ void EmuD3DInit()
// cleanup Direct3D // cleanup Direct3D
void EmuD3DCleanup() {} void EmuD3DCleanup() {}
// enumeration procedure for locating display device GUIDs
static BOOL WINAPI EmuEnumDisplayDevices(GUID FAR *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID lpContext, HMONITOR hm)
{
static DWORD dwEnumCount = 0;
if(dwEnumCount++ == g_EmuCDPD.Adapter + 1)
{
g_hMonitor = hm;
dwEnumCount = 0;
if(lpGUID != 0)
{
memcpy(&g_ddguid, lpGUID, sizeof(GUID));
}
else
{
memset(&g_ddguid, 0, sizeof(GUID));
}
return FALSE;
}
return TRUE;
}
// window message processing thread // window message processing thread
static DWORD WINAPI EmuRenderWindow(LPVOID lpVoid) static DWORD WINAPI EmuRenderWindow(LPVOID lpParam)
{ {
CxbxSetThreadName("Cxbx Render Window"); CxbxSetThreadName("Cxbx Render Window");
SetThreadAffinityMask(GetCurrentThread(), g_CPUOthers);
// register window class // register window class
{ {
@ -1772,6 +1724,8 @@ static DWORD WINAPI EmuRenderWindow(LPVOID lpVoid)
DbgConsole *dbgConsole = new DbgConsole(); DbgConsole *dbgConsole = new DbgConsole();
#endif #endif
SetEvent(*reinterpret_cast<PHANDLE>(lpParam));
// message processing loop // message processing loop
{ {
MSG msg; MSG msg;
@ -1780,8 +1734,6 @@ static DWORD WINAPI EmuRenderWindow(LPVOID lpVoid)
bool lPrintfOn = g_bPrintfOn; bool lPrintfOn = g_bPrintfOn;
g_bRenderWindowActive = true;
while(msg.message != WM_QUIT) while(msg.message != WM_QUIT)
{ {
if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
@ -1809,8 +1761,6 @@ static DWORD WINAPI EmuRenderWindow(LPVOID lpVoid)
} }
} }
g_bRenderWindowActive = false;
#ifdef INCLUDE_DBG_CONSOLE #ifdef INCLUDE_DBG_CONSOLE
delete dbgConsole; delete dbgConsole;
#endif #endif
@ -2116,6 +2066,13 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
} }
break; break;
case WM_CXBXR_RUN_ON_MESSAGE_THREAD:
{
auto func = reinterpret_cast<const std::function<void()>*>(wParam);
(*func)();
return 0;
}
default: default:
return DefWindowProc(hWnd, msg, wParam, lParam); return DefWindowProc(hWnd, msg, wParam, lParam);
} }
@ -2225,385 +2182,283 @@ void UpdateDepthStencilFlags(IDirect3DSurface *pDepthStencilSurface)
} }
} }
} }
// thread dedicated to create devices
static DWORD WINAPI EmuCreateDeviceProxy(LPVOID) static void SetupPresentationParameters
(
const xbox::X_D3DPRESENT_PARAMETERS *pXboxPresentationParameters
)
{ {
LOG_FUNC(); D3DPRESENT_PARAMETERS& params = g_EmuCDPD.HostPresentationParameters;
CxbxSetThreadName("Cxbx CreateDevice Proxy"); params.Windowed = !g_XBVideo.bFullScreen;
EmuLog(LOG_LEVEL::DEBUG, "CreateDevice proxy thread is running."); // TODO: Investigate the best option for this
params.SwapEffect = D3DSWAPEFFECT_COPY;
while(true) // Attempt to match backbuffer format, this is not *required*, but leads to faster blitting/swapping
{ params.BackBufferFormat = EmuXB2PC_D3DFormat(pXboxPresentationParameters->BackBufferFormat);
// if we have been signalled, create the device with cached parameters
if(g_EmuCDPD.bReady)
{
EmuLog(LOG_LEVEL::DEBUG, "CreateDevice proxy thread received request.");
// only one device should be created at once params.PresentationInterval = g_XBVideo.bVSync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
if (g_pD3DDevice != nullptr) { g_Xbox_PresentationInterval_Default = pXboxPresentationParameters->PresentationInterval;
EmuLog(LOG_LEVEL::DEBUG, "CreateDevice proxy thread releasing old Device.");
g_pD3DDevice->EndScene(); // We only want *one* backbuffer on the host, triple buffering, etc should be handled by our Present/Swap impl
params.BackBufferCount = 1;
ClearResourceCache(g_Cxbx_Cached_PaletizedTextures); // We don't want multisampling on the host backbuffer, it should be applied to Xbox surfaces if required
ClearResourceCache(g_Cxbx_Cached_Direct3DResources); params.MultiSampleType = D3DMULTISAMPLE_NONE;
params.MultiSampleQuality = 0;
// TODO: ensure all other resources are cleaned up too // We want a lockable backbuffer for swapping/blitting purposes
params.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
g_EmuCDPD.hRet = g_pD3DDevice->Release(); // retrieve resolution from configuration
g_pD3DDevice = nullptr; char szBackBufferFormat[16] = {};
const char* resolution = g_XBVideo.szVideoResolution;
// cleanup overlay clipper if (4 != sscanf(resolution, "%u x %u %*dbit %s (%u hz)",
if (g_pDDClipper != nullptr) { &params.BackBufferWidth,
g_pDDClipper->Release(); &params.BackBufferHeight,
g_pDDClipper = nullptr; szBackBufferFormat,
} &params.FullScreen_RefreshRateInHz)) {
EmuLog(LOG_LEVEL::DEBUG, "EmuCreateDeviceProxy: Couldn't parse resolution : %s. Using Xbox Default (%d, %d @ %uhz)", resolution,
// cleanup directdraw surface pXboxPresentationParameters->BackBufferWidth, pXboxPresentationParameters->BackBufferHeight,
if (g_pDDSPrimary != nullptr) { pXboxPresentationParameters->FullScreen_RefreshRateInHz);
g_pDDSPrimary->Release(); params.BackBufferWidth = pXboxPresentationParameters->BackBufferWidth;
g_pDDSPrimary = nullptr; params.BackBufferHeight = pXboxPresentationParameters->BackBufferHeight;
} params.FullScreen_RefreshRateInHz = pXboxPresentationParameters->FullScreen_RefreshRateInHz;
// cleanup directdraw
if (g_pDD7 != nullptr) {
g_pDD7->Release();
g_pDD7 = nullptr;
}
}
if (g_EmuCDPD.bCreate) {
// Apply render scale factor for high-resolution rendering
g_RenderUpscaleFactor = g_XBVideo.renderScaleFactor;
g_RenderTargetUpscaleFactor = 1;
// Setup the HostPresentationParameters
{
g_EmuCDPD.HostPresentationParameters = {};
g_EmuCDPD.HostPresentationParameters.Windowed = !g_XBVideo.bFullScreen;
// TODO: Investigate the best option for this
g_EmuCDPD.HostPresentationParameters.SwapEffect = D3DSWAPEFFECT_COPY;
// Attempt to match backbuffer format, this is not *required*, but leads to faster blitting/swapping
g_EmuCDPD.HostPresentationParameters.BackBufferFormat = EmuXB2PC_D3DFormat(g_EmuCDPD.XboxPresentationParameters.BackBufferFormat);
g_EmuCDPD.HostPresentationParameters.PresentationInterval = g_XBVideo.bVSync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
g_Xbox_PresentationInterval_Default = g_EmuCDPD.XboxPresentationParameters.PresentationInterval;
// We only want *one* backbuffer on the host, triple buffering, etc should be handled by our Present/Swap impl
g_EmuCDPD.HostPresentationParameters.BackBufferCount = 1;
// We don't want multisampling on the host backbuffer, it should be applied to Xbox surfaces if required
g_EmuCDPD.HostPresentationParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
g_EmuCDPD.HostPresentationParameters.MultiSampleQuality = 0;
// We want a lockable backbuffer for swapping/blitting purposes
g_EmuCDPD.HostPresentationParameters.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
// retrieve resolution from configuration
char szBackBufferFormat[16] = {};
const char* resolution = g_XBVideo.szVideoResolution;
if (4 != sscanf(resolution, "%u x %u %*dbit %s (%u hz)",
&g_EmuCDPD.HostPresentationParameters.BackBufferWidth,
&g_EmuCDPD.HostPresentationParameters.BackBufferHeight,
szBackBufferFormat,
&g_EmuCDPD.HostPresentationParameters.FullScreen_RefreshRateInHz)) {
EmuLog(LOG_LEVEL::DEBUG, "EmuCreateDeviceProxy: Couldn't parse resolution : %s. Using Xbox Default (%d, %d @ %uhz)", resolution,
g_EmuCDPD.XboxPresentationParameters.BackBufferWidth, g_EmuCDPD.XboxPresentationParameters.BackBufferHeight,
g_EmuCDPD.XboxPresentationParameters.FullScreen_RefreshRateInHz);
g_EmuCDPD.HostPresentationParameters.BackBufferWidth = g_EmuCDPD.XboxPresentationParameters.BackBufferWidth;
g_EmuCDPD.HostPresentationParameters.BackBufferHeight = g_EmuCDPD.XboxPresentationParameters.BackBufferHeight;
g_EmuCDPD.HostPresentationParameters.FullScreen_RefreshRateInHz = g_EmuCDPD.XboxPresentationParameters.FullScreen_RefreshRateInHz;
}
if(g_EmuCDPD.HostPresentationParameters.Windowed)
{
D3DDISPLAYMODE D3DDisplayMode;
g_pDirect3D->GetAdapterDisplayMode(g_EmuCDPD.Adapter, &D3DDisplayMode);
g_EmuCDPD.HostPresentationParameters.BackBufferFormat = D3DDisplayMode.Format;
g_EmuCDPD.HostPresentationParameters.FullScreen_RefreshRateInHz = 0;
}
else
{
// In exclusive fullscreen mode, make *sure* to use the info that was in the resolution string
if (strcmp(szBackBufferFormat, "x1r5g5b5") == 0)
g_EmuCDPD.HostPresentationParameters.BackBufferFormat = D3DFMT_X1R5G5B5;
else if (strcmp(szBackBufferFormat, "r5g6r5") == 0)
g_EmuCDPD.HostPresentationParameters.BackBufferFormat = D3DFMT_R5G6B5;
else if (strcmp(szBackBufferFormat, "x8r8g8b8") == 0)
g_EmuCDPD.HostPresentationParameters.BackBufferFormat = D3DFMT_X8R8G8B8;
else if (strcmp(szBackBufferFormat, "a8r8g8b8") == 0)
g_EmuCDPD.HostPresentationParameters.BackBufferFormat = D3DFMT_A8R8G8B8;
}
}
// detect vertex processing capabilities
if((g_D3DCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) && g_EmuCDPD.DeviceType == D3DDEVTYPE_HAL)
{
EmuLog(LOG_LEVEL::DEBUG, "Using hardware vertex processing");
g_EmuCDPD.BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
// Unused : g_dwVertexShaderUsage = 0;
}
else
{
EmuLog(LOG_LEVEL::DEBUG, "Using software vertex processing");
g_EmuCDPD.BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
// Unused : g_dwVertexShaderUsage = D3DUSAGE_SOFTWAREPROCESSING;
}
// Dxbx addition : Prevent Direct3D from changing the FPU Control word :
g_EmuCDPD.BehaviorFlags |= D3DCREATE_FPU_PRESERVE;
// Direct3D8: (WARN) :Device that was created without D3DCREATE_MULTITHREADED is being used by a thread other than the creation thread.
g_EmuCDPD.BehaviorFlags |= D3DCREATE_MULTITHREADED;
// We never want auto-depth stencil on the host, Xbox D3D will handle this for us
g_EmuCDPD.HostPresentationParameters.EnableAutoDepthStencil = FALSE;
// redirect to windows Direct3D
g_EmuCDPD.hRet = g_pDirect3D->CreateDevice(
g_EmuCDPD.Adapter,
g_EmuCDPD.DeviceType,
g_EmuCDPD.hFocusWindow,
g_EmuCDPD.BehaviorFlags,
&g_EmuCDPD.HostPresentationParameters,
&g_pD3DDevice
);
DEBUG_D3DRESULT(g_EmuCDPD.hRet, "IDirect3D::CreateDevice");
if(FAILED(g_EmuCDPD.hRet))
CxbxKrnlCleanup("IDirect3D::CreateDevice failed");
// Which texture formats does this device support?
memset(g_bSupportsFormatSurface, false, sizeof(g_bSupportsFormatSurface));
memset(g_bSupportsFormatSurfaceRenderTarget, false, sizeof(g_bSupportsFormatSurfaceRenderTarget));
memset(g_bSupportsFormatSurfaceDepthStencil, false, sizeof(g_bSupportsFormatSurfaceDepthStencil));
memset(g_bSupportsFormatTexture, false, sizeof(g_bSupportsFormatTexture));
memset(g_bSupportsFormatTextureRenderTarget, false, sizeof(g_bSupportsFormatTextureRenderTarget));
memset(g_bSupportsFormatTextureDepthStencil, false, sizeof(g_bSupportsFormatTextureDepthStencil));
memset(g_bSupportsFormatVolumeTexture, false, sizeof(g_bSupportsFormatVolumeTexture));
memset(g_bSupportsFormatCubeTexture, false, sizeof(g_bSupportsFormatCubeTexture));
for (int X_Format = xbox::X_D3DFMT_L8; X_Format <= xbox::X_D3DFMT_LIN_R8G8B8A8; X_Format++) {
// Only process Xbox formats that are directly mappable to host
if (!EmuXBFormatRequiresConversionToARGB((xbox::X_D3DFORMAT)X_Format)) {
// Convert the Xbox format into host format (without warning, thanks to the above restriction)
D3DFORMAT PCFormat = EmuXB2PC_D3DFormat((xbox::X_D3DFORMAT)X_Format);
if (PCFormat != D3DFMT_UNKNOWN) {
// Index with Xbox D3DFormat, because host FourCC codes are too big to be used as indices
if (D3D_OK == g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, 0,
D3DRTYPE_SURFACE, PCFormat))
g_bSupportsFormatSurface[X_Format] = true;
if (D3D_OK == g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, D3DUSAGE_RENDERTARGET,
D3DRTYPE_SURFACE, PCFormat))
g_bSupportsFormatSurfaceRenderTarget[X_Format] = true;
if (D3D_OK == g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL,
D3DRTYPE_SURFACE, PCFormat))
g_bSupportsFormatSurfaceDepthStencil[X_Format] = true;
if (D3D_OK == g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, 0,
D3DRTYPE_TEXTURE, PCFormat))
g_bSupportsFormatTexture[X_Format] = true;
if (D3D_OK == g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, D3DUSAGE_RENDERTARGET,
D3DRTYPE_TEXTURE, PCFormat))
g_bSupportsFormatTextureRenderTarget[X_Format] = true;
if (D3D_OK == g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL,
D3DRTYPE_TEXTURE, PCFormat))
g_bSupportsFormatTextureDepthStencil[X_Format] = true;
if (D3D_OK == g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, 0,
D3DRTYPE_VOLUMETEXTURE, PCFormat))
g_bSupportsFormatVolumeTexture[X_Format] = true;
if (D3D_OK == g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, 0,
D3DRTYPE_CUBETEXTURE, PCFormat))
g_bSupportsFormatCubeTexture[X_Format] = true;
}
}
}
// default NULL guid
ZeroMemory(&g_ddguid, sizeof(GUID));
HRESULT hRet;
// enumerate device guid for this monitor, for directdraw
hRet = DirectDrawEnumerateExA(EmuEnumDisplayDevices, nullptr, DDENUM_ATTACHEDSECONDARYDEVICES);
DEBUG_D3DRESULT(hRet, "DirectDrawEnumerateExA");
// create DirectDraw7
{
if(FAILED(hRet)) {
hRet = DirectDrawCreateEx(nullptr, (void**)&g_pDD7, IID_IDirectDraw7, nullptr);
DEBUG_D3DRESULT(hRet, "DirectDrawCreateEx(NULL)");
} else {
hRet = DirectDrawCreateEx(&g_ddguid, (void**)&g_pDD7, IID_IDirectDraw7, nullptr);
DEBUG_D3DRESULT(hRet, "DirectDrawCreateEx(&g_ddguid)");
}
if(FAILED(hRet))
CxbxKrnlCleanup("Could not initialize DirectDraw7");
hRet = g_pDD7->GetCaps(&g_DriverCaps, nullptr);
// TODO : Why does this call return DDERR_INVALIDPARAMS, even when passing in a second argument?
DEBUG_D3DRESULT(hRet, "g_pDD7->GetCaps");
hRet = g_pDD7->SetCooperativeLevel(0, DDSCL_NORMAL);
DEBUG_D3DRESULT(hRet, "g_pDD7->SetCooperativeLevel");
if(FAILED(hRet))
CxbxKrnlCleanup("Could not set cooperative level");
}
// Dump all supported DirectDraw FourCC format codes
{
DWORD dwCodes = 0;
DWORD *lpCodes = nullptr;
g_pDD7->GetFourCCCodes(&dwCodes, lpCodes);
lpCodes = (DWORD*)malloc(dwCodes*sizeof(DWORD));
g_pDD7->GetFourCCCodes(&dwCodes, lpCodes);
for(DWORD v=0;v<dwCodes;v++)
{
EmuLog(LOG_LEVEL::DEBUG, "FourCC[%d] = %.4s", v, (char *)&(lpCodes[v]));
// Map known FourCC codes to Xbox Format
int X_Format;
switch (lpCodes[v]) {
case MAKEFOURCC('Y', 'U', 'Y', '2'):
X_Format = xbox::X_D3DFMT_YUY2;
break;
case MAKEFOURCC('U', 'Y', 'V', 'Y'):
X_Format = xbox::X_D3DFMT_UYVY;
break;
case MAKEFOURCC('D', 'X', 'T', '1'):
X_Format = xbox::X_D3DFMT_DXT1;
break;
case MAKEFOURCC('D', 'X', 'T', '3'):
X_Format = xbox::X_D3DFMT_DXT3;
break;
case MAKEFOURCC('D', 'X', 'T', '5'):
X_Format = xbox::X_D3DFMT_DXT5;
break;
default:
continue;
}
// Warn if CheckDeviceFormat didn't report this format
if (!g_bSupportsFormatTexture[X_Format]) {
EmuLog(LOG_LEVEL::WARNING, "FourCC format %.4s not previously detected via CheckDeviceFormat()! Enabling it.", (char *)&(lpCodes[v]));
// TODO : If this warning never shows, detecting FourCC's could be removed entirely. For now, enable the format :
g_bSupportsFormatTexture[X_Format] = true;
}
}
free(lpCodes);
}
// Can host driver create event queries?
if (SUCCEEDED(g_pD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, nullptr))) {
// Is host GPU query creation enabled?
if (!g_bHack_DisableHostGPUQueries) {
// Create a D3D event query to handle "wait-for-idle" with
hRet = g_pD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, &g_pHostQueryWaitForIdle);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->CreateQuery (wait for idle)");
// Create a D3D event query to handle "callback events" with
hRet = g_pD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, &g_pHostQueryCallbackEvent);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->CreateQuery (callback event)");
}
} else {
LOG_TEST_CASE("Can't CreateQuery(D3DQUERYTYPE_EVENT) on host!");
}
// Can host driver create occlusion queries?
g_bEnableHostQueryVisibilityTest = false;
if (SUCCEEDED(g_pD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, nullptr))) {
// Is host GPU query creation enabled?
if (!g_bHack_DisableHostGPUQueries) {
g_bEnableHostQueryVisibilityTest = true;
} else {
LOG_TEST_CASE("Disabled D3DQUERYTYPE_OCCLUSION on host!");
}
} else {
LOG_TEST_CASE("Can't CreateQuery(D3DQUERYTYPE_OCCLUSION) on host!");
}
hRet = g_pD3DDevice->CreateVertexBuffer
(
1, 0, 0, D3DPOOL_MANAGED,
&g_pDummyBuffer
, nullptr
);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->CreateVertexBuffer");
for(int HostStreamNumber = 0; HostStreamNumber < X_VSH_MAX_STREAMS; HostStreamNumber++)
{
hRet = g_pD3DDevice->SetStreamSource(HostStreamNumber, g_pDummyBuffer,
0, // OffsetInBytes
1);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetStreamSource");
}
// initially, show a black screen
// Only clear depth buffer and stencil if present
//
// Avoids following DirectX Debug Runtime error report
// [424] Direct3D8: (ERROR) :Invalid flag D3DCLEAR_ZBUFFER: no zbuffer is associated with device. Clear failed.
//
hRet = g_pD3DDevice->Clear(
/*Count=*/0,
/*pRects=*/nullptr,
D3DCLEAR_TARGET | (g_bHasDepth ? D3DCLEAR_ZBUFFER : 0) | (g_bHasStencil ? D3DCLEAR_STENCIL : 0),
/*Color=*/0xFF000000, // TODO : Use constant for this
/*Z=*/g_bHasDepth ? 1.0f : 0.0f,
/*Stencil=*/0);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->Clear");
hRet = g_pD3DDevice->BeginScene();
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->BeginScene");
hRet = g_pD3DDevice->EndScene();
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->EndScene");
hRet = g_pD3DDevice->Present(0, 0, 0, 0);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->Present");
// begin scene
hRet = g_pD3DDevice->BeginScene();
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->BeginScene(2nd)");
// Set up cache
g_VertexShaderSource.ResetD3DDevice(g_pD3DDevice);
}
// signal completion
g_EmuCDPD.bReady = false;
}
Sleep(1);
} }
return 0; if(params.Windowed)
{
D3DDISPLAYMODE D3DDisplayMode;
g_pDirect3D->GetAdapterDisplayMode(g_EmuCDPD.Adapter, &D3DDisplayMode);
params.BackBufferFormat = D3DDisplayMode.Format;
params.FullScreen_RefreshRateInHz = 0;
}
else
{
// In exclusive fullscreen mode, make *sure* to use the info that was in the resolution string
if (strcmp(szBackBufferFormat, "x1r5g5b5") == 0)
params.BackBufferFormat = D3DFMT_X1R5G5B5;
else if (strcmp(szBackBufferFormat, "r5g6r5") == 0)
params.BackBufferFormat = D3DFMT_R5G6B5;
else if (strcmp(szBackBufferFormat, "x8r8g8b8") == 0)
params.BackBufferFormat = D3DFMT_X8R8G8B8;
else if (strcmp(szBackBufferFormat, "a8r8g8b8") == 0)
params.BackBufferFormat = D3DFMT_A8R8G8B8;
}
} }
static void DetermineSupportedD3DFormats
(
)
{
memset(g_bSupportsFormatSurface, false, sizeof(g_bSupportsFormatSurface));
memset(g_bSupportsFormatSurfaceRenderTarget, false, sizeof(g_bSupportsFormatSurfaceRenderTarget));
memset(g_bSupportsFormatSurfaceDepthStencil, false, sizeof(g_bSupportsFormatSurfaceDepthStencil));
memset(g_bSupportsFormatTexture, false, sizeof(g_bSupportsFormatTexture));
memset(g_bSupportsFormatTextureRenderTarget, false, sizeof(g_bSupportsFormatTextureRenderTarget));
memset(g_bSupportsFormatTextureDepthStencil, false, sizeof(g_bSupportsFormatTextureDepthStencil));
memset(g_bSupportsFormatVolumeTexture, false, sizeof(g_bSupportsFormatVolumeTexture));
memset(g_bSupportsFormatCubeTexture, false, sizeof(g_bSupportsFormatCubeTexture));
for (int X_Format = xbox::X_D3DFMT_L8; X_Format <= xbox::X_D3DFMT_LIN_R8G8B8A8; X_Format++) {
// Only process Xbox formats that are directly mappable to host
if (!EmuXBFormatRequiresConversionToARGB((xbox::X_D3DFORMAT)X_Format)) {
// Convert the Xbox format into host format (without warning, thanks to the above restriction)
const D3DFORMAT PCFormat = EmuXB2PC_D3DFormat((xbox::X_D3DFORMAT)X_Format);
if (PCFormat != D3DFMT_UNKNOWN) {
// Index with Xbox D3DFormat, because host FourCC codes are too big to be used as indices
g_bSupportsFormatSurface[X_Format] = SUCCEEDED(g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, 0,
D3DRTYPE_SURFACE, PCFormat));
g_bSupportsFormatSurfaceRenderTarget[X_Format] = SUCCEEDED(g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, D3DUSAGE_RENDERTARGET,
D3DRTYPE_SURFACE, PCFormat));
g_bSupportsFormatSurfaceDepthStencil[X_Format] = SUCCEEDED(g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL,
D3DRTYPE_SURFACE, PCFormat));
g_bSupportsFormatTexture[X_Format] = SUCCEEDED(g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, 0,
D3DRTYPE_TEXTURE, PCFormat));
g_bSupportsFormatTextureRenderTarget[X_Format] = SUCCEEDED(g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, D3DUSAGE_RENDERTARGET,
D3DRTYPE_TEXTURE, PCFormat));
g_bSupportsFormatTextureDepthStencil[X_Format] = SUCCEEDED(g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL,
D3DRTYPE_TEXTURE, PCFormat));
g_bSupportsFormatVolumeTexture[X_Format] = SUCCEEDED(g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, 0,
D3DRTYPE_VOLUMETEXTURE, PCFormat));
g_bSupportsFormatCubeTexture[X_Format] = SUCCEEDED(g_pDirect3D->CheckDeviceFormat(
g_EmuCDPD.Adapter, g_EmuCDPD.DeviceType,
g_EmuCDPD.HostPresentationParameters.BackBufferFormat, 0,
D3DRTYPE_CUBETEXTURE, PCFormat));
}
}
}
}
static void DrawInitialBlackScreen
(
)
{
LOG_INIT;
// initially, show a black screen
// Only clear depth buffer and stencil if present
//
// Avoids following DirectX Debug Runtime error report
// [424] Direct3D8: (ERROR) :Invalid flag D3DCLEAR_ZBUFFER: no zbuffer is associated with device. Clear failed.
//
HRESULT hRet = g_pD3DDevice->Clear(
/*Count=*/0,
/*pRects=*/nullptr,
D3DCLEAR_TARGET | (g_bHasDepth ? D3DCLEAR_ZBUFFER : 0) | (g_bHasStencil ? D3DCLEAR_STENCIL : 0),
/*Color=*/0xFF000000, // TODO : Use constant for this
/*Z=*/g_bHasDepth ? 1.0f : 0.0f,
/*Stencil=*/0);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->Clear");
hRet = g_pD3DDevice->BeginScene();
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->BeginScene");
hRet = g_pD3DDevice->EndScene();
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->EndScene");
hRet = g_pD3DDevice->Present(0, 0, 0, 0);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->Present");
// begin scene
hRet = g_pD3DDevice->BeginScene();
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->BeginScene(2nd)");
}
static void CreateDefaultD3D9Device
(
const xbox::X_D3DPRESENT_PARAMETERS *pPresentationParameters
)
{
LOG_INIT;
// only one device should be created at once
if (g_pD3DDevice != nullptr) {
EmuLog(LOG_LEVEL::DEBUG, "CreateDefaultD3D9Device releasing old Device.");
g_pD3DDevice->EndScene();
ClearResourceCache(g_Cxbx_Cached_PaletizedTextures);
ClearResourceCache(g_Cxbx_Cached_Direct3DResources);
// TODO: ensure all other resources are cleaned up too
// Final release of IDirect3DDevice9 must be called from the window message thread
// See https://docs.microsoft.com/en-us/windows/win32/direct3d9/multithreading-issues
RunOnWndMsgThread([] {
g_pD3DDevice->Release();
});
}
// Apply render scale factor for high-resolution rendering
g_RenderUpscaleFactor = g_XBVideo.renderScaleFactor;
g_RenderTargetUpscaleFactor = 1;
// Setup the HostPresentationParameters
SetupPresentationParameters(pPresentationParameters);
// detect vertex processing capabilities
DWORD BehaviorFlags;
if((g_D3DCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) && g_EmuCDPD.DeviceType == D3DDEVTYPE_HAL)
{
EmuLog(LOG_LEVEL::DEBUG, "Using hardware vertex processing");
BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
else
{
EmuLog(LOG_LEVEL::DEBUG, "Using software vertex processing");
BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
// Dxbx addition : Prevent Direct3D from changing the FPU Control word :
BehaviorFlags |= D3DCREATE_FPU_PRESERVE;
// Direct3D8: (WARN) :Device that was created without D3DCREATE_MULTITHREADED is being used by a thread other than the creation thread.
BehaviorFlags |= D3DCREATE_MULTITHREADED;
// We never want auto-depth stencil on the host, Xbox D3D will handle this for us
g_EmuCDPD.HostPresentationParameters.EnableAutoDepthStencil = FALSE;
// IDirect3D9::CreateDevice must be called from the window message thread
// See https://docs.microsoft.com/en-us/windows/win32/direct3d9/multithreading-issues
HRESULT hr;
RunOnWndMsgThread([&hr, BehaviorFlags] {
hr = g_pDirect3D->CreateDevice(
g_EmuCDPD.Adapter,
g_EmuCDPD.DeviceType,
g_hEmuWindow,
BehaviorFlags,
&g_EmuCDPD.HostPresentationParameters,
&g_pD3DDevice);
});
DEBUG_D3DRESULT(hr, "IDirect3D::CreateDevice");
if(FAILED(hr))
CxbxKrnlCleanup("IDirect3D::CreateDevice failed");
// Which texture formats does this device support?
DetermineSupportedD3DFormats();
// Can host driver create event queries?
if (SUCCEEDED(g_pD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, nullptr))) {
// Is host GPU query creation enabled?
if (!g_bHack_DisableHostGPUQueries) {
// Create a D3D event query to handle "wait-for-idle" with
hr = g_pD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, &g_pHostQueryWaitForIdle);
DEBUG_D3DRESULT(hr, "g_pD3DDevice->CreateQuery (wait for idle)");
// Create a D3D event query to handle "callback events" with
hr = g_pD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, &g_pHostQueryCallbackEvent);
DEBUG_D3DRESULT(hr, "g_pD3DDevice->CreateQuery (callback event)");
}
} else {
LOG_TEST_CASE("Can't CreateQuery(D3DQUERYTYPE_EVENT) on host!");
}
// Can host driver create occlusion queries?
g_bEnableHostQueryVisibilityTest = false;
if (SUCCEEDED(g_pD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, nullptr))) {
// Is host GPU query creation enabled?
if (!g_bHack_DisableHostGPUQueries) {
g_bEnableHostQueryVisibilityTest = true;
} else {
LOG_TEST_CASE("Disabled D3DQUERYTYPE_OCCLUSION on host!");
}
} else {
LOG_TEST_CASE("Can't CreateQuery(D3DQUERYTYPE_OCCLUSION) on host!");
}
DrawInitialBlackScreen();
// Set up cache
g_VertexShaderSource.ResetD3DDevice(g_pD3DDevice);
}
// check if a resource has been registered yet (if not, register it) // check if a resource has been registered yet (if not, register it)
void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTextureStage, DWORD dwSize); // Forward declartion to prevent restructure of code void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTextureStage, DWORD dwSize); // Forward declartion to prevent restructure of code
static void EmuVerifyResourceIsRegistered(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTextureStage, DWORD dwSize) static void EmuVerifyResourceIsRegistered(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTextureStage, DWORD dwSize)
@ -2941,7 +2796,7 @@ void UpdateHostBackBufferDesc()
pCurrentHostBackBuffer->Release(); pCurrentHostBackBuffer->Release();
} }
void SetAspectRatioScale(xbox::X_D3DPRESENT_PARAMETERS* pPresentationParameters) void SetAspectRatioScale(const xbox::X_D3DPRESENT_PARAMETERS* pPresentationParameters)
{ {
// NOTE: Some games use anamorphic widesceen (expecting a 4:3 surface to be displayed at 16:9) // NOTE: Some games use anamorphic widesceen (expecting a 4:3 surface to be displayed at 16:9)
// For those, we *lie* about the default width, for the scaler // For those, we *lie* about the default width, for the scaler
@ -3082,7 +2937,7 @@ void GetRenderTargetBaseDimensions(float& x, float& y) {
void Direct3D_CreateDevice_Start void Direct3D_CreateDevice_Start
( (
xbox::X_D3DPRESENT_PARAMETERS *pPresentationParameters const xbox::X_D3DPRESENT_PARAMETERS *pPresentationParameters
) )
{ {
CxbxVertexShaderSetFlags(); CxbxVertexShaderSetFlags();
@ -3097,27 +2952,15 @@ void Direct3D_CreateDevice_Start
SetXboxMultiSampleType(pPresentationParameters->MultiSampleType); SetXboxMultiSampleType(pPresentationParameters->MultiSampleType);
// create default device *before* calling Xbox Direct3D_CreateDevice trampline // create default device *before* calling Xbox Direct3D_CreateDevice trampoline
// to avoid hitting EMUPATCH'es that need a valid g_pD3DDevice // to avoid hitting EMUPATCH'es that need a valid g_pD3DDevice
{ CreateDefaultD3D9Device(pPresentationParameters);
// Wait until proxy is done with an existing call (i highly doubt this situation will come up)
while (g_EmuCDPD.bReady)
Sleep(10);
// Cache parameters
memcpy(&(g_EmuCDPD.XboxPresentationParameters), pPresentationParameters, sizeof(xbox::X_D3DPRESENT_PARAMETERS));
// Signal proxy thread (this will trigger EmuCreateDeviceProxy to call CreateDevice)
g_EmuCDPD.bCreate = true;
g_EmuCDPD.bReady = true;
// Wait until host proxy is completed (otherwise, Xbox code could hit patches that need an assigned g_pD3DDevice)
while (g_EmuCDPD.bReady)
Sleep(10);
}
} }
void Direct3D_CreateDevice_End() void Direct3D_CreateDevice_End
(
const xbox::X_D3DPRESENT_PARAMETERS *pPresentationParameters
)
{ {
#if 0 // Unused : #if 0 // Unused :
// Set g_Xbox_D3DDevice to point to the Xbox D3D Device // Set g_Xbox_D3DDevice to point to the Xbox D3D Device
@ -3128,7 +2971,7 @@ void Direct3D_CreateDevice_End()
#endif #endif
UpdateHostBackBufferDesc(); UpdateHostBackBufferDesc();
SetAspectRatioScale(&g_EmuCDPD.XboxPresentationParameters); SetAspectRatioScale(pPresentationParameters);
// If the Xbox version of CreateDevice didn't call SetRenderTarget, we must derive the default backbuffer ourselves // If the Xbox version of CreateDevice didn't call SetRenderTarget, we must derive the default backbuffer ourselves
// This works because CreateDevice always sets the current render target to the Xbox Backbuffer // This works because CreateDevice always sets the current render target to the Xbox Backbuffer
@ -3231,7 +3074,7 @@ __declspec(naked) xbox::hresult_xt WINAPI xbox::EMUPATCH(Direct3D_CreateDevice_4
mov hRet, eax mov hRet, eax
} }
Direct3D_CreateDevice_End(); Direct3D_CreateDevice_End(pPresentationParameters);
__asm { __asm {
mov eax, hRet mov eax, hRet
@ -3302,7 +3145,7 @@ __declspec(naked) xbox::hresult_xt WINAPI xbox::EMUPATCH(Direct3D_CreateDevice_1
mov hRet, eax mov hRet, eax
} }
Direct3D_CreateDevice_End(); Direct3D_CreateDevice_End(pPresentationParameters);
__asm { __asm {
mov eax, hRet mov eax, hRet
@ -3373,7 +3216,7 @@ __declspec(naked) xbox::hresult_xt WINAPI xbox::EMUPATCH(Direct3D_CreateDevice_1
mov hRet, eax mov hRet, eax
} }
Direct3D_CreateDevice_End(); Direct3D_CreateDevice_End(pPresentationParameters);
__asm { __asm {
mov eax, hRet mov eax, hRet
@ -3458,7 +3301,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(Direct3D_CreateDevice)
// Only then call Xbox CreateDevice function // Only then call Xbox CreateDevice function
hresult_xt hRet = XB_TRMP(Direct3D_CreateDevice)(Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface); hresult_xt hRet = XB_TRMP(Direct3D_CreateDevice)(Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface);
Direct3D_CreateDevice_End(); Direct3D_CreateDevice_End(pPresentationParameters);
return hRet; return hRet;
} }