Search code examples
javaopengl-esawtrenderingjawt

Losing AWT DrawingSurface when Canvas is hidden


I am writing 3d rendering module for an AWT/Swing application.

To provide good FPS, I can't draw using Swing/AWT methods and graphics. Instead, I obtain the Drawing Surface from the Canvas element, and then render directly to it. Something like this:

public class Window {

    private Component canvas;
    private JAWTDrawingSurface ds;

    public static final JAWT awt;
    static {
        awt = JAWT.calloc();
        awt.version(JAWT_VERSION_1_4);
        if (!JAWT_GetAWT(awt))
            throw new AssertionError("GetAWT failed");
    }

    public void lock() throws AWTException {
        int lock = JAWT_DrawingSurface_Lock(ds, ds.Lock());
        if ((lock & JAWT_LOCK_ERROR) != 0)
            throw new AWTException("JAWT_DrawingSurface_Lock() failed");
    }

    public void unlock() throws AWTException {
        JAWT_DrawingSurface_Unlock(ds, ds.Unlock());
    }

    public void Init2()
    {    
        this.ds = JAWT_GetDrawingSurface(canvas, awt.GetDrawingSurface());
        try
        {
            lock();
            // Create GL Capabilities
            unlock();
        }
     }

It works fine when I call it the first time. But when I hide the canvas for any reason (for example minimizing window or displaying another panel instead of Canvas), the ds variable remains the same, but it doesn't work after that. Basically, even if I make sure I call the variable only when it is visible and on top - any call using ds will throw an exception. For example lock() function stops working.

I'm wondering why's that?

Also I tried to basically obtain a new DS if I minimize and then maximize the window again, but this also doesn't work - the new DS address is returned as it should, but I can't use that new object just as I couldn't use the original one.

There's probably something stupid I'm missing here, but I can't figure out what. Please help me sort this out. Thank you!


Solution

  • The solution:

    When the Canvas is hidden, call eglMakeCurrent(eglDisplay,EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT) to unbind the current context.

    When you need to start drawing again, you need to do something like this:

    public void Reinit()
    {
        System.err.println("Context Reinit()");
    
        this.ds = JAWT_GetDrawingSurface(canvas, awt.GetDrawingSurface());
        try
        {
            lock();
            try
            {
                JAWTDrawingSurfaceInfo dsi = JAWT_DrawingSurface_GetDrawingSurfaceInfo(ds, ds.GetDrawingSurfaceInfo());
    
                JAWTX11DrawingSurfaceInfo dsiWin = JAWTX11DrawingSurfaceInfo.create(dsi.platformInfo());
    
                this.display = dsiWin.display();
                this.drawable = dsiWin.drawable();
    
                eglDisplay = eglGetDisplay(display);
    
                surface = eglCreateWindowSurface(eglDisplay,fbConfigs.get(0),drawable,(int[])null);
    
                eglMakeCurrent(eglDisplay,surface,surface,context);
    
                GLES.setCapabilities(glesCaps);
    
                JAWT_DrawingSurface_FreeDrawingSurfaceInfo(dsi, ds.FreeDrawingSurfaceInfo());
            }
            finally
            {
                unlock();
                System.err.printf("Unlock \n");
            }
    
        }
        catch (Exception e)
        {
            System.err.println("JAWT Failed" + e.getMessage());
        }
    }
    

    As You can see, I re-create the display and surface, but I use the previously created context for rendering, without needing to re-create it.