More robust Cg support on non-NVIDIA card + automatically enable hardware skinning in Shader Generator

This commit is contained in:
rdb 2015-07-07 02:51:48 +02:00
parent 1088cdedc8
commit ef9908c277
14 changed files with 659 additions and 216 deletions

View File

@ -814,17 +814,12 @@ dispatch_compute(int num_groups_x, int num_groups_y, int num_groups_z) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
PT(GeomMunger) GraphicsStateGuardian:: PT(GeomMunger) GraphicsStateGuardian::
get_geom_munger(const RenderState *state, Thread *current_thread) { get_geom_munger(const RenderState *state, Thread *current_thread) {
// We can cast the RenderState to a non-const object because we are
// only updating a cache within the RenderState, not really changing
// any of its properties.
RenderState *nc_state = ((RenderState *)state);
// Before we even look up the map, see if the _last_mi value points // Before we even look up the map, see if the _last_mi value points
// to this GSG. This is likely because we tend to visit the same // to this GSG. This is likely because we tend to visit the same
// state multiple times during a frame. Also, this might well be // state multiple times during a frame. Also, this might well be
// the only GSG in the world anyway. // the only GSG in the world anyway.
if (!nc_state->_mungers.empty()) { if (!state->_mungers.empty()) {
RenderState::Mungers::const_iterator mi = nc_state->_last_mi; RenderState::Mungers::const_iterator mi = state->_last_mi;
if (!(*mi).first.was_deleted() && (*mi).first == this) { if (!(*mi).first.was_deleted() && (*mi).first == this) {
if ((*mi).second->is_registered()) { if ((*mi).second->is_registered()) {
return (*mi).second; return (*mi).second;
@ -833,23 +828,23 @@ get_geom_munger(const RenderState *state, Thread *current_thread) {
} }
// Nope, we have to look it up in the map. // Nope, we have to look it up in the map.
RenderState::Mungers::iterator mi = nc_state->_mungers.find(this); RenderState::Mungers::iterator mi = state->_mungers.find(this);
if (mi != nc_state->_mungers.end() && !(*mi).first.was_deleted()) { if (mi != state->_mungers.end() && !(*mi).first.was_deleted()) {
if ((*mi).second->is_registered()) { if ((*mi).second->is_registered()) {
nc_state->_last_mi = mi; state->_last_mi = mi;
return (*mi).second; return (*mi).second;
} }
// This GeomMunger is no longer registered. Remove it from the // This GeomMunger is no longer registered. Remove it from the
// map. // map.
nc_state->_mungers.erase(mi); state->_mungers.erase(mi);
} }
// Nothing in the map; create a new entry. // Nothing in the map; create a new entry.
PT(GeomMunger) munger = make_geom_munger(nc_state, current_thread); PT(GeomMunger) munger = make_geom_munger(state, current_thread);
nassertr(munger != (GeomMunger *)NULL && munger->is_registered(), munger); nassertr(munger != (GeomMunger *)NULL && munger->is_registered(), munger);
mi = nc_state->_mungers.insert(RenderState::Mungers::value_type(this, munger)).first; mi = state->_mungers.insert(RenderState::Mungers::value_type(this, munger)).first;
nc_state->_last_mi = mi; state->_last_mi = mi;
return munger; return munger;
} }

View File

@ -131,7 +131,8 @@ munge_data_impl(const GeomVertexData *data) {
} }
GeomVertexAnimationSpec animation = new_data->get_format()->get_animation(); GeomVertexAnimationSpec animation = new_data->get_format()->get_animation();
if (_shader_skinning) { if (_shader_skinning || (_auto_shader && hardware_animated_vertices &&
!basic_shaders_only && animation.get_animation_type() == AT_panda)) {
animation.set_hardware(4, true); animation.set_hardware(4, true);
} else if (hardware_animated_vertices && } else if (hardware_animated_vertices &&
@ -387,7 +388,17 @@ munge_state_impl(const RenderState *state) {
} }
if (shader_state->_generated_shader == NULL) { if (shader_state->_generated_shader == NULL) {
// Cache the generated ShaderAttrib on the shader state. // Cache the generated ShaderAttrib on the shader state.
shader_state->_generated_shader = shader_generator->synthesize_shader(shader_state); GeomVertexAnimationSpec spec;
// Currently we overload this flag to request vertex animation
// for the shader generator.
const ShaderAttrib *sattr;
shader_state->get_attrib_def(sattr);
if (sattr->get_flag(ShaderAttrib::F_hardware_skinning)) {
spec.set_hardware(4, true);
}
shader_state->_generated_shader = shader_generator->synthesize_shader(shader_state, spec);
} }
munged_state = munged_state->set_attrib(shader_state->_generated_shader); munged_state = munged_state->set_attrib(shader_state->_generated_shader);
} }

View File

@ -41,6 +41,11 @@ CLP(CgShaderContext)::
CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext(s) { CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext(s) {
_glgsg = glgsg; _glgsg = glgsg;
_cg_program = 0; _cg_program = 0;
_glsl_program = 0;
_has_divisor = false;
_color_attrib_index = CA_color;
_transform_table_param = 0;
_slider_table_param = 0;
nassertv(s->get_language() == Shader::SL_Cg); nassertv(s->get_language() == Shader::SL_Cg);
@ -53,6 +58,21 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
return; return;
} }
_transform_table_param = cgGetNamedParameter(_cg_program, "tbl_transforms");
if (_transform_table_param) {
_transform_table_size = cgGetArraySize(_transform_table_param, 0);
}
_slider_table_param = cgGetNamedParameter(_cg_program, "tbl_sliders");
if (_slider_table_param) {
_slider_table_size = cgGetArraySize(_slider_table_param, 0);
}
if (GLCAT.is_debug()) {
GLCAT.debug()
<< "Loading Cg shader " << s->get_filename() << "\n";
}
// Load the program. // Load the program.
if (_cg_program == 0) { if (_cg_program == 0) {
const char *str = cgGetErrorString(cgGetError()); const char *str = cgGetErrorString(cgGetError());
@ -73,6 +93,214 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
} }
} }
if (_cg_program != 0) {
if (cgGetProgramProfile(_cg_program) == CG_PROFILE_GLSLC) {
_glsl_program = cgGLGetProgramID(_cg_program);
// Sometimes it fails to link, and Cg fails to propagate the error.
GLint link_status;
_glgsg->_glGetProgramiv(_glsl_program, GL_LINK_STATUS, &link_status);
if (link_status != GL_TRUE) {
release_resources();
}
}
}
if (_cg_program == 0) {
return;
}
// We don't use cgGLSetParameterPointer to set the vertex attributes any
// longer, since it is buggy on non-NVIDIA hardware and doesn't allow explicit
// control over some parameters. Instead, we have to figure out ourselves how
// to map the input varyings to OpenGL vertex attributes.
//
// We use positive indices to indicate generic vertex attributes, and negative
// indices to indicate conventional vertex attributes (ie. glVertexPointer).
int nvarying = _shader->_var_spec.size();
for (int i = 0; i < nvarying; ++i) {
Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
CGparameter p = _cg_parameter_map[i];
if (p == 0) {
bind._id._seqno = CA_unknown;
continue;
}
GLint loc = CA_unknown;
CGresource res = cgGetParameterResource(p);
if (cgGetParameterBaseResource(p) == CG_ATTR0) {
// The Cg toolkit claims that it is bound to a generic vertex attribute.
if (_glsl_program != 0) {
// This is where the Cg glslv compiler lies, making the stupid assumption
// that we're using an NVIDIA card where generic attributes are aliased
// with conventional vertex attributes. Instead, it always uses
// conventional attributes in this case. Correct this.
int index = cgGetParameterResourceIndex(p);
switch (index) {
case 0: // gl_Vertex
loc = CA_vertex;
break;
case 2: // gl_Normal
loc = CA_normal;
break;
case 3: // gl_Color
loc = CA_color;
break;
case 4: // gl_SecondaryColor
loc = CA_secondary_color;
break;
case 1: // glWeightPointerARB?
case 5: // gl_FogCoord
case 6: // PSIZE?
case 7: // BLENDINDICES
GLCAT.error()
<< "Cg varying " << cgGetParameterName(p) << " is bound to "
"unrecognized attribute " << index << "\n";
loc = CA_unknown;
break;
default:
loc = CA_texcoord + (index - 8);
break;
}
} else {
loc = cgGetParameterResourceIndex(p);
if (loc != 0 && bind._id._name == "vtx_position") {
// We really have to bind the vertex position to attribute 0, since
// OpenGL will hide the model if attribute 0 is not enabled, and we
// can only ever be sure that vtx_position is bound.
GLCAT.warning()
<< "CG varying vtx_position is bound to generic attribute " << loc
<< "instead of 0. Use ATTR0 semantic to prevent this.\n";
}
}
} else if (res == CG_GLSL_ATTRIB || _glsl_program != 0) {
// With cg-glsl-version 130 and higher, no conventional attributes are
// used, but it instead uses specially named variables.
// A bit of guesswork is involved here; Cg seems to mostly use the
// semantics as attribute names in GLSL, with a few exceptions.
const char *attribname = NULL;
switch (res) {
case CG_POSITION0:
attribname = "cg_Vertex";
break;
case CG_NORMAL0:
attribname = "NORMAL";
break;
case CG_COLOR0:
case CG_DIFFUSE0:
attribname = "COLOR";
break;
case CG_COLOR1:
case CG_SPECULAR0:
attribname = "SPECULAR";
break;
default:
// Everything else appears to be named after the semantic string.
attribname = cgGetParameterSemantic(p);
}
loc = _glgsg->_glGetAttribLocation(_glsl_program, attribname);
if (bind._id._name == "vtx_color") {
_color_attrib_index = loc;
}
if (loc == -1) {
const char *resource = cgGetParameterResourceName(p);
if (!resource) {
resource = "unknown";
}
GLCAT.error()
<< "Could not find Cg varying " << cgGetParameterName(p);
if (attribname) {
GLCAT.error(false) << " : " << attribname;
}
GLCAT.error(false) << " (" << resource << ") in the compiled GLSL program.\n";
} else if (loc != 0 && bind._id._name == "vtx_position") {
// We really have to bind the vertex position to attribute 0, since
// OpenGL will hide the model if attribute 0 is not enabled, and we
// can only ever be sure that vtx_position is bound.
GLCAT.warning()
<< "CG varying vtx_position is bound to generic attribute " << loc
<< "instead of 0. Use ATTR0 semantic to prevent this.\n";
}
} else if (cgGetParameterBaseResource(p) == CG_TEXCOORD0) {
// A conventional texture coordinate set.
loc = CA_texcoord + cgGetParameterResourceIndex(p);
} else {
// Some other conventional vertex attribute.
switch (res) {
case CG_POSITION0:
loc = CA_vertex;
break;
case CG_NORMAL0:
loc = CA_normal;
break;
case CG_COLOR0:
case CG_DIFFUSE0:
loc = CA_color;
break;
case CG_COLOR1:
case CG_SPECULAR0:
loc = CA_secondary_color;
break;
default:
GLCAT.error()
<< "Cg varying " << cgGetParameterName(p);
if (cgGetParameterSemantic(p)) {
GLCAT.error(false) << " : " << cgGetParameterSemantic(p);
}
GLCAT.error(false) << " has an unrecognized resource";
if (cgGetParameterResourceName(p)) {
GLCAT.error(false) << " (" << cgGetParameterResourceName(p) << ")";
}
GLCAT.error(false) << ".\n";
loc = CA_unknown;
}
}
#ifndef NDEBUG
if (GLCAT.is_debug()) {
GLCAT.debug()
<< "Cg varying " << cgGetParameterName(p);
const char *semantic = cgGetParameterSemantic(p);
if (semantic) {
GLCAT.debug(false) << " : " << semantic;
}
if (loc == CA_unknown) {
GLCAT.debug(false)
<< " is not bound to a vertex attribute\n";
} else if (loc >= 0) {
GLCAT.debug(false)
<< " is bound to generic attribute " << loc << "\n";
} else {
const char *resource = cgGetParameterResourceName(p);
if (!resource) {
resource = "unknown";
}
GLCAT.debug(false)
<< " is bound to a conventional attribute (" << resource << ")\n";
}
}
if (loc == CA_unknown) {
// Suggest fix to developer.
GLCAT.error() << "Try using a different semantic.\n";
}
#endif
// Abuse the seqno field to store the GLSL attribute location.
bind._id._seqno = loc;
}
_glgsg->report_my_gl_errors(); _glgsg->report_my_gl_errors();
} }
@ -385,6 +613,58 @@ issue_parameters(int altered) {
_glgsg->report_my_gl_errors(); _glgsg->report_my_gl_errors();
} }
////////////////////////////////////////////////////////////////////
// Function: CgGLShaderContext::update_transform_table
// Access: Public
// Description: Changes the active transform table, used for hardware
// skinning.
////////////////////////////////////////////////////////////////////
void CLP(CgShaderContext)::
update_transform_table(const TransformTable *table) {
LMatrix4f *matrices = (LMatrix4f *)alloca(_transform_table_size * 64);
int i = 0;
if (table != NULL) {
int num_transforms = min(_transform_table_size, (long)table->get_num_transforms());
for (; i < num_transforms; ++i) {
#ifdef STDFLOAT_DOUBLE
LMatrix4 matrix;
table->get_transform(i)->get_matrix(matrix);
matrices[i] = LCAST(float, matrix);
#else
table->get_transform(i)->get_matrix(matrices[i]);
#endif
}
}
for (; i < _transform_table_size; ++i) {
matrices[i] = LMatrix4f::ident_mat();
}
cgGLSetMatrixParameterArrayfc(_transform_table_param, 0,
_transform_table_size, (float *)matrices);
}
////////////////////////////////////////////////////////////////////
// Function: CgGLShaderContext::update_slider_table
// Access: Public
// Description: Changes the active slider table, used for hardware
// skinning.
////////////////////////////////////////////////////////////////////
void CLP(CgShaderContext)::
update_slider_table(const SliderTable *table) {
float *sliders = (float *)alloca(_slider_table_size * 4);
memset(sliders, 0, _slider_table_size * 4);
if (table != NULL) {
int num_sliders = min(_slider_table_size, (long)table->get_num_sliders());
for (int i = 0; i < num_sliders; ++i) {
sliders[i] = table->get_slider(i)->get_slider();
}
}
cgGLSetParameterArray4f(_slider_table_param, 0, _slider_table_size, sliders);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: GLCgShaderContext::disable_shader_vertex_arrays // Function: GLCgShaderContext::disable_shader_vertex_arrays
// Access: Public // Access: Public
@ -396,27 +676,35 @@ disable_shader_vertex_arrays() {
return; return;
} }
for (int i=0; i<(int)_shader->_var_spec.size(); i++) { for (int i = 0; i < (int)_shader->_var_spec.size(); ++i) {
CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno]; GLint p = _shader->_var_spec[i]._id._seqno;
if (p == 0) continue;
if (cgGetParameterBaseResource(p) == CG_ATTR0) { if (p >= 0) {
int index = cgGetParameterResourceIndex(p); _glgsg->_glDisableVertexAttribArray(p);
if (index >= 8) { if (_has_divisor) {
_glgsg->_glClientActiveTexture(GL_TEXTURE0 + (index - 8)); _glgsg->_glVertexAttribDivisor(p, 0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
} else if (index == 0) {
glDisableClientState(GL_VERTEX_ARRAY);
} else if (index == 2) {
glDisableClientState(GL_NORMAL_ARRAY);
} else if (index == 3) {
glDisableClientState(GL_COLOR_ARRAY);
} }
} else { } else {
cgGLDisableClientState(p); switch (p) {
case CA_unknown:
break;
case CA_vertex:
glDisableClientState(GL_VERTEX_ARRAY);
break;
case CA_normal:
glDisableClientState(GL_NORMAL_ARRAY);
break;
case CA_color:
glDisableClientState(GL_COLOR_ARRAY);
break;
case CA_secondary_color:
glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
break;
default:
_glgsg->_glClientActiveTexture(GL_TEXTURE0 + (p - CA_texcoord));
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
break;
}
} }
} }
@ -458,12 +746,9 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
int start, stride, num_values; int start, stride, num_values;
int nvarying = _shader->_var_spec.size(); int nvarying = _shader->_var_spec.size();
for (int i = 0; i < nvarying; ++i) { for (int i = 0; i < nvarying; ++i) {
if (_cg_parameter_map[_shader->_var_spec[i]._id._seqno] == 0) { const Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
continue; InternalName *name = bind._name;
} int texslot = bind._append_uv;
InternalName *name = _shader->_var_spec[i]._name;
int texslot = _shader->_var_spec[i]._append_uv;
if (texslot >= 0 && texslot < _glgsg->_state_texture->get_num_on_stages()) { if (texslot >= 0 && texslot < _glgsg->_state_texture->get_num_on_stages()) {
TextureStage *stage = _glgsg->_state_texture->get_on_stage(texslot); TextureStage *stage = _glgsg->_state_texture->get_on_stage(texslot);
InternalName *texname = stage->get_texcoord_name(); InternalName *texname = stage->get_texcoord_name();
@ -474,84 +759,146 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
name = name->append(texname->get_basename()); name = name->append(texname->get_basename());
} }
} }
if (_glgsg->_data_reader->get_array_info(name, GLint p = bind._id._seqno;
array_reader, num_values, numeric_type,
start, stride)) { // Don't apply vertex colors if they are disabled with a ColorAttrib.
int num_elements, element_stride, divisor;
bool normalized;
if ((p != _color_attrib_index || _glgsg->_vertex_colors_enabled) &&
_glgsg->_data_reader->get_array_info(name, array_reader,
num_values, numeric_type,
normalized, start, stride, divisor,
num_elements, element_stride)) {
const unsigned char *client_pointer; const unsigned char *client_pointer;
if (!_glgsg->setup_array_data(client_pointer, array_reader, force)) { if (!_glgsg->setup_array_data(client_pointer, array_reader, force)) {
return false; return false;
} }
client_pointer += start;
CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno]; // We don't use cgGLSetParameterPointer because it is very buggy and
// limited in the options we can set.start
GLenum type = _glgsg->get_numeric_type(numeric_type);
if (p >= 0) {
_glgsg->_glEnableVertexAttribArray(p);
if (numeric_type == GeomEnums::NT_packed_dabc) { if (bind._integer) {
// Yes, this is a thing. _glgsg->_glVertexAttribIPointer(p, num_values, type,
num_values = GL_BGRA; stride, client_pointer);
} } else if (numeric_type == GeomEnums::NT_packed_dabc) {
// GL_BGRA is a special accepted value available since OpenGL 3.2.
// It requires us to pass GL_TRUE for normalized.
_glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
GL_TRUE, stride, client_pointer);
} else {
_glgsg->_glVertexAttribPointer(p, num_values, type,
normalized, stride, client_pointer);
}
// cgGLSetParameterPointer is just stupidly bugged on every level. if (_glgsg->_supports_vertex_attrib_divisor) {
// Sigh. This seems to work on both NVIDIA and AMD cards now. _glgsg->_glVertexAttribDivisor(p, divisor);
if (cgGetParameterBaseResource(p) == CG_ATTR0) { _has_divisor = true;
int index = cgGetParameterResourceIndex(p); }
switch (index) {
case 0: // gl_Vertex } else {
glVertexPointer(num_values, _glgsg->get_numeric_type(numeric_type), // It's a conventional vertex attribute. Ugh.
stride, client_pointer + start); switch (p) {
case CA_unknown:
break;
case CA_vertex:
glVertexPointer(num_values, type, stride, client_pointer);
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_VERTEX_ARRAY);
break; break;
case 2: // gl_Normal case CA_normal:
glNormalPointer(_glgsg->get_numeric_type(numeric_type), glNormalPointer(type, stride, client_pointer);
stride, client_pointer + start);
glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_NORMAL_ARRAY);
break; break;
case 3: // gl_Color case CA_color:
glColorPointer(num_values, _glgsg->get_numeric_type(numeric_type), glColorPointer(num_values, type, stride, client_pointer);
stride, client_pointer + start);
glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_COLOR_ARRAY);
break; break;
case 4: // gl_SecondaryColor case CA_secondary_color:
//glSecondaryColorPointer(num_values, _glgsg->get_numeric_type(numeric_type), _glgsg->_glSecondaryColorPointer(num_values, type,
// stride, client_pointer + start); stride, client_pointer);
//glEnableClientState(GL_SECONDARY_COLOR_ARRAY); glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
//break;
case 5: // gl_FogCoord
case 6: // PSIZE?
case 7: // BLENDINDICES?
case 1: // glWeightPointerARB?
GLCAT.error()
<< "Unable to bind " << *name << " to "
<< cgGetParameterResourceName(p) << "\n";
break; break;
default: default:
_glgsg->_glClientActiveTexture(GL_TEXTURE0 + (index - 8)); _glgsg->_glClientActiveTexture(GL_TEXTURE0 + (p - CA_texcoord));
glTexCoordPointer(num_values, _glgsg->get_numeric_type(numeric_type), glTexCoordPointer(num_values, type, stride, client_pointer);
stride, client_pointer + start);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
break; break;
} }
} else {
if (name == InternalName::get_normal() && num_values == 4) {
// In some cases, the normals are aligned to 4 values. We tell
// it to use three values exactly, otherwise we get the error:
// An unsupported GL extension was required to perform this operation.
num_values = 3;
}
cgGLSetParameterPointer(p, num_values,
_glgsg->get_numeric_type(numeric_type),
stride, client_pointer + start);
cgGLEnableClientState(p);
} }
} else { } else {
CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno]; // There is no vertex column with this name; disable the attribute array.
cgGLDisableClientState(p); if (p == 0) {
//NOTE: if we disable attribute 0 in compatibility profile, the object
// will disappear. In GLSL we fix this by forcing the vertex column
// to be at 0, but we don't have control over that with Cg. So, we
// work around this by just binding something silly to 0.
// This breaks flat colors, but it's better than invisible objects?
_glgsg->_glEnableVertexAttribArray(0);
if (bind._integer) {
_glgsg->_glVertexAttribIPointer(0, 4, GL_INT, 0, 0);
} else {
_glgsg->_glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
}
} else if (p > 0) {
_glgsg->_glDisableVertexAttribArray(p);
if (p == _color_attrib_index) {
#ifdef STDFLOAT_DOUBLE
_glgsg->_glVertexAttrib4dv(p, _glgsg->_scene_graph_color.get_data());
#else
_glgsg->_glVertexAttrib4fv(p, _glgsg->_scene_graph_color.get_data());
#endif
}
} else {
switch (p) {
case CA_unknown:
break;
case CA_vertex:
glDisableClientState(GL_VERTEX_ARRAY);
break;
case CA_normal:
glDisableClientState(GL_NORMAL_ARRAY);
break;
case CA_color:
glDisableClientState(GL_COLOR_ARRAY);
#ifdef STDFLOAT_DOUBLE
glColor4dv(_glgsg->_scene_graph_color.get_data());
#else
glColor4fv(_glgsg->_scene_graph_color.get_data());
#endif
break;
case CA_secondary_color:
glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
break;
default:
_glgsg->_glClientActiveTexture(GL_TEXTURE0 + (p - CA_texcoord));
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
break;
}
}
} }
} }
} }
if (_transform_table_param) {
const TransformTable *table = _glgsg->_data_reader->get_transform_table();
update_transform_table(table);
}
if (_slider_table_param) {
const SliderTable *table = _glgsg->_data_reader->get_slider_table();
update_slider_table(table);
}
cg_report_errors(); cg_report_errors();
_glgsg->report_my_gl_errors(); _glgsg->report_my_gl_errors();

