Selaa lähdekoodia

Refactors the context restart code. (#1526)

* Refactors the context restart code.

Now most of the code that goes into initializing the renderer

* Fixed a misleading comment in lwjgl3's LwjglWindow

* Adds documentation to the LwjglContext methods.

* Cleans up the code and comments.

* Moves the renderer initialization for jme3-lwjgl to just the first run.

Apparently, this seems to fix the issue of LWJGL not rendering to the new display. However, trying to apply this fix to jme3-lwjgl3 actually creates the problem there.
Markil3 4 vuotta sitten
vanhempi
commit
f15f3ed84e

+ 129 - 0
jme3-examples/src/main/java/jme3test/renderer/TestContextRestart.java

@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2009-2021 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.renderer;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.control.AbstractControl;
+import com.jme3.scene.shape.Box;
+import com.jme3.system.AppSettings;
+
+/**
+ * Tests whether gamma correction works after a context restart. This test
+ * generates a series of boxes, each one with a slightly different shade from
+ * the other. If the boxes look the same before and after the restart, that
+ * means that gamma correction is working properly.
+ * <p>
+ * Note that for testing, it may be helpful to bypass the test chooser and run
+ * this class directly, since it can be easier to define your own settings
+ * beforehand. Of course, it should still workif all you need to test is the
+ * gamma correction, as long as you enable it in the settings dialog.
+ * </p>
+ *
+ * @author Markil 3
+ */
+public class TestContextRestart extends SimpleApplication
+{
+    public static final String INPUT_RESTART_CONTEXT = "SIMPLEAPP_Restart";
+
+    public static void main(String[] args)
+    {
+        TestContextRestart app = new TestContextRestart();
+        AppSettings settings = new AppSettings(true);
+        settings.setGammaCorrection(true);
+//        settings.setRenderer(AppSettings.LWJGL_OPENGL32);
+        app.setSettings(settings);
+        app.start();
+    }
+
+    @Override
+    public void simpleInitApp()
+    {
+        for (int i = 0, l = 256; i < l; i += 8)
+        {
+            Geometry box = new Geometry("Box" + i, new Box(10, 200, 10));
+            Material mat = new Material(this.assetManager,
+                    "Common/MatDefs/Misc/Unshaded.j3md");
+            mat.setColor("Color", new ColorRGBA((float) i / 255F, 0, 0, 1));
+            box.setMaterial(mat);
+            box.setLocalTranslation(-2.5F * (l / 2 - i), 0, -700);
+            box.addControl(new AbstractControl()
+            {
+                @Override
+                protected void controlUpdate(float tpf)
+                {
+                    float[] angles = this.getSpatial()
+                            .getLocalRotation()
+                            .toAngles(new float[3]);
+                    angles[0] = angles[0] + (FastMath.PI / 500F);
+                    this.getSpatial()
+                            .setLocalRotation(new Quaternion().fromAngles(angles));
+                }
+
+                @Override
+                protected void controlRender(RenderManager rm, ViewPort vp)
+                {
+
+                }
+            });
+            this.rootNode.attachChild(box);
+        }
+
+        this.viewPort.setBackgroundColor(ColorRGBA.Yellow);
+
+        this.flyCam.setEnabled(false);
+        this.inputManager.setCursorVisible(true);
+
+        inputManager.addMapping(INPUT_RESTART_CONTEXT, new KeyTrigger(
+                KeyInput.KEY_TAB));
+        this.inputManager.addListener(new ActionListener()
+        {
+            @Override
+            public void onAction(String name, boolean isPressed, float tpf)
+            {
+                if (name.equals(INPUT_RESTART_CONTEXT))
+                {
+                    restart();
+                }
+            }
+        }, INPUT_RESTART_CONTEXT);
+    }
+}

+ 62 - 38
jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java

@@ -251,42 +251,65 @@ public abstract class LwjglContext implements JmeContext {
         return samples;
     }
 
+    /**
+     * Reinitializes the relevent details of the context. For internal use only.
+     */
+    protected void reinitContext() {
+        initContext(false);
+    }
+
+    /**
+     * Initializes the LWJGL renderer and input for the first time. For internal
+     * use only.
+     */
     protected void initContextFirstTime() {
+        initContext(true);
+    }
+
+    /**
+     * Initializes the LWJGL renderer and input.
+     * @param first - Whether this is the first time we are initializing and we
+     * need to create the renderer or not. Otherwise, we'll just reset the
+     * renderer as needed.
+     */
+    private void initContext(boolean first) {
         if (!GLContext.getCapabilities().OpenGL20) {
             throw new RendererException("OpenGL 2.0 or higher is "
                     + "required for jMonkeyEngine");
         }
-        
+
         int vers[] = getGLVersion(settings.getRenderer());
         if (vers != null) {
-            GL gl = new LwjglGL();
-            GLExt glext = new LwjglGLExt();
-            GLFbo glfbo;
-            
-            if (GLContext.getCapabilities().OpenGL30) {
-                glfbo = new LwjglGLFboGL3();
-            } else {
-                glfbo = new LwjglGLFboEXT();
-            }
-            
-            if (settings.getBoolean("GraphicsDebug")) {
-                gl = (GL) GLDebug.createProxy(gl, gl, GL.class, GL2.class, GL3.class, GL4.class);
-                glext = (GLExt) GLDebug.createProxy(gl, glext, GLExt.class);
-                glfbo = (GLFbo) GLDebug.createProxy(gl, glfbo, GLFbo.class);
-            }
-            if (settings.getBoolean("GraphicsTiming")) {
-                GLTimingState timingState = new GLTimingState();
-                gl = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class);
-                glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class);
-                glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class);
-            }
-            if (settings.getBoolean("GraphicsTrace")) {
-                gl = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class);
-                glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class);
-                glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class);
+            if (first) {
+                GL gl = new LwjglGL();
+                GLExt glext = new LwjglGLExt();
+                GLFbo glfbo;
+
+                if (GLContext.getCapabilities().OpenGL30) {
+                    glfbo = new LwjglGLFboGL3();
+                } else {
+                    glfbo = new LwjglGLFboEXT();
+                }
+
+                if (settings.getBoolean("GraphicsDebug")) {
+                    gl = (GL) GLDebug.createProxy(gl, gl, GL.class, GL2.class, GL3.class, GL4.class);
+                    glext = (GLExt) GLDebug.createProxy(gl, glext, GLExt.class);
+                    glfbo = (GLFbo) GLDebug.createProxy(gl, glfbo, GLFbo.class);
+                }
+                if (settings.getBoolean("GraphicsTiming")) {
+                    GLTimingState timingState = new GLTimingState();
+                    gl = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class);
+                    glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class);
+                    glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class);
+                }
+                if (settings.getBoolean("GraphicsTrace")) {
+                    gl = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class);
+                    glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class);
+                    glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class);
+                }
+                renderer = new GLRenderer(gl, glext, glfbo);
+                renderer.initialize();
             }
