ShaderNodes : generated shaders are now cached by the assetManager to avoid generating a new shader for already loaded materials. This saves memory and avoids a lot of shader switches at render time.

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10575 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
rem..om 12 years ago
parent 77a3cba69e
commit 4f3319f049
  1. 2
      engine/src/core-plugins/com/jme3/material/plugins/J3MLoader.java
  2. 27
      engine/src/core/com/jme3/asset/DesktopAssetManager.java
  3. 13
      engine/src/core/com/jme3/material/Technique.java
  4. 20
      engine/src/core/com/jme3/shader/ShaderGenerator.java
  5. 11
      engine/src/core/com/jme3/shader/ShaderKey.java

@ -448,6 +448,8 @@ public class J3MLoader implements AssetLoader {
if(isUseNodes){ if(isUseNodes){
nodesLoaderDelegate.computeConditions(); nodesLoaderDelegate.computeConditions();
//used for caching later, the shader here is not a file.
technique.setShaderFile(technique.hashCode() + "", technique.hashCode() + "", "GLSL100", "GLSL100");
} }
if (vertName != null && fragName != null){ if (vertName != null && fragName != null){

@ -398,16 +398,23 @@ public class DesktopAssetManager implements AssetManager {
AssetCache cache = handler.getCache(SimpleAssetCache.class); AssetCache cache = handler.getCache(SimpleAssetCache.class);
Shader shader = (Shader) cache.getFromCache(key); Shader shader = (Shader) cache.getFromCache(key);
if (shader == null){ if (shader == null){
String vertName = key.getVertName(); if (key.isUsesShaderNodes()) {
String fragName = key.getFragName(); if(shaderGenerator == null){
throw new UnsupportedOperationException("ShaderGenerator was not initialized, make sure assetManager.getGenerator(caps) has been called");
String vertSource = (String) loadAsset(new AssetKey(vertName)); }
String fragSource = (String) loadAsset(new AssetKey(fragName)); shader = shaderGenerator.generateShader();
} else {
shader = new Shader(); String vertName = key.getVertName();
shader.initialize(); String fragName = key.getFragName();
shader.addSource(Shader.ShaderType.Vertex, vertName, vertSource, key.getDefines().getCompiled(), key.getVertexShaderLanguage());
shader.addSource(Shader.ShaderType.Fragment, fragName, fragSource, key.getDefines().getCompiled(), key.getFragmentShaderLanguage()); String vertSource = (String) loadAsset(new AssetKey(vertName));
String fragSource = (String) loadAsset(new AssetKey(fragName));
shader = new Shader();
shader.initialize();
shader.addSource(Shader.ShaderType.Vertex, vertName, vertSource, key.getDefines().getCompiled(), key.getVertexShaderLanguage());
shader.addSource(Shader.ShaderType.Fragment, fragName, fragSource, key.getDefines().getCompiled(), key.getFragmentShaderLanguage());
}
cache.addToCache(key, shader); cache.addToCache(key, shader);
} }

@ -204,17 +204,18 @@ public class Technique /* implements Savable */ {
private void loadShader(AssetManager manager,EnumSet<Caps> rendererCaps) { private void loadShader(AssetManager manager,EnumSet<Caps> rendererCaps) {
if (getDef().isUsingShaderNodes()) { ShaderKey key = new ShaderKey(def.getVertexShaderName(),
shader = manager.getShaderGenerator(rendererCaps).generateShader(this);
} else {
ShaderKey key = new ShaderKey(def.getVertexShaderName(),
def.getFragmentShaderName(), def.getFragmentShaderName(),
getAllDefines(), getAllDefines(),
def.getVertexShaderLanguage(), def.getVertexShaderLanguage(),
def.getFragmentShaderLanguage()); def.getFragmentShaderLanguage());
shader = manager.loadShader(key);
} if (getDef().isUsingShaderNodes()) {
manager.getShaderGenerator(rendererCaps).initialize(this);
key.setUsesShaderNodes(true);
}
shader = manager.loadShader(key);
// register the world bound uniforms // register the world bound uniforms
worldBindUniforms.clear(); worldBindUniforms.clear();
if (def.getWorldBindings() != null) { if (def.getWorldBindings() != null) {

@ -52,6 +52,8 @@ public abstract class ShaderGenerator {
protected AssetManager assetManager; protected AssetManager assetManager;
//indentation value for generation //indentation value for generation
protected int indent; protected int indent;
//the technique to use for the shader generation
protected Technique technique = null;
/** /**
* Build a shaderGenerator * Build a shaderGenerator
@ -59,16 +61,23 @@ public abstract class ShaderGenerator {
* @param assetManager * @param assetManager
*/ */
protected ShaderGenerator(AssetManager assetManager) { protected ShaderGenerator(AssetManager assetManager) {
this.assetManager = assetManager; this.assetManager = assetManager;
} }
public void initialize(Technique technique){
this.technique = technique;
}
/** /**
* Generate vertex and fragment shaders for the given technique * Generate vertex and fragment shaders for the given technique
* *
* @param technique the technique to use to generate the shaders * @param technique the technique to use to generate the shaders
* @return a Shader program * @return a Shader program
*/ */
public Shader generateShader(Technique technique) { public Shader generateShader() {
if(technique == null){
throw new UnsupportedOperationException("The shaderGenerator was not properly initialized, call initialize(Technique) before any generation");
}
DefineList defines = technique.getAllDefines(); DefineList defines = technique.getAllDefines();
TechniqueDef def = technique.getDef(); TechniqueDef def = technique.getDef();
@ -81,7 +90,8 @@ public abstract class ShaderGenerator {
shader.initialize(); shader.initialize();
shader.addSource(Shader.ShaderType.Vertex, technique.getDef().getName() + ".vert", vertexSource, defines.getCompiled(), getLanguageAndVersion(ShaderType.Vertex)); shader.addSource(Shader.ShaderType.Vertex, technique.getDef().getName() + ".vert", vertexSource, defines.getCompiled(), getLanguageAndVersion(ShaderType.Vertex));
shader.addSource(Shader.ShaderType.Fragment, technique.getDef().getName() + ".frag", fragmentSource, defines.getCompiled(), getLanguageAndVersion(ShaderType.Fragment)); shader.addSource(Shader.ShaderType.Fragment, technique.getDef().getName() + ".frag", fragmentSource, defines.getCompiled(), getLanguageAndVersion(ShaderType.Fragment));
technique = null;
return shader; return shader;
} }
@ -286,5 +296,5 @@ public abstract class ShaderGenerator {
} }
} }
return index; return index;
} }
} }

@ -45,6 +45,7 @@ public class ShaderKey extends AssetKey<Shader> {
protected String vertLanguage; protected String vertLanguage;
protected String fragLanguage; protected String fragLanguage;
protected int cachedHashedCode = 0; protected int cachedHashedCode = 0;
protected boolean usesShaderNodes = false;
public ShaderKey(){ public ShaderKey(){
} }
@ -56,7 +57,7 @@ public class ShaderKey extends AssetKey<Shader> {
this.vertLanguage = vertLanguage; this.vertLanguage = vertLanguage;
this.fragLanguage = fragLanguage; this.fragLanguage = fragLanguage;
} }
@Override @Override
public ShaderKey clone() { public ShaderKey clone() {
ShaderKey clone = (ShaderKey) super.clone(); ShaderKey clone = (ShaderKey) super.clone();
@ -125,6 +126,14 @@ public class ShaderKey extends AssetKey<Shader> {
return fragLanguage; return fragLanguage;
} }
public boolean isUsesShaderNodes() {
return usesShaderNodes;
}
public void setUsesShaderNodes(boolean usesShaderNodes) {
this.usesShaderNodes = usesShaderNodes;
}
@Override @Override
public void write(JmeExporter ex) throws IOException{ public void write(JmeExporter ex) throws IOException{
super.write(ex); super.write(ex);

Loading…
Cancel
Save