diff --git a/src/ossia/dataflow/data.cpp b/src/ossia/dataflow/data.cpp index 415501b65bf..e2e7a1b3ef5 100644 --- a/src/ossia/dataflow/data.cpp +++ b/src/ossia/dataflow/data.cpp @@ -497,10 +497,4 @@ value_vector& value_port::get_data() { return data; } - -void geometry_port::clear() -{ - flags = {}; -} - } diff --git a/src/ossia/dataflow/data_copy.hpp b/src/ossia/dataflow/data_copy.hpp index fb50f0f9f56..1c4e3acbe8c 100644 --- a/src/ossia/dataflow/data_copy.hpp +++ b/src/ossia/dataflow/data_copy.hpp @@ -19,8 +19,6 @@ struct clear_data void operator()(audio_port& p) const { p.set_channels(0); } - void operator()(geometry_port& p) const { p.clear(); } - void operator()() const { } }; @@ -32,11 +30,6 @@ struct data_size std::size_t operator()(const audio_delay_line& p) const { return p.samples.size(); } - std::size_t operator()(const geometry_delay_line& p) const - { - return p.geometries.size(); - } - std::size_t operator()(const ossia::monostate&) const { return 0; } std::size_t operator()() const { return 0; } }; @@ -61,17 +54,6 @@ struct move_data in.messages = std::move(out.messages); out.messages = std::move(tmp); } - - void operator()(geometry_port& out, geometry_port& in) - { - // OPTIMIZEME - // if(out.flags & geometry_port::dirty_meshes) - in.geometry = out.geometry; //std::move(out.meshes); - // if(out.flags & geometry_port::dirty_transform) - in.transform = out.transform; - in.flags = out.flags; - out.flags = {}; - } }; struct copy_data @@ -157,30 +139,6 @@ struct copy_data // Called in env_writer, when copying from a node to a delay line in.messages.push_back(out.messages); } - - /// Geometry /// - void operator()(const geometry_port& out, geometry_port& in) - { - // Called in init_node_visitor::copy, when copying from a node to another - //if(out.flags & geometry_port::dirty_meshes) - in.geometry = out.geometry; - //if(out.flags & geometry_port::dirty_transform) - in.transform = out.transform; - in.flags = out.flags; - } - - void operator()(const geometry_spec& out, geometry_port& in) - { - // Called in copy_data_pos below - in.geometry = out; - } - - void operator()(const geometry_port& out, geometry_delay_line& in) - { - // Called in env_writer, when copying from a node to a delay line - // if(out.flags & geometry_port::dirty_meshes) - in.geometries.push_back(out.geometry); - } }; struct copy_data_pos @@ -188,39 +146,39 @@ struct copy_data_pos const std::size_t pos; template - void operator()(const T&, const U&) const + bool operator()(const T&, const U&) const { + return false; } - void operator()(const value_delay_line& out, value_port& in) + bool operator()(const value_delay_line& out, value_port& in) { if(pos < out.data.size()) { copy_data{}(out.data[pos], in); + return true; } + return false; } - void operator()(const audio_delay_line& out, audio_port& in) + bool operator()(const audio_delay_line& out, audio_port& in) { if(pos < out.samples.size()) { mix(out.samples[pos], in.get()); + return true; } + return false; } - void operator()(const midi_delay_line& out, midi_port& in) + bool operator()(const midi_delay_line& out, midi_port& in) { if(pos < out.messages.size()) { copy_data{}(out.messages[pos], in); + return true; } - } - void operator()(const geometry_delay_line& out, geometry_port& in) - { - if(pos < out.geometries.size()) - { - copy_data{}(out.geometries[pos], in); - } + return false; } }; } diff --git a/src/ossia/dataflow/dataflow_fwd.hpp b/src/ossia/dataflow/dataflow_fwd.hpp index 6930bf5c089..3aba85e08ed 100644 --- a/src/ossia/dataflow/dataflow_fwd.hpp +++ b/src/ossia/dataflow/dataflow_fwd.hpp @@ -55,10 +55,7 @@ struct geometry_port; struct audio_delay_line; struct midi_delay_line; struct value_delay_line; -struct geometry_delay_line; -// using data_type -// = ossia::nullable_variant; -using delay_line_type = ossia::nullable_variant< - audio_delay_line, midi_delay_line, value_delay_line, geometry_delay_line>; +using delay_line_type + = ossia::nullable_variant; } diff --git a/src/ossia/dataflow/geometry_port.cpp b/src/ossia/dataflow/geometry_port.cpp new file mode 100644 index 00000000000..262f4a6aac8 --- /dev/null +++ b/src/ossia/dataflow/geometry_port.cpp @@ -0,0 +1,173 @@ +#include + +#include +#include + +namespace ossia +{ + +struct semantic_entry +{ + attribute_semantic semantic; + std::string_view name; +}; + +static bool icase_equal(std::string_view a, std::string_view b) noexcept +{ + if(a.size() != b.size()) + return false; + for(std::size_t i = 0; i < a.size(); ++i) + if(std::tolower(static_cast(a[i])) + != std::tolower(static_cast(b[i]))) + return false; + return true; +} + +// Sorted by enum value for binary search in semantic_to_name. +// Sorted by name for binary search in name_to_semantic (separate array below). +static constexpr std::array semantic_table = { + // Core geometry + semantic_entry{attribute_semantic::position, "position"}, + semantic_entry{attribute_semantic::normal, "normal"}, + semantic_entry{attribute_semantic::tangent, "tangent"}, + semantic_entry{attribute_semantic::bitangent, "bitangent"}, + + // Basic materials + semantic_entry{attribute_semantic::texcoord0, "texcoord0"}, + semantic_entry{attribute_semantic::texcoord1, "texcoord1"}, + semantic_entry{attribute_semantic::texcoord2, "texcoord2"}, + semantic_entry{attribute_semantic::texcoord3, "texcoord3"}, + semantic_entry{attribute_semantic::texcoord4, "texcoord4"}, + semantic_entry{attribute_semantic::texcoord5, "texcoord5"}, + semantic_entry{attribute_semantic::texcoord6, "texcoord6"}, + semantic_entry{attribute_semantic::texcoord7, "texcoord7"}, + + semantic_entry{attribute_semantic::color0, "color0"}, + semantic_entry{attribute_semantic::color1, "color1"}, + semantic_entry{attribute_semantic::color2, "color2"}, + semantic_entry{attribute_semantic::color3, "color3"}, + + // Skinning / skeletal animation + semantic_entry{attribute_semantic::joints0, "joints0"}, + semantic_entry{attribute_semantic::joints1, "joints1"}, + semantic_entry{attribute_semantic::weights0, "weights0"}, + semantic_entry{attribute_semantic::weights1, "weights1"}, + + // Morph targets / blend shapes + semantic_entry{attribute_semantic::morph_position, "morph_position"}, + semantic_entry{attribute_semantic::morph_normal, "morph_normal"}, + semantic_entry{attribute_semantic::morph_tangent, "morph_tangent"}, + semantic_entry{attribute_semantic::morph_texcoord, "morph_texcoord"}, + semantic_entry{attribute_semantic::morph_color, "morph_color"}, + + // Transform / instancing + semantic_entry{attribute_semantic::rotation, "rotation"}, + semantic_entry{attribute_semantic::rotation_extra, "rotation_extra"}, + semantic_entry{attribute_semantic::scale, "scale"}, + semantic_entry{attribute_semantic::uniform_scale, "uniform_scale"}, + semantic_entry{attribute_semantic::up, "up"}, + semantic_entry{attribute_semantic::pivot, "pivot"}, + semantic_entry{attribute_semantic::transform_matrix, "transform_matrix"}, + semantic_entry{attribute_semantic::translation, "translation"}, + + // Particle dynamics + semantic_entry{attribute_semantic::velocity, "velocity"}, + semantic_entry{attribute_semantic::acceleration, "acceleration"}, + semantic_entry{attribute_semantic::force, "force"}, + semantic_entry{attribute_semantic::mass, "mass"}, + semantic_entry{attribute_semantic::age, "age"}, + semantic_entry{attribute_semantic::lifetime, "lifetime"}, + semantic_entry{attribute_semantic::birth_time, "birth_time"}, + semantic_entry{attribute_semantic::particle_id, "particle_id"}, + semantic_entry{attribute_semantic::drag, "drag"}, + semantic_entry{attribute_semantic::angular_velocity, "angular_velocity"}, + semantic_entry{attribute_semantic::previous_position, "previous_position"}, + semantic_entry{attribute_semantic::rest_position, "rest_position"}, + semantic_entry{attribute_semantic::target_position, "target_position"}, + semantic_entry{attribute_semantic::previous_velocity, "previous_velocity"}, + semantic_entry{attribute_semantic::state, "state"}, + semantic_entry{attribute_semantic::collision_count, "collision_count"}, + semantic_entry{attribute_semantic::collision_normal, "collision_normal"}, + semantic_entry{attribute_semantic::sleep, "sleep"}, + + // Rendering hints + semantic_entry{attribute_semantic::sprite_size, "sprite_size"}, + semantic_entry{attribute_semantic::sprite_rotation, "sprite_rotation"}, + semantic_entry{attribute_semantic::sprite_facing, "sprite_facing"}, + semantic_entry{attribute_semantic::sprite_index, "sprite_index"}, + semantic_entry{attribute_semantic::width, "width"}, + semantic_entry{attribute_semantic::opacity, "opacity"}, + semantic_entry{attribute_semantic::emissive, "emissive"}, + semantic_entry{attribute_semantic::emissive_strength, "emissive_strength"}, + + // Material / PBR + semantic_entry{attribute_semantic::roughness, "roughness"}, + semantic_entry{attribute_semantic::metallic, "metallic"}, + semantic_entry{attribute_semantic::ambient_occlusion, "ambient_occlusion"}, + semantic_entry{attribute_semantic::specular, "specular"}, + semantic_entry{attribute_semantic::subsurface, "subsurface"}, + semantic_entry{attribute_semantic::clearcoat, "clearcoat"}, + semantic_entry{attribute_semantic::clearcoat_roughness, "clearcoat_roughness"}, + semantic_entry{attribute_semantic::anisotropy, "anisotropy"}, + semantic_entry{attribute_semantic::anisotropy_direction, "anisotropy_direction"}, + semantic_entry{attribute_semantic::ior, "ior"}, + semantic_entry{attribute_semantic::transmission, "transmission"}, + semantic_entry{attribute_semantic::thickness, "thickness"}, + semantic_entry{attribute_semantic::material_id, "material_id"}, + + // Gaussian splatting + semantic_entry{attribute_semantic::sh_dc, "sh_dc"}, + semantic_entry{attribute_semantic::sh_coeffs, "sh_coeffs"}, + semantic_entry{attribute_semantic::covariance_3d, "covariance_3d"}, + semantic_entry{attribute_semantic::sh_degree, "sh_degree"}, + + // Volumetric / field data + semantic_entry{attribute_semantic::density, "density"}, + semantic_entry{attribute_semantic::temperature, "temperature"}, + semantic_entry{attribute_semantic::fuel, "fuel"}, + semantic_entry{attribute_semantic::pressure, "pressure"}, + semantic_entry{attribute_semantic::divergence, "divergence"}, + semantic_entry{attribute_semantic::sdf_distance, "sdf_distance"}, + semantic_entry{attribute_semantic::voxel_color, "voxel_color"}, + + // Topology / connectivity + semantic_entry{attribute_semantic::name, "name"}, + semantic_entry{attribute_semantic::piece_id, "piece_id"}, + semantic_entry{attribute_semantic::line_id, "line_id"}, + semantic_entry{attribute_semantic::prim_id, "prim_id"}, + semantic_entry{attribute_semantic::point_id, "point_id"}, + semantic_entry{attribute_semantic::group_mask, "group_mask"}, + semantic_entry{attribute_semantic::instance_id, "instance_id"}, + + // UI + semantic_entry{attribute_semantic::selection, "selection"}, + + // User / general purpose + semantic_entry{attribute_semantic::fx0, "fx0"}, + semantic_entry{attribute_semantic::fx1, "fx1"}, + semantic_entry{attribute_semantic::fx2, "fx2"}, + semantic_entry{attribute_semantic::fx3, "fx3"}, + semantic_entry{attribute_semantic::fx4, "fx4"}, + semantic_entry{attribute_semantic::fx5, "fx5"}, + semantic_entry{attribute_semantic::fx6, "fx6"}, + semantic_entry{attribute_semantic::fx7, "fx7"}, +}; + +std::string_view semantic_to_name(attribute_semantic s) noexcept +{ + // FIXME lower_bound or boost::bimap if there's a constexpr one + for(auto& e : semantic_table) + if(e.semantic == s) + return e.name; + return {}; +} + +attribute_semantic name_to_semantic(std::string_view name) noexcept +{ + for(auto& e : semantic_table) + if(icase_equal(e.name, name)) + return e.semantic; + return attribute_semantic::custom; +} + +} diff --git a/src/ossia/dataflow/geometry_port.hpp b/src/ossia/dataflow/geometry_port.hpp index c7579339013..ad39f4b35ce 100644 --- a/src/ossia/dataflow/geometry_port.hpp +++ b/src/ossia/dataflow/geometry_port.hpp @@ -4,11 +4,156 @@ #include #include +#include #include #include +#include namespace ossia { + +// clang-format off +// Semantic identification for geometry attributes. +// Custom attributes use attribute_semantic::custom + a string name. +enum class attribute_semantic : uint16_t +{ + // Core geometry + position = 0, // vec3. Object-space position. + normal = 1, // vec3. Surface normal. + tangent = 2, // vec4. xyz=tangent, w=handedness (±1). [glTF TANGENT] + bitangent = 3, // vec3. cross(N, T.xyz) * T.w. + + // Basic materials + texcoord0 = 100, // vec2/3. Primary UV. [glTF TEXCOORD_0] + texcoord1 = texcoord0 + 1, // vec2. Secondary UV (lightmaps). [glTF TEXCOORD_1] + texcoord2 = texcoord0 + 2, // vec2. Secondary UV. [glTF TEXCOORD_2] + texcoord3 = texcoord0 + 3, // vec2. Secondary UV. [glTF TEXCOORD_3] + texcoord4 = texcoord0 + 4, // vec2. Secondary UV. [glTF TEXCOORD_4] + texcoord5 = texcoord0 + 5, // vec2. Secondary UV. + texcoord6 = texcoord0 + 6, // vec2. Secondary UV. + texcoord7 = texcoord0 + 7, // vec2. Secondary UV. + + color0 = 200, // vec4. Vertex color RGBA. [glTF COLOR_0] + color1 = color0 + 1, // vec4. Secondary vertex color. [glTF COLOR_1] + color2 = color0 + 2, // vec4. Secondary vertex color. + color3 = color0 + 3, // vec4. Secondary vertex color. + + // Skinning / skeletal animation + joints0 = 300, // uvec4. Bone indices, set 0. [glTF JOINTS_0] + joints1 = joints0 + 1, // uvec4. Bone indices, set 1. [glTF JOINTS_1] + + weights0 = 400, // vec4. Bone weights, set 0. [glTF WEIGHTS_0] + weights1 = weights0 + 1, // vec4. Bone weights, set 1. [glTF WEIGHTS_1] + + // Morph targets / blend shapes + morph_position = 500, // vec3. Position delta for morph target. + morph_normal = morph_position + 1, // vec3. Normal delta for morph target. + morph_tangent = morph_position + 2, // vec3. Tangent delta (no w). [glTF morph TANGENT] + morph_texcoord = morph_position + 3, // vec2. UV delta for morph target. + morph_color = morph_position + 4, // vec3/4. Color delta for morph target. + + // Transform / instancing + rotation = 600, // vec4. Quaternion (x,y,z,w). + rotation_extra = morph_position + 1, // vec4. Post-orient rotation. + scale = morph_position + 2, // vec3. Non-uniform scale. + uniform_scale = morph_position + 3, // float. Uniform scale. + up = morph_position + 4, // vec3. Up vector for LookAt. + pivot = morph_position + 5, // vec3. Local pivot point. + transform_matrix = morph_position + 6, // mat4. Full transform, overrides TRS. (note: remember that mat4 takes 4 lanes of attributes) + translation = morph_position + 7, // vec3. Additional translation offset. + + // Particle dynamics + velocity = 1000, // vec3. Velocity in units/sec. + acceleration = velocity + 1, // vec3. Current acceleration. + force = velocity + 2, // vec3. Accumulated force this frame. + mass = velocity + 3, // float. + age = velocity + 4, // float. Time since birth, seconds. + lifetime = velocity + 5, // float. Max age before death. + birth_time = velocity + 6, // float. Absolute time of birth. + particle_id = velocity + 7, // int. Stable unique ID. + drag = velocity + 8, // float. Per-particle drag coefficient. + angular_velocity = velocity + 9, // vec3. Rotation speed rad/sec. + previous_position = velocity + 10, // vec3. For Verlet / motion blur. + rest_position = velocity + 11, // vec3. Undeformed position. + target_position = velocity + 12, // vec3. Goal position for constraints. + previous_velocity = velocity + 13, // vec3. Velocity at previous frame. + state = velocity + 14, // int. alive/dying/dead/collided enum. + collision_count = velocity + 15, // int. Number of collisions. + collision_normal = velocity + 16, // vec3. Normal at last collision. + sleep = velocity + 17, // int. Dormant flag (skip simulation). + + // Rendering hints + sprite_size = 1100, // vec2. Billboard width/height. + sprite_rotation = sprite_size + 1, // float. Billboard screen-space rotation. + sprite_facing = sprite_size + 2, // vec3. Custom billboard facing direction. + sprite_index = sprite_size + 3, // int/float. Sub-image index for sprite sheets. + width = sprite_size + 4, // float. Curve/ribbon thickness. + opacity = sprite_size + 5, // float. Separate from color alpha. + emissive = sprite_size + 6, // vec3. Self-illumination color. + emissive_strength = sprite_size + 7, // float. Emissive intensity multiplier. + + // Material / PBR + roughness = 1200, // float. PBR roughness [0-1]. + metallic = roughness + 1, // float. PBR metalness [0-1]. + ambient_occlusion = roughness + 2, // float. Baked AO [0-1]. + specular = roughness + 3, // float. Specular factor. + subsurface = roughness + 4, // float. SSS intensity. + clearcoat = roughness + 5, // float. Clearcoat factor. + clearcoat_roughness = roughness + 6, // float. Clearcoat roughness. + anisotropy = roughness + 7, // float. Anisotropic reflection. + anisotropy_direction = roughness + 8, // vec3. Anisotropy tangent direction. + ior = roughness + 9, // float. Index of refraction. + transmission = roughness + 10, // float. Transmission factor (glass-like). + thickness = roughness + 11, // float. Volume thickness for transmission. + material_id = roughness + 22, // int. Index into material array. + + // Gaussian splatting + sh_dc = 1300, // vec3. SH degree-0 (DC) color. + sh_coeffs = sh_dc + 1, // float[N]. SH coefficients for higher degrees. + covariance_3d = sh_dc + 2, // vec6 or mat3. 3D covariance (6 unique floats). + sh_degree = sh_dc + 3, // int. Active SH degree for this splat (0-3). + + // Volumetric / field data + density = 1400, // float. Scalar density. + temperature = density + 1, // float. + fuel = density + 2, // float. + pressure = density + 3, // float. + divergence = density + 4, // float. + sdf_distance = density + 5, // float. Signed distance field value. + voxel_color = density + 6, // vec4. Per-voxel RGBA. + + // Topology / connectivity + name = 1600, // string. Piece/group identifier. + piece_id = name + 1, // int. Numeric piece/group index. + line_id = name + 2, // int. Which line strip this point belongs to. + prim_id = name + 3, // int. Source primitive index. + point_id = name + 4, // int. Stable point ID (distinct from array index). + group_mask = name + 5, // int. Bitfield for group membership. + instance_id = name + 6, // int. Which instance this element belongs to. + + // UI + selection = 1700, // float. Soft selection weight [0-1]. + + // User / general purpose + fx0 = 2000, // float. General-purpose effect control. + fx1 = fx0 + 1, // float. General-purpose effect control. + fx2 = fx0 + 2, // float. General-purpose effect control. + fx3 = fx0 + 3, // float. General-purpose effect control. + fx4 = fx0 + 4, // float. General-purpose effect control. + fx5 = fx0 + 5, // float. General-purpose effect control. + fx6 = fx0 + 6, // float. General-purpose effect control. + fx7 = fx0 + 7, // float. General-purpose effect control. + + // Custom (string name lookup) + custom = 0xFFFF +}; + +// Returns a display name for well-known semantics, empty for custom. +OSSIA_EXPORT std::string_view semantic_to_name(attribute_semantic s) noexcept; + +// Returns the semantic for a well-known name, or custom if not recognized. +OSSIA_EXPORT attribute_semantic name_to_semantic(std::string_view name) noexcept; + struct geometry { struct cpu_buffer @@ -27,6 +172,7 @@ struct geometry { ossia::variant data; bool dirty{}; + int64_t active_element_count{-1}; // -1 = use full buffer; else first N elements valid }; struct binding @@ -78,6 +224,12 @@ struct geometry = float4; uint32_t byte_offset = 0; + + // Semantic identification for this attribute. + // For well-known semantics, name is empty (derivable from the enum). + // For custom semantics, name holds the user-defined attribute name. + attribute_semantic semantic = attribute_semantic::custom; + std::string name; }; struct input @@ -123,6 +275,67 @@ struct geometry uint32 } format{}; } index; + + // Axis-aligned bounding box. All zeros = not computed. + struct + { + float min[3]{}; + float max[3]{}; + } bounds; + + // Optional GPU buffer holding a uint32 element count for indirect dispatch/draw. + // When set, renderers can use drawIndirect/dispatchIndirect. + gpu_buffer indirect_count; + + // Auxiliary structured buffers that travel with the geometry. + // These are NOT per-vertex attributes; they are opaque buffers with + // application-defined internal layouts (e.g. particle bookkeeping structs, + // indirect dispatch/draw args, index lists). + // The buffer data lives in the `buffers` array; this struct references it. + // Consumers match by name against their shader storage declarations. + struct auxiliary_buffer + { + std::string name; // Shader-visible name for matching (e.g. "particle_aux") + int buffer{-1}; // Index into the buffers array + int64_t byte_offset{}; // Offset within the buffer + int64_t byte_size{}; // Size of the auxiliary data region + }; + ossia::small_vector auxiliary; + + // Find an auxiliary buffer by name. Returns nullptr if not found. + const auxiliary_buffer* find_auxiliary(std::string_view name) const noexcept + { + for(auto& a : auxiliary) + if(a.name == name) + return &a; + return nullptr; + } + + // Find an attribute by semantic enum. Returns nullptr if not found. + const attribute* find(attribute_semantic sem) const noexcept + { + for(auto& a : attributes) + if(a.semantic == sem) + return &a; + return nullptr; + } + + // Find a custom attribute by name. Returns nullptr if not found. + const attribute* find(std::string_view attr_name) const noexcept + { + for(auto& a : attributes) + if(a.semantic == attribute_semantic::custom && a.name == attr_name) + return &a; + return nullptr; + } + + // Returns the display name for an attribute (semantic name or custom name). + static std::string_view display_name(const attribute& a) noexcept + { + if(a.semantic != attribute_semantic::custom) + return semantic_to_name(a.semantic); + return a.name; + } }; struct mesh_list @@ -182,22 +395,5 @@ struct geometry_spec struct OSSIA_EXPORT geometry_port { static const constexpr int which = 4; - enum dirt_flags - { - dirty_transform = 0x1, - dirty_meshes = 0x2 - }; - - void clear(); - - geometry_spec geometry; - transform3d transform; - uint8_t flags{}; -}; - -struct geometry_delay_line -{ - std::vector geometries; }; - } diff --git a/src/ossia/dataflow/graph/graph.hpp b/src/ossia/dataflow/graph/graph.hpp index 3e4fe7769fb..84884fe0a02 100644 --- a/src/ossia/dataflow/graph/graph.hpp +++ b/src/ossia/dataflow/graph/graph.hpp @@ -230,7 +230,8 @@ class OSSIA_EXPORT graph final const auto N = boost::num_vertices(impl); m_topo_order_cache.clear(); m_topo_order_cache.reserve(N); - boost::topological_sort(gr, std::back_inserter(m_topo_order_cache)); + auto view = boost::filtered_graph(gr, no_delay_edges{&gr}); + boost::topological_sort(view, std::back_inserter(m_topo_order_cache)); nodes.clear(); nodes.reserve(N); diff --git a/src/ossia/dataflow/graph/graph_ordering.hpp b/src/ossia/dataflow/graph/graph_ordering.hpp index a06cfd6c87f..515582ba44b 100644 --- a/src/ossia/dataflow/graph/graph_ordering.hpp +++ b/src/ossia/dataflow/graph/graph_ordering.hpp @@ -77,7 +77,7 @@ struct init_node_visitor const graph_edge& edge; execution_state& e; - static void copy(const delay_line_type& out, std::size_t pos, inlet& in) + static bool copy(const delay_line_type& out, std::size_t pos, inlet& in) { const auto w = out.which(); if(w.to_std_index() == in.which() && w.valid()) @@ -85,27 +85,20 @@ struct init_node_visitor switch(w.index()) { case delay_line_type::index_of().index(): - copy_data_pos{pos}( + return copy_data_pos{pos}( *reinterpret_cast(out.target()), in.cast()); - break; case delay_line_type::index_of().index(): - copy_data_pos{pos}( + return copy_data_pos{pos}( *reinterpret_cast(out.target()), in.cast()); - break; case delay_line_type::index_of().index(): - copy_data_pos{pos}( + return copy_data_pos{pos}( *reinterpret_cast(out.target()), in.cast()); - break; - case delay_line_type::index_of().index(): - copy_data_pos{pos}( - *reinterpret_cast(out.target()), - in.cast()); - break; } } + return false; } static void move(outlet& out, inlet& in) @@ -124,9 +117,6 @@ struct init_node_visitor case ossia::value_port::which: move_data{}(out.cast(), in.cast()); break; - case ossia::geometry_port::which: - move_data{}(out.cast(), in.cast()); - break; } } } @@ -153,10 +143,6 @@ struct init_node_visitor case ossia::value_port::which: copy_data{}(out.cast(), in.cast()); break; - case ossia::geometry_port::which: - copy_data{}( - out.cast(), in.cast()); - break; } } } @@ -186,17 +172,15 @@ struct init_node_visitor bool operator()(delayed_glutton_connection& con) const { - // TODO If there is data... - // Else... - copy(con.buffer, con.pos, in); - con.pos++; + if(copy(con.buffer, con.pos, in)) + con.pos++; return false; } bool operator()(delayed_strict_connection& con) const { - copy(con.buffer, con.pos, in); - con.pos++; + if(copy(con.buffer, con.pos, in)) + con.pos++; return false; } diff --git a/src/ossia/dataflow/graph/graph_static.hpp b/src/ossia/dataflow/graph/graph_static.hpp index 18bfb96d462..0c8c8402b57 100644 --- a/src/ossia/dataflow/graph/graph_static.hpp +++ b/src/ossia/dataflow/graph/graph_static.hpp @@ -16,6 +16,8 @@ namespace ossia { +using filtered_graph_t = std::decay_t(), no_delay_edges{nullptr}))>; template struct graph_static final : public graph_util @@ -25,7 +27,7 @@ struct graph_static final UpdateImpl update_fun; TickImpl tick_fun{*this}; std::vector m_color_map_cache; - std::vector> m_stack_cache; + std::vector> m_stack_cache; explicit graph_static(const ossia::graph_setup_options& opt = {}) : update_fun{*this, opt} { @@ -50,8 +52,10 @@ struct graph_static final // TODO this should be doable with a single vector m_topo_order_cache.clear(); m_topo_order_cache.reserve(m_nodes.size()); - custom_topological_sort( - gr, std::back_inserter(m_topo_order_cache), m_color_map_cache, m_stack_cache); + auto view = boost::filtered_graph{gr, no_delay_edges{&gr}}; + custom_topological_sort( + view, std::back_inserter(m_topo_order_cache), m_color_map_cache, + m_stack_cache); // First put the ones without any I/O (most likely states) for(auto vtx : m_topo_order_cache) diff --git a/src/ossia/dataflow/graph/graph_utils.hpp b/src/ossia/dataflow/graph/graph_utils.hpp index 5619073e622..289ec53db05 100644 --- a/src/ossia/dataflow/graph/graph_utils.hpp +++ b/src/ossia/dataflow/graph/graph_utils.hpp @@ -18,6 +18,7 @@ #include #include +#include #include // broken due to dynamic_property_map requiring rtti... // #include @@ -96,19 +97,26 @@ namespace boost { namespace detail { + template +using VertexDescriptor = typename graph_traits::vertex_descriptor; +template +using OutEdgeIterator = std::decay_t( + out_edges(std::declval>(), std::declval())))>; + +template using DFSVertexInfo = std::pair< typename graph_traits::vertex_descriptor, std::pair< boost::optional::edge_descriptor>, - std::pair< - typename graph_traits::out_edge_iterator, - typename graph_traits::out_edge_iterator>>>; + std::pair, OutEdgeIterator>>>; -template +template < + typename IncidenceGraph, typename FilteredGraph, class DFSVisitor, class ColorMap> void custom_depth_first_visit_impl( - const IncidenceGraph& g, typename graph_traits::vertex_descriptor u, - DFSVisitor& vis, ColorMap color, std::vector>& stack) + const FilteredGraph& g, typename graph_traits::vertex_descriptor u, + DFSVisitor& vis, ColorMap color, + std::vector>& stack) { constexpr detail::nontruth2 func; BOOST_CONCEPT_ASSERT((IncidenceGraphConcept)); @@ -124,7 +132,6 @@ void custom_depth_first_visit_impl( VertexInfo; boost::optional src_e; - Iter ei, ei_end; // Possible optimization for vector stack.clear(); @@ -132,7 +139,8 @@ void custom_depth_first_visit_impl( put(color, u, Color::gray()); vis.discover_vertex(u, g); - boost::tie(ei, ei_end) = out_edges(u, g); + auto [ei, ei_end] = out_edges(u, g); + if(func(u, g)) { // If this vertex terminates the search, we push empty range @@ -146,7 +154,7 @@ void custom_depth_first_visit_impl( } while(!stack.empty()) { - VertexInfo& back = stack.back(); + auto& back = stack.back(); u = back.first; src_e = back.second.first; boost::tie(ei, ei_end) = back.second.second; @@ -197,19 +205,19 @@ void custom_depth_first_visit_impl( } } -template +template < + typename VertexListGraph, typename FilteredGraph, class DFSVisitor, class ColorMap> void custom_depth_first_search( - const VertexListGraph& g, DFSVisitor vis, ColorMap color, + const FilteredGraph& g, DFSVisitor vis, ColorMap color, typename graph_traits::vertex_descriptor start_vertex, - std::vector>& stack) + std::vector>& stack) { typedef typename graph_traits::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT((DFSVisitorConcept)); typedef typename property_traits::value_type ColorValue; typedef color_traits Color; - typename graph_traits::vertex_iterator ui, ui_end; - for(boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) + for(auto [ui, ui_end] = vertices(g); ui != ui_end; ++ui) { Vertex u = implicit_cast(*ui); put(color, u, Color::white()); @@ -219,17 +227,18 @@ void custom_depth_first_search( if(start_vertex != detail::get_default_starting_vertex(g)) { vis.start_vertex(start_vertex, g); - detail::custom_depth_first_visit_impl(g, start_vertex, vis, color, stack); + detail::custom_depth_first_visit_impl( + g, start_vertex, vis, color, stack); } - for(boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) + for(auto [ui, ui_end] = vertices(g); ui != ui_end; ++ui) { Vertex u = implicit_cast(*ui); ColorValue u_color = get(color, u); if(u_color == Color::white()) { vis.start_vertex(u, g); - detail::custom_depth_first_visit_impl(g, u, vis, color, stack); + detail::custom_depth_first_visit_impl(g, u, vis, color, stack); } } } @@ -244,11 +253,11 @@ inline void remove_vertex(typename graph_t::vertex_descriptor v, graph_t& g) boost::detail::remove_vertex_dispatch(g, v, Cat()); } -template +template void custom_topological_sort( - VertexListGraph& g, OutputIterator result, + FilteredGraph& g, OutputIterator result, std::vector& color_map, - std::vector>& stack) + std::vector>& stack) { color_map.clear(); color_map.resize(boost::num_vertices(g)); @@ -256,7 +265,7 @@ void custom_topological_sort( auto map = boost::make_iterator_property_map( color_map.begin(), boost::get(boost::vertex_index, g), color_map[0]); - boost::custom_depth_first_search( + boost::custom_depth_first_search( g, boost::topo_sort_visitor(result), map, boost::detail::get_default_starting_vertex(g), stack); @@ -364,6 +373,24 @@ void print_graph(Graph_T& g, IO& stream) #endif } +struct no_delay_edges +{ + const graph_t* g{}; + + bool operator()(const boost::graph_traits::edge_descriptor& e) const + { + switch((*g)[e]->con.index()) + { + case 0: + case 1: + case 4: + return true; + default: + return false; + } + } +}; + struct OSSIA_EXPORT graph_util { static void pull_from_parameter(inlet& in, execution_state& e) @@ -669,7 +696,8 @@ struct OSSIA_EXPORT graph_util bool previous_nodes_executed = ossia::all_of(inlet.sources, [&](graph_edge* edge) { return edge->out_node->executed() || (!edge->out_node->enabled() /* && bool(inlet->address) */ - /* TODO check that it's in scope */); + /* TODO check that it's in scope */) + || edge->delayed(); }); // it does not have source ports ; we have to check for variables : @@ -837,6 +865,7 @@ struct OSSIA_EXPORT graph_base : graph_interface // TODO check that two edges can be added boost::add_edge(in_vtx, out_vtx, edge, m_graph); + recompute_maps(); m_dirty = true; } diff --git a/src/ossia/dataflow/graph_edge.hpp b/src/ossia/dataflow/graph_edge.hpp index 2a058e204a8..9b0d602260a 100644 --- a/src/ossia/dataflow/graph_edge.hpp +++ b/src/ossia/dataflow/graph_edge.hpp @@ -10,10 +10,6 @@ struct init_delay_line void operator()(const audio_port&) const noexcept { delay_line = audio_delay_line{}; } void operator()(const value_port&) const noexcept { delay_line = value_delay_line{}; } void operator()(const midi_port&) const noexcept { delay_line = midi_delay_line{}; } - void operator()(const geometry_port&) const noexcept - { - delay_line = geometry_delay_line{}; - } void operator()() const noexcept { } }; @@ -42,6 +38,21 @@ struct OSSIA_EXPORT graph_edge void init() noexcept; void clear() noexcept; + bool delayed() const noexcept + { + switch(con.index()) + { + default: + case 0: + case 1: + case 4: + return false; + case 2: + case 3: + return true; + } + } + static std::size_t size_of_allocated_memory_by_make_shared() noexcept; connection con{}; diff --git a/src/ossia/dataflow/port.hpp b/src/ossia/dataflow/port.hpp index 46a8119ed8d..abc41dd6cad 100644 --- a/src/ossia/dataflow/port.hpp +++ b/src/ossia/dataflow/port.hpp @@ -865,8 +865,7 @@ inline auto inlet::visit(const T& t) case 2: return t(static_cast(this)->data); // case 3: return t(static_cast(*this)); - case 4: - return t(static_cast(this)->data); + // case 4: return t(static_cast(this)->data); } if constexpr(std::is_invocable_v) @@ -885,8 +884,7 @@ inline auto outlet::visit(const T& t) case 2: return t(static_cast(this)->data); // case 3: return t(static_cast(*this)); - case 4: - return t(static_cast(this)->data); + // case 4: return t(static_cast(this)->data); } if constexpr(std::is_invocable_v) @@ -904,8 +902,7 @@ inline auto inlet::visit(const T& t) const case 2: return t(static_cast(this)->data); // case 3: return t(static_cast(*this)); - case 4: - return t(static_cast(this)->data); + // case 4: return t(static_cast(this)->data); } if constexpr(std::is_invocable_v) @@ -923,8 +920,7 @@ inline auto outlet::visit(const T& t) const case 2: return t(static_cast(this)->data); // case 3: return t(static_cast(*this)); - case 4: - return t(static_cast(this)->data); + // case 4: return t(static_cast(this)->data); } if constexpr(std::is_invocable_v) diff --git a/src/ossia_sources.cmake b/src/ossia_sources.cmake index 541a900ad80..b11b0fc0ca3 100644 --- a/src/ossia_sources.cmake +++ b/src/ossia_sources.cmake @@ -858,6 +858,7 @@ set(OSSIA_DATAFLOW_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/ordered_policy.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution/priorized_policy.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/data.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/geometry_port.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/port.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/graph_node.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ossia/dataflow/execution_state.cpp"