Viktor, specifically in an Android 3D game using GLSurfaceView, the are you want to parallelize on is what happens after the lock is released by the renderer because significant time will be spent during the buffer swapping as the gl command list is flushed there and it is at that time that the logic thread can begin processing the next tick. Set up an expensive scene, log it and you should see this order:
Renderer acquires lock Renderer releases lock - Logic thread acquires lock and - flush/swap starts in either order --- - Logic thread releases lock and - Renderer.onDrawFrame() is called in either order So there will be time for the logic thread to run while waiting on the GPU. Bob, Perhaps we're just arguing semantics. I was simply saying that you can only call a thread idle when it is in wait() or sleep(), neither of which consume any CPU. If it is in any other state, it is not idle. I don't remember calling a Looper/Handler slow specifically but I will say with certainty that there is more overhead there than a simple wait/notify or sleep, though it is probably negligibly more when we're only talking about 60 times per second. I personally think a simple loop in a thread is easier to read and manage but it is just a matter of preference. On Apr 10, 2:57 pm, Bob Kerns <r...@acm.org> wrote: > If a thread is hogging the CPU, it is *BY DEFINITION* not idle. And > vice versa. > > An idle thread will be waiting on something. Either a synchronization > lock, or an object using wait(), or some blocking IO call. This may be > buried inside some other code, of course. > > I would suggest wondering why you thought this. How are you > determining what threads are consuming what CPU? Either you have some > sort of methodology error, or interpretation error. > > I would wonder about your statement about a Looper and Handler being > slow. I haven't read the code, but the implementation I would expect > would be very simple, and using wait/notify. In other words, they > SHOULD be fast. If you find them slow, I'd again check your > methodology -- and if you can confirm, I'd suggest filing a bug > report, since that's something that could be improved and would > improve things for the entire platform. > > Re 60 fps game logic -- some alternatives to consider that may be > better choices in some circumstances. I'm only considering physics > here; I'm not sure what the time constraints on other game logic might > be: > > If you're doing your physics calculations correctly, you won't be > constrained to a constant game logic rate. You may be able to vary > your simulation time step to maintain a more steady render rate (at > the cost of some accuracy), and even vary it between different parts > of the model, e.g. critical portions (e.g. collisions) run a higher > rate, while running a longer timestep for portions not subject to time- > varying forces. > > If smooth display is more important than physical accuracy, running > physics after each frame, driven by actual elapsed time, may be the > way to go. You can trigger that as you're about to flip the scene, so > it overlaps the GPU. You may prioritize your fast-moving stuff, and > only update a portion of your model on each frame. > > Also, you may be able to apply Level of Detail (LOD) control to your > scene -- including fewer polygons when the overall frame rate drops > (due to either graphics or physics). > > All that is a lot more complex, of course, but may let you push the > envelope a bit further. > > On Apr 9, 7:42 pm, Miguel Morales <therevolti...@gmail.com> wrote: > > > > > I may be completely wrong on this, but I've found that threads hog the > > CPU even when idle. > > > The way that has worked well for me is to have the render thread, and > > the logic timer. > > > (using a looper and communicating via a handler can be slow, from my > > experience locks are faster) > > > To keep things simply I use a TimerTask to simulate a 60fps game logic > > rate (game_loop_timer.schedule(game_loop_task, 0, 17);). The game > > logic rate can vary based on what needs to be done. (i.e pathfinding, > > network syncing, etc.) and sets a scene to the buffer. > > > The render thread stays constant by simply drawing what's on the scene > > buffer at every onDraw. > > > I use a single lock to keep the scene buffer safe between the two threads. > > > It's actually pretty simple, and I only really need two classes. > > > I highly recommend reading articles about this, here are some of my > > bookmarks:http://gafferongames.com/game-physics/fix-your-timestep/http://stacko...... > > > For input, I use a lock for the state of the hardware. (i.e. when the > > screen is being touched, I set a boolean isTouched to true and use a > > lock to safely read/write from the threads. However, a queue/handler > > is really the way to go when it comes to that since it's not as > > time/latency sensitive. > > > On Fri, Apr 9, 2010 at 6:29 PM, Lance Nanek <lna...@gmail.com> wrote: > > > There are a lot of built in classes in Android and Java that you can > > > use to avoid having to write any synchronization or lock code > > > yourself. In my case GLSurfaceView sets up my render thread. I use > > > HandlerThread for my game thread. The game thread sends an update > > > object detailing all the draw commands needed for a frame to the > > > render thread via a BlockingQueue. The render thread returns it via > > > the game thread's Handler. The UI thread tells the game thread about > > > input via the game thread's Handler as well. These classes are in the > > > android.os and java.util.concurrent packages. > > > > On Apr 9, 6:36 pm, Eddie Ringle <ed...@eringle.net> wrote: > > >> Okay, I figured I could just pass the Activity through parameters, but > > >> wanted to know if a better way was possible. > > >> Thanks for all the help everyone. > > > >> On Apr 9, 5:56 pm, Mario Zechner <badlogicga...@gmail.com> wrote: > > > >> > That depends on what kind of input you need. If your game is happy > > >> > with just checking the current state of the accelerometer/touch screen/ > > >> > keyboard/trackball simply polling will do the trick. This means that > > >> > in the UI thread, where you have your event listeners installed, you > > >> > simply save the last state reported to you. In your logic thread you > > >> > can savely access this state even without synchronization as it will > > >> > only be composed of plain old data types like booleans or ints (of > > >> > course there are cases where you catch the x coordinate of the > > >> > previous event and the y coordinate of the current event but i dare > > >> > say that the differences are so tiny, it doesn't make a difference). > > > >> > Other things might need event based input handling, like a GUI you > > >> > implement yourself with say OpenGL. In that case you will need a queue > > >> > that gets filled in the Android GUI thread by the listeners you have > > >> > installed for the input devices. The logic thread acts as a consumer > > >> > and takes the events from the queue. As you are working with a complex > > >> > data structure you need to synchronize the adding and removing of > > >> > events to and from the queue in both the Android GUI thread and your > > >> > logic thread. This is a classical consumer/producer pattern which can > > >> > be found frequently in multithreaded applications. Check out Robert's > > >> > site athttp://www.rbgrn.net, i think he wrote an article on that sort > > >> > of thing once. > > > >> > it basicaly boils down to this (pseudo code, written from the top of > > >> > my head, will not compile) > > > >> > public class GameActivity extends Activity implements > > >> > MotionEventListener > > >> > { > > >> > Queue<Event> events = new Queue<Event>(); > > > >> > public void onTouch( MotionEvent event ) > > >> > { > > >> > synchronized( events ) > > >> > { > > >> > events.add( new Event( event.getX(), event.getY() ); > > >> > } > > >> > } > > > >> > } > > > >> > public class GameLogic > > >> > { > > >> > GameActivity activity; > > > >> > public GameLogic( GameActivity activity ) > > >> > { > > >> > this.activity = activity; > > >> > } > > > >> > public void handleInput( ) > > >> > { > > >> > synchronized( gameActivity.events ) > > >> > { > > >> > // proces events here > > >> > } > > >> > } > > > >> > } > > > >> > Now, a couple of comments: You don't want to instantiate a new Event > > >> > everytime a listener method in the GameActivity is called. You will > > >> > need to implement a simple object pool and reuse events. That way the > > >> > garbage collector will stay calm. Also note that the design above is a > > >> > bit nasty, i would directly pass the GameActivity to the GameLogic > > >> > among other things. But that's up to you. > > > >> > Polling input handling would work like above but without a queue and > > >> > without the need for the synchronized blocks. All you do is set some > > >> > members of GameActivity, say touchX and touchY in the onTouch method > > >> > and read those values in the GameLogic class' handleInput method. > > > >> > hth, > > >> > Mario > > > >> > On 9 Apr., 22:39, Eddie Ringle <ed...@eringle.net> wrote: > > > >> > > Robert, > > > >> > > Silly question, but how do you get input to the logic thread? I have > > >> > > to get sensor and touch data from the main Activity class and somehow > > >> > > get it to the logic thread. > > > >> > > Current program flow is as follows: > > >> > > onCreate() -> GameView() -> World() & Renderer() & GameLogic() > > > >> > > On Apr 9, 3:24 pm, Robert Green <rbgrn....@gmail.com> wrote: > > > >> > > > Eddie, > > > >> > > > Yes, that'll do the trick. > > > >> > > > As far as the multiple threads goes, sure you can drive your logic > > >> > > > off > > >> > > > of the call to onDrawFrame but there is a situation in which > > >> > > > having a > > >> > > > separate thread makes sense: > > > >> > > > After onDrawFrame, the rendering thread is finishing/swapping. > > >> > > > That > > >> > > > can actually take a decent amount of time to do in certain cases > > >> > > > and > > >> > > > most of it is happening on the GPU, especially on a device like the > > >> > > > Droid which has a discrete CPU/GPU. During that time, the CPU is > > >> > > > available and can be used on the logic thread. Properly > > >> > > > implemented, > > >> > > > in a heavy scene you can get some or all of the logic processed > > >> > > > before > > >> > > > the rendering thread is ready again, which is why I favor it. > > > >> > > > My question is: onDrawFrame is only called once the GPU is ready > > >> > > > for > > >> > > > another draw. Why waste those precious GPU idle moments just doing > > >> > > > CPU stuff like physics and collisions? You can maximize with > > >> > > > another > > >> > > > thread. > > > >> > > > Also - 2 (game and UI) or 3 threads (game logic, rendering and UI) > > >> > > > does make sense because you never want to block the UI thread in > > >> > > > Android. Get out of its way as fast as possible! :) > > > >> > > > On Apr 9, 1:58 pm, Eddie Ringle <ed...@eringle.net> wrote: > > > >> > > > > Is it as simple as: > > > >> > > > > In GameView.java (my custom GLSurfaceView class): > > >> > > > > World _world = new World(); > > > >> > > > > GameRenderer _renderer = new GameRenderer(_world); > > > >> > > > > In GameRenderer.java: > > >> > > > > public World _world; > > > >> > > > > public GameRenderer(World world) > > >> > > > > { > > >> > > > > _world = world; > > ... > > read more » -- You received this message because you are subscribed to the Google Groups "Android Developers" group. To post to this group, send email to android-developers@googlegroups.com To unsubscribe from this group, send email to android-developers+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/android-developers?hl=en To unsubscribe, reply using "remove me" as the subject.