Is there a faster alternative to FImageUtils::CreateTexture2D?

Dear Friends at Epic,

I am using FImageUtils::CreateTexture2D to make a T2D from a color buffer obtained from ReadPixels using custom viewportclient class.

//.h
UTexture2D* MyScreenshot;

//.cpp
    MyScreenshot = FImageUtils::CreateTexture2D(
    	MyScreenshotResizeWidth, 
    	MyScreenshotResizeHeight,  
    	MySaveDetails.SavePic.ColorBuffer, 
    	this, 
    	FString("HappyTexture"), 
    	EObjectFlags::RF_Public|EObjectFlags::RF_Transient, 
    	FCreateTexture2DParameters()
    );

I have verified that the only thing that is causing my game to hang during this process is the call to FImageUtils::CreateTexture2D

I have looked at the code for this function and I cannot see an easy way to break it up over multiple ticks.

I also cannot use Task Graph System because this is a modification / creation of a UObject

#The Question

Is there an alternative to FImageUtils::CreateTexture2D that will not cause the system to hang for a brief time?

The hang averages about 2 seconds.

#Loading from Binary Array

I will be loading images from compressed binary arrays and will need to turn them into T2Ds, so I really do need a way to make a T2D from color buffer that does not cause a hang :slight_smile:

Thanks!

Rama

How many textures are there and how big are they? I would consider just doing all your CreateTexture2D calls ahead of time. You could basically write your own simple memory manager for textures and recycle these UTexture2D objects that way. Creating such a manager would be easiest if you restrict the size of the allowed textures, a problem you don’t usually get to ignore in that problem space.

thanks for the idea!

I ended up writing my own version which works almost instantly :slight_smile:

#Very Fast Version of CreateTexture2D

I wrote my own version which is basically instant

One notable feature is I made the SrcPtr const.

void AYourClass::TextureFromImage_Internal(const int32 SrcWidth, const int32 SrcHeight, const TArray<FColor> &SrcData, const bool UseAlpha)
{
	// Create the texture
	MyScreenshot = UTexture2D::CreateTransient(
		SrcWidth, 
		SrcHeight, 
		PF_B8G8R8A8
	);
	
	// Lock the texture so it can be modified
	uint8* MipData = static_cast<uint8*>(MyScreenshot->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE));

	// Create base mip.
	uint8* DestPtr = NULL;
	const FColor* SrcPtr = NULL;
	for( int32 y=0; y<SrcHeight; y++ )
	{
		DestPtr = &MipData[(SrcHeight - 1 - y) * SrcWidth * sizeof(FColor)];
		SrcPtr = const_cast<FColor*>(&SrcData[(SrcHeight - 1 - y) * SrcWidth]);
		for( int32 x=0; x<SrcWidth; x++ )
		{
			*DestPtr++ = SrcPtr->B;
			*DestPtr++ = SrcPtr->G;
			*DestPtr++ = SrcPtr->R;
			if( UseAlpha )
			{
				*DestPtr++ = SrcPtr->A;
			}
			else
			{
				*DestPtr++ = 0xFF;
			}
			SrcPtr++;
		}
	}
	
	// Unlock the texture
	MyScreenshot->PlatformData->Mips[0].BulkData.Unlock();
	MyScreenshot->UpdateResource();
}