View File

@ -41,6 +41,8 @@ public:
void bind(bool reissue_parameters = true); void bind(bool reissue_parameters = true);
void unbind(); void unbind();
void issue_parameters(int altered); void issue_parameters(int altered);
void update_transform_table(const TransformTable *table);
void update_slider_table(const SliderTable *table);
void disable_shader_vertex_arrays(); void disable_shader_vertex_arrays();
bool update_shader_vertex_arrays(ShaderContext *prev, bool force); bool update_shader_vertex_arrays(ShaderContext *prev, bool force);
void disable_shader_texture_bindings(); void disable_shader_texture_bindings();
@ -50,13 +52,32 @@ public:
INLINE bool uses_custom_vertex_arrays(void); INLINE bool uses_custom_vertex_arrays(void);
INLINE bool uses_custom_texture_bindings(void); INLINE bool uses_custom_texture_bindings(void);
// Special values for location to indicate conventional attrib slots.
enum ConventionalAttrib {
CA_unknown = -1,
CA_vertex = -2,
CA_normal = -3,
CA_color = -4,
CA_secondary_color = -5,
CA_texcoord = -32,
};
private: private:
CGprogram _cg_program; CGprogram _cg_program;
GLuint _glsl_program;
GLint _color_attrib_index;
CGparameter _transform_table_param;
CGparameter _slider_table_param;
long _transform_table_size;
long _slider_table_size;
pvector<CGparameter> _cg_parameter_map; pvector<CGparameter> _cg_parameter_map;
CLP(GraphicsStateGuardian) *_glgsg; CLP(GraphicsStateGuardian) *_glgsg;
bool _has_divisor;
void release_resources(); void release_resources();
public: public:

