]> git.sesse.net Git - casparcg/commitdiff
* Refactored blend_mode to be part of frame_transform instead of a global parameter...
authorHelge Norberg <helge.norberg@svt.se>
Fri, 5 Jun 2015 12:35:27 +0000 (14:35 +0200)
committerHelge Norberg <helge.norberg@svt.se>
Fri, 5 Jun 2015 12:35:27 +0000 (14:35 +0200)
* Added support for sub layers in the image mixer.
* Added blend_mode support to layers in a scene_producer.

15 files changed:
accelerator/cpu/image/image_mixer.cpp
accelerator/cpu/image/image_mixer.h
accelerator/ogl/image/image_mixer.cpp
accelerator/ogl/image/image_mixer.h
core/frame/draw_frame.cpp
core/frame/frame_transform.cpp
core/frame/frame_transform.h
core/mixer/image/image_mixer.h
core/mixer/mixer.cpp
core/mixer/mixer.h
core/producer/frame_producer.cpp
core/producer/scene/scene_producer.cpp
core/producer/scene/scene_producer.h
core/producer/scene/xml_scene_producer.cpp
protocol/amcp/AMCPCommandsImpl.cpp

index 9f8371ccc2bc1fbf13bee3e9255d3b62ccf87da4..3491d226eaff8e6d1d3bfb91b0c54da5abc28a69 100644 (file)
@@ -309,10 +309,6 @@ public:
        {
                CASPAR_LOG(info) << L"Initialized Streaming SIMD Extensions Accelerated CPU Image Mixer";
        }
-
-       void begin_layer(core::blend_mode blend_mode)
-       {
-       }
                
        void push(const core::frame_transform& transform)
        {
@@ -346,10 +342,6 @@ public:
        {
                transform_stack_.pop_back();
        }
-
-       void end_layer()
-       {               
-       }
        
        std::future<array<const std::uint8_t>> render(const core::video_format_desc& format_desc)
        {
@@ -374,8 +366,6 @@ void image_mixer::push(const core::frame_transform& transform){impl_->push(trans
 void image_mixer::visit(const core::const_frame& frame){impl_->visit(frame);}
 void image_mixer::pop(){impl_->pop();}
 std::future<array<const std::uint8_t>> image_mixer::operator()(const core::video_format_desc& format_desc){return impl_->render(format_desc);}
-void image_mixer::begin_layer(core::blend_mode blend_mode){impl_->begin_layer(blend_mode);}
-void image_mixer::end_layer(){impl_->end_layer();}
 core::mutable_frame image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc) {return impl_->create_frame(tag, desc);}
 
 }}}
index 039e932282be5cc74ea02feb54c6c3b1c6748143..f955f68a8e1ce7819f4191b073c9fac96ef9a9e6 100644 (file)
@@ -35,9 +35,6 @@ public:
 
        // Methods      
 
-       virtual void begin_layer(core::blend_mode blend_mode);
-       virtual void end_layer();
-
        virtual void push(const core::frame_transform& frame);
        virtual void visit(const core::const_frame& frame);
        virtual void pop();
index 27a2251f2fc552eeb12e113abb44578eefd935ad..bea3bbe6b059fbd2c86863a3d85430c937290459 100644 (file)
@@ -63,17 +63,12 @@ struct item
 
 struct layer
 {
+       std::vector<layer>      sublayers;
        std::vector<item>       items;
        core::blend_mode        blend_mode;
 
-       layer()
-               : blend_mode(core::blend_mode::normal)
-       {
-       }
-
-       layer(std::vector<item> items, core::blend_mode blend_mode)
-               : items(std::move(items))
-               , blend_mode(blend_mode)
+       layer(core::blend_mode blend_mode)
+               : blend_mode(blend_mode)
        {
        }
 };
@@ -150,7 +145,10 @@ private:
                std::shared_ptr<texture> layer_key_texture;
 
                for (auto& layer : layers)
