Crash using copyPixels() for CPP targets

Hey Guys,

I’m getting a weird crash that happens about 50% of the time on the desktop and ~80% of the time on android. It seems like something in copyPixels() is dying.

What i’m doing is the following:

  1. Creating a new Tilesheet with blank bitmap data 2048x2048
  2. Loading bitmaps with Assets.getBitmap() then copying them to the Tilesheet using copyPixels()
  3. Calling tilesheet.addTileRect() to add the rectangle info to the Tilesheet
  4. Crashes sometimes occur during copyPixels()

Note: I don’t use embed=true for the assets
Note2: This doesn’t fail on the first copyPixels(), it fails at miscSeal, see snippet below

Void AssetMaker_obj::createGenericTiles( ){
{
HX_STACK_FRAME(“hobo.loader.AssetMaker”,“createGenericTiles”,0xc4f0f8e3,“hobo.loader.AssetMaker.createGenericTiles”,“hobo/loader/AssetMaker.hx”,906,0x1dcdc6c9)
HX_STACK_THIS(this)
HX_STACK_LINE(909)
this->createMiscTile(HX_CSTRING(“iris”));
HX_STACK_LINE(910)
this->createMiscTile(HX_CSTRING(“dazedStars”));
HX_STACK_LINE(911)
this->createMiscTile(HX_CSTRING(“BoilingFoam”));
HX_STACK_LINE(912)
this->createMiscTile(HX_CSTRING(“disarmParticle”));
HX_STACK_LINE(913)
this->createMiscTile(HX_CSTRING(“fire”));
HX_STACK_LINE(914)
this->createMiscTile(HX_CSTRING(“gunParticleA”));
HX_STACK_LINE(915)
this->createMiscTile(HX_CSTRING(“gunParticleB”));
HX_STACK_LINE(916)
this->createMiscTile(HX_CSTRING(“gunParticleC”));
HX_STACK_LINE(917)
this->createMiscTile(HX_CSTRING(“gunParticleD”));
HX_STACK_LINE(918)
this->createMiscTile(HX_CSTRING(“heart”));
HX_STACK_LINE(919)
this->createMiscTile(HX_CSTRING(“puffBall”));
HX_STACK_LINE(920)
this->createMiscTile(HX_CSTRING(“hellFire”));
HX_STACK_LINE(921)
this->createMiscTile(HX_CSTRING(“purpleRainBox”));
HX_STACK_LINE(922)
this->createMiscTile(HX_CSTRING(“rainBox”));
HX_STACK_LINE(923)
this->createMiscTile(HX_CSTRING(“shadow”));
HX_STACK_LINE(924)
this->createMiscTile(HX_CSTRING(“speedLine”));
HX_STACK_LINE(925)
this->createMiscTile(HX_CSTRING(“stars”));
HX_STACK_LINE(926)
this->createMiscTile(HX_CSTRING(“iconFire”));
HX_STACK_LINE(927)
this->createMiscTile(HX_CSTRING(“iconIce”));
HX_STACK_LINE(928)
this->createMiscTile(HX_CSTRING(“iconLight”));
HX_STACK_LINE(929)
this->createMiscTile(HX_CSTRING(“iconWater”));
HX_STACK_LINE(930)
this->createMiscTile(HX_CSTRING(“iconEarth”));
HX_STACK_LINE(931)
this->createMiscTile(HX_CSTRING(“iconAir”));
HX_STACK_LINE(932)
this->createMiscTile(HX_CSTRING(“arrowUp”));
HX_STACK_LINE(933)
this->createMiscTile(HX_CSTRING(“arrowDown”));
HX_STACK_LINE(934)
this->createMiscTile(HX_CSTRING(“attraction”));
HX_STACK_LINE(937)
this->createMiscTile(HX_CSTRING(“miscBlock2”));
HX_STACK_LINE(938)
this->createMiscTile(HX_CSTRING(“miscZero”));
HX_STACK_LINE(939)
this->createMiscTile(HX_CSTRING(“miscOne”));
HX_STACK_LINE(940)
this->createMiscTile(HX_CSTRING(“miscTwo”));
HX_STACK_LINE(941)
this->createMiscTile(HX_CSTRING(“miscThree”));
HX_STACK_LINE(942)
this->createMiscTile(HX_CSTRING(“miscFour”));
HX_STACK_LINE(943)
this->createMiscTile(HX_CSTRING(“miscFive”));
HX_STACK_LINE(944)
this->createMiscTile(HX_CSTRING(“miscSix”));
HX_STACK_LINE(945)
this->createMiscTile(HX_CSTRING(“miscSeven”));
HX_STACK_LINE(946)
this->createMiscTile(HX_CSTRING(“miscEight”));
HX_STACK_LINE(947)
this->createMiscTile(HX_CSTRING(“miscNine”));
HX_STACK_LINE(948)
this->createMiscTile(HX_CSTRING(“miscHp”));
HX_STACK_LINE(949)
this->createMiscTile(HX_CSTRING(“miscVp”));
HX_STACK_LINE(950)
this->createMiscTile(HX_CSTRING(“miscSkull”));
HX_STACK_LINE(951)
this->createMiscTile(HX_CSTRING(“miscMig”));
HX_STACK_LINE(952)
this->createMiscTile(HX_CSTRING(“miscRua”));
HX_STACK_LINE(953)
this->createMiscTile(HX_CSTRING(“miscSki”));
HX_STACK_LINE(954)
this->createMiscTile(HX_CSTRING(“miscWis”));
HX_STACK_LINE(955)
this->createMiscTile(HX_CSTRING(“miscPlus”));
HX_STACK_LINE(958)
this->createHudTile(HX_CSTRING(“iconMoney”));
HX_STACK_LINE(961)
this->createAnimatedEffect(HX_CSTRING(“miscShooterHitPhysical”));
HX_STACK_LINE(962)
this->createAnimatedEffect(HX_CSTRING(“miscChargerHitPhysical”));
HX_STACK_LINE(963)
this->createAnimatedEffect(HX_CSTRING(“guardRune”));
HX_STACK_LINE(964)
this->createAnimatedEffect(HX_CSTRING(“miscDetonate”));
HX_STACK_LINE(966)
this->createAnimatedEffect(HX_CSTRING(“miscSeal”)); //Crash occurs in this instance of copyPixels()
HX_STACK_LINE(967)
this->createAnimatedEffect(HX_CSTRING(“statusConfuse”));
HX_STACK_LINE(968)
this->createAnimatedEffect(HX_CSTRING(“statusDisarm”));
HX_STACK_LINE(969)
this->createAnimatedEffect(HX_CSTRING(“statusFear”));
HX_STACK_LINE(970)

Because it fails only on some images I figured that maybe the .png is corrupt, but it opens in all the programs I tried … AND sometimes works in the openFL app, so its confusing.

Reference

Versions tested (both lime 2.02 and I rebuilt lime legacy from github today commit 954ab3a)

actuate: [1.7.5]
dconsole: [4.3.2]
format: [3.1.2]
hscript: [2.0.4]
hxcpp: 3.1.39 [3.1.48]
lime: 2.0.2 [dev:c:\devland\lime]
nape: [2.0.16]
openfl-samples: [2.1.0]
openfl: [2.1.8]
stablexui: [1.1.1]
swf: [1.7.2]

Here is the crash in lime if mergeAlpha=on for copypixels

Crash if mergeAlpha=off


What fixes it

I re-saved the image and now it doesn’t crash at all. Before I could open the app and it crashed every other time now I can open it 20 times in a row without an issue. I didn’t rebuild the CPP app, I just replaced the .png in the bin folder to get these results.

  • This one crashes (Bad Image)

  • This one doesn’t crash

  • I took the image that crashes (4-bit color) and opened and saved with paint.net and now it doesn’t crash (Good Image)

Finally the question

Are there any rules / known formats the png files should be in? I use texturepacker to generate spritesheets, or photoshop -> imageMagick(trim whitespace) then PNGOUT (reduce size) to store individual PNG files. PNGOUT will optimize many of the images to 4-bit color, but I don’t know if that is the exact root cause.

Is there a difference in alpha channels, between the original and the new one? Perhaps the first one had no alpha, the latter one does?

Hmm, i don’t think so. The image that didn’t work correctly definitely had alpha, I’m working on creating a test project now to try and reproduce it.

Thanks, that would be awesome :smile:

Alright … I think the problem is a stackoverflow that coincidentally occurs inside of copyPixels(). The randomness seems to depend on when the GC runs (when does it run?). After loading with var bd = Assets.bitmapData() if I use bd.dispose() the crash doesn’t happen. I must be loading too much stuff before the GC runs. In the code below the failure occurs everytime after 254 iterations and if I load additional game assets in the example project the failure occurs at 220 iterations. Maybe I’m maxxing the memory available? Doh.

The nice part of my approach is I can dynamically create tilesheets at runtime and the disk size of the app stays small…but it might be better to just pre-gen the tilesheets at compiletime at the expense of some diskspace.

The following example project shows the behavior:
FlashDevelop Project showing crash in copyPixels()


var bd = new BitmapData(2048, 2048, true,0x336699);
		var ts = new Tilesheet(bd); 
		
		var testImage = Assets.getBitmapData("img/miscSeal.png", false);
		
		//4 images in the test image animation
		var rect1 = new Rectangle(1, 1,   101, 45);
		var rect2 = new Rectangle(1, 47,  99,  51);
		var rect3 = new Rectangle(1, 99,  99,  51);
		var rect4 = new Rectangle(1, 151, 89,  51);
		var i = 0;
		
		var debugBmp = new Bitmap(bd);
		debugBmp.scaleX = debugBmp.scaleY = .35;
		Lib.current.addChild(debugBmp);
		
		var p = new Point();
		
		for (i in 0...500)
		{
			var testImage = Assets.getBitmapData("img/miscSeal.png", false);
			bd.copyPixels(testImage, rect1, p, null, null, false);
			bd.copyPixels(testImage, rect2, p, null, null, false);
			bd.copyPixels(testImage, rect3, p, null, null, false);
			bd.copyPixels(testImage, rect4, p, null, null, false);
			
			//testImage.dispose(); //uncomment this and it fixes the crash
			//OR
			//Gc.run(true); //uncomment this and it fixes the crash
		}

If you put “var testImage” outside of the for loop, does that also fix the crash?

Like:

var testImage;

for (i in 0...500)
{
    testImage = Assets.getBitmapData("img/miscSeal.png");
    ...

Yup it does, problem in my case is I load a number of different images/animations at level initialization so I’m calling Assets.getBitmapData(x) quite a bit.

One form of maxing out memory is a stack overflow. When there is a local “var” within a function or a loop, these are maintained until after the function exits.

A fast way to try and fix this problem is to put your “var” references outside of a loop. It can also be helped by not inlining certain functions, which may also cause the same behavior.

If this is not the issue, of course, we can keep looking, but if moving “var testImage” out, above, fixes the issue for you, then this might be what’s going on