]> git.sesse.net Git - casparcg/commitdiff
* Merged MIXER MIPMAP support from 2.0. Implemented as a setting in frame_transform...
authorHelge Norberg <helge.norberg@svt.se>
Thu, 4 Jun 2015 14:42:59 +0000 (16:42 +0200)
committerHelge Norberg <helge.norberg@svt.se>
Thu, 4 Jun 2015 14:42:59 +0000 (16:42 +0200)
* Exposed mipmap and is_key setting to scene_producer.
* Fixed bug in async destruction of consumers and producers where counter was uninitialized.

13 files changed:
accelerator/ogl/image/image_mixer.cpp
accelerator/ogl/util/device.cpp
accelerator/ogl/util/device.h
accelerator/ogl/util/texture.cpp
accelerator/ogl/util/texture.h
core/consumer/frame_consumer.cpp
core/frame/frame_transform.cpp
core/frame/frame_transform.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 9dcc90e8b7a32056d011a3fabdaf728a2f770ad1..27a2251f2fc552eeb12e113abb44578eefd935ad 100644 (file)
@@ -108,13 +108,13 @@ public:
                if(format_desc.field_mode != core::field_mode::progressive)
                { // Remove jitter from still.
                        for (auto& layer : layers)
-                       {       
+                       {
                                // Remove first field stills.
                                boost::range::remove_erase_if(layer.items, [&](const item& item)
                                {
                                        return item.transform.is_still && item.transform.field_mode == format_desc.field_mode; // only us last field for stills.
                                });
-               
+
                                // Stills are progressive
                                for (auto& item : layer.items)
                                {
@@ -126,7 +126,7 @@ public:
 
                return flatten(ogl_->begin_invoke([=]() mutable -> std::shared_future<array<const std::uint8_t>>
                {
-                       auto target_texture = ogl_->create_texture(format_desc.width, format_desc.height, 4);
+                       auto target_texture = ogl_->create_texture(format_desc.width, format_desc.height, 4, false);
 
                        if (format_desc.field_mode != core::field_mode::progressive)
                        {
@@ -198,7 +198,7 @@ private:
                                
                if(layer.blend_mode != core::blend_mode::normal)
                {
-                       auto layer_texture = ogl_->create_texture(target_texture->width(), target_texture->height(), 4);
+                       auto layer_texture = ogl_->create_texture(target_texture->width(), target_texture->height(), 4, false);
 
                        for (auto& item : layer.items)
                                draw(layer_texture, std::move(item), layer_key_texture, local_key_texture, local_mix_texture, format_desc);
@@ -235,7 +235,7 @@ private:
 
                if(item.transform.is_key)
                {
-                       local_key_texture = local_key_texture ? local_key_texture : ogl_->create_texture(target_texture->width(), target_texture->height(), 1);
+                       local_key_texture = local_key_texture ? local_key_texture : ogl_->create_texture(target_texture->width(), target_texture->height(), 1, draw_params.transform.use_mipmap);
 
                        draw_params.background  = local_key_texture;
                        draw_params.local_key   = nullptr;
@@ -245,7 +245,7 @@ private:
                }
                else if(item.transform.is_mix)
                {
-                       local_mix_texture = local_mix_texture ? local_mix_texture : ogl_->create_texture(target_texture->width(), target_texture->height(), 4);
+                       local_mix_texture = local_mix_texture ? local_mix_texture : ogl_->create_texture(target_texture->width(), target_texture->height(), 4, draw_params.transform.use_mipmap);
 
                        draw_params.background  = local_mix_texture;
                        draw_params.local_key   = std::move(local_key_texture);
@@ -330,7 +330,7 @@ public:
                
                // NOTE: Once we have copied the arrays they are no longer valid for reading!!! Check for alternative solution e.g. transfer with AMD_pinned_memory.
                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.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);
        }
index bd14a902d2ae71c854df493db740a3cd229f7e79..b0a4a9cb03928c413519c2de1fc9157487a574d4 100644 (file)
@@ -63,7 +63,7 @@ struct device::impl : public std::enable_shared_from_this<impl>
 
        std::unique_ptr<sf::Context> device_;
        
-       std::array<tbb::concurrent_unordered_map<std::size_t, tbb::concurrent_bounded_queue<std::shared_ptr<texture>>>, 4>      device_pools_;
+       std::array<tbb::concurrent_unordered_map<std::size_t, tbb::concurrent_bounded_queue<std::shared_ptr<texture>>>, 8>      device_pools_;
        std::array<tbb::concurrent_unordered_map<std::size_t, tbb::concurrent_bounded_queue<std::shared_ptr<buffer>>>, 2>       host_pools_;
        
        GLuint fbo_;
@@ -128,7 +128,7 @@ struct device::impl : public std::enable_shared_from_this<impl>
                }
        }
                                                        
-       spl::shared_ptr<texture> create_texture(int width, int height, int stride, bool clear = false)
+       spl::shared_ptr<texture> create_texture(int width, int height, int stride, bool mipmapped, bool clear)
        {
                CASPAR_VERIFY(stride > 0 && stride < 5);
                CASPAR_VERIFY(width > 0 && height > 0);
@@ -136,11 +136,11 @@ struct device::impl : public std::enable_shared_from_this<impl>
                if(!executor_.is_current())
                        CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Operation only valid in an OpenGL Context."));
                                        
-               auto pool = &device_pools_[stride-1][((width << 16) & 0xFFFF0000) | (height & 0x0000FFFF)];
+               auto pool = &device_pools_[stride - 1 + (mipmapped ? 4 : 0)][((width << 16) & 0xFFFF0000) | (height & 0x0000FFFF)];
                
                std::shared_ptr<texture> tex;
                if(!pool->try_pop(tex))         
-                       tex = spl::make_shared<texture>(width, height, stride);
+                       tex = spl::make_shared<texture>(width, height, stride, mipmapped);
        
                if(clear)
                        tex->clear();
@@ -171,11 +171,20 @@ struct device::impl : public std::enable_shared_from_this<impl>
                                CASPAR_LOG(debug) << L"[ogl-device] Performance warning. Buffer allocation blocked: " << timer.elapsed();
                }
                
-               auto self = shared_from_this(); // buffers can leave the device context, take a hold on life-time.
+               std::weak_ptr<impl> self = shared_from_this(); // buffers can leave the device context, take a hold on life-time.
                return spl::shared_ptr<buffer>(buf.get(), [=](buffer*) mutable
-               {       
-                       texture_cache_.erase(buf.get());
-                       pool->push(buf);
+               {
+                       auto strong = self.lock();
+
+                       if (strong)
+                       {
+                               strong->texture_cache_.erase(buf.get());
+                               pool->push(buf);
+                       }
+                       else
+                       {
+                               CASPAR_LOG(info) << L"Buffer outlived ogl device";
+                       }
                });
        }
 
@@ -206,7 +215,7 @@ struct device::impl : public std::enable_shared_from_this<impl>
        }
 
        // TODO: Since the returned texture is cached it SHOULD NOT be modified.
-       std::future<std::shared_ptr<texture>> copy_async(const array<const std::uint8_t>& source, int width, int height, int stride)
+       std::future<std::shared_ptr<texture>> copy_async(const array<const std::uint8_t>& source, int width, int height, int stride, bool mipmapped)
        {
                std::shared_ptr<buffer> buf = copy_to_buf(source);
                                
@@ -216,8 +225,8 @@ struct device::impl : public std::enable_shared_from_this<impl>
                        if(texture_cache_.find(a, buf.get()))
                                return spl::make_shared_ptr(a->second);
 
-                       auto texture = create_texture(width, height, stride);
-                       texture->copy_from(*buf);       
+                       auto texture = create_texture(width, height, stride, mipmapped, false);
+                       texture->copy_from(*buf);
 
                        texture_cache_.insert(std::make_pair(buf.get(), texture));
                        
@@ -225,13 +234,13 @@ struct device::impl : public std::enable_shared_from_this<impl>
                }, task_priority::high_priority);
        }
        
-       std::future<std::shared_ptr<texture>> copy_async(const array<std::uint8_t>& source, int width, int height, int stride)
+       std::future<std::shared_ptr<texture>> copy_async(const array<std::uint8_t>& source, int width, int height, int stride, bool mipmapped)
        {
                std::shared_ptr<buffer> buf = copy_to_buf(source);
 
                return executor_.begin_invoke([=]() -> std::shared_ptr<texture>
                {
-                       auto texture = create_texture(width, height, stride, false);
+                       auto texture = create_texture(width, height, stride, mipmapped, false);
                        texture->copy_from(*buf);       
                        
                        return texture;
@@ -260,10 +269,10 @@ device::device()
        : executor_(L"OpenGL Rendering Context")
        , impl_(new impl(executor_)){}
 device::~device(){}
-spl::shared_ptr<texture>                                       device::create_texture(int width, int height, int stride){return impl_->create_texture(width, height, stride, true);}
+spl::shared_ptr<texture>                                       device::create_texture(int width, int height, int stride, bool mipmapped){ return impl_->create_texture(width, height, stride, mipmapped, true); }
 array<std::uint8_t>                                                    device::create_array(int size){return impl_->create_array(size);}
-std::future<std::shared_ptr<texture>>          device::copy_async(const array<const std::uint8_t>& source, int width, int height, int stride){return impl_->copy_async(source, width, height, stride);}
-std::future<std::shared_ptr<texture>>          device::copy_async(const array<std::uint8_t>& source, int width, int height, int stride){return impl_->copy_async(source, width, height, stride);}
+std::future<std::shared_ptr<texture>>          device::copy_async(const array<const std::uint8_t>& source, int width, int height, int stride, bool mipmapped){return impl_->copy_async(source, width, height, stride, mipmapped);}
+std::future<std::shared_ptr<texture>>          device::copy_async(const array<std::uint8_t>& source, int width, int height, int stride, bool mipmapped){ return impl_->copy_async(source, width, height, stride, mipmapped); }
 std::future<array<const std::uint8_t>>         device::copy_async(const spl::shared_ptr<texture>& source){return impl_->copy_async(source);}
 std::wstring                                                           device::version() const{return impl_->version();}
 
index 68bff80884f8e05fcdc56d6479b41b6d822ba063..f010df743b67e5c246850f03ab5c7ad74b6862d0 100644 (file)
@@ -47,13 +47,13 @@ public:
 
        // Methods
                        
-       spl::shared_ptr<texture> create_texture(int width, int height, int stride);
+       spl::shared_ptr<texture> create_texture(int width, int height, int stride, bool mipmapped);
        array<std::uint8_t>              create_array(int size);
                
        // NOTE: Since the returned texture is cached it SHOULD NOT be modified.
-       std::future<std::shared_ptr<texture>>   copy_async(const array<const std::uint8_t>& source, int width, int height, int stride);
+       std::future<std::shared_ptr<texture>>   copy_async(const array<const std::uint8_t>& source, int width, int height, int stride, bool mipmapped);
 
-       std::future<std::shared_ptr<texture>>   copy_async(const array<std::uint8_t>& source, int width, int height, int stride);
+       std::future<std::shared_ptr<texture>>   copy_async(const array<std::uint8_t>& source, int width, int height, int stride, bool mipmapped);
        std::future<array<const std::uint8_t>>  copy_async(const spl::shared_ptr<texture>& source);
                        
        template<typename Func>
index 9e308762326cfcef4ad9fbc67013a8c9b3d24263..79e5cdd6c631b07496498093f665f11b174fc20d 100644 (file)
@@ -46,26 +46,52 @@ struct texture::impl : boost::noncopyable
 {
        GLuint  id_;
 
-       const int width_;
-       const int height_;
-       const int stride_;
+       const int       width_;
+       const int       height_;
+       const int       stride_;
+       const bool      mipmapped_;
 public:
-       impl(int width, int height, int stride) 
+       impl(int width, int height, int stride, bool mipmapped
                : width_(width)
                , height_(height)
                , stride_(stride)
+               , mipmapped_(mipmapped)
        {       
                GL(glGenTextures(1, &id_));
                GL(glBindTexture(GL_TEXTURE_2D, id_));
-               GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
-               GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
-               GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
-               GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+               GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (mipmapped ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR)));
+               GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+               GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+               GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
                GL(glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT[stride_], width_, height_, 0, FORMAT[stride_], TYPE[stride_], NULL));
+
+               if (mipmapped)
+               {
+                       enable_anosotropic_filtering_if_available();
+                       GL(glGenerateMipmap(GL_TEXTURE_2D));
+               }
+
                GL(glBindTexture(GL_TEXTURE_2D, 0));
                //CASPAR_LOG(trace) << "[texture] [" << ++g_total_count << L"] allocated size:" << width*height*stride; 
        }       
 
+       void enable_anosotropic_filtering_if_available()
+       {
+               static auto AVAILABLE = glewIsSupported("GL_EXT_texture_filter_anisotropic");
+
+               if (!AVAILABLE)
+                       return;
+
+               static GLfloat MAX_ANISOTROPY = []() -> GLfloat
+               {
+                       GLfloat anisotropy;
+                       glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropy);
+                       return anisotropy;
+               }();
+
+               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, MAX_ANISOTROPY);
+       }
+
        ~impl()
        {
                glDeleteTextures(1, &id_);
@@ -104,6 +130,10 @@ public:
                source.bind();
                GL(glBindTexture(GL_TEXTURE_2D, id_));
                GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, FORMAT[stride_], TYPE[stride_], NULL));
+
+               if (mipmapped_)
+                       GL(glGenerateMipmap(GL_TEXTURE_2D));
+
                GL(glBindTexture(GL_TEXTURE_2D, 0));
                source.unbind();
                source.map(); // Just map it back since map will orphan buffer.
@@ -122,7 +152,7 @@ public:
        }
 };
 