+               {
+                       draw(target_texture, layer.sublayers, format_desc, field_mode);
                        draw(target_texture, std::move(layer), layer_key_texture, format_desc, field_mode);
+               }
        }
 
        void draw(spl::shared_ptr<texture>&                     target_texture,
@@ -293,6 +291,7 @@ struct image_mixer::impl : public core::frame_factory
        image_renderer                                          renderer_;
        std::vector<core::image_transform>      transform_stack_;
        std::vector<layer>                                      layers_; // layer/stream/items
+       std::vector<layer*>                                     layer_stack_;
 public:
        impl(const spl::shared_ptr<device>& ogl, bool blend_modes_wanted) 
                : ogl_(ogl)
@@ -301,15 +300,29 @@ public:
        {
                CASPAR_LOG(info) << L"Initialized OpenGL Accelerated GPU Image Mixer";
        }
-
-       void begin_layer(core::blend_mode blend_mode)
-       {
-               layers_.push_back(layer(std::vector<item>(), blend_mode));
-       }
                
        void push(const core::frame_transform& transform)
        {
-               transform_stack_.push_back(transform_stack_.back()*transform.image_transform);
+               auto previous_layer_depth = transform_stack_.back().layer_depth;
+               transform_stack_.push_back(transform_stack_.back() * transform.image_transform);
+               auto new_layer_depth = transform_stack_.back().layer_depth;
+
+               if (previous_layer_depth < new_layer_depth)
+               {
+                       layer new_layer(transform_stack_.back().blend_mode);
+
+                       if (layer_stack_.empty())
+                       {
+                               layers_.push_back(std::move(new_layer));
+                               layer_stack_.push_back(&layers_.back());
+                       }
+                       else
+                       {
+                               layer_stack_.back()->sublayers.push_back(std::move(new_layer));
+                               layer_stack_.push_back(&layer_stack_.back()->sublayers.back());
+                       }
+               }
+
        }
                
        void visit(const core::const_frame& frame)
@@ -332,16 +345,13 @@ public:
                for(int n = 0; n < static_cast<int>(item.pix_desc.planes.size()); ++n)
                        item.textures.push_back(ogl_->copy_async(frame.image_data(n), item.pix_desc.planes[n].width, item.pix_desc.planes[n].height, item.pix_desc.planes[n].stride, item.transform.use_mipmap));
                
-               layers_.back().items.push_back(item);
+               layer_stack_.back()->items.push_back(item);
        }
 
        void pop()
        {
                transform_stack_.pop_back();
-       }
-
-       void end_layer()
-       {               
+               layer_stack_.resize(transform_stack_.back().layer_depth);
        }
        
        std::future<array<const std::uint8_t>> render(const core::video_format_desc& format_desc)
@@ -365,8 +375,6 @@ void image_mixer::push(const core::frame_transform& transform){impl_->push(trans
 void image_mixer::visit(const core::const_frame& frame){impl_->visit(frame);}
 void image_mixer::pop(){impl_->pop();}
 std::future<array<const std::uint8_t>> image_mixer::operator()(const core::video_format_desc& format_desc){return impl_->render(format_desc);}
-void image_mixer::begin_layer(core::blend_mode blend_mode){impl_->begin_layer(blend_mode);}
-void image_mixer::end_layer(){impl_->end_layer();}
 core::mutable_frame image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc) {return impl_->create_frame(tag, desc);}
 
 }}}
index be09940d63114da4c9388ed64890495201d888dc..af21ceb45c6a47ca4a92d55ad2a50d22a15ce626 100644 (file)
@@ -58,9 +58,6 @@ public:
        core::mutable_frame create_frame(const void* tag, const core::pixel_format_desc& desc) override;
 
        // core::image_mixer
-       
-       void begin_layer(core::blend_mode blend_mode) override;
-       void end_layer() override;
 
        void push(const core::frame_transform& frame) override;
        void visit(const core::const_frame& frame) override;