-            renderer = new GLRenderer(gl, glext, glfbo);
-            renderer.initialize();
         } else {
             throw new UnsupportedOperationException("Unsupported renderer: " + settings.getRenderer());
         }
@@ -296,19 +319,20 @@ public abstract class LwjglContext implements JmeContext {
         renderer.setMainFrameBufferSrgb(settings.isGammaCorrection());
         renderer.setLinearizeSrgbImages(settings.isGammaCorrection());
 
-        // Init input
-        if (keyInput != null) {
-            keyInput.initialize();
-        }
+        if (first) {
+            // Init input
+            if (keyInput != null) {
+                keyInput.initialize();
+            }
 
-        if (mouseInput != null) {
-            mouseInput.initialize();
-        }
+            if (mouseInput != null) {
+                mouseInput.initialize();
+            }
 
-        if (joyInput != null) {
-            joyInput.initialize();
+            if (joyInput != null) {
+                joyInput.initialize();
+            }
         }
-        
     }
 
     @SuppressWarnings("unchecked")

+ 5 - 0
jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java

@@ -185,6 +185,11 @@ public class LwjglDisplay extends LwjglAbstractDisplay {
                 logger.log(Level.SEVERE, "Failed to set display settings!", ex);
             }
             listener.reshape(settings.getWidth(), settings.getHeight());
+            if (renderable.get()) {
+                reinitContext();
+            } else {
+                assert getType() == Type.Canvas;
+            }
             logger.fine("Display restarted.");
         } else if (Display.wasResized()) {
             int newWidth = Display.getWidth();

+ 76 - 51
jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java

@@ -174,7 +174,28 @@ public abstract class LwjglContext implements JmeContext {
         return samples;
     }
 
+    /**
+     * Reinitializes the relevant details of the context. For internal use only.
+     */
+    protected void reinitContext() {
+        initContext(false);
+    }
+
+    /**
+     * Initializes the LWJGL renderer and input for the first time. For internal
+     * use only.
+     */
     protected void initContextFirstTime() {
+        initContext(true);
+    }
+
+    /**
+     * Initializes the LWJGL renderer and input.
+     * @param first - Whether this is the first time we are initializing and we
+     * need to create the renderer or not. Otherwise, we'll just reset the
+     * renderer as needed.
+     */
+    private void initContext(boolean first) {
 
         final String renderer = settings.getRenderer();
         final GLCapabilities capabilities = createCapabilities(!renderer.equals(AppSettings.LWJGL_OPENGL2));
@@ -185,36 +206,38 @@ public abstract class LwjglContext implements JmeContext {
             throw new UnsupportedOperationException("Unsupported renderer: " + renderer);
         }
 
-        GL gl = new LwjglGL();
-        GLExt glext = new LwjglGLExt();
-        GLFbo glfbo;
+        if (first) {
+            GL gl = new LwjglGL();
+            GLExt glext = new LwjglGLExt();
+            GLFbo glfbo;
 
-        if (capabilities.OpenGL30) {
-            glfbo = new LwjglGLFboGL3();
-        } else {
-            glfbo = new LwjglGLFboEXT();
-        }
+            if (capabilities.OpenGL30) {
+                glfbo = new LwjglGLFboGL3();
+            } else {
+                glfbo = new LwjglGLFboEXT();
+            }
 
-        if (settings.getBoolean("GraphicsDebug")) {
-            gl = (GL) GLDebug.createProxy(gl, gl, GL.class, GL2.class, GL3.class, GL4.class);
-            glext = (GLExt) GLDebug.createProxy(gl, glext, GLExt.class);
-            glfbo = (GLFbo) GLDebug.createProxy(gl, glfbo, GLFbo.class);
-        }
+            if (settings.getBoolean("GraphicsDebug")) {
+                gl = (GL) GLDebug.createProxy(gl, gl, GL.class, GL2.class, GL3.class, GL4.class);
+                glext = (GLExt) GLDebug.createProxy(gl, glext, GLExt.class);
+                glfbo = (GLFbo) GLDebug.createProxy(gl, glfbo, GLFbo.class);
+            }
 
-        if (settings.getBoolean("GraphicsTiming")) {
-            GLTimingState timingState = new GLTimingState();
-            gl = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class);
-            glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class);
-            glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class);
-        }
+            if (settings.getBoolean("GraphicsTiming")) {
+                GLTimingState timingState = new GLTimingState();
+                gl = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class);
+                glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class);
+                glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class);
+            }
 
