Implements SSBO (Shader Storage Buffer Object) and UBO (Uniform Buffer Object) support

shader-nodes-enhancement
Rémy Bouquet 7 years ago committed by Nehon
parent 302e746a94
commit 266d8b0828
  1. 75
      jme3-core/src/main/java/com/jme3/material/Material.java
  2. 10
      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. 479
      jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java
  6. 83
      jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java
  7. 50
      jme3-core/src/main/java/com/jme3/renderer/opengl/GL4.java
  8. 32
      jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java
  9. 197
      jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java
  10. 828
      jme3-core/src/main/java/com/jme3/shader/BufferObject.java
  11. 77
      jme3-core/src/main/java/com/jme3/shader/BufferObjectField.java
  12. 64
      jme3-core/src/main/java/com/jme3/shader/Shader.java
  13. 93
      jme3-core/src/main/java/com/jme3/shader/ShaderBufferBlock.java
  14. 3
      jme3-core/src/main/java/com/jme3/shader/VarType.java
  15. 15
      jme3-core/src/main/java/com/jme3/system/NullRenderer.java
  16. 3
      jme3-core/src/main/java/com/jme3/util/NativeObject.java
  17. 33
      jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java
  18. 35
      jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java
  19. 25
      jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java

@ -46,10 +46,7 @@ import com.jme3.renderer.RenderManager;
import com.jme3.renderer.Renderer; import com.jme3.renderer.Renderer;
import com.jme3.renderer.queue.RenderQueue.Bucket; import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.shader.Shader; import com.jme3.shader.*;
import com.jme3.shader.Uniform;
import com.jme3.shader.UniformBindingManager;
import com.jme3.shader.VarType;
import com.jme3.texture.Image; import com.jme3.texture.Image;
import com.jme3.texture.Texture; import com.jme3.texture.Texture;
import com.jme3.texture.image.ColorSpace; import com.jme3.texture.image.ColorSpace;
@ -412,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.
@ -660,6 +668,28 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
setParam(name, VarType.Vector4, value); setParam(name, VarType.Vector4, value);
} }
/**
* Pass an uniform 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 setUniformBufferObject(final String name, final BufferObject value) {
value.setBufferType(BufferObject.BufferType.UniformBufferObject);
setParam(name, VarType.BufferObject, value);
}
/**
* Pass a shader storage 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 setShaderStorageBufferObject(final String name, final BufferObject value) {
value.setBufferType(BufferObject.BufferType.ShaderStorageBufferObject);
setParam(name, VarType.BufferObject, value);
}
/** /**
* Pass a Vector2f to the material shader. * Pass a Vector2f to the material shader.
* *
@ -794,20 +824,29 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
} }
for (int i = 0; i < paramValues.size(); i++) { for (int i = 0; i < paramValues.size(); i++) {
MatParam param = paramValues.getValue(i); MatParam param = paramValues.getValue(i);
VarType type = param.getVarType(); VarType type = param.getVarType();
Uniform uniform = shader.getUniform(param.getPrefixedName());
if (uniform.isSetByCurrentMaterial()) { if (isBO(type)) {
continue;
} final ShaderBufferBlock bufferBlock = shader.getBufferBlock(param.getPrefixedName());
bufferBlock.setBufferObject((BufferObject) param.getValue());
if (type.isTextureType()) {
renderer.setTexture(unit, (Texture) param.getValue());
uniform.setValue(VarType.Int, unit);
unit++;
} else { } else {
uniform.setValue(type, param.getValue());
Uniform uniform = shader.getUniform(param.getPrefixedName());
if (uniform.isSetByCurrentMaterial()) {
continue;
}
if (type.isTextureType()) {
renderer.setTexture(unit, (Texture) param.getValue());
uniform.setValue(VarType.Int, unit);
unit++;
} else {
uniform.setValue(type, param.getValue());
}
} }
} }
@ -815,6 +854,16 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
return unit; return unit;
} }
/**
* Returns true if the type is Buffer Object's type.
*
* @param type the material parameter type.
* @return true if the type is Buffer Object's type.
*/
private boolean isBO(final VarType type) {
return type == VarType.BufferObject;
}
private void updateRenderState(RenderManager renderManager, Renderer renderer, TechniqueDef techniqueDef) { private void updateRenderState(RenderManager renderManager, Renderer renderer, TechniqueDef techniqueDef) {
if (renderManager.getForcedRenderState() != null) { if (renderManager.getForcedRenderState() != null) {
renderer.applyRenderState(renderManager.getForcedRenderState()); renderer.applyRenderState(renderManager.getForcedRenderState());

@ -394,7 +394,15 @@ 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.
*/
ShaderStorageBufferObject;
/** /**
* Returns true if given the renderer capabilities, the texture * Returns true if given the renderer capabilities, the texture

@ -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,
} }

@ -35,6 +35,7 @@ import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
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;
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.system.AppSettings; import com.jme3.system.AppSettings;
@ -267,12 +268,26 @@ public interface Renderer {
*/ */
public void updateBufferData(VertexBuffer vb); public void updateBufferData(VertexBuffer vb);
/**
* 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. * Deletes a vertex buffer from the GPU.
* @param vb The vertex buffer to delete * @param vb The vertex buffer to delete
*/ */
public void deleteBuffer(VertexBuffer vb); public void deleteBuffer(VertexBuffer vb);
/**
* Deletes the buffer object from the GPU.
*
* @param bo the buffer object to delete.
*/
public void deleteBuffer(BufferObject bo);
/** /**
* Renders <code>count</code> meshes, with the geometry data supplied and * Renders <code>count</code> meshes, with the geometry data supplied and
* per-instance data supplied. * per-instance data supplied.

File diff suppressed because it is too large Load Diff

@ -83,6 +83,46 @@ public interface GL3 extends GL2 {
public static final int GL_RGB_INTEGER = 36248; public static final int GL_RGB_INTEGER = 36248;
public static final int GL_RGBA_INTEGER = 36249; public static final int GL_RGBA_INTEGER = 36249;
public static final int GL_UNIFORM_OFFSET = 0x8A3B;
/**
* Accepted by the {@code target} parameters of BindBuffer, BufferData, BufferSubData, MapBuffer, UnmapBuffer, GetBufferSubData, and GetBufferPointerv.
*/
public static final int GL_UNIFORM_BUFFER = 0x8A11;
/**
* Accepted by the {@code pname} parameter of GetActiveUniformBlockiv.
*/
public static final int GL_UNIFORM_BLOCK_BINDING = 0x8A3F;
public static final int GL_UNIFORM_BLOCK_DATA_SIZE = 0x8A40;
public static final int GL_UNIFORM_BLOCK_NAME_LENGTH = 0x8A41;
public static final int GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS = 0x8A42;
public static final int GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES = 0x8A43;
public static final int GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER = 0x8A44;
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 &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,
* BindBufferRange, BindBufferOffset and BindBufferBase.
*/
public static final int GL_TRANSFORM_FEEDBACK_BUFFER = 0x8C8E;
/** /**
* <p><a target="_blank" href="http://docs.gl/gl4/glBindFragDataLocation">Reference Page</a></p> * <p><a target="_blank" href="http://docs.gl/gl4/glBindFragDataLocation">Reference Page</a></p>
* <p> * <p>
@ -128,4 +168,47 @@ public interface GL3 extends GL2 {
* @param index the index of the particular element being queried. * @param index the index of the particular element being queried.
*/ */
public String glGetString(int name, int index); /// GL3+ public String glGetString(int name, int index); /// GL3+
/**
* <p><a target="_blank" href="http://docs.gl/gl4/glGetUniformBlockIndex">Reference Page</a></p>
*
* Retrieves the index of a named uniform block.
*
* @param program the name of a program containing the uniform block.
* @param uniformBlockName an array of characters to containing the name of the uniform block whose index to retrieve.
* @return the block index.
*/
public int glGetUniformBlockIndex(int program, String uniformBlockName);
/**
* <p><a target="_blank" href="http://docs.gl/gl4/glBindBufferBase">Reference Page</a></p>
*
* Binds a buffer object to an indexed buffer target.
*
* @param target the target of the bind operation. One of:<br><table><tr><td>{@link #GL_TRANSFORM_FEEDBACK_BUFFER TRANSFORM_FEEDBACK_BUFFER}</td><td>{@link #GL_UNIFORM_BUFFER UNIFORM_BUFFER}</td><td>{@link GL4#GL_ATOMIC_COUNTER_BUFFER ATOMIC_COUNTER_BUFFER}</td><td>{@link GL4#GL_SHADER_STORAGE_BUFFER SHADER_STORAGE_BUFFER}</td></tr></table>
* @param index the index of the binding point within the array specified by {@code target}
* @param buffer a buffer object to bind to the specified binding point
*/
public void glBindBufferBase(int target, int index, int buffer);
/**
* Binding points for active uniform blocks are assigned using glUniformBlockBinding. Each of a program's active
* uniform blocks has a corresponding uniform buffer binding point. program is the name of a program object for
* which the command glLinkProgram has been issued in the past.
* <p>
* If successful, glUniformBlockBinding specifies that program will use the data store of the buffer object bound
* to the binding point uniformBlockBinding to extract the values of the uniforms in the uniform block identified
* by uniformBlockIndex.
* <p>
* When a program object is linked or re-linked, the uniform buffer object binding point assigned to each of its
* active uniform blocks is reset to zero.
*
* @param program The name of a program object containing the active uniform block whose binding to
* assign.
* @param uniformBlockIndex The index of the active uniform block within program whose binding to assign.
* @param uniformBlockBinding Specifies the binding point to which to bind the uniform block with index
* uniformBlockIndex within program.
*/
public void glUniformBlockBinding(int program, int uniformBlockIndex, int uniformBlockBinding);
} }

@ -42,6 +42,32 @@ public interface GL4 extends GL3 {
public static final int GL_TESS_EVALUATION_SHADER = 0x8E87; public static final int GL_TESS_EVALUATION_SHADER = 0x8E87;
public static final int GL_PATCHES = 0xE; public static final int GL_PATCHES = 0xE;
/**
* Accepted by the {@code target} parameter of BindBufferBase and BindBufferRange.
*/
public static final int GL_ATOMIC_COUNTER_BUFFER = 0x92C0;
/**
* Accepted by the {@code target} parameters of BindBuffer, BufferData, BufferSubData, MapBuffer, UnmapBuffer, GetBufferSubData, and GetBufferPointerv.
*/
public static final int GL_SHADER_STORAGE_BUFFER = 0x90D2;
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_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>
* <p> * <p>
@ -50,4 +76,28 @@ public interface GL4 extends GL3 {
* @param count the new value for the parameter given by {@code pname} * @param count the new value for the parameter given by {@code pname}
*/ */
public void glPatchParameter(int count); public void glPatchParameter(int count);
/**
* Returns the unsigned integer index assigned to a resource named name in the interface type programInterface of
* program object program.
*
* @param program the name of a program object whose resources to query.
* @param programInterface a token identifying the interface within program containing the resource named name.
* @param name the name of the resource to query the index of.
* @return the index of a named resource within a program.
*/
public int glGetProgramResourceIndex(int program, int programInterface, String name);
/**
* Cchanges the active shader storage block with an assigned index of storageBlockIndex in program object program.
* storageBlockIndex must be an active shader storage block index in program. storageBlockBinding must be less
* than the value of {@code #GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS}. If successful, glShaderStorageBlockBinding specifies
* that program will use the data store of the buffer object bound to the binding point storageBlockBinding to
* read and write the values of the buffer variables in the shader storage block identified by storageBlockIndex.
*
* @param program the name of a program object whose resources to query.
* @param storageBlockIndex The index storage block within the program.
* @param storageBlockBinding The index storage block binding to associate with the specified storage block.
*/
public void glShaderStorageBlockBinding(int program, int storageBlockIndex, int storageBlockBinding);
} }

@ -83,6 +83,19 @@ public class GLDebugDesktop extends GLDebugES implements GL2, GL3, GL4 {
return result; return result;
} }
@Override
public int glGetUniformBlockIndex(final int program, final String uniformBlockName) {
final int result = gl3.glGetUniformBlockIndex(program, uniformBlockName);
checkError();
return result;
}
@Override
public void glBindBufferBase(final int target, final int index, final int buffer) {
gl3.glBindBufferBase(target, index, buffer);
checkError();
}
@Override @Override
public void glDeleteVertexArrays(IntBuffer arrays) { public void glDeleteVertexArrays(IntBuffer arrays) {
gl3.glDeleteVertexArrays(arrays); gl3.glDeleteVertexArrays(arrays);
@ -95,8 +108,27 @@ public class GLDebugDesktop extends GLDebugES implements GL2, GL3, GL4 {
checkError(); checkError();
} }
@Override
public int glGetProgramResourceIndex(int program, int programInterface, String name) {
final int result = gl4.glGetProgramResourceIndex(program, programInterface, name);
checkError();
return result;
}
@Override
public void glShaderStorageBlockBinding(int program, int storageBlockIndex, int storageBlockBinding) {
gl4.glShaderStorageBlockBinding(program, storageBlockIndex, storageBlockBinding);
checkError();
}
public void glBlendEquationSeparate(int colorMode, int alphaMode) { public void glBlendEquationSeparate(int colorMode, int alphaMode) {
gl.glBlendEquationSeparate(colorMode, alphaMode); gl.glBlendEquationSeparate(colorMode, alphaMode);
checkError(); checkError();
} }
@Override
public void glUniformBlockBinding(final int program, final int uniformBlockIndex, final int uniformBlockBinding) {
gl3.glUniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding);
checkError();
}
} }

