]> git.sesse.net Git - casparcg/blobdiff - accelerator/ogl/util/device.cpp
set svn:eol-style native on .h and .cpp files
[casparcg] / accelerator / ogl / util / device.cpp
index a4a1ffcd547d50663a36739e1390eb90967f2937..4dc5db8b0d79e0cf89f27d09e511a962c93ab0f0 100644 (file)
-/*\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();}
+
+
+}}}
+
+