* Added shader validation system. Requires either NVIDIA Cg or GPU Shader Analyser to be in the path. Run the ShaderCheck class to see which jME3 shaders fail validation.
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9316 75d07b2b-3a1a-0410-a2c5-0572b91ccdca3.0
parent
5d37b914e1
commit
ad01d36915
@ -0,0 +1,112 @@ |
|||||||
|
package jme3tools.shadercheck; |
||||||
|
|
||||||
|
import com.jme3.shader.Shader; |
||||||
|
import com.jme3.shader.Shader.ShaderSource; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.OutputStreamWriter; |
||||||
|
import java.util.Scanner; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
public class CgcValidator implements Validator { |
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(CgcValidator.class.getName()); |
||||||
|
private static String version; |
||||||
|
|
||||||
|
private static String checkCgCompilerVersion(){ |
||||||
|
try { |
||||||
|
ProcessBuilder pb = new ProcessBuilder("cgc", "--version"); |
||||||
|
Process p = pb.start(); |
||||||
|
|
||||||
|
Scanner scan = new Scanner(p.getErrorStream()); |
||||||
|
String ln = scan.nextLine(); |
||||||
|
scan.close(); |
||||||
|
|
||||||
|
p.waitFor(); |
||||||
|
|
||||||
|
String versionNumber = ln.split("\\s")[2]; |
||||||
|
return versionNumber.substring(0, versionNumber.length()-1); |
||||||
|
} catch (IOException ex) { |
||||||
|
logger.log(Level.SEVERE, "IOEx", ex); |
||||||
|
} catch (InterruptedException ex){ |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public String getName() { |
||||||
|
return "NVIDIA Cg Toolkit"; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isInstalled() { |
||||||
|
return getInstalledVersion() != null; |
||||||
|
} |
||||||
|
|
||||||
|
public String getInstalledVersion() { |
||||||
|
if (version == null){ |
||||||
|
version = checkCgCompilerVersion(); |
||||||
|
} |
||||||
|
return version; |
||||||
|
} |
||||||
|
|
||||||
|
private static void executeCg(String sourceCode, String language, String defines, String profile, StringBuilder output){ |
||||||
|
try { |
||||||
|
ProcessBuilder pb = new ProcessBuilder("cgc", "-oglsl", |
||||||
|
"-nocode", |
||||||
|
"-strict", |
||||||
|
"-glslWerror", |
||||||
|
"-profile", profile, |
||||||
|
//"-po", "NumMathInstructionSlots=64",// math instruction slots
|
||||||
|
//"-po", "MaxTexIndirections=4", // texture indirections
|
||||||
|
"-po", "NumTemps=32", // temporary variables
|
||||||
|
//"-po", "NumInstructionSlots=1", // total instruction slots
|
||||||
|
//"-po", "NumTexInstructionSlots=32",// texture instruction slots
|
||||||
|
"-po", "MaxLocalParams=32"); // local parameters
|
||||||
|
|
||||||
|
|
||||||
|
Process p = pb.start(); |
||||||
|
|
||||||
|
String glslVer = language.substring(4); |
||||||
|
|
||||||
|
OutputStreamWriter writer = new OutputStreamWriter(p.getOutputStream()); |
||||||
|
writer.append("#version ").append(glslVer).append('\n'); |
||||||
|
writer.append("#extension all : warn").append('\n'); |
||||||
|
writer.append(defines).append('\n'); |
||||||
|
writer.write(sourceCode); |
||||||
|
writer.close(); |
||||||
|
|
||||||
|
Scanner scan = new Scanner(p.getErrorStream()); |
||||||
|
String ln = scan.nextLine(); |
||||||
|
if (ln.contains("0 errors")){ |
||||||
|
output.append(" - Success!").append('\n'); |
||||||
|
}else{ |
||||||
|
output.append(" - Failure!").append('\n'); |
||||||
|
output.append(ln).append('\n'); |
||||||
|
while (scan.hasNextLine()){ |
||||||
|
output.append(scan.nextLine()).append('\n'); |
||||||
|
} |
||||||
|
} |
||||||
|
scan.close(); |
||||||
|
|
||||||
|
p.waitFor(); |
||||||
|
} catch (IOException ex) { |
||||||
|
logger.log(Level.SEVERE, "IOEx", ex); |
||||||
|
} catch (InterruptedException ex){ |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void validate(Shader shader, StringBuilder results) { |
||||||
|
String language = shader.getLanguage(); |
||||||
|
for (ShaderSource source : shader.getSources()){ |
||||||
|
results.append("Checking: ").append(source.getName()); |
||||||
|
switch (source.getType()){ |
||||||
|
case Fragment: |
||||||
|
executeCg(source.getSource(), language, source.getDefines(), "arbfp1", results); |
||||||
|
break; |
||||||
|
case Vertex: |
||||||
|
executeCg(source.getSource(), language, source.getDefines(), "arbvp1", results); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,122 @@ |
|||||||
|
package jme3tools.shadercheck; |
||||||
|
|
||||||
|
import com.jme3.shader.Shader; |
||||||
|
import com.jme3.shader.Shader.ShaderSource; |
||||||
|
import java.io.File; |
||||||
|
import java.io.FileWriter; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.Scanner; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* Shader validator implementation for AMD's GPUShaderAnalyser. |
||||||
|
* |
||||||
|
* @author Kirill Vainer |
||||||
|
*/ |
||||||
|
public class GpuAnalyzerValidator implements Validator { |
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(CgcValidator.class.getName()); |
||||||
|
private static String version; |
||||||
|
|
||||||
|
private static String checkGpuAnalyzerVersion(){ |
||||||
|
try { |
||||||
|
ProcessBuilder pb = new ProcessBuilder("GPUShaderAnalyzer", "-ListModules"); |
||||||
|
Process p = pb.start(); |
||||||
|
|
||||||
|
Scanner scan = new Scanner(p.getInputStream()); |
||||||
|
String ln = scan.nextLine(); |
||||||
|
scan.close(); |
||||||
|
|
||||||
|
p.destroy(); |
||||||
|
|
||||||
|
return ln; |
||||||
|
} catch (IOException ex) { |
||||||
|
logger.log(Level.SEVERE, "IOEx", ex); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public String getName() { |
||||||
|
return "AMD GPU Shader Analyzer"; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isInstalled() { |
||||||
|
return getInstalledVersion() != null; |
||||||
|
} |
||||||
|
|
||||||
|
public String getInstalledVersion() { |
||||||
|
if (version == null){ |
||||||
|
version = checkGpuAnalyzerVersion(); |
||||||
|
} |
||||||
|
return version; |
||||||
|
} |
||||||
|
private static void executeAnalyzer(String sourceCode, String language, String defines, String asic, StringBuilder results){ |
||||||
|
try { |
||||||
|
// Export sourcecode to temporary file
|
||||||
|
File tempFile = File.createTempFile("test_shader", ".glsl"); |
||||||
|
FileWriter writer = new FileWriter(tempFile); |
||||||
|
|
||||||
|
String glslVer = language.substring(4); |
||||||
|
writer.append("#version ").append(glslVer).append('\n'); |
||||||
|
writer.append("#extension all : warn").append('\n'); |
||||||
|
writer.append(defines).append('\n'); |
||||||
|
writer.write(sourceCode); |
||||||
|
writer.close(); |
||||||
|
|
||||||
|
ProcessBuilder pb = new ProcessBuilder("GPUShaderAnalyzer", |
||||||
|
tempFile.getAbsolutePath(), |
||||||
|
"-I", |
||||||
|
"-ASIC", asic); |
||||||
|
|
||||||
|
Process p = pb.start(); |
||||||
|
|
||||||
|
Scanner scan = new Scanner(p.getInputStream()); |
||||||
|
|
||||||
|
if (!scan.hasNextLine()){ |
||||||
|
String x = scan.next(); |
||||||
|
System.out.println(x); |
||||||
|
} |
||||||
|
|
||||||
|
String ln = scan.nextLine(); |
||||||
|
|
||||||
|
if (ln.startsWith(";")){ |
||||||
|
results.append(" - Success!").append('\n'); |
||||||
|
}else{ |
||||||
|
results.append(" - Failure!").append('\n'); |
||||||
|
results.append(ln).append('\n'); |
||||||
|
while (scan.hasNextLine()){ |
||||||
|
results.append(scan.nextLine()).append('\n'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
scan.close(); |
||||||
|
p.getOutputStream().close(); |
||||||
|
p.getErrorStream().close(); |
||||||
|
|
||||||
|
p.waitFor(); |
||||||
|
p.destroy(); |
||||||
|
|
||||||
|
tempFile.delete(); |
||||||
|
} catch (InterruptedException ex) { |
||||||
|
} catch (IOException ex) { |
||||||
|
logger.log(Level.SEVERE, "IOEx", ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void validate(Shader shader, StringBuilder results) { |
||||||
|
String language = shader.getLanguage(); |
||||||
|
for (ShaderSource source : shader.getSources()){ |
||||||
|
results.append("Checking: ").append(source.getName()); |
||||||
|
switch (source.getType()){ |
||||||
|
case Fragment: |
||||||
|
executeAnalyzer(source.getSource(), language, source.getDefines(), "HD5770", results); |
||||||
|
break; |
||||||
|
case Vertex: |
||||||
|
executeAnalyzer(source.getSource(), language, source.getDefines(), "HD5770", results); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,97 @@ |
|||||||
|
package jme3tools.shadercheck; |
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager; |
||||||
|
import com.jme3.asset.plugins.ClasspathLocator; |
||||||
|
import com.jme3.asset.plugins.FileLocator; |
||||||
|
import com.jme3.material.MaterialDef; |
||||||
|
import com.jme3.material.TechniqueDef; |
||||||
|
import com.jme3.material.plugins.J3MLoader; |
||||||
|
import com.jme3.shader.DefineList; |
||||||
|
import com.jme3.shader.Shader; |
||||||
|
import com.jme3.shader.ShaderKey; |
||||||
|
import com.jme3.shader.plugins.GLSLLoader; |
||||||
|
import com.jme3.system.JmeSystem; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
public class ShaderCheck { |
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(ShaderCheck.class.getName()); |
||||||
|
private static AssetManager assetManager; |
||||||
|
|
||||||
|
private static Validator[] validators = new Validator[]{ |
||||||
|
new CgcValidator(), |
||||||
|
// new GpuAnalyzerValidator()
|
||||||
|
}; |
||||||
|
|
||||||
|
private static void initAssetManager(){ |
||||||
|
assetManager = JmeSystem.newAssetManager(); |
||||||
|
assetManager.registerLocator(".", FileLocator.class); |
||||||
|
assetManager.registerLocator("/", ClasspathLocator.class); |
||||||
|
assetManager.registerLoader(J3MLoader.class, "j3m"); |
||||||
|
assetManager.registerLoader(J3MLoader.class, "j3md"); |
||||||
|
assetManager.registerLoader(GLSLLoader.class, "vert", "frag", "glsllib"); |
||||||
|
} |
||||||
|
|
||||||
|
private static void checkMatDef(String matdefName){ |
||||||
|
MaterialDef def = (MaterialDef) assetManager.loadAsset(matdefName); |
||||||
|
for (TechniqueDef techDef : def.getDefaultTechniques()){ |
||||||
|
if (techDef.isUsingShaders()){ |
||||||
|
DefineList dl = new DefineList(); |
||||||
|
dl.addFrom(techDef.getShaderPresetDefines()); |
||||||
|
ShaderKey shaderKey = new ShaderKey(techDef.getVertexShaderName(), |
||||||
|
techDef.getFragmentShaderName(), |
||||||
|
dl, |
||||||
|
techDef.getShaderLanguage()); |
||||||
|
Shader shader = assetManager.loadShader(shaderKey); |
||||||
|
|
||||||
|
for (Validator validator : validators){ |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
validator.validate(shader, sb); |
||||||
|
System.out.println("==== Validator: " + validator.getName() + " " + |
||||||
|
validator.getInstalledVersion() + " ===="); |
||||||
|
System.out.println(sb.toString()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void main(String[] args){ |
||||||
|
Logger.getLogger(MaterialDef.class.getName()).setLevel(Level.OFF); |
||||||
|
initAssetManager(); |
||||||
|
checkMatDef("Common/MatDefs/Blur/HGaussianBlur.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Blur/RadialBlur.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Blur/VGaussianBlur.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Gui/Gui.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Hdr/LogLum.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Hdr/ToneMap.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Light/Lighting.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Misc/ColoredTextured.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Misc/Particle.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Misc/ShowNormals.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Misc/Sky.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Misc/Unshaded.j3md"); |
||||||
|
|
||||||
|
checkMatDef("Common/MatDefs/Post/BloomExtract.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Post/BloomFinal.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Post/CartoonEdge.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Post/CrossHatch.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Post/DepthOfField.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Post/FXAA.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Post/Fade.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Post/Fog.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Post/GammaCorrection.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Post/LightScattering.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Post/Overlay.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Post/Posterization.j3md"); |
||||||
|
|
||||||
|
checkMatDef("Common/MatDefs/SSAO/ssao.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/SSAO/ssaoBlur.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Shadow/PostShadow.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Shadow/PostShadowPSSM.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Shadow/PreShadow.j3md"); |
||||||
|
|
||||||
|
checkMatDef("Common/MatDefs/Water/SimpleWater.j3md"); |
||||||
|
checkMatDef("Common/MatDefs/Water/Water.j3md"); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
package jme3tools.shadercheck; |
||||||
|
|
||||||
|
import com.jme3.shader.Shader; |
||||||
|
|
||||||
|
/** |
||||||
|
* Interface for shader validator tools. |
||||||
|
*/ |
||||||
|
public interface Validator { |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the name of the validation tool |
||||||
|
*/ |
||||||
|
public String getName(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns true if the tool is installed on the system, false otherwise. |
||||||
|
*/ |
||||||
|
public boolean isInstalled(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the tool version as a string, must return null if the tool |
||||||
|
* is not installed. |
||||||
|
*/ |
||||||
|
public String getInstalledVersion(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Validates the given shader to make sure it follows all requirements |
||||||
|
* of the shader language specified as {@link Shader#getLanguage() }. |
||||||
|
* The results of the validation will be written into the |
||||||
|
* results argument. |
||||||
|
* |
||||||
|
* @param shader The shader to validate |
||||||
|
* @param results The storage for the validation results |
||||||
|
*/ |
||||||
|
public void validate(Shader shader, StringBuilder results); |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue