clean up shader code, add more debugging info, make shaders writable

This commit is contained in:
rdb 2013-03-13 09:47:37 +00:00
parent 962ff28af0
commit 8ef24aa846
4 changed files with 347 additions and 102 deletions

View File

@ -1790,11 +1790,20 @@ reset() {
CGprofile vertex_profile;
CGprofile pixel_profile;
vertex_profile = cgGLGetLatestProfile (CG_GL_VERTEX);
pixel_profile = cgGLGetLatestProfile (CG_GL_FRAGMENT);
vertex_profile = cgGLGetLatestProfile(CG_GL_VERTEX);
pixel_profile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
if (GLCAT.is_debug()) {
// Temp ifdef: this crashes Mesa.
#ifndef OSMESA_MAJOR_VERSION
GLCAT.debug() << "Supported Cg profiles:\n";
int num_profiles = cgGetNumSupportedProfiles();
for (int i = 0; i < num_profiles; ++i) {
CGprofile profile = cgGetSupportedProfile(i);
if (cgGLIsProfileSupported(profile)) {
GLCAT.debug() << " " << cgGetProfileString(profile) << "\n";
}
}
GLCAT.debug()
<< "\nCg vertex profile = " << cgGetProfileString(vertex_profile) << " id = " << vertex_profile
<< "\nCg pixel profile = " << cgGetProfileString(pixel_profile) << " id = " << pixel_profile

View File

@ -542,3 +542,127 @@ ShaderPtrData(const LMatrix3d &mat) :
nassertv(sizeof(mat(0, 0)) * mat.get_num_components() == pta.size() * sizeof(pta[0]));
memcpy(_ptr, mat.get_data(), sizeof(mat(0, 0)) * mat.get_num_components());
}
////////////////////////////////////////////////////////////////////
// Function: Shader::ShaderPtrData::write_datagram
// Access: Public
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
INLINE void Shader::ShaderPtrData::
write_datagram(Datagram &dg) const {
dg.add_uint8(_type);
dg.add_uint32(_size);
if (_type == SPT_double) {
const double *data = (const double *) _ptr;
for (size_t i = 0; i < _size; ++i) {
dg.add_float64(data[i]);
}
} else if (_type == SPT_float) {
const float *data = (const float *) _ptr;
for (size_t i = 0; i < _size; ++i) {
dg.add_float32(data[i]);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: Shader::ShaderPtrData::write_datagram
// Access: Public
// Description: Reads the object from a Datagram.
////////////////////////////////////////////////////////////////////
INLINE void Shader::ShaderPtrData::
read_datagram(DatagramIterator &scan) {
_type = (ShaderPtrType) scan.get_uint8();
_size = scan.get_uint32();
if (_type == SPT_double) {
PTA_double pta = PTA_double::empty_array(_size);
for (size_t i = 0; i < _size; ++i) {
pta[i] = scan.get_float64();
}
_pta = pta.v0();
_ptr = pta.p();
} else if (_type == SPT_float) {
PTA_float pta = PTA_float::empty_array(_size);
for (size_t i = 0; i < _size; ++i) {
pta[i] = scan.get_float32();
}
_pta = pta.v0();
_ptr = pta.p();
}
}
////////////////////////////////////////////////////////////////////
// Function: Shader::ShaderFile::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE Shader::ShaderFile::
ShaderFile(const string &shared) :
_separate(false),
_shared(shared)
{
}
////////////////////////////////////////////////////////////////////
// Function: Shader::ShaderFile::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE Shader::ShaderFile::
ShaderFile(const string &vertex,
const string &fragment,
const string &geometry,
const string &tess_control,
const string &tess_evaluation) :
_separate(false),
_vertex(vertex),
_fragment(fragment),
_geometry(geometry),
_tess_control(tess_control),
_tess_evaluation(tess_evaluation)
{
}
////////////////////////////////////////////////////////////////////
// Function: Shader::ShaderFile::write_datagram
// Access: Public
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
INLINE void Shader::ShaderFile::
write_datagram(Datagram &dg) const {
dg.add_bool(_separate);
if (_separate) {
dg.add_string(_vertex);
dg.add_string(_fragment);
dg.add_string(_geometry);
dg.add_string(_tess_control);
dg.add_string(_tess_evaluation);
} else {
dg.add_string(_shared);
}
}
////////////////////////////////////////////////////////////////////
// Function: Shader::ShaderFile::write_datagram
// Access: Public
// Description: Reads the object from a Datagram.
////////////////////////////////////////////////////////////////////
INLINE void Shader::ShaderFile::
read_datagram(DatagramIterator &scan) {
_separate = scan.get_bool();
if (_separate) {
_vertex = scan.get_string();
_fragment = scan.get_string();
_geometry = scan.get_string();
_tess_control = scan.get_string();
_tess_evaluation = scan.get_string();
} else {
_shared = scan.get_string();
}
}

View File

@ -1405,6 +1405,22 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
compiler_args[nargs] = 0;
if ((active != (int)CG_PROFILE_UNKNOWN) && (active != ultimate)) {
// Print out some debug information about what we're doing.
if (gobj_cat.is_debug()) {
gobj_cat.debug()
<< "Compiling Cg shader " << get_filename(type) << " with entry point " << entry
<< " and active profile " << cgGetProfileString((CGprofile) active) << "\n";
if (nargs > 0) {
gobj_cat.debug() << "Using compiler arguments:";
for (int i = 0; i < nargs; ++i) {
gobj_cat.debug(false) << " " << compiler_args[i];
}
gobj_cat.debug(false) << "\n";
}
}
// Compile the shader with the active profile.
prog = cgCreateProgram(_cg_context, CG_SOURCE, text.c_str(),
(CGprofile)active, entry, (const char **)compiler_args);
err = cgGetError();
@ -1414,8 +1430,19 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
if (prog != 0) {
cgDestroyProgram(prog);
}
if (gobj_cat.is_debug()) {
gobj_cat.debug()
<< "Compilation with active profile failed: " << cgGetErrorString(err) << "\n";
}
}
if (gobj_cat.is_debug()) {
gobj_cat.debug()
<< "Compiling Cg shader " << get_filename(type) << " with entry point " << entry
<< " and ultimate profile " << cgGetProfileString((CGprofile) ultimate) << "\n";
}
// The active profile failed, so recompile it with the ultimate profile.
prog = cgCreateProgram(_cg_context, CG_SOURCE, text.c_str(),
(CGprofile)ultimate, entry, (const char **)NULL);
err = cgGetError();
@ -1423,10 +1450,11 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
return prog;
}
if (err == CG_COMPILER_ERROR) {
// A compiler error has occurred. Extract the error messages.
string listing = cgGetLastListing(_cg_context);
vector_string errlines;
tokenize(listing, errlines, "\n");
for (int i=0; i<(int)errlines.size(); i++) {
for (int i = 0; i < (int) errlines.size(); ++i) {
string line = trim(errlines[i]);
if (line != "") {
gobj_cat.error() << get_filename(type) << ": " << errlines[i] << "\n";
@ -1466,12 +1494,8 @@ cg_compile_shader(const ShaderCaps &caps) {
_cg_context = cgCreateContext();
if (!_text->_separate) {
gobj_cat.debug() << "Compiling Shader: \n" << _text << "\n";
}
if (_cg_context == 0) {
gobj_cat.error() << "could not create a Cg context object.\n";
gobj_cat.error() << "Could not create a Cg context object.\n";
return false;
}
@ -1481,6 +1505,7 @@ cg_compile_shader(const ShaderCaps &caps) {
cg_release_resources();
return false;
}
_cg_vprofile = cgGetProgramProfile(_cg_vprogram);
}
if (!_text->_separate || !_text->_fragment.empty()) {
@ -1489,6 +1514,7 @@ cg_compile_shader(const ShaderCaps &caps) {
cg_release_resources();
return false;
}
_cg_fprofile = cgGetProgramProfile(_cg_fprogram);
}
if ((_text->_separate && !_text->_geometry.empty()) || (!_text->_separate && _text->_shared.find("gshader") != string::npos)) {
@ -1497,6 +1523,7 @@ cg_compile_shader(const ShaderCaps &caps) {
cg_release_resources();
return false;
}
_cg_gprofile = cgGetProgramProfile(_cg_gprogram);
}
if (_cg_vprogram == 0 && _cg_fprogram == 0 && _cg_gprogram == 0) {
@ -1508,19 +1535,25 @@ cg_compile_shader(const ShaderCaps &caps) {
// DEBUG: output the generated program
if (gobj_cat.is_debug()) {
const char *vertex_program;
const char *pixel_program;
const char *fragment_program;
const char *geometry_program;
if (_cg_vprogram != 0) {
vertex_program = cgGetProgramString (_cg_vprogram, CG_COMPILED_PROGRAM);
gobj_cat.debug()
<< "Cg vertex profile: " << cgGetProfileString((CGprofile)_cg_vprofile) << "\n";
vertex_program = cgGetProgramString(_cg_vprogram, CG_COMPILED_PROGRAM);
gobj_cat.debug() << vertex_program << "\n";
}
if (_cg_fprogram != 0) {
pixel_program = cgGetProgramString (_cg_fprogram, CG_COMPILED_PROGRAM);
gobj_cat.debug() << pixel_program << "\n";
gobj_cat.debug()
<< "Cg fragment profile: " << cgGetProfileString((CGprofile)_cg_fprofile) << "\n";
fragment_program = cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM);
gobj_cat.debug() << fragment_program << "\n";
}
if (_cg_gprogram != 0) {
geometry_program = cgGetProgramString (_cg_gprogram, CG_COMPILED_PROGRAM);
gobj_cat.debug()
<< "Cg geometry profile: " << cgGetProfileString((CGprofile)_cg_gprofile) << "\n";
geometry_program = cgGetProgramString(_cg_gprogram, CG_COMPILED_PROGRAM);
gobj_cat.debug() << geometry_program << "\n";
}
}
@ -1752,7 +1785,6 @@ cg_compile_for(const ShaderCaps &caps,
pvector<CGparameter> &map) {
// Initialize the return values to empty.
ctx = 0;
vprogram = 0;
fprogram = 0;
@ -1771,31 +1803,23 @@ cg_compile_for(const ShaderCaps &caps,
// If the compile routine used the ultimate profile instead of the
// active one, it means the active one isn't powerful enough to
// compile the shader.
if (_filename->_separate) {
if (_cg_vprogram != 0 && _cg_vprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_vprogram) != caps._active_vprofile) {
gobj_cat.error() << "Cg vprogram too complex for driver: "
<< get_filename(ST_vertex) << ". Try choosing a different profile.\n";
return false;
}
if (_cg_fprogram != 0 && _cg_fprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_fprogram) != caps._active_fprofile) {
gobj_cat.error() << "Cg fprogram too complex for driver: "
<< get_filename(ST_fragment) << ". Try choosing a different profile.\n";
return false;
}
if (_cg_gprogram != 0 && _cg_gprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_gprogram) != caps._active_gprofile) {
gobj_cat.error() << "Cg gprogram too complex for driver: "
<< get_filename(ST_geometry) << ". Try choosing a different profile.\n";
return false;
}
} else {
if ((_cg_vprogram != 0 && _cg_vprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_vprogram) != caps._active_vprofile) ||
(_cg_fprogram != 0 && _cg_fprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_fprogram) != caps._active_fprofile) ||
(_cg_gprogram != 0 && _cg_gprofile == CG_PROFILE_UNKNOWN && cgGetProgramProfile(_cg_gprogram) != caps._active_gprofile)) {
gobj_cat.error() << "Cg program too complex for driver: "
<< get_filename() << ". Try choosing a different profile.\n";
return false;
}
if (_cg_vprogram != 0 && _cg_vprofile != caps._active_vprofile) {
gobj_cat.error() << "Cg vertex program not supported by profile "
<< cgGetProfileString((CGprofile) caps._active_vprofile) << ": "
<< get_filename(ST_vertex) << ". Try choosing a different profile.\n";
return false;
}
if (_cg_fprogram != 0 && _cg_fprofile != caps._active_fprofile) {
gobj_cat.error() << "Cg vertex program not supported by profile "
<< cgGetProfileString((CGprofile) caps._active_fprofile) << ": "
<< get_filename(ST_fragment) << ". Try choosing a different profile.\n";
return false;
}
if (_cg_gprogram != 0 && _cg_gprofile != caps._active_gprofile) {
gobj_cat.error() << "Cg vertex program not supported by profile "
<< cgGetProfileString((CGprofile) caps._active_gprofile) << ": "
<< get_filename(ST_fragment) << ". Try choosing a different profile.\n";
return false;
}
// Build a parameter map.
@ -1854,6 +1878,43 @@ cg_compile_for(const ShaderCaps &caps,
}
#endif // HAVE_CG
////////////////////////////////////////////////////////////////////
// Function: Shader::Constructor
// Access: Private
// Description: Construct a Shader that will be filled in using
// fillin() later.
////////////////////////////////////////////////////////////////////
Shader::
Shader() :
_error_flag(false),
_text(NULL),
_filename(NULL),
_parse(0),
_loaded(false),
_language(SL_none)
{
#ifdef HAVE_CG
_cg_context = 0;
_cg_vprogram = 0;
_cg_fprogram = 0;
_cg_gprogram = 0;
_cg_vprofile = CG_PROFILE_UNKNOWN;
_cg_fprofile = CG_PROFILE_UNKNOWN;
_cg_gprofile = CG_PROFILE_UNKNOWN;
if (_default_caps._ultimate_vprofile == 0 || _default_caps._ultimate_vprofile == CG_PROFILE_UNKNOWN) {
_default_caps._active_vprofile = CG_PROFILE_UNKNOWN;
_default_caps._active_fprofile = CG_PROFILE_UNKNOWN;
_default_caps._active_gprofile = CG_PROFILE_UNKNOWN;
_default_caps._ultimate_vprofile = cgGetProfile("glslv");
_default_caps._ultimate_fprofile = cgGetProfile("glslf");
_default_caps._ultimate_gprofile = cgGetProfile("glslg");
if (_default_caps._ultimate_gprofile == CG_PROFILE_UNKNOWN) {
_default_caps._ultimate_gprofile = cgGetProfile("gp4gp");
}
}
#endif
}
////////////////////////////////////////////////////////////////////
// Function: Shader::Constructor
// Access: Private
@ -1861,15 +1922,13 @@ cg_compile_for(const ShaderCaps &caps,
////////////////////////////////////////////////////////////////////
Shader::
Shader(CPT(ShaderFile) filename, CPT(ShaderFile) text, const ShaderLanguage &lang) :
_error_flag(true),
_error_flag(false),
_text(text),
_filename(filename),
_parse(0),
_loaded(false),
_language(lang)
{
_error_flag = false;
#ifdef HAVE_CG
_cg_context = 0;
_cg_vprogram = 0;
@ -2466,10 +2525,64 @@ clear() {
////////////////////////////////////////////////////////////////////
// Function: Shader::register_with_read_factory
// Access: Public, Static
// Description:
// Description: Tells the BamReader how to create objects of type
// Shader.
////////////////////////////////////////////////////////////////////
void Shader::
register_with_read_factory() {
// IMPLEMENT ME
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: Shader::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void Shader::
write_datagram(BamWriter *manager, Datagram &dg) {
dg.add_uint8(_language);
dg.add_bool(_loaded);
_filename->write_datagram(dg);
_text->write_datagram(dg);
}
////////////////////////////////////////////////////////////////////
// Function: Shader::make_from_bam
// Access: Protected, Static
// Description: This function is called by the BamReader's factory
// when a new object of type Shader is encountered
// in the Bam file. It should create the Shader
// and extract its information from the file.
////////////////////////////////////////////////////////////////////
TypedWritable *Shader::
make_from_bam(const FactoryParams &params) {
Shader *attrib = new Shader;
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
attrib->fillin(scan, manager);
return attrib;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::fillin
// Access: Protected
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new Shader.
////////////////////////////////////////////////////////////////////
void Shader::
fillin(DatagramIterator &scan, BamReader *manager) {
_language = (ShaderLanguage) scan.get_uint8();
_loaded = scan.get_bool();
PT(ShaderFile) filename = new ShaderFile;
filename->read_datagram(scan);
_filename = filename;
PT(ShaderFile) text = new ShaderFile;
text->read_datagram(scan);
_text = text;
}

View File

@ -16,7 +16,7 @@
#define SHADER_H
#include "pandabase.h"
#include "typedReferenceCount.h"
#include "typedWritableReferenceCount.h"
#include "namable.h"
#include "graphicsStateGuardianBase.h"
#include "internalName.h"
@ -44,10 +44,8 @@ typedef struct _CGparameter *CGparameter;
// finally compile and store the shader parameters
// in the appropriate structure.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_GOBJ Shader: public TypedReferenceCount {
class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount {
PUBLISHED:
enum ShaderLanguage {
SL_none,
SL_Cg,
@ -110,7 +108,6 @@ PUBLISHED:
GraphicsStateGuardianBase *gsg);
public:
enum ShaderMatInput {
SMO_identity,
@ -311,6 +308,9 @@ public:
INLINE ShaderPtrData(const LVecBase2d &vec);
INLINE ShaderPtrData(const LMatrix4d &mat);
INLINE ShaderPtrData(const LMatrix3d &mat);
INLINE void write_datagram(Datagram &dg) const;
INLINE void read_datagram(DatagramIterator &source);
};
struct ShaderMatSpec {
@ -372,22 +372,16 @@ public:
class ShaderFile : public ReferenceCount {
public:
ShaderFile(const string &shared) {
_separate = false;
_shared = shared;
}
ShaderFile(const string &vertex,
const string &fragment,
const string &geometry,
const string &tess_control,
const string &tess_evaluation) {
_separate = true;
_vertex = vertex;
_fragment = fragment;
_geometry = geometry;
_tess_control = tess_control;
_tess_evaluation = tess_evaluation;
}
INLINE ShaderFile() {};
INLINE ShaderFile(const string &shared);
INLINE ShaderFile(const string &vertex,
const string &fragment,
const string &geometry,
const string &tess_control,
const string &tess_evaluation);
INLINE void write_datagram(Datagram &dg) const;
INLINE void read_datagram(DatagramIterator &source);
public:
bool _separate;
@ -399,7 +393,7 @@ public:
string _tess_evaluation;
};
public:
public:
// These routines help split the shader into sections,
// for those shader implementations that need to do so.
// Don't use them when you use separate shader programs.
@ -446,23 +440,23 @@ public:
void clear_parameters();
#ifdef HAVE_CG
private:
ShaderArgClass cg_parameter_class(CGparameter p);
ShaderArgType cg_parameter_type(CGparameter p);
ShaderArgDir cg_parameter_dir(CGparameter p);
private:
ShaderArgClass cg_parameter_class(CGparameter p);
ShaderArgType cg_parameter_type(CGparameter p);
ShaderArgDir cg_parameter_dir(CGparameter p);
CGprogram cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType type = ST_vertex);
CGprogram cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType type = ST_vertex);
bool cg_analyze_entry_point(CGprogram prog, ShaderType type);
bool cg_analyze_entry_point(CGprogram prog, ShaderType type);
bool cg_analyze_shader(const ShaderCaps &caps);
bool cg_compile_shader(const ShaderCaps &caps);
void cg_release_resources();
void cg_report_errors();
bool cg_analyze_shader(const ShaderCaps &caps);
bool cg_compile_shader(const ShaderCaps &caps);
void cg_release_resources();
void cg_report_errors();
// Determines the appropriate cg profile settings and stores them in the active shader caps
// based on any profile settings stored in the shader's header
void cg_get_profile_from_header(ShaderCaps &caps);
void cg_get_profile_from_header(ShaderCaps &caps);
ShaderCaps _cg_last_caps;
CGcontext _cg_context;
@ -470,36 +464,33 @@ public:
CGprogram _cg_fprogram;
CGprogram _cg_gprogram;
int _cg_vprofile;
int _cg_fprofile;
int _cg_gprofile;
int _cg_vprofile;
int _cg_fprofile;
int _cg_gprofile;
CGprogram cg_program_from_shadertype(ShaderType type);
CGprogram cg_program_from_shadertype(ShaderType type);
public:
public:
bool cg_compile_for(const ShaderCaps &caps,
CGcontext &ctx,
CGprogram &vprogram,
CGprogram &fprogram,
CGprogram &gprogram,
pvector<CGparameter> &map);
bool cg_compile_for(const ShaderCaps &caps, CGcontext &ctx,
CGprogram &vprogram, CGprogram &fprogram,
CGprogram &gprogram, pvector<CGparameter> &map);
#endif
public:
public:
pvector <ShaderPtrSpec> _ptr_spec;
epvector <ShaderMatSpec> _mat_spec;
pvector <ShaderTexSpec> _tex_spec;
pvector <ShaderVarSpec> _var_spec;
bool _error_flag;
bool _error_flag;
CPT(ShaderFile) _text;
protected:
protected:
CPT(ShaderFile) _filename;
int _parse;
bool _loaded;
int _parse;
bool _loaded;
ShaderLanguage _language;
static ShaderCaps _default_caps;
@ -517,30 +508,38 @@ public:
typedef pmap <PreparedGraphicsObjects *, ShaderContext *> Contexts;
Contexts _contexts;
private:
private:
void clear_prepared(PreparedGraphicsObjects *prepared_objects);
public:
Shader();
public:
Shader(CPT(ShaderFile) name, CPT(ShaderFile) text, const ShaderLanguage &lang = SL_none);
static void register_with_read_factory();
~Shader();
public:
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
void fillin(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedReferenceCount::init_type();
TypedWritableReferenceCount::init_type();
register_type(_type_handle, "Shader",
TypedReferenceCount::get_class_type());
TypedWritableReferenceCount::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
private:
static TypeHandle _type_handle;
};