From 89f1a0e63c7c0c01562f58e05712dfe393d21b66 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 25 Jan 2020 17:05:36 +0100 Subject: [PATCH] shader: separate shader matrix input cache from ShaderMatSpec If multiple ShaderMatSpec entries use the same state matrix, this should result in a reduction in the number of times that state matrix is fetched. This is especially so for arrays, which are now fetched once rather than once for every item. This is the first step towards trying to solve #846. --- panda/src/display/graphicsStateGuardian.cxx | 710 +++++++++++--------- panda/src/display/graphicsStateGuardian.h | 10 +- panda/src/dxgsg9/dxShaderContext9.cxx | 17 +- panda/src/dxgsg9/dxShaderContext9.h | 2 + panda/src/glstuff/glCgShaderContext_src.cxx | 11 +- panda/src/glstuff/glCgShaderContext_src.h | 1 + panda/src/glstuff/glShaderContext_src.cxx | 136 +--- panda/src/glstuff/glShaderContext_src.h | 2 + panda/src/gobj/shader.cxx | 173 +++-- panda/src/gobj/shader.h | 30 +- panda/src/pgraph/shaderAttrib.cxx | 3 +- 11 files changed, 589 insertions(+), 506 deletions(-) diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 46c5bfa0f6..c36eea42ae 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -876,6 +876,22 @@ compute_distance_to(const LPoint3 &point) const { } } +/** + * A shader can request a number of values from the current render state. These + * are stored in the form of a matrix. Each ShaderContext caches the current + * value of these matrices, and calls this routine to update the matrices that + * have changed based on the aspects of the render state that were altered. + */ +void GraphicsStateGuardian:: +update_shader_matrix_cache(Shader *shader, LMatrix4 *cache, int altered) { + for (Shader::ShaderMatPart &part : shader->_mat_parts) { + if (altered & part._dep) { + fetch_specified_part(part._part, part._arg, cache, part._count); + } + cache += part._count; + } +} + /** * The gsg contains a large number of useful matrices: * @@ -902,54 +918,45 @@ compute_distance_to(const LPoint3 &point) const { * */ const LMatrix4 *GraphicsStateGuardian:: -fetch_specified_value(Shader::ShaderMatSpec &spec, int altered) { +fetch_specified_value(Shader::ShaderMatSpec &spec, const LMatrix4 *cache, int altered) { LVecBase3 v; - if (altered & spec._dep[0]) { - const LMatrix4 *t = fetch_specified_part(spec._part[0], spec._arg[0], spec._cache[0], spec._index); - if (t != &spec._cache[0]) { - spec._cache[0] = *t; - } - } - if (altered & spec._dep[1]) { - const LMatrix4 *t = fetch_specified_part(spec._part[1], spec._arg[1], spec._cache[1], spec._index); - if (t != &spec._cache[1]) { - spec._cache[1] = *t; - } - } + const LMatrix4 *cache0 = cache + spec._cache_offset[0]; + const LMatrix4 *cache1 = cache + spec._cache_offset[1]; - switch(spec._func) { + + switch (spec._func) { case Shader::SMF_compose: - spec._value.multiply(spec._cache[0], spec._cache[1]); + spec._value.multiply((*cache0), (*cache1)); return &spec._value; case Shader::SMF_transform_dlight: - spec._value = spec._cache[0]; - v = spec._cache[1].xform_vec(spec._cache[0].get_row3(2)); + spec._value = (*cache0); + v = (*cache1).xform_vec((*cache0).get_row3(2)); v.normalize(); spec._value.set_row(2, v); - v = spec._cache[1].xform_vec(spec._cache[0].get_row3(3)); + v = (*cache1).xform_vec((*cache0).get_row3(3)); v.normalize(); spec._value.set_row(3, v); return &spec._value; case Shader::SMF_transform_plight: { // Careful not to touch the w component, which contains the near value. - spec._value = spec._cache[0]; - LPoint3 point = spec._cache[1].xform_point(spec._cache[0].get_row3(2)); + spec._value = *cache0; + LPoint3 point = (*cache1).xform_point((*cache0).get_row3(2)); spec._value(2, 0) = point[0]; spec._value(2, 1) = point[1]; spec._value(2, 2) = point[2]; return &spec._value; } case Shader::SMF_transform_slight: - spec._value = spec._cache[0]; - spec._value.set_row(2, spec._cache[1].xform_point(spec._cache[0].get_row3(2))); - v = spec._cache[1].xform_vec(spec._cache[0].get_row3(3)); + spec._value = *cache0; + spec._value.set_row(2, (*cache1).xform_point((*cache0).get_row3(2))); + v = (*cache1).xform_vec((*cache0).get_row3(3)); v.normalize(); spec._value.set_row(3, v); return &spec._value; case Shader::SMF_first: - return &spec._cache[0]; + return cache0; default: // should never get here spec._value = LMatrix4::ident_mat(); @@ -960,57 +967,62 @@ fetch_specified_value(Shader::ShaderMatSpec &spec, int altered) { /** * See fetch_specified_value */ -const LMatrix4 *GraphicsStateGuardian:: +void GraphicsStateGuardian:: fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, - LMatrix4 &t, int index) { + LMatrix4 *into, int count) { + nassertv(count > 0); + switch (part) { case Shader::SMO_identity: { - return &LMatrix4::ident_mat(); + for (int i = 0; i < count; ++i) { + into[i] = LMatrix4::ident_mat(); + } + return; } case Shader::SMO_window_size: case Shader::SMO_pixel_size: { LVecBase2i pixel_size = _current_display_region->get_pixel_size(); - t = LMatrix4::translate_mat(pixel_size[0], pixel_size[1], 0); - return &t; + into[0] = LMatrix4::translate_mat(pixel_size[0], pixel_size[1], 0); + return; } case Shader::SMO_frame_time: { PN_stdfloat time = ClockObject::get_global_clock()->get_frame_time(); - t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, time, time, time, time); - return &t; + into[0].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, time, time, time, time); + return; } case Shader::SMO_frame_delta: { PN_stdfloat dt = ClockObject::get_global_clock()->get_dt(); - t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dt, dt, dt, dt); - return &t; + into[0].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dt, dt, dt, dt); + return; } case Shader::SMO_texpad_x: { Texture *tex = _target_shader->get_shader_input_texture(name); - nassertr(tex != nullptr, &LMatrix4::zeros_mat()); + nassertv(tex != nullptr); int sx = tex->get_x_size() - tex->get_pad_x_size(); int sy = tex->get_y_size() - tex->get_pad_y_size(); int sz = tex->get_z_size() - tex->get_pad_z_size(); double cx = (sx * 0.5) / tex->get_x_size(); double cy = (sy * 0.5) / tex->get_y_size(); double cz = (sz * 0.5) / tex->get_z_size(); - t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, cx, cy, cz, 0); - return &t; + into[0].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, cx, cy, cz, 0); + return; } case Shader::SMO_texpix_x: { Texture *tex = _target_shader->get_shader_input_texture(name); - nassertr(tex != nullptr, &LMatrix4::zeros_mat()); + nassertv(tex != nullptr); double px = 1.0 / tex->get_x_size(); double py = 1.0 / tex->get_y_size(); double pz = 1.0 / tex->get_z_size(); - t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, px, py, pz, 0); - return &t; + into[0].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, px, py, pz, 0); + return; } case Shader::SMO_attr_material: { const MaterialAttrib *target_material = (const MaterialAttrib *) _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()); // Material matrix contains AMBIENT, DIFFUSE, EMISSION, SPECULAR+SHININESS if (target_material->is_off()) { - t.set(1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0); - return &t; + into[0].set(1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0); + return; } Material *m = target_material->get_material(); LVecBase4 const &amb = m->get_ambient(); @@ -1018,148 +1030,152 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LVecBase4 const &emm = m->get_emission(); LVecBase4 spc = m->get_specular(); spc[3] = m->get_shininess(); - t.set(amb[0], amb[1], amb[2], amb[3], - dif[0], dif[1], dif[2], dif[3], - emm[0], emm[1], emm[2], emm[3], - spc[0], spc[1], spc[2], spc[3]); - return &t; + into[0].set(amb[0], amb[1], amb[2], amb[3], + dif[0], dif[1], dif[2], dif[3], + emm[0], emm[1], emm[2], emm[3], + spc[0], spc[1], spc[2], spc[3]); + return; } case Shader::SMO_attr_material2: { const MaterialAttrib *target_material = (const MaterialAttrib *) _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()); if (target_material->is_off()) { - t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); - return &t; + into[0].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + return; } Material *m = target_material->get_material(); - t.set_row(0, m->get_base_color()); - t.set_row(3, LVecBase4(m->get_metallic(), m->get_refractive_index(), 0, m->get_roughness())); - return &t; + into[0].set_row(0, m->get_base_color()); + into[0].set_row(3, LVecBase4(m->get_metallic(), m->get_refractive_index(), 0, m->get_roughness())); + return; } case Shader::SMO_attr_color: { const ColorAttrib *target_color = (const ColorAttrib *) _target_rs->get_attrib_def(ColorAttrib::get_class_slot()); if (target_color->get_color_type() != ColorAttrib::T_flat) { - return &LMatrix4::ones_mat(); + into[0] = LMatrix4::ones_mat(); + return; } LVecBase4 c = target_color->get_color(); - t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]); - return &t; + into[0].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]); + return; } case Shader::SMO_attr_colorscale: { const ColorScaleAttrib *target_color = (const ColorScaleAttrib *) _target_rs->get_attrib_def(ColorScaleAttrib::get_class_slot()); if (target_color->is_identity()) { - return &LMatrix4::ones_mat(); + into[0] = LMatrix4::ones_mat(); + return; } LVecBase4 cs = target_color->get_scale(); - t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, cs[0], cs[1], cs[2], cs[3]); - return &t; + into[0].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, cs[0], cs[1], cs[2], cs[3]); + return; } case Shader::SMO_attr_fog: { const FogAttrib *target_fog = (const FogAttrib *) _target_rs->get_attrib_def(FogAttrib::get_class_slot()); Fog *fog = target_fog->get_fog(); if (fog == nullptr) { - return &LMatrix4::ones_mat(); + into[0] = LMatrix4::ones_mat(); + return; } PN_stdfloat start, end; fog->get_linear_range(start, end); - t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - fog->get_exp_density(), start, end, 1.0f / (end - start)); - return &t; + into[0].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + fog->get_exp_density(), start, end, 1.0f / (end - start)); + return; } case Shader::SMO_attr_fogcolor: { const FogAttrib *target_fog = (const FogAttrib *) _target_rs->get_attrib_def(FogAttrib::get_class_slot()); Fog *fog = target_fog->get_fog(); if (fog == nullptr) { - return &LMatrix4::ones_mat(); + into[0] = LMatrix4::ones_mat(); + return; } LVecBase4 c = fog->get_color(); - t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]); - return &t; + into[0].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]); + return; } case Shader::SMO_alight_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); - nassertr(!np.is_empty(), &LMatrix4::zeros_mat()); + nassertv(!np.is_empty()); AmbientLight *lt; - DCAST_INTO_R(lt, np.node(), &LMatrix4::zeros_mat()); + DCAST_INTO_V(lt, np.node()); LColor const &c = lt->get_color(); - t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]); - return &t; + into[0].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]); + return; } case Shader::SMO_satten_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); - nassertr(!np.is_empty(), &LMatrix4::ones_mat()); + nassertv(!np.is_empty()); Spotlight *lt; - DCAST_INTO_R(lt, np.node(), &LMatrix4::ones_mat()); + DCAST_INTO_V(lt, np.node()); LVecBase3 const &a = lt->get_attenuation(); PN_stdfloat x = lt->get_exponent(); - t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a[0], a[1], a[2], x); - return &t; + into[0].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a[0], a[1], a[2], x); + return; } case Shader::SMO_dlight_x: { // The dlight matrix contains COLOR, SPECULAR, DIRECTION, PSEUDOHALFANGLE const NodePath &np = _target_shader->get_shader_input_nodepath(name); - nassertr(!np.is_empty(), &LMatrix4::zeros_mat()); + nassertv(!np.is_empty()); DirectionalLight *lt; - DCAST_INTO_R(lt, np.node(), &LMatrix4::zeros_mat()); + DCAST_INTO_V(lt, np.node()); LColor const &c = lt->get_color(); LColor const &s = lt->get_specular_color(); - t = np.get_net_transform()->get_mat() * - _scene_setup->get_world_transform()->get_mat(); - LVecBase3 d = -(t.xform_vec(lt->get_direction())); + *into = np.get_net_transform()->get_mat() * + _scene_setup->get_world_transform()->get_mat(); + LVecBase3 d = -(into[0].xform_vec(lt->get_direction())); d.normalize(); LVecBase3 h = d + LVecBase3(0,-1,0); h.normalize(); - t.set(c[0], c[1], c[2], c[3], - s[0], s[1], s[2], c[3], - d[0], d[1], d[2], 0, - h[0], h[1], h[2], 0); - return &t; + into[0].set(c[0], c[1], c[2], c[3], + s[0], s[1], s[2], c[3], + d[0], d[1], d[2], 0, + h[0], h[1], h[2], 0); + return; } case Shader::SMO_plight_x: { // The plight matrix contains COLOR, SPECULAR, POINT, ATTENUATION const NodePath &np = _target_shader->get_shader_input_nodepath(name); - nassertr(!np.is_empty(), &LMatrix4::ones_mat()); + nassertv(!np.is_empty()); PointLight *lt; - DCAST_INTO_R(lt, np.node(), &LMatrix4::zeros_mat()); + DCAST_INTO_V(lt, np.node()); LColor const &c = lt->get_color(); LColor const &s = lt->get_specular_color(); - t = np.get_net_transform()->get_mat() * - _scene_setup->get_world_transform()->get_mat(); - LVecBase3 p = (t.xform_point(lt->get_point())); + into[0] = np.get_net_transform()->get_mat() * + _scene_setup->get_world_transform()->get_mat(); + LVecBase3 p = (into[0].xform_point(lt->get_point())); LVecBase3 a = lt->get_attenuation(); Lens *lens = lt->get_lens(0); PN_stdfloat lnear = lens->get_near(); PN_stdfloat lfar = lens->get_far(); - t.set(c[0], c[1], c[2], c[3], - s[0], s[1], s[2], s[3], - p[0], p[1], p[2], lnear, - a[0], a[1], a[2], lfar); - return &t; + into[0].set(c[0], c[1], c[2], c[3], + s[0], s[1], s[2], s[3], + p[0], p[1], p[2], lnear, + a[0], a[1], a[2], lfar); + return; } case Shader::SMO_slight_x: { // The slight matrix contains COLOR, SPECULAR, POINT, DIRECTION const NodePath &np = _target_shader->get_shader_input_nodepath(name); - nassertr(!np.is_empty(), &LMatrix4::zeros_mat()); + nassertv(!np.is_empty()); Spotlight *lt; - DCAST_INTO_R(lt, np.node(), &LMatrix4::zeros_mat()); + DCAST_INTO_V(lt, np.node()); Lens *lens = lt->get_lens(); - nassertr(lens != nullptr, &LMatrix4::zeros_mat()); + nassertv(lens != nullptr); LColor const &c = lt->get_color(); LColor const &s = lt->get_specular_color(); PN_stdfloat cutoff = ccos(deg_2_rad(lens->get_hfov() * 0.5f)); - t = np.get_net_transform()->get_mat() * - _scene_setup->get_world_transform()->get_mat(); - LVecBase3 p = t.xform_point(lens->get_nodal_point()); - LVecBase3 d = -(t.xform_vec(lens->get_view_vector())); - t.set(c[0], c[1], c[2], c[3], - s[0], s[1], s[2], s[3], - p[0], p[1], p[2], 0, - d[0], d[1], d[2], cutoff); - return &t; + into[0] = np.get_net_transform()->get_mat() * + _scene_setup->get_world_transform()->get_mat(); + LVecBase3 p = into[0].xform_point(lens->get_nodal_point()); + LVecBase3 d = -(into[0].xform_vec(lens->get_view_vector())); + into[0].set(c[0], c[1], c[2], c[3], + s[0], s[1], s[2], s[3], + p[0], p[1], p[2], 0, + d[0], d[1], d[2], cutoff); + return; } case Shader::SMO_light_ambient: { LColor cur_ambient_light(0.0f, 0.0f, 0.0f, 0.0f); @@ -1169,89 +1185,127 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, if (!target_light->has_any_on_light()) { // There are no lights at all. This means, to follow the fixed- // function model, we pretend there is an all-white ambient light. - t.set_row(3, LVecBase4(1, 1, 1, 1)); + into[0].set_row(3, LVecBase4(1, 1, 1, 1)); } else { - t.set_row(3, target_light->get_ambient_contribution()); + into[0].set_row(3, target_light->get_ambient_contribution()); } - return &t; + return; } case Shader::SMO_texmat_i: { const TexMatrixAttrib *tma; const TextureAttrib *ta; - if (_target_rs->get_attrib(ta) && _target_rs->get_attrib(tma) && - index < ta->get_num_on_stages()) { - return &tma->get_mat(ta->get_on_stage(index)); - } else { - return &LMatrix4::ident_mat(); + + int num_stages = 0; + if (_target_rs->get_attrib(ta) && _target_rs->get_attrib(tma)) { + num_stages = std::min(count, (int)ta->get_num_on_stages()); } + + int i = 0; + for (; i < num_stages; ++i) { + into[i] = tma->get_mat(ta->get_on_stage(i)); + } + for (; i < count; ++i) { + into[i] = LMatrix4::ident_mat(); + } + return; } case Shader::SMO_inv_texmat_i: { const TexMatrixAttrib *tma; const TextureAttrib *ta; - if (_target_rs->get_attrib(ta) && _target_rs->get_attrib(tma) && - index < ta->get_num_on_stages()) { - t = tma->get_transform(ta->get_on_stage(index))->get_inverse()->get_mat(); - return &t; - } else { - return &LMatrix4::ident_mat(); + + int num_stages = 0; + if (_target_rs->get_attrib(ta) && _target_rs->get_attrib(tma)) { + num_stages = std::min(count, (int)ta->get_num_on_stages()); } + + int i = 0; + for (; i < num_stages; ++i) { + into[i] = tma->get_transform(ta->get_on_stage(i))->get_inverse()->get_mat(); + } + for (; i < count; ++i) { + into[i] = LMatrix4::ident_mat(); + } + return; } case Shader::SMO_texscale_i: { const TexMatrixAttrib *tma; const TextureAttrib *ta; - if (_target_rs->get_attrib(ta) && _target_rs->get_attrib(tma) && - index < ta->get_num_on_stages()) { - LVecBase3 scale = tma->get_transform(ta->get_on_stage(index))->get_scale(); - t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, scale[0], scale[1], scale[2], 0); - return &t; - } else { - return &LMatrix4::ident_mat(); + + int num_stages = 0; + if (_target_rs->get_attrib(ta) && _target_rs->get_attrib(tma)) { + num_stages = std::min(count, (int)ta->get_num_on_stages()); } + + int i = 0; + for (; i < num_stages; ++i) { + LVecBase3 scale = tma->get_transform(ta->get_on_stage(i))->get_scale(); + into[i].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, scale[0], scale[1], scale[2], 0); + } + for (; i < count; ++i) { + into[i] = LMatrix4::ident_mat(); + } + return; } case Shader::SMO_texcolor_i: { const TextureAttrib *ta; - if (_target_rs->get_attrib(ta) && index < ta->get_num_on_stages()) { - TextureStage *ts = ta->get_on_stage(index); - t.set_row(3, ts->get_color()); - return &t; - } else { - return &LMatrix4::zeros_mat(); + + int num_stages = 0; + if (_target_rs->get_attrib(ta)) { + num_stages = std::min(count, (int)ta->get_num_on_stages()); } + + int i = 0; + for (; i < num_stages; ++i) { + TextureStage *ts = ta->get_on_stage(i); + into[i].set_row(3, ts->get_color()); + } + for (; i < count; ++i) { + into[i] = LMatrix4::ident_mat(); + } + return; } case Shader::SMO_tex_is_alpha_i: { // This is a hack so we can support both F_alpha and other formats in the // default shader, to fix font rendering in GLES2 const TextureAttrib *ta; - if (_target_rs->get_attrib(ta) && - index < ta->get_num_on_stages()) { - TextureStage *ts = ta->get_on_stage(index); - PN_stdfloat v = (ta->get_on_texture(ts)->get_format() == Texture::F_alpha); - t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, v, v, v, 0); - return &t; - } else { - return &LMatrix4::zeros_mat(); + + int num_stages = 0; + if (_target_rs->get_attrib(ta)) { + num_stages = std::min(count, (int)ta->get_num_on_stages()); } + + int i = 0; + for (; i < num_stages; ++i) { + TextureStage *ts = ta->get_on_stage(i); + PN_stdfloat v = (ta->get_on_texture(ts)->get_format() == Texture::F_alpha); + into[i].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, v, v, v, 0); + } + for (; i < count; ++i) { + into[i] = LMatrix4::zeros_mat(); + } + return; } case Shader::SMO_plane_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); - nassertr(!np.is_empty(), &LMatrix4::zeros_mat()); + nassertv(!np.is_empty()); const PlaneNode *plane_node; - DCAST_INTO_R(plane_node, np.node(), &LMatrix4::zeros_mat()); + DCAST_INTO_V(plane_node, np.node()); LPlane p = plane_node->get_plane(); - t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, p[0], p[1], p[2], p[3]); - return &t; + into[0].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, p[0], p[1], p[2], p[3]); + return; } case Shader::SMO_clipplane_x: { const ClipPlaneAttrib *cpa; _target_rs->get_attrib_def(cpa); int planenr = atoi(name->get_name().c_str()); if (planenr >= cpa->get_num_on_planes()) { - return &LMatrix4::zeros_mat(); + into[0] = LMatrix4::zeros_mat(); + return; } const NodePath &np = cpa->get_on_plane(planenr); - nassertr(!np.is_empty(), &LMatrix4::zeros_mat()); + nassertv(!np.is_empty()); const PlaneNode *plane_node; - DCAST_INTO_R(plane_node, np.node(), &LMatrix4::zeros_mat()); + DCAST_INTO_V(plane_node, np.node()); // Transform plane to world space CPT(TransformState) transform = np.get_net_transform(); @@ -1259,206 +1313,223 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, if (!transform->is_identity()) { plane.xform(transform->get_mat()); } - t.set_row(3, plane); - return &t; + into[0].set_row(3, plane); + return; } case Shader::SMO_apiview_clipplane_i: { const ClipPlaneAttrib *cpa; _target_rs->get_attrib_def(cpa); - if (index >= cpa->get_num_on_planes()) { - return &LMatrix4::zeros_mat(); + + int num_planes = std::min(count, (int)cpa->get_num_on_planes()); + int i = 0; + for (; i < num_planes; ++i) { + const NodePath &plane = cpa->get_on_plane(i); + nassertv(!plane.is_empty()); + const PlaneNode *plane_node; + DCAST_INTO_V(plane_node, plane.node()); + + CPT(TransformState) transform = + _scene_setup->get_cs_world_transform()->compose( + plane.get_transform(_scene_setup->get_scene_root().get_parent())); + + LPlane xformed_plane = plane_node->get_plane() * transform->get_mat(); + into[i].set_row(3, xformed_plane); } - const NodePath &plane = cpa->get_on_plane(index); - nassertr(!plane.is_empty(), &LMatrix4::zeros_mat()); - const PlaneNode *plane_node; - DCAST_INTO_R(plane_node, plane.node(), &LMatrix4::zeros_mat()); - - CPT(TransformState) transform = - _scene_setup->get_cs_world_transform()->compose( - plane.get_transform(_scene_setup->get_scene_root().get_parent())); - - LPlane xformed_plane = plane_node->get_plane() * transform->get_mat(); - t.set_row(3, xformed_plane); - return &t; + for (; i < count; ++i) { + // Fill the remainder with zeroes. + into[i] = LMatrix4::zeros_mat(); + } + return; } case Shader::SMO_mat_constant_x: { - return &_target_shader->get_shader_input_matrix(name, t); + _target_shader->get_shader_input_matrix(name, into[0]); + return; } case Shader::SMO_vec_constant_x: { const LVecBase4 &input = _target_shader->get_shader_input_vector(name); const PN_stdfloat *data = input.get_data(); - t.set(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; + into[0].set(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; } case Shader::SMO_world_to_view: { - return &(_scene_setup->get_world_transform()->get_mat()); + into[0] = _scene_setup->get_world_transform()->get_mat(); + return; } case Shader::SMO_view_to_world: { - return &(_scene_setup->get_camera_transform()->get_mat()); + into[0] = _scene_setup->get_camera_transform()->get_mat(); + return; } case Shader::SMO_model_to_view: { - t = _inv_cs_transform->compose(_internal_transform)->get_mat(); - return &t; + into[0] = _inv_cs_transform->compose(_internal_transform)->get_mat(); + return; } case Shader::SMO_model_to_apiview: { - return &(_internal_transform->get_mat()); + into[0] = _internal_transform->get_mat(); + return; } case Shader::SMO_view_to_model: { - t = _internal_transform->invert_compose(_cs_transform)->get_mat(); - return &t; + into[0] = _internal_transform->invert_compose(_cs_transform)->get_mat(); + return; } case Shader::SMO_apiview_to_model: { - t = _internal_transform->get_inverse()->get_mat(); - return &t; + into[0] = _internal_transform->get_inverse()->get_mat(); + return; } case Shader::SMO_apiview_to_view: { - return &(_inv_cs_transform->get_mat()); + into[0] = _inv_cs_transform->get_mat(); + return; } case Shader::SMO_view_to_apiview: { - return &(_cs_transform->get_mat()); + into[0] = _cs_transform->get_mat(); + return; } case Shader::SMO_clip_to_view: { if (_current_lens->get_coordinate_system() == _coordinate_system) { - return &(_current_lens->get_projection_mat_inv(_current_stereo_channel)); + into[0] = _current_lens->get_projection_mat_inv(_current_stereo_channel); } else { - t = _current_lens->get_projection_mat_inv(_current_stereo_channel) * - LMatrix4::convert_mat(_current_lens->get_coordinate_system(), _coordinate_system); - return &t; + into[0] = _current_lens->get_projection_mat_inv(_current_stereo_channel) * + LMatrix4::convert_mat(_current_lens->get_coordinate_system(), _coordinate_system); } + return; } case Shader::SMO_view_to_clip: { if (_current_lens->get_coordinate_system() == _coordinate_system) { - return &(_current_lens->get_projection_mat(_current_stereo_channel)); + into[0] = _current_lens->get_projection_mat(_current_stereo_channel); } else { - t = LMatrix4::convert_mat(_coordinate_system, _current_lens->get_coordinate_system()) * - _current_lens->get_projection_mat(_current_stereo_channel); - return &t; + into[0] = LMatrix4::convert_mat(_coordinate_system, _current_lens->get_coordinate_system()) * + _current_lens->get_projection_mat(_current_stereo_channel); } + return; } case Shader::SMO_apiclip_to_view: { - t = _projection_mat_inv->get_mat() * _inv_cs_transform->get_mat(); - return &t; + into[0] = _projection_mat_inv->get_mat() * _inv_cs_transform->get_mat(); + return; } case Shader::SMO_view_to_apiclip: { - t = _cs_transform->get_mat() * _projection_mat->get_mat(); - return &t; + into[0] = _cs_transform->get_mat() * _projection_mat->get_mat(); + return; } case Shader::SMO_apiclip_to_apiview: { - return &(_projection_mat_inv->get_mat()); + into[0] = _projection_mat_inv->get_mat(); + return; } case Shader::SMO_apiview_to_apiclip: { - return &(_projection_mat->get_mat()); + into[0] = _projection_mat->get_mat(); + return; } case Shader::SMO_view_x_to_view: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); - nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - t = np.get_net_transform()->get_mat() * + nassertv(!np.is_empty()); + into[0] = np.get_net_transform()->get_mat() * _scene_setup->get_world_transform()->get_mat(); - return &t; + return; } case Shader::SMO_view_to_view_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); - nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - t = _scene_setup->get_camera_transform()->get_mat() * + nassertv(!np.is_empty()); + into[0] = _scene_setup->get_camera_transform()->get_mat() * np.get_net_transform()->get_inverse()->get_mat(); - return &t; + return; } case Shader::SMO_apiview_x_to_view: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); - nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - t = LMatrix4::convert_mat(_internal_coordinate_system, _coordinate_system) * + nassertv(!np.is_empty()); + into[0] = LMatrix4::convert_mat(_internal_coordinate_system, _coordinate_system) * np.get_net_transform()->get_mat() * _scene_setup->get_world_transform()->get_mat(); - return &t; + return; } case Shader::SMO_view_to_apiview_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); - nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - t = (_scene_setup->get_camera_transform()->get_mat() * + nassertv(!np.is_empty()); + into[0] = (_scene_setup->get_camera_transform()->get_mat() * np.get_net_transform()->get_inverse()->get_mat() * LMatrix4::convert_mat(_coordinate_system, _internal_coordinate_system)); - return &t; + return; } case Shader::SMO_clip_x_to_view: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); - nassertr(!np.is_empty(), &LMatrix4::ident_mat()); + nassertv(!np.is_empty()); const LensNode *node; - DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat()); + DCAST_INTO_V(node, np.node()); const Lens *lens = node->get_lens(); - t = lens->get_projection_mat_inv(_current_stereo_channel) * + into[0] = lens->get_projection_mat_inv(_current_stereo_channel) * LMatrix4::convert_mat(lens->get_coordinate_system(), _coordinate_system) * np.get_net_transform()->get_mat() * _scene_setup->get_world_transform()->get_mat(); - return &t; + return; } case Shader::SMO_view_to_clip_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); - nassertr(!np.is_empty(), &LMatrix4::ident_mat()); + nassertv(!np.is_empty()); const LensNode *node; - DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat()); + DCAST_INTO_V(node, np.node()); const Lens *lens = node->get_lens(); - t = _scene_setup->get_camera_transform()->get_mat() * + into[0] = _scene_setup->get_camera_transform()->get_mat() * np.get_net_transform()->get_inverse()->get_mat() * LMatrix4::convert_mat(_coordinate_system, lens->get_coordinate_system()) * lens->get_projection_mat(_current_stereo_channel); - return &t; + return; } case Shader::SMO_apiclip_x_to_view: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); - nassertr(!np.is_empty(), &LMatrix4::ident_mat()); + nassertv(!np.is_empty()); const LensNode *node; - DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat()); + DCAST_INTO_V(node, np.node()); const Lens *lens = node->get_lens(); - t = calc_projection_mat(lens)->get_inverse()->get_mat() * + into[0] = calc_projection_mat(lens)->get_inverse()->get_mat() * get_cs_transform_for(lens->get_coordinate_system())->get_inverse()->get_mat() * np.get_net_transform()->get_mat() * _scene_setup->get_world_transform()->get_mat(); - return &t; + return; } case Shader::SMO_view_to_apiclip_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); - nassertr(!np.is_empty(), &LMatrix4::ident_mat()); + nassertv(!np.is_empty()); const LensNode *node; - DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat()); + DCAST_INTO_V(node, np.node()); const Lens *lens = node->get_lens(); - t = _scene_setup->get_camera_transform()->get_mat() * + into[0] = _scene_setup->get_camera_transform()->get_mat() * np.get_net_transform()->get_inverse()->get_mat() * get_cs_transform_for(lens->get_coordinate_system())->get_mat() * calc_projection_mat(lens)->get_mat(); - return &t; + return; } case Shader::SMO_mat_constant_x_attrib: { if (_target_shader->has_shader_input(name)) { // There is an input specifying precisely this whole thing, with dot and // all. Support this, even if only for backward compatibility. - return &_target_shader->get_shader_input_matrix(name, t); + _target_shader->get_shader_input_matrix(name, into[0]); + return; } const NodePath &np = _target_shader->get_shader_input_nodepath(name->get_parent()); - nassertr(!np.is_empty(), &LMatrix4::ident_mat()); + nassertv(!np.is_empty()); - return fetch_specified_member(np, name->get_basename(), t); + fetch_specified_member(np, name->get_basename(), into[0]); + return; } case Shader::SMO_vec_constant_x_attrib: { if (_target_shader->has_shader_input(name)) { // There is an input specifying precisely this whole thing, with dot and // all. Support this, even if only for backward compatibility. const LVecBase4 &data = _target_shader->get_shader_input_vector(name); - t.set(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; + into[0].set(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; } const NodePath &np = _target_shader->get_shader_input_nodepath(name->get_parent()); - nassertr(!np.is_empty(), &LMatrix4::ident_mat()); + nassertv(!np.is_empty()); - return fetch_specified_member(np, name->get_basename(), t); + fetch_specified_member(np, name->get_basename(), into[0]); + return; } case Shader::SMO_light_source_i_attrib: { const LightAttrib *target_light; @@ -1466,22 +1537,24 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, // We don't count ambient lights, which would be pretty silly to handle // via this mechanism. - size_t num_lights = target_light->get_num_non_ambient_lights(); - if (index >= 0 && (size_t)index < num_lights) { - NodePath light = target_light->get_on_light((size_t)index); - nassertr(!light.is_empty(), &LMatrix4::ident_mat()); - Light *light_obj = light.node()->as_light(); - nassertr(light_obj != nullptr, &LMatrix4::ident_mat()); + size_t num_lights = std::min((size_t)count, target_light->get_num_non_ambient_lights()); - return fetch_specified_member(light, name, t); - - } else if (index == 0) { - // Apply the default OpenGL lights otherwise. - // Special exception for light 0, which defaults to white. - string basename = name->get_basename(); - return &LMatrix4::ones_mat(); + size_t i = 0; + for (i = 0; i < num_lights; ++i) { + NodePath light = target_light->get_on_light(i); + nassertv(!light.is_empty()); + fetch_specified_member(light, name, into[i]); } - return fetch_specified_member(NodePath(), name, t); + // Apply the default OpenGL lights otherwise. + // Special exception for light 0, which defaults to white. + if (i == 0) { + into[0] = LMatrix4::ones_mat(); + ++i; + } + for (; i < (size_t)count; ++i) { + fetch_specified_member(NodePath(), name, into[i]); + } + return; } case Shader::SMO_light_source_i_packed: { // The light matrix contains COLOR, ATTENUATION, POSITION, VIEWVECTOR @@ -1490,15 +1563,17 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, // We don't count ambient lights, which would be pretty silly to handle // via this mechanism. - size_t num_lights = target_light->get_num_non_ambient_lights(); - if (index >= 0 && (size_t)index < num_lights) { - NodePath np = target_light->get_on_light((size_t)index); - nassertr(!np.is_empty(), &LMatrix4::ident_mat()); + size_t num_lights = std::min((size_t)count, target_light->get_num_non_ambient_lights()); + + size_t i = 0; + for (i = 0; i < num_lights; ++i) { + NodePath np = target_light->get_on_light(i); + nassertv(!np.is_empty()); PandaNode *node = np.node(); Light *light = node->as_light(); - nassertr(light != nullptr, &LMatrix4::zeros_mat()); - t.set_row(0, light->get_color()); - t.set_row(1, light->get_attenuation()); + nassertv(light != nullptr); + into[i].set_row(0, light->get_color()); + into[i].set_row(1, light->get_attenuation()); LMatrix4 mat = np.get_net_transform()->get_mat() * _scene_setup->get_world_transform()->get_mat(); @@ -1506,42 +1581,47 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, if (node->is_of_type(DirectionalLight::get_class_type())) { LVecBase3 d = mat.xform_vec(((const DirectionalLight *)node)->get_direction()); d.normalize(); - t.set_row(2, LVecBase4(d, 0)); - t.set_row(3, LVecBase4(-d, 0)); + into[i].set_row(2, LVecBase4(d, 0)); + into[i].set_row(3, LVecBase4(-d, 0)); } else if (node->is_of_type(LightLensNode::get_class_type())) { const Lens *lens = ((const LightLensNode *)node)->get_lens(); LPoint3 p = mat.xform_point(lens->get_nodal_point()); - t.set_row(3, LVecBase4(p)); + into[i].set_row(3, LVecBase4(p)); // For shadowed point light we need to store near/far. // For spotlight we need to store cutoff angle. if (node->is_of_type(Spotlight::get_class_type())) { PN_stdfloat cutoff = ccos(deg_2_rad(lens->get_hfov() * 0.5f)); LVecBase3 d = -(mat.xform_vec(lens->get_view_vector())); - t.set_cell(1, 3, ((const Spotlight *)node)->get_exponent()); - t.set_row(2, LVecBase4(d, cutoff)); + into[i].set_cell(1, 3, ((const Spotlight *)node)->get_exponent()); + into[i].set_row(2, LVecBase4(d, cutoff)); } else if (node->is_of_type(PointLight::get_class_type())) { - t.set_cell(1, 3, lens->get_far()); - t.set_cell(3, 3, lens->get_near()); + into[i].set_cell(1, 3, lens->get_far()); + into[i].set_cell(3, 3, lens->get_near()); if (node->is_of_type(SphereLight::get_class_type())) { - t.set_cell(2, 3, ((const SphereLight *)node)->get_radius()); + into[i].set_cell(2, 3, ((const SphereLight *)node)->get_radius()); } } } - } else if (index == 0) { - // Apply the default OpenGL lights otherwise. - // Special exception for light 0, which defaults to white. - t.set_row(0, LVecBase4(1, 1, 1, 1)); } - return &t; + // Apply the default OpenGL lights otherwise. + // Special exception for light 0, which defaults to white. + if (i == 0) { + into[0].set_row(0, LVecBase4(1, 1, 1, 1)); + ++i; + } + for (; i < (size_t)count; ++i) { + fetch_specified_member(NodePath(), name, into[i]); + } + return; } default: - nassertr(false /*should never get here*/, &LMatrix4::ident_mat()); - return &LMatrix4::ident_mat(); + nassertv(false /*should never get here*/); + return; } } @@ -1549,7 +1629,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, * Given a NodePath passed into a shader input that is a structure, fetches * the value for the given member. */ -const LMatrix4 *GraphicsStateGuardian:: +void GraphicsStateGuardian:: fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) { // This system is not ideal. It will be improved in the future. static const CPT_InternalName IN_color("color"); @@ -1575,20 +1655,19 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) if (attrib == IN_color) { if (node == nullptr) { - return &LMatrix4::ident_mat(); + t = LMatrix4::ident_mat(); } Light *light = node->as_light(); - nassertr(light != nullptr, &LMatrix4::ident_mat()); + nassertv(light != nullptr); LColor c = light->get_color(); t.set_row(3, c); - return &t; } else if (attrib == IN_ambient) { if (node == nullptr) { - return &LMatrix4::ident_mat(); + t = LMatrix4::ident_mat(); } Light *light = node->as_light(); - nassertr(light != nullptr, &LMatrix4::ident_mat()); + nassertv(light != nullptr); if (node->is_ambient_light()) { LColor c = light->get_color(); t.set_row(3, c); @@ -1596,14 +1675,13 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) // Non-ambient lights don't currently have an ambient color in Panda3D. t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f)); } - return &t; } else if (attrib == IN_diffuse) { if (node == nullptr) { - return &LMatrix4::ident_mat(); + t = LMatrix4::ident_mat(); } Light *light = node->as_light(); - nassertr(light != nullptr, &LMatrix4::ones_mat()); + nassertv(light != nullptr); if (node->is_ambient_light()) { // Ambient light has no diffuse color. t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f)); @@ -1611,39 +1689,34 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) LColor c = light->get_color(); t.set_row(3, c); } - return &t; } else if (attrib == IN_specular) { if (node == nullptr) { - return &LMatrix4::ident_mat(); + t = LMatrix4::ident_mat(); } Light *light = node->as_light(); - nassertr(light != nullptr, &LMatrix4::ones_mat()); + nassertv(light != nullptr); t.set_row(3, light->get_specular_color()); - return &t; } else if (attrib == IN_position) { if (np.is_empty()) { t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); - return &t; } else if (node->is_ambient_light()) { // Ambient light has no position. t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - return &t; } else if (node->is_of_type(DirectionalLight::get_class_type())) { DirectionalLight *light; - DCAST_INTO_R(light, node, &LMatrix4::ident_mat()); + DCAST_INTO_V(light, node); CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent()); LVector3 dir = -(light->get_direction() * transform->get_mat()); dir *= _scene_setup->get_cs_world_transform()->get_mat(); t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dir[0], dir[1], dir[2], 0); - return &t; } else { LightLensNode *light; - DCAST_INTO_R(light, node, &LMatrix4::ident_mat()); + DCAST_INTO_V(light, node); Lens *lens = light->get_lens(); - nassertr(lens != nullptr, &LMatrix4::ident_mat()); + nassertv(lens != nullptr); CPT(TransformState) transform = _scene_setup->get_cs_world_transform()->compose( @@ -1652,20 +1725,17 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) const LMatrix4 &light_mat = transform->get_mat(); LPoint3 pos = lens->get_nodal_point() * light_mat; t = LMatrix4::translate_mat(pos); - return &t; } } else if (attrib == IN_halfVector) { if (np.is_empty()) { t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); - return &t; } else if (node->is_ambient_light()) { // Ambient light has no half-vector. t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - return &t; } else if (node->is_of_type(DirectionalLight::get_class_type())) { DirectionalLight *light; - DCAST_INTO_R(light, node, &LMatrix4::ident_mat()); + DCAST_INTO_V(light, node); CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent()); LVector3 dir = -(light->get_direction() * transform->get_mat()); @@ -1674,12 +1744,11 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) dir += LVector3(0, 0, 1); dir.normalize(); t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dir[0], dir[1], dir[2], 1); - return &t; } else { LightLensNode *light; - DCAST_INTO_R(light, node, &LMatrix4::ident_mat()); + DCAST_INTO_V(light, node); Lens *lens = light->get_lens(); - nassertr(lens != nullptr, &LMatrix4::ident_mat()); + nassertv(lens != nullptr); CPT(TransformState) transform = _scene_setup->get_cs_world_transform()->compose( @@ -1691,22 +1760,19 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) pos += LVector3(0, 0, 1); pos.normalize(); t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pos[0],pos[1],pos[2], 1); - return &t; } } else if (attrib == IN_spotDirection) { if (node == nullptr) { t.set_row(3, LVector3(0.0f, 0.0f, -1.0f)); - return &t; } else if (node->is_ambient_light()) { // Ambient light has no spot direction. t.set_row(3, LVector3(0.0f, 0.0f, 0.0f)); - return &t; } else { LightLensNode *light; - DCAST_INTO_R(light, node, &LMatrix4::ident_mat()); + DCAST_INTO_V(light, node); Lens *lens = light->get_lens(); - nassertr(lens != nullptr, &LMatrix4::ident_mat()); + nassertv(lens != nullptr); CPT(TransformState) transform = _scene_setup->get_cs_world_transform()->compose( @@ -1715,93 +1781,87 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) const LMatrix4 &light_mat = transform->get_mat(); LVector3 dir = lens->get_view_vector() * light_mat; t.set_row(3, dir); - return &t; } } else if (attrib == IN_spotCutoff) { if (node != nullptr && node->is_of_type(Spotlight::get_class_type())) { LightLensNode *light; - DCAST_INTO_R(light, node, &LMatrix4::ident_mat()); + DCAST_INTO_V(light, node); Lens *lens = light->get_lens(); - nassertr(lens != nullptr, &LMatrix4::ident_mat()); + nassertv(lens != nullptr); float cutoff = lens->get_hfov() * 0.5f; t.set_row(3, LVecBase4(cutoff)); - return &t; } else { // Other lights have no cut-off. t.set_row(3, LVecBase4(180)); - return &t; } } else if (attrib == IN_spotCosCutoff) { if (node != nullptr && node->is_of_type(Spotlight::get_class_type())) { LightLensNode *light; - DCAST_INTO_R(light, node, &LMatrix4::ident_mat()); + DCAST_INTO_V(light, node); Lens *lens = light->get_lens(); - nassertr(lens != nullptr, &LMatrix4::ident_mat()); + nassertv(lens != nullptr); float cutoff = lens->get_hfov() * 0.5f; t.set_row(3, LVecBase4(ccos(deg_2_rad(cutoff)))); - return &t; } else { // Other lights have no cut-off. t.set_row(3, LVecBase4(-1)); - return &t; } } else if (attrib == IN_spotExponent) { if (node == nullptr) { - return &LMatrix4::zeros_mat(); + t = LMatrix4::zeros_mat(); + return; } Light *light = node->as_light(); - nassertr(light != nullptr, &LMatrix4::ident_mat()); + nassertv(light != nullptr); t.set_row(3, LVecBase4(light->get_exponent())); - return &t; } else if (attrib == IN_attenuation) { if (node != nullptr) { Light *light = node->as_light(); - nassertr(light != nullptr, &LMatrix4::ones_mat()); + nassertv(light != nullptr); t.set_row(3, LVecBase4(light->get_attenuation(), 0)); } else { t.set_row(3, LVecBase4(1, 0, 0, 0)); } - return &t; } else if (attrib == IN_constantAttenuation) { if (node == nullptr) { - return &LMatrix4::ones_mat(); + t = LMatrix4::ones_mat(); + return; } Light *light = node->as_light(); - nassertr(light != nullptr, &LMatrix4::ones_mat()); + nassertv(light != nullptr); t.set_row(3, LVecBase4(light->get_attenuation()[0])); - return &t; } else if (attrib == IN_linearAttenuation) { if (node == nullptr) { - return &LMatrix4::zeros_mat(); + t = LMatrix4::zeros_mat(); + return; } Light *light = node->as_light(); - nassertr(light != nullptr, &LMatrix4::ident_mat()); + nassertv(light != nullptr); t.set_row(3, LVecBase4(light->get_attenuation()[1])); - return &t; } else if (attrib == IN_quadraticAttenuation) { if (node == nullptr) { - return &LMatrix4::zeros_mat(); + t = LMatrix4::zeros_mat(); + return; } Light *light = node->as_light(); - nassertr(light != nullptr, &LMatrix4::ident_mat()); + nassertv(light != nullptr); t.set_row(3, LVecBase4(light->get_attenuation()[2])); - return &t; } else if (attrib == IN_shadowViewMatrix) { static const LMatrix4 biasmat(0.5f, 0.0f, 0.0f, 0.0f, @@ -1810,11 +1870,12 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) 0.5f, 0.5f, 0.5f, 1.0f); if (node == nullptr) { - return &biasmat; + t = biasmat; + return; } LensNode *lnode; - DCAST_INTO_R(lnode, node, &LMatrix4::ident_mat()); + DCAST_INTO_V(lnode, node); Lens *lens = lnode->get_lens(); t = _inv_cs_transform->get_mat() * @@ -1825,13 +1886,12 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) if (!node->is_of_type(PointLight::get_class_type())) { t *= lens->get_projection_mat() * biasmat; } - return &t; } else { display_cat.error() << "Shader input requests invalid attribute " << *attrib << " from node " << np << "\n"; - return &LMatrix4::ident_mat(); + t = LMatrix4::ident_mat(); } } diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index 2e165b6dc6..8d14ab9aba 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -336,10 +336,12 @@ public: virtual void clear(DrawableRegion *clearable); - const LMatrix4 *fetch_specified_value(Shader::ShaderMatSpec &spec, int altered); - const LMatrix4 *fetch_specified_part(Shader::ShaderMatInput input, InternalName *name, - LMatrix4 &t, int index); - const LMatrix4 *fetch_specified_member(const NodePath &np, CPT_InternalName member, LMatrix4 &t); + void update_shader_matrix_cache(Shader *shader, LMatrix4 *cache, int altered); + const LMatrix4 *fetch_specified_value(Shader::ShaderMatSpec &spec, const LMatrix4 *cache, int altered); + void fetch_specified_part(Shader::ShaderMatInput input, InternalName *name, + LMatrix4 *into, int count = 1); + void fetch_specified_member(const NodePath &np, CPT_InternalName member, + LMatrix4 &t); PT(Texture) fetch_specified_texture(Shader::ShaderTexSpec &spec, SamplerState &sampler, int &view); const Shader::ShaderPtrData *fetch_ptr_parameter(const Shader::ShaderPtrSpec& spec); diff --git a/panda/src/dxgsg9/dxShaderContext9.cxx b/panda/src/dxgsg9/dxShaderContext9.cxx index a737c342bf..6c7a15d313 100644 --- a/panda/src/dxgsg9/dxShaderContext9.cxx +++ b/panda/src/dxgsg9/dxShaderContext9.cxx @@ -74,6 +74,8 @@ DXShaderContext9(Shader *s, GSG *gsg) : ShaderContext(s) { } } #endif + + _mat_part_cache = new LMatrix4[s->cp_get_mat_cache_size()]; } /** @@ -92,6 +94,8 @@ DXShaderContext9:: delete _vertex_element_array; _vertex_element_array = nullptr; } + + delete[] _mat_part_cache; } /** @@ -232,15 +236,20 @@ issue_parameters(GSG *gsg, int altered) { } } - for (size_t i = 0; i < _shader->_mat_spec.size(); ++i) { - Shader::ShaderMatSpec &spec = _shader->_mat_spec[i]; + if (altered & _shader->_mat_deps) { + gsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered); + + for (Shader::ShaderMatSpec &spec : _shader->_mat_spec) { + if ((altered & spec._dep) == 0) { + continue; + } - if (altered & (spec._dep[0] | spec._dep[1])) { CGparameter p = _cg_parameter_map[spec._id._seqno]; if (p == nullptr) { continue; } - const LMatrix4 *val = gsg->fetch_specified_value(spec, altered); + + const LMatrix4 *val = gsg->fetch_specified_value(spec, _mat_part_cache, altered); if (val) { HRESULT hr; PN_stdfloat v [4]; diff --git a/panda/src/dxgsg9/dxShaderContext9.h b/panda/src/dxgsg9/dxShaderContext9.h index b637cb0a81..c02dcea201 100644 --- a/panda/src/dxgsg9/dxShaderContext9.h +++ b/panda/src/dxgsg9/dxShaderContext9.h @@ -87,6 +87,8 @@ private: pvector _cg_parameter_map; #endif + LMatrix4 *_mat_part_cache = nullptr; + private: void release_resources(void); diff --git a/panda/src/glstuff/glCgShaderContext_src.cxx b/panda/src/glstuff/glCgShaderContext_src.cxx index 8d90d1cd50..23d765b349 100644 --- a/panda/src/glstuff/glCgShaderContext_src.cxx +++ b/panda/src/glstuff/glCgShaderContext_src.cxx @@ -338,6 +338,8 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte } } + _mat_part_cache = new LMatrix4[_shader->cp_get_mat_cache_size()]; + _glgsg->report_my_gl_errors(); } @@ -347,6 +349,7 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte CLP(CgShaderContext):: ~CLP(CgShaderContext)() { // Don't call release_resources; we may not have an active context. + delete[] _mat_part_cache; } /** @@ -690,14 +693,14 @@ issue_parameters(int altered) { } if (altered & _shader->_mat_deps) { - for (int i = 0; i < (int)_shader->_mat_spec.size(); ++i) { - Shader::ShaderMatSpec &spec = _shader->_mat_spec[i]; + _glgsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered); - if ((altered & (spec._dep[0] | spec._dep[1])) == 0) { + for (Shader::ShaderMatSpec &spec : _shader->_mat_spec) { + if ((altered & spec._dep) == 0) { continue; } - const LMatrix4 *val = _glgsg->fetch_specified_value(spec, altered); + const LMatrix4 *val = _glgsg->fetch_specified_value(spec, _mat_part_cache, altered); if (!val) continue; const PN_stdfloat *data = val->get_data(); diff --git a/panda/src/glstuff/glCgShaderContext_src.h b/panda/src/glstuff/glCgShaderContext_src.h index 553cafe487..35a2d5dd36 100644 --- a/panda/src/glstuff/glCgShaderContext_src.h +++ b/panda/src/glstuff/glCgShaderContext_src.h @@ -75,6 +75,7 @@ private: long _transform_table_size; long _slider_table_size; + LMatrix4 *_mat_part_cache = nullptr; pvector _cg_parameter_map; WCPT(RenderState) _state_rs; diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index 6032417124..df510abf69 100644 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -228,9 +228,7 @@ parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, GLenum param_t bind._part[1] = Shader::SMO_apiclip_to_view; } - objShader->cp_optimize_mat_spec(bind); - objShader->_mat_spec.push_back(bind); - objShader->_mat_deps |= bind._dep[0] | bind._dep[1]; + objShader->cp_add_mat_spec(bind); if (param_size > 1) { // We support arrays of rows and arrays of columns, so we can run the @@ -243,7 +241,7 @@ parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, GLenum param_t for (int i = 1; i < param_size; ++i) { bind._id._seqno += 1; bind._piece = (Shader::ShaderMatPiece)((int)bind._piece + 1); - objShader->_mat_spec.push_back(bind); + objShader->cp_add_mat_spec(bind); } } else { GLCAT.warning() << basename << "[" << param_size << "] should not be an array, only the first element will be defined\n"; @@ -380,6 +378,8 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext } else { _glgsg->_current_shader_context->bind(); } + + _mat_part_cache = new LMatrix4[_shader->cp_get_mat_cache_size()]; } /** @@ -885,15 +885,12 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._part[0] = inverse ? Shader::SMO_inv_texmat_i : Shader::SMO_texmat_i; bind._part[1] = Shader::SMO_identity; - bind._dep[0] = Shader::SSD_general | Shader::SSD_tex_matrix; - bind._dep[1] = 0; // Add it once for each index. for (bind._index = 0; bind._index < param_size; ++bind._index) { bind._id._seqno = p + bind._index; - _shader->_mat_spec.push_back(bind); + _shader->cp_add_mat_spec(bind); } - _shader->_mat_deps |= bind._dep[0]; return; } else if (matrix_name.size() > 15 && @@ -938,9 +935,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { GLCAT.error() << "Unrecognized uniform matrix name '" << matrix_name << "'!\n"; return; } - _shader->cp_optimize_mat_spec(bind); - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0] | bind._dep[1]; + _shader->cp_add_mat_spec(bind); return; } if (size > 7 && noprefix.substr(0, 7) == "Texture") { @@ -973,10 +968,8 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_first; bind._part[0] = Shader::SMO_attr_material; bind._arg[0] = nullptr; - bind._dep[0] = Shader::SSD_general | Shader::SSD_material | Shader::SSD_frame; bind._part[1] = Shader::SMO_identity; bind._arg[1] = nullptr; - bind._dep[1] = Shader::SSD_NONE; if (noprefix == "Material.baseColor") { if (param_type != GL_FLOAT_VEC4) { @@ -985,9 +978,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { } bind._part[0] = Shader::SMO_attr_material2; bind._piece = Shader::SMP_row0; - bind._dep[0] |= Shader::SSD_color; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } else if (noprefix == "Material.ambient") { @@ -996,8 +987,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { << "p3d_Material.ambient should be vec4\n"; } bind._piece = Shader::SMP_row0; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } else if (noprefix == "Material.diffuse") { @@ -1006,8 +996,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { << "p3d_Material.diffuse should be vec4\n"; } bind._piece = Shader::SMP_row1; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } else if (noprefix == "Material.emission") { @@ -1016,8 +1005,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { << "p3d_Material.emission should be vec4\n"; } bind._piece = Shader::SMP_row2; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } else if (noprefix == "Material.specular") { @@ -1026,8 +1014,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { << "p3d_Material.specular should be vec3\n"; } bind._piece = Shader::SMP_row3x3; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } else if (noprefix == "Material.shininess") { @@ -1036,8 +1023,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { << "p3d_Material.shininess should be float\n"; } bind._piece = Shader::SMP_cell15; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } else if (noprefix == "Material.roughness") { @@ -1047,8 +1033,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { } bind._part[0] = Shader::SMO_attr_material2; bind._piece = Shader::SMP_cell15; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } else if (noprefix == "Material.metallic") { @@ -1058,8 +1043,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { } bind._part[0] = Shader::SMO_attr_material2; bind._piece = Shader::SMP_row3x1; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } else if (noprefix == "Material.refractiveIndex") { @@ -1069,8 +1053,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { } bind._part[0] = Shader::SMO_attr_material2; bind._piece = Shader::SMP_cell13; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } } @@ -1080,10 +1063,8 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_first; bind._part[0] = Shader::SMO_attr_colorscale; bind._arg[0] = nullptr; - bind._dep[0] = Shader::SSD_general | Shader::SSD_colorscale; bind._part[1] = Shader::SMO_identity; bind._arg[1] = nullptr; - bind._dep[1] = Shader::SSD_NONE; if (param_type == GL_FLOAT_VEC3) { bind._piece = Shader::SMP_row3x3; @@ -1094,8 +1075,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { << "p3d_ColorScale should be vec3 or vec4\n"; return; } - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } if (noprefix == "Color") { @@ -1104,10 +1084,8 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_first; bind._part[0] = Shader::SMO_attr_color; bind._arg[0] = nullptr; - bind._dep[0] = Shader::SSD_general | Shader::SSD_color; bind._part[1] = Shader::SMO_identity; bind._arg[1] = nullptr; - bind._dep[1] = Shader::SSD_NONE; if (param_type == GL_FLOAT_VEC3) { bind._piece = Shader::SMP_row3x3; @@ -1118,8 +1096,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { << "p3d_Color should be vec3 or vec4\n"; return; } - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } if (noprefix == "ClipPlane") { @@ -1137,12 +1114,9 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._index = i; bind._part[0] = Shader::SMO_apiview_clipplane_i; bind._arg[0] = nullptr; - bind._dep[0] = Shader::SSD_general | Shader::SSD_clip_planes; bind._part[1] = Shader::SMO_identity; bind._arg[1] = nullptr; - bind._dep[1] = Shader::SSD_NONE; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); } return; } @@ -1151,10 +1125,8 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._id = arg_id; bind._func = Shader::SMF_first; bind._arg[0] = nullptr; - bind._dep[0] = Shader::SSD_general | Shader::SSD_fog; bind._part[1] = Shader::SMO_identity; bind._arg[1] = nullptr; - bind._dep[1] = Shader::SSD_NONE; if (noprefix == "Fog.color") { bind._part[0] = Shader::SMO_attr_fogcolor; @@ -1214,8 +1186,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { } } - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } if (noprefix == "LightModel.ambient") { @@ -1224,10 +1195,8 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_first; bind._part[0] = Shader::SMO_light_ambient; bind._arg[0] = nullptr; - bind._dep[0] = Shader::SSD_general | Shader::SSD_light; bind._part[1] = Shader::SMO_identity; bind._arg[1] = nullptr; - bind._dep[1] = Shader::SSD_NONE; if (param_type == GL_FLOAT_VEC3) { bind._piece = Shader::SMP_row3x3; @@ -1238,8 +1207,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { << "p3d_LightModel.ambient should be vec3 or vec4\n"; return; } - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } if (size > 15 && noprefix.substr(0, 12) == "LightSource[") { @@ -1279,15 +1247,8 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._index = index; bind._part[0] = Shader::SMO_light_source_i_attrib; bind._arg[0] = InternalName::make(member_name); - bind._dep[0] = Shader::SSD_general | Shader::SSD_light | Shader::SSD_frame; bind._part[1] = Shader::SMO_identity; bind._arg[1] = nullptr; - bind._dep[1] = Shader::SSD_NONE; - - if (member_name == "position" || member_name == "halfVector" || - member_name == "spotDirection") { - bind._dep[0] |= Shader::SSD_view_transform; - } switch (param_type) { case GL_FLOAT: @@ -1311,8 +1272,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { << "p3d_LightSource[]." << member_name << " should be float or vec\n"; return; } - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0] | bind._dep[1]; + _shader->cp_add_mat_spec(bind); return; } } @@ -1344,13 +1304,10 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._index = 0; bind._part[0] = Shader::SMO_tex_is_alpha_i; bind._arg[0] = nullptr; - bind._dep[0] = Shader::SSD_general | Shader::SSD_texture | Shader::SSD_frame; bind._part[1] = Shader::SMO_identity; bind._arg[1] = nullptr; - bind._dep[1] = Shader::SSD_NONE; bind._piece = Shader::SMP_row3; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0] | bind._dep[1]; + _shader->cp_add_mat_spec(bind); return; } GLCAT.error() << "Unrecognized uniform name '" << param_name << "'!\n"; @@ -1371,10 +1328,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_compose; bind._part[0] = Shader::SMO_world_to_view; bind._part[1] = Shader::SMO_view_to_apiview; - bind._dep[0] = Shader::SSD_general | Shader::SSD_view_transform; - bind._dep[1] = Shader::SSD_general; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0] | bind._dep[1]; + _shader->cp_add_mat_spec(bind); return; } else if (noprefix == "InverseViewMatrix" || noprefix == "ViewMatrixInverse") { @@ -1382,10 +1336,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_compose; bind._part[0] = Shader::SMO_apiview_to_view; bind._part[1] = Shader::SMO_view_to_world; - bind._dep[0] = Shader::SSD_general; - bind._dep[1] = Shader::SSD_general | Shader::SSD_view_transform; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0] | bind._dep[1]; + _shader->cp_add_mat_spec(bind); return; } else if (noprefix == "FrameTime") { @@ -1393,10 +1344,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_first; bind._part[0] = Shader::SMO_frame_time; bind._part[1] = Shader::SMO_identity; - bind._dep[0] = Shader::SSD_general | Shader::SSD_frame; - bind._dep[1] = Shader::SSD_NONE; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0] | bind._dep[1]; + _shader->cp_add_mat_spec(bind); return; } else if (noprefix == "DeltaFrameTime") { @@ -1404,10 +1352,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_first; bind._part[0] = Shader::SMO_frame_delta; bind._part[1] = Shader::SMO_identity; - bind._dep[0] = Shader::SSD_general | Shader::SSD_frame; - bind._dep[1] = Shader::SSD_NONE; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0] | bind._dep[1]; + _shader->cp_add_mat_spec(bind); return; } else if (noprefix == "FrameNumber") { @@ -1491,12 +1436,9 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_first; bind._part[0] = Shader::SMO_mat_constant_x; bind._arg[0] = InternalName::make(param_name); - bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame; bind._part[1] = Shader::SMO_identity; bind._arg[1] = nullptr; - bind._dep[1] = Shader::SSD_NONE; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } case GL_FLOAT_MAT4: { @@ -1506,7 +1448,6 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_first; bind._part[1] = Shader::SMO_identity; bind._arg[1] = nullptr; - bind._dep[1] = Shader::SSD_NONE; PT(InternalName) iname = InternalName::make(param_name); if (iname->get_parent() != InternalName::get_root()) { // It might be something like an attribute of a shader input, like a @@ -1527,22 +1468,17 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_compose; bind._part[0] = Shader::SMO_model_to_apiview; bind._arg[0] = nullptr; - bind._dep[0] = Shader::SSD_general | Shader::SSD_transform; bind._part[1] = Shader::SMO_mat_constant_x_attrib; bind._arg[1] = iname->get_parent()->append("shadowViewMatrix"); - bind._dep[1] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_view_transform; } else { bind._part[0] = Shader::SMO_mat_constant_x_attrib; bind._arg[0] = InternalName::make(param_name); - bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_view_transform; } } else { bind._part[0] = Shader::SMO_mat_constant_x; bind._arg[0] = InternalName::make(param_name); - bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame; } - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } case GL_FLOAT: @@ -1572,14 +1508,9 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_first; bind._part[0] = Shader::SMO_vec_constant_x_attrib; bind._arg[0] = iname; - // We need SSD_view_transform since some attributes (eg. light - // position) have to be transformed to view space. - bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_view_transform; bind._part[1] = Shader::SMO_identity; bind._arg[1] = nullptr; - bind._dep[1] = Shader::SSD_NONE; - _shader->_mat_spec.push_back(bind); - _shader->_mat_deps |= bind._dep[0]; + _shader->cp_add_mat_spec(bind); return; } // else fall through } @@ -1913,6 +1844,7 @@ get_sampler_texture_type(int &out, GLenum param_type) { CLP(ShaderContext):: ~CLP(ShaderContext)() { // Don't call release_resources; we may not have an active context. + delete[] _mat_part_cache; } /** @@ -2230,14 +2162,14 @@ issue_parameters(int altered) { } if (altered & _shader->_mat_deps) { - for (int i = 0; i < (int)_shader->_mat_spec.size(); ++i) { - Shader::ShaderMatSpec &spec = _shader->_mat_spec[i]; + _glgsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered); - if ((altered & (spec._dep[0] | spec._dep[1])) == 0) { + for (Shader::ShaderMatSpec &spec : _shader->_mat_spec) { + if ((altered & spec._dep) == 0) { continue; } - const LMatrix4 *val = _glgsg->fetch_specified_value(spec, altered); + const LMatrix4 *val = _glgsg->fetch_specified_value(spec, _mat_part_cache, altered); if (!val) continue; #ifndef STDFLOAT_DOUBLE // In this case, the data is already single-precision. diff --git a/panda/src/glstuff/glShaderContext_src.h b/panda/src/glstuff/glShaderContext_src.h index 0ccb99fe90..06561336fa 100644 --- a/panda/src/glstuff/glShaderContext_src.h +++ b/panda/src/glstuff/glShaderContext_src.h @@ -114,6 +114,8 @@ private: }; pvector _glsl_img_inputs; + LMatrix4 *_mat_part_cache = nullptr; + CLP(GraphicsStateGuardian) *_glgsg; bool _uses_standard_vertex_arrays; diff --git a/panda/src/gobj/shader.cxx b/panda/src/gobj/shader.cxx index cf9631f660..a4b6881518 100644 --- a/panda/src/gobj/shader.cxx +++ b/panda/src/gobj/shader.cxx @@ -384,7 +384,7 @@ cp_dependency(ShaderMatInput inp) { if (inp == SMO_attr_material || inp == SMO_attr_material2) { dep |= SSD_material | SSD_frame; } - if (inp == SMO_attr_color) { + if (inp == SMO_attr_color || inp == SMO_attr_material2) { dep |= SSD_color; } if (inp == SMO_attr_colorscale) { @@ -422,6 +422,7 @@ cp_dependency(ShaderMatInput inp) { (inp == SMO_slight_x) || (inp == SMO_satten_x) || (inp == SMO_mat_constant_x) || + (inp == SMO_mat_constant_x_attrib) || (inp == SMO_vec_constant_x) || (inp == SMO_vec_constant_x_attrib) || (inp == SMO_view_x_to_view) || @@ -441,6 +442,8 @@ cp_dependency(ShaderMatInput inp) { (inp == SMO_plight_x) || (inp == SMO_slight_x) || (inp == SMO_satten_x) || + (inp == SMO_mat_constant_x) || + (inp == SMO_mat_constant_x_attrib) || (inp == SMO_vec_constant_x_attrib) || (inp == SMO_view_x_to_view) || (inp == SMO_view_to_view_x) || @@ -459,10 +462,13 @@ cp_dependency(ShaderMatInput inp) { (inp == SMO_light_source_i_attrib) || (inp == SMO_light_source_i_packed)) { dep |= SSD_light | SSD_frame; - if (inp == SMO_light_source_i_attrib || - inp == SMO_light_source_i_packed) { - dep |= SSD_view_transform; - } + } + if (inp == SMO_light_source_i_attrib || + inp == SMO_light_source_i_packed || + inp == SMO_mat_constant_x_attrib || + inp == SMO_vec_constant_x_attrib) { + // Some light attribs (eg. position) need to be transformed to view space. + dep |= SSD_view_transform; } if ((inp == SMO_light_product_i_ambient) || (inp == SMO_light_product_i_diffuse) || @@ -499,14 +505,10 @@ cp_dependency(ShaderMatInput inp) { } /** - * 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. + * Adds the given ShaderMatSpec to the shader's mat spec table. */ void Shader:: -cp_optimize_mat_spec(ShaderMatSpec &spec) { - +cp_add_mat_spec(ShaderMatSpec &spec) { // If we're composing with identity, simplify. if (spec._func == SMF_first) { @@ -563,10 +565,92 @@ cp_optimize_mat_spec(ShaderMatSpec &spec) { } } - // Calculate state and transform dependencies. + // Determine which part is an array, for determining which one the count and + // index refer to. (It can't be the case that both parts are arrays.) + int begin[2] = {0, 0}; + int end[2] = {1, 1}; + if (spec._index > 0) { + for (int i = 0; i < 2; ++i) { + if (spec._part[i] == SMO_texmat_i || + spec._part[i] == SMO_inv_texmat_i || + spec._part[i] == SMO_light_source_i_attrib || + spec._part[i] == SMO_light_product_i_ambient || + spec._part[i] == SMO_light_product_i_diffuse || + spec._part[i] == SMO_light_product_i_specular || + spec._part[i] == SMO_apiview_clipplane_i || + spec._part[i] == SMO_tex_is_alpha_i || + spec._part[i] == SMO_transform_i || + spec._part[i] == SMO_slider_i || + spec._part[i] == SMO_light_source_i_packed || + spec._part[i] == SMO_texscale_i || + spec._part[i] == SMO_texcolor_i) { + begin[i] = spec._index; + end[i] = spec._index + 1; + } + } + nassertv(end[0] == 1 || end[1] == 1); + } - spec._dep[0] = cp_dependency(spec._part[0]); - spec._dep[1] = cp_dependency(spec._part[1]); + // Make sure that we have a place in the part cache for both parts. + int num_parts = (spec._func != SMF_first) ? 2 : 1; + + for (int p = 0; p < num_parts; ++p) { + int dep = cp_dependency(spec._part[p]); + spec._dep |= dep; + + // Do we already have a spot in the cache for this part? + size_t i; + size_t offset = 0; + for (i = 0; i < _mat_parts.size(); ++i) { + ShaderMatPart &part = _mat_parts[i]; + if (part._part == spec._part[p] && part._arg == spec._arg[p]) { + int diff = end[p] - part._count; + if (diff <= 0) { + // The existing cache entry is big enough. + break; + } else { + // It's not big enough. Enlarge it, which means we have to change the + // offset of some of the other spec entries. + for (ShaderMatSpec &spec : _mat_spec) { + if (spec._cache_offset[0] >= offset + part._count) { + spec._cache_offset[0] += diff; + } + if (spec._cache_offset[1] >= offset + part._count) { + spec._cache_offset[1] += diff; + } + } + part._count = end[p]; + break; + } + } + offset += part._count; + } + if (i == _mat_parts.size()) { + // Didn't find this part yet, create a new one. + ShaderMatPart part; + part._part = spec._part[p]; + part._count = end[p]; + part._arg = spec._arg[p]; + part._dep = dep; + _mat_parts.push_back(std::move(part)); + } + spec._cache_offset[p] = offset + begin[p]; + } + + _mat_spec.push_back(spec); + _mat_deps |= spec._dep; +} + +/** + * Returns the total size of the matrix part cache. + */ +size_t Shader:: +cp_get_mat_cache_size() const { + size_t size = 0; + for (const ShaderMatPart &part : _mat_parts) { + size += part._count; + } + return size; } #ifdef HAVE_CG @@ -776,9 +860,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { bind._arg[0] = nullptr; bind._index = atoi(pieces[2].c_str()); - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -931,9 +1013,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { if (!cp_parse_eol(p, pieces, next)) { return false; } - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -1041,9 +1121,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { return false; } - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -1055,9 +1133,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { } ShaderMatSpec bind; - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -1079,9 +1155,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { bind._part[1] = SMO_identity; bind._arg[1] = nullptr; - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -1101,9 +1175,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { bind._part[1] = SMO_identity; bind._arg[1] = nullptr; - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -1143,9 +1215,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { if (!cp_parse_eol(p, pieces, next)) { return false; } - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -1166,9 +1236,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { bind._arg[1] = nullptr; bind._index = atoi(pieces[1].c_str()); - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -1189,9 +1257,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { bind._arg[1] = nullptr; bind._index = atoi(pieces[1].c_str()); - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -1212,9 +1278,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { bind._arg[1] = nullptr; bind._index = atoi(pieces[1].c_str()); - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -1234,9 +1298,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { bind._part[1] = SMO_identity; bind._arg[1] = nullptr; - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -1256,9 +1318,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { bind._part[1] = SMO_identity; bind._arg[1] = nullptr; - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -1303,9 +1363,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { return false; } - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -1388,9 +1446,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { bind._arg[0] = InternalName::make(pieces[1]); bind._part[1] = SMO_identity; bind._arg[1] = nullptr; - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -1409,9 +1465,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { bind._arg[0] = InternalName::make(pieces[1]); bind._part[1] = SMO_identity; bind._arg[1] = nullptr; - cp_optimize_mat_spec(bind); - _mat_spec.push_back(bind); - _mat_deps |= bind._dep[0] | bind._dep[1]; + cp_add_mat_spec(bind); return true; } @@ -2362,7 +2416,6 @@ Shader(ShaderLanguage lang) : _loaded(false), _language(lang), _last_modified(0), - _mat_deps(0), _cache_compiled_shader(false) { #ifdef HAVE_CG diff --git a/panda/src/gobj/shader.h b/panda/src/gobj/shader.h index 720025d7b0..0cc7ce1dae 100644 --- a/panda/src/gobj/shader.h +++ b/panda/src/gobj/shader.h @@ -402,15 +402,30 @@ public: INLINE void read_datagram(DatagramIterator &source); }; + /** + * Describes a matrix making up a single part of the ShaderMatInput cache. + * The cache is made up of a continuous array of matrices, as described by + * a successive list of ShaderMatPart (each of which takes up _count matrices) + */ + struct ShaderMatPart { + ShaderMatInput _part; + PT(InternalName) _arg; + int _count = 1; + int _dep = SSD_NONE; + }; + + /** + * Describes a shader input that is sourced from the render state. + */ struct ShaderMatSpec { - LMatrix4 _cache[2]; - LMatrix4 _value; + size_t _cache_offset[2]; ShaderArgId _id; ShaderMatFunc _func; ShaderMatInput _part[2]; PT(InternalName) _arg[2]; - int _dep[2]; - int _index; + LMatrix4 _value; + int _dep = SSD_NONE; + int _index = 0; ShaderMatPiece _piece; }; @@ -514,7 +529,8 @@ public: vector_string &pieces, int &next, ShaderMatSpec &spec, bool fromflag); int cp_dependency(ShaderMatInput inp); - void cp_optimize_mat_spec(ShaderMatSpec &spec); + void cp_add_mat_spec(ShaderMatSpec &spec); + size_t cp_get_mat_cache_size() const; #ifdef HAVE_CG void cg_recurse_parameters(CGparameter parameter, @@ -578,7 +594,9 @@ public: epvector _mat_spec; pvector _tex_spec; pvector _var_spec; - int _mat_deps; + pvector _mat_parts; + int _mat_deps = 0; + int _mat_cache_size = 0; bool _error_flag; ShaderFile _text; diff --git a/panda/src/pgraph/shaderAttrib.cxx b/panda/src/pgraph/shaderAttrib.cxx index 7647945291..fde1a99a3d 100644 --- a/panda/src/pgraph/shaderAttrib.cxx +++ b/panda/src/pgraph/shaderAttrib.cxx @@ -530,7 +530,8 @@ get_shader_input_matrix(const InternalName *id, LMatrix4 &matrix) const { if (p.get_value_type() == ShaderInput::M_nodepath) { const NodePath &np = p.get_nodepath(); nassertr(!np.is_empty(), LMatrix4::ident_mat()); - return np.get_transform()->get_mat(); + matrix = np.get_transform()->get_mat(); + return matrix; } else if (p.get_value_type() == ShaderInput::M_numeric && p.get_ptr()._size >= 16 && (p.get_ptr()._size & 15) == 0) {