From 23b0c5d8506734b9ce78dc444c534644b6acfa59 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Fri, 9 Sep 2005 01:42:48 +0000 Subject: [PATCH] Added better code to compile shaders --- doc/makepanda/makepanda.py | 5 +- doc/makepanda/makepanda71.vcproj | 84 +-- .../glstuff/glGraphicsStateGuardian_src.cxx | 27 +- .../src/glstuff/glGraphicsStateGuardian_src.h | 10 - panda/src/glstuff/glShaderContext_src.I | 34 +- panda/src/glstuff/glShaderContext_src.cxx | 610 +++++++++++++++++- panda/src/glstuff/glShaderContext_src.h | 79 ++- panda/src/gobj/shader.cxx | 14 + panda/src/gobj/shader.h | 6 +- panda/src/gobj/shaderContext.h | 6 + 10 files changed, 740 insertions(+), 135 deletions(-) diff --git a/doc/makepanda/makepanda.py b/doc/makepanda/makepanda.py index 8e766246ea..5fe9550c68 100755 --- a/doc/makepanda/makepanda.py +++ b/doc/makepanda/makepanda.py @@ -1773,7 +1773,10 @@ ConditionalWriteFile(PREFIX+'/include/dtool_config.h',conf) ########################################################################################## CONFAUTOPRC=ReadFile("makepanda/confauto.in") -CONFIGPRC=ReadFile("makepanda/config.in") +if (os.path.isfile("makepanda/myconfig.in")): + CONFIGPRC=ReadFile("makepanda/myconfig.in") +else: + CONFIGPRC=ReadFile("makepanda/config.in") if (sys.platform != "win32"): CONFAUTOPRC = CONFAUTOPRC.replace("aux-display pandadx9","") diff --git a/doc/makepanda/makepanda71.vcproj b/doc/makepanda/makepanda71.vcproj index d67212e8ca..d714bf89f5 100755 --- a/doc/makepanda/makepanda71.vcproj +++ b/doc/makepanda/makepanda71.vcproj @@ -1,42 +1,42 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 6e791f46f2..a0d3061458 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -68,10 +68,6 @@ #include "shader.h" #include "shaderMode.h" -#ifdef HAVE_CGGL -#include "Cg/cgGL.h" -#endif - #include TypeHandle CLP(GraphicsStateGuardian)::_type_handle; @@ -859,16 +855,6 @@ reset() { _error_count = 0; -#ifdef HAVE_CGGL - _cg_context = cgCreateContext(); - if (_cg_context != 0) { - _cg_vprofile = cgGLGetLatestProfile(CG_GL_VERTEX); - _cg_fprofile = cgGLGetLatestProfile(CG_GL_FRAGMENT); - } else { - cerr << "Warning: could not create Cg context.\n"; - } -#endif - report_my_gl_errors(); } @@ -1944,7 +1930,10 @@ release_geom(GeomContext *gc) { //////////////////////////////////////////////////////////////////// ShaderContext *CLP(GraphicsStateGuardian):: prepare_shader(Shader *shader) { - return new CLP(ShaderContext)(this, shader); + CLP(ShaderContext) *result = new CLP(ShaderContext)(shader); + if (result->valid()) return result; + delete result; + return NULL; } //////////////////////////////////////////////////////////////////// @@ -2620,7 +2609,7 @@ issue_shader(const ShaderAttrib *attrib) { _shader_context = 0; } if (context != 0) { - context->bind(mode); + context->bind(mode, this); _shader_context = context; } _shader_mode = mode; @@ -4762,12 +4751,6 @@ finish_modify_state() { //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: free_pointers() { -#ifdef HAVE_CGGL - if (_cg_context) { - cgDestroyContext(_cg_context); - _cg_context = 0; - } -#endif } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 3ce0deb003..2d5a17a0ac 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -41,10 +41,6 @@ #include "shader.h" #include "shaderMode.h" -#ifdef HAVE_CGGL -#include "Cg/cgGL.h" -#endif - class PlaneNode; class Light; @@ -389,12 +385,6 @@ public: typedef pvector DeletedDisplayLists; DeletedDisplayLists _deleted_display_lists; -#ifdef HAVE_CGGL - CGcontext _cg_context; - CGprofile _cg_vprofile; - CGprofile _cg_fprofile; -#endif - static PStatCollector _load_display_list_pcollector; static PStatCollector _primitive_batches_display_list_pcollector; static PStatCollector _vertices_display_list_pcollector; diff --git a/panda/src/glstuff/glShaderContext_src.I b/panda/src/glstuff/glShaderContext_src.I index 823f1e0cdd..c87b6ed613 100755 --- a/panda/src/glstuff/glShaderContext_src.I +++ b/panda/src/glstuff/glShaderContext_src.I @@ -17,29 +17,19 @@ //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// -// Function: GLShaderContext::bind +// Function: GLShaderContext::valid // Access: Public -// Description: xyz +// Description: Returns true if the shader is "valid", ie, if the +// compilation was successful. The compilation could +// fail if there is a syntax error in the shader, or +// if the current video card isn't shader-capable, +// or if no shader languages are compiled into panda. //////////////////////////////////////////////////////////////////// -INLINE void CLP(ShaderContext):: -bind(ShaderMode *m) { -} - -//////////////////////////////////////////////////////////////////// -// Function: GLShaderContext::unbind -// Access: Public -// Description: xyz -//////////////////////////////////////////////////////////////////// -INLINE void CLP(ShaderContext):: -unbind() { -} - -//////////////////////////////////////////////////////////////////// -// Function: GLShaderContext::rebind -// Access: Public -// Description: xyz -//////////////////////////////////////////////////////////////////// -INLINE void CLP(ShaderContext):: -rebind(ShaderMode *oldmode, ShaderMode *newmode) { +INLINE bool CLP(ShaderContext):: +valid() { +#ifdef HAVE_CGGL + if (_cg_context) return true; +#endif + return false; } diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index 1ff4667ea5..07489f1d83 100755 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -24,44 +24,95 @@ TypeHandle CLP(ShaderContext)::_type_handle; // Description: xyz //////////////////////////////////////////////////////////////////// CLP(ShaderContext):: -CLP(ShaderContext)(CLP(GraphicsStateGuardian) *gsg, Shader *s) : ShaderContext(s) { +CLP(ShaderContext)(Shader *s) : ShaderContext(s) { string header; - _gsg = gsg; - _valid = false; s->parse_init(); s->parse_line(header, true, true); #ifdef HAVE_CGGL - _cg_vprogram = 0; - _cg_fprogram = 0; + _cg_context = (CGcontext)0; + _cg_profile[VERT_SHADER] = (CGprofile)0; + _cg_profile[FRAG_SHADER] = (CGprofile)0; + _cg_program[VERT_SHADER] = (CGprogram)0; + _cg_program[FRAG_SHADER] = (CGprogram)0; if (header == "Cg") { - if (_gsg->_cg_context == 0) { - cerr << "Cannot compile shader, no Cg context\n"; - return; - } - string commentary, vs, fs; - s->parse_upto(commentary, "---*---", false); - s->parse_upto(vs, "---*---", false); - s->parse_upto(fs, "---*---", false); - _cg_vprogram = cgCreateProgram(_gsg->_cg_context, CG_SOURCE, - vs.c_str(), _gsg->_cg_vprofile, - "main", (const char**)NULL); - _cg_fprogram = cgCreateProgram(_gsg->_cg_context, CG_SOURCE, - fs.c_str(), _gsg->_cg_fprofile, - "main", (const char**)NULL); - - if ((_cg_vprogram==0)||(_cg_fprogram == 0)) { - if (_cg_vprogram != 0) cgDestroyProgram(_cg_vprogram); - if (_cg_fprogram != 0) cgDestroyProgram(_cg_fprogram); - cerr << "Invalid Cg program" << s->_file << "\n"; + CGerror err; + _cg_context = cgCreateContext(); + if (_cg_context == 0) { + release_resources(); + cerr << "Cg not supported by this video card.\n"; return; } + + _cg_profile[VERT_SHADER] = cgGLGetLatestProfile(CG_GL_VERTEX); + _cg_profile[FRAG_SHADER] = cgGLGetLatestProfile(CG_GL_FRAGMENT); + if ((_cg_profile[VERT_SHADER] == CG_PROFILE_UNKNOWN)|| + (_cg_profile[FRAG_SHADER] == CG_PROFILE_UNKNOWN)) { + release_resources(); + cerr << "Cg not supported by this video card II\n"; + return; + } + cgGetError(); + + string commentary, stext[2]; + s->parse_upto(commentary, "---*---", false); + _cg_linebase[0] = s->parse_lineno(); + s->parse_upto(stext[0], "---*---", false); + _cg_linebase[1] = s->parse_lineno(); + s->parse_upto(stext[1], "---*---", false); + + for (int progindex=0; progindex<2; progindex++) { + _cg_program[progindex] = + cgCreateProgram(_cg_context, CG_SOURCE, stext[progindex].c_str(), + _cg_profile[progindex], "main", (const char**)NULL); + err = cgGetError(); + if (err != CG_NO_ERROR) { + if (err == CG_COMPILER_ERROR) { + string listing = cgGetLastListing(_cg_context); + vector_string errlines; + tokenize(listing, errlines, "\n"); + for (int i=0; i<(int)errlines.size(); i++) { + string line = trim(errlines[i]); + if (line != "") { + cerr << s->_file << " " << (_cg_linebase[progindex]-1) << "+" << errlines[i] << "\n"; + } + } + } else { + cerr << s->_file << ": " << cgGetErrorString(err) << "\n"; + } + } + } + + if ((_cg_program[VERT_SHADER]==0)||(_cg_program[FRAG_SHADER]==0)) { + release_resources(); + return; + } + + bool success = true; + CGparameter parameter; + for (int progindex=0; progindex<2; progindex++) { + for (parameter = cgGetFirstLeafParameter(_cg_program[progindex],CG_PROGRAM); + parameter != 0; + parameter = cgGetNextLeafParameter(parameter)) { + success &= compile_cg_parameter(parameter); + } + } + if (!success) { + release_resources(); + return; + } + + cgGLLoadProgram(_cg_program[VERT_SHADER]); + cgGLLoadProgram(_cg_program[FRAG_SHADER]); + + cerr << s->_file << ": compiled ok.\n"; + return; } #endif - - cerr << "Unrecognized shader language " << header << "\n"; + + cerr << s->_file << ": unrecognized shader language " << header << "\n"; } //////////////////////////////////////////////////////////////////// @@ -71,5 +122,512 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *gsg, Shader *s) : ShaderContext(s //////////////////////////////////////////////////////////////////// CLP(ShaderContext):: ~CLP(ShaderContext)() { + release_resources(); } +//////////////////////////////////////////////////////////////////// +// Function: GLShaderContext::release_resources +// Access: Public +// Description: Should deallocate all system resources (such as +// vertex program handles or Cg contexts). +//////////////////////////////////////////////////////////////////// +void CLP(ShaderContext):: +release_resources() { +#ifdef HAVE_CGGL + if (_cg_context) { + cgDestroyContext(_cg_context); + _cg_context = (CGcontext)0; + _cg_profile[VERT_SHADER] = (CGprofile)0; + _cg_profile[FRAG_SHADER] = (CGprofile)0; + _cg_program[VERT_SHADER] = (CGprogram)0; + _cg_program[FRAG_SHADER] = (CGprogram)0; + } +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: GLShaderContext::bind +// Access: Public +// Description: xyz +//////////////////////////////////////////////////////////////////// +void CLP(ShaderContext):: +bind(ShaderMode *m, GraphicsStateGuardianBase *gsg) { +#ifdef HAVE_CGGL + if (_cg_context != 0) { + LVector4d tvec; + + // Assign the uniform Auto-Matrices + for (int i=0; i<(int)_cg_autobind.size(); i++) { + cgGLSetStateMatrixParameter(_cg_autobind[i].parameter, + _cg_autobind[i].matrix, + _cg_autobind[i].orientation); + } + + // Bind the shaders. + cgGLEnableProfile(_cg_profile[VERT_SHADER]); + cgGLBindProgram(_cg_program[VERT_SHADER]); + cgGLEnableProfile(_cg_profile[FRAG_SHADER]); + cgGLBindProgram(_cg_program[FRAG_SHADER]); + + // Pass in uniform sampler2d parameters. + for (int i=0; i<(int)_cg_tbind2d.size(); i++) { + int index = _cg_tbind2d[i].argindex; + if (index >= (int)m->_args.size()) continue; + if (m->_args[index]._type != ShaderModeArg::SAT_TEXTURE) continue; + Texture *tex = m->_args[index]._tvalue; + TextureContext *tc = tex->prepare_now(gsg->get_prepared_objects(),gsg); + CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); + cgGLSetTextureParameter(_cg_tbind2d[i].parameter, gtc->_index); + cgGLEnableTextureParameter(_cg_tbind2d[i].parameter); + } + } +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: GLShaderContext::unbind +// Access: Public +// Description: xyz +//////////////////////////////////////////////////////////////////// +void CLP(ShaderContext):: +unbind() { +#ifdef HAVE_CGGL + if (_cg_context != 0) { + // Disable texture parameters. + for (int i=0; i<(int)_cg_tbind2d.size(); i++) + cgGLDisableTextureParameter(_cg_tbind2d[i].parameter); + + cgGLDisableProfile(_cg_profile[VERT_SHADER]); + cgGLDisableProfile(_cg_profile[FRAG_SHADER]); + } +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: GLShaderContext::rebind +// Access: Public +// Description: xyz +//////////////////////////////////////////////////////////////////// +void CLP(ShaderContext):: +rebind(ShaderMode *oldmode, ShaderMode *newmode) { +} + +#ifdef HAVE_CGGL +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_words +// Access: Public, Static +// Description: Make sure the provided Cg parameter contains +// the specified number of words. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool CLP(ShaderContext):: +errchk_cg_parameter_words(CGparameter p, int len) +{ + vector_string words; + tokenize(cgGetParameterName(p), words, "_"); + if (words.size() != len) { + errchk_cg_output(p, "parameter name has wrong number of words"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_direction +// Access: Public, Static +// Description: Make sure the provided Cg parameter has the +// correct direction. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool CLP(ShaderContext):: +errchk_cg_parameter_direction(CGparameter p, CGenum dir) +{ + if (cgGetParameterDirection(p) != dir) { + if (dir == CG_IN) errchk_cg_output(p, "parameter should be declared 'in'"); + if (dir == CG_OUT) errchk_cg_output(p, "parameter should be declared 'out'"); + if (dir == CG_INOUT) errchk_cg_output(p, "parameter should be declared 'inout'"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_variance +// Access: Public, Static +// Description: Make sure the provided Cg parameter has the +// correct variance. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool CLP(ShaderContext):: +errchk_cg_parameter_variance(CGparameter p, CGenum var) +{ + if (cgGetParameterVariability(p) != var) { + if (var == CG_UNIFORM) + errchk_cg_output(p, "parameter should be declared 'uniform'"); + if (var == CG_VARYING) + errchk_cg_output(p, "parameter should be declared 'varying'"); + if (var == CG_CONSTANT) + errchk_cg_output(p, "parameter should be declared 'const'"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_prog +// Access: Public, Static +// Description: Make sure the provided Cg parameter is a part +// of the correct program. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool CLP(ShaderContext):: +errchk_cg_parameter_prog(CGparameter p, CGprogram prog, const string &msg) +{ + if (cgGetParameterProgram(p) != prog) { + string fmsg = "parameter can only be used in a "; + errchk_cg_output(p, fmsg+msg+" program"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_semantic +// Access: Public, Static +// Description: Make sure the provided Cg parameter has the +// correct semantic string. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool CLP(ShaderContext):: +errchk_cg_parameter_semantic(CGparameter p, const string &semantic) +{ + if (semantic != cgGetParameterSemantic(p)) { + if (semantic == "") { + errchk_cg_output(p, "parameter should have no semantic string"); + } else { + string msg = "parameter should have the semantic string "; + errchk_cg_output(p, msg + semantic); + } + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_type +// Access: Public, Static +// Description: Make sure the provided Cg parameter has the +// correct type. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool CLP(ShaderContext):: +errchk_cg_parameter_type(CGparameter p, CGtype dt) +{ + if (cgGetParameterType(p) != dt) { + string msg = "parameter should be of type "; + errchk_cg_output(p, msg + cgGetTypeString(dt)); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_float +// Access: Public, Static +// Description: Make sure the provided Cg parameter has +// a floating point type. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool CLP(ShaderContext):: +errchk_cg_parameter_float(CGparameter p) +{ + CGtype t = cgGetParameterType(p); + if ((t != CG_FLOAT1)&&(t != CG_FLOAT2)&&(t != CG_FLOAT3)&&(t != CG_FLOAT4)) { + errchk_cg_output(p, "parameter should have a float type"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_sampler +// Access: Public, Static +// Description: Make sure the provided Cg parameter has +// a texture type. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool CLP(ShaderContext):: +errchk_cg_parameter_sampler(CGparameter p) +{ + CGtype t = cgGetParameterType(p); + if (t != CG_SAMPLER2D) { + errchk_cg_output(p, "parameter should have a 'sampler' type"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_direction +// Access: Public, Static +// Description: Print an error message including a description +// of the specified Cg parameter. +//////////////////////////////////////////////////////////////////// +void CLP(ShaderContext):: +errchk_cg_output(CGparameter p, const string &msg) +{ + string vstr; + CGenum v = cgGetParameterVariability(p); + if (v == CG_UNIFORM) vstr = "uniform "; + if (v == CG_VARYING) vstr = "varying "; + if (v == CG_CONSTANT) vstr = "const "; + + string dstr; + CGenum d = cgGetParameterDirection(p); + if (d == CG_IN) dstr = "in "; + if (d == CG_OUT) dstr = "out "; + if (d == CG_INOUT) dstr = "inout "; + + const char *ts = cgGetTypeString(cgGetParameterType(p)); + const char *ss = cgGetParameterSemantic(p); + + string err; + string fn = _shader->_file; + if (ss) { + err = fn + ": " + msg + " (" + vstr + dstr + ts + " " + cgGetParameterName(p) + ":" + ss + ")\n"; + } else { + err = fn + ": " + msg + " (" + vstr + dstr + ts + " " + cgGetParameterName(p) + ")\n"; + } + cerr << err << "\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: GLShaderContext::compile_cg_parameter +// Access: Public +// Description: Analyzes a Cg parameter and decides how to +// bind the parameter to some part of panda's +// internal state. Updates one of the cg bind +// arrays to cause the binding to occur. +//////////////////////////////////////////////////////////////////// +bool CLP(ShaderContext):: +compile_cg_parameter(CGparameter p) +{ + string pname = cgGetParameterName(p); + if (pname.size() == 0) return true; + if (pname[0] == '$') return true; + vector_string pieces; + tokenize(pname, pieces, "_"); + + if (pieces[0] == "vtx") { + if ((!errchk_cg_parameter_words(p,2)) || + (!errchk_cg_parameter_direction(p, CG_IN)) || + (!errchk_cg_parameter_variance(p, CG_VARYING)) || + (!errchk_cg_parameter_prog(p, _cg_program[VERT_SHADER], "vertex"))) + return false; + if (pieces[1] == "position") { + if (!errchk_cg_parameter_semantic(p,"POSITION")) return false; + if (!errchk_cg_parameter_float(p)) return false; + return true; // Cg handles this automatically. + } + if (pieces[1] == "normal") { + if (!errchk_cg_parameter_semantic(p,"NORMAL")) return false; + if (!errchk_cg_parameter_float(p)) return false; + return true; // Cg handles this automatically. + } + if (pieces[1] == "color") { + if (!errchk_cg_parameter_semantic(p,"COLOR")) return false; + if (!errchk_cg_parameter_float(p)) return false; + return true; // Cg handles this automatically. + } + if (pieces[1].substr(0,8) == "texcoord") { + string ss = upcase(pieces[1]); + if (!errchk_cg_parameter_semantic(p,ss)) return false; + if (!errchk_cg_parameter_float(p)) return false; + return true; // Cg handles this automatically. + } + // Handle an arbitrary column taken from the vertex array. + // IMPLEMENT ME. + errchk_cg_output(p, "Arbitrary vertex fields not implemented yet"); + return false; + } + + if ((pieces[0] == "trans")|| + (pieces[0] == "tpose")|| + (pieces[0] == "row0")|| + (pieces[0] == "row1")|| + (pieces[0] == "row2")|| + (pieces[0] == "row3")|| + (pieces[0] == "col0")|| + (pieces[0] == "col1")|| + (pieces[0] == "col2")|| + (pieces[0] == "col3")|| + (pieces[0] == "xvec")|| + (pieces[0] == "yvec")|| + (pieces[0] == "zvec")|| + (pieces[0] == "pos")) { + if ((!errchk_cg_parameter_words(p,4)) || + (!errchk_cg_parameter_direction(p, CG_IN)) || + (!errchk_cg_parameter_variance(p, CG_UNIFORM)) || + (!errchk_cg_parameter_semantic(p, ""))) + return false; + if (pieces[2] != "rel") { + errchk_cg_output(p, "syntax error"); + return false; + } + ShaderTransBind bind; + bind.parameter = p; + + if (pieces[0]=="trans") bind.trans_piece = TRANS_NORMAL; + else if (pieces[0]=="tpose") bind.trans_piece = TRANS_TPOSE; + else if (pieces[0]=="row0") bind.trans_piece = TRANS_ROW0; + else if (pieces[0]=="row1") bind.trans_piece = TRANS_ROW1; + else if (pieces[0]=="row2") bind.trans_piece = TRANS_ROW2; + else if (pieces[0]=="row3") bind.trans_piece = TRANS_ROW3; + else if (pieces[0]=="col0") bind.trans_piece = TRANS_COL0; + else if (pieces[0]=="col1") bind.trans_piece = TRANS_COL1; + else if (pieces[0]=="col2") bind.trans_piece = TRANS_COL2; + else if (pieces[0]=="col3") bind.trans_piece = TRANS_COL3; + else if (pieces[0]=="xvec") bind.trans_piece = TRANS_ROW0; + else if (pieces[0]=="yvec") bind.trans_piece = TRANS_ROW1; + else if (pieces[0]=="zvec") bind.trans_piece = TRANS_ROW2; + else if (pieces[0]=="pos") bind.trans_piece = TRANS_ROW3; + + if (pieces[1] == "world") bind.src_argindex = ARGINDEX_WORLD; + else if (pieces[1] == "camera") bind.src_argindex = ARGINDEX_CAMERA; + else if (pieces[1] == "model") bind.src_argindex = ARGINDEX_MODEL; + else bind.src_argindex = _shader->arg_index(pieces[1]); + if (pieces[3] == "world") bind.rel_argindex = ARGINDEX_WORLD; + else if (pieces[3] == "camera") bind.rel_argindex = ARGINDEX_CAMERA; + else if (pieces[3] == "model") bind.rel_argindex = ARGINDEX_MODEL; + else bind.rel_argindex = _shader->arg_index(pieces[3]); + + if ((bind.trans_piece == TRANS_NORMAL)||(bind.trans_piece == TRANS_TPOSE)) { + if (!errchk_cg_parameter_type(p, CG_FLOAT4x4)) return false; + } else { + if (!errchk_cg_parameter_type(p, CG_FLOAT4)) return false; + } + + _cg_trans_bind.push_back(bind); + if ((bind.src_argindex == ARGINDEX_MODEL) || + (bind.rel_argindex == ARGINDEX_MODEL)) { + _cg_trans_rebind.push_back(bind); + } + return true; + } + + if ((pieces[0]=="mstrans")|| + (pieces[0]=="cstrans")|| + (pieces[0]=="wstrans")|| + (pieces[0]=="mspos")|| + (pieces[0]=="cspos")|| + (pieces[0]=="wspos")) { + if ((!errchk_cg_parameter_words(p,2)) || + (!errchk_cg_parameter_direction(p, CG_IN)) || + (!errchk_cg_parameter_variance(p, CG_UNIFORM)) || + (!errchk_cg_parameter_semantic(p, ""))) + return false; + ShaderTransBind bind; + bind.parameter = p; + + if (pieces[0]=="wstrans") { bind.rel_argindex = ARGINDEX_WORLD; bind.trans_piece = TRANS_NORMAL; } + else if (pieces[0]=="cstrans") { bind.rel_argindex = ARGINDEX_CAMERA; bind.trans_piece = TRANS_NORMAL; } + else if (pieces[0]=="mstrans") { bind.rel_argindex = ARGINDEX_MODEL; bind.trans_piece = TRANS_NORMAL; } + else if (pieces[0]=="wspos") { bind.rel_argindex = ARGINDEX_WORLD; bind.trans_piece = TRANS_ROW3; } + else if (pieces[0]=="cspos") { bind.rel_argindex = ARGINDEX_CAMERA; bind.trans_piece = TRANS_ROW3; } + else if (pieces[0]=="mspos") { bind.rel_argindex = ARGINDEX_MODEL; bind.trans_piece = TRANS_ROW3; } + + if (pieces[1] == "world") bind.src_argindex = ARGINDEX_WORLD; + else if (pieces[1] == "camera") bind.src_argindex = ARGINDEX_CAMERA; + else if (pieces[1] == "model") bind.src_argindex = ARGINDEX_MODEL; + else bind.src_argindex = _shader->arg_index(pieces[1]); + + if ((bind.trans_piece == TRANS_NORMAL)||(bind.trans_piece == TRANS_TPOSE)) { + if (!errchk_cg_parameter_type(p, CG_FLOAT4x4)) return false; + } else { + if (!errchk_cg_parameter_type(p, CG_FLOAT4)) return false; + } + _cg_trans_bind.push_back(bind); + if ((bind.src_argindex == ARGINDEX_MODEL) || + (bind.rel_argindex == ARGINDEX_MODEL)) { + _cg_trans_rebind.push_back(bind); + } + return true; + } + + if ((pieces[0]=="mat")|| + (pieces[0]=="inv")|| + (pieces[0]=="tps")|| + (pieces[0]=="itp")) { + if ((!errchk_cg_parameter_words(p,2)) || + (!errchk_cg_parameter_direction(p, CG_IN)) || + (!errchk_cg_parameter_variance(p, CG_UNIFORM)) || + (!errchk_cg_parameter_type(p, CG_FLOAT4x4))) + return false; + ShaderAutoBind bind; + bind.parameter = p; + if (pieces[1] == "modelview") bind.matrix = CG_GL_MODELVIEW_MATRIX; + else if (pieces[1] == "projection") bind.matrix = CG_GL_PROJECTION_MATRIX; + else if (pieces[1] == "texmatrix") bind.matrix = CG_GL_TEXTURE_MATRIX; + else if (pieces[1] == "modelproj") bind.matrix = CG_GL_MODELVIEW_PROJECTION_MATRIX; + else { + errchk_cg_output(p, "unrecognized matrix name"); + return false; + } + if (pieces[0]=="mat") bind.orientation = CG_GL_MATRIX_IDENTITY; + else if (pieces[0]=="inv") bind.orientation = CG_GL_MATRIX_INVERSE; + else if (pieces[0]=="tps") bind.orientation = CG_GL_MATRIX_TRANSPOSE; + else if (pieces[0]=="itp") bind.orientation = CG_GL_MATRIX_INVERSE_TRANSPOSE; + _cg_autobind.push_back(bind); + return true; + } + + if (pieces[0] == "tex") { + if ((!errchk_cg_parameter_words(p,2)) || + (!errchk_cg_parameter_direction(p, CG_IN)) || + (!errchk_cg_parameter_variance(p, CG_UNIFORM)) || + (!errchk_cg_parameter_sampler(p))) + return false; + if (cgGetParameterSemantic(p)[0]!=0) { + string texunit = "TEX"+upcase(pieces[1]); + if (!errchk_cg_parameter_semantic(p, texunit)) return false; + } + return true; // Cg handles this automatically. + } + + if (pieces[0] == "k") { + if ((!errchk_cg_parameter_words(p,2)) || + (!errchk_cg_parameter_direction(p, CG_IN)) || + (!errchk_cg_parameter_variance(p, CG_UNIFORM))) + return false; + ShaderArgBind bind; + bind.parameter = p; + bind.argindex = _shader->arg_index(pieces[1]); + switch (cgGetParameterType(p)) { + case CG_FLOAT1: _cg_vbind1.push_back(bind); break; + case CG_FLOAT2: _cg_vbind2.push_back(bind); break; + case CG_FLOAT3: _cg_vbind3.push_back(bind); break; + case CG_FLOAT4: _cg_vbind4.push_back(bind); break; + case CG_SAMPLER2D: _cg_tbind2d.push_back(bind); break; + case CG_SAMPLER3D: _cg_tbind3d.push_back(bind); break; + case CG_FLOAT4x4: _cg_npbind.push_back(bind); break; + default: + errchk_cg_output(p, "Invalid type for a k-parameter"); + return false; + } + return true; + } + + if (pieces[0] == "l") { + // IMPLEMENT THE ERROR CHECKING + return true; // Cg handles this automatically. + } + + if (pieces[0] == "o") { + // IMPLEMENT THE ERROR CHECKING + return true; // Cg handles this automatically. + } + + errchk_cg_output(p, "unrecognized parameter name"); + return false; +} +#endif diff --git a/panda/src/glstuff/glShaderContext_src.h b/panda/src/glstuff/glShaderContext_src.h index 2afb40ede2..2882d5f12c 100755 --- a/panda/src/glstuff/glShaderContext_src.h +++ b/panda/src/glstuff/glShaderContext_src.h @@ -21,8 +21,7 @@ #ifdef HAVE_CGGL #include "Cg/cgGL.h" #endif - -class CLP(GraphicsStateGuardian); +#include "string_utils.h" //////////////////////////////////////////////////////////////////// // Class : GLShaderContext @@ -31,23 +30,81 @@ class CLP(GraphicsStateGuardian); class EXPCL_GL CLP(ShaderContext): public ShaderContext { public: - CLP(ShaderContext)(CLP(GraphicsStateGuardian) *gsg, Shader *shader); + CLP(ShaderContext)(Shader *s); ~CLP(ShaderContext)(); - INLINE void bind(ShaderMode *mode); - INLINE void unbind(); - INLINE void rebind(ShaderMode *oldmode, ShaderMode *newmode); + INLINE bool valid(void); + void bind(ShaderMode *mode, GraphicsStateGuardianBase *gsg); + void unbind(); + void rebind(ShaderMode *oldmode, ShaderMode *newmode); - bool _valid; - private: - CLP(GraphicsStateGuardian) *_gsg; #ifdef HAVE_CGGL - CGprogram _cg_vprogram; - CGprogram _cg_fprogram; + enum { + ARGINDEX_WORLD =-1, + ARGINDEX_CAMERA=-2, + ARGINDEX_MODEL =-3 + }; + enum { + TRANS_NORMAL, + TRANS_TPOSE, + TRANS_ROW0, + TRANS_ROW1, + TRANS_ROW2, + TRANS_ROW3, + TRANS_COL0, + TRANS_COL1, + TRANS_COL2, + TRANS_COL3, + }; + struct ShaderAutoBind { + CGparameter parameter; + CGGLenum matrix; + CGGLenum orientation; + }; + struct ShaderArgBind { + CGparameter parameter; + int argindex; + }; + struct ShaderTransBind { + CGparameter parameter; + int src_argindex; + int rel_argindex; + int trans_piece; + }; + CGcontext _cg_context; + CGprofile _cg_profile[2]; + CGprogram _cg_program[2]; + int _cg_linebase[2]; + + // These arrays contain lists of "bindings." They + // tell us how to fill the shader's input parameters. + vector _cg_autobind; + vector _cg_tbind2d; + vector _cg_tbind3d; + vector _cg_vbind1; + vector _cg_vbind2; + vector _cg_vbind3; + vector _cg_vbind4; + vector _cg_npbind; + vector _cg_trans_bind; + vector _cg_trans_rebind; + + bool compile_cg_parameter(CGparameter p); + bool errchk_cg_parameter_words(CGparameter p, int len); + bool errchk_cg_parameter_direction(CGparameter p, CGenum dir); + bool errchk_cg_parameter_variance(CGparameter p, CGenum var); + bool errchk_cg_parameter_prog(CGparameter p, CGprogram prog, const string &msg); + bool errchk_cg_parameter_semantic(CGparameter p, const string &semantic); + bool errchk_cg_parameter_type(CGparameter p, CGtype dt); + bool errchk_cg_parameter_float(CGparameter p); + bool errchk_cg_parameter_sampler(CGparameter p); + void errchk_cg_output(CGparameter p, const string &msg); #endif + void release_resources(void); + public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/gobj/shader.cxx b/panda/src/gobj/shader.cxx index cafee49bf4..15b722a420 100755 --- a/panda/src/gobj/shader.cxx +++ b/panda/src/gobj/shader.cxx @@ -115,6 +115,19 @@ parse_rest(string &result) { result = _text.substr(_parse, _text.size() - _parse); } +//////////////////////////////////////////////////////////////////// +// Function: Shader::parse_lineno +// Access: Public +// Description: Returns the line number of the current parse pointer. +//////////////////////////////////////////////////////////////////// +int Shader:: +parse_lineno() { + int result = 1; + for (int i=0; i<_parse; i++) + if (_text[i] == '\n') result += 1; + return result; +} + //////////////////////////////////////////////////////////////////// // Function: Shader::parse_eof // Access: Public @@ -277,3 +290,4 @@ void Shader:: register_with_read_factory() { // IMPLEMENT ME } + diff --git a/panda/src/gobj/shader.h b/panda/src/gobj/shader.h index fbc95ef610..4714a55238 100755 --- a/panda/src/gobj/shader.h +++ b/panda/src/gobj/shader.h @@ -61,13 +61,17 @@ PUBLISHED: int release_all(); PUBLISHED: + // These routines help split the shader into sections, + // for those shader implementations that need to do so. void parse_init(); void parse_line(string &result, bool rt, bool lt); void parse_upto(string &result, string pattern, bool include); void parse_rest(string &result); + int parse_lineno(); bool parse_eof(); - + public: + INLINE int arg_count(); int arg_index(const string &id); diff --git a/panda/src/gobj/shaderContext.h b/panda/src/gobj/shaderContext.h index 75f73f8080..3ccd80eafa 100755 --- a/panda/src/gobj/shaderContext.h +++ b/panda/src/gobj/shaderContext.h @@ -41,6 +41,12 @@ public: INLINE ShaderContext(Shader *shader); Shader *_shader; + + enum { + VERT_SHADER=0, + FRAG_SHADER=1, + BOTH_SHADER=2, + }; public: static TypeHandle get_class_type() {