From 43eb434611cf99199e283d7ce91f91c1294c0b8c Mon Sep 17 00:00:00 2001 From: Chong Kai Xiong Date: Tue, 21 Jan 2025 08:18:25 +0800 Subject: [PATCH] Core (LV::Bin): Re-implement. --- libvisual/examples/simple/simple_example.cpp | 17 +- libvisual/libvisual/lv_bin.cpp | 710 ++++++------------- libvisual/libvisual/lv_bin.h | 37 +- libvisual/libvisual/lv_bin_c.cpp | 28 +- libvisual/libvisual/lv_morph.cpp | 5 + libvisual/libvisual/lv_morph.h | 5 + libvisual/tools/lv-tool/lv-tool.cpp | 25 +- 7 files changed, 270 insertions(+), 557 deletions(-) diff --git a/libvisual/examples/simple/simple_example.cpp b/libvisual/examples/simple/simple_example.cpp index 45e0e23b5..d6eb7948a 100644 --- a/libvisual/examples/simple/simple_example.cpp +++ b/libvisual/examples/simple/simple_example.cpp @@ -77,10 +77,8 @@ SimpleExample::SimpleExample () SDL_WM_SetCaption (m_actor_name.c_str (), 0); - m_bin.depth_changed (); - m_bin.realize (); - m_bin.sync (false); + m_bin.sync (); m_bin.use_morph (true); m_bin.set_morph (m_morph_name); @@ -126,7 +124,7 @@ void SimpleExample::resize_display (int width, int height) create_display (width, height, m_bin.get_depth ()); m_bin.set_video (m_screen); - m_bin.sync (false); + m_bin.sync (); } void SimpleExample::set_palette (LV::Palette const& pal) @@ -219,16 +217,5 @@ void SimpleExample::run () if (!handle_events ()) { break; } - - if (m_bin.depth_changed ()) - { - int depthflag = m_bin.get_depth (); - VisVideoDepth depth = visual_video_depth_get_highest (depthflag); - - create_display (m_screen->get_width (), m_screen->get_height (), depth); - m_bin.set_video (m_screen); - - m_bin.sync (true); - } } } diff --git a/libvisual/libvisual/lv_bin.cpp b/libvisual/libvisual/lv_bin.cpp index 85a9f6b39..0d25bfffc 100644 --- a/libvisual/libvisual/lv_bin.cpp +++ b/libvisual/libvisual/lv_bin.cpp @@ -28,78 +28,78 @@ namespace LV { + Time const min_switch_time = Time::from_msecs (100); + class Bin::Impl { public: - ActorPtr actor; - VideoPtr actvideo; - VideoPtr privvid; + bool is_realized; + + VisVideoDepth supported_depths; + VisVideoDepth output_depth; + VisBinDepth depth_policy; + bool need_sync; - VideoPtr actmorphvideo; - ActorPtr actmorph; + VideoPtr output_video; - InputPtr input; + ActorPtr actor; + ActorPtr morph_target; - bool use_morph; - MorphPtr morph; - bool morphing; - Time morphtime; + InputPtr input; - VisBinDepth depthpreferred; /* Prefered depth, highest or lowest */ - VisVideoDepth depthflag; /* Supported depths */ - VisVideoDepth depthold; /* Previous depth */ - VisVideoDepth depth; /* Depth we're running in */ - bool depthchanged; /* Set true if the depth has changed */ - bool depthfromGL; /* Set when switching away from openGL */ - VisVideoDepth depthforced; /* Contains forced depth value, for the actmorph so we've got smooth transformations */ - VisVideoDepth depthforcedmain; /* Contains forced depth value, for the main actor */ + // Morph-specific pipeline state + MorphPtr morph; + Time morph_time; + bool use_morph; + bool is_morphing; Impl (); ~Impl (); - VisVideoDepth get_suitable_depth (VisVideoDepth depth); + void configure_pipeline (); - void set_actor (ActorPtr const& actor); - void set_input (InputPtr const& input); + void setup_actor_output (ActorPtr const& actor, VideoPtr const& video); + + void cut_to_morph_target (); }; - VisVideoDepth Bin::Impl::get_suitable_depth (VisVideoDepth depthflag) + VisVideoDepth find_depth_policy_best (VisBinDepth policy, VisVideoDepth depth_set) { - VisVideoDepth depth = VISUAL_VIDEO_DEPTH_NONE; + auto depth {VISUAL_VIDEO_DEPTH_NONE}; - switch (depthpreferred) { + switch (policy) { case VISUAL_BIN_DEPTH_LOWEST: - depth = visual_video_depth_get_lowest (depthflag); + depth = visual_video_depth_get_lowest (depth_set); break; case VISUAL_BIN_DEPTH_HIGHEST: - depth = visual_video_depth_get_highest (depthflag); + depth = visual_video_depth_get_highest (depth_set); break; } - // Is supported within bin natively - if (depthflag & depth) - return depth; - - // Not supported by the bin, taking the highest depth from the bin - return visual_video_depth_get_highest_nogl (depthflag); + return depth; } + VideoPtr create_matching_format_video (LV::VideoPtr const& source) + { + auto const width {source->get_width ()}; + auto const height {source->get_height ()}; + auto const depth {source->get_depth ()}; + + return Video::create (width, height, depth); + } Bin::Impl::Impl () - : use_morph (false) - , morphing (false) - , morphtime (4, 0) - , depthpreferred (VISUAL_BIN_DEPTH_HIGHEST) - , depthflag (VISUAL_VIDEO_DEPTH_NONE) - , depthold (VISUAL_VIDEO_DEPTH_NONE) - , depth (VISUAL_VIDEO_DEPTH_NONE) - , depthchanged (false) - , depthfromGL (false) - , depthforced (VISUAL_VIDEO_DEPTH_NONE) - , depthforcedmain (VISUAL_VIDEO_DEPTH_NONE) + : is_realized {false} + , supported_depths {VISUAL_VIDEO_DEPTH_ALL} + , output_depth {VISUAL_VIDEO_DEPTH_NONE} + , depth_policy {VISUAL_BIN_DEPTH_HIGHEST} + , need_sync {false} + , morph_time {Time::from_msecs (500)} + , use_morph {true} + , is_morphing {false} { // empty } @@ -109,14 +109,30 @@ namespace LV { // nothing } - void Bin::Impl::set_actor (ActorPtr const& new_actor) + void Bin::Impl::setup_actor_output (ActorPtr const& actor, VideoPtr const& video) { - actor = new_actor; + auto depth_set {actor->get_supported_depths ()}; + auto run_depth {find_depth_policy_best (depth_policy, depth_set)}; + actor->set_video (video); + actor->video_negotiate (run_depth, false, true); + video->fill_color (Color {0, 0, 0}); } - void Bin::Impl::set_input (InputPtr const& new_input) + void Bin::Impl::cut_to_morph_target () { - input = new_input; + if (!morph_target) + return; + + is_morphing = false; + + auto next_actor {morph_target}; + auto actor_output_video {morph->get_video ()}; + setup_actor_output (next_actor, actor_output_video); + + actor = next_actor; + + morph_target.reset (); + morph->set_video (nullptr); } Bin::Bin () @@ -130,18 +146,6 @@ namespace LV { // empty } - void Bin::realize () - { - if (m_impl->actor) - m_impl->actor->realize (); - - if (m_impl->input) - m_impl->input->realize (); - - if (m_impl->morph) - m_impl->morph->realize (); - } - ActorPtr const& Bin::get_actor () const { return m_impl->actor; @@ -152,528 +156,286 @@ namespace LV { return m_impl->input; } - void Bin::set_morph (std::string_view morph_name) - { - m_impl->morph = Morph::load (morph_name); - visual_return_if_fail (m_impl->morph); - - VisVideoDepth depthflag = m_impl->morph->get_supported_depths (); - - if (visual_video_depth_is_supported (depthflag, m_impl->actvideo->get_depth ()) <= 0) { - m_impl->morph.reset (); - return; - } - } - MorphPtr const& Bin::get_morph () const { return m_impl->morph; } - bool Bin::connect (ActorPtr const& actor, InputPtr const& input) + void Bin::set_morph (std::string_view morph_name) { - visual_return_val_if_fail (actor, false); - visual_return_val_if_fail (input, false); + auto new_morph {Morph::load (morph_name)}; + visual_return_if_fail (new_morph); - m_impl->set_actor (actor); - m_impl->set_input (input); + // Morph class doesn't have code to adapt its output format, so we + // have to ensure the pipeout output depth is supported by the morph. - auto depthflag = actor->get_supported_depths (); + auto depth_set {new_morph->get_supported_depths ()}; - if (depthflag == VISUAL_VIDEO_DEPTH_GL) { - set_depth (VISUAL_VIDEO_DEPTH_GL); - } else { - set_depth (m_impl->get_suitable_depth (depthflag)); + if (!(depth_set & m_impl->supported_depths)) { + visual_log (VISUAL_LOG_WARNING, "Morph does not support colour depth (morph:%d, bin:%d)", + depth_set, m_impl->supported_depths); + + if (m_impl->is_morphing) { + m_impl->cut_to_morph_target (); + + m_impl->morph.reset (); + m_impl->use_morph = false; + } + + return; } - m_impl->depthforcedmain = m_impl->depth; + new_morph->set_time (m_impl->morph_time); - return true; + if (m_impl->morph) { + // Swap in new morph + auto output_video {m_impl->morph->get_video ()}; + m_impl->morph = new_morph; + m_impl->morph->set_video (output_video); + } else { + // Set morph for the first time + m_impl->morph = new_morph; + } + + if (m_impl->is_realized) { + m_impl->morph->realize (); + } } bool Bin::connect (std::string_view actor_name, std::string_view input_name) { - // Create the actor + if (m_impl->actor || m_impl->input) { + visual_log (VISUAL_LOG_WARNING, "Bin is already connected."); + return false; + } + auto actor = Actor::load (actor_name); visual_return_val_if_fail (actor, false); - // Create the input auto input = Input::load (input_name); visual_return_val_if_fail (input, false); - // Connect - if (!connect (actor, input)) { - return false; - } + m_impl->actor = actor; + m_impl->input = input; return true; } - void Bin::sync (bool noevent) + void Bin::set_preferred_depth (VisBinDepth policy) { - visual_log (VISUAL_LOG_DEBUG, "starting sync"); - - VideoPtr video; - - /* Sync the actor regarding morph */ - if (m_impl->morphing && m_impl->use_morph && - m_impl->actvideo->get_depth () != VISUAL_VIDEO_DEPTH_GL && !m_impl->depthfromGL) { - - m_impl->morph->set_video (m_impl->actvideo); - - video = m_impl->privvid; - if (!video) { - visual_log (VISUAL_LOG_DEBUG, "Private video data nullptr"); - return; - } - - video->free_buffer (); - video->copy_attrs (m_impl->actvideo); - - visual_log (VISUAL_LOG_DEBUG, "pitches actvideo %d, new video %d", - m_impl->actvideo->get_pitch (), video->get_pitch ()); - - visual_log (VISUAL_LOG_DEBUG, "phase1 m_impl->privvid %p", (void *) m_impl->privvid.get ()); - if (m_impl->actmorph->get_video ()->get_depth () == VISUAL_VIDEO_DEPTH_GL) { - video = m_impl->actvideo; - } else - video->allocate_buffer (); - - visual_log (VISUAL_LOG_DEBUG, "phase2"); - } else { - video = m_impl->actvideo; - if (!video) { - visual_log (VISUAL_LOG_DEBUG, "Actor video is nullptr"); - return; - } - - visual_log (VISUAL_LOG_DEBUG, "setting new video from actvideo %d %d", - video->get_depth (), video->get_bpp ()); - } - - // Main actor - - m_impl->actor->set_video (video); - - visual_log (VISUAL_LOG_DEBUG, "one last video pitch check %d depth old %d forcedmain %d noevent %d", - video->get_pitch (), m_impl->depthold, - m_impl->depthforcedmain, noevent); - - if (m_impl->depthold == VISUAL_VIDEO_DEPTH_GL) { - m_impl->actor->video_negotiate (m_impl->depthforcedmain, false, true); - } - else { - m_impl->actor->video_negotiate (m_impl->depthforcedmain, noevent, true); - } - - visual_log (VISUAL_LOG_DEBUG, "pitch after main actor negotiate %d", video->get_pitch ()); - - // Morphing actor - - if (m_impl->morphing && m_impl->use_morph) { - - auto actvideo = m_impl->actmorphvideo; - if (!actvideo) { - visual_log (VISUAL_LOG_DEBUG, "Morph video is nullptr"); - return; - } - - actvideo->free_buffer (); - - actvideo->copy_attrs (video); - - if (m_impl->actor->get_video ()->get_depth () != VISUAL_VIDEO_DEPTH_GL) - actvideo->allocate_buffer (); - - m_impl->actmorph->realize (); - - visual_log (VISUAL_LOG_DEBUG, "phase3 pitch of real framebuffer %d", - m_impl->actvideo->get_pitch ()); - - m_impl->actmorph->video_negotiate (m_impl->depthforced, false, true); - } - - visual_log (VISUAL_LOG_DEBUG, "end sync function"); + m_impl->depth_policy = policy; + m_impl->need_sync = true; } - void Bin::set_video (VideoPtr const& video) + void Bin::set_supported_depth (VisVideoDepth depth_set) { - m_impl->actvideo = video; + m_impl->supported_depths = depth_set; + m_impl->need_sync = true; } - void Bin::set_supported_depth (VisVideoDepth depthflag) + VisVideoDepth Bin::get_supported_depth () const { - m_impl->depthflag = depthflag; + return m_impl->supported_depths; } - VisVideoDepth Bin::get_supported_depth () const + VisVideoDepth Bin::get_depth () const { - return m_impl->depthflag; + return m_impl->output_depth; } - void Bin::set_preferred_depth (VisBinDepth depthpreferred) + Palette const& Bin::get_palette () const { - m_impl->depthpreferred = depthpreferred; + if (m_impl->is_morphing) + return *m_impl->morph->get_palette (); + else + return *m_impl->actor->get_palette (); } - void Bin::set_depth (VisVideoDepth depth) + void Bin::realize () { - m_impl->depthold = m_impl->depth; - - if (!visual_video_depth_is_supported (m_impl->depthflag, depth)) + if (m_impl->is_realized) { + visual_log (VISUAL_LOG_WARNING, "Bin is already realized."); return; + } - visual_log (VISUAL_LOG_DEBUG, "old: %d new: %d", m_impl->depth, depth); - - if (m_impl->depth != depth) - m_impl->depthchanged = true; - - if (m_impl->depth == VISUAL_VIDEO_DEPTH_GL && m_impl->depthchanged) - m_impl->depthfromGL = true; - else - m_impl->depthfromGL = false; + visual_return_if_fail (m_impl->actor); + visual_return_if_fail (m_impl->input); - m_impl->depth = depth; + m_impl->input->realize (); + m_impl->actor->realize (); - if (m_impl->actvideo) { - m_impl->actvideo->set_depth (depth); + if (m_impl->morph) { + m_impl->morph->realize (); } - } - VisVideoDepth Bin::get_depth () const - { - return m_impl->depth; + m_impl->is_realized = true; } - bool Bin::depth_changed () + void Bin::use_morph (bool use) { - if (!m_impl->depthchanged) - return false; + if (m_impl->use_morph == use) + return; - m_impl->depthchanged = false; + // If disabling morph while it's running, immediately cut to + // the morph target (and reconfigure pipeline). + if (!use && m_impl->is_morphing) { + m_impl->cut_to_morph_target (); + } - return true; + m_impl->use_morph = use; } - Palette const& Bin::get_palette () const + void Bin::set_video (VideoPtr const& video) { - if (m_impl->morphing) - return *m_impl->morph->get_palette (); - else - return *m_impl->actor->get_palette (); + if (!visual_video_depth_is_supported (m_impl->supported_depths, video->get_depth ())) { + visual_log (VISUAL_LOG_WARNING, "Output video depth is not supported by bin, ignoring."); + return; + } + + visual_log (VISUAL_LOG_INFO, "New output video target set, pending sync."); + m_impl->output_video = video; + m_impl->output_depth = video->get_depth (); + m_impl->need_sync = true; } - void Bin::switch_actor (std::string_view actor_name) + void Bin::sync () { - // FIXME: This is needed because visual_log() takes only null-terminated C strings. - std::string actor_name_str {actor_name}; - - visual_log (VISUAL_LOG_DEBUG, "switching to a new actor: %s, old actor: %s", - actor_name_str.c_str (), visual_plugin_get_info (m_impl->actor->get_plugin ())->plugname); - - if (m_impl->actmorph) { - m_impl->actmorph.reset (); - m_impl->actmorphvideo.reset (); + if (!m_impl->need_sync) { + visual_log (VISUAL_LOG_INFO, "No sync needed."); + return; } - /* Create a new managed actor */ - auto actor = LV::Actor::load (actor_name); - visual_return_if_fail (actor); - - auto video = LV::Video::create (); - video->copy_attrs(m_impl->actvideo); - - auto depthflag = actor->get_supported_depths (); - VisVideoDepth depth; - - if (visual_video_depth_is_supported (depthflag, VISUAL_VIDEO_DEPTH_GL)) { - visual_log (VISUAL_LOG_INFO, "Switching to GL mode"); - - depth = VISUAL_VIDEO_DEPTH_GL; + if (!m_impl->output_video) { + visual_log (VISUAL_LOG_INFO, "No output video set, nothing to sync."); + return; + } - m_impl->depthforced = depth; - m_impl->depthforcedmain = depth; + if (!m_impl->is_realized) { + realize (); + } - video->set_depth(depth); + visual_log (VISUAL_LOG_INFO, "Starting sync."); - set_depth (depth); + if (m_impl->is_morphing) { + auto new_video1 {create_matching_format_video (m_impl->output_video)}; + auto new_video2 {create_matching_format_video (m_impl->output_video)}; - m_impl->depthchanged = true; + m_impl->setup_actor_output (m_impl->actor, new_video1); + m_impl->setup_actor_output (m_impl->morph_target, new_video2); + m_impl->morph->set_video (m_impl->output_video); } else { - visual_log (VISUAL_LOG_INFO, "Switching away from Gl mode -- or non Gl switch"); - - /* Switching from GL */ - depth = m_impl->get_suitable_depth (depthflag); - video->set_depth(depth); - - visual_log (VISUAL_LOG_DEBUG, "after depth fixating"); - - /* After a depth change, the pitch value needs an update from the client - * if it's different from width * bpp, after a visual_bin_sync - * the issues are fixed again */ - visual_log (VISUAL_LOG_INFO, "video depth (from fixate): %d", video->get_depth ()); - - /* FIXME check if there are any unneeded depth transform environments and drop these */ - visual_log (VISUAL_LOG_DEBUG, "checking if we need to drop something: depthforcedmain: %d actvideo->depth %d", - m_impl->depthforcedmain, m_impl->actvideo->get_depth ()); - - /* Drop a transformation environment when not needed */ - if (m_impl->depthforcedmain != m_impl->actvideo->get_depth ()) { - m_impl->actor->video_negotiate (m_impl->depthforcedmain, true, true); - visual_log (VISUAL_LOG_DEBUG, "[[[[optionally a bogus transform environment, dropping]]]]"); - } - - if (m_impl->actvideo->get_depth () > video->get_depth () - && m_impl->actvideo->get_depth () != VISUAL_VIDEO_DEPTH_GL - && m_impl->use_morph) { - - visual_log (VISUAL_LOG_INFO, "old depth is higher, video depth %d, bin depth %d", - video->get_depth (), m_impl->depth); - - m_impl->depthforced = depth;; - m_impl->depthforcedmain = m_impl->depth; - - set_depth (m_impl->actvideo->get_depth ()); - video->set_depth (m_impl->actvideo->get_depth ()); - - } else if (m_impl->actvideo->get_depth () != VISUAL_VIDEO_DEPTH_GL) { - - visual_log (VISUAL_LOG_INFO, "new depth is higher, or equal: video depth %d, depth %d bin depth %d", - video->get_depth (), depth, m_impl->depth); - - visual_log (VISUAL_LOG_DEBUG, "depths i can locate: actvideo: %d bin: %d bin-old: %d", - m_impl->actvideo->get_depth (), m_impl->depth, m_impl->depthold); - - m_impl->depthforced = video->get_depth (); - m_impl->depthforcedmain = m_impl->depth; - - visual_log (VISUAL_LOG_DEBUG, "depthforcedmain in switch by name: %d", m_impl->depthforcedmain); - visual_log (VISUAL_LOG_DEBUG, "Bin::set_depth %d", video->get_depth ()); - set_depth (video->get_depth ()); - - } else { - /* Don't force ourself into a GL depth, seen we do a direct - * switch in the run */ - m_impl->depthforced = video->get_depth (); - m_impl->depthforcedmain = video->get_depth (); - - visual_log (VISUAL_LOG_INFO, "Switching from GL to framebuffer for real, framebuffer depth: %d", - video->get_depth ()); - } - - visual_log (VISUAL_LOG_INFO, "Target depth selected: %d", depth); - - video->set_pitch(video->get_width() * (visual_video_depth_bpp(depth) >> 3)); - - video->allocate_buffer(); + m_impl->setup_actor_output (m_impl->actor, m_impl->output_video); } - - visual_log (VISUAL_LOG_INFO, "video pitch of that what connects to the new actor %d", - video->get_pitch ()); - - actor->set_video (video); - - m_impl->actmorphvideo = video; - - visual_log (VISUAL_LOG_INFO, "switching... ******************************************"); - switch_actor (actor); - - visual_log (VISUAL_LOG_INFO, "end switch actor by name function ******************"); + m_impl->need_sync = false; } - void Bin::switch_actor (ActorPtr const& actor) + void Bin::switch_actor (std::string_view actor_name) { - visual_return_if_fail (actor); + // FIXME: This is needed because visual_log() takes only null-terminated C strings. + std::string actor_name_str {actor_name}; - /* Set the new actor */ - m_impl->actmorph = actor; + visual_log (VISUAL_LOG_INFO, "Switching to a new actor: %s", actor_name_str.c_str ()); - visual_log (VISUAL_LOG_DEBUG, "Starting actor switch..."); + // Create a new managed actor + auto new_actor {Actor::load (actor_name)}; + visual_return_if_fail (new_actor); - /* Free the private video */ - m_impl->privvid.reset (); + if (m_impl->is_morphing) { + // Morph in progress => complete running morph immediately and update the morph target + // the newly loaded actor - visual_log (VISUAL_LOG_INFO, "depth of the main actor: %d", - m_impl->actor->get_video ()->get_depth ()); + // Save reference to video to be reused for new actor. + auto temp_video {m_impl->actor->get_video ()}; - /* Starting the morph, but first check if we don't have anything todo with openGL */ - if (m_impl->use_morph && - m_impl->actor->get_video ()->get_depth () != VISUAL_VIDEO_DEPTH_GL && - m_impl->actmorph->get_video ()->get_depth () != VISUAL_VIDEO_DEPTH_GL && - !m_impl->depthfromGL) { + // Replace current actor with morph target + m_impl->actor.reset (); + m_impl->actor = m_impl->morph_target; - if (m_impl->morph) { - m_impl->morph->set_progress (0.0f); - m_impl->morph->set_video (m_impl->actvideo); - m_impl->morph->set_time (m_impl->morphtime); - } + // Setup new actor to render to video #2. + m_impl->setup_actor_output (new_actor, temp_video); - visual_log (VISUAL_LOG_DEBUG, "phase 1"); - /* Allocate a private video for the main actor, so the morph - * can draw to the framebuffer */ - auto privvid = Video::create (); + // Set morph target to newly added actor and start morphing process + m_impl->morph_target = new_actor; + m_impl->morph_time = Time::now (); - visual_log (VISUAL_LOG_DEBUG, "actvideo->depth %d actmorph->video->depth %d", - m_impl->actvideo->get_depth (), - m_impl->actmorph->get_video ()->get_depth ()); + new_actor->realize (); - visual_log (VISUAL_LOG_DEBUG, "phase 2"); - privvid->copy_attrs (m_impl->actvideo); + } else if (m_impl->use_morph && m_impl->morph) { + // Morph enabled, but no morph process is running => setup morph process + visual_log (VISUAL_LOG_DEBUG, "Setting up morph process."); - visual_log (VISUAL_LOG_DEBUG, "phase 3 pitch privvid %d actvideo %d", - privvid->get_pitch (), m_impl->actvideo->get_pitch ()); + auto actor_output_video {m_impl->actor->get_video ()}; + auto video1 {create_matching_format_video (actor_output_video)}; + auto video2 {create_matching_format_video (actor_output_video)}; - privvid->allocate_buffer (); + // Set current actor to render to video #1 instead. + // Rendering target is already in the correct format, so there's nothing else to do + m_impl->actor->set_video (video1); - visual_log (VISUAL_LOG_DEBUG, "phase 4"); - /* Initial privvid initialize */ + // Setup new actor to render to video #2. + m_impl->setup_actor_output (new_actor, video2); - visual_log (VISUAL_LOG_DEBUG, "actmorph->video->depth %d %p", - m_impl->actmorph->get_video ()->get_depth (), - m_impl->actvideo->get_pixels ()); + // Redirect morph to render to output + m_impl->morph->set_video (actor_output_video); - if (m_impl->actvideo->get_pixels () && privvid->get_pixels ()) - visual_mem_copy (privvid->get_pixels (), m_impl->actvideo->get_pixels (), - privvid->get_size ()); - else if (privvid->get_pixels ()) - visual_mem_set (privvid->get_pixels (), 0, privvid->get_size ()); + // Start morph target to newly added actor and start morphing procss + visual_log (VISUAL_LOG_DEBUG, "Morph start."); + m_impl->morph_target = new_actor; + m_impl->is_morphing = true; + m_impl->morph_time = Time::now (); - m_impl->actor->set_video (privvid); - m_impl->privvid = privvid; + new_actor->realize (); } else { - visual_log (VISUAL_LOG_DEBUG, "Pointer actvideo->pixels %p", m_impl->actvideo->get_pixels ()); - if (m_impl->actor->get_video ()->get_depth () != VISUAL_VIDEO_DEPTH_GL && - m_impl->actvideo->get_pixels ()) { - visual_mem_set (m_impl->actvideo->get_pixels (), 0, m_impl->actvideo->get_size ()); - } - } - - visual_log (VISUAL_LOG_DEBUG, "Leaving, actor->video->depth: %d actmorph->video->depth: %d", - m_impl->actor->get_video ()->get_depth (), - m_impl->actmorph->get_video ()->get_depth ()); - - m_impl->morphing = true; - } - - void Bin::switch_finalize () - { - visual_log (VISUAL_LOG_DEBUG, "Completing actor switch..."); - - /* Copy over the depth to be sure, and for GL plugins */ - /* m_impl->actvideo->set_depth (m_impl->actmorphvideo->get_depth ()); */ - - m_impl->actmorphvideo.reset (); - m_impl->privvid.reset (); - - m_impl->actor = m_impl->actmorph; - m_impl->actmorph.reset (); - - m_impl->actor->set_video (m_impl->actvideo); - - m_impl->morphing = false; - m_impl->morph.reset (); - - visual_log (VISUAL_LOG_DEBUG, " - in finalize - fscking depth from actvideo: %d %d", - m_impl->actvideo->get_depth (), - m_impl->actvideo->get_bpp ()); - - VisVideoDepth depthflag = m_impl->actor->get_supported_depths (); - m_impl->actvideo->set_depth (m_impl->get_suitable_depth (depthflag)); - set_depth (m_impl->actvideo->get_depth ()); + // Morphing is disabled => Immediately replace actor + visual_log (VISUAL_LOG_DEBUG, "No morph is running, replacing actor"); - m_impl->depthforcedmain = m_impl->actvideo->get_depth (); - visual_log (VISUAL_LOG_DEBUG, "m_impl->depthforcedmain in finalize %d", m_impl->depthforcedmain); + auto actor_output_video {m_impl->actor->get_video ()}; + m_impl->actor.reset (); + m_impl->setup_actor_output (new_actor, actor_output_video); + m_impl->actor = new_actor; - /* FIXME replace with a depth fixer */ - if (m_impl->depthchanged) { - visual_log (VISUAL_LOG_INFO, "negotiate without event"); - m_impl->actor->video_negotiate (m_impl->depthforcedmain, true, true); - visual_log (VISUAL_LOG_INFO, "end negotiate without event"); - //sync(false); + new_actor->realize (); } - - visual_log (VISUAL_LOG_DEBUG, "Leaving..."); - } - - void Bin::use_morph (bool use) - { - m_impl->use_morph = use; } - void Bin::switch_set_time (Time const& time) + void Bin::switch_set_time (LV::Time const& time) { - m_impl->morphtime = time; + visual_return_if_fail (m_impl->is_morphing); + m_impl->morph_time = std::max (time, min_switch_time); } void Bin::run () { visual_return_if_fail (m_impl->actor); visual_return_if_fail (m_impl->input); + visual_return_if_fail (m_impl->output_video); - m_impl->input->run (); - - /* If we have a direct switch, do this BEFORE we run the actor, - * else we can get into trouble especially with GL, also when - * switching away from a GL plugin this is needed */ - if (m_impl->morphing) { - if (!visual_plugin_is_realized (m_impl->actmorph->get_plugin ())) { - m_impl->actmorph->realize (); - - m_impl->actmorph->video_negotiate (m_impl->depthforced, false, true); - } - - /* When we've got multiple switch events without a sync we need - * to realize the main actor as well */ - if (!visual_plugin_is_realized (m_impl->actor->get_plugin ())) { - m_impl->actor->realize (); - - m_impl->actor->video_negotiate (m_impl->depthforced, false, true); - } - - /* When the style is DIRECT or the context is GL we shouldn't try - * to morph and instead finalize at once */ - if (!m_impl->use_morph || m_impl->actor->get_video ()->get_depth () == VISUAL_VIDEO_DEPTH_GL) { - - switch_finalize (); - - /* We can't start drawing yet, the client needs to catch up with - * the depth change */ - return; - } + if (m_impl->need_sync) { + sync (); } - m_impl->actor->realize (); - + // Read audio data from input + m_impl->input->run (); auto const& audio = m_impl->input->get_audio (); - m_impl->actor->run (audio); - - if (m_impl->morphing) { - if (m_impl->use_morph && - m_impl->actmorph->get_video ()->get_depth () != VISUAL_VIDEO_DEPTH_GL && - m_impl->actor->get_video ()->get_depth () != VISUAL_VIDEO_DEPTH_GL) { + if (m_impl->is_morphing) { + // Run actors to render inputs for morph + m_impl->actor->run (audio); + m_impl->morph_target->run (audio); - m_impl->actmorph->run (audio); + // Run morph + auto source1 {m_impl->actor->get_video ()}; + auto source2 {m_impl->morph_target->get_video ()}; + m_impl->morph->run (audio, source1, source2); - if (!m_impl->morph) { - switch_finalize (); - return; - } - - /* Same goes for the morph, we realize it here for depth changes - * (especially the OpenGL case */ - m_impl->morph->realize (); - m_impl->morph->run (audio, - m_impl->actor->get_video (), - m_impl->actmorph->get_video ()); - - if (m_impl->morph->is_done ()) { - switch_finalize (); - } - } else { - /* visual_bin_switch_finalize (bin); */ + // Reconfigure pipeline to a single running actor + if (m_impl->morph->is_done ()) { + visual_log (VISUAL_LOG_INFO, "Morph is complete, simplifying pipeline."); + m_impl->cut_to_morph_target (); } + } else { + m_impl->actor->run (audio); } } diff --git a/libvisual/libvisual/lv_bin.h b/libvisual/libvisual/lv_bin.h index 0c36371a9..5822ae1e5 100644 --- a/libvisual/libvisual/lv_bin.h +++ b/libvisual/libvisual/lv_bin.h @@ -59,53 +59,44 @@ namespace LV { Bin& operator= (Bin const&) = delete; - void realize (); - ActorPtr const& get_actor () const; InputPtr const& get_input () const; MorphPtr const& get_morph () const; - void set_morph (std::string_view morph_name); + void run (); + + void realize (); + + void sync (); + bool connect (std::string_view actor_name, std::string_view input_name); - void sync (bool noevent); + void set_morph (std::string_view morph_name); void set_video (VideoPtr const& video); - void set_supported_depth (VisVideoDepth depthflag); + void set_supported_depth (VisVideoDepth depth_set); VisVideoDepth get_supported_depth () const; - void set_preferred_depth (VisBinDepth depthpreferred); - - void set_depth (VisVideoDepth depth); + void set_preferred_depth (VisBinDepth depth); VisVideoDepth get_depth () const; - bool depth_changed (); - Palette const& get_palette () const; - void switch_actor (std::string_view actname); - - void switch_finalize (); - - void use_morph (bool use); + void switch_actor (std::string_view name); void switch_set_time (Time const& time); - void run (); + void use_morph (bool use); private: class Impl; const std::unique_ptr m_impl; - - // FIXME: Remove - bool connect (ActorPtr const& actor, InputPtr const& input); - void switch_actor (ActorPtr const& actor); }; } // LV namespace @@ -135,22 +126,18 @@ LV_API VisMorph *visual_bin_get_morph (VisBin *bin); LV_API void visual_bin_connect (VisBin *bin, const char *actname, const char *inname); -LV_API void visual_bin_sync (VisBin *bin, int noevent); +LV_API void visual_bin_sync (VisBin *bin); LV_API void visual_bin_set_video (VisBin *bin, VisVideo *video); LV_API void visual_bin_set_supported_depth (VisBin *bin, VisVideoDepth depthflag); LV_API VisVideoDepth visual_bin_get_supported_depth (VisBin *bin); LV_API void visual_bin_set_preferred_depth (VisBin *bin, VisBinDepth depthpreferred); -LV_API void visual_bin_set_depth (VisBin *bin, int depth); LV_API VisVideoDepth visual_bin_get_depth (VisBin *bin); -LV_API int visual_bin_depth_changed (VisBin *bin); - LV_API const VisPalette* visual_bin_get_palette (VisBin *bin); LV_API void visual_bin_switch_actor (VisBin *bin, const char *name); -LV_API void visual_bin_switch_finalize (VisBin *bin); LV_API void visual_bin_switch_set_time (VisBin *bin, long sec, long usec); LV_API void visual_bin_run (VisBin *bin); diff --git a/libvisual/libvisual/lv_bin_c.cpp b/libvisual/libvisual/lv_bin_c.cpp index 86d775949..aa56b54a1 100644 --- a/libvisual/libvisual/lv_bin_c.cpp +++ b/libvisual/libvisual/lv_bin_c.cpp @@ -54,11 +54,11 @@ void visual_bin_connect (VisBin *bin, const char *actname, const char *inname) bin->connect (actname, inname); } -void visual_bin_sync (VisBin *bin, int noevent) +void visual_bin_sync (VisBin *bin) { visual_return_if_fail (bin != nullptr); - bin->sync (noevent); + bin->sync (); } void visual_bin_set_video (VisBin *bin, VisVideo *video) @@ -75,18 +75,18 @@ void visual_bin_set_supported_depth (VisBin *bin, VisVideoDepth depthflag) bin->set_supported_depth (depthflag); } -void visual_bin_set_preferred_depth (VisBin *bin, VisBinDepth depth) +VisVideoDepth visual_bin_get_supported_depth (VisBin *bin) { - visual_return_if_fail (bin != nullptr); + visual_return_val_if_fail (bin != nullptr, VISUAL_VIDEO_DEPTH_NONE); - bin->set_preferred_depth (depth); + return bin->get_supported_depth (); } -void visual_bin_set_depth (VisBin *bin, VisVideoDepth depth) +void visual_bin_set_preferred_depth (VisBin *bin, VisBinDepth depth) { visual_return_if_fail (bin != nullptr); - bin->set_depth (depth); + bin->set_preferred_depth (depth); } VisVideoDepth visual_bin_get_depth (VisBin *bin) @@ -96,13 +96,6 @@ VisVideoDepth visual_bin_get_depth (VisBin *bin) return bin->get_depth (); } -int visual_bin_depth_changed (VisBin *bin) -{ - visual_return_val_if_fail (bin != nullptr, FALSE); - - return bin->depth_changed (); -} - const VisPalette *visual_bin_get_palette (VisBin *bin) { visual_return_val_if_fail (bin != nullptr, nullptr); @@ -117,13 +110,6 @@ void visual_bin_switch_actor (VisBin *bin, const char *actname) bin->switch_actor (actname); } -void visual_bin_switch_finalize (VisBin *bin) -{ - visual_return_if_fail (bin != nullptr); - - bin->switch_finalize (); -} - void visual_bin_use_morph (VisBin *bin, int use) { visual_return_if_fail (bin != nullptr); diff --git a/libvisual/libvisual/lv_morph.cpp b/libvisual/libvisual/lv_morph.cpp index 4a3105fac..a31d539cb 100644 --- a/libvisual/libvisual/lv_morph.cpp +++ b/libvisual/libvisual/lv_morph.cpp @@ -142,6 +142,11 @@ namespace LV { m_impl->progress = std::clamp (progress, 0.0f, 1.0f); } + VideoPtr Morph::get_video () const + { + return m_impl->dest; + } + Palette const* Morph::get_palette () { // FIXME: This should return nullptr if there is no palette diff --git a/libvisual/libvisual/lv_morph.h b/libvisual/libvisual/lv_morph.h index 6aa920066..d97ffe29a 100644 --- a/libvisual/libvisual/lv_morph.h +++ b/libvisual/libvisual/lv_morph.h @@ -123,6 +123,11 @@ namespace LV { */ void set_progress (float progress); + /** + * Returns the rendering video target. + */ + VideoPtr get_video () const; + /** * Returns the colour palette used. * diff --git a/libvisual/tools/lv-tool/lv-tool.cpp b/libvisual/tools/lv-tool/lv-tool.cpp index 8211a693b..cc991029d 100644 --- a/libvisual/tools/lv-tool/lv-tool.cpp +++ b/libvisual/tools/lv-tool/lv-tool.cpp @@ -503,7 +503,6 @@ int main (int argc, char **argv) // create new VisBin for video output LV::Bin bin; bin.set_supported_depth(VISUAL_VIDEO_DEPTH_ALL); - bin.use_morph(false); // Apply dynamic actor default, as needed if (actor_name.empty()) { @@ -546,8 +545,6 @@ int main (int argc, char **argv) depth = visual_video_depth_get_highest (depthflag); } - bin.set_depth (depth); - auto vidoptions = actor->get_video_attribute_options (); // initialize display @@ -565,8 +562,7 @@ int main (int argc, char **argv) // put it all together bin.set_video(video); bin.realize(); - bin.sync(false); - bin.depth_changed(); + bin.sync(); bin.set_morph(morph_name); @@ -739,25 +735,10 @@ int main (int argc, char **argv) video = display.create(depth, vidoptions, width, height, true); display.set_title(_("lv-tool")); - bin.set_video (video); - bin.sync(false); - - resize_request.mark_as_applied(); - } - - if (bin.depth_changed()) - { - DisplayLock lock {display}; - - int depthflag = bin.get_depth(); - VisVideoDepth depth = visual_video_depth_get_highest(depthflag); - - display.create(depth, vidoptions, width, height, true); - - video = display.get_video(); bin.set_video(video); + bin.sync(); - bin.sync(true); + resize_request.mark_as_applied(); } }