Просмотр исходного кода

Make GLFence, SSBO, ComputeShader NativeObjects

scott 4 дней назад
Родитель
Сommit
e4cda6f915

+ 8 - 1
jme3-core/src/main/java/com/jme3/renderer/Renderer.java

@@ -33,6 +33,7 @@ package com.jme3.renderer;
 
 
 import com.jme3.material.RenderState;
 import com.jme3.material.RenderState;
 import com.jme3.math.ColorRGBA;
 import com.jme3.math.ColorRGBA;
+import com.jme3.renderer.opengl.GLFence;
 import com.jme3.scene.Mesh;
 import com.jme3.scene.Mesh;
 import com.jme3.scene.VertexBuffer;
 import com.jme3.scene.VertexBuffer;
 import com.jme3.shader.bufferobject.BufferObject;
 import com.jme3.shader.bufferobject.BufferObject;
@@ -552,5 +553,11 @@ public interface Renderer {
 
 
     public void setShaderStorageBufferObject(int bindingPoint, BufferObject bufferObject) ;
     public void setShaderStorageBufferObject(int bindingPoint, BufferObject bufferObject) ;
     public void setUniformBufferObject(int bindingPoint, BufferObject bufferObject) ;
     public void setUniformBufferObject(int bindingPoint, BufferObject bufferObject) ;
-    
+
+    public void deleteFence(GLFence fence);
+
+    /**
+     * Registers a NativeObject to be cleaned up by this renderer.
+     */
+    public void registerNativeObject(NativeObject nativeObject);
 }
 }

+ 54 - 19
jme3-core/src/main/java/com/jme3/renderer/opengl/ComputeShader.java

@@ -37,6 +37,7 @@ import com.jme3.math.Vector3f;
 import com.jme3.math.Vector4f;
 import com.jme3.math.Vector4f;
 import com.jme3.renderer.RendererException;
 import com.jme3.renderer.RendererException;
 import com.jme3.util.BufferUtils;
 import com.jme3.util.BufferUtils;
+import com.jme3.util.NativeObject;
 
 
 import java.nio.FloatBuffer;
 import java.nio.FloatBuffer;
 import java.nio.IntBuffer;
 import java.nio.IntBuffer;
@@ -46,16 +47,28 @@ import java.nio.IntBuffer;
  * <p>
  * <p>
  * Compute shaders require OpenGL 4.3 or higher.
  * Compute shaders require OpenGL 4.3 or higher.
  */
  */