View File

@ -599,6 +599,17 @@ reset() {
} }
#endif #endif
#ifndef OPENGLES
if (is_at_least_gl_version(1, 4)) {
_glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)
get_extension_func("glSecondaryColorPointer");
} else if (has_extension("GL_EXT_secondary_color")) {
_glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)
get_extension_func("glSecondaryColorPointerEXT");
}
#endif
#ifdef OPENGLES_2 #ifdef OPENGLES_2
_supports_vertex_blend = false; _supports_vertex_blend = false;
#else #else
@ -7121,6 +7132,7 @@ get_extension_func(const char *name) {
#endif #endif
#ifdef EXPECT_GL_VERSION_1_4 #ifdef EXPECT_GL_VERSION_1_4
{ "glPointParameterfv", (void *)&glPointParameterfv }, { "glPointParameterfv", (void *)&glPointParameterfv },
{ "glSecondaryColorPointer", (void *)&glSecondaryColorPointer },
#endif #endif
#ifdef EXPECT_GL_VERSION_1_5 #ifdef EXPECT_GL_VERSION_1_5
{ "glBeginQuery", (void *)&glBeginQuery }, { "glBeginQuery", (void *)&glBeginQuery },

View File

@ -103,6 +103,7 @@ typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face); typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);
typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count); typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count);
typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights); typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);
@ -662,6 +663,10 @@ public:
bool _explicit_primitive_restart; bool _explicit_primitive_restart;
#endif #endif
#ifndef OPENGLES
PFNGLSECONDARYCOLORPOINTERPROC _glSecondaryColorPointer;
#endif
bool _supports_vertex_blend; bool _supports_vertex_blend;
PFNGLWEIGHTPOINTERARBPROC _glWeightPointer; PFNGLWEIGHTPOINTERARBPROC _glWeightPointer;
PFNGLVERTEXBLENDARBPROC _glVertexBlend; PFNGLVERTEXBLENDARBPROC _glVertexBlend;

