added limits, caps, working with buffer objects in renderer.

JavaSaBr-added_new_var_type
JavaSaBr 7 years ago committed by Nehon
parent 4d42e4b624
commit b342b1ede1
  1. 27
      jme3-core/src/main/java/com/jme3/material/Material.java
  2. 4
      jme3-core/src/main/java/com/jme3/renderer/Caps.java
  3. 16
      jme3-core/src/main/java/com/jme3/renderer/Limits.java
  4. 15
      jme3-core/src/main/java/com/jme3/renderer/Renderer.java
  5. 15
      jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java
  6. 14
      jme3-core/src/main/java/com/jme3/renderer/opengl/GL4.java
  7. 68
      jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java
  8. 18
      jme3-core/src/main/java/com/jme3/shader/BufferObject.java
  9. 133
      jme3-core/src/main/java/com/jme3/shader/ShaderStorageBufferObject.java
  10. 17
      jme3-core/src/main/java/com/jme3/shader/UniformBufferObject.java
  11. 1
      jme3-core/src/main/java/com/jme3/shader/VarType.java

@ -409,6 +409,17 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
return paramValues.get(name); 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> 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 the texture parameter set on this material with the given name,
* returns <code>null</code> if the parameter is not set. * returns <code>null</code> if the parameter is not set.
@ -657,6 +668,22 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
setParam(name, VarType.Vector4, value); 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. * Pass a Vector2f to the material shader.
* *

@ -395,6 +395,10 @@ public enum Caps {
* GPU can provide and accept binary shaders. * GPU can provide and accept binary shaders.
*/ */
BinaryShader, BinaryShader,
/**
* Supporting working with UniformBufferObject.
*/
UniformBufferObject,
/** /**
* Supporting working with ShaderStorageBufferObjects. * Supporting working with ShaderStorageBufferObjects.
*/ */

@ -62,4 +62,20 @@ public enum Limits {
ColorTextureSamples, ColorTextureSamples,
DepthTextureSamples, DepthTextureSamples,
TextureAnisotropy, TextureAnisotropy,
// UBO
UniformBufferObjectMaxVertexBlocks,
UniformBufferObjectMaxFragmentBlocks,
UniformBufferObjectMaxGeometryBlocks,
UniformBufferObjectMaxBlockSize,
// SSBO
ShaderStorageBufferObjectMaxBlockSize,
ShaderStorageBufferObjectMaxVertexBlocks,
ShaderStorageBufferObjectMaxFragmentBlocks,
ShaderStorageBufferObjectMaxGeometryBlocks,
ShaderStorageBufferObjectMaxTessControlBlocks,
ShaderStorageBufferObjectMaxTessEvaluationBlocks,
ShaderStorageBufferObjectMaxComputeBlocks,
ShaderStorageBufferObjectMaxCombineBlocks,
} }