-texture::texture(int width, int height, int stride) : impl_(new impl(width, height, stride)){}
+texture::texture(int width, int height, int stride, bool mipmapped) : impl_(new impl(width, height, stride, mipmapped)){}
 texture::texture(texture&& other) : impl_(std::move(other.impl_)){}
 texture::~texture(){}
 texture& texture::operator=(texture&& other){impl_ = std::move(other.impl_); return *this;}
@@ -135,6 +165,7 @@ void texture::copy_to(buffer& dest){impl_->copy_to(dest);}
 int texture::width() const { return impl_->width_; }
 int texture::height() const { return impl_->height_; }
 int texture::stride() const { return impl_->stride_; }
+bool texture::mipmapped() const { return impl_->mipmapped_; }
 std::size_t texture::size() const { return static_cast<std::size_t>(impl_->width_*impl_->height_*impl_->stride_); }
 int texture::id() const{ return impl_->id_;}
 
index 93c9df3b9ec68020204a8a8566d76c9f33eb2e6f..c9575747fb08d0736fa15dfac39ddee2b7c2f75e 100644 (file)
@@ -40,7 +40,7 @@ public:
 
        // Constructors
 
-       texture(int width, int height, int stride);
+       texture(int width, int height, int stride, bool mipmapped);
        texture(texture&& other);
        ~texture();
        
