Disclaimer: it's possible I'm going about this in completely the wrong way & trying to solve the wrong problem.
I'm writing an Android app that uses Google Maps to show cloud cover over a 1km square area by adding a 1km-diameter circle to the map for each area with detected cloud cover via the following (probably naive) method:
CircleOptions options = new CircleOptions();
// ... set the center, radius, fillColor, strokeWidth, and strokeColor...
mMap.addCircle(options);
If there are just a few dozen circles added to the map, the performance is fine. If half the state of Florida is covered with clouds, the program chokes & hangs the UI for 5-30 seconds while it makes a few thousand calls to addCircle()
AsyncTask won't work here, because the time-consuming jobs are the calls to mMap.addCircle(), which HAVE to be made from the UI thread. I actually tried using doInBackground() to populate an array of CircleOptions, then iterated through it in onPostExecute() to make the calls to addCircle()... and as expected, it made absolutely no difference whatsoever to the app's performance (I think populating the CircleOptions array in doInBackground() shaved a whopping 18ms from the execution time on the UI thread).
In Unity, I could just use the Update() lifecycle method (which gets called once per video frame) and make 20-50 calls to addCircle() at a time before exiting to give it time to metaphorically go up for air and service the UI before the next batch. But AFAIK, Android Activity has no equivalent to this. You can do things that don't require UI changes in a background thread, then update the UI when it finishes... but there doesn't seem to be any explicit provision in Android for gracefully spreading multiple time-consuming UI updates across multiple frames.
So... DOES Android have some way to gracefully batch time-consuming UI updates across multiple frames a-la-Unity? Or is there a better way to render circle overlays onto a Google Map that can scale gracefully and handle thousands of such circles without choking?
Related
The way I understand the HERE Android SDK is that there's a MapView that has a backing Map object. Adding objects, setting the center, zooming etc should be performed on the Map object and this eventually reflects on the MapView.
Question:
Are there any restrictions on what thread the operations on the Map object must be performed? For example, must they all be called on the UI thread? Also, should multiple subsequent calls be synchronized?
I ask this because I want to make multiple changes in a Map (resize the map view, change some visible layers, change the scheme, add a MapRoute and zoom out to the bounding box of the route). When I try this, it sometimes works but sometimes doesn't. Sometimes, only some of the operations are applied. For example, everything works except the zoom is not applied.
I know there are some listeners that can help me:
Map.OnTransformListener - this I can use to let me know when a zooming operation has ended
Map.OnSchemeChangedListener - this I can use to know when a scheme change event has ended
What is not clear to me from the documentation is what other operations constitute a "transform"? Which of these operations must be performed in a synchronized fashion?
For example, is the following code expected to behave correctly?
map.setCenter(coordinate, Animation.BOW, 18, 0f, 60f);
map.addMapObject(routeObject);
map.setVisibleLayers(layersToShow, true);
map.setScheme(Map.Scheme.NORMAL_DAY)
Note that in the above example, I'm proceeding to make changes immediately after setCenter even before the animation is complete. Is this the expected way to use the API?
There is no restriction on what thread you call the API from. Internally, all calls are synchronized and thread safe.
What you are looking for is the MapView#executeSynchronized API. [link] This will batch up a few operations into one screen redraw. [At least when I wrote that API a few years ago]
What you are experiencing happens because the underlying rendering thread started drawing some of the commands from the calling thread. This caused subsequent calls to lose effect.
Will calling stage.act on a seperate thread within an infinite loop is a good idea?
Is there any pros and cons on this approach?
I've tried doing it,but im not sure if this will cause problem in the long run. it looks faster though.
From LibGDX documentation:
No class in libgdx is thread-safe unless explicitly marked as thread-safe in the class documentation.
You should never perform multi-threaded operations on anything that is
graphics or audio related, e.g. use scene2D components from multiple
threads.
From Stage api:
The Stage and its constituents (like Actors and Listeners) are not thread-safe and should only be updated and queried from a single thread (presumably the main render thread).
So how you can see, it's a bad idea.
We always write stage.act in render method and purpose of that we get time(dt) between 2 render method(Gdx.graphics.getDeltaTime()) call. You can write stage.act in your own loop. but for that you have to manage stop calling stage.act().
If you want to set same anim speed in every device then you should use
stage.act(Gdx.graphics.getDeltaTime()).
Talking in context of a game based on openGL renderer :
Lets assume there are two threads :
that updates the gameLogic and physics etc. for the in game objects
that makes openGL draw calls for each game object based on data in the game objects (that thread 1 keeps updating)
Unless you have two copies of each game object in the current state of the game you'll have to pause Thread 1 while Thread 2 makes the draw calls otherwise the game objects will get updated in the middle of a draw call for that object ! which is undesirable!
but stopping thread 1 to safely make draw calls from thread 2 kills the whole purpose of multithreading/cocurrency
Is there a better approach for this other than using hundreds or thousands or sync objects/fences so that the multicore architecture can be exploited for performance?
I know I can still use multiThreading for loading texture and compiling shaders for the objects which are yet to be the part of the current game state but how do I do it for the active/visible objects without causing conflict with draw and update?
The usual approach is that the simulation thread after completing a game step commits the state into an intermediary buffer and then signals the renderer thread. Since OpenGL executes asynchronously the render thread should complete rather quickly, thereby releasing the intermediary buffer for the next state.
You shouldn't render directly from the game state anyway, since what the renderer needs to do its works and what the simulation produces not always are the same things. So some mapping may be necessary anyway.
This is quite a general question you're asking. If you ask 10 different people, you'll probably get 10 different answers. In the past I implemented something similar, and here's what I did (after a long series of optimisation cycles).
Your model-update loop which runs on a background thread should look something like this:
while(true)
{
updateAllModels()
}
As you said, this will cause an issue when the GL thread kicks in, since it may very well render a view based on a model which is half way through being rendered, which can cause UI glitches at the best case.
The straight-forward way for dealing with this would be synchronising the update:
while (true)
{
synchronized(...)
{
updateAllModels();
}
}
Where the object you synchronize with here is the same object you'll use to synchronize the drawing method.
Now we have an improved method which won't cause glitches in the UI, but the overall rendering will probably take a very severe performance hit, since all rendering needs to wait until all model updates are finished, or vise versa - the models update will need to wait until all drawing is finished.
Now, lets think for a moment - what do we really need to be synchronizing?
In my app (a space game), when updating the models, I needed to calculate vectors, check for collisions and update all the object's positions, rotations, scale, etc.
Out of all these things, the only things the view cares about is the position, rotation, scale and a few other small considerations which the UI needs to know in order to correctly render the game world. The rendering process doesn't care about a game object's vector, the AI code, collision tests, etc. Considering this, I altered my update code to look something like this:
while (true)
{
synchronized(...)
{
updateVisibleChanges(); // sets all visible changes - positions, rotations, etc
}
updateInvisibleChanges(); // alters vectors, AI calculations, collision tests, etc
}
Same as before, we're synchronising the update and the draw methods, but this time, the critical section is much smaller than before. Essentially, the only things which should be set in the updateVisibleChanges method are things which pertain to the position, rotation, scale, etc of the objects which should be rendered. All other calculations (which are usually the most exhaustive ones) are performed afterwards, and do not stop the rendering from occurring.
An added bonus from this method - when you're performing your invisible changes, you can be sure that all objects are in the position they need to be (which is very useful for accurate collision tests). For example, in the method before the last one, object A moves, then object A tests a collision against object B which hasn't moved yet. It is possible that had object B moved before object A tested a collision, there would be a different result.
Of course, the last example I showed isn't perfect - you will still need to hang the rendering method and/or the updateVisible method to avoid clashes, but I fear that this will always be a problem, and the key is minimizing the amount of work you're doing in either thread sensitive method.
Hope this helps :)
Hi Android Developers,
What is the best way to interrupt a current rendering phase of GLSurfaceView and start a new one when mode is equal to "Render_when_dirty"? I artificially stop rendering in "onDraw" method by checking a flag and returning from actual rendering method which is called in "onDraw" method; then, in main thread's context i call "requestRender()" to refresh the scene. However, due to a reason that i am not aware of, some of the intermediary old frames are displayed for a very very short period of time(on the other hand, they endure for so long period of time that users can realize the transition); before actual scene is rendered by opengl es 2.x engine. It doesn't affect anything at all; but troublesome to be fixed. What do you suggest?
P.S. Throwing InterruptedException within onDraw method is useless due to the destruction of actual rendering thread of GLSurfaveView.
Kind Regards.
When you say some of the old frames are drawn - do you mean part of the frame that is drawn is old or multiple calls of onDraw() still lead to some of the old information being shown on the display.
There are a few things I can see happening here. If you have a onDraw() like this:
onDrawFrame(){
... stuff ...
if (stateVariableSet)
return;
... stuff ...
my understanding is that when the function is done being run, that the back/front buffer get swapped and drawn. One thing that could be happening here is that you see a few calls of onDrawFrame() being rendered while you try to update the state/State variable.
On the other hand, if you have something like this:
onDrawFrame(){
... stuff..
semaphore.acquire(); // lock the thread waiting for the state to update
... stuff ...
then the things that have been drawn before the lock will be stale (for that frame only though - at least that's what I'd anticipate).
Also are you running on a multi-core system?
I am currently writing an app that should display a real time measurement curve in a scrolling fashion (think ECG recorder or oscilloscope). An unexpected system call in the UI-Thread makes the display stutter.
The data rolls in via bluetooth. All works fine and the display is reasonably smoothly scrolling with an average update rate of 26 frames/s. But, nevertheless the display is stuttering remarkably.
I used traceview to get more insight and according to traceview the stuttering is the result of a call to android/view/ViewRoot.handleMessage which lasts 131 ms per call on average.
If I dig down further in traceview the cycles are burnt inside android/view/ViewRoot.performTraversals. 92% of these CPU cycles are consumed in mostly recursive calls to android/view/View.measure.
From there it gets complicated due to the recursive call structure. But I can find calls to the onMeasure() method of LinearLayout, FrameLayout and RelativeLayout. The onMeasure() method of each Layout type consumes about the same amount of CPU cycles. Which is very strange since in my activity I use only a simple LinearLayout with just 2 Elements.
I just see no reason on why a supposed re-layout of a LinearLayout with 2 Elements performs calls to non-used Layouts and takes a whopping 131 ms to do that.
Further info:
Platform HTC desire HD with Android 2.3.1.
I use a handler to perform the drawing in the UI thread.
The Layout is a simple LinearLayout with 2 Elements: a custom view and a textField.
The status bar is hidden with getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);.
The drawing is performed on each new block of data, which arrives approx. every 50 ms.
The drawing itself uses a canvas and is performant enough to keep up with the incoming data.
After that long explanation, here are the questions:
What is calling the android/view/ViewRoot.handleMessage? (the calls are relatively equal spaced every 850 ms and have no obvious link (no direct calls, number of calls and relative positions are not linked to the message handler for drawing) to any activity of my Activity)
How can I suppress the calls to android/view/ViewRoot.handleMessage or how can I make them faster (there are just 2 elements in my LinearLayout)
the calls to unused layouts first got me think of the status bar or some hidden activity (e.g. home screen), which may use such layouts. But how come those calls are part of the trace of my activity? As far as I understand the trace should only trace the active process. e.g. the calls of my service which produces the real time data is not part of the trace.
Is there any possibility to trace individual calls to some system components? When I zoom in in traceview I see this call sequence: toplevel -> android/os/Message.clearForRecycle() -> android/os/MessageQueue.nativePollOnce() -> android/os/SystemClock.uptimeMillis() -> com/htc/profileflag/ProfileConfig.getProfilePerformance() -> android/os/Handler.dispatchMessage() -> android/view/ViewRoot.performTraversals()
Off topic: Is there a possibility to export the data which is shown inside traceview (parents-children-CPU time etc.) other than a screenshot?
Ok, I found the reason for the long call to android/view/ViewRoot.handleMessage.
This was indeed caused by my application.
My App has 2 screens (Activities) one with a complicated Layout for status information and the other one the real time display of incoming data.
The data, which comes in over bluetooth contains mixed real time data and status data. When I switch to the real time Activity, I was stopping the status Activity with finish(); after starting the new real time Activity. Unfortunately this is not enough to stop also the message handler, which receives the new status information in the UI thread, and continued to update status data in an invisible and finished Activity. The relayout of this activity caused the stutter of the real time data.
This is now solved. The display scrolling is now reasonable smooth.
Thanks for your patience. May it be useful to anyone who stumbles on this Thread on stackoverflow.
jepo