Dynamic texture write texel broken on android

I’m attempted to use a dynamic texture on Android. It works on Windows, but when I package for Android, it doesn’t work.

Everything works on Android except my dynamic texture is not successfully changed (written to) by my C++ code.

I’m not sure how to debug this? I tried UE_LOG(), but for some reason (adb logcat) doesn’t show my messages. Blueprints function Print doesn’t work either.

The following C++ code is called every tick by the Blueprints script for an actor that uses the texture:

UTexture2D* ABoardActor::GetBoardTexture(UTexture2D* tex)
{
	//
	//TODO: track whether update was already done, actually better yet do a callback to blueprints
	//

	UE_LOG(HeroQuestLog, Log, TEXT("BOARD 1"));
	HQMap* pMap = HQMap::GetTheMap();
	FTexture2DMipMap& Mip = tex->PlatformData->Mips[0];
	FColor* FormatedImageData = static_cast<FColor*>(Mip.BulkData.Lock(LOCK_READ_WRITE));
	int32 width = Mip.SizeX;
	int32 height = Mip.SizeY;
	UE_LOG(HeroQuestLog, Log, TEXT("BOARD 2"));
	for (int32 y = 0; y < height; ++y)
	{
		for (int32 x = 0; x < width; ++x)
		{
			FColor pixColor(0, 0, 0);
			HQSpace* pSpace = pMap->GetSpace(x, y);
			if (pSpace && pSpace->IsRevealed())
			{
				pixColor.R = 255;
				pixColor.G = 255;
				pixColor.B = 255;
				pixColor.A = 255;
			}
			else
			{
				pixColor.R = 70;
				pixColor.G = 70;
				pixColor.B = 70;
				pixColor.A = 70;
			}
			FormatedImageData[y * width + x].R = pixColor.R;
			FormatedImageData[y * width + x].G = pixColor.G;
			FormatedImageData[y * width + x].B = pixColor.B;
		}
	}
	UE_LOG(HeroQuestLog, Log, TEXT("BOARD 3"));
	Mip.BulkData.Unlock();
	tex->UpdateResource();
	UE_LOG(HeroQuestLog, Log, TEXT("BOARD 4"));
	return tex;
}

Update: Is there some way to tell whether it’s a UE4 bug vs. not supported on Android vs. not supported on my particular tablet? It seems like it should be supported because after all I’m not updating the texture every frame. So really any device that supports an OpenGL texture should support this because the run-time texture edit doesn’t need to be high performance.

Update #2: adb logcat shows (E/libEGL ( 703): called unimplemented OpenGL ES API)), but I don’t know what’s causing it. I don’t even know whether it’s a real issue vs. a red herring?

Update #3: Has anyone seen a dynamic texture work on Android? Can you share sample code?

I think maybe the issue is that in the editor I set texture Compression Settings to VectorDisplacementmap (RGBA8). But for my Android package I think maybe it uses some other format for the texture. So maybe it is incorrect to do (FColor* FormatedImageData = static_cast(Mip.BulkData.Lock(LOCK_READ_ONLY));)… Because that assumes that Mip.BulkData is FColor when in fact it’s not for Android? If that is the problem, then how do I SetTexel(x, y, color) in a generic way that doesn’t care about the texture format? Performance is not important because the dynamic texture only updates when something changes in a turn-based game… ???

After some debug, I realized that my dynamic texture didn’t just not work as an Android package - it also didn’t work as a Windows desktop package.

So I rewrote my code based on the following “minimal working example”:

Because this is a quirk of Unreal Engine (ie not of OpenGL or GPUs), I don’t completely understand all the under-the-hood details of why this fixed the issue. Plus I think the “minimal working example” style is better overall, and currently I don’t have time to narrow down which difference is broken. But here’s some notes on that issue.

I do notice one glaring difference between (the version that only worked in the editor) and (the version that works for packages too)… My above broken GetBoardTexture(UTexture2D* tex) is called from Blueprints passing the content texture as an argument. So I’m guessing that the problem is either that (it’s not a dynamic texture when packaged) or (it uses a different texture format when packaged). I’m passing EPixelFormat::PF_B8G8R8A8 to UTexture2D::CreateTransient(), so I think automatic editor settings for texture format are less likely to be overwritten by UE4 packaging for Android, though I did not confirm this detail of UE4.

By rewriting my code based on the “minimal working example”, I’m now creating the texture in C++ using = UTexture2D::CreateTransient(). I’m also using UpdateTextureRegions() → ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(). So one of those two things must be the difference.

In summary, I’m using “minimal working example” from above link.

Update #1: Creating the UTexture2D in the editor instead of with UTexture2D::CreateTransient() also worked for windows package:

void ABoardActor::InitBoardActor(UTexture2D* tex0, UTexture2D* tex1)
{
	echoUpdateTextureRegion = new FUpdateTextureRegion2D(0, 0, 0, 0, TEXTURE_SIZEX, TEXTURE_SIZEY);  // Note: This never gets freed
	BoardTex0 = tex0;
	BoardTex0->UpdateResource();
	BoardTex1 = tex1;
	BoardTex1->UpdateResource();
	data0.Init(FColor(255,   0,   0, 0), TEXTURE_DATA_LENGTH);
	data1.Init(FColor(  0, 255,   0, 0), TEXTURE_DATA_LENGTH);
}

Update #2: Android Package also worked when creating the UTexture2D in the editor (instead of UTexture2D::CreateTransient).