Skip to content

Commit f1ed5e3

Browse files
committed
D3D fix-up #1
1 parent 0f1cac6 commit f1ed5e3

File tree

5 files changed

+143
-132
lines changed

5 files changed

+143
-132
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*****************************************************************************
2+
*
3+
* PROJECT: Multi Theft Auto v1.0
4+
* LICENSE: See LICENSE in the top level directory
5+
* FILE: core/DXHook/CProxyComHelpers.h
6+
* PURPOSE: Shared COM interface helper functions for proxy classes
7+
*
8+
* Multi Theft Auto is available from https://www.multitheftauto.com/
9+
*
10+
*****************************************************************************/
11+
12+
#pragma once
13+
14+
#include "ComPtrValidation.h"
15+
16+
template <typename T>
17+
void ReleaseInterface(T*& pointer, int errorCode, const char* context = nullptr)
18+
{
19+
if (!pointer)
20+
return;
21+
22+
T* heldPointer = pointer;
23+
24+
const bool valid = IsValidComInterfacePointer(pointer, ComPtrValidation::ValidationMode::ForceRefresh);
25+
26+
if (!valid)
27+
{
28+
SString label;
29+
label = context ? context : "ReleaseInterface";
30+
SString message;
31+
message.Format("%s: calling Release on potentially invalid COM pointer %p", label.c_str(), heldPointer);
32+
AddReportLog(errorCode, message, 5);
33+
ComPtrValidation::Invalidate(heldPointer);
34+
}
35+
36+
heldPointer->Release();
37+
pointer = nullptr;
38+
}
39+
40+
template <typename T>
41+
void ReleaseInterface(T*& pointer)
42+
{
43+
if (pointer)
44+
{
45+
pointer->Release();
46+
pointer = nullptr;
47+
}
48+
}
49+
50+
template <typename T>
51+
void ReplaceInterface(T*& destination, T* source, int releaseErrorCode, int replaceErrorCode, const char* context = nullptr)
52+
{
53+
if (destination == source)
54+
return;
55+
56+
ReleaseInterface(destination, releaseErrorCode, context);
57+
58+
if (source && !IsValidComInterfacePointer(source, ComPtrValidation::ValidationMode::ForceRefresh))
59+
{
60+
SString label;
61+
label = context ? context : "ReplaceInterface";
62+
SString message;
63+
message.Format("%s: refusing to assign invalid COM pointer %p", label.c_str(), source);
64+
AddReportLog(replaceErrorCode, message, 5);
65+
destination = nullptr;
66+
return;
67+
}
68+
69+
destination = source;
70+
if (destination)
71+
destination->AddRef();
72+
}
73+
74+
template <typename T>
75+
void ReplaceInterface(T*& destination, T* source)
76+
{
77+
if (destination == source)
78+
return;
79+
80+
if (destination)
81+
{
82+
destination->Release();
83+
destination = nullptr;
84+
}
85+
86+
destination = source;
87+
if (destination)
88+
destination->AddRef();
89+
}
90+
91+
template <typename T>
92+
void ReplaceInterface(T*& destination, T* source, const char* context)
93+
{
94+
constexpr int GENERIC_COM_ERROR = 8799;
95+
ReplaceInterface(destination, source, GENERIC_COM_ERROR, GENERIC_COM_ERROR, context);
96+
}

Client/core/DXHook/CProxyDirect3D9.cpp

Lines changed: 26 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -10,62 +10,17 @@
1010
*****************************************************************************/
1111

1212
#include "StdInc.h"
13+
#include "CProxyComHelpers.h"
1314
#include "ComPtrValidation.h"
1415
#include <dwmapi.h>
16+
#include <mutex>
17+
#include <atomic>
1518
#include <resource.h>
1619

1720
extern HINSTANCE g_hModule;
1821

