NASAWorldWind / WorldWindJava

The NASA WorldWind Java SDK (WWJ) is for building cross-platform 3D geospatial desktop applications in Java.
718 stars 327 forks source link

WorldWindowGLJPanel with Redhat 8/Ubuntu 20.04 shows corrupted blocky image #226

Open adamish opened 3 years ago

adamish commented 3 years ago

Description

A small WorldWindowGLJPanel example shows large blue pixels on Redhat 8/Ubuntu 20.04, exact same code on Redhat 6 works correctly. Also equivalent WorldWindowGLCanvas works correctly.

image

Problem appears related to GLSL flipping. If "jogl.gljpanel.noglsl" property is set to true then WorldWind works correctly, however in a large application this was unusable as some layers were positioned incorrectly and went in opposite direction to panning (i.e. vertically flipped)

Also a simple Hello World for JOGL with GLJPanel (copied from https://www.javatpoint.com/jogl-hello-world) works correctly indicating problem may be closer to WorldWind than JOGL

Steps to Reproduce

  1. Run test program attached

Expected behavior: Normal display

Actual behavior: Large blue pixels

Reproduces how often: 100%

Operating System and Version

Additional Information


import javax.swing.JFrame;

import com.jogamp.opengl.util.texture.TextureIO;

import gov.nasa.worldwind.BasicModel;
import gov.nasa.worldwind.awt.WorldWindowGLJPanel;
import gov.nasa.worldwind.globes.EarthFlat;
import gov.nasa.worldwind.layers.LayerList;

public class WorldWindGLJPanelTest {

    public static void main(String[] args) {
        System.setProperty("jogl.debug.GLJPanel", "true");
//        System.setProperty("jogl.gljpanel.noglsl", "true");
        final WorldWindowGLJPanel canvas = new WorldWindowGLJPanel();
        final EarthFlat earth = new EarthFlat();
        final BasicModel model = new BasicModel(earth, new LayerList());
        canvas.setModel(model);
        canvas.setSize(640, 480);

        final JFrame frame = new JFrame("Hello World");
        frame.add(canvas);
        frame.setSize(640, 400);
        frame.setUndecorated(true);
        frame.setLayout(null);
        frame.setVisible(true);
        TextureIO.setTexRectEnabled(true);

    }
}

Logs

GLJPanel: DEBUG_VIEWPORT false
GLJPanel: USE_GLSL_TEXTURE_RASTERIZER true
GLJPanel: SKIP_VERTICAL_FLIP_DEFAULT false
GLJPanel: java2dOGLEnabledByProp false
GLJPanel: useJava2DGLPipeline false
GLJPanel: java2DGLPipelineOK false
WARNING: An illegal reflective access operation has occurred
WARNING: Please consider reporting this to the maintainers of com.jogamp.common.os.NativeLibrary$3
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
main: GLJPanel.reshape.0 null resize [ this 640x480, panel 0x0, reshape: 0x0] -> 640x480
main: GLJPanel.addNotify()
AWT-EventQueue-0: GLJPanel.createAndInitializeBackend: 0x0 -> 640x480
AWT-EventQueue-0: OffscreenBackend: initialize() - frameCount 0
AWT-EventQueue-0: OffscreenBackend.initialize: useGLSLFlip true [flip true, isFBO true, isGL2ES2 true, noglsl false, glslNonCompliant false, isGL2ES2 true]
adamish commented 3 years ago

image

Jebonicus commented 3 years ago

The JOGL API docs it specifically says its inbuilt flipping should not be used at all, and that users should turn it off and perform the flipping themselves in the client code. Other people have reported this as being a bug too, e.g. here

This GLSL-based flipping requires that the OpenGL Fixed Function Pipeline be in a known and 'normal' state (e.g. all the various settings like glFrontFace, glTexture, etc are set to default values). WorldWind must be setting them to something strange and incompatible at the point where the flipping is invoked (at the end of the final display() callback).

The way to turn off this GLSL flipping, but retain overall GLSL capability, is to call this API function on the WorldWindowGLJPanel after construction:

canvas.setSkipGLOrientationVerticalFlip(true);

The JOGL API docs recommened that client code should instead perform this vertical flipping themselves, e.g. a scaling via the Projection matrix.

So possible solutions are:

  1. Disable GLJPanel’s flipping and do it ourselves (e.g. in BasicOrbitView)
  2. Retain GLJPanel flipping by ensuring the GL state is set to correct/default values at the end of the display loop. For example, push and pop the attribute stack at the beginning/end of the display callback (the brute-force approach), or figure out precisely which state attribute is breaking the GLSL flipping shader and only set that.

Note that I cannot find any definitive reason this problem is specifically limited to RedHat8/Ubuntu - yet I am sure there must be some reason, or this problem would have been spotted by any testing on WorldWindowGLJPanel.

adamish commented 2 years ago

Another workaround is to add a GLEventListener which effectively does nothing. It is unclear why this works. Speculation is that this somehow flushes the pipeline.

Credit to @Jebonicus for this.

worldwindCanvas.addGLEventListener(0, new VSyncBugWorkaroundGLEventListener());

public class VSyncBugWorkaroundGLEventListener implements GLEventListener {
...
    @Override
    public void display(GLAutoDrawable drawable) {
        drawable.getGL().glDrawArrays(GL.GL_LINES, 0, 1);
    }
...
}