Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 80 additions & 70 deletions Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ bool DX8Wrapper::IsRenderToTexture = false;
unsigned DX8Wrapper::_MainThreadID = 0;
bool DX8Wrapper::CurrentDX8LightEnables[4];
bool DX8Wrapper::IsDeviceLost;
bool DX8Wrapper::DeviceResetFailed = false;
int DX8Wrapper::ZBias;
float DX8Wrapper::ZNear;
float DX8Wrapper::ZFar;
Expand Down Expand Up @@ -345,16 +346,12 @@ void DX8Wrapper::Shutdown()

}

if (CurrentCaps)
for (size_t i = 0; i < ARRAY_SIZE(Textures); ++i)
{
int max = CurrentCaps->Get_Max_Textures_Per_Pass();
for (int i = 0; i < max; i++)
if (Textures[i])
{
if (Textures[i])
{
Textures[i]->Release();
Textures[i] = nullptr;
}
Textures[i]->Release();
Textures[i] = nullptr;
}
}

Expand Down Expand Up @@ -436,7 +433,7 @@ void DX8Wrapper::Invalidate_Cached_Render_States()
}
//Need to explicitly set texture to null, otherwise app will not be able to
//set it to null because of redundant state checker. MW
if (_Get_D3D_Device8())
if (_Get_D3D_Device8() && !DeviceResetFailed)
_Get_D3D_Device8()->SetTexture(a, nullptr);
if (Textures[a] != nullptr) {
Textures[a]->Release();
Expand Down Expand Up @@ -490,6 +487,7 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns()
bool DX8Wrapper::Create_Device()
{
WWASSERT(D3DDevice == nullptr); // for now, once you've created a device, you're stuck with it!
DeviceResetFailed = false;

D3DCAPS8 caps;
if
Expand Down Expand Up @@ -610,83 +608,95 @@ bool DX8Wrapper::Reset_Device(bool reload_assets)
{
WWDEBUG_SAY(("Resetting device."));
DX8_THREAD_ASSERT();
if ((IsInitted) && (D3DDevice != nullptr)) {
// Release all non-MANAGED stuff
WW3D::_Invalidate_Textures();
if (!IsInitted || D3DDevice == nullptr) {
WWDEBUG_SAY(("Device reset failed"));
return false;
}

for (unsigned i = 0;i < MAX_VERTEX_STREAMS;++i)
{
Set_Vertex_Buffer(nullptr, i);
}
Set_Index_Buffer(nullptr, 0);
if (m_pCleanupHook) {
m_pCleanupHook->ReleaseResources();
}
DynamicVBAccessClass::_Deinit();
DynamicIBAccessClass::_Deinit();
DX8TextureManagerClass::Release_Textures();
SHD_SHUTDOWN_SHADERS;
// Release all non-MANAGED stuff
WW3D::_Invalidate_Textures();

// Reset frame count to reflect the flipping chain being reset by Reset()
FrameCount = 0;
for (unsigned i = 0;i < MAX_VERTEX_STREAMS;++i)
{
Set_Vertex_Buffer(nullptr, i);
}
Set_Index_Buffer(nullptr, 0);
if (m_pCleanupHook) {
m_pCleanupHook->ReleaseResources();
}
DynamicVBAccessClass::_Deinit();
DynamicIBAccessClass::_Deinit();
DX8TextureManagerClass::Release_Textures();
SHD_SHUTDOWN_SHADERS;

memset(Vertex_Shader_Constants, 0, sizeof(Vector4) * MAX_VERTEX_SHADER_CONSTANTS);
memset(Pixel_Shader_Constants, 0, sizeof(Vector4) * MAX_PIXEL_SHADER_CONSTANTS);
// Reset frame count to reflect the flipping chain being reset by Reset()
FrameCount = 0;

// Set_Vertex_Buffer/Set_Index_Buffer are deferred, so unbind on the device itself.
// Resources still bound during Reset() crash the runtime in DestroyResource.
for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
{
DX8CALL(SetStreamSource(i, nullptr, 0));
}
DX8CALL(SetIndices(nullptr, 0));
Invalidate_Cached_Render_States();
memset(Vertex_Shader_Constants, 0, sizeof(Vector4) * MAX_VERTEX_SHADER_CONSTANTS);
memset(Pixel_Shader_Constants, 0, sizeof(Vector4) * MAX_PIXEL_SHADER_CONSTANTS);

// Rebind the back buffer and release all surface
// references before Reset(), otherwise it crashes in DestroyResource.
Set_Render_Target((IDirect3DSurface8*)nullptr);
HRESULT hr = _Get_D3D_Device8()->TestCooperativeLevel();
if (hr == D3DERR_DEVICELOST) {
return false; //device is lost and can't be reset.
}

HRESULT hr = _Get_D3D_Device8()->TestCooperativeLevel();
if (hr != D3DERR_DEVICELOST)
{
// TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll to prevent
// the graphics driver from potentially loading the old game dbghelp.dll and then crashing the game process.
DbgHelpGuard dbgHelpGuard;
DX8CALL_HRES(Reset(&_PresentParameters), hr)
if (hr != D3D_OK)
return false; //reset failed.
}
else
return false; //device is lost and can't be reset.
// TheSuperHackers @bugfix arcticdolphin 09/10/2026 Reset() fails while resources are still bound
if (!DeviceResetFailed) {
Unbind_Device_Buffers();
}
Invalidate_Cached_Render_States();
Set_Render_Target((IDirect3DSurface8*)nullptr);

if (reload_assets)
{
DX8TextureManagerClass::Recreate_Textures();
if (m_pCleanupHook) {
m_pCleanupHook->ReAcquireResources();
}
{
// TheSuperHackers @bugfix xezon 13/06/2025 Front load the system dbghelp.dll to prevent
// the graphics driver from potentially loading the old game dbghelp.dll and then crashing the game process.
DbgHelpGuard dbgHelpGuard;
hr = _Get_D3D_Device8()->Reset(&_PresentParameters);
Increment_DX8_CallCount();
}
DeviceResetFailed = (hr != D3D_OK);
if (DeviceResetFailed) {
Non_Fatal_Log_DX8_ErrorCode(hr, __FILE__, __LINE__);
return false; //reset failed.
}

if (reload_assets)
{
DX8TextureManagerClass::Recreate_Textures();
if (m_pCleanupHook) {
m_pCleanupHook->ReAcquireResources();
}
Invalidate_Cached_Render_States();
Set_Default_Global_Render_States();
SHD_INIT_SHADERS;
WWDEBUG_SAY(("Device reset completed"));
return true;
}
WWDEBUG_SAY(("Device reset failed"));
return false;
Invalidate_Cached_Render_States();
Set_Default_Global_Render_States();
SHD_INIT_SHADERS;
WWDEBUG_SAY(("Device reset completed"));
return true;
}

// Set_Vertex_Buffer and Set_Index_Buffer are deferred
void DX8Wrapper::Unbind_Device_Buffers()
{
for (unsigned stream = 0; stream < MAX_VERTEX_STREAMS; ++stream)
{
DX8CALL(SetStreamSource(stream, nullptr, 0));
}
DX8CALL(SetIndices(nullptr, 0));
}

void DX8Wrapper::Release_Device()
{
if (D3DDevice) {

for (int a = 0;a < MAX_TEXTURE_STAGES;++a)
{ //release references to any textures that were used in last rendering call
DX8CALL(SetTexture(a, nullptr));
}
if (!DeviceResetFailed)
{
for (int a = 0;a < MAX_TEXTURE_STAGES;++a)
{ //release references to any textures that were used in last rendering call
DX8CALL(SetTexture(a, nullptr));
}

DX8CALL(SetStreamSource(0, nullptr, 0)); //release reference count on last rendered vertex buffer
DX8CALL(SetIndices(nullptr, 0)); //release reference count on last rendered index buffer
Unbind_Device_Buffers();
}


/*
Expand Down
2 changes: 2 additions & 0 deletions Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,7 @@ class DX8Wrapper

static bool Create_Device();
static void Release_Device();
static void Unbind_Device_Buffers();

static void Reset_Statistics();
static void Enumerate_Devices();
Expand Down Expand Up @@ -634,6 +635,7 @@ class DX8Wrapper

static bool IsInitted;
static bool IsDeviceLost;
static bool DeviceResetFailed; ///< Until a Reset() succeeds the device only takes TestCooperativeLevel, Reset and Release
static void * Hwnd;
static unsigned _MainThreadID;

Expand Down
Loading