]> git.sesse.net Git - casparcg/blobdiff - accelerator/ogl/util/device.cpp
Add call tracing at selected placed in the code to help debug deadlocks in OpenGL.
[casparcg] / accelerator / ogl / util / device.cpp
index b1e52ea942ca669f1f43a62041ee25ba65a20f26..7afefa616c46bf49b5220501944c4a2c854a35eb 100644 (file)
@@ -46,6 +46,7 @@
 #include <tbb/concurrent_queue.h>
 
 #include <boost/utility/declval.hpp>
+#include <boost/property_tree/ptree.hpp>
 
 #include <array>
 #include <unordered_map>
@@ -97,8 +98,11 @@ struct device::impl : public std::enable_shared_from_this<impl>
 
        ~impl()
        {
+               auto context = executor_.is_current() ? std::string() : get_context();
+
                executor_.invoke([=]
                {
+                       CASPAR_SCOPED_CONTEXT_MSG(context);
                        texture_cache_.clear();
 
                        for (auto& pool : host_pools_)
@@ -112,6 +116,93 @@ struct device::impl : public std::enable_shared_from_this<impl>
                        device_.reset();
                });
        }
+
+       boost::property_tree::wptree info() const
+       {
+               boost::property_tree::wptree info;
+
+               boost::property_tree::wptree pooled_device_buffers;
+               size_t total_pooled_device_buffer_size  = 0;
+               size_t total_pooled_device_buffer_count = 0;
+
+               for (size_t i = 0; i < device_pools_.size(); ++i)
+               {
+                       auto& pools             = device_pools_.at(i);
+                       bool mipmapping = i > 3;
+                       auto stride             = mipmapping ? i - 3 : i + 1;
+
+                       for (auto& pool : pools)
+                       {
+                               auto width      = pool.first >> 16;
+                               auto height     = pool.first & 0x0000FFFF;
+                               auto size       = width * height * stride;
+                               auto count      = pool.second.size();
+
+                               if (count == 0)
+                                       continue;
+
+                               boost::property_tree::wptree pool_info;
+
+                               pool_info.add(L"stride",                stride);
+                               pool_info.add(L"mipmapping",    mipmapping);
+                               pool_info.add(L"width",                 width);
+                               pool_info.add(L"height",                height);
+                               pool_info.add(L"size",                  size);
+                               pool_info.add(L"count",                 count);
+
+                               total_pooled_device_buffer_size         += size * count;
+                               total_pooled_device_buffer_count        += count;
+
+                               pooled_device_buffers.add_child(L"device_buffer_pool", pool_info);
+                       }
+               }
+
+               info.add_child(L"gl.details.pooled_device_buffers", pooled_device_buffers);
+
+               boost::property_tree::wptree pooled_host_buffers;
+               size_t total_read_size          = 0;
+               size_t total_write_size         = 0;
+               size_t total_read_count         = 0;
+               size_t total_write_count        = 0;
+
+               for (size_t i = 0; i < host_pools_.size(); ++i)
+               {
+                       auto& pools     = host_pools_.at(i);
+                       auto usage      = static_cast<buffer::usage>(i);
+
+                       for (auto& pool : pools)
+                       {
+                               auto size       = pool.first;
+                               auto count      = pool.second.size();
+
+                               if (count == 0)
+                                       continue;
+
+                               boost::property_tree::wptree pool_info;
+
+                               pool_info.add(L"usage", usage == buffer::usage::read_only ? L"read_only" : L"write_only");
+                               pool_info.add(L"size",  size);
+                               pool_info.add(L"count", count);
+
+                               pooled_host_buffers.add_child(L"host_buffer_pool", pool_info);
+
+                               (usage == buffer::usage::read_only ? total_read_count : total_write_count) += count;
+                               (usage == buffer::usage::read_only ? total_read_size : total_write_size) += size * count;
+                       }
+               }
+
+               info.add_child(L"gl.details.pooled_host_buffers",                               pooled_host_buffers);
+               info.add(L"gl.summary.pooled_device_buffers.total_count",               total_pooled_device_buffer_count);
+               info.add(L"gl.summary.pooled_device_buffers.total_size",                total_pooled_device_buffer_size);
+               info.add_child(L"gl.summary.all_device_buffers",                                texture::info());
+               info.add(L"gl.summary.pooled_host_buffers.total_read_count",    total_read_count);
+               info.add(L"gl.summary.pooled_host_buffers.total_write_count",   total_write_count);
+               info.add(L"gl.summary.pooled_host_buffers.total_read_size",             total_read_size);
+               info.add(L"gl.summary.pooled_host_buffers.total_write_size",    total_write_size);
+               info.add_child(L"gl.summary.all_host_buffers",                                  buffer::info());
+
+               return info;
+       }
                
        std::wstring version()
        {       
@@ -162,8 +253,11 @@ struct device::impl : public std::enable_shared_from_this<impl>
                {
                        caspar::timer timer;
 
+                       auto context = executor_.is_current() ? std::string() : get_context();
+
                        buf = executor_.invoke([&]
                        {
+                               CASPAR_SCOPED_CONTEXT_MSG(context);
                                return std::make_shared<buffer>(size, usage);
                        }, task_priority::high_priority);
                        
@@ -178,7 +272,14 @@ struct device::impl : public std::enable_shared_from_this<impl>
 
                        if (strong)
                        {
-                               strong->texture_cache_.erase(buf.get());
+                               auto context = executor_.is_current() ? std::string() : get_context();
+
+                               strong->executor_.invoke([&]
+                               {
+                                       CASPAR_SCOPED_CONTEXT_MSG(context);
+                                       strong->texture_cache_.erase(buf.get());
+                               }, task_priority::high_priority);
+                               
                                pool->push(buf);
                        }
                        else
@@ -218,9 +319,11 @@ struct device::impl : public std::enable_shared_from_this<impl>
        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);
-                               
+               auto context = executor_.is_current() ? std::string() : get_context();
+
                return executor_.begin_invoke([=]() -> std::shared_ptr<texture>
                {
+                       CASPAR_SCOPED_CONTEXT_MSG(context);
                        tbb::concurrent_hash_map<buffer*, std::shared_ptr<texture>>::const_accessor a;
                        if(texture_cache_.find(a, buf.get()))
                                return spl::make_shared_ptr(a->second);
@@ -237,9 +340,11 @@ struct device::impl : public std::enable_shared_from_this<impl>
        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);
+               auto context = executor_.is_current() ? std::string() : get_context();
 
                return executor_.begin_invoke([=]() -> std::shared_ptr<texture>
                {
+                       CASPAR_SCOPED_CONTEXT_MSG(context);
                        auto texture = create_texture(width, height, stride, mipmapped, false);
                        texture->copy_from(*buf);       
                        
@@ -256,13 +361,44 @@ struct device::impl : public std::enable_shared_from_this<impl>
                source->copy_to(*buffer);       
 
                auto self = shared_from_this();
-               auto cmd = [self, buffer]() mutable -> array<const std::uint8_t>
+               auto context = get_context();
+               auto cmd = [self, buffer, context]() mutable -> array<const std::uint8_t>
                {
-                       self->executor_.invoke(std::bind(&buffer::map, std::ref(buffer))); // Defer blocking "map" call until data is needed.
+                       self->executor_.invoke([&buffer, &context] // Defer blocking "map" call until data is needed.
+                       {
+                               CASPAR_LOG_CALL(trace) << "Readback <- " << context;
+                               buffer->map();
+                       });
                        return array<const std::uint8_t>(buffer->data(), buffer->size(), true, buffer);
                };
                return std::async(std::launch::deferred, std::move(cmd));
        }
+
+       std::future<void> gc()
+       {
+               return executor_.begin_invoke([=]
+               {
+                       CASPAR_LOG(info) << " ogl: Running GC.";
+
+                       try
+                       {
+                               for (auto& pools : device_pools_)
+                               {
+                                       for (auto& pool : pools)
+                                               pool.second.clear();
+                               }
+                               for (auto& pools : host_pools_)
+                               {
+                                       for (auto& pool : pools)
+                                               pool.second.clear();
+                               }
+                       }
+                       catch (...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                       }
+               }, task_priority::high_priority);
+       }
 };
 
 device::device() 
@@ -274,6 +410,8 @@ array<std::uint8_t>                                                 device::create_array(int size){return impl_->create_ar
 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::future<void>                                                      device::gc() { return impl_->gc(); }
+boost::property_tree::wptree                           device::info() const { return impl_->info(); }
 std::wstring                                                           device::version() const{return impl_->version();}