Skip to content

Release replacement textures when a client is torn down#38

Merged
3vcloud merged 2 commits into
devfrom
fix/release-replacements-on-unload
Jun 8, 2026
Merged

Release replacement textures when a client is torn down#38
3vcloud merged 2 commits into
devfrom
fix/release-replacements-on-unload

Conversation

@3vcloud

@3vcloud 3vcloud commented Jun 8, 2026

Copy link
Copy Markdown
Member

TextureClient::~TextureClient deleted the per-texture side-state but never released the replacement IDirect3DTexture9 objects gMod created. That's fine when the client dies because the device hit refcount 0 (a texture refs its device, so by then every fake is already released and the maps are empty). But when gMod is unloaded via FreeLibrary while the game's device is still alive (late-injected/SetDevice integrations), the maps are full of textures gMod still owns and they all leak - and ExitInstance never deleted the clients, so the destructor didn't even run.

  • ~TextureClient now releases each replacement it still owns (a fake is still owned while it has a partner; an orphaned fake was already released and is left alone). No-op in the device-release path.
  • Add DestroyAllTextureClients() to delete the per-device clients.
  • ExitInstance calls it, gated on a genuine FreeLibrary (lpReserved == nullptr) so it's skipped during process termination where the device/d3d9 may already be gone.

Jon and others added 2 commits June 8, 2026 14:09
TextureClient::~TextureClient deleted the per-texture side-state but never
released the replacement IDirect3DTexture9 objects gMod created. That's
fine when the client dies because the device hit refcount 0 (a texture
refs its device, so by then every fake is already released and the maps
are empty). But when gMod is unloaded via FreeLibrary while the game's
device is still alive (late-injected/SetDevice integrations), the maps
are full of textures gMod still owns and they all leak - and ExitInstance
never deleted the clients, so the destructor didn't even run.

- ~TextureClient now releases each replacement it still owns (a fake is
  still owned while it has a partner; an orphaned fake was already
  released and is left alone). No-op in the device-release path.
- Add DestroyAllTextureClients() to delete the per-device clients.
- ExitInstance calls it, gated on a genuine FreeLibrary
  (lpReserved == nullptr) so it's skipped during process termination
  where the device/d3d9 may already be gone.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@henderkes henderkes force-pushed the fix/release-replacements-on-unload branch from e80f22a to 614cd2d Compare June 8, 2026 16:06
@3vcloud 3vcloud changed the base branch from master to dev June 8, 2026 16:14
@3vcloud 3vcloud merged commit ac39241 into dev Jun 8, 2026
2 checks passed
@henderkes henderkes deleted the fix/release-replacements-on-unload branch June 8, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants