Texture created with IImageWrapper appears distorted on PS4

Hi there!

I’m using the IImageWrapper to create a texture from a downloaded PNG at runtime.
It appears fine in my editor tests, but when we run it on the PS4 the texture appears distorted:

132157-distortedthumbnail.png

132158-editorthumbnail.png

Does anyone have any idea what this might be?
I’m just using the standard Image creation example which you’ll find if you search for ‘texture from URL’:

UTexture2D* texture = nullptr;
	
	IImageWrapperModule& imageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
	IImageWrapperPtr imageWrapper = imageWrapperModule.CreateImageWrapper(EImageFormat::PNG);

	if (imageWrapper.IsValid() && imageWrapper->SetCompressed(imageArray.GetData(), imageArray.Num()))
	{
		const TArray<uint8>* uncompressedBGRA = nullptr;
		if (imageWrapper->GetRaw(ERGBFormat::BGRA, 8, uncompressedBGRA))
		{
			int32 height = imageWrapper->GetHeight();
			int32 width = imageWrapper->GetWidth();

			texture = UTexture2D::CreateTransient(width, height, PF_B8G8R8A8);

			void* TextureData = texture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
			FMemory::Memcpy(TextureData, uncompressedBGRA->GetData(), uncompressedBGRA->Num());
			texture->PlatformData->Mips[0].BulkData.Unlock();
			texture->UpdateResource();
		}
	}

Any help would be much appreciated!

Not sure if it is related, but PS4 only takes square textures.

Thanks! Ours are square already unfortunately :frowning:

There is a bIsTiling that you can disable from the texture that might help. (call it before UpdateResource)
If this doesnt work I suggest using UTexture2DDynamic and take a look at ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER() macro to store data into it. In 4.15 you can take a look at AsyncTaskDownloadImage.cpp (not previous version) to see how it is used.

Correcting myself as it is bNoTiling that you should look for instead of bIsTiling . Might still not work though.

Thank you!

I’ll try this first thing tomorrow :slight_smile:

This was solved by making the following changes to my code. Thanks for all the help!

texture->bNoTiling;

uint8* TextureData = static_cast<uint8*>(texture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE));

It should be: texture->bNoTiling = true; … right? Otherwise that part should not do anything.

yes indeed

Solved it on PS4, but not on XBoxOne unfortunately. Any Idea ?

texture->bNoTiling = true; is not enough to make it work on XBoxOne because the low-level creation of the texture is done via a function called CreateVirtualTexture() which does not handle tiling as intended (at least, that’s my understanding of it).

So, I modified the code of FTexture2DResource::InitRHI() to force the call of SafeCreateTexture2D() instead of CreateVirtualTexture().
In /Engine/Source/Runtime/Engine/Private/Texture2D.cpp, do the following :

	if( Owner->bNoTiling )
	{
		TexCreateFlags |= TexCreate_NoTiling;
//[DN][CDL] 10/Jul/2018
// This is to force SafeCreateTexture2D() instead of CreateVirtualTexture() in \Engine\Source\Runtime\D3D12RHI\Private\XboxOne\XboxOneD3D12Texture.cpp
#if PLATFORM_XBOXONE
		TexCreateFlags &= ~(TexCreate_OfflineProcessed);
#endif
//[\DN][CDL] 10/Jul/2018
	}

It’s kind of a hack but it works fine for me.