View File

@ -49,7 +49,7 @@ get_filename(const ShaderType &type) const {
} else { } else {
// Um, better than nothing? // Um, better than nothing?
return _filename._vertex; return _filename._fragment;
} }
} }

View File

@ -553,6 +553,7 @@ cg_recurse_parameters(CGparameter parameter, const ShaderType &type,
ShaderArgClass arg_subclass = arg_class; ShaderArgClass arg_subclass = arg_class;
CGenum vbl = cgGetParameterVariability(parameter); CGenum vbl = cgGetParameterVariability(parameter);
CGtype base_type = cgGetParameterBaseType(parameter);
if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) { if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) {
switch (cgGetParameterType(parameter)) { switch (cgGetParameterType(parameter)) {
@ -567,16 +568,28 @@ cg_recurse_parameters(CGparameter parameter, const ShaderType &type,
arg_dim[0] = cgGetArraySize(parameter, 0); arg_dim[0] = cgGetArraySize(parameter, 0);
// Fall through
default: { default: {
arg_dim[1] = cgGetParameterRows(parameter); arg_dim[1] = cgGetParameterRows(parameter);
arg_dim[2] = cgGetParameterColumns(parameter); arg_dim[2] = cgGetParameterColumns(parameter);
ShaderArgId id; ShaderArgInfo p;
id._name = cgGetParameterName(parameter); p._id._name = cgGetParameterName(parameter);
id._type = type; p._id._type = type;
id._seqno = -1; p._id._seqno = -1;
success &= compile_parameter(id, arg_class, arg_subclass, arg_type, p._class = arg_class;
arg_dir, (vbl == CG_VARYING), arg_dim, shader_cat.get_safe_ptr()); break; p._subclass = arg_subclass;
p._type = arg_type;
p._direction = arg_dir;
p._varying = (vbl == CG_VARYING);
p._integer = (base_type == CG_UINT || base_type == CG_INT ||
base_type == CG_ULONG || base_type == CG_LONG ||
base_type == CG_USHORT || base_type == CG_SHORT ||
base_type == CG_UCHAR || base_type == CG_CHAR);
p._cat = shader_cat.get_safe_ptr();
success &= compile_parameter(p, arg_dim);
break;
} }
} }
} }
@ -601,24 +614,7 @@ cg_recurse_parameters(CGparameter parameter, const ShaderType &type,
// an error message onto the error messages. // an error message onto the error messages.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool Shader:: bool Shader::
compile_parameter(const ShaderArgId &arg_id, compile_parameter(ShaderArgInfo &p, int *arg_dim) {
const ShaderArgClass &arg_class,
const ShaderArgClass &arg_subclass,
const ShaderArgType &arg_type,
const ShaderArgDir &arg_direction,
bool arg_varying,
int *arg_dim,
NotifyCategory *arg_cat)
{
ShaderArgInfo p;
p._id = arg_id;
p._class = arg_class;
p._subclass = arg_subclass;
p._type = arg_type;
p._direction = arg_direction;
p._varying = arg_varying;
p._cat = arg_cat;
if (p._id._name.size() == 0) return true; if (p._id._name.size() == 0) return true;
if (p._id._name[0] == '$') return true; if (p._id._name[0] == '$') return true;
@ -650,9 +646,9 @@ compile_parameter(const ShaderArgId &arg_id,
return false; return false;
} }
ShaderVarSpec bind; ShaderVarSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._append_uv = -1; bind._append_uv = -1;
bind._integer = false; bind._integer = p._integer;
if (pieces.size() == 2) { if (pieces.size() == 2) {
if (pieces[1] == "position") { if (pieces[1] == "position") {
@ -685,6 +681,24 @@ compile_parameter(const ShaderArgId &arg_id,
_var_spec.push_back(bind); _var_spec.push_back(bind);
return true; return true;
} }
} else if (pieces.size() == 3) {
if (pieces[1] == "transform") {
if (pieces[2] == "blend") {
bind._name = InternalName::get_transform_blend();
_var_spec.push_back(bind);
return true;
}
if (pieces[2] == "index") {
bind._name = InternalName::get_transform_index();
_var_spec.push_back(bind);
return true;
}
if (pieces[2] == "weight") {
bind._name = InternalName::get_transform_weight();
_var_spec.push_back(bind);
return true;
}
}
} }
bind._name = InternalName::get_root(); bind._name = InternalName::get_root();
@ -793,7 +807,7 @@ compile_parameter(const ShaderArgId &arg_id,
return false; return false;
ShaderMatSpec bind; ShaderMatSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._func = SMF_compose; bind._func = SMF_compose;
int next = 1; int next = 1;
@ -856,7 +870,7 @@ compile_parameter(const ShaderArgId &arg_id,
if (!cp_errchk_parameter_float(p,16,16)) { if (!cp_errchk_parameter_float(p,16,16)) {
return false; return false;
} }
bind._id = arg_id; bind._id = p._id;
bind._piece = SMP_transpose; bind._piece = SMP_transpose;
bind._func = SMF_first; bind._func = SMF_first;
bind._part[0] = SMO_attr_material; bind._part[0] = SMO_attr_material;
@ -867,7 +881,7 @@ compile_parameter(const ShaderArgId &arg_id,
if (!cp_errchk_parameter_float(p,3,4)) { if (!cp_errchk_parameter_float(p,3,4)) {
return false; return false;
} }
bind._id = arg_id; bind._id = p._id;
bind._piece = SMP_row3; bind._piece = SMP_row3;
bind._func = SMF_first; bind._func = SMF_first;
bind._part[0] = SMO_attr_color; bind._part[0] = SMO_attr_color;
@ -878,7 +892,7 @@ compile_parameter(const ShaderArgId &arg_id,
if (!cp_errchk_parameter_float(p,3,4)) { if (!cp_errchk_parameter_float(p,3,4)) {
return false; return false;
} }
bind._id = arg_id; bind._id = p._id;
bind._piece = SMP_row3; bind._piece = SMP_row3;
bind._func = SMF_first; bind._func = SMF_first;
bind._part[0] = SMO_attr_colorscale; bind._part[0] = SMO_attr_colorscale;
@ -889,7 +903,7 @@ compile_parameter(const ShaderArgId &arg_id,
if (!cp_errchk_parameter_float(p,3,4)) { if (!cp_errchk_parameter_float(p,3,4)) {
return false; return false;
} }
bind._id = arg_id; bind._id = p._id;
bind._piece = SMP_row3; bind._piece = SMP_row3;
bind._func = SMF_first; bind._func = SMF_first;
bind._part[0] = SMO_attr_fog; bind._part[0] = SMO_attr_fog;
@ -900,7 +914,7 @@ compile_parameter(const ShaderArgId &arg_id,
if (!cp_errchk_parameter_float(p,3,4)) { if (!cp_errchk_parameter_float(p,3,4)) {
return false; return false;
} }
bind._id = arg_id; bind._id = p._id;
bind._piece = SMP_row3; bind._piece = SMP_row3;
bind._func = SMF_first; bind._func = SMF_first;
bind._part[0] = SMO_attr_fogcolor; bind._part[0] = SMO_attr_fogcolor;
@ -940,7 +954,7 @@ compile_parameter(const ShaderArgId &arg_id,
return false; return false;
} }
ShaderMatSpec bind; ShaderMatSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._piece = SMP_row3; bind._piece = SMP_row3;
bind._func = SMF_first; bind._func = SMF_first;
bind._part[0] = SMO_alight_x; bind._part[0] = SMO_alight_x;
@ -961,7 +975,7 @@ compile_parameter(const ShaderArgId &arg_id,
return false; return false;
} }
ShaderMatSpec bind; ShaderMatSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._piece = SMP_row3; bind._piece = SMP_row3;
bind._func = SMF_first; bind._func = SMF_first;
bind._part[0] = SMO_satten_x; bind._part[0] = SMO_satten_x;
@ -981,7 +995,7 @@ compile_parameter(const ShaderArgId &arg_id,
return false; return false;
} }
ShaderMatSpec bind; ShaderMatSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._piece = SMP_transpose; bind._piece = SMP_transpose;
int next = 1; int next = 1;
pieces.push_back(""); pieces.push_back("");
@ -1023,7 +1037,7 @@ compile_parameter(const ShaderArgId &arg_id,
return false; return false;
} }
ShaderMatSpec bind; ShaderMatSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._piece = SMP_whole; bind._piece = SMP_whole;
bind._func = SMF_first; bind._func = SMF_first;
bind._part[0] = SMO_texmat_x; bind._part[0] = SMO_texmat_x;
@ -1044,7 +1058,7 @@ compile_parameter(const ShaderArgId &arg_id,
return false; return false;
} }
ShaderMatSpec bind; ShaderMatSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._piece = SMP_row3; bind._piece = SMP_row3;
bind._func = SMF_first; bind._func = SMF_first;
bind._part[0] = SMO_plane_x; bind._part[0] = SMO_plane_x;
@ -1065,7 +1079,7 @@ compile_parameter(const ShaderArgId &arg_id,
return false; return false;
} }
ShaderMatSpec bind; ShaderMatSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._piece = SMP_row3; bind._piece = SMP_row3;
bind._func = SMF_first; bind._func = SMF_first;
bind._part[0] = SMO_clipplane_x; bind._part[0] = SMO_clipplane_x;
@ -1087,7 +1101,7 @@ compile_parameter(const ShaderArgId &arg_id,
return false; return false;
} }
ShaderMatSpec bind; ShaderMatSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._piece = SMP_row3; bind._piece = SMP_row3;
bind._func = SMF_first; bind._func = SMF_first;
bind._part[1] = SMO_identity; bind._part[1] = SMO_identity;
@ -1136,7 +1150,7 @@ compile_parameter(const ShaderArgId &arg_id,
return false; return false;
} }
ShaderTexSpec bind; ShaderTexSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._name = 0; bind._name = 0;
bind._stage = atoi(pieces[1].c_str()); bind._stage = atoi(pieces[1].c_str());
switch (p._type) { switch (p._type) {
@ -1168,7 +1182,7 @@ compile_parameter(const ShaderArgId &arg_id,
return false; return false;
} }
ShaderMatSpec bind; ShaderMatSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._piece = SMP_row3; bind._piece = SMP_row3;
bind._func = SMF_first; bind._func = SMF_first;
bind._part[0] = SMO_texpad_x; bind._part[0] = SMO_texpad_x;
@ -1188,7 +1202,7 @@ compile_parameter(const ShaderArgId &arg_id,
return false; return false;
} }
ShaderMatSpec bind; ShaderMatSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._piece = SMP_row3; bind._piece = SMP_row3;
bind._func = SMF_first; bind._func = SMF_first;
bind._part[0] = SMO_texpix_x; bind._part[0] = SMO_texpix_x;
@ -1200,6 +1214,11 @@ compile_parameter(const ShaderArgId &arg_id,
return true; return true;
} }
if (pieces[0] == "tbl") {
// Handled elsewhere.
return true;
}
if (pieces[0] == "l") { if (pieces[0] == "l") {
// IMPLEMENT THE ERROR CHECKING // IMPLEMENT THE ERROR CHECKING
return true; // Cg handles this automatically. return true; // Cg handles this automatically.
@ -1235,7 +1254,7 @@ compile_parameter(const ShaderArgId &arg_id,
return false; return false;
ShaderPtrSpec bind; ShaderPtrSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._arg = kinputname; bind._arg = kinputname;
bind._info = p; bind._info = p;
bind._dep[0] = SSD_general | SSD_shaderinputs; bind._dep[0] = SSD_general | SSD_shaderinputs;
@ -1253,7 +1272,7 @@ compile_parameter(const ShaderArgId &arg_id,
switch (p._type) { switch (p._type) {
case SAT_sampler1d: { case SAT_sampler1d: {
ShaderTexSpec bind; ShaderTexSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._name = kinputname; bind._name = kinputname;
bind._desired_type = Texture::TT_1d_texture; bind._desired_type = Texture::TT_1d_texture;
_tex_spec.push_back(bind); _tex_spec.push_back(bind);
@ -1261,7 +1280,7 @@ compile_parameter(const ShaderArgId &arg_id,
} }
case SAT_sampler2d: { case SAT_sampler2d: {
ShaderTexSpec bind; ShaderTexSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._name = kinputname; bind._name = kinputname;
bind._desired_type = Texture::TT_2d_texture; bind._desired_type = Texture::TT_2d_texture;
_tex_spec.push_back(bind); _tex_spec.push_back(bind);
@ -1269,7 +1288,7 @@ compile_parameter(const ShaderArgId &arg_id,
} }
case SAT_sampler3d: { case SAT_sampler3d: {
ShaderTexSpec bind; ShaderTexSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._name = kinputname; bind._name = kinputname;
bind._desired_type = Texture::TT_3d_texture; bind._desired_type = Texture::TT_3d_texture;
_tex_spec.push_back(bind); _tex_spec.push_back(bind);
@ -1277,7 +1296,7 @@ compile_parameter(const ShaderArgId &arg_id,
} }
case SAT_sampler2dArray: { case SAT_sampler2dArray: {
ShaderTexSpec bind; ShaderTexSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._name = kinputname; bind._name = kinputname;
bind._desired_type = Texture::TT_2d_texture_array; bind._desired_type = Texture::TT_2d_texture_array;
_tex_spec.push_back(bind); _tex_spec.push_back(bind);
@ -1285,7 +1304,7 @@ compile_parameter(const ShaderArgId &arg_id,
} }
case SAT_samplercube: { case SAT_samplercube: {
ShaderTexSpec bind; ShaderTexSpec bind;
bind._id = arg_id; bind._id = p._id;
bind._name = kinputname; bind._name = kinputname;
bind._desired_type = Texture::TT_cube_map; bind._desired_type = Texture::TT_cube_map;
_tex_spec.push_back(bind); _tex_spec.push_back(bind);
@ -1385,7 +1404,8 @@ cg_parameter_type(CGparameter p) {
default: return SAT_unknown; default: return SAT_unknown;
} }
case CG_PARAMETERCLASS_ARRAY: return SAT_unknown; case CG_PARAMETERCLASS_ARRAY: return SAT_unknown;
default: return SAT_unknown; default:
return SAT_unknown;
} }
} }
@ -1531,6 +1551,12 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps,
if (shader_cat.is_debug()) { if (shader_cat.is_debug()) {
shader_cat.debug() shader_cat.debug()
<< "Compilation with active profile failed: " << cgGetErrorString(err) << "\n"; << "Compilation with active profile failed: " << cgGetErrorString(err) << "\n";
if (err == CG_COMPILER_ERROR) {
const char *listing = cgGetLastListing(context);
if (listing != NULL) {
shader_cat.debug(false) << listing;
}
}
} }
} }
@ -1632,19 +1658,19 @@ cg_compile_shader(const ShaderCaps &caps, CGcontext context) {
shader_cat.debug() shader_cat.debug()
<< "Cg vertex profile: " << cgGetProfileString((CGprofile)_cg_vprofile) << "\n"; << "Cg vertex profile: " << cgGetProfileString((CGprofile)_cg_vprofile) << "\n";
vertex_program = cgGetProgramString(_cg_vprogram, CG_COMPILED_PROGRAM); vertex_program = cgGetProgramString(_cg_vprogram, CG_COMPILED_PROGRAM);
shader_cat.debug() << vertex_program << "\n"; shader_cat.spam() << vertex_program << "\n";
} }
if (_cg_fprogram != 0) { if (_cg_fprogram != 0) {
shader_cat.debug() shader_cat.debug()
<< "Cg fragment profile: " << cgGetProfileString((CGprofile)_cg_fprofile) << "\n"; << "Cg fragment profile: " << cgGetProfileString((CGprofile)_cg_fprofile) << "\n";
fragment_program = cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM); fragment_program = cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM);
shader_cat.debug() << fragment_program << "\n"; shader_cat.spam() << fragment_program << "\n";
} }
if (_cg_gprogram != 0) { if (_cg_gprogram != 0) {
shader_cat.debug() shader_cat.debug()
<< "Cg geometry profile: " << cgGetProfileString((CGprofile)_cg_gprofile) << "\n"; << "Cg geometry profile: " << cgGetProfileString((CGprofile)_cg_gprofile) << "\n";
geometry_program = cgGetProgramString(_cg_gprogram, CG_COMPILED_PROGRAM); geometry_program = cgGetProgramString(_cg_gprogram, CG_COMPILED_PROGRAM);
shader_cat.debug() << geometry_program << "\n"; shader_cat.spam() << geometry_program << "\n";
} }
} }
@ -1745,17 +1771,18 @@ cg_analyze_shader(const ShaderCaps &caps) {
} }
} }
// Assign sequence numbers to all parameters. // Assign sequence numbers to all parameters. GLCgShaderContext relies
// on the fact that the varyings start at seqno 0.
int seqno = 0; int seqno = 0;
for (int i=0; i<(int)_var_spec.size(); i++) {
_var_spec[i]._id._seqno = seqno++;
}
for (int i=0; i<(int)_mat_spec.size(); i++) { for (int i=0; i<(int)_mat_spec.size(); i++) {
_mat_spec[i]._id._seqno = seqno++; _mat_spec[i]._id._seqno = seqno++;
} }
for (int i=0; i<(int)_tex_spec.size(); i++) { for (int i=0; i<(int)_tex_spec.size(); i++) {
_tex_spec[i]._id._seqno = seqno++; _tex_spec[i]._id._seqno = seqno++;
} }
for (int i=0; i<(int)_var_spec.size(); i++) {
_var_spec[i]._id._seqno = seqno++;
}
for (int i=0; i<(int)_ptr_spec.size(); i++) { for (int i=0; i<(int)_ptr_spec.size(); i++) {
_ptr_spec[i]._id._seqno = seqno++; _ptr_spec[i]._id._seqno = seqno++;
@ -1955,7 +1982,7 @@ cg_compile_for(const ShaderCaps &caps, CGcontext context,
const char *resource = cgGetParameterResourceName(p); const char *resource = cgGetParameterResourceName(p);
if (resource != NULL) { if (resource != NULL) {
shader_cat.debug() << "Texture parameter " << id._name shader_cat.debug() << "Texture parameter " << id._name
<< " is bound to resource " << resource << "\n"; << " is bound to resource " << resource << "\n";
} }
} }
map[id._seqno] = p; map[id._seqno] = p;
@ -1967,48 +1994,18 @@ cg_compile_for(const ShaderCaps &caps, CGcontext context,
const char *resource = cgGetParameterResourceName(p); const char *resource = cgGetParameterResourceName(p);
if (shader_cat.is_debug() && resource != NULL) { if (shader_cat.is_debug() && resource != NULL) {
shader_cat.debug() if (cgGetParameterResource(p) == CG_GLSL_ATTRIB) {
<< "Varying parameter " << id._name << " is bound to resource " shader_cat.debug()
<< cgGetParameterResourceName(p) << "\n"; << "Varying parameter " << id._name << " is bound to GLSL attribute "
<< resource << "\n";
} else {
shader_cat.debug()
<< "Varying parameter " << id._name << " is bound to resource "
<< resource << " (" << cgGetParameterResource(p)
<< ", index " << cgGetParameterResourceIndex(p) << ")\n";
}
} }
if (cgGetParameterBaseResource(p) == CG_UNDEFINED) {
// I really don't know what this means, but it happens when I
// use the NORMAL0 semantic instead of NORMAL, or POSITION0
// instead of POSITION, etc. Not catching this results in a
// continuous stream of errors at the renderer side.
shader_cat.error()
<< "Varying parameter " << id._name;
const char *semantic = cgGetParameterSemantic(p);
if (semantic != NULL) {
shader_cat.error(false) << " : " << semantic;
}
if (resource != NULL) {
shader_cat.error(false) << " (bound to resource " << resource << ")";
}
shader_cat.error(false) << " is invalid!\n";
#ifndef NDEBUG
// Let's try to give the developer a hint...
if (semantic != NULL) {
if (strcmp(semantic, "POSITION0") == 0) {
shader_cat.error() << "Try using the semantic POSITION instead of POSITION0.\n";
} else if (strcmp(semantic, "NORMAL0") == 0) {
shader_cat.error() << "Try using the semantic NORMAL instead of NORMAL0.\n";
} else if (strcmp(semantic, "DIFFUSE0") == 0) {
shader_cat.error() << "Try using the semantic DIFFUSE instead of DIFFUSE0.\n";
} else if (strcmp(semantic, "SPECULAR0") == 0) {
shader_cat.error() << "Try using the semantic SPECULAR instead of SPECULAR0.\n";
} else if (strcmp(semantic, "FOGCOORD0") == 0) {
shader_cat.error() << "Try using the semantic FOGCOORD instead of FOGCOORD0.\n";
} else if (strcmp(semantic, "PSIZE0") == 0) {
shader_cat.error() << "Try using the semantic PSIZE instead of PSIZE0.\n";
}
}
#endif // NDEBUG
p = 0;
}
map[id._seqno] = p; map[id._seqno] = p;
} }
@ -2059,9 +2056,9 @@ Shader(ShaderLanguage lang) :
_cg_fprofile = CG_PROFILE_UNKNOWN; _cg_fprofile = CG_PROFILE_UNKNOWN;
_cg_gprofile = CG_PROFILE_UNKNOWN; _cg_gprofile = CG_PROFILE_UNKNOWN;
if (_default_caps._ultimate_vprofile == 0 || _default_caps._ultimate_vprofile == 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_vprofile = CG_PROFILE_GENERIC;
_default_caps._active_fprofile = CG_PROFILE_UNKNOWN; _default_caps._active_fprofile = CG_PROFILE_GENERIC;
_default_caps._active_gprofile = CG_PROFILE_UNKNOWN; _default_caps._active_gprofile = CG_PROFILE_GENERIC;
_default_caps._ultimate_vprofile = cgGetProfile("glslv"); _default_caps._ultimate_vprofile = cgGetProfile("glslv");
_default_caps._ultimate_fprofile = cgGetProfile("glslf"); _default_caps._ultimate_fprofile = cgGetProfile("glslf");
_default_caps._ultimate_gprofile = cgGetProfile("glslg"); _default_caps._ultimate_gprofile = cgGetProfile("glslg");

View File

@ -297,6 +297,7 @@ public:
ShaderArgType _type; ShaderArgType _type;
ShaderArgDir _direction; ShaderArgDir _direction;
bool _varying; bool _varying;
bool _integer;
NotifyCategory *_cat; NotifyCategory *_cat;
}; };
@ -478,14 +479,7 @@ public:
bool &success); bool &success);
#endif #endif
bool compile_parameter(const ShaderArgId &arg_id, bool compile_parameter(ShaderArgInfo &p, int *arg_dim);
const ShaderArgClass &arg_class,
const ShaderArgClass &arg_subclass,
const ShaderArgType &arg_type,
const ShaderArgDir &arg_direction,
bool arg_varying,
int *arg_dim,
NotifyCategory *arg_cat);
void clear_parameters(); void clear_parameters();

