From 5fa80f8c405be14da847c9f280c5d628aa27971e Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Thu, 2 Mar 2006 22:08:48 +0000 Subject: [PATCH] More code for shader matrix computation --- panda/src/display/graphicsStateGuardian.cxx | 364 ++++++++++-------- panda/src/display/graphicsStateGuardian.h | 5 +- .../glstuff/glGraphicsStateGuardian_src.cxx | 3 +- panda/src/glstuff/glShaderContext_src.cxx | 22 +- panda/src/gobj/lens.I | 31 -- panda/src/gobj/lens.h | 3 - panda/src/gobj/shaderContext.cxx | 159 +++++--- panda/src/gobj/shaderContext.h | 108 +++--- 8 files changed, 375 insertions(+), 320 deletions(-) diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 3586f308d9..9661851e82 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -105,8 +105,6 @@ GraphicsStateGuardian(const FrameBufferProperties &properties, _current_lens = (Lens *)NULL; _projection_mat = TransformState::make_identity(); _projection_mat_inv = TransformState::make_identity(); - _clip_to_view = TransformState::make_identity(); - _view_to_clip = TransformState::make_identity(); _needs_reset = true; _is_valid = false; @@ -373,10 +371,6 @@ set_scene(SceneSetup *scene_setup) { return false; } _projection_mat_inv = _projection_mat->get_inverse(); - _view_to_clip = TransformState::make_mat(_current_lens-> - get_projection_mat(_coordinate_system, _current_stereo_channel)); - _clip_to_view = TransformState::make_mat(_current_lens-> - get_projection_mat_inv(_coordinate_system, _current_stereo_channel)); return prepare_lens(); } @@ -677,177 +671,205 @@ clear(DrawableRegion *clearable) { // shoehorning them into a matrix. In this way, we avoid // the need for a separate routine to fetch these values. // -// This routine is actually a simple pcode-interpreter, -// and the ShaderMatSpec is actually a small pcode-array. -// This makes it possible to express requests for a -// large variety of values, and a large variety of -// possible conversions. +// If "altered" is false, that means you promise that +// this ShaderMatSpec has been evaluated before, and that +// since the last time this ShaderMatSpec was evaluated, +// that no part of the render state has changed except +// the external and internal transforms. +// //////////////////////////////////////////////////////////////////// -bool GraphicsStateGuardian:: -fetch_specified_value(const ShaderContext::ShaderMatSpec &spec, LMatrix4f &result) { - pvector stack; - int pc = 0; - int ac = 0; - while (pc < (int)spec._opcodes.size()) { - int opcode = spec._opcodes[pc++]; - switch(opcode) { - case ShaderContext::SMO_identity: { - stack.push_back(LMatrix4f::ident_mat()); - break; +const LMatrix4f *GraphicsStateGuardian:: +fetch_specified_value(ShaderContext::ShaderMatSpec &spec, bool altered) { + static LMatrix4f acc; + const LMatrix4f *val1; + const LMatrix4f *val2; + static LMatrix4f t1; + static LMatrix4f t2; + + switch(spec._func) { + case ShaderContext::SMF_compose: + val1 = fetch_specified_part(spec._part[0], spec._arg[0], t1); + val2 = fetch_specified_part(spec._part[1], spec._arg[1], t2); + acc.multiply(*val1, *val2); + return &acc; + case ShaderContext::SMF_compose_cache_first: + if (altered) { + spec._cache = *fetch_specified_part(spec._part[0], spec._arg[0], t1); } - case ShaderContext::SMO_modelview: { - stack.push_back(_internal_transform->get_mat()); - break; - } - case ShaderContext::SMO_projection: { - stack.push_back(_projection_mat->get_mat()); - break; - } - case ShaderContext::SMO_modelproj: { - stack.push_back(_internal_transform->get_mat() * _projection_mat->get_mat()); - break; - } - case ShaderContext::SMO_window_size: { - stack.push_back(LMatrix4f::translate_mat(_current_display_region->get_pixel_width(), - _current_display_region->get_pixel_height(), - 0.0)); - break; - } - case ShaderContext::SMO_pixel_size: { - stack.push_back(LMatrix4f::translate_mat(_current_display_region->get_pixel_width(), - _current_display_region->get_pixel_height(), - 0.0)); - break; - } - case ShaderContext::SMO_card_center: { - int px = _current_display_region->get_pixel_width(); - int py = _current_display_region->get_pixel_height(); - stack.push_back(LMatrix4f::translate_mat((px*0.5) / Texture::up_to_power_2(px), - (py*0.5) / Texture::up_to_power_2(py), - 0.0)); - break; - } - case ShaderContext::SMO_mat_constant_x: { - const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); - if (input->get_nodepath().is_empty()) { - return false; - } - stack.push_back(input->get_nodepath().node()->get_transform()->get_mat()); - break; - } - case ShaderContext::SMO_vec_constant_x: { - const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); - const float *data = input->get_vector().get_data(); - stack.push_back(LMatrix4f(data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3])); - break; - } - case ShaderContext::SMO_world_to_view: { - stack.push_back(get_scene()->get_world_transform()->get_mat()); - break; - } - case ShaderContext::SMO_view_to_world_C: { - stack.back() *= get_scene()->get_camera_transform()->get_mat(); - break; - } - case ShaderContext::SMO_model_to_view: { - stack.push_back(_external_transform->get_mat()); - break; - } - case ShaderContext::SMO_view_to_model_C: { - stack.back() *= invert(_external_transform->get_mat()); - break; - } - case ShaderContext::SMO_apiview_to_view: { - stack.push_back(_inv_cs_transform->get_mat()); - break; - } - case ShaderContext::SMO_view_to_apiview_C: { - stack.back() *= _cs_transform->get_mat(); - break; - } - case ShaderContext::SMO_clip_to_view: { - stack.push_back(_clip_to_view->get_mat()); - break; - } - case ShaderContext::SMO_view_to_clip_C: { - stack.back() *= _view_to_clip->get_mat(); - break; - } - case ShaderContext::SMO_apiclip_to_view: { - stack.push_back(_projection_mat_inv->get_mat() * _inv_cs_transform->get_mat()); - break; - } - case ShaderContext::SMO_view_to_apiclip_C: { - stack.back() *= _cs_transform->get_mat() * _projection_mat->get_mat(); - break; - } - case ShaderContext::SMO_view_x_to_view: { - const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); - nassertr(!input->get_nodepath().is_empty(), false); - stack.push_back(input->get_nodepath().get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat()); - break; - } - case ShaderContext::SMO_view_to_view_x_C: { - const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); - nassertr(!input->get_nodepath().is_empty(), false); - stack.back()*= (get_scene()->get_camera_transform()->get_mat() * - invert(input->get_nodepath().get_net_transform()->get_mat())); - break; - } - case ShaderContext::SMO_apiview_x_to_view: { - const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); - nassertr(!input->get_nodepath().is_empty(), false); - stack.push_back(LMatrix4f::convert_mat(_internal_coordinate_system, _coordinate_system) * - input->get_nodepath().get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat()); - break; - } - case ShaderContext::SMO_view_to_apiview_x_C: { - const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); - nassertr(!input->get_nodepath().is_empty(), false); - stack.back()*= (get_scene()->get_camera_transform()->get_mat() * - invert(input->get_nodepath().get_net_transform()->get_mat()) * - LMatrix4f::convert_mat(_coordinate_system, _internal_coordinate_system)); - break; - } - case ShaderContext::SMO_clip_x_to_view: { - const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); - nassertr(!input->get_nodepath().is_empty(), false); - Lens *lens = DCAST(LensNode, input->get_nodepath().node())->get_lens(); - stack.push_back(lens->get_projection_mat_inv(_coordinate_system, _current_stereo_channel) * - input->get_nodepath().get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat()); - break; - } - case ShaderContext::SMO_view_to_clip_x_C: { - const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); - nassertr(!input->get_nodepath().is_empty(), false); - Lens *lens = DCAST(LensNode, input->get_nodepath().node())->get_lens(); - stack.back()*= (get_scene()->get_camera_transform()->get_mat() * - invert(input->get_nodepath().get_net_transform()->get_mat()) * - lens->get_projection_mat(_coordinate_system, _current_stereo_channel)); - break; - } - case ShaderContext::SMO_apiclip_x_to_view: { - // NOT IMPLEMENTED - break; - } - case ShaderContext::SMO_view_to_apiclip_x_C: { - // NOT IMPLEMENTED - break; + val2 = fetch_specified_part(spec._part[1], spec._arg[1], t2); + acc.multiply(spec._cache, *val2); + return &acc; + case ShaderContext::SMF_compose_cache_second: + if (altered) { + spec._cache = *fetch_specified_part(spec._part[1], spec._arg[1], t2); } + val1 = fetch_specified_part(spec._part[0], spec._arg[0], t1); + acc.multiply(*val1, spec._cache); + return &acc; + case ShaderContext::SMF_first: + return fetch_specified_part(spec._part[0], spec._arg[0], t1); + default: + // should never get here + return &LMatrix4f::ident_mat(); + } +} - case ShaderContext::SMO_transpose: - stack.back().transpose_in_place(); - break; +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::fetch_specified_part +// Access: Public +// Description: See fetch_specified_value +//////////////////////////////////////////////////////////////////// +const LMatrix4f *GraphicsStateGuardian:: +fetch_specified_part(ShaderContext::ShaderMatInput part, InternalName *name, LMatrix4f &t) { + switch(part) { + case ShaderContext::SMO_identity: { + return &LMatrix4f::ident_mat(); + } + case ShaderContext::SMO_window_size: { + t = LMatrix4f::translate_mat(_current_display_region->get_pixel_width(), + _current_display_region->get_pixel_height(), + 0.0); + return &t; + } + case ShaderContext::SMO_pixel_size: { + t = LMatrix4f::translate_mat(_current_display_region->get_pixel_width(), + _current_display_region->get_pixel_height(), + 0.0); + return &t; + } + case ShaderContext::SMO_card_center: { + int px = _current_display_region->get_pixel_width(); + int py = _current_display_region->get_pixel_height(); + t = LMatrix4f::translate_mat((px*0.5) / Texture::up_to_power_2(px), + (py*0.5) / Texture::up_to_power_2(py), + 0.0); + return &t; + } + case ShaderContext::SMO_mat_constant_x: { + const ShaderInput *input = _target._shader->get_shader_input(name); + if (input->get_nodepath().is_empty()) { + return &LMatrix4f::ident_mat(); + } + return &(input->get_nodepath().node()->get_transform()->get_mat()); + } + case ShaderContext::SMO_vec_constant_x: { + const ShaderInput *input = _target._shader->get_shader_input(name); + const float *data = input->get_vector().get_data(); + t = LMatrix4f(data[0],data[1],data[2],data[3], + data[0],data[1],data[2],data[3], + data[0],data[1],data[2],data[3], + data[0],data[1],data[2],data[3]); + return &t; + } + case ShaderContext::SMO_world_to_view: { + return &(get_scene()->get_world_transform()->get_mat()); + break; + } + case ShaderContext::SMO_view_to_world: { + return &(get_scene()->get_camera_transform()->get_mat()); + } + case ShaderContext::SMO_model_to_view: { + return &(_external_transform->get_mat()); + } + case ShaderContext::SMO_view_to_model: { + // DANGER: SLOW AND NOT CACHEABLE! + t.invert_from(_external_transform->get_mat()); + return &t; + } + case ShaderContext::SMO_apiview_to_view: { + return &(_inv_cs_transform->get_mat()); + } + case ShaderContext::SMO_view_to_apiview: { + return &(_cs_transform->get_mat()); + } + case ShaderContext::SMO_clip_to_view: { + if (_current_lens->get_coordinate_system() == _coordinate_system) { + return &(_current_lens->get_projection_mat_inv(_current_stereo_channel)); + } else { + t = _current_lens->get_projection_mat_inv(_current_stereo_channel) * + LMatrix4f::convert_mat(_current_lens->get_coordinate_system(), _coordinate_system); + return &t; } } - result = stack.back(); - return true; + case ShaderContext::SMO_view_to_clip: { + if (_current_lens->get_coordinate_system() == _coordinate_system) { + return &(_current_lens->get_projection_mat(_current_stereo_channel)); + } else { + t = LMatrix4f::convert_mat(_coordinate_system, _current_lens->get_coordinate_system()) * + _current_lens->get_projection_mat(_current_stereo_channel); + return &t; + } + } + case ShaderContext::SMO_apiclip_to_view: { + t = _projection_mat_inv->get_mat() * _inv_cs_transform->get_mat(); + return &t; + } + case ShaderContext::SMO_view_to_apiclip: { + t = _cs_transform->get_mat() * _projection_mat->get_mat(); + return &t; + } + case ShaderContext::SMO_view_x_to_view: { + const ShaderInput *input = _target._shader->get_shader_input(name); + nassertr(!input->get_nodepath().is_empty(), &LMatrix4f::ident_mat()); + t = input->get_nodepath().get_net_transform()->get_mat() * + get_scene()->get_world_transform()->get_mat(); + return &t; + } + case ShaderContext::SMO_view_to_view_x: { + const ShaderInput *input = _target._shader->get_shader_input(name); + nassertr(!input->get_nodepath().is_empty(), &LMatrix4f::ident_mat()); + t = get_scene()->get_camera_transform()->get_mat() * + invert(input->get_nodepath().get_net_transform()->get_mat()); + return &t; + } + case ShaderContext::SMO_apiview_x_to_view: { + const ShaderInput *input = _target._shader->get_shader_input(name); + nassertr(!input->get_nodepath().is_empty(), &LMatrix4f::ident_mat()); + t = LMatrix4f::convert_mat(_internal_coordinate_system, _coordinate_system) * + input->get_nodepath().get_net_transform()->get_mat() * + get_scene()->get_world_transform()->get_mat(); + return &t; + } + case ShaderContext::SMO_view_to_apiview_x: { + const ShaderInput *input = _target._shader->get_shader_input(name); + nassertr(!input->get_nodepath().is_empty(), &LMatrix4f::ident_mat()); + t = (get_scene()->get_camera_transform()->get_mat() * + invert(input->get_nodepath().get_net_transform()->get_mat()) * + LMatrix4f::convert_mat(_coordinate_system, _internal_coordinate_system)); + return &t; + } + case ShaderContext::SMO_clip_x_to_view: { + const ShaderInput *input = _target._shader->get_shader_input(name); + nassertr(!input->get_nodepath().is_empty(), &LMatrix4f::ident_mat()); + Lens *lens = DCAST(LensNode, input->get_nodepath().node())->get_lens(); + t = lens->get_projection_mat_inv(_current_stereo_channel) * + LMatrix4f::convert_mat(lens->get_coordinate_system(), _coordinate_system) * + input->get_nodepath().get_net_transform()->get_mat() * + get_scene()->get_world_transform()->get_mat(); + return &t; + } + case ShaderContext::SMO_view_to_clip_x: { + const ShaderInput *input = _target._shader->get_shader_input(name); + nassertr(!input->get_nodepath().is_empty(), &LMatrix4f::ident_mat()); + Lens *lens = DCAST(LensNode, input->get_nodepath().node())->get_lens(); + t = get_scene()->get_camera_transform()->get_mat() * + invert(input->get_nodepath().get_net_transform()->get_mat()) * + LMatrix4f::convert_mat(_coordinate_system, lens->get_coordinate_system()) * + lens->get_projection_mat(_current_stereo_channel); + return &t; + } + case ShaderContext::SMO_apiclip_x_to_view: { + // NOT IMPLEMENTED + return &LMatrix4f::ident_mat(); + } + case ShaderContext::SMO_view_to_apiclip_x: { + // NOT IMPLEMENTED + return &LMatrix4f::ident_mat(); + } + default: + // should never get here + return &LMatrix4f::ident_mat(); + } } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index 7d74d48be4..8f3e41fefc 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -159,7 +159,8 @@ public: void clear(DrawableRegion *clearable); - bool fetch_specified_value(const ShaderContext::ShaderMatSpec &spec, LMatrix4f &result); + const LMatrix4f *fetch_specified_value(ShaderContext::ShaderMatSpec &spec, bool altered); + const LMatrix4f *fetch_specified_part(ShaderContext::ShaderMatInput input, InternalName *name, LMatrix4f &t); virtual void prepare_display_region(DisplayRegion *dr, Lens::StereoChannel stereo_channel); @@ -295,8 +296,6 @@ protected: CPT(Lens) _current_lens; CPT(TransformState) _projection_mat; CPT(TransformState) _projection_mat_inv; - CPT(TransformState) _view_to_clip; - CPT(TransformState) _clip_to_view; CoordinateSystem _coordinate_system; CoordinateSystem _internal_coordinate_system; diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index a1128695d5..052d0dea40 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -2763,8 +2763,9 @@ do_issue_transform() { do_auto_rescale_normal(); } - if (_current_shader_context) + if (_current_shader_context) { _current_shader_context->issue_parameters(this, false); + } report_my_gl_errors(); } diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index 3ab5a92499..ec1f40f683 100755 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -442,13 +442,17 @@ unbind() // Description: This function gets called whenever the RenderState // or TransformState has changed, but the ShaderExpansion // itself has not changed. It loads new values into the -// shader's parameters. The flag "all" is false if the -// only thing that has changed is the modelview matrix. -// In this case, only the transform-dependent parameters -// are reloaded. +// shader's parameters. +// +// If "altered" is false, that means you promise that +// the parameters for this shader context have already +// been issued once, and that since the last time the +// parameters were issued, no part of the render +// state has changed except the external and internal +// transforms. //////////////////////////////////////////////////////////////////// void CLP(ShaderContext):: -issue_parameters(GSG *gsg, bool all) +issue_parameters(GSG *gsg, bool altered) { #ifdef HAVE_CGGL if (_cg_context == 0) { @@ -456,11 +460,11 @@ issue_parameters(GSG *gsg, bool all) } for (int i=0; i<(int)_mat_spec.size(); i++) { - if (all || _mat_spec[i]._trans_dependent) { - LMatrix4f result; + if (altered || _mat_spec[i]._trans_dependent) { CGparameter p = (CGparameter)(_mat_spec[i]._parameter); - if (gsg->fetch_specified_value(_mat_spec[i], result)) { - const float *data = result.get_data(); + const LMatrix4f *val = gsg->fetch_specified_value(_mat_spec[i], altered); + if (val) { + const float *data = val->get_data(); switch (_mat_spec[i]._piece) { case SMP_whole: cgGLSetMatrixParameterfc(p, data); break; case SMP_transpose: cgGLSetMatrixParameterfr(p, data); break; diff --git a/panda/src/gobj/lens.I b/panda/src/gobj/lens.I index ccc9cdd503..a9abc535fb 100644 --- a/panda/src/gobj/lens.I +++ b/panda/src/gobj/lens.I @@ -443,34 +443,3 @@ operator << (ostream &out, const Lens &lens) { return out; } -//////////////////////////////////////////////////////////////////// -// Function: Lens::get_projection_mat -// Access: Published -// Description: Returns the complete transformation matrix from a 3-d -// point in space to a point on the film, if such a -// matrix exists, or the identity matrix if the lens is -// nonlinear, in the specified coordinate system. -//////////////////////////////////////////////////////////////////// -const LMatrix4f Lens:: -get_projection_mat(CoordinateSystem cs, StereoChannel channel) const { - return - LMatrix4f::convert_mat(cs, _cs) * - get_projection_mat(channel) * - LMatrix4f::convert_mat(CS_yup_right, cs); -} - -//////////////////////////////////////////////////////////////////// -// Function: Lens::get_projection_mat_inv -// Access: Published -// Description: Returns the matrix that transforms from a 2-d point -// on the film to a 3-d vector in space, if such a -// matrix exists, in the specified coordinate system. -//////////////////////////////////////////////////////////////////// -const LMatrix4f Lens:: -get_projection_mat_inv(CoordinateSystem cs, StereoChannel channel) const { - return - LMatrix4f::convert_mat(cs, CS_yup_right) * - get_projection_mat_inv(channel) * - LMatrix4f::convert_mat(_cs, cs); -} - diff --git a/panda/src/gobj/lens.h b/panda/src/gobj/lens.h index ec3c72ee49..91a739e935 100644 --- a/panda/src/gobj/lens.h +++ b/panda/src/gobj/lens.h @@ -155,9 +155,6 @@ PUBLISHED: const LMatrix4f &get_projection_mat(StereoChannel channel = SC_mono) const; const LMatrix4f &get_projection_mat_inv(StereoChannel channel = SC_mono) const; - INLINE const LMatrix4f get_projection_mat(CoordinateSystem cs, StereoChannel channel) const; - INLINE const LMatrix4f get_projection_mat_inv(CoordinateSystem cs, StereoChannel channel) const; - const LMatrix4f &get_film_mat() const; const LMatrix4f &get_film_mat_inv() const; diff --git a/panda/src/gobj/shaderContext.cxx b/panda/src/gobj/shaderContext.cxx index 602323bd52..a64d19e3cb 100755 --- a/panda/src/gobj/shaderContext.cxx +++ b/panda/src/gobj/shaderContext.cxx @@ -171,35 +171,88 @@ cp_errchk_parameter_sampler(ShaderArgInfo &p) } //////////////////////////////////////////////////////////////////// -// Function: GLShaderContext::cp_parse_trans_clause +// Function: ShaderContext::cp_parse_trans_clause // Access: Public // Description: Parses a single clause of a "trans" parameter. //////////////////////////////////////////////////////////////////// bool ShaderContext:: -cp_parse_trans_clause(ShaderArgInfo &p, ShaderMatSpec &spec, const vector_string &pieces, - int &next, ShaderMatOp ofop, ShaderMatOp op) { +cp_parse_trans_clause(ShaderArgInfo &p, ShaderMatSpec &spec, + int part, const vector_string &pieces, + int &next, ShaderMatInput ofop, ShaderMatInput op) { if (pieces[next+1]=="of") { if (pieces[next+2]=="") { cp_report_error(p, "'of' should be followed by a name"); return false; } - if (ofop != SMO_noop) { - spec._opcodes.push_back(ofop); - spec._args.push_back(InternalName::make(pieces[next+2])); - } + spec._part[part] = ofop; + spec._arg[part] = InternalName::make(pieces[next+2]); next += 3; return true; } else { - if (op != SMO_noop) { - spec._opcodes.push_back(op); - } + spec._part[part] = op; + spec._arg[part] = NULL; next += 1; return true; } } //////////////////////////////////////////////////////////////////// -// Function: GLShaderContext::compile_parameter +// Function: ShaderContext::cp_optimize_mat_spec +// Access: Public +// Description: Analyzes a ShaderMatSpec and decides what it should +// use its cache for. It can cache the results of any +// one opcode, or, it can cache the entire result. This +// routine needs to be smart enough to know which +// data items can be correctly cached, and which cannot. +//////////////////////////////////////////////////////////////////// +void ShaderContext:: +cp_optimize_mat_spec(ShaderMatSpec &spec) { + + // If we're composing with identity, simplify. + if (spec._func == SMF_compose) { + if (spec._part[1] == SMO_identity) { + spec._func = SMF_first; + } + } + if (spec._func == SMF_compose) { + if (spec._part[0] == SMO_identity) { + spec._func = SMF_first; + spec._part[0] = spec._part[1]; + spec._arg[0] = spec._arg[1]; + } + } + + // See if either half can be cached. + bool can_cache_part0 = true; + bool can_cache_part1 = true; + if ((spec._part[0] == SMO_model_to_view)|| + (spec._part[0] == SMO_view_to_model)) { + can_cache_part0 = false; + } + if ((spec._part[1] == SMO_model_to_view)|| + (spec._part[1] == SMO_view_to_model)) { + can_cache_part1 = false; + } + + // See if we can use a compose-with-cache variant. + if (spec._func == SMF_compose) { + if (can_cache_part0) { + spec._func = SMF_compose_cache_first; + } else if (can_cache_part1) { + spec._func = SMF_compose_cache_second; + } + } + + // Determine transform-dependence. + if (can_cache_part0 && can_cache_part1) { + spec._trans_dependent = false; + } else { + spec._trans_dependent = true; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderContext::compile_parameter // Access: Public // Description: Analyzes a parameter and decides how to // bind the parameter to some part of panda's @@ -377,14 +430,14 @@ compile_parameter(void *reference, ShaderMatSpec bind; bind._parameter = reference; - bind._trans_dependent = false; + bind._func = SMF_compose; int next = 1; pieces.push_back(""); // Decide whether this is a matrix or vector. if (pieces[0]=="trans") bind._piece = SMP_whole; - else if (pieces[0]=="tpose") bind._piece = SMP_whole; + else if (pieces[0]=="tpose") bind._piece = SMP_transpose; else if (pieces[0]=="row0") bind._piece = SMP_row0; else if (pieces[0]=="row1") bind._piece = SMP_row1; else if (pieces[0]=="row2") bind._piece = SMP_row2; @@ -393,7 +446,7 @@ compile_parameter(void *reference, else if (pieces[0]=="col1") bind._piece = SMP_col1; else if (pieces[0]=="col2") bind._piece = SMP_col2; else if (pieces[0]=="col3") bind._piece = SMP_col3; - if (bind._piece == SMP_whole) { + if ((bind._piece == SMP_whole)||(bind._piece == SMP_transpose)) { if (!cp_errchk_parameter_float(p, 16, 16)) return false; } else { if (!cp_errchk_parameter_float(p, 4, 4)) return false; @@ -405,21 +458,22 @@ compile_parameter(void *reference, cp_report_error(p, "argument missing"); return false; } else if (pieces[next] == "world") { - bind._opcodes.push_back(SMO_world_to_view); + bind._part[0] = SMO_world_to_view; + bind._arg[0] = NULL; next += 1; } else if (pieces[next] == "model") { - ok &= cp_parse_trans_clause(p, bind, pieces, next, SMO_view_x_to_view, SMO_model_to_view); + ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_view_x_to_view, SMO_model_to_view); } else if (pieces[next] == "clip") { - ok &= cp_parse_trans_clause(p, bind, pieces, next, SMO_clip_x_to_view, SMO_clip_to_view); + ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_clip_x_to_view, SMO_clip_to_view); } else if (pieces[next] == "view") { - ok &= cp_parse_trans_clause(p, bind, pieces, next, SMO_view_x_to_view, SMO_identity); + ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_view_x_to_view, SMO_identity); } else if (pieces[next] == "apiview") { - ok &= cp_parse_trans_clause(p, bind, pieces, next, SMO_apiview_x_to_view, SMO_apiview_to_view); + ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_apiview_x_to_view, SMO_apiview_to_view); } else if (pieces[next] == "apiclip") { - ok &= cp_parse_trans_clause(p, bind, pieces, next, SMO_apiclip_x_to_view, SMO_apiclip_to_view); + ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_apiclip_x_to_view, SMO_apiclip_to_view); } else { - bind._opcodes.push_back(SMO_view_x_to_view); - bind._args.push_back(InternalName::make(pieces[next])); + bind._part[0] = SMO_view_x_to_view; + bind._arg[0] = InternalName::make(pieces[next]); next += 1; } @@ -428,11 +482,6 @@ compile_parameter(void *reference, return false; } - // Check for transform-dependence. - if (bind._opcodes.back() == SMO_model_to_view) { - bind._trans_dependent = true; - } - // Check for syntactic well-formed-ness. if (pieces[next] != "to") { cp_report_error(p, "keyword 'to' expected"); @@ -446,21 +495,22 @@ compile_parameter(void *reference, cp_report_error(p, "argument missing"); return false; } else if (pieces[next] == "world") { - bind._opcodes.push_back(SMO_view_to_world_C); + bind._part[1] = SMO_view_to_world; + bind._arg[1] = NULL; next += 1; } else if (pieces[next] == "model") { - ok &= cp_parse_trans_clause(p, bind, pieces, next, SMO_view_to_view_x_C, SMO_view_to_model_C); + ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_view_x, SMO_view_to_model); } else if (pieces[next] == "clip") { - ok &= cp_parse_trans_clause(p, bind, pieces, next, SMO_view_to_clip_x_C, SMO_view_to_clip_C); + ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_clip_x, SMO_view_to_clip); } else if (pieces[next] == "view") { - ok &= cp_parse_trans_clause(p, bind, pieces, next, SMO_view_to_view_x_C, SMO_noop); + ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_view_x, SMO_identity); } else if (pieces[next] == "apiview") { - ok &= cp_parse_trans_clause(p, bind, pieces, next, SMO_view_to_apiview_x_C, SMO_view_to_apiview_C); + ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_apiview_x, SMO_view_to_apiview); } else if (pieces[next] == "apiclip") { - ok &= cp_parse_trans_clause(p, bind, pieces, next, SMO_view_to_apiclip_x_C, SMO_view_to_apiclip_C); + ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_apiclip_x, SMO_view_to_apiclip); } else { - bind._opcodes.push_back(SMO_view_to_view_x_C); - bind._args.push_back(InternalName::make(pieces[next])); + bind._part[1] = SMO_view_to_view_x; + bind._arg[1] = InternalName::make(pieces[next]); next += 1; } @@ -469,17 +519,13 @@ compile_parameter(void *reference, return false; } - // Check for transform-dependence. - if (bind._opcodes.back() == SMO_view_to_model_C) { - bind._trans_dependent = true; - } - // Check for syntactic well-formed-ness. if (pieces[next] != "") { cp_report_error(p, "end of line expected"); return false; } + cp_optimize_mat_spec(bind); _mat_spec.push_back(bind); return true; } @@ -494,27 +540,34 @@ compile_parameter(void *reference, } ShaderMatSpec bind; bind._parameter = reference; - bind._trans_dependent = false; bind._piece = SMP_row3; + bind._func = SMF_first; + bind._part[1] = SMO_identity; + bind._arg[1] = NULL; if (pieces[1] == "pixelsize") { if (!cp_errchk_parameter_float(p, 2, 2)) { return false; } - bind._opcodes.push_back(SMO_pixel_size); + bind._part[0] = SMO_pixel_size; + bind._arg[0] = NULL; } else if (pieces[1] == "windowsize") { if (!cp_errchk_parameter_float(p, 2, 2)) { return false; } - bind._opcodes.push_back(SMO_window_size); + bind._part[0] = SMO_window_size; + bind._arg[0] = NULL; } else if (pieces[1] == "cardcenter") { if (!cp_errchk_parameter_float(p, 2, 2)) { return false; } - bind._opcodes.push_back(SMO_card_center); + bind._part[0] = SMO_card_center; + bind._arg[0] = NULL; } else { cp_report_error(p,"unknown system parameter"); return false; } + + cp_optimize_mat_spec(bind); _mat_spec.push_back(bind); return true; } @@ -561,20 +614,26 @@ compile_parameter(void *reference, case SAT_float4: { ShaderMatSpec bind; bind._parameter = reference; - bind._trans_dependent = false; bind._piece = SMP_row3; - bind._opcodes.push_back(SMO_vec_constant_x); - bind._args.push_back(InternalName::make(pieces[1])); + bind._func = SMF_first; + bind._part[0] = SMO_vec_constant_x; + bind._arg[0] = InternalName::make(pieces[1]); + bind._part[1] = SMO_identity; + bind._arg[1] = NULL; + cp_optimize_mat_spec(bind); _mat_spec.push_back(bind); break; } case SAT_float4x4: { ShaderMatSpec bind; bind._parameter = reference; - bind._trans_dependent = false; bind._piece = SMP_whole; - bind._opcodes.push_back(SMO_mat_constant_x); - bind._args.push_back(InternalName::make(pieces[1])); + bind._func = SMF_first; + bind._part[0] = SMO_vec_constant_x; + bind._arg[0] = InternalName::make(pieces[1]); + bind._part[1] = SMO_identity; + bind._arg[1] = NULL; + cp_optimize_mat_spec(bind); _mat_spec.push_back(bind); break; } diff --git a/panda/src/gobj/shaderContext.h b/panda/src/gobj/shaderContext.h index b26c002f99..4784f2d1fc 100755 --- a/panda/src/gobj/shaderContext.h +++ b/panda/src/gobj/shaderContext.h @@ -49,6 +49,44 @@ public: SHADER_type_both=2, }; + enum ShaderMatInput { + SMO_identity, + + SMO_window_size, + SMO_pixel_size, + SMO_card_center, + + SMO_mat_constant_x, + SMO_vec_constant_x, + + SMO_world_to_view, + SMO_view_to_world, + + SMO_model_to_view, + SMO_view_to_model, + + SMO_apiview_to_view, + SMO_view_to_apiview, + + SMO_clip_to_view, + SMO_view_to_clip, + + SMO_apiclip_to_view, + SMO_view_to_apiclip, + + SMO_view_x_to_view, + SMO_view_to_view_x, + + SMO_apiview_x_to_view, + SMO_view_to_apiview_x, + + SMO_clip_x_to_view, + SMO_view_to_clip_x, + + SMO_apiclip_x_to_view, + SMO_view_to_apiclip_x, + }; + enum ShaderArgType { SAT_float1, SAT_float2, @@ -69,51 +107,6 @@ public: SAD_unknown, }; - enum ShaderMatOp { - SMO_identity, - - SMO_modelview, - SMO_projection, - SMO_modelproj, - - SMO_window_size, - SMO_pixel_size, - SMO_card_center, - - SMO_mat_constant_x, - SMO_vec_constant_x, - - SMO_world_to_view, - SMO_view_to_world_C, - - SMO_model_to_view, - SMO_view_to_model_C, - - SMO_apiview_to_view, - SMO_view_to_apiview_C, - - SMO_clip_to_view, - SMO_view_to_clip_C, - - SMO_apiclip_to_view, - SMO_view_to_apiclip_C, - - SMO_view_x_to_view, - SMO_view_to_view_x_C, - - SMO_apiview_x_to_view, - SMO_view_to_apiview_x_C, - - SMO_clip_x_to_view, - SMO_view_to_clip_x_C, - - SMO_apiclip_x_to_view, - SMO_view_to_apiclip_x_C, - - SMO_transpose, - SMO_noop, - }; - enum ShaderMatPiece { SMP_whole, SMP_transpose, @@ -127,12 +120,21 @@ public: SMP_col3, }; + enum ShaderMatFunc { + SMF_compose, + SMF_compose_cache_first, + SMF_compose_cache_second, + SMF_first, + }; + struct ShaderMatSpec { - pvector _opcodes; - pvector _args; - ShaderMatPiece _piece; - bool _trans_dependent; - void *_parameter; + ShaderMatFunc _func; + ShaderMatInput _part[2]; + PT(InternalName) _arg[2]; + LMatrix4f _cache; + ShaderMatPiece _piece; + bool _trans_dependent; + void *_parameter; }; struct ShaderTexSpec { @@ -174,10 +176,12 @@ private: bool cp_errchk_parameter_sampler(ShaderArgInfo &arg); bool cp_parse_trans_clause(ShaderArgInfo &arg, ShaderMatSpec &spec, + int part, const vector_string &pieces, int &next, - ShaderMatOp ofop, - ShaderMatOp op); + ShaderMatInput ofop, + ShaderMatInput op); + void cp_optimize_mat_spec(ShaderMatSpec &spec); protected: bool compile_parameter(void *reference,