index 4d3a0bd4d972ef2e39949cc8ee21b330a36be6ff..443a0f2da5d0e1e199a534236da9f756f9640326 100644 (file)
@@ -174,8 +174,8 @@ draw_frame late_frame(const_frame(0));
 
 draw_frame draw_frame::still(draw_frame frame)
 {
-       frame.transform().image_transform.is_still      = true; 
-       frame.transform().audio_transform.is_still      = true;         
+       frame.transform().image_transform.is_still = true;      
+       frame.transform().audio_transform.is_still = true;              
        return frame;
 }
 
index e93d3a7c563af2603237769cd22e042161feffec..52e33d3cf74b123e16d2626594150eb8b13cc9f1 100644 (file)
@@ -96,6 +96,8 @@ image_transform& image_transform::operator*=(const image_transform &other)
        is_mix                                  |= other.is_mix;
        is_still                                |= other.is_still;
        use_mipmap                              |= other.use_mipmap;
+       blend_mode                               = std::max(blend_mode, other.blend_mode);
+       layer_depth                             += other.layer_depth;
 
        return *this;
 }
@@ -158,6 +160,8 @@ image_transform image_transform::tween(double time, const image_transform& sourc
        result.is_mix                           = source.is_mix | dest.is_mix;
        result.is_still                         = source.is_still | dest.is_still;
        result.use_mipmap                       = source.use_mipmap | dest.use_mipmap;
+       result.blend_mode                       = std::max(source.blend_mode, dest.blend_mode);
+       result.layer_depth                      = dest.layer_depth;
 
        do_tween_rectangle(source.crop, dest.crop, result.crop, time, duration, tween);
        do_tween_corners(source.perspective, dest.perspective, result.perspective, time, duration, tween);
@@ -204,6 +208,8 @@ bool operator==(const image_transform& lhs, const image_transform& rhs)
                lhs.is_mix == rhs.is_mix &&
                lhs.is_still == rhs.is_still &&
                lhs.use_mipmap == rhs.use_mipmap &&
+               lhs.blend_mode == rhs.blend_mode &&
+               lhs.layer_depth == rhs.layer_depth &&
                lhs.crop == rhs.crop &&
                lhs.perspective == rhs.perspective;
 }
index bb421f54559a812949e22a0db8adf92ad86bbe12..3d245171f1b72ecf7a2f47774a0e1b7f8c4d10d6 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <common/tweener.h>
 #include <core/video_format.h>
+#include <core/mixer/image/blend_modes.h>
 
 #include <boost/array.hpp>
 
@@ -76,6 +77,8 @@ struct image_transform final
        bool                                    is_mix                          = false;
        bool                                    is_still                        = false;
        bool                                    use_mipmap                      = false;
+       core::blend_mode                blend_mode                      = core::blend_mode::normal;
+       int                                             layer_depth                     = 0;
        
        image_transform& operator*=(const image_transform &other);
        image_transform operator*(const image_transform &other) const;
index f382e11ce3816e6976f7a793e5def24f03e04f41..bd019d9721c941d794acbf79a8684add445acd06 100644 (file)
@@ -58,9 +58,6 @@ public:
        virtual void push(const struct frame_transform& frame) = 0;
        virtual void visit(const class const_frame& frame) = 0;
        virtual void pop() = 0;
-
-       virtual void begin_layer(blend_mode blend_mode) = 0;
-       virtual void end_layer() = 0;
                
        virtual std::future<array<const std::uint8_t>> operator()(const struct video_format_desc& format_desc) = 0;
 
index ee5e091640073dabf056c948560137c4c40cdb1e..26f97cc34ea0ffdd7fa02e716fdcba6d3ae84c27 100644 (file)
@@ -56,8 +56,6 @@ struct mixer::impl : boost::noncopyable
        spl::shared_ptr<diagnostics::graph> graph_;
        audio_mixer                                                     audio_mixer_;
        spl::shared_ptr<image_mixer>            image_mixer_;
-       
-       std::unordered_map<int, blend_mode>     blend_modes_;
                        
        executor executor_                                                                      { L"mixer" };
 
