From 4f3319f0494951c7c4fa3369a19c1db3dadfb077 Mon Sep 17 00:00:00 2001 From: "rem..om" Date: Thu, 25 Apr 2013 21:01:26 +0000 Subject: [PATCH] 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 --- .../com/jme3/material/plugins/J3MLoader.java | 2 ++ .../com/jme3/asset/DesktopAssetManager.java | 27 ++++++++++++------- .../src/core/com/jme3/material/Technique.java | 13 ++++----- .../core/com/jme3/shader/ShaderGenerator.java | 20 ++++++++++---- .../src/core/com/jme3/shader/ShaderKey.java | 11 +++++++- 5 files changed, 51 insertions(+), 22 deletions(-) diff --git a/engine/src/core-plugins/com/jme3/material/plugins/J3MLoader.java b/engine/src/core-plugins/com/jme3/material/plugins/J3MLoader.java index 5ad0953e5..4adb5a692 100644 --- a/engine/src/core-plugins/com/jme3/material/plugins/J3MLoader.java +++ b/engine/src/core-plugins/com/jme3/material/plugins/J3MLoader.java @@ -448,6 +448,8 @@ public class J3MLoader implements AssetLoader { if(isUseNodes){ 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){ diff --git a/engine/src/core/com/jme3/asset/DesktopAssetManager.java b/engine/src/core/com/jme3/asset/DesktopAssetManager.java index f2f3a7852..083f85e25 100644 --- a/engine/src/core/com/jme3/asset/DesktopAssetManager.java +++ b/engine/src/core/com/jme3/asset/DesktopAssetManager.java @@ -398,16 +398,23 @@ public class DesktopAssetManager implements AssetManager { AssetCache cache = handler.getCache(SimpleAssetCache.class); Shader shader = (Shader) cache.getFromCache(key); if (shader == null){ - String vertName = key.getVertName(); - String fragName = key.getFragName(); - - 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()); + if (key.isUsesShaderNodes()) { + if(shaderGenerator == null){ + throw new UnsupportedOperationException("ShaderGenerator was not initialized, make sure assetManager.getGenerator(caps) has been called"); + } + shader = shaderGenerator.generateShader(); + } else { + String vertName = key.getVertName(); + String fragName = key.getFragName(); + + 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); } diff --git a/engine/src/core/com/jme3/material/Technique.java b/engine/src/core/com/jme3/material/Technique.java index ad9f76ec7..945db95d9 100644 --- a/engine/src/core/com/jme3/material/Technique.java +++ b/engine/src/core/com/jme3/material/Technique.java @@ -204,17 +204,18 @@ public class Technique /* implements Savable */ { private void loadShader(AssetManager manager,EnumSet rendererCaps) { - if (getDef().isUsingShaderNodes()) { - shader = manager.getShaderGenerator(rendererCaps).generateShader(this); - } else { - ShaderKey key = new ShaderKey(def.getVertexShaderName(), + ShaderKey key = new ShaderKey(def.getVertexShaderName(), def.getFragmentShaderName(), getAllDefines(), def.getVertexShaderLanguage(), 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 worldBindUniforms.clear(); if (def.getWorldBindings() != null) { diff --git a/engine/src/core/com/jme3/shader/ShaderGenerator.java b/engine/src/core/com/jme3/shader/ShaderGenerator.java index ce509dba1..e26765f77 100644 --- a/engine/src/core/com/jme3/shader/ShaderGenerator.java +++ b/engine/src/core/com/jme3/shader/ShaderGenerator.java @@ -52,6 +52,8 @@ public abstract class ShaderGenerator { protected AssetManager assetManager; //indentation value for generation protected int indent; + //the technique to use for the shader generation + protected Technique technique = null; /** * Build a shaderGenerator @@ -59,16 +61,23 @@ public abstract class ShaderGenerator { * @param 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 * * @param technique the technique to use to generate the shaders * @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(); TechniqueDef def = technique.getDef(); @@ -81,7 +90,8 @@ public abstract class ShaderGenerator { shader.initialize(); 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)); - + + technique = null; return shader; } @@ -286,5 +296,5 @@ public abstract class ShaderGenerator { } } return index; - } + } } diff --git a/engine/src/core/com/jme3/shader/ShaderKey.java b/engine/src/core/com/jme3/shader/ShaderKey.java index b758bb91c..f6cb81508 100644 --- a/engine/src/core/com/jme3/shader/ShaderKey.java +++ b/engine/src/core/com/jme3/shader/ShaderKey.java @@ -45,6 +45,7 @@ public class ShaderKey extends AssetKey { protected String vertLanguage; protected String fragLanguage; protected int cachedHashedCode = 0; + protected boolean usesShaderNodes = false; public ShaderKey(){ } @@ -56,7 +57,7 @@ public class ShaderKey extends AssetKey { this.vertLanguage = vertLanguage; this.fragLanguage = fragLanguage; } - + @Override public ShaderKey clone() { ShaderKey clone = (ShaderKey) super.clone(); @@ -125,6 +126,14 @@ public class ShaderKey extends AssetKey { return fragLanguage; } + public boolean isUsesShaderNodes() { + return usesShaderNodes; + } + + public void setUsesShaderNodes(boolean usesShaderNodes) { + this.usesShaderNodes = usesShaderNodes; + } + @Override public void write(JmeExporter ex) throws IOException{ super.write(ex);