C++ UTexture2D get null from GetPlatformData() after texture is initialized.

Hi, I think I should address my question through C++ and BP, and the result. It will be helpful to understand the issue.
I am using LYRA template and UE5.3.2

Thanks for your patience to read.

Following is my code to create my texture.

  • I log Width, Height, PlatformData, GetSizeX().
init_dynamic_texture(int _w, int _h, int _c, EPixelFormat pixel_format) : w(_w), h(_h), pixel_stride(_c)
    {
        pixel_size = w * h * pixel_stride;

        // Initialize Texture Data Array.
        texture_data.Init(0, pixel_size);

        // Create Texture Object.
        UE_LOG(LogTemp, Error, TEXT("wh = (%d, %d)."), w, h);// ---Log to debug.---

        texture = UTexture2D::CreateTransient(w, h, EPixelFormat::PF_R8G8B8A8);
        texture->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap;
        texture->NeverStream         = true;
        texture->SRGB                = 0;
        texture->MipGenSettings      = TextureMipGenSettings::TMGS_NoMipmaps;
        texture->Filter              = TextureFilter::TF_Nearest;

        UE_LOG(LogTemp, Error, TEXT("addr1 = %d"), texture->GetPlatformData());//---Log address of PlatformData.---
        UE_LOG(LogTemp, Error, TEXT("W = %d"), texture->GetSizeX());//---Log width.---

        FTexture2DMipMap &mip_0          = texture->GetPlatformData()->Mips[0];
        void             *byte_bulk_data = mip_0.BulkData.Lock(LOCK_READ_WRITE);
        FMemory::Memcpy(byte_bulk_data, texture_data.GetData(), pixel_size);
        mip_0.BulkData.Unlock();

        texture->UpdateResource();
    }

In my debug function. I try to access the PlatformData, which will be used to do Memcpy.
However, I got UE crash.

  • So I Log PlatformData’s address again.
  • And log GetSizeX().
void update_dynamic_texture(){
    UE_LOG(LogTemp, Error, TEXT("addr2 = %d"), texture->GetPlatformData());
    UE_LOG(LogTemp, Error, TEXT("W = %d"), texture->GetSizeX());

    FTexturePlatformData *platform_data = texture->GetPlatformData();
    if (platform_data == nullptr) {
        UE_LOG(LogTemp, Error, TEXT("platform_data is nullptr."));
    }

    // FTexture2DMipMap &mip_0          = platform_data->Mips[0];
    // void             *byte_bulk_data = mip_0.BulkData.Lock(LOCK_READ_WRITE);
    // FMemory::Memcpy(byte_bulk_data, color.GetData(), pixel_size);
    // mip_0.BulkData.Unlock();
    // texture->UpdateResource();
}

My test BP.

  • I have a Delay. Set it 0 second.
  • I init texture.
  • I set a bool Ready=true.

  • Pring “nor Ready” if it’s false.
  • Update texture (code is commented out, only LOG left).
  • Tick every 1 second.

Now the interesting result from OutputLog.

  1. LogWorld: Bringing World /A_UE53/Maps/UEDPIE_0_L_Basic_Level.L_Basic_Level up for play (max tick rate 0) at 2024.07.18-08.04.14
  2. LogWorld: Bringing up level for play took: 0.001103
  3. LogCommonGame: [B_LyraUIPolicy_C_0] is adding player [LyraLocalPlayer_1]'s root layout [W_OverallUILayout_C_0] to the viewport
  4. PIE: Server logged in
  5. PIE: Play in editor total start time 0.149 seconds.
  6. LogBackChannel: Listening on FBackChannelConnection Client Socket (localport: 2049)
  7. LogRemoteSession: Started listening on port 2049
  8. LogSlate: InvalidateAllWidgets triggered. All widgets were invalidated
  9. :no_entry:LogBlueprintUserMessages: [t3_C_1] not Ready
  10. :no_entry:LogBlueprintUserMessages: [t3_C_1] =====================Init
  11. :no_entry:LogTemp: Error: wh = (256, 256).
  12. :no_entry:LogTemp: Error: addr1 = 1053805184
  13. :no_entry:LogTemp: Error: W = 256
  14. LogLyraExperience: Identified experience LyraExperienceDefinition:BP_ExpDef (Source: WorldSettings)
  15. LogLyraExperience: EXPERIENCE: StartExperienceLoad(CurrentExperience = LyraExperienceDefinition:BP_ExpDef, Server)
  16. LogLoadingScreen: Showing loading screen when ‘IsShowingInitialLoadingScreen()’ is false.
  17. LogLoadingScreen: Experience still loading
  18. LogLoadingScreen: Loading screen showing: 1. Reason: Experience still loading
  19. LogLyraExperience: EXPERIENCE: OnExperienceLoadComplete(CurrentExperience = LyraExperienceDefinition:BP_ExpDef, Server)
  20. LogUIActionRouter: Display: Applying input config for leaf-most node [W_AI_HUDLayout_C_0]
  21. LogUIActionRouter: Display: UIInputConfig being changed. bForceRefresh: 1
  22. LogUIActionRouter: Display: InputMode: Previous (None), New (ECommonInputMode::All)
  23. LogViewport: Display: Viewport MouseCaptureMode Changed, CapturePermanently_IncludingInitialMouseDown → CapturePermanently
  24. LogViewport: Display: Viewport HideCursorDuringCapture Changed, False → True
  25. LogUIActionRouter: Display: [User 0] No focus target for leaf-most node [W_AI_HUDLayout_C_0], and the widget isn’t focusable - focusing the game viewport.
  26. LogLoadingScreen: Hiding loading screen when ‘IsShowingInitialLoadingScreen()’ is false.
  27. LogLoadingScreen: (nothing wants to show it anymore)
  28. LogLoadingScreen: Garbage Collecting before dropping load screen
  29. LogLoadingScreen: LoadingScreen was visible for 0.05s
  30. LogUObjectHash: Compacting FUObjectHashTables data took 1.07ms
  31. LogUIActionRouter: Cleaned out [1] inactive UI action bindings
  32. :no_entry:LogTemp: Error: addr2 = 0
  33. :no_entry:LogTemp: Error: W = 0
  34. :no_entry:LogTemp: Error: platform_data is nullptr.
  35. :no_entry:LogTemp: Error: addr2 = 0
  36. :no_entry:LogTemp: Error: W = 0
  37. :no_entry:LogTemp: Error: platform_data is nullptr.
  38. :no_entry:LogTemp: Error: addr2 = 0
  39. :no_entry:LogTemp: Error: W = 0
  40. :no_entry:LogTemp: Error: platform_data is nullptr.
  41. :no_entry:LogTemp: Error: addr2 = 0
  42. :no_entry:LogTemp: Error: W = 0
  43. :no_entry:LogTemp: Error: platform_data is nullptr.
  44. :no_entry:LogTemp: Error: addr2 = 0
  45. :no_entry:LogTemp: Error: W = 0
  46. :no_entry:LogTemp: Error: platform_data is nullptr.
  47. :no_entry:LogTemp: Error: addr2 = 0
  48. :no_entry:LogTemp: Error: W = 0
  49. :no_entry:LogTemp: Error: platform_data is nullptr.
  50. :no_entry:LogTemp: Error: addr2 = 0
  51. :no_entry:LogTemp: Error: W = 0
  52. :no_entry:LogTemp: Error: platform_data is nullptr.
  53. Cmd: quit

