Skip to content

Commit

Permalink
Simplify creating Direct3D9 from another thread
Browse files Browse the repository at this point in the history
  • Loading branch information
elishacloud committed Nov 8, 2024
1 parent 38d6363 commit 9eaac52
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 81 deletions.
2 changes: 1 addition & 1 deletion Dllmain/BuildNo.rc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#define BUILD_NUMBER 7309
#define BUILD_NUMBER 7310
16 changes: 3 additions & 13 deletions GDI/WndProc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <algorithm>
#include "WndProc.h"
#include "GDI.h"
#include "ddraw\ddraw.h"
#include "ddraw\ddrawExternal.h"
#include "Settings\Settings.h"
#include "Logging\Logging.h"
Expand Down Expand Up @@ -248,20 +249,9 @@ LRESULT CALLBACK WndProc::Handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lPa
}

// Handle Direct3D9 device creation
if (Msg == WM_USER_CREATE_D3D9_DEVICE)
if (Msg == WM_USER_CREATE_D3D9_DEVICE && CheckDirectDrawXInterface((void*)wParam))
{
// Verify call is coming from m_IDirectDrawX interface
if (!CheckDirectDrawXInterface((void*)wParam))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: invalid m_IDirectDrawX interface!");
return NULL;
}

D9_DEVICE_CREATION* pDeviceStruct = (D9_DEVICE_CREATION*)lParam;

pDeviceStruct->hr = CreateDeviceV9(pDeviceStruct->d3d9Object, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, pDeviceStruct->hWnd, pDeviceStruct->BehaviorFlags, pDeviceStruct->presParams, pDeviceStruct->d3d9Device);

SetEvent(pDeviceStruct->hEvent);
((m_IDirectDrawX*)wParam)->CreateD9Device(__FUNCTION__);

return NULL;
}
Expand Down
11 changes: 0 additions & 11 deletions GDI/WndProc.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#pragma once

#include "d3d9\d3d9External.h"
#include <atomic>

#define WM_USER_CREATE_D3D9_DEVICE (WM_APP + 0x1234)
Expand All @@ -19,13 +18,3 @@ namespace WndProc
void RemoveWndProc(HWND hWnd);
DATASTRUCT* GetWndProctStruct(HWND hWnd);
}

struct D9_DEVICE_CREATION {
HWND hWnd = nullptr;
DWORD BehaviorFlags = 0;
LPDIRECT3D9 d3d9Object = nullptr;
LPDIRECT3DDEVICE9* d3d9Device = nullptr;
D3DPRESENT_PARAMETERS* presParams = nullptr;
HANDLE hEvent = nullptr;
HRESULT hr = E_FAIL;
};
76 changes: 22 additions & 54 deletions ddraw/IDirectDrawX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1711,7 +1711,7 @@ HRESULT m_IDirectDrawX::SetCooperativeLevel(HWND hWnd, DWORD dwFlags, DWORD Dire
}

// Check if handle is valid
if (IsWindow(DisplayMode.hWnd) && DisplayMode.hWnd == hWnd)
if (IsWindow(DisplayMode.hWnd) && (DisplayMode.hWnd == hWnd || (!hWnd && (dwFlags & DDSCL_FPUPRESERVE))))
{
// Set exclusive mode resolution
if (ExclusiveMode && DisplayMode.Width && DisplayMode.Height && DisplayMode.BPP)
Expand Down Expand Up @@ -3064,17 +3064,6 @@ HRESULT m_IDirectDrawX::ResetD9Device()
return hr;
}

HRESULT CreateDeviceV9(IDirect3D9* Object, UINT Adapter, D3DDEVTYPE DeviceType, HWND FocusWindow, DWORD Flags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface)
{
HRESULT hr = Object->CreateDevice(Adapter, DeviceType, FocusWindow, Flags, pPresentationParameters, ppReturnedDeviceInterface);
if (FAILED(hr) && pPresentationParameters && pPresentationParameters->FullScreen_RefreshRateInHz)
{
pPresentationParameters->FullScreen_RefreshRateInHz = 0;
hr = Object->CreateDevice(Adapter, DeviceType, FocusWindow, Flags, pPresentationParameters, ppReturnedDeviceInterface);
}
return hr;
}

// Creates or resets the d3d9 device
HRESULT m_IDirectDrawX::CreateD9Device(char* FunctionName)
{
Expand All @@ -3092,31 +3081,39 @@ HRESULT m_IDirectDrawX::CreateD9Device(char* FunctionName)
return D3DERR_DEVICELOST;
}

// Get hwnd
HWND hWnd = GetHwnd();

