#include "cpu/image/image_mixer.h"
#endif
#include "ogl/image/image_mixer.h"
-
#include "ogl/util/device.h"
#include <common/env.h>
+#include <core/mixer/image/image_mixer.h>
+
#include <tbb/mutex.h>
namespace caspar { namespace accelerator {
return impl_->create_image_mixer(channel_id);
}
+std::shared_ptr<ogl::device> accelerator::get_ogl_device() const
+{
+ return impl_->ogl_device_;
+}
+
}}
#include <common/forward.h>
#include <common/memory.h>
-#include <core/mixer/image/image_mixer.h>
+#include <core/fwd.h>
#include <boost/noncopyable.hpp>
~accelerator();
std::unique_ptr<core::image_mixer> create_image_mixer(int channel_id);
+
+ std::shared_ptr<ogl::device> get_ogl_device() const;
private:
struct impl;
spl::unique_ptr<impl> impl_;
#include <GL/glew.h>
+#include <boost/property_tree/ptree.hpp>
+
#include <tbb/atomic.h>
namespace caspar { namespace accelerator { namespace ogl {
-static tbb::atomic<int> g_w_total_count;
-static tbb::atomic<int> g_r_total_count;
-
+static tbb::atomic<int> g_w_total_count;
+static tbb::atomic<std::size_t> g_w_total_size;
+static tbb::atomic<int> g_r_total_count;
+static tbb::atomic<std::size_t> g_r_total_size;
+
struct buffer::impl : boost::noncopyable
{
GLuint pbo_;
if(!pbo_)
CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to allocate buffer."));
+
+ (usage == usage::write_only ? g_w_total_count : g_r_total_count) ++;
+ (usage == usage::write_only ? g_w_total_size : g_r_total_size) += size_;
if(timer.elapsed() > 0.02)
CASPAR_LOG(warning) << L"[buffer] Performance warning. Buffer allocation blocked: " << timer.elapsed();
~impl()
{
glDeleteBuffers(1, &pbo_);
+ (usage_ == GL_STREAM_DRAW ? g_w_total_size : g_r_total_size) -= size_;
+ (usage_ == GL_STREAM_DRAW ? g_w_total_count : g_r_total_count) --;
}
void* map()
std::size_t buffer::size() const { return impl_->size_; }
int buffer::id() const {return impl_->pbo_;}
+boost::property_tree::wptree buffer::info()
+{
+ boost::property_tree::wptree info;
+
+ info.add(L"total_read_count", g_r_total_count);
+ info.add(L"total_write_count", g_w_total_count);
+ info.add(L"total_read_size", g_r_total_size);
+ info.add(L"total_write_size", g_w_total_size);
+
+ return info;
+}
+
}}}
#include <common/memory.h>
+#include <boost/property_tree/ptree_fwd.hpp>
+
#include <cstdint>
namespace caspar { namespace accelerator { namespace ogl {
int id() const;
+ static boost::property_tree::wptree info();
private:
struct impl;
spl::unique_ptr<impl> impl_;
#include <tbb/concurrent_queue.h>
#include <boost/utility/declval.hpp>
+#include <boost/property_tree/ptree.hpp>
#include <array>
#include <unordered_map>
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()
{
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);}
+boost::property_tree::wptree device::info() const { return impl_->info(); }
std::wstring device::version() const{return impl_->version();}
#include <common/memory.h>
#include <common/executor.h>
+#include <boost/property_tree/ptree_fwd.hpp>
+
namespace caspar { namespace accelerator { namespace ogl {
class texture;
// Properties
- std::wstring version() const;
+ boost::property_tree::wptree info() const;
+ std::wstring version() const;
private:
struct impl;
static GLenum INTERNAL_FORMAT[] = {0, GL_R8, GL_RG8, GL_RGB8, GL_RGBA8};
static GLenum TYPE[] = {0, GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT_8_8_8_8_REV};
-static tbb::atomic<int> g_total_count;
+static tbb::atomic<int> g_total_count;
+static tbb::atomic<std::size_t> g_total_size;
struct texture::impl : boost::noncopyable
{
}
GL(glBindTexture(GL_TEXTURE_2D, 0));
+ g_total_count++;
+ g_total_size += static_cast<std::size_t>(width * height * stride * (mipmapped ? 1.33 : 1.0));
//CASPAR_LOG(trace) << "[texture] [" << ++g_total_count << L"] allocated size:" << width*height*stride;
}
~impl()
{
glDeleteTextures(1, &id_);
+ g_total_size -= static_cast<std::size_t>(width_ * height_ * stride_ * (mipmapped_ ? 1.33 : 1.0));
+ g_total_count--;
}
void bind()
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_;}
+boost::property_tree::wptree texture::info()
+{
+ boost::property_tree::wptree info;
+
+ info.add(L"total_count", g_total_count);
+ info.add(L"total_size", g_total_size);
+
+ return info;
+}
+
}}}
#include <common/memory.h>
+#include <boost/property_tree/ptree_fwd.hpp>
+
#include <cstddef>
namespace caspar { namespace accelerator { namespace ogl {
int id() const;
+ static boost::property_tree::wptree info();
private:
struct impl;
spl::unique_ptr<impl> impl_;
return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4), std::forward<P5>(p5), std::forward<P6>(p6), std::forward<P7>(p7), std::forward<P8>(p8)));
}
+template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9>
+shared_ptr<T> make_shared(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5, P6&& p6, P7&& p7, P8&& p8, P9&& p9)
+{
+ return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4), std::forward<P5>(p5), std::forward<P6>(p6), std::forward<P7>(p7), std::forward<P8>(p8), std::forward<P9>(p9)));
+}
+
template<typename T>
shared_ptr<T>::shared_ptr()
: p_(make_shared<T>())
#include <common/forward.h>
-FORWARD3(caspar, core, ogl, class accelerator);
+FORWARD2(caspar, accelerator, class accelerator);
+FORWARD3(caspar, accelerator, ogl, class device);
FORWARD2(caspar, core, class stage);
FORWARD2(caspar, core, class mixer);
#include "amcp_shared.h"
#include <core/consumer/frame_consumer.h>
#include <core/producer/frame_producer.h>
+#include <accelerator/ogl/util/device.h>
#include <boost/algorithm/string.hpp>
std::shared_ptr<core::thumbnail_generator> thumb_gen;
spl::shared_ptr<const core::frame_producer_registry> producer_registry;
spl::shared_ptr<const core::frame_consumer_registry> consumer_registry;
+ std::shared_ptr<accelerator::ogl::device> ogl_device;
std::promise<bool>& shutdown_server_now;
std::vector<std::wstring> parameters;
std::shared_ptr<core::thumbnail_generator> thumb_gen,
spl::shared_ptr<const core::frame_producer_registry> producer_registry,
spl::shared_ptr<const core::frame_consumer_registry> consumer_registry,
+ std::shared_ptr<accelerator::ogl::device> ogl_device,
std::promise<bool>& shutdown_server_now)
: client(std::move(client))
, channel(channel)
, thumb_gen(std::move(thumb_gen))
, producer_registry(std::move(producer_registry))
, consumer_registry(std::move(consumer_registry))
+ , ogl_device(std::move(ogl_device))
, shutdown_server_now(shutdown_server_now)
{
}
return L"202 DIAG OK\r\n";
}
+void gl_info_describer(core::help_sink& sink, const core::help_repository& repo)
+{
+ sink.short_description(L"Get information about the allocated and pooled OpenGL resources.");
+ sink.syntax(L"GL INFO");
+ sink.para()->text(L"Retrieves information about the allocated and pooled OpenGL resources.");
+}
+
+std::wstring gl_info_command(command_context& ctx)
+{
+ auto device = ctx.ogl_device;
+
+ if (!device)
+ CASPAR_THROW_EXCEPTION(not_supported() << msg_info("GL command only supported with OpenGL accelerator."));
+
+ std::wstringstream result;
+ result << L"201 GL INFO OK\r\n";
+
+ boost::property_tree::xml_writer_settings<std::wstring> w(' ', 3);
+ auto info = device->info();
+ boost::property_tree::write_xml(result, info, w);
+ result << L"\r\n";
+
+ return result.str();
+}
+
static const int WIDTH = 80;
struct max_width_sink : public core::help_sink
repo.register_command( L"Query Commands", L"INFO THREADS", info_threads_describer, info_threads_command, 0);
repo.register_channel_command( L"Query Commands", L"INFO DELAY", info_delay_describer, info_delay_command, 0);
repo.register_command( L"Query Commands", L"DIAG", diag_describer, diag_command, 0);
+ repo.register_command( L"Query Commands", L"GL INFO", gl_info_describer, gl_info_command, 0);
repo.register_command( L"Query Commands", L"BYE", bye_describer, bye_command, 0);
repo.register_command( L"Query Commands", L"KILL", kill_describer, kill_command, 0);
repo.register_command( L"Query Commands", L"RESTART", restart_describer, restart_command, 0);
spl::shared_ptr<core::help_repository> help_repo;
spl::shared_ptr<const core::frame_producer_registry> producer_registry;
spl::shared_ptr<const core::frame_consumer_registry> consumer_registry;
+ std::shared_ptr<accelerator::ogl::device> ogl_device;
std::promise<bool>& shutdown_server_now;
std::map<std::wstring, std::pair<amcp_command_func, int>> commands;
const spl::shared_ptr<core::help_repository>& help_repo,
const spl::shared_ptr<const core::frame_producer_registry>& producer_registry,
const spl::shared_ptr<const core::frame_consumer_registry>& consumer_registry,
+ const std::shared_ptr<accelerator::ogl::device>& ogl_device,
std::promise<bool>& shutdown_server_now)
: thumb_gen(thumb_gen)
, media_info_repo(media_info_repo)
, help_repo(help_repo)
, producer_registry(producer_registry)
, consumer_registry(consumer_registry)
+ , ogl_device(ogl_device)
, shutdown_server_now(shutdown_server_now)
{
int index = 0;
const spl::shared_ptr<core::help_repository>& help_repo,
const spl::shared_ptr<const core::frame_producer_registry>& producer_registry,
const spl::shared_ptr<const core::frame_consumer_registry>& consumer_registry,
+ const std::shared_ptr<accelerator::ogl::device>& ogl_device,
std::promise<bool>& shutdown_server_now)
: impl_(new impl(
channels,
help_repo,
producer_registry,
consumer_registry,
+ ogl_device,
shutdown_server_now))
{
}
self.thumb_gen,
self.producer_registry,
self.consumer_registry,
+ self.ogl_device,
self.shutdown_server_now);
auto command = find_command(self.commands, s, ctx, tokens);
self.thumb_gen,
self.producer_registry,
self.consumer_registry,
+ self.ogl_device,
self.shutdown_server_now);
auto command = find_command(self.channel_commands, s, ctx, tokens);
const spl::shared_ptr<core::help_repository>& help_repo,
const spl::shared_ptr<const core::frame_producer_registry>& producer_registry,
const spl::shared_ptr<const core::frame_consumer_registry>& consumer_registry,
+ const std::shared_ptr<accelerator::ogl::device>& ogl_device,
std::promise<bool>& shutdown_server_now);
AMCPCommand::ptr_type create_command(const std::wstring& s, IO::ClientInfoPtr client, std::list<std::wstring>& tokens) const;
add_executable(generate_docs generate_docs.cpp included_modules.h)
target_link_libraries(generate_docs
protocol
+ accelerator
"${CASPARCG_MODULE_PROJECTS}"
help_repo,
producer_registry,
consumer_registry,
+ nullptr,
shutdown_server_now);
protocol::amcp::register_commands(repo);
#include <core/producer/text/text_producer.h>
#include <core/consumer/output.h>
#include <core/mixer/mixer.h>
+#include <core/mixer/image/image_mixer.h>
#include <core/thumbnail_generator.h>
#include <core/producer/media_info/media_info.h>
#include <core/producer/media_info/media_info_repository.h>
help_repo_,
producer_registry_,
consumer_registry_,
+ accelerator_.get_ogl_device(),
shutdown_server_now_);
amcp::register_commands(*amcp_command_repo_);