View File

@ -18,6 +18,7 @@
#include "colorAttrib.h" #include "colorAttrib.h"
#include "texGenAttrib.h" #include "texGenAttrib.h"
#include "textureAttrib.h" #include "textureAttrib.h"
#include "shaderAttrib.h"
#include "renderState.h" #include "renderState.h"
#include "clockObject.h" #include "clockObject.h"
#include "cullTraverser.h" #include "cullTraverser.h"
@ -128,6 +129,17 @@ munge_geom(GraphicsStateGuardianBase *gsg,
return false; return false;
} }
// If we have prepared it for skinning via the shader generator,
// mark a flag on the state so that the shader generator will do this.
// We should probably find a cleaner way to do this.
const ShaderAttrib *sattr;
if (_state->get_attrib(sattr) && sattr->auto_shader()) {
GeomVertexDataPipelineReader data_reader(_munged_data, current_thread);
if (data_reader.get_format()->get_animation().get_animation_type() == Geom::AT_hardware) {
_state = _state->set_attrib(sattr->set_flag(ShaderAttrib::F_hardware_skinning, true));
}
}
StateMunger *state_munger; StateMunger *state_munger;
DCAST_INTO_R(state_munger, munger, false); DCAST_INTO_R(state_munger, munger, false);
_state = state_munger->munge_state(_state); _state = state_munger->munge_state(_state);

