-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-// TODO: Smart GC\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "device.h"\r
-\r
-#include "buffer.h"\r
-#include "texture.h"\r
-#include "shader.h"\r
-\r
-#include <common/assert.h>\r
-#include <common/except.h>\r
-#include <common/future.h>\r
-#include <common/array.h>\r
-#include <common/gl/gl_check.h>\r
-#include <common/os/windows/windows.h>\r
-\r
-#include <boost/foreach.hpp>\r
-\r
-#include <gl/glew.h>\r
-\r
-#include <SFML/Window/Context.hpp>\r
-\r
-#include <tbb/concurrent_unordered_map.h>\r
-#include <tbb/concurrent_hash_map.h>\r
-#include <tbb/concurrent_queue.h>\r
-\r
-#include <boost/utility/declval.hpp>\r
-\r
-#include <array>\r
-#include <unordered_map>\r
-\r
-#include <asmlib.h>\r
-#include <tbb/parallel_for.h>\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
- \r
-struct device::impl : public std::enable_shared_from_this<impl>\r
-{ \r
- static_assert(std::is_same<decltype(boost::declval<device>().impl_), spl::shared_ptr<impl>>::value, "impl_ must be shared_ptr");\r
-\r
- tbb::concurrent_hash_map<buffer*, std::shared_ptr<texture>> texture_cache_;\r
-\r
- std::unique_ptr<sf::Context> device_;\r
- \r
- std::array<tbb::concurrent_unordered_map<std::size_t, tbb::concurrent_bounded_queue<std::shared_ptr<texture>>>, 4> device_pools_;\r
- std::array<tbb::concurrent_unordered_map<std::size_t, tbb::concurrent_bounded_queue<std::shared_ptr<buffer>>>, 2> host_pools_;\r
- \r
- GLuint fbo_;\r
-\r
- executor& executor_;\r
- \r
- impl(executor& executor) \r
- : executor_(executor)\r
- {\r
- executor_.set_capacity(256);\r
-\r
- CASPAR_LOG(info) << L"Initializing OpenGL Device.";\r
- \r
- executor_.invoke([=]\r
- {\r
- device_.reset(new sf::Context());\r
- device_->SetActive(true); \r
- \r
- if (glewInit() != GLEW_OK)\r
- CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to initialize GLEW."));\r
- \r
- if(!GLEW_VERSION_3_0)\r
- CASPAR_THROW_EXCEPTION(not_supported() << msg_info("Your graphics card does not meet the minimum hardware requirements since it does not support OpenGL 3.0 or higher."));\r
- \r
- glGenFramebuffers(1, &fbo_); \r
- glBindFramebuffer(GL_FRAMEBUFFER, fbo_);\r
- });\r
- \r
- CASPAR_LOG(info) << L"Successfully initialized OpenGL " << version();\r
- }\r
-\r
- ~impl()\r
- {\r
- executor_.invoke([=]\r
- {\r
- BOOST_FOREACH(auto& pool, device_pools_)\r
- pool.clear();\r
- glDeleteFramebuffers(1, &fbo_);\r
-\r
- device_.reset();\r
- });\r
- }\r
- \r
- std::wstring version()\r
- { \r
- try\r
- {\r
- return executor_.invoke([]\r
- {\r
- return u16(reinterpret_cast<const char*>(GL2(glGetString(GL_VERSION)))) + L" " + u16(reinterpret_cast<const char*>(GL2(glGetString(GL_VENDOR))));\r
- }); \r
- }\r
- catch(...)\r
- {\r
- return L"Not found";;\r
- }\r
- }\r
- \r
- spl::shared_ptr<texture> create_texture(int width, int height, int stride, bool clear = false)\r
- {\r
- CASPAR_VERIFY(stride > 0 && stride < 5);\r
- CASPAR_VERIFY(width > 0 && height > 0);\r
-\r
- if(!executor_.is_current())\r
- CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Operation only valid in an OpenGL Context."));\r
- \r
- auto pool = &device_pools_[stride-1][((width << 16) & 0xFFFF0000) | (height & 0x0000FFFF)];\r
- \r
- std::shared_ptr<texture> tex;\r
- if(!pool->try_pop(tex)) \r
- tex = spl::make_shared<texture>(width, height, stride);\r
- \r
- if(clear)\r
- tex->clear();\r
-\r
- return spl::shared_ptr<texture>(tex.get(), [tex, pool](texture*) mutable\r
- { \r
- pool->push(tex); \r
- });\r
- }\r
- \r
- spl::shared_ptr<buffer> create_buffer(std::size_t size, buffer::usage usage)\r
- {\r
- CASPAR_VERIFY(size > 0);\r
- \r
- auto pool = &host_pools_[usage.value()][size];\r
- \r
- std::shared_ptr<buffer> buf;\r
- if(!pool->try_pop(buf)) \r
- {\r
- boost::timer timer;\r
-\r
- buf = executor_.invoke([&]\r
- {\r
- return spl::make_shared<buffer>(size, usage);\r
- }, task_priority::high_priority);\r
- \r
- if(timer.elapsed() > 0.02)\r
- CASPAR_LOG(debug) << L"[ogl-device] Performance warning. Buffer allocation blocked: " << timer.elapsed();\r
- }\r
- \r
- auto self = shared_from_this(); // buffers can leave the device context, take a hold on life-time.\r
- return spl::shared_ptr<buffer>(buf.get(), [=](buffer*) mutable\r
- { \r
- texture_cache_.erase(buf.get());\r
- pool->push(buf);\r
- });\r
- }\r
-\r
- array<std::uint8_t> create_array(std::size_t size)\r
- { \r
- auto buf = create_buffer(size, buffer::usage::write_only);\r
- return array<std::uint8_t>(buf->data(), buf->size(), false, buf);\r
- }\r
-\r
- template<typename T>\r
- std::shared_ptr<buffer> copy_to_buf(const T& source)\r
- {\r
- std::shared_ptr<buffer> buf;\r
-\r
- auto tmp = source.storage<spl::shared_ptr<buffer>>();\r
- if(tmp)\r
- buf = *tmp;\r
- else\r
- { \r
- buf = create_buffer(source.size(), buffer::usage::write_only);\r
- tbb::parallel_for(tbb::blocked_range<std::size_t>(0, source.size()), [&](const tbb::blocked_range<std::size_t>& r)\r
- {\r
- A_memcpy(buf->data() + r.begin(), source.data() + r.begin(), r.size());\r
- });\r
- }\r
-\r
- return buf;\r
- }\r
-\r
- // TODO: Since the returned texture is cached it SHOULD NOT be modified.\r
- boost::unique_future<spl::shared_ptr<texture>> copy_async(const array<const std::uint8_t>& source, int width, int height, int stride)\r
- {\r
- std::shared_ptr<buffer> buf = copy_to_buf(source);\r
- \r
- return executor_.begin_invoke([=]() -> spl::shared_ptr<texture>\r
- {\r
- tbb::concurrent_hash_map<buffer*, std::shared_ptr<texture>>::const_accessor a;\r
- if(texture_cache_.find(a, buf.get()))\r
- return spl::make_shared_ptr(a->second);\r
-\r
- auto texture = create_texture(width, height, stride);\r
- texture->copy_from(*buf); \r
-\r
- texture_cache_.insert(std::make_pair(buf.get(), texture));\r
- \r
- return texture;\r
- }, task_priority::high_priority);\r
- }\r
- \r
- boost::unique_future<spl::shared_ptr<texture>> copy_async(const array<std::uint8_t>& source, int width, int height, int stride)\r
- {\r
- std::shared_ptr<buffer> buf = copy_to_buf(source);\r
-\r
- return executor_.begin_invoke([=]() -> spl::shared_ptr<texture>\r
- {\r
- auto texture = create_texture(width, height, stride, false);\r
- texture->copy_from(*buf); \r
- \r
- return texture;\r
- }, task_priority::high_priority);\r
- }\r
-\r
- boost::unique_future<array<const std::uint8_t>> copy_async(const spl::shared_ptr<texture>& source)\r
- {\r
- if(!executor_.is_current())\r
- CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Operation only valid in an OpenGL Context."));\r
-\r
- auto buffer = create_buffer(source->size(), buffer::usage::read_only); \r
- source->copy_to(*buffer); \r
-\r
- auto self = shared_from_this();\r
- return async(launch::deferred, [self, buffer]() mutable -> array<const std::uint8_t>\r
- {\r
- self->executor_.invoke(std::bind(&buffer::map, std::ref(buffer))); // Defer blocking "map" call until data is needed.\r
- return array<const std::uint8_t>(buffer->data(), buffer->size(), true, buffer);\r
- });\r
- }\r
-};\r
-\r
-device::device() \r
- : executor_(L"OpenGL Rendering Context")\r
- , impl_(new impl(executor_)){}\r
-device::~device(){}\r
-spl::shared_ptr<texture> device::create_texture(int width, int height, int stride){return impl_->create_texture(width, height, stride, true);}\r
-array<std::uint8_t> device::create_array(int size){return impl_->create_array(size);}\r
-boost::unique_future<spl::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);}\r
-boost::unique_future<spl::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);}\r
-boost::unique_future<array<const std::uint8_t>> device::copy_async(const spl::shared_ptr<texture>& source){return impl_->copy_async(source);}\r
-std::wstring device::version() const{return impl_->version();}\r
-\r
-\r
-}}}\r
-\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+// TODO: Smart GC
+
+#include "../../stdafx.h"
+
+#include "device.h"
+
+#include "buffer.h"
+#include "texture.h"
+#include "shader.h"
+
+#include <common/assert.h>
+#include <common/except.h>
+#include <common/future.h>
+#include <common/array.h>
+#include <common/gl/gl_check.h>
+#include <common/os/windows/windows.h>
+
+#include <boost/foreach.hpp>
+
+#include <gl/glew.h>
+
+#include <SFML/Window/Context.hpp>
+
+#include <tbb/concurrent_unordered_map.h>
+#include <tbb/concurrent_hash_map.h>
+#include <tbb/concurrent_queue.h>
+
+#include <boost/utility/declval.hpp>
+
+#include <array>
+#include <unordered_map>
+
+#include <asmlib.h>
+#include <tbb/parallel_for.h>
+
+namespace caspar { namespace accelerator { namespace ogl {
+
+struct device::impl : public std::enable_shared_from_this<impl>
+{
+ static_assert(std::is_same<decltype(boost::declval<device>().impl_), spl::shared_ptr<impl>>::value, "impl_ must be shared_ptr");
+
+ tbb::concurrent_hash_map<buffer*, std::shared_ptr<texture>> texture_cache_;
+
+ 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<buffer>>>, 2> host_pools_;
+
+ GLuint fbo_;
+
+ executor& executor_;
+
+ impl(executor& executor)
+ : executor_(executor)
+ {
+ executor_.set_capacity(256);
+
+ CASPAR_LOG(info) << L"Initializing OpenGL Device.";
+
+ executor_.invoke([=]
+ {
+ device_.reset(new sf::Context());
+ device_->SetActive(true);
+
+ if (glewInit() != GLEW_OK)
+ CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to initialize GLEW."));
+
+ if(!GLEW_VERSION_3_0)
+ CASPAR_THROW_EXCEPTION(not_supported() << msg_info("Your graphics card does not meet the minimum hardware requirements since it does not support OpenGL 3.0 or higher."));
+
+ glGenFramebuffers(1, &fbo_);
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
+ });
+
+ CASPAR_LOG(info) << L"Successfully initialized OpenGL " << version();
+ }
+
+ ~impl()
+ {
+ executor_.invoke([=]
+ {
+ BOOST_FOREACH(auto& pool, device_pools_)
+ pool.clear();
+ glDeleteFramebuffers(1, &fbo_);
+
+ device_.reset();
+ });
+ }
+
+ std::wstring version()
+ {
+ try
+ {
+ return executor_.invoke([]
+ {
+ return u16(reinterpret_cast<const char*>(GL2(glGetString(GL_VERSION)))) + L" " + u16(reinterpret_cast<const char*>(GL2(glGetString(GL_VENDOR))));
+ });
+ }
+ catch(...)
+ {
+ return L"Not found";;
+ }
+ }
+
+ spl::shared_ptr<texture> create_texture(int width, int height, int stride, bool clear = false)
+ {
+ CASPAR_VERIFY(stride > 0 && stride < 5);
+ CASPAR_VERIFY(width > 0 && height > 0);
+
+ 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)];
+
+ std::shared_ptr<texture> tex;
+ if(!pool->try_pop(tex))
+ tex = spl::make_shared<texture>(width, height, stride);
+
+ if(clear)
+ tex->clear();
+
+ return spl::shared_ptr<texture>(tex.get(), [tex, pool](texture*) mutable
+ {
+ pool->push(tex);
+ });
+ }
+
+ spl::shared_ptr<buffer> create_buffer(std::size_t size, buffer::usage usage)
+ {
+ CASPAR_VERIFY(size > 0);
+
+ auto pool = &host_pools_[usage.value()][size];
+
+ std::shared_ptr<buffer> buf;
+ if(!pool->try_pop(buf))
+ {
+ boost::timer timer;
+
+ buf = executor_.invoke([&]
+ {
+ return spl::make_shared<buffer>(size, usage);
+ }, task_priority::high_priority);
+
+ if(timer.elapsed() > 0.02)
+ 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.
+ return spl::shared_ptr<buffer>(buf.get(), [=](buffer*) mutable
+ {
+ texture_cache_.erase(buf.get());
+ pool->push(buf);
+ });
+ }
+
+ array<std::uint8_t> create_array(std::size_t size)
+ {
+ auto buf = create_buffer(size, buffer::usage::write_only);
+ return array<std::uint8_t>(buf->data(), buf->size(), false, buf);
+ }
+
+ template<typename T>
+ std::shared_ptr<buffer> copy_to_buf(const T& source)
+ {
+ std::shared_ptr<buffer> buf;
+
+ auto tmp = source.storage<spl::shared_ptr<buffer>>();
+ if(tmp)
+ buf = *tmp;
+ else
+ {
+ buf = create_buffer(source.size(), buffer::usage::write_only);
+ tbb::parallel_for(tbb::blocked_range<std::size_t>(0, source.size()), [&](const tbb::blocked_range<std::size_t>& r)
+ {
+ A_memcpy(buf->data() + r.begin(), source.data() + r.begin(), r.size());
+ });
+ }
+
+ return buf;
+ }
+
+ // TODO: Since the returned texture is cached it SHOULD NOT be modified.
+ boost::unique_future<spl::shared_ptr<texture>> copy_async(const array<const std::uint8_t>& source, int width, int height, int stride)
+ {
+ std::shared_ptr<buffer> buf = copy_to_buf(source);
+
+ return executor_.begin_invoke([=]() -> spl::shared_ptr<texture>
+ {
+ 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);
+
+ auto texture = create_texture(width, height, stride);
+ texture->copy_from(*buf);
+
+ texture_cache_.insert(std::make_pair(buf.get(), texture));
+
+ return texture;
+ }, task_priority::high_priority);
+ }
+
+ boost::unique_future<spl::shared_ptr<texture>> copy_async(const array<std::uint8_t>& source, int width, int height, int stride)
+ {
+ std::shared_ptr<buffer> buf = copy_to_buf(source);
+
+ return executor_.begin_invoke([=]() -> spl::shared_ptr<texture>
+ {
+ auto texture = create_texture(width, height, stride, false);
+ texture->copy_from(*buf);
+
+ return texture;
+ }, task_priority::high_priority);
+ }
+
+ boost::unique_future<array<const std::uint8_t>> copy_async(const spl::shared_ptr<texture>& source)
+ {
+ if(!executor_.is_current())
+ CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Operation only valid in an OpenGL Context."));
+
+ auto buffer = create_buffer(source->size(), buffer::usage::read_only);
+ source->copy_to(*buffer);
+
+ auto self = shared_from_this();
+ return async(launch::deferred, [self, buffer]() mutable -> array<const std::uint8_t>
+ {
+ self->executor_.invoke(std::bind(&buffer::map, std::ref(buffer))); // Defer blocking "map" call until data is needed.
+ return array<const std::uint8_t>(buffer->data(), buffer->size(), true, buffer);
+ });
+ }
+};
+
+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);}
+array<std::uint8_t> device::create_array(int size){return impl_->create_array(size);}
+boost::unique_future<spl::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);}
+boost::unique_future<spl::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);}
+boost::unique_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();}
+
+
+}}}
+
+