I am developing the android app with NDK and using OpenGL. But I have a problem.
Normally, The OpenGL context is created and destroyed many times during the app running.
after a while, OpenGL is giving that error message.
W/Adreno-GSL: <gsl_ldd_control:553>: ioctl fd 81 code 0xc0080913 (IOCTL_KGSL_DRAWCTXT_CREATE) failed: errno 28 No space left on device
I know that means I couldn't destroy the OpenGL context but it seems everything ok for destroying the OpenGL context. Here is an example of destroying. What can I do to clear the OpenGL context? Or, May it be an Operating System error?
eglMakeCurrent(this->m_egl_display,EGL_NO_SURFACE,EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(this->m_egl_display, this->m_egl_context);
eglDestroySurface(this->m_egl_display, this->m_eglSurfacePbuffer);
eglTerminate(this->m_egl_display);
I searched many different websites and saw the following
https://lwn.net/Articles/394665/
https://issuetracker.google.com/issues/36982885
https://www.ics.uci.edu/~ardalan/papers/Hung_MobiCom22.pdf
I want to learn how to destroy the OpenGL context clearly. But all implementations look like same. Also, I wonder if it is an operating system bug.
Related
There's some possibility for an android OpenGL application of GL context loss while on background. So, to keep things simple, if you're got unexpected Renderer.onSurfaceCreated call - whoah, you're lucky. System wiped you out and you have to recover all you GL stuff from scratch.
One thing that rather bothers me and google documentation seems to keep silence about - how could one firmly and efficiently reproduce the issue during development?
When I pause/unpause my app really fast then I get the following problem:
E/BufferQueueProducer( 177): [SurfaceView] connect(P): already connected (cur=1 req=1)
E/libEGL (25863): eglCreateWindowSurface: native_window_api_connect (win=0xb4984508) failed (0xffffffea) (already connected to another API?)
E/libEGL (25863): eglCreateWindowSurface:416 error 3003 (EGL_BAD_ALLOC)
Im pretty sure that I am stopping/starting my render thread correctly and this issue really only occurs when I pause/resume the app really fast (like when you mash the open-apps button).
Any ideas what might be the cause for eglCreateWindowSurface returning EGL_NO_SURFACE here? My guess would be it has to do with something still being connected to the SurfaceView.
It sounds like you're trying to create an EGLSurface for a Surface that already has one. If speed is an issue it's usually because of the lag in Surface callback handling -- the SurfaceView Surface is partially handled by the Window Manager, which requires inter-process communication.
Perhaps your native code still has a handle to the old SurfaceHolder, and if you moved more slowly the handle would be replaced by an upcoming surfaceCreated()? It's hard to say without knowing exactly what your code does. One way to approach these sorts of problems is by adding logging at all the interesting state change points, and comparing the logs from "slow" pause/resume and "fast" pause/resume.
It should be possible to avoid these situations by managing the SurfaceView state carefully. This appendix to the graphics arch doc talks about the difference between the Activity and SurfaceView lifecycles, and two ways to structure an app to avoid issues.
I have a setup with OpenGL ES 2.0 and EGL on Android 4.4.2 (API level 19).
My goal is to access the buffer of the window (the default framebuffer in OpenGL terms) directly from the CPU / user space.
I have tried using ANativeWindow_fromSurface to get ANativeWindow from the Surface of a GLSurfaceView. Then trying to get access to the buffer with ANativeWindow_lock fails with status -22. Logcat gives
03-25 10:50:25.363: E/BufferQueue(171): [SurfaceView](this:0xb8d5d978,id:32,api:1,p:6488,c:171) connect: already connected (cur=1, req=2)
From this discussion it seems you can't do that with GLSurfaceView, because EGL has already acquired the surface.
How could you get to the memory of the window? Can you somehow do it through an EGLSurface? I am willing to use android::GraphicBuffer, even tough it is not part of the NDK.
If this is not possible, can you use the other direction, by first creating an android::GraphicBuffer and then binding it to an EGLSurface and the displayed window?
Android devices may not have a framebuffer (i.e. /dev/graphics/fb). It's still widely used by the recovery UI, but it's being phased out.
If it does have a framebuffer, it will be opened and held by the Hardware Composer unless the app framework has been shut down. Since you're trying to use the NDK, I assume the framework is still running.
If your NDK code is running as root or system, you can request a top window from SurfaceFlinger. The San Angeles demo provides an example.
Additional information can be found here, here, and here. If you want to work with graphics at a low level, you should also read the graphics architecture doc.
This is not doable with just NDK API, you will need to pull-in some OS headers, that are not guaranteed to be stable.
You will need to subclass ANativeWindow, similarly to what is done in frameworks/native/include/ui/FramebufferNativeWindow.h.
However you may need to construct your own buffer queue using own-created android::GraphicBuffer objects, and properly respond to all dequeue() and enqueue() requests.
On enqueue() you will need to sync (GPU renders asynchronously) and than map enqueued buffer to CPU memory.
Note that this approach may be underperformant, due to explicit GPU<->CPU sync needed.
How to draw some stuff before surfacefligner start on android?
In this situation, it's some kind of traditional Linux with framebuffer device, so directly access framebuffer should be OK.
How about to use HWComposer directly and how about to use egl directly?
If SurfaceFlinger isn't running, you can just open the framebuffer device and write to it (assuming you're on a device that has a framebuffer device).
For an example of this, see the implementation of the "recovery" UI. The key file there is minui/graphics.c. The current implementation relies on libpixelflinger.
Using OpenGL ES / EGL will be a bit more tricky. Some of the early GLES tests, such as San Angeles, use the FramebufferWindow class, but that uses a fair bit of the framework. (FWIW, an upcoming release is expected to deprecate FramebufferWindow and switch the OpenGL tests that use them to a new library that talks to SurfaceFlinger.)
Update: the upcoming release happened, and you can see the replacement for FramebufferWindow ("WindowSurface") here.
If SurfaceFlinger isn't running you can talk to HardwareComposer directly, using the internal interface. There are some old tests that exercise it, but I don't know if they still work. The code in SurfaceFlinger is probably a better example at this point. Only one process can open HardwareComposer at a time, so SurfaceFlinger must not be running.
Question:
Considering the hello-gl2 example from Android NDK r6b, is this example correct when user repeatedly invokes pause/resume actions of the GLSurfaceView? I'm asking because each time a GL2JNIView.Renderer.onSurfaceChanged() is called, it creates all OpenGL resources (shaders, textures) but it never destroys them.
Background:
I'm trying to debug some OpenGL ES 2.0 game implemented using C++ and JNI which behaves incorrectly during pause/resume. I was trying to find some reference example for this but I haven't found any except of the mentioned hello2-gl example from NDK, which may IMHO create memory leaks, and this more complex version of it, which I'm currently using, but where it seems like OpenGL context is destroyed before GLSurfaceView finishes with its onPause() method where I'm destroying all the OpengGL shaders and textures bound to the context. Could you point me to some truly correct example of OpenGL ES 2.0 on Android using NDK concerning the correct way of pause/resume OpenGL resource handling?
Thank you for your help.
That's not quite the right lifecycle, but it's close. Any time a GL surface becomes completely obscured its EGL context will be destroyed, and when that happens any resources that you have allocated through OpenGL calls will be freed. As such, there is no need to manually free those resources unless your application requires active management during runtime (e.g. too many textures to cache in memory, etc).
Note that this only applies to resources and memory allocated by OpenGL via OpenGL calls. Any buffers that you allocate outside of OpenGL do need to be freed, as usual.