I'm currently developing a game, which only uses 2D graphics.
In the game i extensively use android's SurfaceView to display my graphics.
I've heard that GLSurfaceView uses Hardware-accelerated graphics, and i can increase performance of my app using that instead of the current SurfaceView.
Currently, i have a class extending SurfaceView, which updates and renders the game state, when methods update() and render() are called by my own thread class extending Thread. The Thread basically helps me maintain a nearly constant FPS.
NOW THE PROBLEM:
How do i change from SurfaceView to GLSurfaceView, and call methods to update and render game state from the Thread, to still have control over the FPS. I read the android documentation on OpenGL ES, and i can't quite understand how to use the GLSurfaceView.Renderer.
If someone can explain how can i easily switch from SurfaceView to GLSurfaceView, It'd be of great help! Thanks!
The Class that displays your game will extend GLSurfaceView. Your rendering class will implement Renderer. In your Renderer class you will need to add these unimplemented methods: onDrawFrame(), onSurfaceChanged(), and onSurfaceCreated().
Hope this helps.
Related
I got a problem with drawing a mapView from the here-api into a glSurfaceView (it should be a glSurfaceView as some external devices requeres it to ensure good performance).
The map draws into a normal SurfaceView just perfectly.
I do the following steps to create the map-view in the GLSurfaceView:
Extend my view from GLSurfaceView:
public class MapView extends GLSurfaceView
Setting the Renderer uppon initialisation in the ctors:
setRenderer(...)
Start rendering after the map has been initialized:
Renderer renderer = new MapOffScreenRenderer(getContext());
renderer.setMap(map); //mapView, not null
updateRendererSize(); //update the render size to the screen size
renderer.start(getHolder(), surfaceUpdatedListener); // HERE COMES THE CRASH
It seems like the MapOffscreenRenderer crashes if i try to tell him to draw the map into the glSurfaceView.
The crash is a generic error: "12291 EGL_BAD_ALLOC during rendering".
If i try to call the renderer.start() func (without the holder param), then everything is fine (the only bad thing is that the map is not being drawn).
The GlSurceView initialisation itself is fine as i am able to draw my own geometries into it.
Thank you very much for you help.
MapOffScreenRenderer internally uses a PBuffer backed surface and its own rendering thread and EGL context. It is not intended to be used to push into another GLSurfaceView surface. If you really want to do this then maybe create an independent OpenGL surface and share it between the GLSurfaceView and the MapOffScreenRenderer.
What use case are you try to accomplish using this type of design?
I am getting confused with EGL.
My GLSurfaceView creates an EGLContext. Now I create a shared context. Now I need to use a EGLExtension.
The Method I have to use is called (>=API18):
EGLExt.eglPresentationTimeANDROID(android.opengl.EGLDisplay display, android.opengl.EGLSurface surface, long time);
The Problem is, that the GLSurfaceView does only creates javax.microedition.khronos.egl.EGLContext s.
Which tells me, NOT to use GLSurfaceView. So I tried TextureView, which is slightly similar, with the difference that you have to handle your own EGL stuff. Which is good for that purpose.
But:
The TextureView is slower, at least it looked like that, so I recorded some diagrams with the Method Profiler:
Here the TextureView with own EGL Handling:
The Thread on the top is a clock that wakes the Thread in the middle, which renders onto the TextureView. The main Thread will be called after that, for redrawing the TextureView.
... and here the GLSurfaceView with their own EGL Handling
The clock is in the middle this time, it calls the Thread on the top to render my image into a framebuffer, which I give directly into the SurfaceView (RENDERMODE_WHEN_DIRTY) and call requestRender to request the view to render.
As you can see with a short look already that with the GLSurfaceView it looks way cleaner that with the TextureView.
On both Examples I havn't had anything else on the screen and they rendered exactly the same Meshes with the same shader.
To my question:
Is there a way to use GLSurfaceView with EGL14 Contexts?
Did I do something wrong?
What you probably want to do is use a plain SurfaceView.
Here's the short version:
SurfaceView has two parts, the Surface and a bit of fake stuff in the View. The Surface gets passed directly to the surface compositor (SurfaceFlinger), so when you draw on it with OpenGL there's relatively little overhead. This makes it fast, but it also makes it not play quite right with the View hierarchy, because the Surface is on one layer and the View-based UI is on a different layer.
TextureView also has two parts, but the part you draw on lives behind the scenes (that's where the SurfaceTexture comes in). When the frame is complete, the stuff you drew is blitted onto the View layer. The GPU can do this quickly, but "some work" is always slower than "no work".
GLSurfaceView is a SurfaceView with a wrapper class that does all the EGL setup and inter-thread messaging for you.
Edit: the long version is available here.
If you can do the GL/EGL setup and thread management yourself -- which, if you're now running on a TextureView, you clearly can -- then you should probably use a plain SurfaceView.
Having said all that, it should be possible to make your original code work with GLSurfaceView. I expect you want to call eglPresentationTimeANDROID() on the EGL context that's shared with the GLSurfaceView, not from within GLSurfaceView itself, so it doesn't matter that GLSurfaceView is using EGL10 internally. What matters for sharing the context is the context client version (e.g. GLES2 vs. GLES3), not the EGL interface version used to configure the context.
You can see examples of all of this working in Grafika. In particular:
"Show + capture camera" uses a GLSurfaceView, the camera, and the video encoder. Note the EGL context is shared. The example is convoluted and somewhat painful, mostly because it's deliberately trying to use GLSurfaceView and a shared EGL context. (Update: note this issue about race conditions with shared contexts.)
"Play video (TextureView)" and "Basic GL in TextureView" show TextureView in action.
"Record GL app with FBO" uses a plain SurfaceView.
Thanks to fadden! It worked as expected.
To everyone who thinks about doing something similar:
It has advantages AND disadvantages using the (GL)SurfaceView to render images on it.
My testresults in the post above do not have anything else on the screen than the rendered image itself.
If you have other UI elements on the screen, especially if they get updated frequently, you should reconsider my choice of prefering the (GL)SurfaceView.
The SurfaceView creates a new window in the Android Windowsystem. Its advantage is, that if the SurfaceView gets refreshed, only this window will be refreshed. If you additionally update UI Elements (which are in another window of the windowsystem), then both refresh operations block themselfes (especially when ui drawing is hardwaresupported) because opengl cannot handle multi thread drawing properly.
For such a case it could be better using the TextureView, cause it's not another window of the Android Windowsystem. so if you refresh your View, all UI elements get refreshed as well. (Probably) everything in one Thread.
Hope I could help some of you!
I have 2 Activitiys which use OpenGL for drawing. At a transition from one activity to the next I get an unsightly empty screen filled with my OpenGL clear colour (so its not as bad as a black screen).
I wish to effectively transition seamlessly between Activitys, but there are several high load regions when a GLSurfaceView is created. The main issue is texture loading as this is slowest.
Is there anyway to double buffer between Activitys so that the last Activity view is frozen until I explicitly tell my next Activity to draw? I want transitions to be seamless?
Moving everything into one GLSurfaceView instance isn't really an option I want to consider.
You can use setRenderMode( RENDERMODE_WHEN_DIRTY) in your GLSurfaceView, so the surface only will be redraw when you call requestRender().
This way, anything that you draw before calling another surface view will only be cleared when you request a new draw.
You can back to the continuous drawing by setting render mode as RENDERMODE_CONTINUOUSLY.
It is hard to do it in Android 2.x because of its OpenGL ES. Also, it is not recommended that you use two OpenGL in one applications if you are in render continously. If so, to control them easily, you will need RENDERMODE_WHEN_DIRTY.
If you use it in Android 4.x, TextureView is an optional to do it.
TextureView is as same as GLSurfaceView but with View compatible, it means that you can use ViewAnimation for TextureView.
I am working on a map engine. I would like to let user rotate the map. If I do the rotation by standard drawing on canvas, it will slow down the phone and the map tiles rotated by standard canvas API looks bad.
I found some OpenGL frameworks for Android on the Internet. But none of them do what I want. Most of them cannot use Android standard components within the OpenGL Activity.
I want to put a custom view that drawn by OpenGL to a Layout component (eg, LinearLayout). Thus, I can put everything (including OpenGL layout) to a Activity. I am sure that it can be done by using standard Android OpenGL API. But the OpenGL draw is too difficult to me.
Is it any OpenGL framework to let me draw a custom view by OpenGL? All I need is a framework that supports simple drawing.
Its called GLSurfaceView.
In one of my projects I have this:
public static GLView glSurfaceView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
glSurfaceView = new GLView(this);
setContentView(glSurfaceView);
}
Make sure the class you make extends the GLSurfaceView.
public class GLView extends GLSurfaceView
In the GLView class you will have to have this:
private GLRenderer _renderer;
public GLView(Context context) {
super(context);
_renderer = new GLRenderer(context);
setRenderer(_renderer);
}
The GLRenderer class will implement GLSurfaceView.Renderer
Atleast this is what I think you are asking. If not post comment below and I will try and answer it better.
It's a shame that you gave up on OpenGL, I've recently discovered it and find it heaps better then doing standard drawing. Using textures instead of keeping images as Bitmap objects takes much better advantage of device's memory (especially on the pre Honeycomb devices) and if you use an orthogonal projection you don't need to bother with a good portion of OpenGL's fancy 3d stuff. Plus, you no longer have to care (as much) about various devices resolutions so that all the stuff you put on screen is well proportioned (you still have to care about width and height ratio's but that's a lot better).
I'm developing chess game for Android (androidchess.appspot.com). If I want to add animations, should I use custom View extending Canvas (I do this now), or custom View extending SurfaceView?
I haven't tried using a View to extend Canvas, but for my game I'm using the same method as the LunarLander example game:
public class CustomView extends SurfaceView implements SurfaceHolder.Callback
The usefulness of this is that it gives you handles for SurfaceHolder (so you can call up the canvas which is drawn to the screen), and the callbacks for surfaceCreated, surfaceChanged and surfaceDestroyed. That lets you do things like drawing a custom animation as soon as the surface is available or make sure that you don't try to draw to the canvas after it has been deactivated. Looking through LunarLander should show you how to use these properly.
Edit: I remembered another reason why using a SurfaceHolder was useful. This is because, as I mentioned above, it lets you get direct access to the canvas which is drawn to the screen. With a SurfaceHolder this is done not by overriding onDraw but by using something like Canvas canvas = mSurfaceHolder.lockCanvas(). (See LunarLander for exact syntax). The reason this is important is because it lets you control exactly when the drawing happens. If you can only work by overriding onDraw(), then the drawing doesn't happen until your program reaches a 'waiting' phase. In other words, you can't use invalidate() and onDraw() in a loop because the drawing won't happen until the loop finishes. And since you're likely to use loops for things like drawing a piece moving across the screen, this becomes a problem.
Note: It may be possible to avoid this problem by using multiple threads. I simply haven't tried that since it isn't required for my game; the only animation is has is fixed-length animations in response to user input rather than something continuously moving in the background, so I haven't experimented with multiple threads yet.