Skip to content

Commit 0a0a685

Browse files
committed
Different approach for 8e4f245 (Fix vertex buffer lock failures)
1 parent e0ae3d9 commit 0a0a685

File tree

2 files changed

+35
-244
lines changed

2 files changed

+35
-244
lines changed

Client/core/DXHook/CProxyDirect3DVertexBuffer.cpp

Lines changed: 34 additions & 224 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,6 @@
1414
#include "CAdditionalVertexStreamManager.h"
1515
#include "CVertexStreamBoundingBoxManager.h"
1616

17-
#include <algorithm>
18-
#include <array>
19-
#include <cstring>
20-
#include <new>
21-
2217
/////////////////////////////////////////////////////////////
2318
//
2419
// CProxyDirect3DVertexBuffer::CProxyDirect3DVertexBuffer
@@ -114,50 +109,40 @@ HRESULT CProxyDirect3DVertexBuffer::Lock(UINT OffsetToLock, UINT SizeToLock, voi
114109
CVertexStreamBoundingBoxManager::GetSingleton()->OnVertexBufferRangeInvalidated(m_pOriginal, OffsetToLock, SizeToLock);
115110
}
116111

117-
ClearFallbackLock();
118-
119112
*ppbData = NULL;
113+
HRESULT hr = DoLock(OffsetToLock, SizeToLock, ppbData, Flags);
114+
HRESULT originalHr = hr;
120115

121-
const UINT clampedSize = ClampLockSize(OffsetToLock, SizeToLock);
122-
123-
HRESULT hr = DoLock(OffsetToLock, clampedSize, ppbData, Flags);
124-
if (SUCCEEDED(hr) && *ppbData != NULL)
125-
return hr;
126-
127-
HRESULT recoveryHr = TryRecoverLock(OffsetToLock, clampedSize, ppbData, Flags, hr);
128-
if (SUCCEEDED(recoveryHr) && *ppbData != NULL)
129-
return recoveryHr;
130-
131-
HRESULT finalHr = FAILED(recoveryHr) ? recoveryHr : hr;
132-
HRESULT fallbackHr = ActivateFallbackLock(OffsetToLock, clampedSize, ppbData, Flags, finalHr);
133-
if (SUCCEEDED(fallbackHr) && *ppbData != NULL)
134-
return fallbackHr;
135-
136-
if (FAILED(fallbackHr))
137-
finalHr = fallbackHr;
138-
139-
struct
116+
if (SUCCEEDED(hr) && *ppbData == NULL)
140117
{
141-
const char* szText;
142-
uint uiReportId;
143-
uint uiLogEventId;
144-
} info;
145-
if (finalHr == D3D_OK)
146-
info = {"result NULL", 8621, 621};
147-
else if (finalHr == STATUS_ARRAY_BOUNDS_EXCEEDED)
148-
info = {"offset out of range", 8622, 622};
149-
else if (finalHr == STATUS_ACCESS_VIOLATION)
150-
info = {"access violation", 8623, 623};
151-
else
152-
info = {"fail", 8620, 620};
118+
hr = D3DERR_INVALIDCALL;
119+
}
153120

154-
SString strMessage("Lock VertexBuffer [%s] hr:%x Length:%x Usage:%x FVF:%x Pool:%x OffsetToLock:%x SizeToLock:%x Flags:%x", info.szText, finalHr, m_iMemUsed,
155-
m_dwUsage, m_dwFVF, m_pool, OffsetToLock, clampedSize, Flags);
156-
WriteDebugEvent(strMessage);
157-
AddReportLog(info.uiReportId, strMessage);
158-
CCore::GetSingleton().LogEvent(info.uiLogEventId, "Lock VertexBuffer", "", strMessage);
121+
// Report problems
122+
if (FAILED(hr))
123+
{
124+
struct
125+
{
126+
const char* szText;
127+
uint uiReportId;
128+
uint uiLogEventId;
129+
} info;
130+
if (hr == D3DERR_INVALIDCALL && originalHr == D3D_OK)
131+
info = {"result NULL", 8621, 621};
132+
else if (hr == STATUS_ARRAY_BOUNDS_EXCEEDED)
133+
info = {"offset out of range", 8622, 622};
134+
else if (hr == STATUS_ACCESS_VIOLATION)
135+
info = {"access violation", 8623, 623};
136+
else
137+
info = {"fail", 8620, 620};
159138

160-
return finalHr;
139+
SString strMessage("Lock VertexBuffer [%s] hr:%x origHr:%x Length:%x Usage:%x FVF:%x Pool:%x OffsetToLock:%x SizeToLock:%x Flags:%x", info.szText, hr,
140+
originalHr, m_iMemUsed, m_dwUsage, m_dwFVF, m_pool, OffsetToLock, SizeToLock, Flags);
141+
WriteDebugEvent(strMessage);
142+
AddReportLog(info.uiReportId, strMessage);
143+
CCore::GetSingleton().LogEvent(info.uiLogEventId, "Lock VertexBuffer", "", strMessage);
144+
}
145+
return hr;
161146
}
162147

