ArrayIndexOutOfBoundsException in World.renderScene()

Started by robert, October 28, 2012, 11:57:38 PM

Previous topic - Next topic

robert

Hi there, I got this report today from a couple of users. Stacktrace follows:

java.lang.ArrayIndexOutOfBoundsException
at com.threed.jpct.CompiledInstance.fill(CompiledInstance.java:1017)
at com.threed.jpct.Object3DCompiler.compile(Object3DCompiler.java:145)
at com.threed.jpct.World.compile(World.java:1911)
at com.threed.jpct.World.renderScene(World.java:1035)

The full code that triggers this crash is the following:

mFrameBuffer.clear();
mSkyBox.render(mWorld, mFrameBuffer);
mWorld.renderScene(mFrameBuffer);    <----- This is the culprit
mWorld.draw(mFrameBuffer);
mFrameBuffer.display();

EgonOlsen


EgonOlsen


robert

Quote from: EgonOlsen on October 29, 2012, 07:22:09 AM
Any chance that you've played around with this setting http://www.jpct.net/jpct-ae/doc/com/threed/jpct/Config.html#vertexBufferSize? If so, don't do that... ;)

Hi Egon. No, I've not changed that setting. Since I'm using Bugsense, I know exactly which devices the failure happened on:

- LGL35G (Low end, small screen 240x320).
- LG-E400 (Low end, small screen 240x320).
- XT557 (Motorola, 512MB RAM, 1Ghz Processor, 854x480 screen). This has the same features than my test phone (Xperia Neo V).
- WT19a (CPU Scorpion at 1 GHz, GPU Adreno 205, chipset Qualcomm MSM8255 Snapdragon).
- GT-I9003 (Samsung Galaxy S).

All devices are running Android Gingerbread, and I'm using latest JPCT-AE (1.25).

EgonOlsen

I fail to see any relation to the hardware or the Android version ATM...can you please give the latest beta a try: http://jpct.de/download/beta/jpct_ae.jar?

robert

Quote from: EgonOlsen on October 29, 2012, 12:20:37 PM
I fail to see any relation to the hardware or the Android version ATM...can you please give the latest beta a try: http://jpct.de/download/beta/jpct_ae.jar?

I'm going to give the beta a try and report back. Thanks.

robert

Egon, the error is still there with the latest beta:

java.lang.ArrayIndexOutOfBoundsException
at com.threed.jpct.CompiledInstance.fill(CompiledInstance.java:1068)
at com.threed.jpct.Object3DCompiler.compile(Object3DCompiler.java:145)
at com.threed.jpct.World.compile(World.java:1928)
at com.threed.jpct.World.renderScene(World.java:1044)
...

This time the device that triggered the error is this one: http://pdadb.net/index.php?m=specs&id=2751&c=samsung_gt-s5660_galaxy_gio  (but running Android 2.3.6 instead of 2.2).

EgonOlsen

Are you by any chance doing a call like  object3D.compile(false, true); in your code? If so, do you have to? Are you really changing the uv-coordinates on the fly?

robert

#8
Quote from: EgonOlsen on November 01, 2012, 11:15:29 PM
Are you by any chance doing a call like  object3D.compile(false, true); in your code? If so, do you have to? Are you really changing the uv-coordinates on the fly?

Nope, I'm not calling compile(), just build(). Here's the code I use to load the mesh:

String meshName = mPreferences.getString("mesh", null);
int id = res.getIdentifier(meshName, "raw", mContext.getPackageName());
InputStream is = res.openRawResource(id);
mMesh = Loader.loadSerializedObjectArray(is)[0];
mMesh.rotateX((float)(Math.PI / 2.0f));
mMesh.rotateMesh();
mMesh.setSpecularLighting(true);
mMesh.build();
mWorld.addObject(mMesh);


I suspect it has something to do with short vs int buffers... since I use both Rajawali and your engine, and the author of Rajawali had a similar issue: https://github.com/MasDennis/Rajawali/issues/20

Also, it seems that not all devices support int buffer as shown here: https://github.com/MasDennis/Rajawali/issues/28

EgonOlsen

#9
No, it has nothing to do with that. It's just the access to some VM side arrays to process uv-coordinates of the object in question. And i still fail to see any relation to the device's hardware it's running on except that this code is somehow related to the number of texture units that the underlying hardware supports. Maybe that it the problem somehow...how does your code look that assigns the textures to these objects?

Edit: Do you have access to such a device so that i can give you some debug version to run on it?

robert

#10
Hi Egon,

Unfortunately I don't have access to any of those devices. I own a couple of devices, and the code works fine on them.

I don't set any texture on the mesh, I just light it with some color, like this:

