0

(via Xamarin C#) On Android I am unable to create the framebuffer.

I have a subclassed Android.OpenGL.GLSurfaceView, set to GL ES 2, with preserve EGL Context, and my other GL commands are drawing successfully, with no GLErrors:

public class PaintingView : GLSurfaceView, GLSurfaceView.IRenderer
{
    public PaintingView( Context context, IAttributeSet attrs ) :
        base( context, attrs )
    {
        SetEGLContextClientVersion( 2 );

        // Set the Renderer for drawing on the GLSurfaceView
        SetRenderer( this );
        PreserveEGLContextOnPause = true;
    }

    public void OnSurfaceCreated( IGL10 gl, Javax.Microedition.Khronos.Egl.EGLConfig config )
    {
        ...
    }
}

OnSurfaceCreated does get called, and it invokes the following code on the UI thread via myActivity.RunOnUiThread( Action ), as part of creating a buffer of desired size for offscreen rendering:

        frameBuffer = -123;   // Invalid value, so we can test whether it was set.
        GL.GenFramebuffers( 1, out frameBuffer );
        Shader.CheckGLError( "Offscreen.Resize 1" );   // My method that checks result of "GL.GetErrorCode()"
        if (frameBuffer <= -1) {
            ... failed to assign an FBO!
        }

Problem:

GenFramebuffers failed to assign an FBO - "frameBuffer" is still set to "-123".

Q: Why might this occur? Is there something I was supposed to do first? Is there a working Xamarin example of using an FBO on Android?

NOTES:

  1. On iOS we successfully used code that created a second EGLContext and pbuffer for offscreen rendering, but after reading that switching between two EGLContexts has poor performance on Android, we are attempting an FBO approach for Android.

  2. The problem seems to be specific to Android, as it involves setting up the FBO.

  3. I've seen several java examples of using an FBO on Android, but have been unable to get past this first step, using Xamarin.

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196

1 Answers1

1

This isn't a Xamarin-specific issue. The problem is attempting to create and use an FBO at a time that the current (active) EGLContext is not able to handle GL calls (even though GLError did not report an error).

The code needs to be part of the draw cycle for the GL view that the FBO will be rendered to.

For an Android.OpenGL.GLSurfaceView, that means "during GLSurfaceView.IRenderer.OnDrawFrame( IGL10 gl )":

public class PaintingView : GLSurfaceView, GLSurfaceView.IRenderer
{
    ...
    public void OnDrawFrame( IGL10 gl )
    {
            Int32 frameBuffer = -123;   // Invalid value, so we can test whether it was set.
            GL.GenFramebuffers( 1, out frameBuffer );
            Shader.CheckGLError( "PaintingView.OnDrawFrame 1" );   // My method that checks result of "GL.GetErrorCode()"
            if (frameBuffer <= -1) {
                ...
            }
            ...
    }
}

Here, frameBuffer gets assigned "1". (On the first call. On second call it is "2", and so on. TBD whether these increasing values are a bad sign.)

TBD whether we should create it once and re-use it in future calls, or recreate it each time.

TBD whether there is an earlier point in GLSurfaceView's lifecycle, at which this can be initialized. If done too early, the view is not attached to the window, so there is no surface, so all GL calls fail because Android has not initialized an EGLContext yet for this view. In addition, it needs to be done on the GL rendering thread, which AFAIK is only accessible via OnDrawFrame.

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
  • For an example of using an offscreen buffer, **without** having a `GLSurfaceView` or `TextureView`, see [multiple thumbnails of GLES scenes](http://stackoverflow.com/a/41525113/199364). – ToolmakerSteve Jan 07 '17 at 19:39