FSkinnedSceneProxy's never get unregistered from the DynamicWind system
In FDynamicWindTransformProvider::UnregisterSceneProxy, there's an early out that says:
if (SkinningSceneExtProxy == nullptr || SkinningSceneExtProxy->GetTransformProviderId() != DynamicWindTransformProviderId)
This UnregisterSceneProxy is triggered by a OnDestroyRenderThreadResources delegate. By the time it reaches the if above, it has already destroyed the RenderThreadResources, which makes FInstancedSkinningSceneExtensionProxy::TransformProviderProxy null. Due to this, when SkinningSceneExtProxy->GetTransformProviderId() is called, it does not identify itself as being of DynamicWind kind, but instead if falls back to REF_POSE_TRANSFORM_PROVIDER_GUID, and due to this the UnregisterSceneProxy earlies out, disregarding any proxy that arrives here. To check, I added a breakpoint after this early out, and it's never triggered it (removing ISkMs with wind, reloading the level, etc.). I have added a fix that returns the TransformProviderId member directly for this specific check, without going through the TransformProviderProxy.
This means SkeletonLookup entries leak — the ReferenceCount is never decremented, bone data is never freed from the BoneDataAllocator, and entries accumulate
It appears FInstancedSkinningSceneExtensionProxy::TransformProviderId defaults to RefPoseProviderId in the constructor when !succeeded, can we just return TransformProviderId in FInstancedSkinningSceneExtensionProxy::GetTransformProviderId()?
Steps to Reproduce
There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-370935 in the post.
| 1 |
| Component | UE - Rendering - Architecture |
|---|---|
| Affects Versions | 5.7 |
| Target Fix | 5.8 |
| Fix Commit | 52064875 |
|---|
| Created | Mar 20, 2026 |
|---|---|
| Resolved | Mar 23, 2026 |
| Updated | May 4, 2026 |