// Hook WndProc before creating device
WndProc::DATASTRUCT* WndDataStruct = WndProc::AddWndProc(hWnd);
if (WndDataStruct) WndDataStruct->IsDirectDraw = true;

// Check if creating from another thread
if (WndDataStruct && GetWindowThreadProcessId(hWnd, nullptr) != GetCurrentThreadId())
{
LOG_LIMIT(100, __FUNCTION__ << " " << FunctionName << " Warning: trying to create Direct3D9 device from a different thread than the hwnd was created from!");

SendMessage(hWnd, WM_USER_CREATE_D3D9_DEVICE, (WPARAM)this, WM_NULL);

return d3d9Device ? DD_OK : DDERR_GENERIC;
}

SetCriticalSection();
SetPTCriticalSection();

WndProc::DATASTRUCT* WndDataStruct = nullptr;

HRESULT hr = DD_OK;
do {
// Last call variables
HWND LastHWnd = hFocusWindow;
BOOL LastWindowedMode = presParams.Windowed;
DWORD LastBehaviorFlags = BehaviorFlags;

// Get hwnd
HWND hWnd = GetHwnd();

// Store new focus window
hFocusWindow = hWnd;

// Check active
bool WndLastActive = (hWnd == GetForegroundWindow() && hWnd == GetFocus() && hWnd == GetActiveWindow());

// Hook WndProc before creating device
WndDataStruct = WndProc::AddWndProc(hWnd);
if (WndDataStruct) WndDataStruct->IsDirectDraw = true;

// Get current resolution and rect
DWORD CurrentWidth = 0, CurrentHeight = 0;
Utils::GetScreenSize(hWnd, (LONG&)CurrentWidth, (LONG&)CurrentHeight);
Expand Down Expand Up @@ -3277,38 +3274,11 @@ HRESULT m_IDirectDrawX::CreateD9Device(char* FunctionName)

if (WndDataStruct) WndDataStruct->IsCreatingD3d9 = true;

// Check window handle thread
if (WndDataStruct && GetWindowThreadProcessId(hWnd, nullptr) != GetCurrentThreadId())
{
LOG_LIMIT(100, __FUNCTION__ << " " << FunctionName << " Warning: trying to create Direct3D9 device from a different thread than the hwnd was created from!");

HANDLE hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);

if (!hEvent)
{
LOG_LIMIT(100, __FUNCTION__ << " Error: failed to create event handle!");
hr = DDERR_GENERIC;
break;
}

D9_DEVICE_CREATION DeviceStruct;
DeviceStruct.hWnd = hWnd;
DeviceStruct.BehaviorFlags = BehaviorFlags;
DeviceStruct.d3d9Object = d3d9Object;
DeviceStruct.d3d9Device = &d3d9Device;
DeviceStruct.presParams = &presParams;
DeviceStruct.hEvent = hEvent;

PostMessage(hWnd, WM_USER_CREATE_D3D9_DEVICE, (WPARAM)this, (LPARAM)&DeviceStruct);
WaitForSingleObject(hEvent, INFINITE);

hr = DeviceStruct.hr;

CloseHandle(hEvent);
}
else
hr = d3d9Object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, BehaviorFlags, &presParams, &d3d9Device);
if (FAILED(hr) && presParams.FullScreen_RefreshRateInHz)
{
hr = CreateDeviceV9(d3d9Object, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, BehaviorFlags, &presParams, &d3d9Device);
presParams.FullScreen_RefreshRateInHz = 0;
hr = d3d9Object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, BehaviorFlags, &presParams, &d3d9Device);
}

if (WndDataStruct) WndDataStruct->IsCreatingD3d9 = false;
Expand Down Expand Up @@ -3404,8 +3374,6 @@ HRESULT m_IDirectDrawX::CreateD9Device(char* FunctionName)

} while (false);

if (WndDataStruct) WndDataStruct->IsCreatingD3d9 = false;

ReleasePTCriticalSection();
ReleaseCriticalSection();

Expand Down
2 changes: 0 additions & 2 deletions ddraw/ddrawExternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ HRESULT WINAPI dd_RegisterSpecialCase(DWORD arg1, DWORD arg2, DWORD arg3, DWORD
HRESULT WINAPI dd_ReleaseDDThreadLock();
HRESULT WINAPI dd_SetAppCompatData(DWORD Type, DWORD Value);

HRESULT CreateDeviceV9(IDirect3D9* Object, UINT Adapter, D3DDEVTYPE DeviceType, HWND FocusWindow, DWORD Flags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface);

bool CheckDirectDrawXInterface(void* pInterface);

class m_IDirectDrawClipper;
Expand Down

0 comments on commit 9eaac52

Please sign in to comment.