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) {