* 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-0572b91ccdca
This commit is contained in:
parent
5d37b914e1
commit
ad01d36915
112
engine/src/tools/jme3tools/shadercheck/CgcValidator.java
Normal file
112
engine/src/tools/jme3tools/shadercheck/CgcValidator.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
122
engine/src/tools/jme3tools/shadercheck/GpuAnalyzerValidator.java
Normal file
122
engine/src/tools/jme3tools/shadercheck/GpuAnalyzerValidator.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
97
engine/src/tools/jme3tools/shadercheck/ShaderCheck.java
Normal file
97
engine/src/tools/jme3tools/shadercheck/ShaderCheck.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
37
engine/src/tools/jme3tools/shadercheck/Validator.java
Normal file
37
engine/src/tools/jme3tools/shadercheck/Validator.java
Normal file
@ -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…
x
Reference in New Issue
Block a user