mKeyLight = new Light(mWorld);
mKeyLight.setIntensity(Color.red(meshColor), Color.green(meshColor), Color.blue(meshColor));
SimpleVector sv = new SimpleVector(mMesh.getTransformedCenter());
sv.y -= 100;
sv.z -= 100;
sv.rotateY((float)(-Math.PI / 8.0f));
mKeyLight.setPosition(sv);


Note that I use two more lights, a fill light and a rim light, but I don't think that really matters. The only other mesh I have in the scene beside the main mesh, is a simple billboarded plane with a 256x256 texture.

In total, there are 6 512x512 textures for the skybox and 1 256x256 texture for the billboarded plane (and I'm still getting OOM errors on some devices [mostly mdpi 320x480 devices]). Since you asked for it, here's the code that assigns a texture to the billboarded plane:


String sunName = "sun" + sufix;
int id = res.getIdentifier(sunName, "drawable", mContext.getPackageName());
Log.d(TAG, "Loading new texture " + sunName);
tm.addTexture("light", new Texture(res.getDrawable(id), true));

// Create sun billboarded plane
Object3D sun = Primitives.getPlane(1, 3.0f);
sun.setBillboarding(true);
sun.translate(1.0f, -2.5f, -3.5f);
sun.setTexture("light");
sun.setTransparency(1000);
sun.setLighting(Object3D.LIGHTING_NO_LIGHTS);
sun.setAdditionalColor(RGBColor.WHITE);
sun.build();
mWorld.addObject(sun);


Maybe it has something to do with the number of polygons in the main mesh ? It has 6432 triangles, 3218 vertices... but please notice that I just use one mesh in the scene besides the simple billboarded plane.

P.D: I serialize the mesh with this code:


Object3D[] objs = Loader.loadOBJ(inputFileName, null, 1.0f);
for (Object3D obj : objs) {
obj.build();
}
String outputFileName = inputFileName.substring(0, inputFileName.lastIndexOf('.')) + ".ser";
new DeSerializer().serializeArray(objs, new FileOutputStream(outputFileName), true);


Thank you for your support.

K24A3

Are you using multithreading separating the manipulation of 3D objects in one thread and having the render in another?

This has always been troublesome so if you are doing this, try doing everything in the rendering thread using a frame delta to calculate the correct movement of objects.

EgonOlsen

Quote from: K24A3 on November 02, 2012, 01:23:13 PM
Are you using multithreading separating the manipulation of 3D objects in one thread and having the render in another?
That's the only idea that i've left too...it might help to see the rest of the stack trace and not just that part after renderScene().

robert

#13
Quote from: EgonOlsen on November 02, 2012, 02:01:02 PM
Quote from: K24A3 on November 02, 2012, 01:23:13 PM
Are you using multithreading separating the manipulation of 3D objects in one thread and having the render in another?
That's the only idea that i've left too...it might help to see the rest of the stack trace and not just that part after renderScene().

There's not much in the stack frame...

java.lang.ArrayIndexOutOfBoundsException
at com.threed.jpct.CompiledInstance.fill(CompiledInstance.java:1068)
at com.threed.jpct.Object3DCompiler.compile(Object3DCompiler.java:145)
at com.threed.jpct.World.compile(World.java:1928)
at com.threed.jpct.World.renderScene(World.java:1044)
at com.wallpaper.MyRenderer.onDrawFrame(MyRenderer.java:264)
at net.rbgrn.android.glwallpaperservice.GLThread.guardedRun(GLWallpaperService.java:627)
at net.rbgrn.android.glwallpaperservice.GLThread.run(GLWallpaperService.java:492)


And yes, as you can see the wallpaperservice creates a thread, but it takes care of the setup. I initialize all JPCT code in onSurfaceChanged() and manipulate it in onDrawFrame() so I don't see how that might be causing the error... In fact, I have coded three wallpapers with Rajawali (which internally uses the GLWallpaperService by Robert Green) and never had any issues.

EgonOlsen

I've no idea what this wallpaper stuff does exactly, but if it blindly spawns a thread in on<Something>, this might cause a problem. Some Android versions show a strange behaviour when it comes to create and destroy Acitivities. Maybe it happens that two of these threads exist in parallel, at least for a short time. The line that fails is this:


smallBufferMT[0][sbPosMT[0]++] = ((int) (u[pind] * 65536f));


pind can't cause the exception, because it has been used multiple times before in that method  on arrays of the exact same size as u. The 0 index can't cause it either, because it's always sized 4. The same goes for sbPosMT. So all that's left is smallBufferMT[0][sbPosMT[0]++]. This can't cause the error either if the code isn't called in multiple threads. If it is, this counter might overflow.

I've updated the beta jar with two changes: Calling the method from multiple threads should now happen in a synchronized way. While this doesn't fix the root problem, it might cure the symptoms. If it doesn't, i've added extended logging that prints out some indices in cause of an exception.

I hope this helps in one way or the other.