added limits, caps, working with buffer objects in renderer.
This commit is contained in:
parent
4d42e4b624
commit
b342b1ede1
@ -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> 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 <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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -395,6 +395,10 @@ public enum Caps {
|
||||
* GPU can provide and accept binary shaders.
|
||||
*/
|
||||
BinaryShader,
|
||||
/**
|
||||
* Supporting working with UniformBufferObject.
|
||||
*/
|
||||
UniformBufferObject,
|
||||
/**
|
||||
* Supporting working with ShaderStorageBufferObjects.
|
||||
*/
|
||||
|
@ -62,4 +62,20 @@ public enum Limits {
|
||||
ColorTextureSamples,
|
||||
DepthTextureSamples,
|
||||
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.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;
|
||||
@ -276,19 +277,19 @@ public interface Renderer {
|
||||
*/
|
||||
public void updateBufferData(ShaderStorageBufferObject ssbo);
|
||||
|
||||
/**
|
||||
* Uploads data of the buffer object on the GPU.
|
||||
*
|
||||
* @param bo the buffer object to upload.
|
||||
*/
|
||||
public void updateBufferData(BufferObject bo);
|
||||
|
||||
/**
|
||||
* Deletes a vertex buffer from the GPU.
|
||||
* @param vb The vertex buffer to delete
|
||||
*/
|
||||
public void deleteBuffer(VertexBuffer vb);
|
||||
|
||||
/**
|
||||
* Deletes a shader storage buffer object from the GPU.
|
||||
*
|
||||
* @param ssbo the shader storage buffer object to delete.
|
||||
*/
|
||||
public void deleteBuffer(ShaderStorageBufferObject ssbo);
|
||||
|
||||
/**
|
||||
* 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_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.
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
* <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")) {
|
||||
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 (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.");
|
||||
}
|
||||
|
||||
final ByteBuffer data = ssbo.getData();
|
||||
if (data == null) {
|
||||
throw new IllegalArgumentException("Can't upload SSBO without data.");
|
||||
} else {
|
||||
throw new IllegalArgumentException("Not expected type of the BO " + bo);
|
||||
}
|
||||
|
||||
int bufferId = ssbo.getId();
|
||||
final ByteBuffer data = bo.computeData(maxSize);
|
||||
if (data == null) {
|
||||
throw new IllegalArgumentException("Can't upload BO without data.");
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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() {
|
||||
|
@ -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<String, BufferObjectField> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
public class ShaderStorageBufferObject extends BufferObject {
|
||||
|
||||
/**
|
||||
* The buffer's data.
|
||||
*/
|
||||
private ByteBuffer data;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <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"),
|
||||
TextureCubeMap(false,true,"samplerCube"),
|
||||
Int("int"),
|
||||
UniformBufferObject(false, false, "dynamic"),
|
||||
ShaderStorageBufferObject(false, false, "dynamic");
|
||||
|
||||
private boolean usesMultiData = false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user