Oculus Rift Support

OK, @rickard, I think I found the root cause of the flickering. Jherico explains it here:

https://developer.oculusvr.com/forums/viewtopic.php?p=174280#p174280

Basically, endFrame is doing the buffer swapping, so “the Oculus SDK becomes responsible for performing the swapbuffer operation, so you need to disable it in your own application.”

So, how do we do that in jME3?

I also noticed this little nugget in jmonkeyengine/LwjglAbstractDisplay.java at 1b0f6d0f59650772bac4588d1733c061ff50d8c8 · jMonkeyEngine/jmonkeyengine · GitHub (LwjglAbstractDisplay.java):

[java] // calls swap buffers, etc.
try {
if (autoFlush){
Display.update(false);
}else{
Display.processMessages();
Thread.sleep(50);
// add a small wait
// to reduce CPU usage
}
} catch (Throwable ex){
listener.handleError(“Error while swapping buffers”, ex);
}[/java]

Looks like when you set autoFlush to false (which does appear to fix the flicker), a Thread.sleep(50) gets called. That is likely causing the slow frame rate! I wonder if the solution can be simply bypassing that sleep() call? I’d love to find a solution that wouldn’t require modification of the jME3 library. Or, maybe we will need to push some jME3 changes to make it compatible with the Rift.

I did get a development environment setup on my Windows box to work on this, but heading to bed now… hopefully you can pick up where I left off before I get back to this.

1 Like

It looks like the code assumes that because it’s not calling swapbuffers, you’re operating in single buffered mode and that therefore you don’t want to update too often (this can actually lead to the card overheating, to the extent that my system often freezes up if I draw a simple enough scene and disable vsync).

That sleep should definitely be bypassed for Rift mode. It seems like maybe there needs to be a more complex flag here, like an enum that indicates a) internal buffer swapping vs b) external buffer swapping vs c) single buffered operation.

Even without this, 50 milliseconds is WAY too long and represents a maximum framerate of 20 fps. 10ms might be better since that would represent 100 fps max, but I’m not sure how accurate the sleep is. If you ask it to sleep for 10ms and it ends up sleeping for 15, you’re at 66 fps, which is too low.

1 Like

Thank you for stopping by, jherico!

In my opinion, that sleep call should just be removed. If the developer decides to skip the default buffer swapping behavior, he or she better know what they are replacing that behavior with to control CPU and frame rate. An inherent long sleep (or short inconsistent sleep) isn’t a good solution especially when built deep into the engine.

I have a jME3 fork on github that I’ll make this change to & make a pull request for the main jME3 branch. I have high hopes this will solve our problem.

I agree that the sleep should be removed. And 50 ms is pretty ridiculous.

If the app wants to sleep then they can sleep in their update().

3 Likes

Please make sure that when you commit the change the comment is ‘turn the suck knob down’

@pspeed said: I agree that the sleep should be removed. And 50 ms is pretty ridiculous.

If the app wants to sleep then they can sleep in their update().

Yes. I was going to suggest that if there is a worry about overheating, a configurable “lockFPS” could be used instead of a hard coded sleep call.

Good find @phr00t!

@rickard said: Yes. I was going to suggest that if there is a worry about overheating, a configurable "lockFPS" could be used instead of a hard coded sleep call.

Good find @phr00t!

Or just put a Thread.sleep() in simpleUpdate() if you’ve already gone through the trouble to do the (normally) strange thing of turning off autoflush in a regular desktop app.

I can confirm that it works. Commenting out the Thread.sleep makes for a much smoother experience.

I updated my repository with this change here:

… but I don’t know how to create a pull request for just the sleep removal. It wants to otherwise pull all of my changes over to jMonkeyEngine (which I am OK with, but the jME3 may not, hehe).

All set! Tested with my DK2 & orientation tracking is very smooth, responsive & no flicker! Unfortunately, positional tracking doesn’t seem to be working at all… guess that’s my job :smiley:

Just checked in working positional tracking with my DK2! Looks VERY good! :smiley: Excited to finally try this all out in my 4089 game…

https://code.google.com/p/jmonkeyengine-oculus-rift/source/detail?r=134

1 Like
@phr00t said: Just checked in working positional tracking with my DK2! Looks VERY good! :D Excited to finally try this all out in my 4089 game...

Google Code Archive - Long-term storage for Google Code Project Hosting.

Sweet! I’ve been away all weekend, so I haven’t been able to check out anything, yet.

JmeContext.setAutoFlushFrames() is not meant to be used by user code! When the application loses focus, this method is used to throttle the update loop and disable rendering to reduce CPU / GPU usage (e.g. when Alt-Tabbed out of the app).