-public class ComputeShader {
+public class ComputeShader extends NativeObject {
 
 
     private final GL4 gl;
     private final GL4 gl;
-    private final int programId;
+    private final String source;
     /**
     /**
      * Creates a new compute shader from GLSL source code.
      * Creates a new compute shader from GLSL source code.
      */
      */
     public ComputeShader(GL4 gl, String source) {
     public ComputeShader(GL4 gl, String source) {
+        super();
         this.gl = gl;
         this.gl = gl;
+        this.source = source;
+        //Load this upfront to surface any problems at init time
+        createComputeShader();
+    }
+    private ComputeShader(ComputeShader source){
+        super();
+        this.gl = source.gl;
+        this.id = source.id;
+        this.source = null;
+    }
 
 
+    private void createComputeShader(){
         // Create and compile the shader
         // Create and compile the shader
         int shaderId = gl.glCreateShader(GL4.GL_COMPUTE_SHADER);
         int shaderId = gl.glCreateShader(GL4.GL_COMPUTE_SHADER);
         if (shaderId <= 0) {
         if (shaderId <= 0) {
@@ -78,27 +91,29 @@ public class ComputeShader {
         }
         }
 
 
         // Create program and link
         // Create program and link
-        programId = gl.glCreateProgram();
-        if (programId <= 0) {
+        id = gl.glCreateProgram();
+        if (id <= 0) {
             gl.glDeleteShader(shaderId);
             gl.glDeleteShader(shaderId);
             throw new RendererException("Failed to create shader program");
             throw new RendererException("Failed to create shader program");
         }
         }
 
 
-        gl.glAttachShader(programId, shaderId);
-        gl.glLinkProgram(programId);
+        gl.glAttachShader(id, shaderId);
+        gl.glLinkProgram(id);
 
 
         // Check link status
         // Check link status
-        gl.glGetProgram(programId, GL.GL_LINK_STATUS, intBuf);
+        gl.glGetProgram(id, GL.GL_LINK_STATUS, intBuf);
         if (intBuf.get(0) != GL.GL_TRUE) {
         if (intBuf.get(0) != GL.GL_TRUE) {
-            gl.glGetProgram(programId, GL.GL_INFO_LOG_LENGTH, intBuf);
-            String infoLog = gl.glGetProgramInfoLog(programId, intBuf.get(0));
+            gl.glGetProgram(id, GL.GL_INFO_LOG_LENGTH, intBuf);
+            String infoLog = gl.glGetProgramInfoLog(id, intBuf.get(0));
             gl.glDeleteShader(shaderId);
             gl.glDeleteShader(shaderId);
-            gl.glDeleteProgram(programId);
+            gl.glDeleteProgram(id);
             throw new RendererException("Compute shader program linking failed: " + infoLog);
             throw new RendererException("Compute shader program linking failed: " + infoLog);
         }
         }
 
 
         // Shader object can be deleted after linking
         // Shader object can be deleted after linking
         gl.glDeleteShader(shaderId);
         gl.glDeleteShader(shaderId);
+
+        clearUpdateNeeded();
     }
     }
 
 
     /**
     /**
@@ -106,7 +121,10 @@ public class ComputeShader {
      * Must be called before setting uniforms or dispatching.
      * Must be called before setting uniforms or dispatching.
      */
      */
     public void makeActive() {
     public void makeActive() {
-        gl.glUseProgram(programId);
+        if(isUpdateNeeded()){
+            createComputeShader();
+        }
+        gl.glUseProgram(id);
     }
     }
 
 
     /**
     /**
@@ -144,18 +162,35 @@ public class ComputeShader {
     }
     }
 
 
     public int getUniformLocation(String name) {
     public int getUniformLocation(String name) {
-        return gl.glGetUniformLocation(programId, name);
+        return gl.glGetUniformLocation(id, name);
     }
     }
 
 
     public void bindShaderStorageBuffer(int location, ShaderStorageBufferObject ssbo) {
     public void bindShaderStorageBuffer(int location, ShaderStorageBufferObject ssbo) {
-        gl.glBindBufferBase(GL4.GL_SHADER_STORAGE_BUFFER, location, ssbo.getBufferId());
+        gl.glBindBufferBase(GL4.GL_SHADER_STORAGE_BUFFER, location, ssbo.getId());
     }
     }
 
 
-    /**
-     * Deletes this compute shader and releases GPU resources.
-     * The shader should not be used after calling this method.
-     */
-    public void delete() {
-        gl.glDeleteProgram(programId);
+    @Override
+    public void resetObject() {
+        id = INVALID_ID;
+        setUpdateNeeded();
+    }
+
+    @Override
+    public void deleteObject(Object rendererObject) {
+        if(id != INVALID_ID){
+            gl.glDeleteProgram(id);
+        }
+        resetObject();
+    }
+
+    @Override
+    public NativeObject createDestructableClone() {
+        return new ComputeShader(this);
+    }
+
+    @Override
+    public long getUniqueId() {
+        //Note this is the same type of ID as a regular shader.
+        return ((long)OBJTYPE_SHADER << 32) | (0xffffffffL & (long)id);
     }
     }
 }
 }

+ 49 - 21
jme3-core/src/main/java/com/jme3/renderer/opengl/GLFence.java

@@ -31,6 +31,11 @@
  */
  */
 package com.jme3.renderer.opengl;
 package com.jme3.renderer.opengl;
 
 
+import com.jme3.renderer.Renderer;
+import com.jme3.util.NativeObject;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
 /**
 /**
  * Wrapper for an OpenGL sync object (fence).
  * Wrapper for an OpenGL sync object (fence).
  * <p><a target="_blank" href="https://registry.khronos.org/OpenGL-Refpages/gl4/html/glFenceSync.xhtml">See here.</a></p>
  * <p><a target="_blank" href="https://registry.khronos.org/OpenGL-Refpages/gl4/html/glFenceSync.xhtml">See here.</a></p>
@@ -45,38 +50,36 @@ package com.jme3.renderer.opengl;
  * @see GL4#glClientWaitSync(GLFence, int, long)
  * @see GL4#glClientWaitSync(GLFence, int, long)
  * @see GL4#glDeleteSync(GLFence)
  * @see GL4#glDeleteSync(GLFence)
  */
  */
-public class GLFence {
-
-    private final long handle;
+public class GLFence extends NativeObject {
+    private final static AtomicInteger nextUniqueId = new AtomicInteger(1);
     private Object nativeSync;
     private Object nativeSync;
 
 
+
     /**
     /**
-     * Creates a new fence wrapper with the given handle.
-     *
-     * @param handle the native sync object handle (pointer)
+     * Most NativeObject implementations use the int handle GL returns as the NativeObjectId.
+     * However, fence IDs are actually longs.
+     * (This probably won't cause overflow issues; you're not likely to have 2 billion fences usefully around at once.)
      */
      */
-    public GLFence(long handle) {
-        this.handle = handle;
-    }
+    private final long fenceId;
 
 
     /**
     /**
      * Creates a new fence wrapper with the given handle and native sync object.
      * Creates a new fence wrapper with the given handle and native sync object.
      *
      *
-     * @param handle the native sync object handle (pointer)
-     * @param nativeSync the backend-specific sync object (e.g., LWJGL2's GLSync)
+     * @param fenceId the native sync object handle (pointer)
+     * @param nativeSync the backend-specific sync object (e.g., LWJGL2's GLSync) or null
      */
      */
-    public GLFence(long handle, Object nativeSync) {
-        this.handle = handle;
+    public GLFence(long fenceId, Object nativeSync) {
+        super();
+        this.fenceId = fenceId;
+        this.id = nextUniqueId.getAndIncrement();
         this.nativeSync = nativeSync;
         this.nativeSync = nativeSync;
+        clearUpdateNeeded();
     }
     }
-
-    /**
-     * Returns the native sync object handle.
-     *
-     * @return the sync handle
-     */
-    public long getHandle() {
-        return handle;
+    private GLFence(GLFence source) {
+        super();
+        this.fenceId = source.fenceId;
+        this.nativeSync = source.nativeSync;
+        this.id = source.id;
     }
     }
 
 
     /**
     /**
@@ -90,4 +93,29 @@ public class GLFence {
     public Object getNativeSync() {
     public Object getNativeSync() {
         return nativeSync;
         return nativeSync;
     }
     }
+    public long getFenceId() {
+        return fenceId;
+    }
+
+    @Override
+    public void resetObject() {
+        this.nativeSync = null;
+        this.id = INVALID_ID;
+        setUpdateNeeded();
+    }
+
+    @Override
+    public void deleteObject(Object rendererObject) {
+        ((Renderer)rendererObject).deleteFence(this);
+    }
+
+    @Override
+    public NativeObject createDestructableClone() {
+        return new GLFence(this);
+    }
+
+    @Override
+    public long getUniqueId() {
+        return ((long) OBJTYPE_FENCE << 32) | (0xffffffffL & (long) id);
+    }
 }
 }

+ 13 - 0
jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java

@@ -3603,4 +3603,17 @@ public final class GLRenderer implements Renderer {
     public GL4 getGl4(){
     public GL4 getGl4(){
         return gl4;
         return gl4;
     }
     }
+
+    @Override
+    public void deleteFence(GLFence fence) {
+        if(gl4 != null && fence.getId() != NativeObject.INVALID_ID){
+            gl4.glDeleteSync(fence);
+            fence.resetObject();
+        }
+    }
+
+    @Override
+    public void registerNativeObject(NativeObject nativeObject) {
+        objManager.registerObject(nativeObject);
+    }
 }
 }

+ 51 - 18
jme3-core/src/main/java/com/jme3/renderer/opengl/ShaderStorageBufferObject.java

@@ -31,7 +31,9 @@
  */
  */
 package com.jme3.renderer.opengl;
 package com.jme3.renderer.opengl;
 
 
+import com.jme3.renderer.RendererException;
 import com.jme3.util.BufferUtils;
 import com.jme3.util.BufferUtils;
+import com.jme3.util.NativeObject;
 
 
 import java.nio.IntBuffer;
 import java.nio.IntBuffer;
 
 
@@ -42,10 +44,9 @@ import java.nio.IntBuffer;
  * SSBOs are buffers that can be read from and written to by shaders.
  * SSBOs are buffers that can be read from and written to by shaders.
  * SSBOs require OpenGL 4.3 or higher.
  * SSBOs require OpenGL 4.3 or higher.
  */
  */
-public class ShaderStorageBufferObject {
+public class ShaderStorageBufferObject extends NativeObject {
 
 
     private final GL4 gl;
     private final GL4 gl;
-    private final int bufferId;
 
 
     /**
     /**
      * Creates a new SSBO.
      * Creates a new SSBO.
@@ -53,10 +54,23 @@ public class ShaderStorageBufferObject {
      * @param gl the GL4 interface (required for glBindBufferBase)
      * @param gl the GL4 interface (required for glBindBufferBase)
      */
      */
     public ShaderStorageBufferObject(GL4 gl) {
     public ShaderStorageBufferObject(GL4 gl) {
+        super();
         this.gl = gl;
         this.gl = gl;
-        IntBuffer buf = BufferUtils.createIntBuffer(1);
-        gl.glGenBuffers(buf);
-        this.bufferId = buf.get(0);
+        ensureBufferReady();
+    }
+    private ShaderStorageBufferObject(ShaderStorageBufferObject source){
+        super();
+        this.gl = source.gl;
+        this.id = source.id;
+    }
+
+    private void ensureBufferReady(){
+        if(isUpdateNeeded()){
+            IntBuffer buf = BufferUtils.createIntBuffer(1);
+            gl.glGenBuffers(buf);
+            this.id = buf.get(0);
+            clearUpdateNeeded();
+        }
     }
     }
 
 
     /**
     /**
@@ -76,7 +90,8 @@ public class ShaderStorageBufferObject {
      * @param data the initial data to upload
      * @param data the initial data to upload
      */
      */
     public void initialize(IntBuffer data) {
     public void initialize(IntBuffer data) {
-        gl.glBindBuffer(GL4.GL_SHADER_STORAGE_BUFFER, bufferId);
+        ensureBufferReady();
+        gl.glBindBuffer(GL4.GL_SHADER_STORAGE_BUFFER, id);
         gl.glBufferData(GL4.GL_SHADER_STORAGE_BUFFER, data, GL.GL_DYNAMIC_COPY);
         gl.glBufferData(GL4.GL_SHADER_STORAGE_BUFFER, data, GL.GL_DYNAMIC_COPY);
     }
     }
 
 
@@ -109,23 +124,41 @@ public class ShaderStorageBufferObject {
      * @param destination the buffer to read into
      * @param destination the buffer to read into
      */
      */
     public void read(IntBuffer destination) {
     public void read(IntBuffer destination) {
-        gl.glBindBuffer(GL4.GL_SHADER_STORAGE_BUFFER, bufferId);
+        if(isUpdateNeeded()){
+            //If the SSBO was deleted from e.g. context restart, it probably isn't sensible to read from it.
+            //We could create a fresh empty buffer and read from that, but that might result in garbage data.
+            throw new RendererException("SSBO was not ready for read");
+        }
+        gl.glBindBuffer(GL4.GL_SHADER_STORAGE_BUFFER, id);
         gl.glGetBufferSubData(GL4.GL_SHADER_STORAGE_BUFFER, 0, destination);
         gl.glGetBufferSubData(GL4.GL_SHADER_STORAGE_BUFFER, 0, destination);
         gl.glBindBuffer(GL4.GL_SHADER_STORAGE_BUFFER, 0);
         gl.glBindBuffer(GL4.GL_SHADER_STORAGE_BUFFER, 0);
     }
     }
 
 
-    /**
-     * Deletes this buffer and releases GPU resources.
-     * The buffer should not be used after calling this method.
-     */
-    public void delete() {
-        IntBuffer buf = BufferUtils.createIntBuffer(1);
-        buf.put(bufferId);
-        buf.flip();
-        gl.glDeleteBuffers(buf);
+
+    @Override
+    public void resetObject() {
+        this.id = INVALID_ID;
+        setUpdateNeeded();
+    }
+
+    @Override
+    public void deleteObject(Object rendererObject) {
+        if(id != INVALID_ID){
+            IntBuffer buf = BufferUtils.createIntBuffer(1);
+            buf.put(id);
+            buf.flip();
+            gl.glDeleteBuffers(buf);
+        }
+        resetObject();
+    }
+
+    @Override
+    public NativeObject createDestructableClone() {
+        return new ShaderStorageBufferObject(this);
     }
     }
 
 
-    public int getBufferId() {
-        return bufferId;
+    @Override
+    public long getUniqueId() {
+        return ((long) OBJTYPE_BO << 32) | (0xffffffffL & (long) id);
     }
     }
 }
 }

+ 17 - 7
jme3-core/src/main/java/com/jme3/shadow/SdsmFitter.java

@@ -229,20 +229,25 @@ public class SdsmFitter {
 
 
         SdsmResultHolder() {
         SdsmResultHolder() {
             this.minMaxDepthSsbo = new ShaderStorageBufferObject(gl4);
             this.minMaxDepthSsbo = new ShaderStorageBufferObject(gl4);
+            renderer.registerNativeObject(this.minMaxDepthSsbo);
             this.fitFrustumSsbo = new ShaderStorageBufferObject(gl4);
             this.fitFrustumSsbo = new ShaderStorageBufferObject(gl4);
+            renderer.registerNativeObject(this.fitFrustumSsbo);
         }
         }
 
 
         boolean isReady(boolean wait) {
         boolean isReady(boolean wait) {
             if (fence == null) {
             if (fence == null) {
                 return true;
                 return true;
             }
             }
+            if(fence.isUpdateNeeded()){
+                return true;
+            }
             int status = gl4.glClientWaitSync(fence, 0, wait ? -1 : 0);
             int status = gl4.glClientWaitSync(fence, 0, wait ? -1 : 0);
             return status == GL4.GL_ALREADY_SIGNALED || status == GL4.GL_CONDITION_SATISFIED;
             return status == GL4.GL_ALREADY_SIGNALED || status == GL4.GL_CONDITION_SATISFIED;
         }
         }
 
 
         SplitFitResult extract() {
         SplitFitResult extract() {
             if (fence != null) {
             if (fence != null) {
-                gl4.glDeleteSync(fence);
+                renderer.deleteFence(fence);
                 fence = null;
                 fence = null;
             }
             }
             SplitFit fit = extractFit();
             SplitFit fit = extractFit();
@@ -250,6 +255,7 @@ public class SdsmFitter {
         }
         }
 
 
         private SplitFit extractFit() {
         private SplitFit extractFit() {
+            if(fitFrustumSsbo.isUpdateNeeded()){ return null; }
             int[] uintFit = fitFrustumSsbo.read(32);
             int[] uintFit = fitFrustumSsbo.read(32);
             float[] fitResult = new float[32];
             float[] fitResult = new float[32];
             for(int i=0;i<fitResult.length;i++) {
             for(int i=0;i<fitResult.length;i++) {
@@ -296,10 +302,10 @@ public class SdsmFitter {
         }
         }
 
 
         void cleanup() {
         void cleanup() {
-            minMaxDepthSsbo.delete();
-            fitFrustumSsbo.delete();
+            minMaxDepthSsbo.deleteObject(renderer);
+            fitFrustumSsbo.deleteObject(renderer);
             if (fence != null) {
             if (fence != null) {
-                gl4.glDeleteSync(fence);
+                fence.deleteObject(renderer);
             }
             }
         }
         }
     }
     }
@@ -313,7 +319,9 @@ public class SdsmFitter {
         String fitSource = (String)assetManager.loadAsset(FIT_FRUSTUMS_SHADER);
         String fitSource = (String)assetManager.loadAsset(FIT_FRUSTUMS_SHADER);
 
 
         depthReduceShader = new ComputeShader(gl, reduceSource);
         depthReduceShader = new ComputeShader(gl, reduceSource);
+        renderer.registerNativeObject(depthReduceShader);
         fitFrustumsShader = new ComputeShader(gl, fitSource);
         fitFrustumsShader = new ComputeShader(gl, fitSource);
+        renderer.registerNativeObject(fitFrustumsShader);
     }
     }
 
 
     /**
     /**
@@ -377,7 +385,9 @@ public class SdsmFitter {
         gl4.glMemoryBarrier(GL4.GL_SHADER_STORAGE_BARRIER_BIT);
         gl4.glMemoryBarrier(GL4.GL_SHADER_STORAGE_BARRIER_BIT);
 
 
         // Create fence for async readback
         // Create fence for async readback
-        holder.fence = gl4.glFenceSync(GL4.GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+        GLFence fence = gl4.glFenceSync(GL4.GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+        renderer.registerNativeObject(fence);
+        holder.fence = fence;
         resultHoldersInFlight.add(holder);
         resultHoldersInFlight.add(holder);
     }
     }
 
 
@@ -428,10 +438,10 @@ public class SdsmFitter {
         resultHoldersReady.clear();
         resultHoldersReady.clear();
 
 
         if (depthReduceShader != null) {
         if (depthReduceShader != null) {
-            depthReduceShader.delete();
+            depthReduceShader.deleteObject(renderer);
         }
         }
         if (fitFrustumsShader != null) {
         if (fitFrustumsShader != null) {
-            fitFrustumsShader.delete();
+            fitFrustumsShader.deleteObject(renderer);
         }
         }
     }
     }
 
 

+ 12 - 1
jme3-core/src/main/java/com/jme3/system/NullRenderer.java

@@ -40,6 +40,7 @@ import com.jme3.renderer.Limits;
 import com.jme3.renderer.Renderer;
 import com.jme3.renderer.Renderer;
 import com.jme3.renderer.Statistics;
 import com.jme3.renderer.Statistics;
 import com.jme3.renderer.TextureUnitException;
 import com.jme3.renderer.TextureUnitException;
+import com.jme3.renderer.opengl.GLFence;
 import com.jme3.scene.Mesh;
 import com.jme3.scene.Mesh;
 import com.jme3.scene.VertexBuffer;
 import com.jme3.scene.VertexBuffer;
 import com.jme3.shader.Shader;
 import com.jme3.shader.Shader;
@@ -49,6 +50,7 @@ import com.jme3.texture.FrameBuffer;
 import com.jme3.texture.Image;
 import com.jme3.texture.Image;
 import com.jme3.texture.Texture;
 import com.jme3.texture.Texture;
 import com.jme3.texture.TextureImage;
 import com.jme3.texture.TextureImage;
+import com.jme3.util.NativeObject;
 
 
 import java.nio.ByteBuffer;
 import java.nio.ByteBuffer;
 import java.util.EnumMap;
 import java.util.EnumMap;
@@ -320,5 +322,14 @@ public class NullRenderer implements Renderer {
     public void setUniformBufferObject(int bindingPoint, BufferObject bufferObject) {
     public void setUniformBufferObject(int bindingPoint, BufferObject bufferObject) {
 
 
     }
     }
-    
+
+    @Override
+    public void deleteFence(GLFence fence) {
+
+    }
+
+    @Override
+    public void registerNativeObject(NativeObject nativeObject) {
+
+    }
 }
 }

+ 2 - 1
jme3-core/src/main/java/com/jme3/util/NativeObject.java

@@ -54,7 +54,8 @@ public abstract class NativeObject implements Cloneable {
                                OBJTYPE_AUDIOBUFFER  = 6,
                                OBJTYPE_AUDIOBUFFER  = 6,
                                OBJTYPE_AUDIOSTREAM  = 7,
                                OBJTYPE_AUDIOSTREAM  = 7,
                                OBJTYPE_FILTER       = 8,
                                OBJTYPE_FILTER       = 8,
-                               OBJTYPE_BO           = 9;
+                               OBJTYPE_BO           = 9,
+                               OBJTYPE_FENCE = 10;
     
     
     /**
     /**
      * The object manager to which this NativeObject is registered to.
      * The object manager to which this NativeObject is registered to.

+ 5 - 2
jme3-examples/src/main/java/jme3test/light/TestSdsmDirectionalLightShadow.java

@@ -304,6 +304,7 @@ public class TestSdsmDirectionalLightShadow extends SimpleApplication implements
         sb.append("  Numpad 8/5 - Light elevation\n");
         sb.append("  Numpad 8/5 - Light elevation\n");
         sb.append("  Numpad 4/6 - Light rotation\n");
         sb.append("  Numpad 4/6 - Light rotation\n");
         sb.append("  X - Show shadow frustum debug\n");
         sb.append("  X - Show shadow frustum debug\n");
+        sb.append("  C - Restart display\n");
 
 
         statusText.setText(sb.toString());
         statusText.setText(sb.toString());
     }
     }
@@ -317,6 +318,7 @@ public class TestSdsmDirectionalLightShadow extends SimpleApplication implements
         inputManager.addMapping("sizeUp", new KeyTrigger(KeyInput.KEY_EQUALS));
         inputManager.addMapping("sizeUp", new KeyTrigger(KeyInput.KEY_EQUALS));
         inputManager.addMapping("sizeDown", new KeyTrigger(KeyInput.KEY_MINUS));
         inputManager.addMapping("sizeDown", new KeyTrigger(KeyInput.KEY_MINUS));
         inputManager.addMapping("debug", new KeyTrigger(KeyInput.KEY_X));
         inputManager.addMapping("debug", new KeyTrigger(KeyInput.KEY_X));
+        inputManager.addMapping("restartDisplay", new KeyTrigger(KeyInput.KEY_C));
 
 
         inputManager.addMapping("elevUp", new KeyTrigger(KeyInput.KEY_NUMPAD8));
         inputManager.addMapping("elevUp", new KeyTrigger(KeyInput.KEY_NUMPAD8));
         inputManager.addMapping("elevDown", new KeyTrigger(KeyInput.KEY_NUMPAD5));
         inputManager.addMapping("elevDown", new KeyTrigger(KeyInput.KEY_NUMPAD5));
@@ -325,7 +327,7 @@ public class TestSdsmDirectionalLightShadow extends SimpleApplication implements
 
 
         inputManager.addListener(this,
         inputManager.addListener(this,
                 "toggleMode", "splits1", "splits2", "splits3", "splits4",
                 "toggleMode", "splits1", "splits2", "splits3", "splits4",
-                "sizeUp", "sizeDown", "debug",
+                "sizeUp", "sizeDown", "debug", "restartDisplay",
                 "elevUp", "elevDown", "azimLeft", "azimRight");
                 "elevUp", "elevDown", "azimLeft", "azimRight");
     }
     }
 
 
@@ -389,7 +391,8 @@ public class TestSdsmDirectionalLightShadow extends SimpleApplication implements
                     traditionalFilter.displayFrustum();
                     traditionalFilter.displayFrustum();
                 }
                 }
                 break;
                 break;
-
+            case "restartDisplay":
+                (context).restart();
             default:
             default:
                 break;
                 break;
         }
         }

+ 3 - 3
jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java

@@ -101,17 +101,17 @@ public class LwjglGL extends LwjglRender implements GL, GL2, GL3, GL4 {
 
 
     @Override
     @Override
     public GLFence glFenceSync(final int condition, final int flags) {
     public GLFence glFenceSync(final int condition, final int flags) {
-        return new GLFence(GL32.glFenceSync(condition, flags));
+        return new GLFence(GL32.glFenceSync(condition, flags), null);
     }
     }
 
 
     @Override
     @Override
     public int glClientWaitSync(final GLFence sync, final int flags, final long timeout) {
     public int glClientWaitSync(final GLFence sync, final int flags, final long timeout) {
-        return GL32.glClientWaitSync(sync.getHandle(), flags, timeout);
+        return GL32.glClientWaitSync(sync.getFenceId(), flags, timeout);
     }
     }
 
 
     @Override
     @Override
     public void glDeleteSync(final GLFence sync) {
     public void glDeleteSync(final GLFence sync) {
-        GL32.glDeleteSync(sync.getHandle());
+        GL32.glDeleteSync(sync.getFenceId());
     }
     }
 
 
     @Override
     @Override