@ -45,11 +45,9 @@ import com.jme3.scene.VertexBuffer;
import com.jme3.scene.VertexBuffer.Format; import com.jme3.scene.VertexBuffer.Format;
import com.jme3.scene.VertexBuffer.Type; import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.VertexBuffer.Usage; import com.jme3.scene.VertexBuffer.Usage;
import com.jme3.shader.Attribute; import com.jme3.shader.*;
import com.jme3.shader.Shader;
import com.jme3.shader.Shader.ShaderSource; import com.jme3.shader.Shader.ShaderSource;
import com.jme3.shader.Shader.ShaderType; import com.jme3.shader.Shader.ShaderType;
import com.jme3.shader.Uniform;
import com.jme3.texture.FrameBuffer; import com.jme3.texture.FrameBuffer;
import com.jme3.texture.FrameBuffer.RenderBuffer; import com.jme3.texture.FrameBuffer.RenderBuffer;
import com.jme3.texture.Image; import com.jme3.texture.Image;
@ -61,17 +59,17 @@ import com.jme3.util.BufferUtils;
import com.jme3.util.ListMap; import com.jme3.util.ListMap;
import com.jme3.util.MipMapGenerator; import com.jme3.util.MipMapGenerator;
import com.jme3.util.NativeObjectManager; import com.jme3.util.NativeObjectManager;
import java.nio.*; import jme3tools.shader.ShaderDebug;
import java.util.Arrays;
import java.util.EnumMap; import java.nio.ByteBuffer;
import java.util.EnumSet; import java.nio.FloatBuffer;
import java.util.HashSet; import java.nio.IntBuffer;
import java.util.List; import java.nio.ShortBuffer;
import java.util.*;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import jme3tools.shader.ShaderDebug;
public final class GLRenderer implements Renderer { public final class GLRenderer implements Renderer {
@ -480,6 +478,26 @@ 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 // Print context information
logger.log(Level.INFO, "OpenGL Renderer Information\n" + logger.log(Level.INFO, "OpenGL Renderer Information\n" +
" * Vendor: {0}\n" + " * Vendor: {0}\n" +
@ -1050,12 +1068,25 @@ public final class GLRenderer implements Renderer {
} }
} }
@Override
public void postFrame() { public void postFrame() {
objManager.deleteUnused(this); objManager.deleteUnused(this);
OpenCLObjectManager.getInstance().deleteUnusedObjects(); OpenCLObjectManager.getInstance().deleteUnusedObjects();
gl.resetStats(); gl.resetStats();
} }
protected void bindProgram(Shader shader) {
int shaderId = shader.getId();
if (context.boundShaderProgram != shaderId) {
gl.glUseProgram(shaderId);
statistics.onShaderUse(shader, true);
context.boundShader = shader;
context.boundShaderProgram = shaderId;
} else {
statistics.onShaderUse(shader, false);
}
}
/*********************************************************************\ /*********************************************************************\
|* Shaders *| |* Shaders *|
\*********************************************************************/ \*********************************************************************/
@ -1070,18 +1101,6 @@ public final class GLRenderer implements Renderer {
} }
} }
protected void bindProgram(Shader shader) {
int shaderId = shader.getId();
if (context.boundShaderProgram != shaderId) {
gl.glUseProgram(shaderId);
statistics.onShaderUse(shader, true);
context.boundShader = shader;
context.boundShaderProgram = shaderId;
} else {
statistics.onShaderUse(shader, false);
}
}
protected void updateUniform(Shader shader, Uniform uniform) { protected void updateUniform(Shader shader, Uniform uniform) {
int shaderId = shader.getId(); int shaderId = shader.getId();
@ -1187,6 +1206,58 @@ public final class GLRenderer implements Renderer {
} }
} }
/**
* Updates the buffer block for the shader.
*
* @param shader the shader.
* @param bufferBlock the storage block.
*/
protected void updateShaderBufferBlock(final Shader shader, final ShaderBufferBlock bufferBlock) {
assert bufferBlock.getName() != null;
assert shader.getId() > 0;
final BufferObject bufferObject = bufferBlock.getBufferObject();
if (bufferObject.getUniqueId() == -1 || bufferObject.isUpdateNeeded()) {
updateBufferData(bufferObject);
}
if (!bufferBlock.isUpdateNeeded()) {
return;
}
bindProgram(shader);
final int shaderId = shader.getId();
final BufferObject.BufferType bufferType = bufferObject.getBufferType();
bindBuffer(bufferBlock, bufferObject, shaderId, bufferType);
bufferBlock.clearUpdateNeeded();
}
private void bindBuffer(final ShaderBufferBlock bufferBlock, final BufferObject bufferObject, final int shaderId,
final BufferObject.BufferType bufferType) {
switch (bufferType) {
case UniformBufferObject: {
final int blockIndex = gl3.glGetUniformBlockIndex(shaderId, bufferBlock.getName());
gl3.glBindBufferBase(GL3.GL_UNIFORM_BUFFER, bufferObject.getBinding(), bufferObject.getId());
gl3.glUniformBlockBinding(GL3.GL_UNIFORM_BUFFER, blockIndex, bufferObject.getBinding());
break;
}
case ShaderStorageBufferObject: {
final int blockIndex = gl4.glGetProgramResourceIndex(shaderId, GL4.GL_SHADER_STORAGE_BLOCK, bufferBlock.getName());
gl4.glShaderStorageBlockBinding(shaderId, blockIndex, bufferObject.getBinding());
gl4.glBindBufferBase(GL4.GL_SHADER_STORAGE_BUFFER, bufferObject.getBinding(), bufferObject.getId());
break;
}
default: {
throw new IllegalArgumentException("Doesn't support binding of " + bufferType);
}
}
}
protected void updateShaderUniforms(Shader shader) { protected void updateShaderUniforms(Shader shader) {
ListMap<String, Uniform> uniforms = shader.getUniformMap(); ListMap<String, Uniform> uniforms = shader.getUniformMap();
for (int i = 0; i < uniforms.size(); i++) { for (int i = 0; i < uniforms.size(); i++) {
@ -1197,6 +1268,18 @@ public final class GLRenderer implements Renderer {
} }
} }
/**
* Updates all shader's buffer blocks.
*
* @param shader the shader.
*/
protected void updateShaderBufferBlocks(final Shader shader) {
final ListMap<String, ShaderBufferBlock> bufferBlocks = shader.getBufferBlockMap();
for (int i = 0; i < bufferBlocks.size(); i++) {
updateShaderBufferBlock(shader, bufferBlocks.getValue(i));
}
}
protected void resetUniformLocations(Shader shader) { protected void resetUniformLocations(Shader shader) {
ListMap<String, Uniform> uniforms = shader.getUniformMap(); ListMap<String, Uniform> uniforms = shader.getUniformMap();
for (int i = 0; i < uniforms.size(); i++) { for (int i = 0; i < uniforms.size(); i++) {
@ -1415,6 +1498,7 @@ public final class GLRenderer implements Renderer {
assert shader.getId() > 0; assert shader.getId() > 0;
updateShaderUniforms(shader); updateShaderUniforms(shader);
updateShaderBufferBlocks(shader);
bindProgram(shader); bindProgram(shader);
} }
} }
@ -2503,6 +2587,58 @@ public final class GLRenderer implements Renderer {
vb.clearUpdateNeeded(); vb.clearUpdateNeeded();
} }
@Override
public void updateBufferData(final BufferObject bo) {
int maxSize = Integer.MAX_VALUE;
final BufferObject.BufferType bufferType = bo.getBufferType();
if (!caps.contains(bufferType.getRequiredCaps())) {
throw new IllegalArgumentException("The current video hardware doesn't support " + bufferType);
}
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
intBuf1.clear();
gl.glGenBuffers(intBuf1);
bufferId = intBuf1.get(0);
bo.setId(bufferId);
objManager.registerObject(bo);
}
data.rewind();
switch (bufferType) {
case 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);
break;
}
case ShaderStorageBufferObject: {
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);
break;
}
default: {
throw new IllegalArgumentException("Doesn't support binding of " + bufferType);
}
}
bo.clearUpdateNeeded();
}
public void deleteBuffer(VertexBuffer vb) { public void deleteBuffer(VertexBuffer vb) {
int bufId = vb.getId(); int bufId = vb.getId();
if (bufId != -1) { if (bufId != -1) {
@ -2516,6 +2652,23 @@ public final class GLRenderer implements Renderer {
} }
} }
@Override
public void deleteBuffer(final BufferObject bo) {
int bufferId = bo.getId();
if (bufferId == -1) {
return;
}
intBuf1.clear();
intBuf1.put(bufferId);
intBuf1.flip();
gl.glDeleteBuffers(intBuf1);
bo.resetObject();
}
public void clearVertexAttribs() { public void clearVertexAttribs() {
IDList attribList = context.attribIndexList; IDList attribList = context.attribIndexList;
for (int i = 0; i < attribList.oldLen; i++) { for (int i = 0; i < attribList.oldLen; i++) {

@ -0,0 +1,828 @@
package com.jme3.shader;
import com.jme3.math.*;
import com.jme3.renderer.Caps;
import com.jme3.renderer.Renderer;
import com.jme3.util.BufferUtils;
import com.jme3.util.NativeObject;
import com.jme3.util.SafeArrayList;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* The base implementation of BO.
*
* @author JavaSaBr
*/
public class BufferObject extends NativeObject {
private static final Map<Class<?>, VarType> CLASS_TO_VAR_TYPE = new HashMap<>();
static {
CLASS_TO_VAR_TYPE.put(Float.class, VarType.Float);
CLASS_TO_VAR_TYPE.put(Integer.class, VarType.Int);
CLASS_TO_VAR_TYPE.put(Boolean.class, VarType.Boolean);
CLASS_TO_VAR_TYPE.put(Vector2f.class, VarType.Vector2);
CLASS_TO_VAR_TYPE.put(Vector3f.class, VarType.Vector3);
CLASS_TO_VAR_TYPE.put(ColorRGBA.class, VarType.Vector4);
CLASS_TO_VAR_TYPE.put(Quaternion.class, VarType.Vector4);
CLASS_TO_VAR_TYPE.put(Vector4f.class, VarType.Vector4);
CLASS_TO_VAR_TYPE.put(Vector2f[].class, VarType.Vector2Array);
CLASS_TO_VAR_TYPE.put(Vector3f[].class, VarType.Vector3Array);
CLASS_TO_VAR_TYPE.put(Vector4f[].class, VarType.Vector4Array);
CLASS_TO_VAR_TYPE.put(ColorRGBA[].class, VarType.Vector4Array);
CLASS_TO_VAR_TYPE.put(Quaternion[].class, VarType.Vector4Array);
CLASS_TO_VAR_TYPE.put(Matrix3f.class, VarType.Matrix3);
CLASS_TO_VAR_TYPE.put(Matrix4f.class, VarType.Matrix4);
CLASS_TO_VAR_TYPE.put(Matrix3f[].class, VarType.Matrix3Array);
CLASS_TO_VAR_TYPE.put(Matrix4f[].class, VarType.Matrix4Array);
}
protected static VarType getVarTypeByValue(final Object value) {
final VarType varType = CLASS_TO_VAR_TYPE.get(value.getClass());
if (varType != null) {
return varType;
} else if (value instanceof Collection<?> && ((Collection) value).isEmpty()) {
throw new IllegalArgumentException("Can't calculate a var type for the empty collection value[" + value + "].");
} else if (value instanceof List<?>) {
return getVarTypeByValue(((List) value).get(0));
} else if (value instanceof Collection<?>) {
return getVarTypeByValue(((Collection) value).iterator().next());
}
throw new IllegalArgumentException("Can't calculate a var type for the value " + value);
}
public enum Layout {
std140,
/** unsupported yet */
@Deprecated
std430,
}
public enum BufferType {
ShaderStorageBufferObject(Caps.ShaderStorageBufferObject),
UniformBufferObject(Caps.UniformBufferObject),
;
private final Caps requiredCaps;
BufferType(final Caps requiredCaps) {
this.requiredCaps = requiredCaps;
}
/**
* Get the required caps.
*
* @return the required caps.
*/
public Caps getRequiredCaps() {
return requiredCaps;
}
}
/**
* The fields of this BO.
*/
private final Map<String, BufferObjectField> fields;
/**
* The field's array.
*/
private final SafeArrayList<BufferObjectField> fieldArray;
/**
* The buffer's data layout.
*/
private final Layout layout;
/**
* The binding number.
*/
private final int binding;
/**
* The buffer's type.
*/
private BufferType bufferType;
/**
* The previous data buffer.
*/
private ByteBuffer previousData;
public BufferObject(final int binding, final Layout layout, final BufferType bufferType) {
this.handleRef = new Object();
this.bufferType = bufferType;
this.binding = binding;
this.layout = layout;
this.fields = new HashMap<>();
this.fieldArray = new SafeArrayList<>(BufferObjectField.class);
}
public BufferObject(final int binding, final Layout layout) {
this(binding, layout, BufferType.UniformBufferObject);
}
public BufferObject(final int binding, final BufferType bufferType) {
this(binding, Layout.std140, bufferType);
}
public BufferObject(final BufferType bufferType) {
this(1, Layout.std140, bufferType);
}
public BufferObject(final Layout layout) {
this(1, layout, BufferType.UniformBufferObject);
}
public BufferObject(final int binding) {
this(binding, Layout.std140, BufferType.UniformBufferObject);
}
public BufferObject() {
this(1, Layout.std140, BufferType.UniformBufferObject);
}
private BufferObject(final Void unused, final int id) {
super(id);
this.fieldArray = null;
this.fields = null;
this.layout = null;
this.binding = 0;
}
/**
* Declares a filed in this BO.
*
* @param name the field's name.
* @param varType the field's type.
*/
public void declareField(final String name, final VarType varType) {
if (fields.containsKey(name)) {
throw new IllegalArgumentException("The field " + name + " is already declared.");
}
final BufferObjectField field = new BufferObjectField(name, varType);
fields.put(name, field);
fieldArray.add(field);
}
/**
* Gets the buffer's type.
*
* @return the buffer's type.
*/
public BufferType getBufferType() {
return bufferType;
}
/**
* Sets the buffer's type.
*
* @param bufferType the buffer's type.
*/
public void setBufferType(final BufferType bufferType) {
if (getId() != -1) {
throw new IllegalStateException("Can't change buffer's type when this buffer is already initialized.");
}
this.bufferType = bufferType;
}
/**
* Sets the value to the filed by the field's name.
*
* @param name the field's name.
* @param value the value.
*/
public void setFieldValue(final String name, final Object value) {
BufferObjectField field = fields.get(name);
if (field == null) {
declareField(name, getVarTypeByValue(value));
field = fields.get(name);
}
field.setValue(value);
setUpdateNeeded();
}
/**
* Gets the current value of the field by the name.
*
* @param name the field name.
* @param <T> the value's type.
* @return the current value.
*/
public <T> T getFieldValue(final String name) {
final BufferObjectField field = fields.get(name);
if (field == null) {
throw new IllegalArgumentException("Unknown a field with the name " + name);
}
return (T) field.getValue();
}
/**
* Get the binding number.
*
* @return the binding number.
*/
public int getBinding() {
return binding;
}
@Override
public void resetObject() {
this.id = -1;
setUpdateNeeded();
}
/**
* Computes the current binary data of this BO.
*
* @param maxSize the max data size.
* @return the current binary data of this BO.
*/
public ByteBuffer computeData(final int maxSize) {
int estimateSize = 0;
for (final BufferObjectField field : fieldArray) {
estimateSize += estimateSize(field);
}
if(maxSize < estimateSize) {
throw new IllegalStateException("The estimated size(" + estimateSize + ") of this BO is bigger than " +
"maximum available size " + maxSize);
}
if (previousData != null) {
if (previousData.capacity() < estimateSize) {
BufferUtils.destroyDirectBuffer(previousData);
previousData = null;
} else {
previousData.clear();
}
}
final ByteBuffer data = previousData == null ? BufferUtils.createByteBuffer(estimateSize) : previousData;
for (final BufferObjectField field : fieldArray) {
writeField(field, data);
}
data.flip();
this.previousData = data;
return data;
}
/**
* Estimates size of the field.
*
* @param field the field.
* @return the estimated size.
*/
protected int estimateSize(final BufferObjectField field) {
switch (field.getType()) {
case Float:
case Int: {
if (layout == Layout.std140) {
return 16;
}
return 4;
}
case Boolean: {
if (layout == Layout.std140) {
return 16;
}
return 1;
}
case Vector2: {
return 4 * 2;
}
case Vector3: {
final int multiplier = layout == Layout.std140 ? 4 : 3;
return 4 * multiplier;
}
case Vector4:
return 16;
case IntArray: {
return estimate((int[]) field.getValue());
}
case FloatArray: {
return estimate((float[]) field.getValue());
}
case Vector2Array: {
return estimateArray(field.getValue(), 8);
}
case Vector3Array: {
final int multiplier = layout == Layout.std140 ? 16 : 12;
return estimateArray(field.getValue(), multiplier);
}
case Vector4Array: {
return estimateArray(field.getValue(), 16);
}
case Matrix3: {
final int multiplier = layout == Layout.std140 ? 16 : 12;
return 3 * 3 * multiplier;
}
case Matrix4: {
return 4 * 4 * 4;
}
case Matrix3Array: {
int multiplier = layout == Layout.std140 ? 16 : 12;
multiplier = 3 * 3 * multiplier;
return estimateArray(field.getValue(), multiplier);
}
case Matrix4Array: {
final int multiplier = 4 * 4 * 16;
return estimateArray(field.getValue(), multiplier);
}
default: {
throw new IllegalArgumentException("The type of BO field " + field.getType() + " doesn't support.");
}
}
}
/**
* Estimates bytes count to present the value on GPU.
*
* @param value the value.
* @param multiplier the multiplier.
* @return the estimated bytes cunt.
*/
protected int estimateArray(final Object value, final int multiplier) {
if (value instanceof Object[]) {
return ((Object[]) value).length * multiplier;
} else if (value instanceof Collection) {
return ((Collection) value).size() * multiplier;
}
throw new IllegalArgumentException("Unexpected value " + value);
}
/**
* Estimates bytes count to present the values on GPU.
*
* @param values the values.
* @return the estimated bytes cunt.
*/
protected int estimate(final float[] values) {
return values.length * 4;
}
/**
* Estimates bytes count to present the values on GPU.
*
* @param values the values.
* @return the estimated bytes cunt.
*/
protected int estimate(final int[] values) {
return values.length * 4;
}
/**
* Writes the field to the data buffer.
*
* @param field the field.
* @param data the data buffer.
*/
protected void writeField(final BufferObjectField field, final ByteBuffer data) {
final Object value = field.getValue();
switch (field.getType()) {
case Int: {
data.putInt(((Number) value).intValue());
if (layout == Layout.std140) {
data.putInt(0);
data.putLong(0);
}
break;
}
case Float: {
data.putFloat(((Number) value).floatValue());
if (layout == Layout.std140) {
data.putInt(0);
data.putLong(0);
}
break;
}
case Boolean:
data.put((byte) (((Boolean) value) ? 1 : 0));
if (layout == Layout.std140) {
data.putInt(0);
data.putLong(0);
data.putShort((short) 0);
data.put((byte) 0);
}
break;
case Vector2:
write(data, (Vector2f) value);
break;
case Vector3:
write(data, (Vector3f) value);
break;
case Vector4:
writeVec4(data, value);
break;
case IntArray: {
write(data, (int[]) value);
break;
}
case FloatArray: {
write(data, (float[]) value);
break;
}
case Vector2Array: {
writeVec2Array(data, value);
break;
}
case Vector3Array: {
writeVec3Array(data, value);
break;
}
case Vector4Array: {
writeVec4Array(data, value);
break;
}
case Matrix3: {
write(data, (Matrix3f) value);
break;
}
case Matrix4: {
write(data, (Matrix4f) value);
break;
}
case Matrix3Array: {
writeMat3Array(data, value);
break;
}
case Matrix4Array: {
writeMat4Array(data, value);
break;
}
default: {
throw new IllegalArgumentException("The type of BO field " + field.getType() + " doesn't support.");
}
}
}
/**
* Writes the value to the data buffer.
*
* @param data the data buffer.
* @param value the value.
*/
protected void writeMat3Array(final ByteBuffer data, final Object value) {
if (value instanceof Matrix3f[]) {
final Matrix3f[] values = (Matrix3f[]) value;
for (final Matrix3f mat : values) {
write(data, mat);
}
} else if(value instanceof SafeArrayList) {
final SafeArrayList<Matrix3f> values = (SafeArrayList<Matrix3f>) value;
for (final Matrix3f mat : values.getArray()) {
write(data, mat);
}
} else if(value instanceof Collection) {
final Collection<Matrix3f> values = (Collection<Matrix3f>) value;
for (final Matrix3f mat : values) {
write(data, mat);
}
}
}
/**
* Writes the value to the data buffer.
*
* @param data the data buffer.
* @param value the value.
*/
protected void writeMat4Array(final ByteBuffer data, final Object value) {
if (value instanceof Matrix4f[]) {
final Matrix4f[] values = (Matrix4f[]) value;
for (final Matrix4f mat : values) {
write(data, mat);
}
} else if(value instanceof SafeArrayList) {
final SafeArrayList<Matrix4f> values = (SafeArrayList<Matrix4f>) value;
for (final Matrix4f mat : values.getArray()) {
write(data, mat);
}
} else if(value instanceof Collection) {
final Collection<Matrix4f> values = (Collection<Matrix4f>) value;
for (final Matrix4f mat : values) {
write(data, mat);
}
}
}
/**
* Writes the value to the data buffer.
*
* @param data the data buffer.
* @param value the value.
*/
protected void writeVec4Array(final ByteBuffer data, final Object value) {
if (value instanceof Object[]) {
final Object[] values = (Object[]) value;
for (final Object vec : values) {
writeVec4(data, vec);
}
} else if(value instanceof SafeArrayList) {
final SafeArrayList<Object> values = (SafeArrayList<Object>) value;
for (final Object vec : values.getArray()) {
writeVec4(data, vec);
}
} else if(value instanceof Collection) {
final Collection<Object> values = (Collection<Object>) value;
for (final Object vec : values) {
writeVec4(data, vec);
}
}
}
/**
* Writes the value to the data buffer.
*
* @param data the data buffer.
* @param value the value.
*/
protected void writeVec3Array(final ByteBuffer data, final Object value) {
if (value instanceof Vector3f[]) {
final Vector3f[] values = (Vector3f[]) value;
for (final Vector3f vec : values) {
write(data, vec);
}
} else if(value instanceof SafeArrayList) {
final SafeArrayList<Vector3f> values = (SafeArrayList<Vector3f>) value;
for (final Vector3f vec : values.getArray()) {
write(data, vec);
}
} else if(value instanceof Collection) {
final Collection<Vector3f> values = (Collection<Vector3f>) value;
for (final Vector3f vec : values) {
write(data, vec);
}
}
}
/**
* Writes the value to the data buffer.
*
* @param data the data buffer.
* @param value the value.
*/
protected void writeVec2Array(final ByteBuffer data, final Object value) {
if (value instanceof Vector2f[]) {
final Vector2f[] values = (Vector2f[]) value;
for (final Vector2f vec : values) {
write(data, vec);
}
} else if(value instanceof SafeArrayList) {
final SafeArrayList<Vector2f> values = (SafeArrayList<Vector2f>) value;
for (final Vector2f vec : values.getArray()) {
write(data, vec);
}
} else if(value instanceof Collection) {
final Collection<Vector2f> values = (Collection<Vector2f>) value;
for (final Vector2f vec : values) {
write(data, vec);
}
}
}
/**
* Writes the value to the data buffer.
*
* @param data the data buffer.
* @param value the value.
*/
protected void write(final ByteBuffer data, final float[] value) {
for (float val : value) {
data.putFloat(val);
}
}
/**
* Writes the value to the data buffer.
*
* @param data the data buffer.
* @param value the value.
*/
protected void write(final ByteBuffer data, final int[] value) {
for (int val : value) {
data.putInt(val);
}
}
/**
* Writes the value to the data buffer.
*
* @param data the data buffer.
* @param value the value.
*/
protected void writeVec4(final ByteBuffer data, final Object value) {
if (value == null) {
data.putLong(0).putLong(0);
} else if (value instanceof Vector4f) {
final Vector4f vec4 = (Vector4f) value;
data.putFloat(vec4.getX())
.putFloat(vec4.getY())
.putFloat(vec4.getZ())
.putFloat(vec4.getW());
} else if(value instanceof Quaternion) {
final Quaternion vec4 = (Quaternion) value;
data.putFloat(vec4.getX())
.putFloat(vec4.getY())
.putFloat(vec4.getZ())
.putFloat(vec4.getW());
} else if(value instanceof ColorRGBA) {
final ColorRGBA vec4 = (ColorRGBA) value;
data.putFloat(vec4.getRed())
.putFloat(vec4.getGreen())
.putFloat(vec4.getBlue())
.putFloat(vec4.getAlpha());
}
}
/**
* Writes the value to the data buffer.
*
* @param data the data buffer.
* @param value the value.
*/
protected void write(final ByteBuffer data, final Vector3f value) {
if (value == null) {
data.putLong(0).putInt(0);
} else {
data.putFloat(value.getX())
.putFloat(value.getY())
.putFloat(value.getZ());
}
if (layout == Layout.std140) {
data.putInt(0);
}
}
/**
* Writes the value to the data buffer.
*
* @param data the data buffer.
* @param x the x value.
* @param y the y value.
* @param z the z value.
*/
protected void write(final ByteBuffer data, final float x, final float y, final float z) {
data.putFloat(x)
.putFloat(y)
.putFloat(z);
if (layout == Layout.std140) {
data.putInt(0);
}
}
/**
* Writes the value to the data buffer.
*
* @param data the data buffer.
* @param x the x value.
* @param y the y value.
* @param z the z value.
* @param w the w value.
*/
protected void write(final ByteBuffer data, final float x, final float y, final float z, final float w) {
data.putFloat(x)
.putFloat(y)
.putFloat(z)
.putFloat(w);
}
/**
* Writes the value to the data buffer.
*
* @param data the data buffer.
* @param value the value.
*/
protected void write(final ByteBuffer data, final Vector2f value) {
if (value == null) {
data.putLong(0);
} else {
data.putFloat(value.getX()).putFloat(value.getY());
}
}
/**
* Writes the value to the data buffer.
*
* @param data the data buffer.
* @param value the value.
*/
protected void write(final ByteBuffer data, final Matrix3f value) {
write(data, value.get(0, 0), value.get(1, 0), value.get(2, 0));
write(data, value.get(0, 1), value.get(1, 1), value.get(2, 1));
write(data, value.get(0, 2), value.get(1, 2), value.get(2, 2));
}
/**
* Writes the value to the data buffer.
*
* @param data the data buffer.
* @param value the value.
*/
protected void write(final ByteBuffer data, final Matrix4f value) {
write(data, value.get(0, 0), value.get(1, 0), value.get(2, 0), value.get(3, 0));
write(data, value.get(0, 1), value.get(1, 1), value.get(2, 1), value.get(3, 1));
write(data, value.get(0, 2), value.get(1, 2), value.get(2, 2), value.get(3, 2));
write(data, value.get(0, 3), value.get(1, 3), value.get(2, 3), value.get(3, 3));
}
@Override
public void deleteObject(final Object rendererObject) {
if (!(rendererObject instanceof Renderer)) {
throw new IllegalArgumentException("This bo can't be deleted from " + rendererObject);
}
((Renderer) rendererObject).deleteBuffer(this);
}
@Override
public NativeObject createDestructableClone() {
return new BufferObject(null, getId());
}
@Override
protected void deleteNativeBuffers() {
super.deleteNativeBuffers();
if (previousData != null) {
BufferUtils.destroyDirectBuffer(previousData);
previousData = null;
}
}
@Override
public long getUniqueId() {
return ((long) OBJTYPE_BO << 32) | ((long) id);
}
}

@ -0,0 +1,77 @@
package com.jme3.shader;
import static java.util.Objects.requireNonNull;
/**
* The class to describe a filed in BO.
*
* @author JavaSaBr
*/
public class BufferObjectField {
/**
* The field name.
*/
private final String name;
/**
* The field type.
*/
private final VarType type;
/**
* The field value.
*/
private Object value;
public BufferObjectField(final String name, final VarType type) {
this.name = name;
this.type = type;
}
/**
* Get the field name.
*
* @return the field name.
*/
public String getName() {
return name;
}
/**
* Gets the field type.
*
* @return the field type.
*/
public VarType getType() {
return type;
}
/**
* Gets the field value.
*
* @return the field value.
*/
public Object getValue() {
return value;
}
/**
* Sets the field value.
*
* @param value the field value.
*/
public void setValue(final Object value) {
this.value = requireNonNull(value, "The field's value can't be null.");
}
@Override
public String toString() {
return "BufferObjectField{" +
"name='" + name + '\'' +
", type=" + type +
", value=" + value +
'}';
}
}

@ -51,6 +51,11 @@ public final class Shader extends NativeObject {
* Maps uniform name to the uniform variable. * Maps uniform name to the uniform variable.
*/ */
private final ListMap<String, Uniform> uniforms; private final ListMap<String, Uniform> uniforms;
/**
* Maps storage block name to the buffer block variables.
*/
private final ListMap<String, ShaderBufferBlock> bufferBlocks;
/** /**
* Uniforms bound to {@link UniformBinding}s. * Uniforms bound to {@link UniformBinding}s.
@ -220,10 +225,11 @@ public final class Shader extends NativeObject {
*/ */
public Shader(){ public Shader(){
super(); super();
shaderSourceList = new ArrayList<ShaderSource>(); shaderSourceList = new ArrayList<>();
uniforms = new ListMap<String, Uniform>(); uniforms = new ListMap<>();
attribs = new IntMap<Attribute>(); bufferBlocks = new ListMap<>();
boundUniforms = new ArrayList<Uniform>(); attribs = new IntMap<>();
boundUniforms = new ArrayList<>();
} }
/** /**
@ -240,6 +246,7 @@ public final class Shader extends NativeObject {
} }
uniforms = null; uniforms = null;
bufferBlocks = null;
boundUniforms = null; boundUniforms = null;
attribs = null; attribs = null;
} }
@ -288,10 +295,40 @@ public final class Shader extends NativeObject {
return uniform; return uniform;
} }
/**
* Gets or creates a buffer block by the name.
*
* @param name the buffer block's name.
* @return the buffer block.
*/
public ShaderBufferBlock getBufferBlock(final String name) {
assert name.startsWith("m_");
ShaderBufferBlock block = bufferBlocks.get(name);
if (block == null) {
block = new ShaderBufferBlock();
block.name = name;
bufferBlocks.put(name, block);
}
return block;
}
public void removeUniform(String name){ public void removeUniform(String name){
uniforms.remove(name); uniforms.remove(name);
} }
/**
* Removes a buffer block by the name.
*
* @param name the buffer block's name.
*/
public void removeBufferBlock(final String name){
bufferBlocks.remove(name);
}
public Attribute getAttribute(VertexBuffer.Type attribType){ public Attribute getAttribute(VertexBuffer.Type attribType){
int ordinal = attribType.ordinal(); int ordinal = attribType.ordinal();
Attribute attrib = attribs.get(ordinal); Attribute attrib = attribs.get(ordinal);
@ -306,7 +343,16 @@ public final class Shader extends NativeObject {
public ListMap<String, Uniform> getUniformMap(){ public ListMap<String, Uniform> getUniformMap(){
return uniforms; return uniforms;
} }
/**
* Get the buffer blocks map.
*
* @return the buffer blocks map.
*/
public ListMap<String, ShaderBufferBlock> getBufferBlockMap() {
return bufferBlocks;
}
public ArrayList<Uniform> getBoundUniforms() { public ArrayList<Uniform> getBoundUniforms() {
return boundUniforms; return boundUniforms;
} }
@ -320,6 +366,7 @@ public final class Shader extends NativeObject {
return getClass().getSimpleName() + return getClass().getSimpleName() +
"[numSources=" + shaderSourceList.size() + "[numSources=" + shaderSourceList.size() +
", numUniforms=" + uniforms.size() + ", numUniforms=" + uniforms.size() +
", numBufferBlocks=" + bufferBlocks.size() +
", shaderSources=" + getSources() + "]"; ", shaderSources=" + getSources() + "]";
} }
@ -343,7 +390,7 @@ public final class Shader extends NativeObject {
* Resets all uniforms that do not have the "set-by-current-material" flag * Resets all uniforms that do not have the "set-by-current-material" flag
* to their default value (usually all zeroes or false). * to their default value (usually all zeroes or false).
* When a uniform is modified, that flag is set, to remove the flag, * When a uniform is modified, that flag is set, to remove the flag,
* use {@link #clearUniformsSetByCurrent() }. * use {@link #clearUniformsSetByCurrentFlag() }.
*/ */
public void resetUniformsNotSetByCurrent() { public void resetUniformsNotSetByCurrent() {
int size = uniforms.size(); int size = uniforms.size();
@ -366,6 +413,11 @@ public final class Shader extends NativeObject {
uniform.reset(); // fixes issue with re-initialization uniform.reset(); // fixes issue with re-initialization
} }
} }
if (bufferBlocks != null) {
for (ShaderBufferBlock shaderBufferBlock : bufferBlocks.values()) {
shaderBufferBlock.reset();
}
}
if (attribs != null) { if (attribs != null) {
for (Entry<Attribute> entry : attribs) { for (Entry<Attribute> entry : attribs) {
entry.getValue().location = ShaderVariable.LOC_UNKNOWN; entry.getValue().location = ShaderVariable.LOC_UNKNOWN;

@ -0,0 +1,93 @@
/*
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.shader;
/**
* Implementation of shader's buffer block.
*
* @author JavaSaBr
*/
public class ShaderBufferBlock extends ShaderVariable {
/**
* Current used buffer object.
*/
protected BufferObject bufferObject;
/**
* Set the new buffer object.
*
* @param bufferObject the new buffer object.
*/
public void setBufferObject(final BufferObject bufferObject) {
if (bufferObject == null) {
throw new IllegalArgumentException("for storage block " + name + ": storageData cannot be null");
}
this.bufferObject = bufferObject;
updateNeeded = true;
}
/**
* Return true if need to update this storage block.
*
* @return true if need to update this storage block.
*/
public boolean isUpdateNeeded(){
return updateNeeded;
}
/**
* Clear the flag {@link #isUpdateNeeded()}.
*/
public void clearUpdateNeeded(){
updateNeeded = false;
}
/**
* Reset this storage block.
*/
public void reset(){
updateNeeded = true;
}
/**
* Get the current storage data.
*
* @return the current storage data.
*/
public BufferObject getBufferObject() {
return bufferObject;
}
}

@ -57,7 +57,8 @@ public enum VarType {
Texture3D(false,true,"sampler3D"), Texture3D(false,true,"sampler3D"),
TextureArray(false,true,"sampler2DArray|sampler2DArrayShadow"), TextureArray(false,true,"sampler2DArray|sampler2DArrayShadow"),
TextureCubeMap(false,true,"samplerCube"), TextureCubeMap(false,true,"samplerCube"),
Int("int"); Int("int"),
BufferObject(false, false, "custom");
private boolean usesMultiData = false; private boolean usesMultiData = false;
private boolean textureType = false; private boolean textureType = false;

@ -31,9 +31,6 @@
*/ */
package com.jme3.system; package com.jme3.system;
import java.nio.ByteBuffer;
import java.util.EnumSet;
import com.jme3.light.LightList; import com.jme3.light.LightList;
import com.jme3.material.RenderState; import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
@ -44,12 +41,16 @@ import com.jme3.renderer.Renderer;
import com.jme3.renderer.Statistics; import com.jme3.renderer.Statistics;
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;
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.texture.FrameBuffer; 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 java.nio.ByteBuffer;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.EnumSet;
public class NullRenderer implements Renderer { public class NullRenderer implements Renderer {
@ -148,9 +149,17 @@ public class NullRenderer implements Renderer {
public void updateBufferData(VertexBuffer vb) { public void updateBufferData(VertexBuffer vb) {
} }
@Override
public void updateBufferData(BufferObject bo) {
}
public void deleteBuffer(VertexBuffer vb) { public void deleteBuffer(VertexBuffer vb) {
} }
@Override
public void deleteBuffer(BufferObject bo) {
}
public void renderMesh(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) { public void renderMesh(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) {
} }

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

@ -4,12 +4,11 @@ import com.jme3.renderer.RendererException;
import com.jme3.renderer.opengl.GL; import com.jme3.renderer.opengl.GL;
import com.jme3.renderer.opengl.GL2; import com.jme3.renderer.opengl.GL2;
import com.jme3.renderer.opengl.GL3; import com.jme3.renderer.opengl.GL3;
import java.nio.*;
import com.jme3.renderer.opengl.GL4; import com.jme3.renderer.opengl.GL4;
import com.jogamp.opengl.GLContext; import com.jogamp.opengl.GLContext;
import java.nio.*;
public class JoglGL implements GL, GL2, GL3, GL4 { public class JoglGL implements GL, GL2, GL3, GL4 {
private static int getLimitBytes(ByteBuffer buffer) { private static int getLimitBytes(ByteBuffer buffer) {
@ -628,10 +627,36 @@ public class JoglGL implements GL, GL2, GL3, GL4 {
public void glPatchParameter(int count) { public void glPatchParameter(int count) {
GLContext.getCurrentGL().getGL3().glPatchParameteri(com.jogamp.opengl.GL3.GL_PATCH_VERTICES, count); GLContext.getCurrentGL().getGL3().glPatchParameteri(com.jogamp.opengl.GL3.GL_PATCH_VERTICES, count);
} }
@Override @Override
public void glDeleteVertexArrays(IntBuffer arrays) { public void glDeleteVertexArrays(IntBuffer arrays) {
checkLimit(arrays); checkLimit(arrays);
GLContext.getCurrentGL().getGL2ES3().glDeleteVertexArrays(arrays.limit(), arrays); GLContext.getCurrentGL().getGL2ES3().glDeleteVertexArrays(arrays.limit(), arrays);
} }
@Override
public int glGetUniformBlockIndex(final int program, final String uniformBlockName) {
return GLContext.getCurrentGL().getGL3bc().glGetUniformBlockIndex(program, uniformBlockName);
}
@Override
public void glBindBufferBase(final int target, final int index, final int buffer) {
GLContext.getCurrentGL().getGL3bc().glBindBufferBase(target, index, buffer);
}
@Override
public int glGetProgramResourceIndex(final int program, final int programInterface, final String name) {
throw new UnsupportedOperationException();
//return GLContext.getCurrentGL().getGL4bc().glGetProgramResourceIndex(program, programInterface, name);
}
@Override
public void glShaderStorageBlockBinding(final int program, final int storageBlockIndex, final int storageBlockBinding) {
GLContext.getCurrentGL().getGL4bc().glShaderStorageBlockBinding(program, storageBlockIndex, storageBlockBinding);
}
@Override
public void glUniformBlockBinding(final int program, final int uniformBlockIndex, final int uniformBlockBinding) {
GLContext.getCurrentGL().getGL3bc().glUniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding);
}
} }

@ -4,16 +4,12 @@ import com.jme3.renderer.RendererException;
import com.jme3.renderer.opengl.GL; import com.jme3.renderer.opengl.GL;
import com.jme3.renderer.opengl.GL2; import com.jme3.renderer.opengl.GL2;
import com.jme3.renderer.opengl.GL3; import com.jme3.renderer.opengl.GL3;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import com.jme3.renderer.opengl.GL4; import com.jme3.renderer.opengl.GL4;
import com.jme3.util.BufferUtils; import com.jme3.util.BufferUtils;
import org.lwjgl.opengl.*; import org.lwjgl.opengl.*;
import java.nio.*;
public final class LwjglGL implements GL, GL2, GL3, GL4 { public final class LwjglGL implements GL, GL2, GL3, GL4 {
IntBuffer tmpBuff = BufferUtils.createIntBuffer(1); IntBuffer tmpBuff = BufferUtils.createIntBuffer(1);
@ -487,10 +483,35 @@ public final class LwjglGL implements GL, GL2, GL3, GL4 {
public void glPatchParameter(int count) { public void glPatchParameter(int count) {
GL40.glPatchParameteri(GL40.GL_PATCH_VERTICES,count); GL40.glPatchParameteri(GL40.GL_PATCH_VERTICES,count);
} }
@Override
public int glGetProgramResourceIndex(final int program, final int programInterface, final String name) {
return GL43.glGetProgramResourceIndex(program, programInterface, name);
}
@Override
public void glShaderStorageBlockBinding(final int program, final int storageBlockIndex, final int storageBlockBinding) {
GL43.glShaderStorageBlockBinding(program, storageBlockIndex, storageBlockBinding);
}
@Override @Override
public void glDeleteVertexArrays(IntBuffer arrays) { public void glDeleteVertexArrays(IntBuffer arrays) {
checkLimit(arrays); checkLimit(arrays);
ARBVertexArrayObject.glDeleteVertexArrays(arrays); ARBVertexArrayObject.glDeleteVertexArrays(arrays);
} }
@Override
public int glGetUniformBlockIndex(final int program, final String uniformBlockName) {
return GL31.glGetUniformBlockIndex(program, uniformBlockName);
}
@Override
public void glBindBufferBase(final int target, final int index, final int buffer) {
GL30.glBindBufferBase(target, index, buffer);
}
@Override
public void glUniformBlockBinding(final int program, final int uniformBlockIndex, final int uniformBlockBinding) {
GL31.glUniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding);
}
} }

@ -616,9 +616,34 @@ public class LwjglGL extends LwjglRender implements GL, GL2, GL3, GL4 {
GL40.glPatchParameteri(GL40.GL_PATCH_VERTICES, count); GL40.glPatchParameteri(GL40.GL_PATCH_VERTICES, count);
} }
@Override
public int glGetProgramResourceIndex(final int program, final int programInterface, final String name) {
return GL43.glGetProgramResourceIndex(program, programInterface, name);
}
@Override
public void glShaderStorageBlockBinding(final int program, final int storageBlockIndex, final int storageBlockBinding) {
GL43.glShaderStorageBlockBinding(program, storageBlockIndex, storageBlockBinding);
}
@Override @Override
public void glDeleteVertexArrays(final IntBuffer arrays) { public void glDeleteVertexArrays(final IntBuffer arrays) {
checkLimit(arrays); checkLimit(arrays);
ARBVertexArrayObject.glDeleteVertexArrays(arrays); ARBVertexArrayObject.glDeleteVertexArrays(arrays);
} }
@Override
public int glGetUniformBlockIndex(final int program, final String uniformBlockName) {
return GL31.glGetUniformBlockIndex(program, uniformBlockName);
}
@Override
public void glBindBufferBase(final int target, final int index, final int buffer) {
GL30.glBindBufferBase(target, index, buffer);
}
@Override
public void glUniformBlockBinding(final int program, final int uniformBlockIndex, final int uniformBlockBinding) {
GL31.glUniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding);
}
} }

Loading…
Cancel
Save