* Shader now stores shader language in the ShaderSources instead of the Shader itself (everything makes a lot more sense now).

^ Make sure your shader languages are appropriate for each shader type (vert / frag) in your J3MS!
 * Shaders no longer have the "usable" member and the renderers don't use it either (its useless)

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9545 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
Sha..rd 13 years ago
parent af7435ffdf
commit 55d75c5abc
  1. 126
      engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java
  2. 7
      engine/src/core-effects/Common/MatDefs/Post/BloomFinal.j3md
  3. 48
      engine/src/core/com/jme3/asset/DesktopAssetManager.java
  4. 13
      engine/src/core/com/jme3/material/Technique.java
  5. 68
      engine/src/core/com/jme3/material/TechniqueDef.java
  6. 287
      engine/src/core/com/jme3/shader/Shader.java
  7. 27
      engine/src/core/com/jme3/shader/ShaderKey.java
  8. 17
      engine/src/core/com/jme3/shader/ShaderVariable.java
  9. 130
      engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglRenderer.java

@ -590,6 +590,18 @@ public class OGLESShaderRenderer implements Renderer {
}
}
protected void bindProgram(Shader shader) {
int shaderId = shader.getId();
if (context.boundShaderProgram != shaderId) {
GLES20.glUseProgram(shaderId);
statistics.onShaderUse(shader, true);
boundShader = shader;
context.boundShaderProgram = shaderId;
} else {
statistics.onShaderUse(shader, false);
}
}
protected void updateUniform(Shader shader, Uniform uniform) {
int shaderId = shader.getId();
@ -698,7 +710,6 @@ public class OGLESShaderRenderer implements Renderer {
protected void updateShaderUniforms(Shader shader) {
ListMap<String, Uniform> uniforms = shader.getUniformMap();
// for (Uniform uniform : shader.getUniforms()){
for (int i = 0; i < uniforms.size(); i++) {
Uniform uniform = uniforms.getValue(i);
if (uniform.isUpdateNeeded()) {
@ -709,7 +720,6 @@ public class OGLESShaderRenderer implements Renderer {
protected void resetUniformLocations(Shader shader) {
ListMap<String, Uniform> uniforms = shader.getUniformMap();
// for (Uniform uniform : shader.getUniforms()){
for (int i = 0; i < uniforms.size(); i++) {
Uniform uniform = uniforms.getValue(i);
uniform.reset(); // e.g check location again
@ -736,10 +746,10 @@ public class OGLESShaderRenderer implements Renderer {
}
}
public void updateShaderSourceData(ShaderSource source, String language) {
public void updateShaderSourceData(ShaderSource source) {
int id = source.getId();
if (id == -1) {
// create id
// Create id
id = GLES20.glCreateShader(convertShaderType(source.getType()));
if (id <= 0) {
throw new RendererException("Invalid ID received when trying to create shader.");
@ -747,16 +757,17 @@ public class OGLESShaderRenderer implements Renderer {
source.setId(id);
}
if (!source.getLanguage().equals("GLSL100")) {
throw new RendererException("This shader cannot run in OpenGL ES. "
+ "Only GLSL 1.0 shaders are supported.");
}
// upload shader source
// merge the defines and source code
byte[] versionData = new byte[]{};//"#version 140\n".getBytes();
// versionData = "#define INSTANCING 1\n".getBytes();
byte[] definesCodeData = source.getDefines().getBytes();
byte[] sourceCodeData = source.getSource().getBytes();
ByteBuffer codeBuf = BufferUtils.createByteBuffer(versionData.length
+ definesCodeData.length
ByteBuffer codeBuf = BufferUtils.createByteBuffer(definesCodeData.length
+ sourceCodeData.length);
codeBuf.put(versionData);
codeBuf.put(definesCodeData);
codeBuf.put(sourceCodeData);
codeBuf.flip();
@ -791,10 +802,11 @@ public class OGLESShaderRenderer implements Renderer {
if (compiledOK) {
if (infoLog != null) {
logger.log(Level.INFO, "compile success: " + source.getName() + ", " + infoLog);
logger.log(Level.INFO, "compile success: {0}, {1}", new Object[]{source.getName(), infoLog});
} else {
logger.log(Level.FINE, "compile success: " + source.getName());
logger.log(Level.FINE, "compile success: {0}", source.getName());
}
source.clearUpdateNeeded();
} else {
logger.log(Level.WARNING, "Bad compile of:\n{0}",
new Object[]{ShaderDebug.formatShaderSource(source.getDefines(), source.getSource(),stringBuf.toString())});
@ -804,18 +816,6 @@ public class OGLESShaderRenderer implements Renderer {
throw new RendererException("compile error in:" + source + " error: <not provided>");
}
}
source.clearUpdateNeeded();
// only usable if compiled
source.setUsable(compiledOK);
if (!compiledOK) {
// make sure to dispose id cause all program's
// shaders will be cleared later.
GLES20.glDeleteShader(id);
} else {
// register for cleanup since the ID is usable
objManager.registerForCleanup(source);
}
}
public void updateShaderData(Shader shader) {
@ -835,15 +835,7 @@ public class OGLESShaderRenderer implements Renderer {
for (ShaderSource source : shader.getSources()) {
if (source.isUpdateNeeded()) {
updateShaderSourceData(source, shader.getLanguage());
// shader has been compiled here
}
if (!source.isUsable()) {
// it's useless.. just forget about everything..
shader.setUsable(false);
shader.clearUpdateNeeded();
return;
updateShaderSourceData(source);
}
GLES20.glAttachShader(id, source.getId());
}
@ -871,41 +863,27 @@ public class OGLESShaderRenderer implements Renderer {
} else {
logger.fine("shader link success");
}
} else {
if (infoLog != null) {
throw new RendererException("Shader link failure, shader:" + shader + " info:" + infoLog);
} else {
throw new RendererException("Shader link failure, shader:" + shader + " info: <not provided>");
}
}
shader.clearUpdateNeeded();
if (!linkOK) {
// failure.. forget about everything
shader.resetSources();
shader.setUsable(false);
deleteShader(shader);
} else {
shader.setUsable(true);
if (needRegister) {
// Register shader for clean up if it was created in this method.
objManager.registerForCleanup(shader);
statistics.onNewShader();
} else {
// OpenGL spec: uniform locations may change after re-link
resetUniformLocations(shader);
}
} else {
if (infoLog != null) {
throw new RendererException("Shader link failure, shader:" + shader + " info:" + infoLog);
} else {
throw new RendererException("Shader link failure, shader:" + shader + " info: <not provided>");
}
}
}
public void setShader(Shader shader) {
if (shader == null) {
if (context.boundShaderProgram > 0) {
GLES20.glUseProgram(0);
statistics.onShaderUse(null, true);
context.boundShaderProgram = 0;
boundShader = null;
}
throw new IllegalArgumentException("Shader cannot be null");
} else {
if (shader.isUpdateNeeded()) {
updateShaderData(shader);
@ -913,37 +891,11 @@ public class OGLESShaderRenderer implements Renderer {
// NOTE: might want to check if any of the
// sources need an update?
if (!shader.isUsable()) {
logger.warning("shader is not usable.");
return;
}
assert shader.getId() > 0;
updateShaderUniforms(shader);
if (context.boundShaderProgram != shader.getId()) {
if (VALIDATE_SHADER) {
// check if shader can be used
// with current state
GLES20.glValidateProgram(shader.getId());
GLES20.glGetProgramiv(shader.getId(), GLES20.GL_VALIDATE_STATUS, intBuf1);
boolean validateOK = intBuf1.get(0) == GLES20.GL_TRUE;
if (validateOK) {
logger.fine("shader validate success");
} else {
logger.warning("shader validate failure");
}
}
GLES20.glUseProgram(shader.getId());
statistics.onShaderUse(shader, true);
context.boundShaderProgram = shader.getId();
boundShader = shader;
} else {
statistics.onShaderUse(shader, false);
}
bindProgram(shader);
}
}
@ -952,9 +904,8 @@ public class OGLESShaderRenderer implements Renderer {
logger.warning("Shader source is not uploaded to GPU, cannot delete.");
return;
}
source.setUsable(false);
source.clearUpdateNeeded();
source.clearUpdateNeeded();
GLES20.glDeleteShader(source.getId());
source.resetObject();
}
@ -964,20 +915,17 @@ public class OGLESShaderRenderer implements Renderer {
logger.warning("Shader is not uploaded to GPU, cannot delete.");
return;
}
for (ShaderSource source : shader.getSources()) {
if (source.getId() != -1) {
GLES20.glDetachShader(shader.getId(), source.getId());
// the next part is done by the GLObjectManager automatically
// glDeleteShader(source.getId());
deleteShaderSource(source);
}
}
// kill all references so sources can be collected
// if needed.
shader.resetSources();
GLES20.glDeleteProgram(shader.getId());
statistics.onDeleteShader();
shader.resetObject();
}
/*********************************************************************\

@ -8,7 +8,7 @@ MaterialDef Bloom Final {
}
Technique {
VertexShader GLSL100: Common/MatDefs/Post/Post15.vert
VertexShader GLSL150: Common/MatDefs/Post/Post15.vert
FragmentShader GLSL150: Common/MatDefs/Post/bloomFinal15.frag
WorldParameters {
@ -28,9 +28,4 @@ MaterialDef Bloom Final {
WorldViewProjectionMatrix
}
}
Technique FixedFunc {
}
}

@ -336,11 +336,6 @@ public class DesktopAssetManager implements AssetManager {
return loadAsset(new AssetKey(name));
}
/**
* Loads a texture.
*
* @return the texture
*/
public Texture loadTexture(TextureKey key){
return (Texture) loadAsset(key);
}
@ -365,18 +360,16 @@ public class DesktopAssetManager implements AssetManager {
return loadAudio(new AudioKey(name, false));
}
/**
* Loads a bitmap font with the given name.
*
* @param name
* @return the loaded {@link BitmapFont}
*/
public BitmapFont loadFont(String name){
return (BitmapFont) loadAsset(new AssetKey(name));
}
public InputStream loadGLSLLibrary(AssetKey key){
return (InputStream) loadAsset(key);
public Spatial loadModel(ModelKey key){
return (Spatial) loadAsset(key);
}
public Spatial loadModel(String name){
return loadModel(new ModelKey(name));
}
/**
@ -389,34 +382,21 @@ public class DesktopAssetManager implements AssetManager {
// cache abuse in method
// that doesn't use loaders/locators
AssetCache cache = handler.getCache(SimpleAssetCache.class);
Shader s = (Shader) cache.getFromCache(key);
if (s == null){
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));
s = new Shader(key.getLanguage());
s.addSource(Shader.ShaderType.Vertex, vertName, vertSource, key.getDefines().getCompiled());
s.addSource(Shader.ShaderType.Fragment, fragName, fragSource, key.getDefines().getCompiled());
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, s);
cache.addToCache(key, shader);
}
return s;
}
public Spatial loadModel(ModelKey key){
return (Spatial) loadAsset(key);
}
/**
* Load a model.
*
* @param name
* @return the loaded model
*/
public Spatial loadModel(String name){
return loadModel(new ModelKey(name));
return shader;
}
}

@ -32,9 +32,7 @@
package com.jme3.material;
import com.jme3.asset.AssetManager;
import com.jme3.export.*;
import com.jme3.shader.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@ -43,7 +41,7 @@ import java.util.logging.Logger;
/**
* Represents a technique instance.
*/
public class Technique implements Savable {
public class Technique /* implements Savable */ {
private static final Logger logger = Logger.getLogger(Technique.class.getName());
private TechniqueDef def;
@ -133,6 +131,10 @@ public class Technique implements Savable {
}
void updateUniformParam(String paramName, VarType type, Object value) {
if (paramName == null) {
throw new IllegalArgumentException();
}
Uniform u = shader.getUniform(paramName);
switch (type) {
case TextureBuffer:
@ -208,7 +210,8 @@ public class Technique implements Savable {
ShaderKey key = new ShaderKey(def.getVertexShaderName(),
def.getFragmentShaderName(),
allDefines,
def.getShaderLanguage());
def.getVertexShaderLanguage(),
def.getFragmentShaderLanguage());
shader = manager.loadShader(key);
// register the world bound uniforms
@ -225,6 +228,7 @@ public class Technique implements Savable {
needReload = false;
}
/*
public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this);
oc.write(def, "def", null);
@ -240,4 +244,5 @@ public class Technique implements Savable {
defines = (DefineList) ic.readSavable("defines", null);
shader = (Shader) ic.readSavable("shader", null);
}
*/
}

@ -51,6 +51,11 @@ import java.util.List;
*/
public class TechniqueDef implements Savable {
/**
* Version #1: Separate shader language for each shader source.
*/
public static final int SAVABLE_VERSION = 1;
/**
* Describes light rendering mode.
*/
@ -101,7 +106,9 @@ public class TechniqueDef implements Savable {
private String vertName;
private String fragName;
private String shaderLang;
private String vertLanguage;
private String fragLanguage;
private DefineList presetDefines;
private boolean usesShaders;
@ -227,13 +234,16 @@ public class TechniqueDef implements Savable {
* @param fragmentShader The name of the fragment shader
* @param shaderLanguage The shader language
*/
public void setShaderFile(String vertexShader, String fragmentShader, String shaderLanguage){
public void setShaderFile(String vertexShader, String fragmentShader, String vertLanguage, String fragLanguage){
this.vertName = vertexShader;
this.fragName = fragmentShader;
this.shaderLang = shaderLanguage;
this.vertLanguage = vertLanguage;
this.fragLanguage = fragLanguage;
Caps langCap = Caps.valueOf(shaderLanguage);
requiredCaps.add(langCap);
Caps vertCap = Caps.valueOf(vertLanguage);
requiredCaps.add(vertCap);
Caps fragCap = Caps.valueOf(fragLanguage);
requiredCaps.add(fragCap);
usesShaders = true;
}
@ -247,9 +257,9 @@ public class TechniqueDef implements Savable {
* @see #addShaderParamDefine(java.lang.String, java.lang.String)
*/
public String getShaderParamDefine(String paramName){
if (defineParams == null)
if (defineParams == null) {
return null;
}
return defineParams.get(paramName);
}
@ -266,9 +276,9 @@ public class TechniqueDef implements Savable {
* @param defineName The name of the define parameter, e.g. USE_LIGHTING
*/
public void addShaderParamDefine(String paramName, String defineName){
if (defineParams == null)
if (defineParams == null) {
defineParams = new HashMap<String, String>();
}
defineParams.put(paramName, defineName);
}
@ -297,9 +307,9 @@ public class TechniqueDef implements Savable {
* @param value The value of the define
*/
public void addShaderPresetDefine(String defineName, VarType type, Object value){
if (presetDefines == null)
if (presetDefines == null) {
presetDefines = new DefineList();
}
presetDefines.set(defineName, type, value);
}
@ -325,12 +335,25 @@ public class TechniqueDef implements Savable {
}
/**
* Returns the shader language of the shaders used in this technique.
*
* @return the shader language of the shaders used in this technique.
* @deprecated Use {@link #getVertexShaderLanguage() } instead.
*/
@Deprecated
public String getShaderLanguage() {
return shaderLang;
return vertLanguage;
}
/**
* Returns the language of the fragment shader used in this technique.
*/
public String getFragmentShaderLanguage() {
return fragLanguage;
}
/**
* Returns the language of the vertex shader used in this technique.
*/
public String getVertexShaderLanguage() {
return vertLanguage;
}
/**
@ -368,12 +391,14 @@ public class TechniqueDef implements Savable {
oc.write(name, "name", null);
oc.write(vertName, "vertName", null);
oc.write(fragName, "fragName", null);
oc.write(shaderLang, "shaderLang", null);
oc.write(vertLanguage, "vertLanguage", null);
oc.write(vertLanguage, "fragLanguage", null);
oc.write(presetDefines, "presetDefines", null);
oc.write(lightMode, "lightMode", LightMode.Disable);
oc.write(shadowMode, "shadowMode", ShadowMode.Disable);
oc.write(renderState, "renderState", null);
oc.write(usesShaders, "usesShaders", false);
// TODO: Finish this when Map<String, String> export is available
// oc.write(defineParams, "defineParams", null);
// TODO: Finish this when List<Enum> export is available
@ -385,12 +410,21 @@ public class TechniqueDef implements Savable {
name = ic.readString("name", null);
vertName = ic.readString("vertName", null);
fragName = ic.readString("fragName", null);
shaderLang = ic.readString("shaderLang", null);
presetDefines = (DefineList) ic.readSavable("presetDefines", null);
lightMode = ic.readEnum("lightMode", LightMode.class, LightMode.Disable);
shadowMode = ic.readEnum("shadowMode", ShadowMode.class, ShadowMode.Disable);
renderState = (RenderState) ic.readSavable("renderState", null);
usesShaders = ic.readBoolean("usesShaders", false);
if (ic.getSavableVersion(TechniqueDef.class) == 0) {
// Old version
vertLanguage = ic.readString("shaderLang", null);
fragLanguage = vertLanguage;
} else {
// New version
vertLanguage = ic.readString("vertLanguage", null);
fragLanguage = ic.readString("fragLanguage", null);;
}
}
}

@ -32,37 +32,33 @@
package com.jme3.shader;
import com.jme3.export.*;
import com.jme3.renderer.Renderer;
import com.jme3.scene.VertexBuffer;
import com.jme3.util.IntMap;
import com.jme3.util.IntMap.Entry;
import com.jme3.util.ListMap;
import com.jme3.util.NativeObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
public final class Shader extends NativeObject implements Savable {
private String language;
public final class Shader extends NativeObject {
/**
* True if the shader is fully compiled & linked.
* (e.g no GL error will be invoked if used).
*
* @deprecated shader language now specified per shader source. See
* {@link ShaderSource#setLanguage(String)
*/
private boolean usable = false;
@Deprecated
private String language;
/**
* A list of all shaders currently attached.
* A list of all shader sources currently attached.
*/
private ArrayList<ShaderSource> shaderList;
private ArrayList<ShaderSource> shaderSourceList;
/**
* Maps uniform name to the uniform variable.
*/
// private HashMap<String, Uniform> uniforms;
private ListMap<String, Uniform> uniforms;
/**
@ -94,50 +90,32 @@ public final class Shader extends NativeObject implements Savable {
* Shader source describes a shader object in OpenGL. Each shader source
* is assigned a certain pipeline which it controls (described by it's type).
*/
public static class ShaderSource extends NativeObject implements Savable {
ShaderType shaderType;
public static class ShaderSource extends NativeObject {
boolean usable = false;
String name = null;
String source = null;
String defines = null;
ShaderType sourceType;
String language;
String name;
String source;
String defines;
public ShaderSource(ShaderType type){
super(ShaderSource.class);
this.shaderType = type;
if (type == null)
this.sourceType = type;
if (type == null) {
throw new NullPointerException("The shader type must be specified");
}
}
protected ShaderSource(ShaderSource ss){
super(ShaderSource.class, ss.id);
this.shaderType = ss.shaderType;
usable = false;
name = ss.name;
// forget source & defines
// No data needs to be copied.
// (This is a destructable clone)
}
public ShaderSource(){
super(ShaderSource.class);
}
public void write(JmeExporter ex) throws IOException{
OutputCapsule oc = ex.getCapsule(this);
oc.write(shaderType, "shaderType", null);
oc.write(name, "name", null);
oc.write(source, "source", null);
oc.write(defines, "defines", null);
}
public void read(JmeImporter im) throws IOException{
InputCapsule ic = im.getCapsule(this);
shaderType = ic.readEnum("shaderType", ShaderType.class, null);
name = ic.readString("name", null);
source = ic.readString("source", null);
defines = ic.readString("defines", null);
}
public void setName(String name){
this.name = name;
}
@ -147,21 +125,33 @@ public final class Shader extends NativeObject implements Savable {
}
public ShaderType getType() {
return shaderType;
return sourceType;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
if (language == null) {
throw new NullPointerException("Shader language cannot be null");
}
this.language = language;
setUpdateNeeded();
}
public void setSource(String source){
if (source == null)
if (source == null) {
throw new NullPointerException("Shader source cannot be null");
}
this.source = source;
setUpdateNeeded();
}
public void setDefines(String defines){
if (defines == null)
if (defines == null) {
throw new NullPointerException("Shader defines cannot be null");
}
this.defines = defines;
setUpdateNeeded();
}
@ -174,14 +164,6 @@ public final class Shader extends NativeObject implements Savable {
return defines;
}
public boolean isUsable(){
return usable;
}
public void setUsable(boolean usable){
this.usable = usable;
}
@Override
public String toString(){
String nameTxt = "";
@ -192,12 +174,11 @@ public final class Shader extends NativeObject implements Savable {
return getClass().getSimpleName() + "["+nameTxt+"type="
+ shaderType.name()+"]";
+ sourceType.name()+", language=" + language + "]";
}
public void resetObject(){
id = -1;
usable = false;
setUpdateNeeded();
}
@ -211,110 +192,103 @@ public final class Shader extends NativeObject implements Savable {
}
/**
* Create an empty shader.
* @deprecated Shader sources are now associated with the shader
* language.
*/
@Deprecated
public Shader(String language){
super(Shader.class);
this.language = language;
shaderList = new ArrayList<ShaderSource>();
// uniforms = new HashMap<String, Uniform>();
initialize();
}
/**
* Initializes the shader for use, must be called after the
* constructor without arguments is used.
*/
public void initialize() {
shaderSourceList = new ArrayList<ShaderSource>();
uniforms = new ListMap<String, Uniform>();
attribs = new IntMap<Attribute>();
}
/**
* Do not use this constructor. Serialization purposes only.
* Creates a new shader, {@link #initialize() } must be called
* after this constructor for the shader to be usable.
*/
public Shader(){
super(Shader.class);
}
/**
* Do not use this constructor. Used for destructable clones only.
*/
protected Shader(Shader s){
super(Shader.class, s.id);
shaderList = new ArrayList<ShaderSource>();
//uniforms = new ListMap<String, Uniform>();
//attribs = new IntMap<Attribute>();
// NOTE: Because ShaderSources are registered separately with
// the GLObjectManager
for (ShaderSource source : s.shaderList){
shaderList.add( (ShaderSource)source.createDestructableClone() );
// Shader sources cannot be shared, therefore they must
// be destroyed together with the parent shader.
shaderSourceList = new ArrayList<ShaderSource>();
for (ShaderSource source : s.shaderSourceList){
shaderSourceList.add( (ShaderSource)source.createDestructableClone() );
}
}
public void write(JmeExporter ex) throws IOException{
OutputCapsule oc = ex.getCapsule(this);
oc.write(language, "language", null);
oc.writeSavableArrayList(shaderList, "shaderList", null);
oc.writeIntSavableMap(attribs, "attribs", null);
oc.writeStringSavableMap(uniforms, "uniforms", null);
}
public void read(JmeImporter im) throws IOException{
InputCapsule ic = im.getCapsule(this);
language = ic.readString("language", null);
shaderList = ic.readSavableArrayList("shaderList", null);
attribs = (IntMap<Attribute>) ic.readIntSavableMap("attribs", null);
HashMap<String, Uniform> uniMap = (HashMap<String, Uniform>) ic.readStringSavableMap("uniforms", null);
uniforms = new ListMap<String, Uniform>(uniMap);
}
/**
* Creates a deep clone of the shader, where the sources are available
* but have not been compiled yet. Does not copy the uniforms or attribs.
* @return
* @deprecated Use the method that takes a language argument instead.
* {@link #addSource(com.jme3.shader.Shader.ShaderType, java.lang.String, java.lang.String, java.lang.String, java.lang.String) }
*/
// public Shader createDeepClone(String defines){
// Shader newShader = new Shader(language);
// for (ShaderSource source : shaderList){
// if (!source.getDefines().equals(defines)){
// // need to clone the shadersource so
// // the correct defines can be placed
// ShaderSource newSource = new ShaderSource(source.getType());
// newSource.setSource(source.getSource());
// newSource.setDefines(defines);
// newShader.addSource(newSource);
// }else{
// // no need to clone source, also saves
// // having to compile the shadersource
// newShader.addSource(source);
// }
// }
// return newShader;
// }
@Deprecated
public void addSource(ShaderType type, String name, String source, String defines) {
addSource(type, name, source, defines, this.language);
}
/**
* Adds source code to a certain pipeline.
*
* @param type The pipeline to control
* @param source The shader source code (in GLSL).
* @deprecated Use the method that takes a language argument instead.
* {@link #addSource(com.jme3.shader.Shader.ShaderType, java.lang.String, java.lang.String, java.lang.String, java.lang.String) }
*/
public void addSource(ShaderType type, String name, String source, String defines){
ShaderSource shader = new ShaderSource(type);
shader.setSource(source);
shader.setName(name);
if (defines != null)
shader.setDefines(defines);
shaderList.add(shader);
setUpdateNeeded();
}
@Deprecated
public void addSource(ShaderType type, String source, String defines){
addSource(type, null, source, defines);
}
/**
* @deprecated Use the method that takes a language argument instead.
* {@link #addSource(com.jme3.shader.Shader.ShaderType, java.lang.String, java.lang.String, java.lang.String, java.lang.String) }
*/
@Deprecated
public void addSource(ShaderType type, String source){
addSource(type, source, null);
}
/**
* Adds an existing shader source to this shader.
* @param source
* @deprecated Shader sources may not be shared.
* {@link #addSource(com.jme3.shader.Shader.ShaderType, java.lang.String, java.lang.String, java.lang.String, java.lang.String) }
*/
@Deprecated
private void addSource(ShaderSource source){
shaderList.add(source);
shaderSourceList.add(source);
setUpdateNeeded();
}
/**
* Adds source code to a certain pipeline.
*
* @param type The pipeline to control
* @param source The shader source code (in GLSL).
* @param defines Preprocessor defines (placed at the beginning of the shader)
* @param language The shader source language, currently accepted is GLSL###
* where ### is the version, e.g. GLSL100 = GLSL 1.0, GLSL330 = GLSL 3.3, etc.
*/
public void addSource(ShaderType type, String name, String source, String defines, String language){
ShaderSource shaderSource = new ShaderSource(type);
shaderSource.setSource(source);
shaderSource.setName(name);
shaderSource.setLanguage(language);
if (defines != null) {
shaderSource.setDefines(defines);
}
shaderSourceList.add(shaderSource);
setUpdateNeeded();
}
@ -343,69 +317,73 @@ public final class Shader extends NativeObject implements Savable {
return attrib;
}
// public Collection<Uniform> getUniforms(){
// return uniforms.values();
// }
public ListMap<String, Uniform> getUniformMap(){
return uniforms;
}
// public Collection<Attribute> getAttributes() {
// return attribs.
// }
public Collection<ShaderSource> getSources(){
return shaderList;
return shaderSourceList;
}
/**
* @deprecated Shaders no longer have a language variable,
* use {@link ShaderSource#getLanguage() } instead.
*/
@Deprecated
public String getLanguage(){
return language;
}
@Override
public String toString(){
return getClass().getSimpleName() + "[language="+language
+ ", numSources="+shaderList.size()
+ ", numUniforms="+uniforms.size()
+ ", shaderSources="+getSources()+"]";
public String toString() {
return getClass().getSimpleName() +
"[numSources=" + shaderSourceList.size() +
", numUniforms=" + uniforms.size() +
", shaderSources=" + getSources() + "]";
}
/**
* Clears all sources. Assuming that they have already been detached and
* removed on the GL side.
* @deprecated This method is not needed since deleting
* a shader causes the sources to delete as well, thus its not required
* for them to be GC'd to be removed from GL.
*/
@Deprecated
public void resetSources(){
shaderList.clear();
shaderSourceList.clear();
}
/**
* Returns true if this program and all it's shaders have been compiled,
* linked and validated successfuly.
* @deprecated Unusable shaders cause the renderer to crash,
* therefore this field no longer serves any purpose.
*/
@Deprecated
public boolean isUsable(){
return usable;
return true;
}
/**
* Sets if the program can be used. Should only be called by the Renderer.
* @param usable
* @deprecated Unusable shaders cause the renderer to crash,
* therefore this field no longer serves any purpose.
*/
@Deprecated
public void setUsable(boolean usable){
this.usable = usable;
}
/**
* Usually called when the shader itself changes or during any
* time when the var locations need to be refreshed.
* time when the variable locations need to be refreshed.
*/
public void resetLocations(){
public void resetLocations() {
if (uniforms != null) {
// NOTE: Shader sources will be reset seperately from the shader itself.
for (Uniform uniform : uniforms.values()){
for (Uniform uniform : uniforms.values()) {
uniform.reset(); // fixes issue with re-initialization
}
for (Entry<Attribute> entry : attribs){
entry.getValue().location = -2;
}
if (attribs != null) {
for (Entry<Attribute> entry : attribs) {
entry.getValue().location = ShaderVariable.LOC_UNKNOWN;
}
}
}
@ -422,12 +400,9 @@ public final class Shader extends NativeObject implements Savable {
@Override
public void resetObject() {
this.id = -1;
this.usable = false;
for (ShaderSource source : shaderList){
for (ShaderSource source : shaderSourceList){
source.resetObject();
}
setUpdateNeeded();
}

@ -43,16 +43,18 @@ public class ShaderKey extends AssetKey<Shader> {
protected String fragName;
protected DefineList defines;
protected String language;
protected String vertLanguage;
protected String fragLanguage;
public ShaderKey(){
}
public ShaderKey(String vertName, String fragName, DefineList defines, String lang){
public ShaderKey(String vertName, String fragName, DefineList defines, String vertLanguage, String fragLanguage){
super(vertName);
this.fragName = fragName;
this.defines = defines;
this.language = lang;
this.vertLanguage = vertLanguage;
this.fragLanguage = fragLanguage;
}
@Override
@ -71,7 +73,6 @@ public class ShaderKey extends AssetKey<Shader> {
final ShaderKey other = (ShaderKey) obj;
if (name.equals(other.name) && fragName.equals(other.fragName)){
// return true;
if (defines != null && other.defines != null)
return defines.getCompiled().equals(other.defines.getCompiled());
else if (defines != null || other.defines != null)
@ -103,8 +104,20 @@ public class ShaderKey extends AssetKey<Shader> {
return fragName;
}
/**
* @deprecated Use {@link #getVertexShaderLanguage() } instead.
*/
@Deprecated
public String getLanguage() {
return language;
return vertLanguage;
}
public String getVertexShaderLanguage() {
return vertLanguage;
}
public String getFragmentShaderLanguage() {
return fragLanguage;
}
@Override
@ -112,7 +125,7 @@ public class ShaderKey extends AssetKey<Shader> {
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(fragName, "fragment_name", null);
oc.write(language, "language", null);
oc.write(vertLanguage, "language", null);
}
@Override
@ -120,7 +133,7 @@ public class ShaderKey extends AssetKey<Shader> {
super.read(im);
InputCapsule ic = im.getCapsule(this);
fragName = ic.readString("fragment_name", null);
language = ic.readString("language", null);
vertLanguage = ic.readString("language", null);
}
}

@ -32,15 +32,15 @@
package com.jme3.shader;
import com.jme3.export.*;
import java.io.IOException;
public class ShaderVariable {
public class ShaderVariable implements Savable {
public static final int LOC_UNKNOWN = -2,
LOC_NOT_DEFINED = -1;
// if -2, location not known
// if -1, not defined in shader
// if >= 0, uniform defined and available.
protected int location = -2;
protected int location = LOC_UNKNOWN;
/**
* Name of the uniform as was declared in the shader.
@ -54,15 +54,6 @@ public class ShaderVariable implements Savable {
*/
protected boolean updateNeeded = true;;
public void write(JmeExporter ex) throws IOException{
OutputCapsule oc = ex.getCapsule(this);
oc.write(name, "name", null);
}
public void read(JmeImporter im) throws IOException{
InputCapsule ic = im.getCapsule(this);
name = ic.readString("name", null);
}
public void setLocation(int location){
this.location = location;

@ -53,7 +53,10 @@ import com.jme3.texture.FrameBuffer.RenderBuffer;
import com.jme3.texture.Image;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapAxis;
import com.jme3.util.*;
import com.jme3.util.BufferUtils;
import com.jme3.util.ListMap;
import com.jme3.util.NativeObjectManager;
import com.jme3.util.SafeArrayList;
import java.nio.*;
import java.util.EnumSet;
import java.util.List;
@ -61,7 +64,6 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import jme3tools.converters.MipMapGenerator;
import jme3tools.shader.ShaderDebug;
import org.lwjgl.opengl.*;
import static org.lwjgl.opengl.ARBTextureMultisample.*;
import static org.lwjgl.opengl.EXTFramebufferBlit.*;
import static org.lwjgl.opengl.EXTFramebufferMultisample.*;
@ -72,6 +74,7 @@ import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL14.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import org.lwjgl.opengl.*;
//import static org.lwjgl.opengl.ARBDrawInstanced.*;
public class LwjglRenderer implements Renderer {
@ -889,7 +892,6 @@ public class LwjglRenderer implements Renderer {
protected void updateShaderUniforms(Shader shader) {
ListMap<String, Uniform> uniforms = shader.getUniformMap();
// for (Uniform uniform : shader.getUniforms()){
for (int i = 0; i < uniforms.size(); i++) {
Uniform uniform = uniforms.getValue(i);
if (uniform.isUpdateNeeded()) {
@ -900,7 +902,6 @@ public class LwjglRenderer implements Renderer {
protected void resetUniformLocations(Shader shader) {
ListMap<String, Uniform> uniforms = shader.getUniformMap();
// for (Uniform uniform : shader.getUniforms()){
for (int i = 0; i < uniforms.size(); i++) {
Uniform uniform = uniforms.getValue(i);
uniform.reset(); // e.g check location again
@ -927,10 +928,10 @@ public class LwjglRenderer implements Renderer {
}
}
public void updateShaderSourceData(ShaderSource source, String language) {
public void updateShaderSourceData(ShaderSource source) {
int id = source.getId();
if (id == -1) {
// create id
// Create id
id = glCreateShader(convertShaderType(source.getType()));
if (id <= 0) {
throw new RendererException("Invalid ID received when trying to create shader.");
@ -941,9 +942,9 @@ public class LwjglRenderer implements Renderer {
throw new RendererException("Cannot recompile shader source");
}
// upload shader source
// merge the defines and source code
// Upload shader source.
// Merge the defines and source code.
String language = source.getLanguage();
stringBuf.setLength(0);
if (language.startsWith("GLSL")) {
int version = Integer.parseInt(language.substring(4));
@ -999,6 +1000,7 @@ public class LwjglRenderer implements Renderer {
} else {
logger.log(Level.FINE, "{0} compile success", source.getName());
}
source.clearUpdateNeeded();
} else {
logger.log(Level.WARNING, "Bad compile of:\n{0}",
new Object[]{ShaderDebug.formatShaderSource(source.getDefines(), source.getSource(), stringBuf.toString())});
@ -1008,21 +1010,6 @@ public class LwjglRenderer implements Renderer {
throw new RendererException("compile error in:" + source + " error: <not provided>");
}
}
source.clearUpdateNeeded();
// only usable if compiled
source.setUsable(compiledOK);
if (!compiledOK) {
// make sure to dispose id cause all program's
// shaders will be cleared later.
glDeleteShader(id);
} else {
// register for cleanup since the ID is usable
// NOTE: From now on cleanup is handled
// by the parent shader object so no need
// to register.
//objManager.registerForCleanup(source);
}
}
public void updateShaderData(Shader shader) {
@ -1041,15 +1028,7 @@ public class LwjglRenderer implements Renderer {
for (ShaderSource source : shader.getSources()) {
if (source.isUpdateNeeded()) {
updateShaderSourceData(source, shader.getLanguage());
// shader has been compiled here
}
if (!source.isUsable()) {
// it's useless.. just forget about everything..
shader.setUsable(false);
shader.clearUpdateNeeded();
return;
updateShaderSourceData(source);
}
glAttachShader(id, source.getId());
}
@ -1057,13 +1036,16 @@ public class LwjglRenderer implements Renderer {
if (caps.contains(Caps.OpenGL30)) {
// Check if GLSL version is 1.5 for shader
GL30.glBindFragDataLocation(id, 0, "outFragColor");
// For MRT
for(int i = 0 ; i < maxMRTFBOAttachs ; i++) {
GL30.glBindFragDataLocation(id, i, "outFragData[" + i + "]");
}
}
// link shaders to program
// Link shaders to program
glLinkProgram(id);
// Check link status
glGetProgram(id, GL_LINK_STATUS, intBuf1);
boolean linkOK = intBuf1.get(0) == GL_TRUE;
String infoLog = null;
@ -1089,41 +1071,27 @@ public class LwjglRenderer implements Renderer {
} else {
logger.fine("shader link success");
}
} else {
if (infoLog != null) {
throw new RendererException("Shader link failure, shader:" + shader + " info:" + infoLog);
} else {
throw new RendererException("Shader link failure, shader:" + shader + " info: <not provided>");
}
}
shader.clearUpdateNeeded();
if (!linkOK) {
// failure.. forget about everything
shader.resetSources();
shader.setUsable(false);
deleteShader(shader);
} else {
shader.setUsable(true);
if (needRegister) {
// Register shader for clean up if it was created in this method.
objManager.registerForCleanup(shader);
statistics.onNewShader();
} else {
// OpenGL spec: uniform locations may change after re-link
resetUniformLocations(shader);
}
} else {
if (infoLog != null) {
throw new RendererException("Shader link failure, shader:" + shader + " info:" + infoLog);
} else {
throw new RendererException("Shader link failure, shader:" + shader + " info: <not provided>");
}
}
}
public void setShader(Shader shader) {
if (shader == null) {
throw new IllegalArgumentException("shader cannot be null");
// if (context.boundShaderProgram > 0) {
// glUseProgram(0);
// statistics.onShaderUse(null, true);
// context.boundShaderProgram = 0;
// boundShader = null;
// }
throw new IllegalArgumentException("Shader cannot be null");
} else {
if (shader.isUpdateNeeded()) {
updateShaderData(shader);
@ -1132,10 +1100,6 @@ public class LwjglRenderer implements Renderer {
// NOTE: might want to check if any of the
// sources need an update?
if (!shader.isUsable()) {
return;
}
assert shader.getId() > 0;
updateShaderUniforms(shader);
@ -1148,7 +1112,6 @@ public class LwjglRenderer implements Renderer {
logger.warning("Shader source is not uploaded to GPU, cannot delete.");
return;
}
source.setUsable(false);
source.clearUpdateNeeded();
glDeleteShader(source.getId());
source.resetObject();
@ -1167,12 +1130,9 @@ public class LwjglRenderer implements Renderer {
}
}
// kill all references so sources can be collected
// if needed.
shader.resetSources();
glDeleteProgram(shader.getId());
statistics.onDeleteShader();
shader.resetObject();
}
/*********************************************************************\
@ -2116,46 +2076,6 @@ public class LwjglRenderer implements Renderer {
throw new UnsupportedOperationException("Unknown buffer format.");
}
}
// }else{
// if (created || vb.hasDataSizeChanged()){
// glBufferData(target, vb.getData().capacity() * vb.getFormat().getComponentSize(), usage);
// }
//
// ByteBuffer buf = glMapBuffer(target,
// GL_WRITE_ONLY,
// vb.getMappedData());
//
// if (buf != vb.getMappedData()){
// buf = buf.order(ByteOrder.nativeOrder());
// vb.setMappedData(buf);
// }
//
// buf.clear();
//
// switch (vb.getFormat()){
// case Byte:
// case UnsignedByte:
// buf.put( (ByteBuffer) vb.getData() );
// break;
// case Short:
// case UnsignedShort:
// buf.asShortBuffer().put( (ShortBuffer) vb.getData() );
// break;
// case Int:
// case UnsignedInt:
// buf.asIntBuffer().put( (IntBuffer) vb.getData() );
// break;
// case Float:
// buf.asFloatBuffer().put( (FloatBuffer) vb.getData() );
// break;
// case Double:
// break;
// default:
// throw new RuntimeException("Unknown buffer format.");
// }
//
// glUnmapBuffer(target);
// }
vb.clearUpdateNeeded();
}

Loading…
Cancel
Save