1922
namespace
2023
{
21-
template <typename T>
22-
void ReleaseInterface(T*& pointer, const char* context = nullptr)
23-
{
24-
if (!pointer)
25-
return;
26-
27-
T* heldPointer = pointer;
28-
29-
const bool valid = IsValidComInterfacePointer(pointer, ComPtrValidation::ValidationMode::ForceRefresh);
30-
31-
if (valid)
32-
{
33-
heldPointer->Release();
34-
}
35-
else
36-
{
37-
SString label;
38-
label = context ? context : "ReleaseInterface";
39-
SString message;
40-
message.Format("%s: skipping Release on invalid COM pointer %p", label.c_str(), heldPointer);
41-
AddReportLog(8752, message, 5);
42-
ComPtrValidation::Invalidate(heldPointer);
43-
}
44-
45-
pointer = nullptr;
46-
}
47-
48-
template <typename T>
49-
void ReplaceInterface(T*& destination, T* source, const char* context = nullptr)
50-
{
51-
if (destination == source)
52-
return;
53-
54-
if (source && !IsValidComInterfacePointer(source, ComPtrValidation::ValidationMode::ForceRefresh))
55-
{
56-
SString label;
57-
label = context ? context : "ReplaceInterface";
58-
SString message;
59-
message.Format("%s: rejected invalid COM pointer %p", label.c_str(), source);
60-
AddReportLog(8753, message, 5);
61-
return;
62-
}
63-
64-
ReleaseInterface(destination, context);
65-
destination = source;
66-
if (destination)
67-
destination->AddRef();
68-
}
6924

7025
IDirect3D9* GetFirstValidTrackedDirect3D(std::vector<IDirect3D9*>& trackedList)
7126
{
@@ -88,7 +43,9 @@ IDirect3D9* GetFirstValidTrackedDirect3D(std::vector<IDirect3D9*>& trackedList)
8843

8944
HRESULT HandleCreateDeviceResult(HRESULT hResult, IDirect3D9* pDirect3D, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags,
9045
D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface);
46+
9147
std::vector<IDirect3D9*> ms_CreatedDirect3D9List;
48+
std::mutex ms_Direct3D9ListMutex;
9249
bool CreateDeviceSecondCallCheck(HRESULT& hOutResult, IDirect3D9* pDirect3D, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags,
9350
D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface);
9451
void ApplyBorderlessColorCorrection(CProxyDirect3DDevice9* proxyDevice, const D3DPRESENT_PARAMETERS& presentationParameters);
@@ -108,15 +65,15 @@ CProxyDirect3D9::CProxyDirect3D9(IDirect3D9* pInterface)
10865
return;
10966
}
11067

111-
// Take ownership of the interface pointer
112-
// ReplaceInterface will AddRef(), giving us our own reference
113-
// Caller retains their reference
114-
ReplaceInterface(m_pDevice, pInterface, "CProxyDirect3D9 ctor");
68+
pInterface->AddRef();
69+
m_pDevice = pInterface;
11570

71+
// Track this Direct3D9 instance for StaticGetDirect3D() lookups
11672
if (m_pDevice)
11773
{
11874
if (IsValidComInterfacePointer(m_pDevice, ComPtrValidation::ValidationMode::ForceRefresh))
11975
{
76+
std::lock_guard<std::mutex> lock(ms_Direct3D9ListMutex);
12077
ms_CreatedDirect3D9List.push_back(m_pDevice);
12178
}
12279
else
@@ -131,8 +88,11 @@ CProxyDirect3D9::CProxyDirect3D9(IDirect3D9* pInterface)
13188
CProxyDirect3D9::~CProxyDirect3D9()
13289
{
13390
WriteDebugEvent(SString("CProxyDirect3D9::~CProxyDirect3D9 %08x", this));
134-
ListRemove(ms_CreatedDirect3D9List, m_pDevice);
135-
ReleaseInterface(m_pDevice, "CProxyDirect3D9 dtor");
91+
{
92+
std::lock_guard<std::mutex> lock(ms_Direct3D9ListMutex);
93+
ListRemove(ms_CreatedDirect3D9List, m_pDevice);
94+
}
95+
ReleaseInterface(m_pDevice, 8752);
13696
}
13797

13898
/*** IUnknown methods ***/
@@ -150,7 +110,7 @@ HRESULT CProxyDirect3D9::QueryInterface(REFIID riid, void** ppvObj)
150110

151111
ULONG CProxyDirect3D9::AddRef()
152112
{
153-
LONG lNewRefCount = InterlockedIncrement(&m_lRefCount);
113+
LONG lNewRefCount = m_lRefCount.fetch_add(1, std::memory_order_relaxed) + 1;
154114

155115
if (m_pDevice)
156116
m_pDevice->AddRef();
@@ -160,7 +120,7 @@ ULONG CProxyDirect3D9::AddRef()
160120

161121
ULONG CProxyDirect3D9::Release()
162122
{
163-
LONG lNewRefCount = InterlockedDecrement(&m_lRefCount);
123+
LONG lNewRefCount = m_lRefCount.fetch_sub(1, std::memory_order_acq_rel) - 1;
164124

165125
if (lNewRefCount < 0)
166126
{
@@ -276,6 +236,7 @@ HMONITOR CProxyDirect3D9::GetAdapterMonitor(UINT Adapter)
276236

277237
HMONITOR CProxyDirect3D9::StaticGetAdapterMonitor(UINT Adapter)
278238
{
239+
std::lock_guard<std::mutex> lock(ms_Direct3D9ListMutex);
279240
IDirect3D9* pDirect3D = GetFirstValidTrackedDirect3D(ms_CreatedDirect3D9List);
280241
if (!pDirect3D)
281242
return NULL;
@@ -285,6 +246,7 @@ HMONITOR CProxyDirect3D9::StaticGetAdapterMonitor(UINT Adapter)
285246

286247
IDirect3D9* CProxyDirect3D9::StaticGetDirect3D()
287248
{
249+
std::lock_guard<std::mutex> lock(ms_Direct3D9ListMutex);
288250
return GetFirstValidTrackedDirect3D(ms_CreatedDirect3D9List);
289251
}
290252

@@ -406,7 +368,7 @@ HRESULT CProxyDirect3D9::CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND
406368
SString message;
407369
message.Format("CProxyDirect3D9::CreateDevice - rejected invalid IDirect3DDevice9 pointer %p", pCreatedDevice);
408370
AddReportLog(8755, message, 5);
409-
ReleaseInterface(pCreatedDevice, "CProxyDirect3D9::CreateDevice invalid return");
371+
ReleaseInterface(pCreatedDevice, 8755, "CProxyDirect3D9::CreateDevice invalid return");
410372
*ppReturnedDeviceInterface = nullptr;
411373
hResult = D3DERR_INVALIDDEVICE;
412374
}
@@ -620,7 +582,7 @@ HRESULT CreateDeviceInsist(uint uiMinTries, uint uiTimeout, IDirect3D9* pDirect3
620582
SString message;
621583
message.Format("CreateDeviceInsist: rejected invalid IDirect3DDevice9 pointer %p", pCreatedDevice);
622584
AddReportLog(8755, message, 5);
623-
ReleaseInterface(pCreatedDevice, "CreateDeviceInsist invalid return");
585+
ReleaseInterface(pCreatedDevice, 8755, "CreateDeviceInsist invalid return");
624586
*ppReturnedDeviceInterface = nullptr;
625587
hResult = D3DERR_INVALIDDEVICE;
626588
}
@@ -902,7 +864,7 @@ void AddCapsReport(UINT Adapter, IDirect3D9* pDirect3D, IDirect3DDevice9* pD3DDe
902864
}
903865
}
904866

905-
ReleaseInterface(pDirect3DOther, "AddCapsReport GetDirect3D");
867+
ReleaseInterface(pDirect3DOther, 8799, "AddCapsReport GetDirect3D");
906868

907869
// Get caps from D3D
908870
D3DCAPS9 D3DCaps9;
@@ -936,7 +898,7 @@ void AddCapsReport(UINT Adapter, IDirect3D9* pDirect3D, IDirect3DDevice9* pD3DDe
936898
VertexElements[0].Type = DeclTypesList[i].VertexType;
937899
IDirect3DVertexDeclaration9* pD3DVertexDecl = nullptr;
938900
hr = pD3DDevice9->CreateVertexDeclaration(VertexElements, &pD3DVertexDecl);
939-
ReleaseInterface(pD3DVertexDecl, "AddCapsReport CreateVertexDeclaration");
901+
ReleaseInterface(pD3DVertexDecl, 8799, "AddCapsReport CreateVertexDeclaration");
940902

941903
// Check against device caps
942904
bool bCapsSaysOk = (DeviceCaps9.DeclTypes & DeclTypesList[i].CapsType) ? true : false;
@@ -1086,7 +1048,7 @@ HRESULT HandleCreateDeviceResult(HRESULT hResult, IDirect3D9* pDirect3D, UINT Ad
10861048
SString message;
10871049
message.Format("HandleCreateDeviceResult: rejected invalid IDirect3DDevice9 pointer %p", pCreatedDevice);
10881050
AddReportLog(8755, message, 5);
1089-
ReleaseInterface(pCreatedDevice, "HandleCreateDeviceResult invalid return");
1051+
ReleaseInterface(pCreatedDevice, 8755, "HandleCreateDeviceResult invalid return");
10901052
*ppReturnedDeviceInterface = nullptr;
10911053
hResult = D3DERR_INVALIDDEVICE;
10921054
}
@@ -1218,7 +1180,7 @@ void CCore::OnPreCreateDevice(IDirect3D9* pDirect3D, UINT Adapter, D3DDEVTYPE De
12181180
WriteDebugEvent(ToString(Adapter, DeviceType, hFocusWindow, BehaviorFlags, *pPresentationParameters));
12191181
IDirect3DDevice9* pReturnedDeviceInterface = NULL;
12201182
HRESULT hResult = pDirect3D->CreateDevice(Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, &pReturnedDeviceInterface);
1221-
ReleaseInterface(pReturnedDeviceInterface, "CCore::OnPreCreateDevice temp release");
1183+
ReleaseInterface(pReturnedDeviceInterface, 8799, "CCore::OnPreCreateDevice temp release");
12221184
WriteDebugEvent(SString(" Unmodified result is: %08x", hResult));
12231185
}
12241186

@@ -1298,7 +1260,7 @@ HRESULT CCore::OnPostCreateDevice(HRESULT hResult, IDirect3D9* pDirect3D, UINT A
12981260

12991261
AddCapsReport(Adapter, pDirect3D, pDevice, false);
13001262

1301-
ReleaseInterface(pDevice, "CCore::OnPostCreateDevice temp release");
1263+
ReleaseInterface(pDevice, 8799, "CCore::OnPostCreateDevice temp release");
13021264
*ppReturnedDeviceInterface = pDevice;
13031265

13041266
//
@@ -1341,7 +1303,7 @@ HRESULT CCore::OnPostCreateDevice(HRESULT hResult, IDirect3D9* pDirect3D, UINT A
13411303
{
13421304
AddReportLog(8755,
13431305
SString("CCore::OnPostCreateDevice: rejected invalid IDirect3DDevice9 pointer %p", pCreatedDevice), 5);
1344-
ReleaseInterface(pCreatedDevice, "CCore::OnPostCreateDevice invalid return");
1306+
ReleaseInterface(pCreatedDevice, 8755, "CCore::OnPostCreateDevice invalid return");
13451307
*ppReturnedDeviceInterface = nullptr;
13461308
hResult = D3DERR_INVALIDDEVICE;
13471309
}

Client/core/DXHook/CProxyDirect3D9.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,5 @@ class CProxyDirect3D9 : public IDirect3D9
4949

5050
private:
5151
IDirect3D9* m_pDevice;
52-
volatile LONG m_lRefCount;
52+
std::atomic<LONG> m_lRefCount;
5353
};

0 commit comments

Comments
 (0)