@@ -61,6 +61,7 @@ public:
        int width() const;
        int height() const;
        int stride() const;     
+       bool mipmapped() const;
        std::size_t size() const;
 
        int id() const;
index 06c324c8178daeeb3aacd94dd65289c1189b8aa3..214b53f0347d2e1ade898b9db6ca1504244db971 100644 (file)
@@ -63,7 +63,12 @@ public:
 
        ~destroy_consumer_proxy()
        {               
-               static tbb::atomic<int> counter = tbb::atomic<int>();
+               static tbb::atomic<int> counter = []
+               {
+                       tbb::atomic<int> c;
+                       c = 0;
+                       return c;
+               }();
                        
                ++counter;
                CASPAR_VERIFY(counter < 8);
@@ -85,7 +90,6 @@ public:
 
                        pointer_guard.reset();
 
-                       --counter;
                }).detach(); 
        }
        
index 86928191cc4fda8df7cb36e3b6bc7c5c4624f9ba..e93d3a7c563af2603237769cd22e042161feffec 100644 (file)
@@ -95,6 +95,7 @@ image_transform& image_transform::operator*=(const image_transform &other)
        is_key                                  |= other.is_key;
        is_mix                                  |= other.is_mix;
        is_still                                |= other.is_still;
+       use_mipmap                              |= other.use_mipmap;
 
        return *this;
 }
