Переглянути джерело

added support for glBindImageTexture

codex 9 місяців тому
батько
коміт
961a72abc2

+ 16 - 4
jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java

@@ -80,6 +80,7 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import org.lwjgl.opengl.GL43;
 
 
 public final class GLRenderer implements Renderer {
@@ -1985,7 +1986,7 @@ public final class GLRenderer implements Renderer {
             // NOTE: For depth textures, sets nearest/no-mips mode
             // Required to fix "framebuffer unsupported"
             // for old NVIDIA drivers!
-            setupTextureParams(0, tex);
+            setupTextureParams(0, tex, true);
         }
 
         if (rb.getLayer() < 0){
@@ -2392,7 +2393,7 @@ public final class GLRenderer implements Renderer {
     }
 
     @SuppressWarnings("fallthrough")
-    private void setupTextureParams(int unit, Texture tex) {
+    private void setupTextureParams(int unit, Texture tex, boolean accessBindUpdate) {
         Image image = tex.getImage();
         int samples = image != null ? image.getMultiSamples() : 1;
         int target = convertTextureType(tex.getType(), samples, -1);
@@ -2477,6 +2478,16 @@ public final class GLRenderer implements Renderer {
 
         // If at this point we didn't bind the texture, bind it now
         bindTextureOnly(target, image, unit);
+        
+        // binds the image so that imageStore and imageLoad operations
+        // can be used in shaders on the image
+        if ((accessBindUpdate || image.isAccessUpdateNeeded()) && image.getAccess() != null) {
+            GL43.glBindImageTexture(unit, image.getId(), 0, image.isLayered(),
+                    Math.max(image.getBindLayer(), 0), image.getAccess().getGlEnum(),
+                    texUtil.getImageFormat(image.getFormat(), false).internalFormat);
+            image.setAccessUpdateNeeded(false);
+        }
+        
     }
 
     /**
@@ -2723,7 +2734,8 @@ public final class GLRenderer implements Renderer {
         }
         
         Image image = tex.getImage();
-        if (image.isUpdateNeeded() || (image.isGeneratedMipmapsRequired() && !image.isMipmapsGenerated())) {
+        boolean updateNeeded = image.isUpdateNeeded();
+        if (updateNeeded || (image.isGeneratedMipmapsRequired() && !image.isMipmapsGenerated())) {
             // Check NPOT requirements
             boolean scaleToPot = false;
 
@@ -2747,7 +2759,7 @@ public final class GLRenderer implements Renderer {
         int texId = image.getId();
         assert texId != -1;
 
-        setupTextureParams(unit, tex);
+        setupTextureParams(unit, tex, updateNeeded);
         if (debug && caps.contains(Caps.GLDebug)) {
             if (tex.getName() != null) glext.glObjectLabel(GL.GL_TEXTURE, tex.getImage().getId(), tex.getName());
         }

+ 148 - 1
jme3-core/src/main/java/com/jme3/texture/Image.java

@@ -37,6 +37,7 @@ import com.jme3.export.JmeImporter;
 import com.jme3.export.OutputCapsule;
 import com.jme3.export.Savable;
 import com.jme3.math.FastMath;
+import com.jme3.opencl.MemoryAccess;
 import com.jme3.renderer.Caps;
 import com.jme3.renderer.Renderer;
 import com.jme3.texture.image.ColorSpace;
@@ -48,6 +49,7 @@ import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import org.lwjgl.opengl.GL20;
 
 /**
  * <code>Image</code> defines a data format for a graphical image. The image
@@ -597,6 +599,61 @@ public class Image extends NativeObject implements Savable /*, Cloneable*/ {
 
 
 
+    }
+    
+    public enum Access {
+        
+        /**
+         * The image can only read from in a shader.
+         */
+        ReadOnly(true, false, GL20.GL_READ_ONLY),
+        
+        /**
+         * The image can written to in a shader.
+         */
+        WriteOnly(false, true, GL20.GL_WRITE_ONLY),
+        
+        /**
+         * The image can both be written to and read from in a shader.
+         */
+        ReadWrite(true, true, GL20.GL_READ_WRITE);
+        
+        private final boolean read, write;
+        private final int glEnum;
+
+        private Access(boolean read, boolean write, int glEnum) {
+            this.read = read;
+            this.write = write;
+            this.glEnum = glEnum;
+        }
+        
+        /**
+         * If true, the image can be read from in a shader.
+         * 
+         * @return 
+         */
+        public boolean isRead() {
+            return read;
+        }
+
+        /**
+         * If true, the image can be written to in a shader.
+         * 
+         * @return 
+         */
+        public boolean isWrite() {
+            return write;
+        }
+        
+        /**
+         * Corresponding OpenGL enum.
+         * 
+         * @return 
+         */
+        public int getGlEnum() {
+            return glEnum;
+        }
+        
     }
 
     // image attributes
@@ -606,11 +663,14 @@ public class Image extends NativeObject implements Savable /*, Cloneable*/ {
     protected ArrayList<ByteBuffer> data;
     protected int multiSamples = 1;
     protected ColorSpace colorSpace = null;
+    protected Access access = null;
+    protected int bindLayer = -1;
 //    protected int mipOffset = 0;
     
     // attributes relating to GL object
     protected boolean mipsWereGenerated = false;
     protected boolean needGeneratedMips = false;
+    protected boolean accessUpdateNeeded = true;
     protected LastTextureState lastTextureState = new LastTextureState();
 
     /**
@@ -1210,6 +1270,90 @@ public class Image extends NativeObject implements Savable /*, Cloneable*/ {
         return colorSpace;
     }
 
+    /**
+     * Sets the access modifier for this image.
+     * <p>
+     * If not null, the image will be bound in such a way as to allow
+     * {@code imageStore} and {@code imageLoad} functions to work. Otherwise
+     * the image will be bound normally.
+     * <p>
+     * default=null
+     * 
+     * @param access 
+     */
+    public void setAccess(Access access) {
+        if (this.access != access) {
+            this.access = access;
+            accessUpdateNeeded = true;
+        }
+    }
+    
+    /**
+     * 
+     * @return 
+     * @see #setAccess(com.jme3.texture.Image.Access)
+     */
+    public Access getAccess() {
+        return access;
+    }
+
+    /**
+     * Sets the bind layer used if {@link #getAccess()} does not
+     * return null.
+     * <p>
+     * If greater than or equal to zero, only the specified layer will be
+     * bound. If less than zero, the entire image will be bound.
+     * <p>
+     * default=-1
+     * 
+     * @param bindLayer 
+     */
+    public void setBindLayer(int bindLayer) {
+        if (this.bindLayer != bindLayer) {
+            this.bindLayer = bindLayer;
+            accessUpdateNeeded = true;
+        }
+    }
+    
+    /**
+     * Sets or clears the update flag indicating that this image must
+     * be rebound in cases where {@link #getAccess()} is not null.
+     * 
+     * @param accessUpdateNeeded 
+     */
+    public void setAccessUpdateNeeded(boolean accessUpdateNeeded) {
+        this.accessUpdateNeeded = accessUpdateNeeded;
+    }
+    
+    /**
+     * Indicates that this image must be rebound in cases
+     * where {@link #getAccess()} is not null.
+     * 
+     * @return 
+     */
+    public boolean isAccessUpdateNeeded() {
+        return accessUpdateNeeded;
+    }
+    
+    /**
+     * 
+     * @return 
+     * @see #setBindLayer(int) 
+     */
+    public int getBindLayer() {
+        return bindLayer;
+    }
+    
+    /**
+     * Returns true if the entire image will be bound in cases where
+     * {@link #getAccess()} does not return null.
+     * 
+     * @return 
+     */
+    public boolean isLayered() {
+        return bindLayer < 0;
+    }
+
     @Override
     public String toString(){
         StringBuilder sb = new StringBuilder();
@@ -1286,6 +1430,8 @@ public class Image extends NativeObject implements Savable /*, Cloneable*/ {
         capsule.write(multiSamples, "multiSamples", 1);
         capsule.writeByteBufferArrayList(data, "data", null);
         capsule.write(colorSpace, "colorSpace", null);
+        capsule.write(access, "access", null);
+        capsule.write(bindLayer, "bindLayer", -1);
     }
 
     @Override
@@ -1299,7 +1445,8 @@ public class Image extends NativeObject implements Savable /*, Cloneable*/ {
         multiSamples = capsule.readInt("multiSamples", 1);
         data = capsule.readByteBufferArrayList("data", null);
         colorSpace = capsule.readEnum("colorSpace", ColorSpace.class, null);
-
+        access = capsule.readEnum("access", Access.class, null);
+        bindLayer = capsule.readInt("bindLayer", -1);
         if (mipMapSizes != null) {
             needGeneratedMips = false;
             mipsWereGenerated = true;