SMeshWidget crash during live edit

We’re mostly looking for feedback/direction on implementation. There are no current engine examples of extending SMeshWidget for performance.

[Attachment Removed]

Steps to Reproduce
Starting with the sample code repo by [dantreble](dantreble (Dan Treble) · GitHub) on [github](GitHub - dantreble/MeshWidgetExample: Nick Darnell's example project from https://forums.unrealengine.com/development-discussion/rendering/75779-smeshwidget-hardware-instanced-slate-meshes-thread?p=710200#post710200 · GitHub)

This example, as-is, crashes whenever the material used by the SMeshWidget instances is modified while the widget itself is being rendered in the Widget Blueprint Editor in another tab.

Looking at the SParticleMeshWidget class, how can it being notified that the underlying material has been changed? Otherwise, it will paint existing meshes in its OnPaint function and cause a crash (IIRC) on the render thread.

The const cast is definitely suspect, but is it sufficient to move some of this logic to a different virtual function, say an override of SWidget::Tick, to avoid this crash?

In any case, we’d appreciate any additional info, documentation or advice on how to utilise the SMeshWidget class, especially as it pertains to workflows allowing designers to preview their work in editor (where applicable), despite the fact that this widget seems intended for runtime use.

```

virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override

{

const float Scale = AllottedGeometry.Scale;

int32 MeshId = This->TrailMeshId;

// Trail

if ( MeshId != -1 )

{

FVector2D TrailOriginWindowSpace = AllottedGeometry.LocalToAbsolute(AllottedGeometry.GetLocalSize() * 0.5f);

FSlateInstanceBufferData PerInstaceUpdate;

//const FVector2D TrailMeshExtentMin = This->TrailMeshAsset->GetExtentMin();

//const FVector2D TrailMeshExtentMax = This->TrailMeshAsset->GetExtentMax();

Emitter.SetPosition(TrailOriginWindowSpace);

Emitter.Update(Args.GetDeltaTime());

for ( int32 i = 0; i < Emitter.ActiveParticles; ++i )

{

const FSimpleParticle& Particle = Emitter.Particles[i];

FSlateVectorArtInstanceData ParticleData;

ParticleData.SetPosition(Particle.Origin + Particle.Position * Scale);

ParticleData.SetScale(Scale);

PerInstaceUpdate.Add(TArray<UE::Math::TVector4<float>>::ElementType(ParticleData.GetData()));

}

const_cast<SParticleMeshWidget*>(this)->UpdatePerInstanceBuffer(MeshId, PerInstaceUpdate);

}

return SMeshWidget::OnPaint(Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);

}

```

[Attachment Removed]

Hi,

I’m likely the one who recommended taking a look at SMeshWidget, but I probably should have mentioned it’s more or less provided as-is and doesn’t currently have an owner or any active development. That said, we handle similar cases elsewhere in the engine by checking and reacquiring the resource before painting it. I think something similar might work here:

const FRenderRun& Run = RenderRuns[RunIndex];
FRenderData& RunRenderData = RenderData[Run.GetMeshIndex()];
if (RunRenderData.Brush.IsValid())
{
	FSlateResourceHandle CurrentHandle =
		FSlateApplication::Get().GetRenderer()->GetResourceHandle(*RunRenderData.Brush);
	if (CurrentHandle.GetResourceProxy() != RunRenderData.RenderingResourceHandle.GetResourceProxy())
	{
		RunRenderData.RenderingResourceHandle = CurrentHandle;
	}
}

You’ll need to mark RenderData as mutable as well. Does that resolve the crash you’re seeing? If so, I can look at getting it checked in for a future release.

Best,

Cody

[Attachment Removed]