@@ -156,6 +157,7 @@ image_transform image_transform::tween(double time, const image_transform& sourc
        result.is_key                           = source.is_key | dest.is_key;
        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;
 
        do_tween_rectangle(source.crop, dest.crop, result.crop, time, duration, tween);
        do_tween_corners(source.perspective, dest.perspective, result.perspective, time, duration, tween);
@@ -201,6 +203,7 @@ bool operator==(const image_transform& lhs, const image_transform& rhs)
                lhs.is_key == rhs.is_key &&
                lhs.is_mix == rhs.is_mix &&
                lhs.is_still == rhs.is_still &&
+               lhs.use_mipmap == rhs.use_mipmap &&
                lhs.crop == rhs.crop &&
                lhs.perspective == rhs.perspective;
 }
index 7eea60ad203dadeeffae3f81140fb955798a0631..bb421f54559a812949e22a0db8adf92ad86bbe12 100644 (file)
@@ -75,6 +75,7 @@ struct image_transform final
        bool                                    is_key                          = false;
        bool                                    is_mix                          = false;
        bool                                    is_still                        = false;
+       bool                                    use_mipmap                      = false;
        
        image_transform& operator*=(const image_transform &other);
        image_transform operator*(const image_transform &other) const;
index 16f48ea9d9c94d40a95a056c1c84f36a1dcc0d11..de5a0bc8b97c400886fdf1185d8b1b2f9241ee45 100644 (file)
@@ -200,7 +200,12 @@ public:
 
        virtual ~destroy_producer_proxy()
        {               
-               static tbb::atomic<int> counter = tbb::atomic<int>();
+               static tbb::atomic<int> counter = []
+               {
+                       tbb::atomic<int> c;
+                       c = 0;
+                       return c;
+               }();
                
                if(producer_ == core::frame_producer::empty())
                        return;
index e48e8351f113857877b3ac29fc5d927fe2378877..41b383a5a39a8df9fba2d4b553bbb844d64689b3 100644 (file)
@@ -195,6 +195,7 @@ 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();
 
                return transform;
        }