@ -39,6 +39,7 @@ import com.jme3.shader.BufferObject;
import com.jme3.shader.Shader; import com.jme3.shader.Shader;
import com.jme3.shader.Shader.ShaderSource; import com.jme3.shader.Shader.ShaderSource;
import com.jme3.shader.ShaderStorageBufferObject; import com.jme3.shader.ShaderStorageBufferObject;
import com.jme3.shader.UniformBufferObject;
import com.jme3.system.AppSettings; import com.jme3.system.AppSettings;
import com.jme3.texture.FrameBuffer; import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image; import com.jme3.texture.Image;
@ -277,17 +278,17 @@ public interface Renderer {
public void updateBufferData(ShaderStorageBufferObject ssbo); public void updateBufferData(ShaderStorageBufferObject ssbo);
/** /**
* Deletes a vertex buffer from the GPU. * Uploads data of the buffer object on the GPU.
* @param vb The vertex buffer to delete *
* @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. * Deletes a vertex buffer from the GPU.
* * @param vb The vertex buffer to delete
* @param ssbo the shader storage buffer object to delete.
*/ */
public void deleteBuffer(ShaderStorageBufferObject ssbo); public void deleteBuffer(VertexBuffer vb);
/** /**
* Deletes the buffer object from the GPU. * Deletes the buffer object from the GPU.

@ -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_GEOMETRY_SHADER = 0x8A45;
public static final int GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER = 0x8A46; public static final int GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER = 0x8A46;
/**
* Accepted by the &lt;pname&gt; 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, * Accepted by the {@code target} parameters of BindBuffer, BufferData, BufferSubData, MapBuffer, UnmapBuffer, GetBufferSubData, GetBufferPointerv,
* BindBufferRange, BindBufferOffset and BindBufferBase. * BindBufferRange, BindBufferOffset and BindBufferBase.

@ -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_BUFFER = 0x90D2;
public static final int GL_SHADER_STORAGE_BLOCK = 0x92E6; public static final int GL_SHADER_STORAGE_BLOCK = 0x92E6;
/**
* Accepted by the &lt;pname&gt; 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_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;
/** /**
* <p><a target="_blank" href="http://docs.gl/gl4/glPatchParameteri">Reference Page</a></p> * <p><a target="_blank" href="http://docs.gl/gl4/glPatchParameteri">Reference Page</a></p>

@ -480,6 +480,22 @@ public final class GLRenderer implements Renderer {
if (hasExtension("GL_ARB_shader_storage_buffer_object")) { if (hasExtension("GL_ARB_shader_storage_buffer_object")) {
caps.add(Caps.ShaderStorageBufferObject); 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 // Print context information
@ -2550,18 +2566,28 @@ public final class GLRenderer implements Renderer {
} }
@Override @Override
public void updateBufferData(final ShaderStorageBufferObject ssbo) { public void updateBufferData(final BufferObject bo) {
int maxSize = Integer.MAX_VALUE;
if (!caps.contains(Caps.ShaderStorageBufferObject)) { if (bo instanceof UniformBufferObject) {
throw new IllegalArgumentException("The current video hardware doesn't support SSBO."); 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) { 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) { if (bufferId == -1) {
// create buffer // create buffer
@ -2569,19 +2595,24 @@ public final class GLRenderer implements Renderer {
gl.glGenBuffers(intBuf1); gl.glGenBuffers(intBuf1);
bufferId = intBuf1.get(0); 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(); data.rewind();
gl4.glBufferData(GL4.GL_SHADER_STORAGE_BUFFER, data, GL4.GL_DYNAMIC_COPY); if (bo instanceof UniformBufferObject) {
gl4.glBindBuffer(GL4.GL_SHADER_STORAGE_BUFFER, 0); 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) { public void deleteBuffer(VertexBuffer vb) {
@ -2598,9 +2629,9 @@ public final class GLRenderer implements Renderer {
} }
@Override @Override
public void deleteBuffer(final ShaderStorageBufferObject ssbo) { public void deleteBuffer(final BufferObject bo) {
int bufferId = ssbo.getId(); int bufferId = bo.getId();
if (bufferId == -1) { if (bufferId == -1) {
return; return;
} }
@ -2611,12 +2642,7 @@ public final class GLRenderer implements Renderer {
gl.glDeleteBuffers(intBuf1); gl.glDeleteBuffers(intBuf1);
ssbo.resetObject(); bo.resetObject();
}
@Override
public void deleteBuffer(BufferObject bo) {
//TODO
} }
public void clearVertexAttribs() { public void clearVertexAttribs() {

@ -40,7 +40,7 @@ public class BufferObject extends NativeObject {
/** /**
* The previous data buffer. * The previous data buffer.
*/ */
private ByteBuffer previosData; private ByteBuffer previousData;
public BufferObject(final int binding, final Layout layout, final BufferObjectField... fields) { public BufferObject(final int binding, final Layout layout, final BufferObjectField... fields) {
this.handleRef = new Object(); this.handleRef = new Object();
@ -128,14 +128,14 @@ public class BufferObject extends NativeObject {
"maximum available size " + maxSize); "maximum available size " + maxSize);
} }
if (previosData != null) { if (previousData != null) {
if (previosData.capacity() < estimateSize) { if (previousData.capacity() < estimateSize) {
BufferUtils.destroyDirectBuffer(previosData); BufferUtils.destroyDirectBuffer(previousData);
previosData = null; 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<String, BufferObjectField> entry : fields.entrySet()) { for (final Map.Entry<String, BufferObjectField> entry : fields.entrySet()) {
writeField(entry.getValue(), data); writeField(entry.getValue(), data);
@ -481,9 +481,9 @@ public class BufferObject extends NativeObject {
@Override @Override
protected void deleteNativeBuffers() { protected void deleteNativeBuffers() {
super.deleteNativeBuffers(); super.deleteNativeBuffers();
if (previosData != null) { if (previousData != null) {
BufferUtils.destroyDirectBuffer(previosData); BufferUtils.destroyDirectBuffer(previousData);
previosData = null; previousData = null;
} }
} }

@ -1,144 +1,17 @@
package com.jme3.shader; 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. * The implementation of SSBO.
* *
* @author JavaSaBr * @author JavaSaBr
*/ */
public class ShaderStorageBufferObject extends NativeObject { public class ShaderStorageBufferObject extends BufferObject {
/**
* The buffer's data.
*/
private ByteBuffer data;
/** public ShaderStorageBufferObject(final int binding, final Layout layout, final BufferObjectField... fields) {
* The binding number. super(binding, layout, fields);
*/
private int binding;
public ShaderStorageBufferObject() {
this.handleRef = new Object();
this.binding = 1;
} }
public ShaderStorageBufferObject(final int id) { public ShaderStorageBufferObject(final int id) {
super(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.
* <p>
* 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);
}
} }

@ -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);
}
}

@ -58,6 +58,7 @@ public enum VarType {
TextureArray(false,true,"sampler2DArray|sampler2DArrayShadow"), TextureArray(false,true,"sampler2DArray|sampler2DArrayShadow"),
TextureCubeMap(false,true,"samplerCube"), TextureCubeMap(false,true,"samplerCube"),
Int("int"), Int("int"),
UniformBufferObject(false, false, "dynamic"),
ShaderStorageBufferObject(false, false, "dynamic"); ShaderStorageBufferObject(false, false, "dynamic");
private boolean usesMultiData = false; private boolean usesMultiData = false;

Loading…
Cancel
Save