Forum Xamarin.Android
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

Android TextureView only draws when OnSurfaceTextureUpdated is called

I'm using a TextureView for OpenGL rendering a view inside a ScrollView.

I have a derived class CustomView which inherits from TextureView which implements TextureView.ISurfaceTextureListener. In my OnSurfaceTextureAvailable override, I construct a custom renderer class which inherits from the standard Java.Lang.Thread:

public void OnSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)
{
    renderThread = new GLRenderer(surface); 
    renderThread.Start();
}

The code for my custom GLRenderer class is provided as follows:

private class GLRenderer : Thread
{
    private bool finished = false;

    private SurfaceTexture surfaceTexture;

    private IEGL10 gl;
    private EGLDisplay display;
    private EGLConfig config;
    private EGLContext context;
    private EGLSurface surface;

    private const int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
    private const int EGL_OPENGL_ES2_BIT = 4;

    public PlotRenderer(SurfaceTexture surfaceTexture)
    {
        if (surfaceTexture == null)
            throw new ArgumentNullException("surfaceTexture");

        this.surfaceTexture = surfaceTexture; 
    }

    public override void Run()
    {
        InitializeGL(); 

        while (!finished)
        {
            MakeCurrent();
            // Draw OpenGL stuff
            SwapBuffers();
        }

        FinalizeGL(); 
    }

    public void Finish()
    {
        Interrupt();
        finished = true; 
    }

    private void InitializeGL()
    {
        gl = EGLContext.EGL.JavaCast<IEGL10>(); 
        display = gl.EglGetDisplay(EGL10.EglDefaultDisplay);

        if (display == EGL10.EglNoDisplay)
            throw new Exception("Failed to get default display.");

        if (!gl.EglInitialize(display, new int[2]))
            throw new Exception("Failed to initialize EGL display.");

        config = ChooseEGLConfig(); 

        if (config == null)
            throw new Exception("EGL config is null", new ArgumentNullException("config"));

        context = gl.EglCreateContext(display, config, EGL10.EglNoContext, defaultAttribList);
        surface = gl.EglCreateWindowSurface(display, config, surfaceTexture, null);

        if (surface == null || surface == EGL10.EglNoSurface)
            throw new Exception("Failed to create EGL window surface.");

        MakeCurrent(); 
    }

    private void FinalizeGL()
    {
        gl.EglDestroyContext(display, context); 
        gl.EglDestroySurface(display, surface);
    }

    private EGLConfig ChooseEGLConfig()
    {
        var configsCount = new int[1]; 
        var configs = new EGLConfig[1]; 

        if (!gl.EglChooseConfig(display, defaultConfigSpec, configs, 1, configsCount))
            throw new Exception("Failed to choose EGL config.");

        return configsCount[0] > 0 ? configs[0] : null; 
    }

    private void MakeCurrent()
    {
        if (!context.Equals(gl.EglGetCurrentContext()) || !surface.Equals(gl.EglGetCurrentSurface(EGL10.EglDraw)))
        {
            if (!gl.EglMakeCurrent(display, surface, surface, context))
                throw new Exception("Failed to EGL make current.");
        }
    }

    private void SwapBuffers()
    {
        if (!gl.EglSwapBuffers(display, surface))
            throw new Exception("Failed to EGL swap buffers.");
    }

    private static int[] defaultConfigSpec =
        {
            EGL10.EglRenderableType, EGL_OPENGL_ES2_BIT,
            EGL10.EglRedSize, 8,
            EGL10.EglGreenSize, 8,
            EGL10.EglBlueSize, 8,
            EGL10.EglAlphaSize, 8,
            EGL10.EglDepthSize, 8,
            EGL10.EglStencilSize, 0,
            EGL10.EglSamples, 4,
            EGL10.EglNone
        };

    private static int[] defaultAttribList =
        {
            EGL_CONTEXT_CLIENT_VERSION, 2,
            EGL10.EglNone
        };
}

This is pretty standard TextureView stuff to set it up for rendering with OpenGL. However, the part of my code which renders when the line with // Draw OpenGL stuff is executed and visible on hardware when I rotate the device and OnSurfaceTextureUpdated is called.

My question is: why is my OpenGL view not rendering in an Android TextureView unless I rotate the device (or when OnSurfaceTextureUpdated is called)?

(Also posted this question on StackOverflow).

Sign In or Register to comment.