diff --git a/jme3-core/src/main/java/com/jme3/material/Material.java b/jme3-core/src/main/java/com/jme3/material/Material.java index 0c99dd235..72b09ae86 100644 --- a/jme3-core/src/main/java/com/jme3/material/Material.java +++ b/jme3-core/src/main/java/com/jme3/material/Material.java @@ -409,6 +409,17 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { return paramValues.get(name); } + /** + * Returns the current parameter's value. + * + * @param name the parameter name to look up. + * @return current value or null if the parameter wasn't set. + */ + public T getParamValue(final String name) { + final MatParam param = paramValues.get(name); + return param == null ? null : (T) param.getValue(); + } + /** * Returns the texture parameter set on this material with the given name, * returns null if the parameter is not set. @@ -657,6 +668,22 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { setParam(name, VarType.Vector4, value); } + /** + * Pass a buffer object to the material shader. + * + * @param name the name of the buffer object defined in the material definition (j3md). + * @param value the buffer object. + */ + public void setBufferObject(final String name, final BufferObject value) { + if (value instanceof UniformBufferObject) { + setParam(name, VarType.UniformBufferObject, value); + } else if (value instanceof ShaderStorageBufferObject) { + setParam(name, VarType.ShaderStorageBufferObject, value); + } else { + throw new IllegalArgumentException("Not expected value " + value); + } + } + /** * Pass a Vector2f to the material shader. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/Caps.java b/jme3-core/src/main/java/com/jme3/renderer/Caps.java index d381ffd07..0369517e2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Caps.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Caps.java @@ -395,6 +395,10 @@ public enum Caps { * GPU can provide and accept binary shaders. */ BinaryShader, + /** + * Supporting working with UniformBufferObject. + */ + UniformBufferObject, /** * Supporting working with ShaderStorageBufferObjects. */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/Limits.java b/jme3-core/src/main/java/com/jme3/renderer/Limits.java index a7e737092..cd1bfec35 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Limits.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Limits.java @@ -62,4 +62,20 @@ public enum Limits { ColorTextureSamples, DepthTextureSamples, TextureAnisotropy, + + // UBO + UniformBufferObjectMaxVertexBlocks, + UniformBufferObjectMaxFragmentBlocks, + UniformBufferObjectMaxGeometryBlocks, + UniformBufferObjectMaxBlockSize, + + // SSBO + ShaderStorageBufferObjectMaxBlockSize, + ShaderStorageBufferObjectMaxVertexBlocks, + ShaderStorageBufferObjectMaxFragmentBlocks, + ShaderStorageBufferObjectMaxGeometryBlocks, + ShaderStorageBufferObjectMaxTessControlBlocks, + ShaderStorageBufferObjectMaxTessEvaluationBlocks, + ShaderStorageBufferObjectMaxComputeBlocks, + ShaderStorageBufferObjectMaxCombineBlocks, } diff --git a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java index 33d7b602f..690acd743 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java @@ -39,6 +39,7 @@ import com.jme3.shader.BufferObject; import com.jme3.shader.Shader; import com.jme3.shader.Shader.ShaderSource; import com.jme3.shader.ShaderStorageBufferObject; +import com.jme3.shader.UniformBufferObject; import com.jme3.system.AppSettings; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; @@ -277,17 +278,17 @@ public interface Renderer { public void updateBufferData(ShaderStorageBufferObject ssbo); /** - * Deletes a vertex buffer from the GPU. - * @param vb The vertex buffer to delete + * Uploads data of the buffer object on the GPU. + * + * @param bo the buffer object to upload. */ - public void deleteBuffer(VertexBuffer vb); + public void updateBufferData(BufferObject bo); /** - * Deletes a shader storage buffer object from the GPU. - * - * @param ssbo the shader storage buffer object to delete. + * Deletes a vertex buffer from the GPU. + * @param vb The vertex buffer to delete */ - public void deleteBuffer(ShaderStorageBufferObject ssbo); + public void deleteBuffer(VertexBuffer vb); /** * Deletes the buffer object from the GPU. diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java index 605e13111..661014138 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java @@ -102,6 +102,21 @@ public interface GL3 extends GL2 { public static final int GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER = 0x8A45; public static final int GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER = 0x8A46; + /** + * Accepted by the <pname> parameter of GetBooleanv, GetIntegerv, + * GetFloatv, and GetDoublev: + */ + public static final int GL_MAX_VERTEX_UNIFORM_BLOCKS = 0x8A2B; + public static final int GL_MAX_GEOMETRY_UNIFORM_BLOCKS = 0x8A2C; + public static final int GL_MAX_FRAGMENT_UNIFORM_BLOCKS = 0x8A2D; + public static final int GL_MAX_COMBINED_UNIFORM_BLOCKS = 0x8A2E; + public static final int GL_MAX_UNIFORM_BUFFER_BINDINGS = 0x8A2F; + public static final int GL_MAX_UNIFORM_BLOCK_SIZE = 0x8A30; + public static final int GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS = 0x8A31; + public static final int GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS = 0x8A32; + public static final int GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS = 0x8A33; + public static final int GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = 0x8A34; + /** * Accepted by the {@code target} parameters of BindBuffer, BufferData, BufferSubData, MapBuffer, UnmapBuffer, GetBufferSubData, GetBufferPointerv, * BindBufferRange, BindBufferOffset and BindBufferBase. diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL4.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL4.java index ccf3c3a7b..821959aee 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL4.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL4.java @@ -52,7 +52,21 @@ public interface GL4 extends GL3 { */ public static final int GL_SHADER_STORAGE_BUFFER = 0x90D2; public static final int GL_SHADER_STORAGE_BLOCK = 0x92E6; + + /** + * Accepted by the <pname> parameter of GetIntegerv, GetBooleanv, + * GetInteger64v, GetFloatv, and GetDoublev: + */ + public static final int GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS = 0x90D6; + public static final int GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS = 0x90D7; + public static final int GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS = 0x90D8; + public static final int GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS = 0x90D9; + public static final int GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS = 0x90DA; + public static final int GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS = 0x90DB; + public static final int GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS = 0x90DC; public static final int GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS = 0x90DD; + public static final int GL_MAX_SHADER_STORAGE_BLOCK_SIZE = 0x90DE; + public static final int GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT = 0x90DF; /** *

Reference Page

diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java index 4ff76b3ce..6611a82a5 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java @@ -480,6 +480,22 @@ public final class GLRenderer implements Renderer { if (hasExtension("GL_ARB_shader_storage_buffer_object")) { caps.add(Caps.ShaderStorageBufferObject); + limits.put(Limits.ShaderStorageBufferObjectMaxBlockSize, getInteger(GL4.GL_MAX_SHADER_STORAGE_BLOCK_SIZE)); + limits.put(Limits.ShaderStorageBufferObjectMaxComputeBlocks, getInteger(GL4.GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS)); + limits.put(Limits.ShaderStorageBufferObjectMaxGeometryBlocks, getInteger(GL4.GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS)); + limits.put(Limits.ShaderStorageBufferObjectMaxFragmentBlocks, getInteger(GL4.GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS)); + limits.put(Limits.ShaderStorageBufferObjectMaxVertexBlocks, getInteger(GL4.GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS)); + limits.put(Limits.ShaderStorageBufferObjectMaxTessControlBlocks, getInteger(GL4.GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS)); + limits.put(Limits.ShaderStorageBufferObjectMaxTessEvaluationBlocks, getInteger(GL4.GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS)); + limits.put(Limits.ShaderStorageBufferObjectMaxCombineBlocks, getInteger(GL4.GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS)); + } + + if (hasExtension("GL_ARB_uniform_buffer_object")) { + caps.add(Caps.UniformBufferObject); + limits.put(Limits.UniformBufferObjectMaxBlockSize, getInteger(GL3.GL_MAX_UNIFORM_BLOCK_SIZE)); + limits.put(Limits.UniformBufferObjectMaxGeometryBlocks, getInteger(GL3.GL_MAX_GEOMETRY_UNIFORM_BLOCKS)); + limits.put(Limits.UniformBufferObjectMaxFragmentBlocks, getInteger(GL3.GL_MAX_FRAGMENT_UNIFORM_BLOCKS)); + limits.put(Limits.UniformBufferObjectMaxVertexBlocks, getInteger(GL3.GL_MAX_VERTEX_UNIFORM_BLOCKS)); } // Print context information @@ -2550,18 +2566,28 @@ public final class GLRenderer implements Renderer { } @Override - public void updateBufferData(final ShaderStorageBufferObject ssbo) { + public void updateBufferData(final BufferObject bo) { + + int maxSize = Integer.MAX_VALUE; - if (!caps.contains(Caps.ShaderStorageBufferObject)) { - throw new IllegalArgumentException("The current video hardware doesn't support SSBO."); + if (bo instanceof UniformBufferObject) { + if (!caps.contains(Caps.UniformBufferObject)) { + throw new IllegalArgumentException("The current video hardware doesn't support UBO."); + } + } else if (bo instanceof ShaderStorageBufferObject) { + if (!caps.contains(Caps.ShaderStorageBufferObject)) { + throw new IllegalArgumentException("The current video hardware doesn't support SSBO."); + } + } else { + throw new IllegalArgumentException("Not expected type of the BO " + bo); } - final ByteBuffer data = ssbo.getData(); + final ByteBuffer data = bo.computeData(maxSize); if (data == null) { - throw new IllegalArgumentException("Can't upload SSBO without data."); + throw new IllegalArgumentException("Can't upload BO without data."); } - int bufferId = ssbo.getId(); + int bufferId = bo.getId(); if (bufferId == -1) { // create buffer @@ -2569,19 +2595,24 @@ public final class GLRenderer implements Renderer { gl.glGenBuffers(intBuf1); bufferId = intBuf1.get(0); - ssbo.setId(bufferId); + bo.setId(bufferId); - objManager.registerObject(ssbo); + objManager.registerObject(bo); } - gl4.glBindBuffer(GL4.GL_SHADER_STORAGE_BUFFER, bufferId); - data.rewind(); - gl4.glBufferData(GL4.GL_SHADER_STORAGE_BUFFER, data, GL4.GL_DYNAMIC_COPY); - gl4.glBindBuffer(GL4.GL_SHADER_STORAGE_BUFFER, 0); + if (bo instanceof UniformBufferObject) { + gl3.glBindBuffer(GL3.GL_UNIFORM_BUFFER, bufferId); + gl3.glBufferData(GL4.GL_UNIFORM_BUFFER, data, GL3.GL_DYNAMIC_DRAW); + gl3.glBindBuffer(GL4.GL_UNIFORM_BUFFER, 0); + } else { + gl4.glBindBuffer(GL4.GL_SHADER_STORAGE_BUFFER, bufferId); + gl4.glBufferData(GL4.GL_SHADER_STORAGE_BUFFER, data, GL4.GL_DYNAMIC_COPY); + gl4.glBindBuffer(GL4.GL_SHADER_STORAGE_BUFFER, 0); + } - ssbo.clearUpdateNeeded(); + bo.clearUpdateNeeded(); } public void deleteBuffer(VertexBuffer vb) { @@ -2598,9 +2629,9 @@ public final class GLRenderer implements Renderer { } @Override - public void deleteBuffer(final ShaderStorageBufferObject ssbo) { + public void deleteBuffer(final BufferObject bo) { - int bufferId = ssbo.getId(); + int bufferId = bo.getId(); if (bufferId == -1) { return; } @@ -2611,12 +2642,7 @@ public final class GLRenderer implements Renderer { gl.glDeleteBuffers(intBuf1); - ssbo.resetObject(); - } - - @Override - public void deleteBuffer(BufferObject bo) { - //TODO + bo.resetObject(); } public void clearVertexAttribs() { diff --git a/jme3-core/src/main/java/com/jme3/shader/BufferObject.java b/jme3-core/src/main/java/com/jme3/shader/BufferObject.java index 7c7689b75..a80fd17ef 100644 --- a/jme3-core/src/main/java/com/jme3/shader/BufferObject.java +++ b/jme3-core/src/main/java/com/jme3/shader/BufferObject.java @@ -40,7 +40,7 @@ public class BufferObject extends NativeObject { /** * The previous data buffer. */ - private ByteBuffer previosData; + private ByteBuffer previousData; public BufferObject(final int binding, final Layout layout, final BufferObjectField... fields) { this.handleRef = new Object(); @@ -128,14 +128,14 @@ public class BufferObject extends NativeObject { "maximum available size " + maxSize); } - if (previosData != null) { - if (previosData.capacity() < estimateSize) { - BufferUtils.destroyDirectBuffer(previosData); - previosData = null; + if (previousData != null) { + if (previousData.capacity() < estimateSize) { + BufferUtils.destroyDirectBuffer(previousData); + previousData = null; } } - final ByteBuffer data = previosData == null ? BufferUtils.createByteBuffer((int) (estimateSize * 1.1F)) : previosData; + final ByteBuffer data = previousData == null ? BufferUtils.createByteBuffer((int) (estimateSize * 1.1F)) : previousData; for (final Map.Entry entry : fields.entrySet()) { writeField(entry.getValue(), data); @@ -481,9 +481,9 @@ public class BufferObject extends NativeObject { @Override protected void deleteNativeBuffers() { super.deleteNativeBuffers(); - if (previosData != null) { - BufferUtils.destroyDirectBuffer(previosData); - previosData = null; + if (previousData != null) { + BufferUtils.destroyDirectBuffer(previousData); + previousData = null; } } diff --git a/jme3-core/src/main/java/com/jme3/shader/ShaderStorageBufferObject.java b/jme3-core/src/main/java/com/jme3/shader/ShaderStorageBufferObject.java index fad394406..583c6d131 100644 --- a/jme3-core/src/main/java/com/jme3/shader/ShaderStorageBufferObject.java +++ b/jme3-core/src/main/java/com/jme3/shader/ShaderStorageBufferObject.java @@ -1,144 +1,17 @@ package com.jme3.shader; -import com.jme3.renderer.Renderer; -import com.jme3.util.BufferUtils; -import com.jme3.util.NativeObject; - -import java.nio.ByteBuffer; - /** * The implementation of SSBO. * * @author JavaSaBr */ -public class ShaderStorageBufferObject extends NativeObject { - - /** - * The buffer's data. - */ - private ByteBuffer data; +public class ShaderStorageBufferObject extends BufferObject { - /** - * The binding number. - */ - private int binding; - - public ShaderStorageBufferObject() { - this.handleRef = new Object(); - this.binding = 1; + public ShaderStorageBufferObject(final int binding, final Layout layout, final BufferObjectField... fields) { + super(binding, layout, fields); } public ShaderStorageBufferObject(final int id) { super(id); } - - /** - * Set the binding number. - * - * @param binding the binding number. - */ - public void setBinding(final int binding) { - this.binding = binding; - } - - /** - * Get the binding number. - * - * @return the binding number. - */ - public int getBinding() { - return binding; - } - - /** - * Called to initialize the data in the {@link ShaderStorageBufferObject}. Must only - * be called once. - * - * @param data the native byte buffer. - */ - public void setupData(final ByteBuffer data) { - - if (id != -1) { - throw new UnsupportedOperationException("Data has already been sent. Cannot setupData again."); - } else if (data.isReadOnly()) { - throw new IllegalArgumentException("VertexBuffer data cannot be read-only."); - } - - this.data = data; - - setUpdateNeeded(); - } - - /** - * Called to update the data in the buffer with new data. Can only - * be called after {@link #setupData(java.nio.ByteBuffer) } - * has been called. Note that it is fine to call this method on the - * data already set, e.g. ssbo.updateData(ssbo.getData()), this will just - * set the proper update flag indicating the data should be sent to the GPU - * again. - *

- * It is allowed to specify a buffer with different capacity than the - * originally set buffer. - * - * @param data the native data buffer to set. - */ - public void updateData(final ByteBuffer data) { - - if (data == null) { - throw new IllegalArgumentException("SSBO can't be without data buffer."); - } - - // Check if the data buffer is read-only which is a sign - // of a bug on the part of the caller - if (data.isReadOnly()) { - throw new IllegalArgumentException("SSBO's data cannot be read-only."); - } - - this.data = data; - - setUpdateNeeded(); - } - - /** - * Get the buffer's data. - * - * @return the buffer's data. - */ - public ByteBuffer getData() { - return data; - } - - @Override - public void resetObject() { - this.id = -1; - setUpdateNeeded(); - } - - @Override - public void deleteObject(final Object rendererObject) { - - if (!(rendererObject instanceof Renderer)) { - throw new IllegalArgumentException("This ssbo can't be deleted from " + rendererObject); - } - - ((Renderer) rendererObject).deleteBuffer(this); - } - - @Override - protected void deleteNativeBuffers() { - super.deleteNativeBuffers(); - if (data != null) { - BufferUtils.destroyDirectBuffer(data); - } - } - - @Override - public NativeObject createDestructableClone() { - return new ShaderStorageBufferObject(id); - } - - @Override - public long getUniqueId() { - return ((long) OBJTYPE_SSBO << 32) | ((long) id); - } } diff --git a/jme3-core/src/main/java/com/jme3/shader/UniformBufferObject.java b/jme3-core/src/main/java/com/jme3/shader/UniformBufferObject.java new file mode 100644 index 000000000..5afebe921 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/shader/UniformBufferObject.java @@ -0,0 +1,17 @@ +package com.jme3.shader; + +/** + * The implementation of UBO. + * + * @author JavaSaBr + */ +public class UniformBufferObject extends BufferObject { + + public UniformBufferObject(final int binding, final Layout layout, final BufferObjectField... fields) { + super(binding, layout, fields); + } + + public UniformBufferObject(final int id) { + super(id); + } +} diff --git a/jme3-core/src/main/java/com/jme3/shader/VarType.java b/jme3-core/src/main/java/com/jme3/shader/VarType.java index 25ea22c9a..049c87786 100644 --- a/jme3-core/src/main/java/com/jme3/shader/VarType.java +++ b/jme3-core/src/main/java/com/jme3/shader/VarType.java @@ -58,6 +58,7 @@ public enum VarType { TextureArray(false,true,"sampler2DArray|sampler2DArrayShadow"), TextureCubeMap(false,true,"samplerCube"), Int("int"), + UniformBufferObject(false, false, "dynamic"), ShaderStorageBufferObject(false, false, "dynamic"); private boolean usesMultiData = false;