Problem:

  • So we got width, height = 256, 256
  • addr1 is the address of PlatformData retrieved from Init func. And I got no err when Memcpy after init.
  • W is also good when retrieve in Init func.
  • but when tick, we are accessing memory with nullptr. :poop:

Solve it but why this happened?
Delay

  • Sleep a while.

Now the result from OutputLog.

  1. LogViewport: Display: Viewport HideCursorDuringCapture Changed, False → True
  2. LogUIActionRouter: Display: [User 0] No focus target for leaf-most node [W_AI_HUDLayout_C_0], and the widget isn’t focusable - focusing the game viewport.
  3. LogLoadingScreen: Hiding loading screen when ‘IsShowingInitialLoadingScreen()’ is false.
  4. LogLoadingScreen: (nothing wants to show it anymore)
  5. LogLoadingScreen: Garbage Collecting before dropping load screen
  6. LogLoadingScreen: LoadingScreen was visible for 0.05s
  7. LogUObjectHash: Compacting FUObjectHashTables data took 0.91ms
  8. LogUIActionRouter: Cleaned out [1] inactive UI action bindings
  9. LogBlueprintUserMessages: [t3_C_1] =====================Init
  10. :no_entry:LogTemp: Error: wh = (256, 256).
  11. :no_entry:LogTemp: Error: addr1 = 836481728
  12. :no_entry:LogTemp: Error: W = 256
  13. :no_entry:LogTemp: Error: addr2 = 836481728
  14. :no_entry:LogTemp: Error: W = 256
  15. :no_entry:LogTemp: Error: addr2 = 836481728
  16. :no_entry:LogTemp: Error: W = 256
  17. :no_entry:LogTemp: Error: addr2 = 836481728
  • Now we can access PlatformData and Width.
  • Why this happened?

Can someone help me and explain what’s going on behind UE?

  • It seems that if I don’t delay, the system will clean the information (but I checked the addr of *UTexture2D texture is always valid).
  • Or the data after Memcpy is put in another thread?
  • The 1st UE OUTPUT LOG prints some system LOG between my custom LOG. Is it a clue?

Try using a render target as a stepping stone to the final UTexture
I use this in my private library and it works fine.


UTexture2D* UImageFunctionLibrary::CreateTexture(UTextureRenderTarget2D* TextureRenderTarget) {

	// Creates Texture2D to store TextureRenderTarget content
	
	UTexture2D* Texture = UTexture2D::CreateTransient(TextureRenderTarget->SizeX, TextureRenderTarget->SizeY, PF_A2B10G10R10);
	//UTexture2D* Texture = UTexture2D::CreateTransient(TextureRenderTarget->SizeX, TextureRenderTarget->SizeY, PF_B8G8R8A8);


#if WITH_EDITORONLY_DATA
	Texture->MipGenSettings = TMGS_NoMipmaps;
#endif
	Texture->SRGB = TextureRenderTarget->SRGB;

	// Read the pixels from the RenderTarget and store them in a FColor array
	TArray<FColor> SurfData;
	FRenderTarget* RenderTarget = TextureRenderTarget->GameThread_GetRenderTargetResource();
	RenderTarget->ReadPixels(SurfData);

	// Lock and copies the data between the textures
	void* TextureData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
	const int32 TextureDataSize = SurfData.Num() * 4;
	FMemory::Memcpy(TextureData, SurfData.GetData(), TextureDataSize);
	Texture->GetPlatformData()->Mips[0].BulkData.Unlock();


	////
	/*
	TArray<FColor> colors;
	FIntRect box;
	RenderTarget->ReadPixels(colors);

	*/
	///

	// Apply Texture changes to GPU memory
	Texture->UpdateResource();
	return Texture;
}

Thanks for your suggestion.

Do you have any idea why I got nullptr to the data and solve this by adding a little bit delay when using UTexture2D?

Sometimes I don’t do shader rendering but just modify the texture2d buffer by CPU.
Texture2D and RenderTarget2D should use the same texture.h to create the texture buffer. Or not?