@@ -83,13 +81,9 @@ public:
 
                                for (auto& frame : frames)
                                {
-                                       auto blend_it = blend_modes_.find(frame.first);
-                                       image_mixer_->begin_layer(blend_it != blend_modes_.end() ? blend_it->second : blend_mode::normal);
-                                                                                                       
-                                       frame.second.accept(audio_mixer_);                                      
+                                       frame.second.accept(audio_mixer_);
+                                       frame.second.transform().image_transform.layer_depth = 1;
                                        frame.second.accept(*image_mixer_);
-
-                                       image_mixer_->end_layer();
                                }
                                
                                auto image = (*image_mixer_)(format_desc);
@@ -110,42 +104,6 @@ public:
 
                return frame;
        }
-                                       
-       void set_blend_mode(int index, blend_mode value)
-       {
-               executor_.begin_invoke([=]
-               {
-                       auto it = blend_modes_.find(index);
-                       if(it == blend_modes_.end())
-                               blend_modes_.insert(std::make_pair(index, value));
-                       else
-                               it->second = value;
-               }, task_priority::high_priority);
-       }
-
-       blend_mode get_blend_mode(int index)
-       {
-               return executor_.invoke([=]
-               {
-                       return blend_modes_[index];
-               }, task_priority::high_priority);
-       }
-
-       void clear_blend_mode(int index)
-       {
-               executor_.begin_invoke([=]
-               {
-                       blend_modes_.erase(index);
-               }, task_priority::high_priority);
-       }
-
-       void clear_blend_modes()
-       {
-               executor_.begin_invoke([=]
-               {
-                       blend_modes_.clear();
-               }, task_priority::high_priority);
-       }
 
        void set_master_volume(float volume)
        {
@@ -171,10 +129,6 @@ public:
        
 mixer::mixer(spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<image_mixer> image_mixer) 
        : impl_(new impl(std::move(graph), std::move(image_mixer))){}
-void mixer::set_blend_mode(int index, blend_mode value){impl_->set_blend_mode(index, value);}
-blend_mode mixer::get_blend_mode(int index) { return impl_->get_blend_mode(index); }
-void mixer::clear_blend_mode(int index) { impl_->clear_blend_mode(index); }
-void mixer::clear_blend_modes() { impl_->clear_blend_modes(); }
 void mixer::set_master_volume(float volume) { impl_->set_master_volume(volume); }
 float mixer::get_master_volume() { return impl_->get_master_volume(); }
 std::future<boost::property_tree::wptree> mixer::info() const{return impl_->info();}
index 087c47ed9e62de99aab8c8bff3d90937786d6ca4..c5f1bdc4e113791b67e870dd60a459f8b71365ba 100644 (file)
@@ -53,11 +53,6 @@ public:
        // Methods
                
        class const_frame operator()(std::map<int, class draw_frame> frames, const struct video_format_desc& format_desc);
-       
-       void set_blend_mode(int index, blend_mode value);
-       blend_mode get_blend_mode(int index);
-       void clear_blend_mode(int index);
-       void clear_blend_modes();
 
        void set_master_volume(float volume);
        float get_master_volume();
index de5a0bc8b97c400886fdf1185d8b1b2f9241ee45..9c66df6ae881d2995c958e61dee10887b09bef85 100644 (file)
@@ -241,7 +241,7 @@ public:
                }).detach(); 
        }
        
-       draw_frame      receive() override                                                                                                                                                                                                              {return producer_->receive();}
+       draw_frame                                                                                      receive() override                                                                                                                                                                                                              {return producer_->receive();}
        std::wstring                                                                            print() const override                                                                                                                  {return producer_->print();}
        void                                                                                            paused(bool value) override                                                                                                             {producer_->paused(value);}
        std::wstring                                                                            name() const override                                                                                                                   {return producer_->name();}
index 41b383a5a39a8df9fba2d4b553bbb844d64689b3..88b7dabef3995d170fcf5fa6c3b0d750b0afb0b7 100644 (file)
@@ -196,6 +196,10 @@ struct scene_producer::impl
                transform.image_transform.opacity = layer.adjustments.opacity.get();
                transform.image_transform.is_key = layer.is_key.get();
                transform.image_transform.use_mipmap = layer.use_mipmap.get();