View File

@ -271,8 +271,8 @@ private:
// The code to manage this map lives in // The code to manage this map lives in
// GraphicsStateGuardian::get_geom_munger(). // GraphicsStateGuardian::get_geom_munger().
typedef pmap<WCPT(GraphicsStateGuardianBase), PT(GeomMunger) > Mungers; typedef pmap<WCPT(GraphicsStateGuardianBase), PT(GeomMunger) > Mungers;
Mungers _mungers; mutable Mungers _mungers;
Mungers::const_iterator _last_mi; mutable Mungers::const_iterator _last_mi;
// This is used to mark nodes as we visit them to detect cycles. // This is used to mark nodes as we visit them to detect cycles.
UpdateSeq _cycle_detect; UpdateSeq _cycle_detect;

View File

@ -702,6 +702,7 @@ get_auto_shader_attrib_impl(const RenderState *state) const {
attrib->_auto_gloss_on = _auto_gloss_on; attrib->_auto_gloss_on = _auto_gloss_on;
attrib->_auto_ramp_on = _auto_ramp_on; attrib->_auto_ramp_on = _auto_ramp_on;
attrib->_auto_shadow_on = _auto_shadow_on; attrib->_auto_shadow_on = _auto_shadow_on;
attrib->_flags = _flags;
return return_new(attrib); return return_new(attrib);
} }