@@ -212,7 +213,7 @@ struct scene_producer::impl
                                continue;
 
                        draw_frame frame(layer.producer.get()->receive());
-                       frame.transform() = get_transform(layer);;
+                       frame.transform() = get_transform(layer);
                        frames.push_back(frame);
                }
 
index 9f9904156ab32219337abad3b35ad54b1e94a2aa..cdc969dc2d0dcc6bc2d18fcc2d50252ece9f950a 100644 (file)
@@ -73,6 +73,7 @@ struct layer
        binding<spl::shared_ptr<frame_producer>>        producer;
        binding<bool>                                                           hidden;
        binding<bool>                                                           is_key;
+       binding<bool>                                                           use_mipmap;
 
        explicit layer(const std::wstring& name, const spl::shared_ptr<frame_producer>& producer);
 };
index 9086861ece2bcfa6713cc49236368f53c288770b..3af6c99bd48141136d0986e01b8260f46cfbe99f 100644 (file)
@@ -131,6 +131,8 @@ spl::shared_ptr<core::frame_producer> create_xml_scene_producer(
                layer.perspective.lower_left.y = scene->create_variable<double>(variable_prefix + L"perspective_lower_left_y", false, elem.second.get<std::wstring>(L"perspective_lower_left_y", layer.producer.get()->pixel_constraints().height.as<std::wstring>().get()));
 
                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"));
 
                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 abc520b5af5ffe4a830f7e901178ae0c652aff79..ff454f79e31ceb2143a8b51feb2821e93e022de8 100644 (file)
@@ -616,6 +616,18 @@ bool MixerCommand::DoExecute()
                                }
                        }
                }
+               else if (boost::iequals(parameters()[0], L"MIPMAP"))
+               {
+                       if (parameters().size() == 1)
+                               return reply_value([](const frame_transform& t) { return t.image_transform.use_mipmap ? 1 : 0; });
+
+                       bool value = boost::lexical_cast<int>(parameters().at(1));
+                       transforms.push_back(stage::transform_tuple_t(layer_index(), [=](frame_transform transform) -> frame_transform
+                       {
+                               transform.image_transform.use_mipmap = value;
+                               return transform;
+                       }, 0, L"linear"));
+               }
                else if(boost::iequals(parameters()[0], L"BLEND"))
                {
                        if (parameters().size() == 1)