Is there a way to know when a UTexture is "prepared"?

I’m creating a UTexture2D with:

 UTexture2D* Texture2D = FImageUtils::CreateTexture2D(/*...*/);

and setting it as the texture parameter of a UMaterialInstanceDynamic with:

MaterialInstanceDynamic->SetTextureParameterValue(TEXT("OutputColor"), Texture2D);

and then rendering it to the HUD with:

void AMyHUD::DrawHUD()
{
    AHUD::DrawHUD();

    DrawMaterial(MaterialInstanceDynamic, 0,0, Canvas->SizeX, Canvas->SizeY, 0, 0, 1, 1);
}

If I create the texture and set the texture parameter in AMyHUD::BeginPlay it works correctly.

If I try to do it inside AMyHUD::DrawHUD or AMyHUD::Tick then it does not work correctly. A checker board pattern is displayed and the text “Preparing Textures (1)” is displayed on the screen.

If I put a delay in AMyHUD::Tick and only generate a new texture every second, it works.

If I reduce the delay to 0.1 seconds, it flickers between “Preparing Textures” and displaying correctly.

I’m guessing what is happening is that after FImageUtils::CreateTexture2D returns then the image data has been copied into main memory, but has not yet been asynchronously transfered to the GPU. That’s what preparing textures means, right? That the texture hasn’t been fully loaded?

Is there any way to get notified of when the texture has been fully loaded ? So I can defer calling SetTextureParameter on the material instance until after it has?

Or have I got it wrong and that’s not what’s happening?

These functions on UStreamableRenderAsset look promising:

	/** Whether all miplevels of this texture have been fully streamed in, LOD settings permitting. Note that if optional mips are not mounted it will always return false. */
	ENGINE_API bool IsFullyStreamedIn();

	FORCEINLINE int32 GetStreamingIndex() const { return StreamingIndex; }

	/** Wait for any pending operation (like InitResource and Streaming) to complete. */
	ENGINE_API void WaitForPendingInitOrStreaming(bool bWaitForLODTransition = false, bool bSendCompletionEvents = false);

	/** Wait for any pending operation and make sure that the asset streamer has performed requested ops on this asset. */
	ENGINE_API void WaitForStreaming(bool bWaitForLODTransition = false, bool bSendCompletionEvents = false);

Perhaps I need one of them?

In lieu of trying to create a new texture each time I changed to updating the same texture as follows:

void AMyHUD::RegenerateTexture(int32 SizeX, int32 SizeY)
{
	auto& BulkData = Texture2D->GetPlatformData()->Mips[0].BulkData;
	uint8* OutBuf = (uint8*)BulkData.Lock(LOCK_READ_WRITE);
	
	for (int32 Y = 0; Y < SizeY; Y++)
	{
		for (int32 X = 0; X < SizeX; X++)
		{
			FColor Color = /* get color for pixel X Y */;
			*OutBuf++ = Color.B;
			*OutBuf++ = Color.G;
			*OutBuf++ = Color.R;
			*OutBuf++ = Color.A;
		}
	}
	BulkData.Unlock();
	Texture2D->UpdateResource();
}

and it appears to work, although it feels a little sketchy.

I’d still like to understand why the previous method didn’t work.