Our app generates a number of scenes using GLES 2. Making a picker (scrolling list of images) to select which scene to go to. The scenes are not available as pre-made images; using GL rendering at the time they are needed. On iOS, we created the scenes in an offscreen pbuffer, as they became visible while the list scrolled.
Attempt #1: On Android, the code equivalent to our iOS code yields GL Errors, because there is no current EGLContext (or it is not a valid time or thread to render to current context). On iOS we found examples of offscreen rendering that did not depend on any association with a GL view. On Android, most examples seem to assume you are inside the drawing code of a GLSurfaceView, so you are already on the GL thread with correct EGLContext. Or they were pre-Lollipop examples, when the framework's internal EGLContext apparently was exposed to the app, so code "just worked", even if it wasn't threadsafe (so eventually causes problems).
Attempt #2: GLSurfaceView per thumbnail. Works great for one thumbnail. Add second thumbnail, emulator crashes with graphics driver error. I think due to two GL threads managed by the GL views.
Attempt #3: Approach used by Grafika as described by fadden: multiple surfaceviews (not GLSurfaceViews), manage own GL thread to render to those surfaceviews. This would likely work if not inside a scrolling list, could change to textureviews (but must share GL thread or maybe EGLContext's in a shared group - see Grafika) to work better with scrolling, but still not a good idea for more than 2 to 4 thumbnails, as per fadden's comment about performance cliff when hit the compositor's limit on N number of surfaces.
Attempt #4: GL with no surfaceviews at all. Manage own GL thread (a la Grafika). When thumbnail draws, render GL into an FBO or pbuffer. Convert to bitmap. Display that bitmap in the thumbnail view. Note that this is different than examples I've seen, because the bitmap doesn't exist at the time the view is created; it only exists when the view goes to draw. Cache the bitmaps so can reuse on each draw.
For #4, here are the subtasks:
- An EGLContext and GL thread.
- Create FBO of correct size, or use our pbuffer code that already works on iOS. (Probably was copied from an ancient example; I understand that FBO would be more efficient solution).
- Render GL into buffer. [This code already works; app-specific.]
- Capture buffer into an Android bitmap. [I have an example of this; not shown here.]
- Dynamically display bitmap in view. For example, attach bitmap to an ImageView.
(1.) is the subtask I am asking how to do.
NOTE #1: Could avoid all this by making the entire scrolling view a single GL surface, simulating list scrolling, rendering each scene into an appropriate rectangle - but that would complicate our cross-platform code (Xamarin), and eliminate flexibility. Seeking a solution that fits into Android's view hierarchy, so can add text captions, or any other desired change. Then we would have a general-purpose ability to render GL anywhere we want, and compose that with non-GL features provided by Android.
NOTE #2: Unlike Grafika, don't need the GL rendering to change every frame. That is why we don't need multiple surfaceviews - once the bitmaps exist, we can reuse them. So the solution won't be multiple real-time GL views. If you are seeking that, limit the number of views, and use Grafika's approach with several SurfaceViews (or TextureViews if need to move them around).
NOTE: This is Xamarin C# code. That is why it has different capitalization and other naming differences (java get/set methods replaced by C# properties). It uses Xamarin wrappers for Android java, a java version would be a 1:1 translation of each line of code.
OurGLRenderer
is a custom class to manage anEGLContext
. This allows GL rendering without aGLSurfaceView
orTextureView
.The heart of this class is "
MakeCurrent
": after calling that, you can make GL calls, because you have an activeEGLContext
. The GL calls render to an offscreen buffer, previously created inCreateGLAndSurface
viaCreateOffscreenBuffer
.To instead render to a
TextureView
(orSurfaceView
?), then useCreateWindowSurface
instead ofCreateOffscreenBuffer
.