+               transform.image_transform.blend_mode = layer.blend_mode.get();
+
+               // Mark as sublayer, so it will be composited separately by the mixer.
+               transform.image_transform.layer_depth = 1;
 
                return transform;
        }
index cdc969dc2d0dcc6bc2d18fcc2d50252ece9f950a..541aa37f30e925ebe7239c35cc9648f18a286a64 100644 (file)
@@ -74,6 +74,7 @@ struct layer
        binding<bool>                                                           hidden;
        binding<bool>                                                           is_key;
        binding<bool>                                                           use_mipmap;
+       binding<core::blend_mode>                                       blend_mode;
 
        explicit layer(const std::wstring& name, const spl::shared_ptr<frame_producer>& producer);
 };
index 3af6c99bd48141136d0986e01b8260f46cfbe99f..1ed285e573d49b5690f44fb03a54d3f49dcf7f9c 100644 (file)
@@ -133,6 +133,7 @@ spl::shared_ptr<core::frame_producer> create_xml_scene_producer(
                layer.adjustments.opacity = scene->create_variable<double>(variable_prefix + L"adjustment.opacity", false, elem.second.get(L"adjustments.opacity", L"1.0"));
                layer.is_key = scene->create_variable<bool>(variable_prefix + L"is_key", false, elem.second.get(L"is_key", L"false"));
                layer.use_mipmap = scene->create_variable<bool>(variable_prefix + L"use_mipmap", false, elem.second.get(L"use_mipmap", L"false"));
+               layer.blend_mode = scene->create_variable<std::wstring>(variable_prefix + L"blend_mode", false, elem.second.get(L"blend_mode", L"normal")).transformed([](const std::wstring& b) { return get_blend_mode(b); });
 
                scene->create_variable<double>(variable_prefix + L"width", false) = layer.producer.get()->pixel_constraints().width;
                scene->create_variable<double>(variable_prefix + L"height", false) = layer.producer.get()->pixel_constraints().height;
index ff454f79e31ceb2143a8b51feb2821e93e022de8..e079c88498b970031116aab09d1281029961d19d 100644 (file)
@@ -631,17 +631,14 @@ bool MixerCommand::DoExecute()
                else if(boost::iequals(parameters()[0], L"BLEND"))
                {
                        if (parameters().size() == 1)
-                       {
-                               auto blend_mode = channel()->mixer().get_blend_mode(layer_index());
-                               SetReplyString(L"201 MIXER OK\r\n"
-                                               + boost::lexical_cast<std::wstring>(get_blend_mode(blend_mode))
-                                               + L"\r\n");
-                               return true;
-                       }
+                               return reply_value([](const frame_transform& t) { return get_blend_mode(t.image_transform.blend_mode); });
 
-                       auto blend_str = parameters().at(1);                                                            
-                       int layer = layer_index();
-                       channel()->mixer().set_blend_mode(layer, get_blend_mode(blend_str));    
+                       auto value = get_blend_mode(parameters().at(1));
+                       transforms.push_back(stage::transform_tuple_t(layer_index(), [=](frame_transform transform) -> frame_transform
+                       {
+                               transform.image_transform.blend_mode = value;
+                               return transform;
+                       }, 0, L"linear"));
                }
                else if(boost::iequals(parameters()[0], L"MASTERVOLUME"))
                {
@@ -765,12 +762,10 @@ bool MixerCommand::DoExecute()
                        if (layer == std::numeric_limits<int>::max())
                        {
                                channel()->stage().clear_transforms();
-                               channel()->mixer().clear_blend_modes();
                        }
                        else
                        {
                                channel()->stage().clear_transforms(layer);
-                               channel()->mixer().clear_blend_mode(layer);
                        }
                }
                else if(boost::iequals(parameters()[0], L"COMMIT"))