163148
/////////////////////////////////////////////////////////////
@@ -169,197 +154,22 @@ HRESULT CProxyDirect3DVertexBuffer::Lock(UINT OffsetToLock, UINT SizeToLock, voi
169154
/////////////////////////////////////////////////////////////
170155
HRESULT CProxyDirect3DVertexBuffer::DoLock(UINT OffsetToLock, UINT SizeToLock, void** ppbData, DWORD Flags)
171156
{
172-
if (OffsetToLock >= m_iMemUsed)
173-
return STATUS_ARRAY_BOUNDS_EXCEEDED;
174-
175-
UINT adjustedSize = ClampLockSize(OffsetToLock, SizeToLock);
176-
if (adjustedSize == 0)
177-
return STATUS_ARRAY_BOUNDS_EXCEEDED;
178-
179-
return LockInternal(OffsetToLock, adjustedSize, ppbData, Flags);
180-
}
181-
182-
HRESULT CProxyDirect3DVertexBuffer::Unlock()
183-
{
184-
if (!m_fallbackLock.active)
185-
return m_pOriginal->Unlock();
186-
187-
HRESULT copyHr = D3D_OK;
188-
189-
if ((m_fallbackLock.flags & D3DLOCK_READONLY) == 0 && m_fallbackLock.size > 0 && !m_fallbackLock.buffer.empty())
157+
// Validate sizes because gta can give invalid values (reason unknown)
158+
if (OffsetToLock + SizeToLock > m_iMemUsed)
190159
{
191-
void* pDestination = NULL;
192-
copyHr = LockInternal(m_fallbackLock.offset, m_fallbackLock.size, &pDestination, 0);
193-
if (SUCCEEDED(copyHr) && pDestination != NULL)
160+
if (OffsetToLock > m_iMemUsed)
194161
{
195-
std::memcpy(pDestination, m_fallbackLock.buffer.data(), m_fallbackLock.size);
196-
HRESULT unlockHr = m_pOriginal->Unlock();
197-
if (FAILED(unlockHr))
198-
{
199-
copyHr = unlockHr;
200-
SString strMessage("Unlock VertexBuffer [fallback unlock failed] hr:%x Length:%x Usage:%x FVF:%x Pool:%x Offset:%x Size:%x", unlockHr, m_iMemUsed,
201-
m_dwUsage, m_dwFVF, m_pool, m_fallbackLock.offset, m_fallbackLock.size);
202-
WriteDebugEvent(strMessage);
203-
AddReportLog(8627, strMessage);
204-
CCore::GetSingleton().LogEvent(627, "Unlock VertexBuffer", "", strMessage);
205-
}
206-
}
207-
else
208-
{
209-
if (SUCCEEDED(copyHr) && pDestination == NULL)
210-
copyHr = D3DERR_INVALIDCALL;
211-
212-
SString strMessage("Unlock VertexBuffer [fallback copy failed] hr:%x Length:%x Usage:%x FVF:%x Pool:%x Offset:%x Size:%x", copyHr, m_iMemUsed, m_dwUsage,
213-
m_dwFVF, m_pool, m_fallbackLock.offset, m_fallbackLock.size);
214-
WriteDebugEvent(strMessage);
215-
AddReportLog(8626, strMessage);
216-
CCore::GetSingleton().LogEvent(626, "Unlock VertexBuffer", "", strMessage);
162+
return STATUS_ARRAY_BOUNDS_EXCEEDED;
217163
}
164+
SizeToLock = m_iMemUsed - OffsetToLock;
218165
}
219166

220-
ClearFallbackLock();
221-
return D3D_OK;
222-
}
223-
224-
UINT CProxyDirect3DVertexBuffer::ClampLockSize(UINT OffsetToLock, UINT SizeToLock) const
225-
{
226-
if (OffsetToLock >= m_iMemUsed)
227-
return 0;
228-
229-
const UINT available = static_cast<UINT>(m_iMemUsed - OffsetToLock);
230-
if (available == 0)
231-
return 0;
232-
233-
if (SizeToLock == 0)
234-
return available;
235-
236-
return std::min(SizeToLock, available);
237-
}
238-
239-
HRESULT CProxyDirect3DVertexBuffer::LockInternal(UINT OffsetToLock, UINT SizeToLock, void** ppbData, DWORD Flags)
240-
{
241-
if (ppbData == NULL)
242-
return E_INVALIDARG;
243-
244-
*ppbData = NULL;
245-
246167
__try
247168
{
248169
return m_pOriginal->Lock(OffsetToLock, SizeToLock, ppbData, Flags);
249170
}
250171
__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
251172
{
252-
*ppbData = NULL;
253173
return STATUS_ACCESS_VIOLATION;
254174
}
255175
}
256-
257-
HRESULT CProxyDirect3DVertexBuffer::TryRecoverLock(UINT OffsetToLock, UINT SizeToLock, void** ppbData, DWORD Flags, HRESULT originalHr)
258-
{
259-
HRESULT lastHr = originalHr;
260-
261-
struct SLockAttempt
262-
{
263-
DWORD flags;
264-
UINT offset;
265-
UINT size;
266-
bool adjustPointer;
267-
};
268-
269-
std::array<SLockAttempt, 7> attempts = {
270-
SLockAttempt{Flags & ~D3DLOCK_DONOTWAIT, OffsetToLock, SizeToLock, false},
271-
SLockAttempt{Flags & ~D3DLOCK_NOOVERWRITE, OffsetToLock, SizeToLock, false},
272-
SLockAttempt{Flags & ~D3DLOCK_DISCARD, OffsetToLock, SizeToLock, false},
273-
SLockAttempt{Flags & ~(D3DLOCK_DONOTWAIT | D3DLOCK_NOOVERWRITE), OffsetToLock, SizeToLock, false},
274-
SLockAttempt{Flags & ~(D3DLOCK_DONOTWAIT | D3DLOCK_NOOVERWRITE | D3DLOCK_NO_DIRTY_UPDATE), OffsetToLock, SizeToLock, false},
275-
SLockAttempt{0u, OffsetToLock, SizeToLock, false},
276-
SLockAttempt{0u, 0u, static_cast<UINT>(m_iMemUsed), true},
277-
};
278-
279-
for (const SLockAttempt& attempt : attempts)
280-
{
281-
if (attempt.flags == Flags && attempt.offset == OffsetToLock && attempt.size == SizeToLock)
282-
continue;
283-
284-
if (attempt.size > m_iMemUsed)
285-
continue;
286-
287-
UINT clampedSize = ClampLockSize(attempt.offset, attempt.size);
288-
if (clampedSize == 0)
289-
continue;
290-
291-
void* pRecovered = NULL;
292-
HRESULT hr = LockInternal(attempt.offset, clampedSize, &pRecovered, attempt.flags);
293-
if (SUCCEEDED(hr) && pRecovered != NULL)
294-
{
295-
if (attempt.adjustPointer)
296-
{
297-
UINT pointerOffset = 0;
298-
if (OffsetToLock > attempt.offset)
299-
pointerOffset = OffsetToLock - attempt.offset;
300-
if (pointerOffset >= clampedSize)
301-
{
302-
lastHr = hr;
303-
continue;
304-
}
305-
pRecovered = static_cast<void*>(static_cast<std::uint8_t*>(pRecovered) + pointerOffset);
306-
}
307-
308-
*ppbData = pRecovered;
309-
310-
SString strMessage("Lock VertexBuffer [retry] hr:%x->%x Length:%x Usage:%x FVF:%x Pool:%x Offset:%x Size:%x Flags:%x->%x", originalHr, hr, m_iMemUsed,
311-
m_dwUsage, m_dwFVF, m_pool, OffsetToLock, SizeToLock, Flags, attempt.flags);
312-
WriteDebugEvent(strMessage);
313-
AddReportLog(8625, strMessage);
314-
CCore::GetSingleton().LogEvent(625, "Lock VertexBuffer", "", strMessage);
315-
316-
return hr;
317-
}
318-
319-
lastHr = hr;
320-
}
321-
322-
return lastHr;
323-
}
324-
325-
HRESULT CProxyDirect3DVertexBuffer::ActivateFallbackLock(UINT OffsetToLock, UINT SizeToLock, void** ppbData, DWORD Flags, HRESULT originalHr)
326-
{
327-
if (ppbData == NULL)
328-
return originalHr;
329-
330-
UINT clampedSize = ClampLockSize(OffsetToLock, SizeToLock);
331-
if (clampedSize == 0)
332-
return originalHr;
333-
334-
try
335-
{
336-
m_fallbackLock.buffer.resize(clampedSize);
337-
}
338-
catch (const std::bad_alloc&)
339-
{
340-
return E_OUTOFMEMORY;
341-
}
342-
343-
m_fallbackLock.active = true;
344-
m_fallbackLock.offset = OffsetToLock;
345-
m_fallbackLock.size = clampedSize;
346-
m_fallbackLock.flags = Flags;
347-
348-
*ppbData = m_fallbackLock.buffer.data();
349-
350-
SString strMessage("Lock VertexBuffer [fallback] hr:%x Length:%x Usage:%x FVF:%x Pool:%x OffsetToLock:%x SizeToLock:%x Flags:%x", originalHr, m_iMemUsed,
351-
m_dwUsage, m_dwFVF, m_pool, OffsetToLock, clampedSize, Flags);
352-
WriteDebugEvent(strMessage);
353-
AddReportLog(8624, strMessage);
354-
CCore::GetSingleton().LogEvent(624, "Lock VertexBuffer", "", strMessage);
355-
356-
return D3D_OK;
357-
}
358-
359-
void CProxyDirect3DVertexBuffer::ClearFallbackLock()
360-
{
361-
m_fallbackLock.active = false;
362-
m_fallbackLock.offset = 0;
363-
m_fallbackLock.size = 0;
364-
m_fallbackLock.flags = 0;
365-
}

Client/core/DXHook/CProxyDirect3DVertexBuffer.h

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
#pragma once
1313

1414
#include <d3d9.h>
15-
#include <vector>
16-
#include <cstdint>
1715
#include "CProxyDirect3DDevice9.h" // Include full definition for SResourceMemory
1816

1917
DEFINE_GUID(CProxyDirect3DVertexBuffer_GUID, 0x128A025E, 0x0100, 0x04F1, 0x40, 0x60, 0x53, 0x19, 0x44, 0x56, 0x59, 0x42);
@@ -41,7 +39,7 @@ class CProxyDirect3DVertexBuffer : public IDirect3DVertexBuffer9
4139

4240
/*** IDirect3DVertexBuffer9 methods ***/
4341
HRESULT __stdcall Lock(UINT OffsetToLock, UINT SizeToLock, void** ppbData, DWORD Flags);
44-
HRESULT __stdcall Unlock();
42+
HRESULT __stdcall Unlock() { return m_pOriginal->Unlock(); }
4543
HRESULT __stdcall GetDesc(D3DVERTEXBUFFER_DESC* pDesc) { return m_pOriginal->GetDesc(pDesc); }
4644

4745
// CProxyDirect3DVertexBuffer
@@ -51,28 +49,11 @@ class CProxyDirect3DVertexBuffer : public IDirect3DVertexBuffer9
5149
IDirect3DVertexBuffer9* GetOriginal() { return m_pOriginal; }
5250
HRESULT DoLock(UINT OffsetToLock, UINT SizeToLock, void** ppbData, DWORD Flags);
5351

54-
private:
55-
struct SFallbackLock
56-
{
57-
bool active = false;
58-
UINT offset = 0;
59-
UINT size = 0;
60-
DWORD flags = 0;
61-
std::vector<std::uint8_t> buffer;
62-
};
63-
64-
UINT ClampLockSize(UINT OffsetToLock, UINT SizeToLock) const;
65-
HRESULT LockInternal(UINT OffsetToLock, UINT SizeToLock, void** ppbData, DWORD Flags);
66-
HRESULT TryRecoverLock(UINT OffsetToLock, UINT SizeToLock, void** ppbData, DWORD Flags, HRESULT originalHr);
67-
HRESULT ActivateFallbackLock(UINT OffsetToLock, UINT SizeToLock, void** ppbData, DWORD Flags, HRESULT originalHr);
68-
void ClearFallbackLock();
69-
7052
protected:
7153
IDirect3DVertexBuffer9* m_pOriginal;
7254
uint m_iMemUsed;
7355
DWORD m_dwUsage;
7456
DWORD m_dwFVF;
7557
D3DPOOL m_pool;
7658
CProxyDirect3DDevice9::SResourceMemory& m_stats;
77-
SFallbackLock m_fallbackLock;
7859
};

0 commit comments

Comments
 (0)