-        if (settings.getBoolean("GraphicsTrace")) {
-            gl = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class);
-            glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class);
-            glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class);
-        }
+            if (settings.getBoolean("GraphicsTrace")) {
+                gl = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class);
+                glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class);
+                glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class);
+            }
 
-        this.renderer = new GLRenderer(gl, glext, glfbo);
+            this.renderer = new GLRenderer(gl, glext, glfbo);
+        }
         this.renderer.initialize();
 
         if (capabilities.GL_ARB_debug_output && settings.getBoolean("GraphicsDebug")) {
@@ -224,36 +247,38 @@ public abstract class LwjglContext implements JmeContext {
         this.renderer.setMainFrameBufferSrgb(settings.isGammaCorrection());
         this.renderer.setLinearizeSrgbImages(settings.isGammaCorrection());
 
-        // Init input
-        if (keyInput != null) {
-            keyInput.initialize();
-        }
-
-        if (mouseInput != null) {
-            mouseInput.initialize();
-        }
-
-        if (joyInput != null) {
-            joyInput.initialize();
-        }
+        if (first) {
+            // Init input
+            if (keyInput != null) {
+                keyInput.initialize();
+            }
 
-        GLFW.glfwSetJoystickCallback(new GLFWJoystickCallback() {
-            @Override
-            public void invoke(int jid, int event) {
+            if (mouseInput != null) {
+                mouseInput.initialize();
+            }
 
-                // Invoke the disconnected event before we reload the joysticks or we lose the reference to it.
-                // Invoke the connected event after we reload the joysticks to obtain the reference to it.
+            if (joyInput != null) {
+                joyInput.initialize();
+            }
 
-                if ( event == GLFW.GLFW_CONNECTED ) {
-                    joyInput.reloadJoysticks();
-                    joyInput.fireJoystickConnectedEvent(jid);
+            GLFW.glfwSetJoystickCallback(new GLFWJoystickCallback() {
+                @Override
+                public void invoke(int jid, int event) {
+
+                    // Invoke the disconnected event before we reload the joysticks or we lose the reference to it.
+                    // Invoke the connected event after we reload the joysticks to obtain the reference to it.
+
+                    if ( event == GLFW.GLFW_CONNECTED ) {
+                        joyInput.reloadJoysticks();
+                        joyInput.fireJoystickConnectedEvent(jid);
+                    }
+                    else {
+                        joyInput.fireJoystickDisconnectedEvent(jid);
+                        joyInput.reloadJoysticks();
+                    }
                 }
-                else {
-                    joyInput.fireJoystickDisconnectedEvent(jid);
-                    joyInput.reloadJoysticks();
-                }
-            }
-        });
+            });
+        }
 
         renderable.set(true);
     }

+ 2 - 0
jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java

@@ -576,6 +576,8 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
         } catch (Exception ex) {
             LOGGER.log(Level.SEVERE, "Failed to set display settings!", ex);
         }
+        // Reinitialize context flags and such
+        reinitContext();
 
         // We need to reinit the mouse and keyboard input as they are tied to a window handle
         if (keyInput != null && keyInput.isInitialized()) {