Skip to content

Commit

Permalink
UBO/SSBO Improvements, Structs, BufferObject and sub data update (#1782)
Browse files Browse the repository at this point in the history
 reimplement UBOs and SSBOs in a more convenient and performant way.
  • Loading branch information
riccardobl authored Jan 21, 2024
1 parent 9a0ab09 commit 0b40bba
Show file tree
Hide file tree
Showing 57 changed files with 4,653 additions and 1,068 deletions.
1 change: 1 addition & 0 deletions jme-angle/src/native/angle
Submodule angle added at 231960
148 changes: 82 additions & 66 deletions jme3-core/src/main/java/com/jme3/material/Material.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2021 jMonkeyEngine
* Copyright (c) 2009-2024 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -47,6 +47,7 @@
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Geometry;
import com.jme3.shader.*;
import com.jme3.shader.bufferobject.BufferObject;
import com.jme3.texture.Image;
import com.jme3.texture.Texture;
import com.jme3.texture.image.ColorSpace;
Expand Down Expand Up @@ -87,6 +88,16 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
private boolean receivesShadows = false;
private int sortingId = -1;

/**
* Track bind ids for textures and buffers
* Used internally
*/
public static class BindUnits {
public int textureUnit = 0;
public int bufferUnit = 0;
}
private BindUnits bindUnits = new BindUnits();

public Material(MaterialDef def) {
if (def == null) {
throw new IllegalArgumentException("Material definition cannot be null");
Expand Down Expand Up @@ -506,6 +517,18 @@ public void setParam(String name, VarType type, Object value) {
}
}

/**
* Pass a parameter to the material shader.
*
* @param name the name of the parameter defined in the material definition (j3md)
* @param value the value of the parameter
*/
public void setParam(String name, Object value) {
MatParam p = getMaterialDef().getMaterialParam(name);
setParam(name, p.getVarType(), value);
}


/**
* Clear a parameter from this material. The parameter must exist
* @param name the name of the parameter to clear
Expand Down Expand Up @@ -685,8 +708,7 @@ public void setColor(String name, ColorRGBA value) {
* @param value the buffer object.
*/
public void setUniformBufferObject(final String name, final BufferObject value) {
value.setBufferType(BufferObject.BufferType.UniformBufferObject);
setParam(name, VarType.BufferObject, value);
setParam(name, VarType.UniformBufferObject, value);
}

/**
Expand All @@ -696,8 +718,7 @@ public void setUniformBufferObject(final String name, final BufferObject value)
* @param value the buffer object.
*/
public void setShaderStorageBufferObject(final String name, final BufferObject value) {
value.setBufferType(BufferObject.BufferType.ShaderStorageBufferObject);
setParam(name, VarType.BufferObject, value);
setParam(name, VarType.ShaderStorageBufferObject, value);
}

/**
Expand Down Expand Up @@ -797,7 +818,7 @@ public void selectTechnique(String name, final RenderManager renderManager) {
sortingId = -1;
}

private int applyOverrides(Renderer renderer, Shader shader, SafeArrayList<MatParamOverride> overrides, int unit) {
private void applyOverrides(Renderer renderer, Shader shader, SafeArrayList<MatParamOverride> overrides, BindUnits bindUnits) {
for (MatParamOverride override : overrides.getArray()) {
VarType type = override.getVarType();

Expand All @@ -810,85 +831,80 @@ private int applyOverrides(Renderer renderer, Shader shader, SafeArrayList<MatPa
Uniform uniform = shader.getUniform(override.getPrefixedName());

if (override.getValue() != null) {
if (type.isTextureType()) {
try {
renderer.setTexture(unit, (Texture) override.getValue());
} catch (TextureUnitException exception) {
int numTexParams = unit + 1;
String message = "Too many texture parameters ("
+ numTexParams + ") assigned\n to " + toString();
throw new IllegalStateException(message);
}
uniform.setValue(VarType.Int, unit);
unit++;
} else {
uniform.setValue(type, override.getValue());
}
updateShaderMaterialParameter(renderer, type, shader, override, bindUnits, true);
} else {
uniform.clearValue();
}
}
return unit;
}

private int updateShaderMaterialParameters(Renderer renderer, Shader shader,
SafeArrayList<MatParamOverride> worldOverrides, SafeArrayList<MatParamOverride> forcedOverrides) {

int unit = 0;
private void updateShaderMaterialParameter(Renderer renderer, VarType type, Shader shader, MatParam param, BindUnits unit, boolean override) {
if (type == VarType.UniformBufferObject || type == VarType.ShaderStorageBufferObject) {
ShaderBufferBlock bufferBlock = shader.getBufferBlock(param.getPrefixedName());
BufferObject bufferObject = (BufferObject) param.getValue();

ShaderBufferBlock.BufferType btype;
if (type == VarType.ShaderStorageBufferObject) {
btype = ShaderBufferBlock.BufferType.ShaderStorageBufferObject;
bufferBlock.setBufferObject(btype, bufferObject);
renderer.setShaderStorageBufferObject(unit.bufferUnit, bufferObject); // TODO: probably not needed
} else {
btype = ShaderBufferBlock.BufferType.UniformBufferObject;
bufferBlock.setBufferObject(btype, bufferObject);
renderer.setUniformBufferObject(unit.bufferUnit, bufferObject); // TODO: probably not needed
}
unit.bufferUnit++;
} else {
Uniform uniform = shader.getUniform(param.getPrefixedName());
if (!override && uniform.isSetByCurrentMaterial()) return;

if (type.isTextureType()) {
try {
renderer.setTexture(unit.textureUnit, (Texture) param.getValue());
} catch (TextureUnitException exception) {
int numTexParams = unit.textureUnit + 1;
String message = "Too many texture parameters (" + numTexParams + ") assigned\n to " + toString();
throw new IllegalStateException(message);
}
uniform.setValue(VarType.Int, unit.textureUnit);
unit.textureUnit++;
} else {
uniform.setValue(type, param.getValue());
}
}
}




private BindUnits updateShaderMaterialParameters(Renderer renderer, Shader shader, SafeArrayList<MatParamOverride> worldOverrides,
SafeArrayList<MatParamOverride> forcedOverrides) {

bindUnits.textureUnit = 0;
bindUnits.bufferUnit = 0;

if (worldOverrides != null) {
unit = applyOverrides(renderer, shader, worldOverrides, unit);
applyOverrides(renderer, shader, worldOverrides, bindUnits);
}
if (forcedOverrides != null) {
unit = applyOverrides(renderer, shader, forcedOverrides, unit);
applyOverrides(renderer, shader, forcedOverrides, bindUnits);
}

for (int i = 0; i < paramValues.size(); i++) {

MatParam param = paramValues.getValue(i);
VarType type = param.getVarType();

if (isBO(type)) {

final ShaderBufferBlock bufferBlock = shader.getBufferBlock(param.getPrefixedName());
bufferBlock.setBufferObject((BufferObject) param.getValue());

} else {

Uniform uniform = shader.getUniform(param.getPrefixedName());
if (uniform.isSetByCurrentMaterial()) {
continue;
}

if (type.isTextureType()) {
try {
renderer.setTexture(unit, (Texture) param.getValue());
} catch (TextureUnitException exception) {
int numTexParams = unit + 1;
String message = "Too many texture parameters ("
+ numTexParams + ") assigned\n to " + toString();
throw new IllegalStateException(message);
}
uniform.setValue(VarType.Int, unit);
unit++;
} else {
uniform.setValue(type, param.getValue());
}
}
updateShaderMaterialParameter(renderer, type, shader, param, bindUnits, false);
}

//TODO HACKY HACK remove this when texture unit is handled by the uniform.
return unit;
// TODO HACKY HACK remove this when texture unit is handled by the
// uniform.
return bindUnits;
}

/**
* 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(Geometry geometry, RenderManager renderManager, Renderer renderer, TechniqueDef techniqueDef) {
if (renderManager.getForcedRenderState() != null) {
Expand Down Expand Up @@ -1064,13 +1080,13 @@ public void render(Geometry geometry, LightList lights, RenderManager renderMana
renderManager.updateUniformBindings(shader);

// Set material parameters
int unit = updateShaderMaterialParameters(renderer, shader, overrides, renderManager.getForcedMatParams());
BindUnits units = updateShaderMaterialParameters(renderer, shader, overrides, renderManager.getForcedMatParams());

// Clear any uniforms not changed by material.
resetUniformsNotSetByCurrent(shader);

// Delegate rendering to the technique
technique.render(renderManager, shader, geometry, lights, unit);
technique.render(renderManager, shader, geometry, lights, units);
}

/**
Expand Down
7 changes: 4 additions & 3 deletions jme3-core/src/main/java/com/jme3/material/Technique.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2021 jMonkeyEngine
* Copyright (c) 2009-2024 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -33,6 +33,7 @@

import com.jme3.asset.AssetManager;
import com.jme3.light.LightList;
import com.jme3.material.Material.BindUnits;
import com.jme3.material.TechniqueDef.LightMode;
import com.jme3.material.logic.TechniqueDefLogic;
import com.jme3.renderer.Caps;
Expand Down Expand Up @@ -162,9 +163,9 @@ Shader makeCurrent(RenderManager renderManager, SafeArrayList<MatParamOverride>
* @param lights Lights which influence the geometry.
* @param lastTexUnit the index of the most recently used texture unit
*/
void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) {
void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) {
TechniqueDefLogic logic = def.getLogic();
logic.render(renderManager, shader, geometry, lights, lastTexUnit);
logic.render(renderManager, shader, geometry, lights, lastBindUnits);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2021 jMonkeyEngine
* Copyright (c) 2009-2024 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -34,6 +34,7 @@
import com.jme3.asset.AssetManager;
import com.jme3.light.*;
import com.jme3.material.TechniqueDef;
import com.jme3.material.Material.BindUnits;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.Caps;
import com.jme3.renderer.RenderManager;
Expand Down Expand Up @@ -91,7 +92,7 @@ protected static ColorRGBA getAmbientColor(LightList lightList, boolean removeLi


@Override
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) {
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) {
Renderer renderer = renderManager.getRenderer();
renderer.setShader(shader);
renderMeshFromGeometry(renderer, geometry);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2021 jMonkeyEngine
* Copyright (c) 2009-2024 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -38,6 +38,7 @@
import com.jme3.light.SpotLight;
import com.jme3.material.RenderState;
import com.jme3.material.TechniqueDef;
import com.jme3.material.Material.BindUnits;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
Expand Down Expand Up @@ -67,7 +68,7 @@ public MultiPassLightingLogic(TechniqueDef techniqueDef) {
}

@Override
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) {
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) {
Renderer r = renderManager.getRenderer();
Uniform lightDir = shader.getUniform("g_LightDirection");
Uniform lightColor = shader.getUniform("g_LightColor");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2021 jMonkeyEngine
* Copyright (c) 2009-2024 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -34,6 +34,7 @@
import com.jme3.asset.AssetManager;
import com.jme3.light.*;
import com.jme3.material.*;
import com.jme3.material.Material.BindUnits;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.*;
import com.jme3.renderer.*;
Expand Down Expand Up @@ -262,17 +263,17 @@ private int setProbeData(RenderManager rm, int lastTexUnit, Uniform lightProbeDa
}

@Override
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) {
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) {
int nbRenderedLights = 0;
Renderer renderer = renderManager.getRenderer();
int batchSize = renderManager.getSinglePassLightBatchSize();
if (lights.size() == 0) {
updateLightListUniforms(shader, geometry, lights,batchSize, renderManager, 0, lastTexUnit);
updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, 0, lastBindUnits.textureUnit);
renderer.setShader(shader);
renderMeshFromGeometry(renderer, geometry);
} else {
while (nbRenderedLights < lights.size()) {
nbRenderedLights = updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, nbRenderedLights, lastTexUnit);
nbRenderedLights = updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, nbRenderedLights, lastBindUnits.textureUnit);
renderer.setShader(shader);
renderMeshFromGeometry(renderer, geometry);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2021 jMonkeyEngine
* Copyright (c) 2009-2024 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -40,6 +40,7 @@
import com.jme3.material.RenderState;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.material.TechniqueDef;
import com.jme3.material.Material.BindUnits;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.math.Vector4f;
Expand Down Expand Up @@ -206,7 +207,7 @@ protected int updateLightListUniforms(Shader shader, Geometry g, LightList light
}

@Override
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) {
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) {
int nbRenderedLights = 0;
Renderer renderer = renderManager.getRenderer();
int batchSize = renderManager.getSinglePassLightBatchSize();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2021 jMonkeyEngine
* Copyright (c) 2009-2024 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -38,6 +38,7 @@
import com.jme3.light.PointLight;
import com.jme3.light.SpotLight;
import com.jme3.material.TechniqueDef;
import com.jme3.material.Material.BindUnits;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Matrix4f;
import com.jme3.math.Vector3f;
Expand Down Expand Up @@ -171,7 +172,7 @@ private void updateLightListUniforms(Matrix4f viewMatrix, Shader shader, LightLi
}

@Override
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) {
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) {
Renderer renderer = renderManager.getRenderer();
Matrix4f viewMatrix = renderManager.getCurrentCamera().getViewMatrix();
updateLightListUniforms(viewMatrix, shader, lights);
Expand Down
Loading

0 comments on commit 0b40bba

Please sign in to comment.