View File

@ -92,19 +92,25 @@ reset_register_allocator() {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
const char *ShaderGenerator:: const char *ShaderGenerator::
alloc_vreg() { alloc_vreg() {
// The ATTR# input sseem to map to generic vertex attributes in
// both arbvp1 and glslv, which behave more consistently.
switch (_vtregs_used) { switch (_vtregs_used) {
case 0: _vtregs_used += 1; return "TEXCOORD0"; case 0: _vtregs_used += 1; return "ATTR8";
case 1: _vtregs_used += 1; return "TEXCOORD1"; case 1: _vtregs_used += 1; return "ATTR9";
case 2: _vtregs_used += 1; return "TEXCOORD2"; case 2: _vtregs_used += 1; return "ATTR10";
case 3: _vtregs_used += 1; return "TEXCOORD3"; case 3: _vtregs_used += 1; return "ATTR11";
case 4: _vtregs_used += 1; return "TEXCOORD4"; case 4: _vtregs_used += 1; return "ATTR12";
case 5: _vtregs_used += 1; return "TEXCOORD5"; case 5: _vtregs_used += 1; return "ATTR13";
case 6: _vtregs_used += 1; return "TEXCOORD6"; case 6: _vtregs_used += 1; return "ATTR14";
case 7: _vtregs_used += 1; return "TEXCOORD7"; case 7: _vtregs_used += 1; return "ATTR15";
} }
switch (_vcregs_used) { switch (_vcregs_used) {
case 0: _vcregs_used += 1; return "COLOR0"; case 0: _vcregs_used += 1; return "ATTR3";
case 1: _vcregs_used += 1; return "COLOR1"; case 1: _vcregs_used += 1; return "ATTR4";
case 2: _vcregs_used += 1; return "ATTR5";
case 3: _vcregs_used += 1; return "ATTR6";
case 4: _vcregs_used += 1; return "ATTR7";
case 5: _vcregs_used += 1; return "ATTR1";
} }
// These don't exist in arbvp1, though they're reportedly // These don't exist in arbvp1, though they're reportedly
// supported by other profiles. // supported by other profiles.
@ -615,6 +621,7 @@ update_shadow_buffer(NodePath light_np) {
// - texmatrix // - texmatrix
// - 1D/2D/3D textures, cube textures, 2D tex arrays // - 1D/2D/3D textures, cube textures, 2D tex arrays
// - linear/exp/exp2 fog // - linear/exp/exp2 fog
// - animation
// //
// Not yet supported: // Not yet supported:
// - dot3_rgb and dot3_rgba combine modes // - dot3_rgb and dot3_rgba combine modes
@ -624,7 +631,7 @@ update_shadow_buffer(NodePath light_np) {
// //
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
CPT(ShaderAttrib) ShaderGenerator:: CPT(ShaderAttrib) ShaderGenerator::
synthesize_shader(const RenderState *rs) { synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
analyze_renderstate(rs); analyze_renderstate(rs);
reset_register_allocator(); reset_register_allocator();
@ -706,7 +713,7 @@ synthesize_shader(const RenderState *rs) {
} }
} }
if (_vertex_colors) { if (_vertex_colors) {
text << "\t in float4 vtx_color : COLOR0,\n"; text << "\t in float4 vtx_color : ATTR3,\n";
text << "\t out float4 l_color : COLOR0,\n"; text << "\t out float4 l_color : COLOR0,\n";
} }
if (_need_world_position || _need_world_normal) { if (_need_world_position || _need_world_normal) {
@ -733,7 +740,7 @@ synthesize_shader(const RenderState *rs) {
text << "\t out float4 l_eye_normal : " << eye_normal_freg << ",\n"; text << "\t out float4 l_eye_normal : " << eye_normal_freg << ",\n";
} }
if (_map_index_height >= 0 || _need_world_normal || _need_eye_normal) { if (_map_index_height >= 0 || _need_world_normal || _need_eye_normal) {
text << "\t in float3 vtx_normal : NORMAL,\n"; text << "\t in float3 vtx_normal : ATTR2,\n";
} }
if (_map_index_height >= 0) { if (_map_index_height >= 0) {
text << "\t uniform float4 mspos_view,\n"; text << "\t uniform float4 mspos_view,\n";
@ -765,11 +772,50 @@ synthesize_shader(const RenderState *rs) {
hpos_freg = alloc_freg(); hpos_freg = alloc_freg();
text << "\t out float4 l_hpos : " << hpos_freg << ",\n"; text << "\t out float4 l_hpos : " << hpos_freg << ",\n";
} }
text << "\t float4 vtx_position : POSITION,\n"; if (anim.get_animation_type() == GeomEnums::AT_hardware &&
anim.get_num_transforms() > 0) {
int num_transforms;
if (anim.get_indexed_transforms()) {
num_transforms = 120;
} else {
num_transforms = anim.get_num_transforms();
}
text << "\t uniform float4x4 tbl_transforms[" << num_transforms << "],\n";
text << "\t in float4 vtx_transform_weight : ATTR1,\n";
if (anim.get_indexed_transforms()) {
text << "\t in uint4 vtx_transform_index : ATTR7,\n";
}
}
text << "\t in float4 vtx_position : ATTR0,\n";
text << "\t out float4 l_position : POSITION,\n"; text << "\t out float4 l_position : POSITION,\n";
text << "\t uniform float4x4 mat_modelproj\n"; text << "\t uniform float4x4 mat_modelproj\n";
text << ") {\n"; text << ") {\n";
if (anim.get_animation_type() == GeomEnums::AT_hardware &&
anim.get_num_transforms() > 0) {
if (!anim.get_indexed_transforms()) {
text << "\t const uint4 vtx_transform_index = uint4(0, 1, 2, 3);\n";
}
text << "\t float4x4 matrix = tbl_transforms[vtx_transform_index.x] * vtx_transform_weight.x";
if (anim.get_num_transforms() > 1) {
text << "\n\t + tbl_transforms[vtx_transform_index.y] * vtx_transform_weight.y";
}
if (anim.get_num_transforms() > 2) {
text << "\n\t + tbl_transforms[vtx_transform_index.z] * vtx_transform_weight.z";
}
if (anim.get_num_transforms() > 3) {
text << "\n\t + tbl_transforms[vtx_transform_index.w] * vtx_transform_weight.w";
}
text << ";\n";
text << "\t vtx_position = mul(matrix, vtx_position);\n";
if (_need_world_normal || _need_eye_normal) {
text << "\t vtx_normal = mul((float3x3)matrix, vtx_normal);\n";
}
}
text << "\t l_position = mul(mat_modelproj, vtx_position);\n"; text << "\t l_position = mul(mat_modelproj, vtx_position);\n";
if (_fog) { if (_fog) {
text << "\t l_hpos = l_position;\n"; text << "\t l_hpos = l_position;\n";

View File

@ -33,6 +33,7 @@ class DirectionalLight;
class PointLight; class PointLight;
class Spotlight; class Spotlight;
class LightAttrib; class LightAttrib;
class GeomVertexAnimationSpec;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Class : ShaderGenerator // Class : ShaderGenerator
@ -71,7 +72,8 @@ class EXPCL_PANDA_PGRAPHNODES ShaderGenerator : public TypedReferenceCount {
PUBLISHED: PUBLISHED:
ShaderGenerator(GraphicsStateGuardianBase *gsg, GraphicsOutputBase *host); ShaderGenerator(GraphicsStateGuardianBase *gsg, GraphicsOutputBase *host);
virtual ~ShaderGenerator(); virtual ~ShaderGenerator();
virtual CPT(ShaderAttrib) synthesize_shader(const RenderState *rs); virtual CPT(ShaderAttrib) synthesize_shader(const RenderState *rs,
const GeomVertexAnimationSpec &anim);
protected: protected:
CPT(RenderAttrib) create_shader_attrib(const string &txt); CPT(RenderAttrib) create_shader_attrib(const string &txt);