How properly read big textures Mip BulkData?

So, I’m trying copy many textures to a unique texture (to create a Texture Atlas), everything seems to work fine for smaller textures (until 64x64), above that, the BulkData seems to be locked and not loaded, what should I do in this case? force load these textures? wait for it to load? will it load any time? (I have ran the atlas texture generation code with a delay of 10s and the bigger textures still seem to not be in memory)

I basically reference the textures in a custom UPrimaryAsset:

And copy them:

for (const auto Texture : Textures)
{
	FTexture2DMipMap& TextureMip = Texture->GetPlatformData()->Mips[0];

	if (!TextureMip.BulkData.IsBulkDataLoaded())
	{
		UE_LOG(LogTemp, Warning, TEXT("Bulk Data not loaded, loading..."));
		TextureMip.BulkData.LoadBulkDataWithFileReader();
		if (!TextureMip.BulkData.IsBulkDataLoaded())
		{
			UE_LOG(LogTemp, Warning, TEXT("Bulk Data still not loaded..."));
		}
	}

	if (TextureMip.BulkData.IsLocked())
	{
		UE_LOG(LogTemp, Error, TEXT("Locked resource!!! %s"),
		       *Texture->GetName());
		continue;
	}

	void* SourceData = TextureMip.BulkData.Lock(LOCK_READ_ONLY);
	if (!SourceData)
	{
		bool StreamedIn = Texture->IsFullyStreamedIn();
		UE_LOG(LogTemp, Warning, TEXT("Couldn't lock the Source Data for texture %s"),
		       *Texture->GetName());
		UE_LOG(LogTemp, Warning, TEXT("Bytes: %lld"), TextureMip.BulkData.GetBulkDataSize());
		UE_LOG(LogTemp, Warning, TEXT("Streamed In? %d"), StreamedIn);
		continue;
	}

	try
	{
		const FVector2D Position = PositionByTexture[Texture];

		const auto TextureSize = Texture->GetImportedSize();
		const auto TextureWidth = TextureSize.X;
		const auto TextureHeight = TextureSize.Y;

		for (int32 y = 0; y < TextureHeight; ++y)
		{
			for (int32 x = 0; x < TextureWidth; ++x)
			{
				int32 DestIndex = ((y + Position.Y) * AtlasWidth + (x + Position.X)) * 4;
				int32 SourceIndex = (y * TextureWidth + x) * 4;

				FMemory::Memcpy(static_cast<uint8*>(Data) + DestIndex,
				                static_cast<uint8*>(SourceData) + SourceIndex, 4);
			}
		}
	}
	catch (const std::exception& Error)
	{
		UE_LOG(LogTemp, Warning, TEXT("Error: %hs"), Error.what());
	}

	TextureMip.BulkData.Unlock();
}

The output for it is:
image

Also, this is general properties for the 128 texture:

I end up solving the problem by disabling the mipmaps of bigger textures

But for a more robust solution it seems like the problem was due to me acessing the PlatformData which is generally accessible only in “cooked” versions of the game (shipped game version)

Someone from Unreal Source provided me the following code for acessing the MipMap BulkData more reliably:

#if WITH_EDITOR // Editor uncooked data.    
TArray64<uint8> EditorData;
Texture2D->Source.GetMipData(EditorData, 0);
std::size_t DataSize = EditorData.Num();

uint8* TextureData = EditorData.GetData();

if(DataSize <= 0)
{
	return FFGPixelMesh();
}

int32 SizeX = Texture2D->Source.GetSizeX();
int32 SizeY = Texture2D->Source.GetSizeY();

#else // !WITH_EDITOR - Cooked Platform Specific Texture.

FTexture2DMipMap& MipMap = Texture2D->GetPlatformData()->Mips[0];
uint8* TextureData = StaticCast<uint8*>(MipMap.BulkData.Lock(LOCK_READ_ONLY));
std::size_t DataSize = MipMap.BulkData.GetBulkDataSize();

if(DataSize <= 0)
{
	return FFGPixelMesh();
}

int32 SizeX = MipMap.SizeX;
int32 SizeY = MipMap.SizeY;

#endif // WITH_EDITOR

checkf(TextureData != nullptr, TEXT("Failed to lock texture data."));
1 Like