If you’re going to make a pull request, you can add this as an application setting via AppSettings to disable buffer swapping, but changing existing behavior in this critical part of the engine is definitely not a good idea.

@Momoko_Fan said: JmeContext.setAutoFlushFrames() is not meant to be used by user code! When the application loses focus, this method is used to throttle the update loop and disable rendering to reduce CPU / GPU usage (e.g. when Alt-Tabbed out of the app).

If you’re going to make a pull request, you can add this as an application setting via AppSettings to disable buffer swapping, but changing existing behavior in this critical part of the engine is definitely not a good idea.

I thought apps either completely pause on lost focus (default setting) or run at full speed?

I’m maintaining my own jME3 fork where I made the change, which so far appears to work very good. I’ll double check for any bad lost focusing behavior, though.

EDIT: I looked more into this, and setAuthFlushFrames() does get changed when focus is lost/gained, but only when the application is set to pause when focus is lost. Therefore, I added a line that sets pauseOnFocus(false); in OVRApplication. Not only should this avoid the buffer swapping settings being changed, but if you (or something) accidentally takes focus away from your Rift application, it would lock up the display which can be very uncomfortable.

DOUBLE EDIT: I also didn’t notice any negative side effects with the sleep(50) removal in my game, 4089. The CPU usage didn’t spike when I changed focus away and minimized the screen, whether it was set to pause or not. Maybe someone should double-check on Windows, just in case…

@phr00t said: I thought apps either completely pause on lost focus (default setting) or run at full speed?

I’m maintaining my own jME3 fork where I made the change, which so far appears to work very good. I’ll double check for any bad lost focusing behavior, though.

EDIT: I looked more into this, and setAuthFlushFrames() does get changed when focus is lost/gained, but only when the application is set to pause when focus is lost. Therefore, I added a line that sets pauseOnFocus(false); in OVRApplication. Not only should this avoid the buffer swapping settings being changed, but if you (or something) accidentally takes focus away from your Rift application, it would lock up the display which can be very uncomfortable.

DOUBLE EDIT: I also didn’t notice any negative side effects with the sleep(50) removal in my game, 4089. The CPU usage didn’t spike when I changed focus away and minimized the screen, whether it was set to pause or not. Maybe someone should double-check on Windows, just in case…


When removing the sleep(50) and alt-tabbing, I have noticed 101% CPU usage from the java process. With the sleep(50), only 5% CPU usage is observed.
See here: https://imgur.com/a/dsutQ

@Momoko_Fan said: When removing the sleep(50) and alt-tabbing, I have noticed 101% CPU usage from the java process. With the sleep(50), only 5% CPU usage is observed. See here: https://imgur.com/a/dsutQ

…but pause on lost focus already skips rendering completely, though. So I’m not sure why that autoflush matters.

[java]
if (speed == 0 || paused) {
return;
}
[/java]

No rendering is done and the window just shows whatever doo-doo is there until focused is gained again. Draw operations are never performed at all.

The render loop calls Application.update() every frame, regardless of whether the application chooses to render anything or not. If there’s no rendering or swap buffers call, then you get an infinite loop using up 100% CPU which is what we observe in the screenshot.

In the typical case, vsync would be turned on, so swap buffers would automatically perform the sleep until the next vsync. If no swap buffers is being performed, then something else must be responsible for throttling the render loop to avoid the 100% CPU usage issue.

Maybe move the sleep(50) call to where that return is from pspeed’s post? e.g.

[java]if( paused ) {
Thread.sleep(50);
return;
} else if( speed == 0 ) return;
[/java]

This way, the sleeping will only happen when the application is considered paused.

EDIT: Checked-in this change to my github repo:

1 Like

I am having trouble with orientation in my 4089 application… e.g. I have to turn my head left to move straight. I tried modifying TestOVRApplication with some new functions that will hopefully be more reliable. Even in the test application previously, moving forward rarely moved in the direction I was looking. I can’t test this change until at least late tonight (where is my Linux SDK!), so let me know if anyone else tries it:

https://code.google.com/p/jmonkeyengine-oculus-rift/source/detail?r=138

@phr00t said: I am having trouble with orientation in my 4089 application... e.g. I have to turn my head left to move straight. I tried modifying TestOVRApplication with some new functions that will hopefully be more reliable. Even in the test application previously, moving forward rarely moved in the direction I was looking. I can't test this change until at least late tonight (where is my Linux SDK!), so let me know if anyone else tries it:

https://code.google.com/p/jmonkeyengine-oculus-rift/source/detail?r=138

It sounds like the problem I faced when testing your first OVR supported build. I can’t think of any direct reason for the behavior, but if I come up with something, I’ll let you know :slight_smile: