]> git.sesse.net Git - casparcg/commitdiff
2.1.0: Added cpu accelerator.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 8 Feb 2012 12:04:19 +0000 (12:04 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 8 Feb 2012 12:04:19 +0000 (12:04 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.1.0@2300 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

19 files changed:
accelerator/accelerator.vcxproj
accelerator/accelerator.vcxproj.filters
accelerator/cpu/factory.cpp [new file with mode: 0644]
accelerator/cpu/factory.h [new file with mode: 0644]
accelerator/cpu/image/image_mixer.cpp
accelerator/cpu/image/image_mixer.h
accelerator/cpu/util/write_frame.cpp [new file with mode: 0644]
accelerator/cpu/util/write_frame.h [new file with mode: 0644]
accelerator/factory.h [new file with mode: 0644]
accelerator/ogl/factory.cpp [new file with mode: 0644]
accelerator/ogl/factory.h [new file with mode: 0644]
accelerator/ogl/image/image_mixer.cpp
accelerator/ogl/util/context.cpp
accelerator/ogl/util/write_frame.h
common/spl/memory.h
core/producer/stage.h
modules/screen/consumer/screen_consumer.cpp
shell/casparcg.config
shell/server.cpp

index 99fccbf70a5459a6ea9ec7b6e28270f129616f49..169ffd31aec9e36f7f2f884dfcf4346bce62fb4b 100644 (file)
@@ -75,6 +75,7 @@
       <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
       <FloatingPointModel>Fast</FloatingPointModel>\r
       <ForcedIncludeFiles>common/compiler/vs/disable_silly_warnings.h</ForcedIncludeFiles>\r
+      <ObjectFileName>$(IntDir)/%(RelativeDir)/</ObjectFileName>\r
     </ClCompile>\r
     <PostBuildEvent>\r
       <Command>\r
     </Lib>\r
   </ItemDefinitionGroup>\r
   <ItemGroup>\r
+    <ClInclude Include="cpu\factory.h" />\r
     <ClInclude Include="cpu\image\image_mixer.h" />\r
     <ClInclude Include="cpu\util\blend.h" />\r
     <ClInclude Include="cpu\util\simd.h" />\r
+    <ClInclude Include="cpu\util\write_frame.h" />\r
+    <ClInclude Include="factory.h" />\r
+    <ClInclude Include="ogl\factory.h" />\r
     <ClInclude Include="ogl\image\blending_glsl.h" />\r
     <ClInclude Include="ogl\image\image_kernel.h" />\r
     <ClInclude Include="ogl\image\image_mixer.h" />\r
     </ProjectReference>\r
   </ItemGroup>\r
   <ItemGroup>\r
+    <ClCompile Include="cpu\factory.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
     <ClCompile Include="cpu\image\image_mixer.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
+    <ClCompile Include="cpu\util\write_frame.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
+    <ClCompile Include="ogl\factory.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
     <ClCompile Include="ogl\image\image_kernel.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
index bd8b7b28296517ad08757abe97b9b9f88987c52c..e5a793e50a2c5589f11bfcd7bce156423e3fdbe7 100644 (file)
@@ -7,9 +7,6 @@
     <Filter Include="source\ogl">\r
       <UniqueIdentifier>{dbb5f22a-c188-4ab8-af04-3ec2b12d2e27}</UniqueIdentifier>\r
     </Filter>\r
-    <Filter Include="source\image">\r
-      <UniqueIdentifier>{1e686392-8f55-4919-8eee-026f3e8d2e9a}</UniqueIdentifier>\r
-    </Filter>\r
     <Filter Include="source\cpu">\r
       <UniqueIdentifier>{51a1672a-ca14-4c53-819d-ba8fbedc01da}</UniqueIdentifier>\r
     </Filter>\r
     <ClInclude Include="cpu\image\image_mixer.h">\r
       <Filter>source\cpu\image</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="cpu\util\write_frame.h">\r
+      <Filter>source\cpu\util</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="factory.h">\r
+      <Filter>source</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="cpu\factory.h">\r
+      <Filter>source\cpu</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="ogl\factory.h">\r
+      <Filter>source\ogl</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="StdAfx.cpp" />\r
     <ClCompile Include="cpu\image\image_mixer.cpp">\r
       <Filter>source\cpu\image</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="cpu\util\write_frame.cpp">\r
+      <Filter>source\cpu\util</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="cpu\factory.cpp">\r
+      <Filter>source\cpu</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="ogl\factory.cpp">\r
+      <Filter>source\ogl</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
diff --git a/accelerator/cpu/factory.cpp b/accelerator/cpu/factory.cpp
new file mode 100644 (file)
index 0000000..1bd3b61
--- /dev/null
@@ -0,0 +1,14 @@
+#include "../StdAfx.h"\r
+\r
+#include "factory.h"\r
+\r
+#include "image/image_mixer.h"\r
+\r
+namespace caspar { namespace accelerator { namespace cpu {\r
+       \r
+spl::shared_ptr<core::image_mixer> factory::create_image_mixer()\r
+{\r
+       return spl::shared_ptr<cpu::image_mixer>();\r
+}\r
+\r
+}}}
\ No newline at end of file
diff --git a/accelerator/cpu/factory.h b/accelerator/cpu/factory.h
new file mode 100644 (file)
index 0000000..b57c2de
--- /dev/null
@@ -0,0 +1,13 @@
+#pragma once\r
+\r
+#include "../factory.h"\r
+\r
+namespace caspar { namespace accelerator { namespace cpu {\r
+       \r
+class factory : public accelerator::factory\r
+{\r
+public:\r
+       virtual spl::shared_ptr<core::image_mixer> create_image_mixer() override;\r
+};\r
+\r
+}}}
\ No newline at end of file
index a8f0768e227cac1713ae18f864c1690486830de7..e13fc5f2eba7114fab194a8a3a461e1b045cc0e2 100644 (file)
@@ -1,7 +1,382 @@
-#include "../../StdAfx.h"\r
+/*\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
+#include "../../stdafx.h"\r
 \r
 #include "image_mixer.h"\r
 \r
+#include "../util/write_frame.h"\r
+\r
+#include <common/assert.h>\r
+#include <common/gl/gl_check.h>\r
+#include <common/concurrency/async.h>\r
+#include <common/memory/memcpy.h>\r
+\r
+#include <core/frame/write_frame.h>\r
+#include <core/frame/frame_transform.h>\r
+#include <core/frame/pixel_format.h>\r
+#include <core/video_format.h>\r
+\r
+#include <asmlib.h>\r
+\r
+#include <gl/glew.h>\r
+\r
+#include <tbb/cache_aligned_allocator.h>\r
+\r
+#include <boost/foreach.hpp>\r
+#include <boost/range.hpp>\r
+#include <boost/range/algorithm_ext/erase.hpp>\r
+#include <boost/thread/future.hpp>\r
+\r
+#include <algorithm>\r
+#include <vector>\r
+\r
 namespace caspar { namespace accelerator { namespace cpu {\r
+               \r
+struct item\r
+{\r
+       core::pixel_format_desc                                         pix_desc;\r
+       std::vector<spl::shared_ptr<host_buffer>>       buffers;\r
+       core::frame_transform                                           transform;\r
+\r
+       item()\r
+               : pix_desc(core::pixel_format::invalid)\r
+       {\r
+       }\r
+};\r
+\r
+bool operator==(const item& lhs, const item& rhs)\r
+{\r
+       return lhs.buffers == rhs.buffers && lhs.transform == rhs.transform;\r
+}\r
+\r
+bool operator!=(const item& lhs, const item& rhs)\r
+{\r
+       return !(lhs == rhs);\r
+}\r
+\r
+struct layer\r
+{\r
+       std::vector<item>       items;\r
+\r
+       layer()\r
+       {\r
+       }\r
+\r
+       layer(std::vector<item> items)\r
+               : items(std::move(items))\r
+       {\r
+       }\r
+};\r
+\r
+bool operator==(const layer& lhs, const layer& rhs)\r
+{\r
+       return lhs.items == rhs.items;\r
+}\r
+\r
+bool operator!=(const layer& lhs, const layer& rhs)\r
+{\r
+       return !(lhs == rhs);\r
+}\r
+\r
+class image_renderer\r
+{\r
+       std::pair<std::vector<layer>, boost::shared_future<boost::iterator_range<const uint8_t*>>> last_image_;\r
+public:\r
+       \r
+       boost::shared_future<boost::iterator_range<const uint8_t*>> operator()(std::vector<layer> layers, const core::video_format_desc& format_desc)\r
+       {       \r
+               if(last_image_.first == layers && last_image_.second.has_value())\r
+                       return last_image_.second;\r
+\r
+               auto image      = render(layers, format_desc);\r
+               last_image_ = std::make_pair(std::move(layers), image);\r
+               return image;\r
+       }\r
+\r
+private:       \r
+       boost::shared_future<boost::iterator_range<const uint8_t*>> render(std::vector<layer> layers, const core::video_format_desc& format_desc)\r
+       {       \r
+               static const auto empty = spl::make_shared<const std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>>>(2048*2048*4, 0);\r
+               CASPAR_VERIFY(empty->size() >= format_desc.size);\r
+               \r
+               if(layers.empty())\r
+               {\r
+                       return async(launch_policy::deferred, [=]\r
+                       {\r
+                               return boost::iterator_range<const uint8_t*>(empty->data(), empty->data() + format_desc.size);\r
+                       });\r
+               }\r
+               else if(layers.size()                           == 1 &&\r
+                           layers.at(0).items.size()   == 1 &&\r
+                           layers.at(0).items.at(0).pix_desc.format            == core::pixel_format::bgra &&\r
+                           layers.at(0).items.at(0).buffers.at(0)->size() == format_desc.size &&\r
+                           layers.at(0).items.at(0).transform                          == core::frame_transform())\r
+               {\r
+                       auto buffer = layers.at(0).items.at(0).buffers.at(0);\r
+                       return async(launch_policy::deferred, [=]\r
+                       {\r
+                               return boost::iterator_range<const uint8_t*>(buffer->data(), buffer->data() + format_desc.size);\r
+                       });\r
+               }\r
+               else\r
+               {\r
+                       return async(launch_policy::deferred, [=]\r
+                       {\r
+                               return boost::iterator_range<const uint8_t*>(empty->data(), empty->data() + format_desc.size);\r
+                       });\r
+               }\r
+               //else\r
+               //{                             \r
+                       //auto draw_buffer = create_mixer_buffer(4, format_desc);\r
+\r
+                       //if(format_desc.field_mode != core::field_mode::progressive)\r
+                       //{\r
+                       //      auto upper = layers;\r
+                       //      auto lower = std::move(layers);\r
+\r
+                       //      BOOST_FOREACH(auto& layer, upper)\r
+                       //      {\r
+                       //              BOOST_FOREACH(auto& item, layer.items)\r
+                       //                      item.transform.field_mode &= core::field_mode::upper;\r
+                       //      }\r
+\r
+                       //      BOOST_FOREACH(auto& layer, lower)\r
+                       //      {\r
+                       //              BOOST_FOREACH(auto& item, layer.items)\r
+                       //                      item.transform.field_mode &= core::field_mode::lower;\r
+                       //      }\r
+\r
+                       //      draw(std::move(upper), draw_buffer, format_desc);\r
+                       //      draw(std::move(lower), draw_buffer, format_desc);\r
+                       //}\r
+                       //else\r
+                       //{\r
+                       //      draw(std::move(layers), draw_buffer, format_desc);\r
+                       //}\r
+                       //                                              \r
+                       //return draw_buffer;\r
+               //}\r
+       }\r
+       \r
+       //void draw(std::vector<layer>&&                                layers, \r
+       //                spl::shared_ptr<device_buffer>&       draw_buffer, \r
+       //                const core::video_format_desc&        format_desc)\r
+       //{\r
+       //      std::shared_ptr<device_buffer> layer_key_buffer;\r
+\r
+       //      BOOST_FOREACH(auto& layer, layers)\r
+       //              draw_layer(std::move(layer), draw_buffer, layer_key_buffer, format_desc);\r
+       //}\r
+\r
+       //void draw_layer(layer&&                                                               layer, \r
+       //                              spl::shared_ptr<device_buffer>&         draw_buffer,\r
+       //                              std::shared_ptr<device_buffer>&         layer_key_buffer,\r
+       //                              const core::video_format_desc&          format_desc)\r
+       //{             \r
+       //      // Remove empty items.\r
+       //      boost::range::remove_erase_if(layer.items, [](const item& item)\r
+       //      {\r
+       //              return item.transform.field_mode == core::field_mode::empty;\r
+       //      });\r
+\r
+       //      if(layer.items.empty())\r
+       //              return;\r
+\r
+       //      std::shared_ptr<device_buffer> local_key_buffer;\r
+       //      std::shared_ptr<device_buffer> local_mix_buffer;\r
+       //                      \r
+       //      if(layer.blend_mode != core::blend_mode::normal)\r
+       //      {\r
+       //              auto layer_draw_buffer = create_mixer_buffer(4, format_desc);\r
+\r
+       //              BOOST_FOREACH(auto& item, layer.items)\r
+       //                      draw_item(std::move(item), layer_draw_buffer, layer_key_buffer, local_key_buffer, local_mix_buffer, format_desc);       \r
+       //      \r
+       //              draw_mixer_buffer(layer_draw_buffer, std::move(local_mix_buffer), core::blend_mode::normal);                                                    \r
+       //              draw_mixer_buffer(draw_buffer, std::move(layer_draw_buffer), layer.blend_mode);\r
+       //      }\r
+       //      else // fast path\r
+       //      {\r
+       //              BOOST_FOREACH(auto& item, layer.items)          \r
+       //                      draw_item(std::move(item), draw_buffer, layer_key_buffer, local_key_buffer, local_mix_buffer, format_desc);             \r
+       //                              \r
+       //              draw_mixer_buffer(draw_buffer, std::move(local_mix_buffer), core::blend_mode::normal);\r
+       //      }                                       \r
+\r
+       //      layer_key_buffer = std::move(local_key_buffer);\r
+       //}\r
+\r
+       //void draw_item(item&&                                                 item, \r
+       //                         spl::shared_ptr<device_buffer>&      draw_buffer, \r
+       //                         std::shared_ptr<device_buffer>&      layer_key_buffer, \r
+       //                         std::shared_ptr<device_buffer>&      local_key_buffer, \r
+       //                         std::shared_ptr<device_buffer>&      local_mix_buffer,\r
+       //                         const core::video_format_desc&       format_desc)\r
+       //{                     \r
+       //      draw_params draw_params;\r
+       //      draw_params.pix_desc    = std::move(item.pix_desc);\r
+       //      draw_params.transform   = std::move(item.transform);\r
+       //      BOOST_FOREACH(auto& future_texture, item.textures)\r
+       //              draw_params.textures.push_back(future_texture.get());\r
+\r
+       //      if(item.transform.is_key)\r
+       //      {\r
+       //              local_key_buffer = local_key_buffer ? local_key_buffer : create_mixer_buffer(1, format_desc);\r
+\r
+       //              draw_params.background                  = local_key_buffer;\r
+       //              draw_params.local_key                   = nullptr;\r
+       //              draw_params.layer_key                   = nullptr;\r
+\r
+       //              kernel_.draw(std::move(draw_params));\r
+       //      }\r
+       //      else if(item.transform.is_mix)\r
+       //      {\r
+       //              local_mix_buffer = local_mix_buffer ? local_mix_buffer : create_mixer_buffer(4, format_desc);\r
+\r
+       //              draw_params.background                  = local_mix_buffer;\r
+       //              draw_params.local_key                   = std::move(local_key_buffer);\r
+       //              draw_params.layer_key                   = layer_key_buffer;\r
+\r
+       //              draw_params.keyer                               = keyer::additive;\r
+\r
+       //              kernel_.draw(std::move(draw_params));\r
+       //      }\r
+       //      else\r
+       //      {\r
+       //              draw_mixer_buffer(draw_buffer, std::move(local_mix_buffer), core::blend_mode::normal);\r
+       //              \r
+       //              draw_params.background                  = draw_buffer;\r
+       //              draw_params.local_key                   = std::move(local_key_buffer);\r
+       //              draw_params.layer_key                   = layer_key_buffer;\r
+\r
+       //              kernel_.draw(std::move(draw_params));\r
+       //      }       \r
+       //}\r
+\r
+       //void draw_mixer_buffer(spl::shared_ptr<device_buffer>&        draw_buffer, \r
+       //                                         std::shared_ptr<device_buffer>&& source_buffer, \r
+       //                                         core::blend_mode                                     blend_mode = core::blend_mode::normal)\r
+       //{\r
+       //      if(!source_buffer)\r
+       //              return;\r
+\r
+       //      draw_params draw_params;\r
+       //      draw_params.pix_desc.format             = core::pixel_format::bgra;\r
+       //      draw_params.pix_desc.planes             = list_of(core::pixel_format_desc::plane(source_buffer->width(), source_buffer->height(), 4));\r
+       //      draw_params.textures                    = list_of(source_buffer);\r
+       //      draw_params.transform                   = core::frame_transform();\r
+       //      draw_params.blend_mode                  = blend_mode;\r
+       //      draw_params.background                  = draw_buffer;\r
+\r
+       //      kernel_.draw(std::move(draw_params));\r
+       //}\r
+       //              \r
+       //spl::shared_ptr<device_buffer> create_mixer_buffer(int stride, const core::video_format_desc& format_desc)\r
+       //{\r
+       //      auto buffer = ogl_->create_device_buffer(format_desc.width, format_desc.height, stride);\r
+       //      buffer->clear();\r
+       //      return buffer;\r
+       //}\r
+};\r
+               \r
+struct image_mixer::impl : boost::noncopyable\r
+{      \r
+       image_renderer                                          renderer_;\r
+       std::vector<core::frame_transform>      transform_stack_;\r
+       std::vector<layer>                                      layers_; // layer/stream/items\r
+public:\r
+       impl() \r
+               : transform_stack_(1)   \r
+       {\r
+               CASPAR_LOG(info) << L"Initialized CPU Accelerated Image Mixer";\r
+       }\r
+\r
+       void begin_layer(core::blend_mode blend_mode)\r
+       {\r
+               layers_.push_back(layer(std::vector<item>()));\r
+       }\r
+               \r
+       void push(core::frame_transform& transform)\r
+       {\r
+               transform_stack_.push_back(transform_stack_.back()*transform);\r
+       }\r
+               \r
+       void visit(core::data_frame& frame2)\r
+       {                       \r
+               write_frame* frame = dynamic_cast<write_frame*>(&frame2);\r
+               if(frame == nullptr)\r
+                       return;\r
+\r
+               if(frame->get_pixel_format_desc().format == core::pixel_format::invalid)\r
+                       return;\r
+\r
+               if(frame->get_buffers().empty())\r
+                       return;\r
+\r
+               if(transform_stack_.back().field_mode == core::field_mode::empty)\r
+                       return;\r
+\r
+               item item;\r
+               item.pix_desc                   = frame->get_pixel_format_desc();\r
+               item.buffers                    = frame->get_buffers();                         \r
+               item.transform                  = transform_stack_.back();\r
+               item.transform.volume   = core::frame_transform().volume; // Set volume to default since we don't care about it here.\r
+\r
+               layers_.back().items.push_back(item);\r
+       }\r
+\r
+       void pop()\r
+       {\r
+               transform_stack_.pop_back();\r
+       }\r
+\r
+       void end_layer()\r
+       {               \r
+       }\r
+       \r
+       boost::shared_future<boost::iterator_range<const uint8_t*>> render(const core::video_format_desc& format_desc)\r
+       {\r
+               // Remove empty layers.\r
+               boost::range::remove_erase_if(layers_, [](const layer& layer)\r
+               {\r
+                       return layer.items.empty();\r
+               });\r
+\r
+               return renderer_(std::move(layers_), format_desc);\r
+       }\r
+       \r
+       virtual spl::shared_ptr<cpu::write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc)\r
+       {\r
+               return spl::make_shared<cpu::write_frame>(tag, desc);\r
+       }\r
+};\r
+\r
+image_mixer::image_mixer() : impl_(new impl()){}\r
+void image_mixer::push(core::frame_transform& transform){impl_->push(transform);}\r
+void image_mixer::visit(core::data_frame& frame){impl_->visit(frame);}\r
+void image_mixer::pop(){impl_->pop();}\r
+boost::shared_future<boost::iterator_range<const uint8_t*>> image_mixer::operator()(const core::video_format_desc& format_desc){return impl_->render(format_desc);}\r
+void image_mixer::begin_layer(core::blend_mode blend_mode){impl_->begin_layer(blend_mode);}\r
+void image_mixer::end_layer(){impl_->end_layer();}\r
+spl::shared_ptr<core::write_frame> image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc) {return impl_->create_frame(tag, desc);}\r
 \r
 }}}
\ No newline at end of file
index 5ac79c8a807203fc74df029bd79e6e169f9c0126..d7706638ae89901583a7d3cb433ead196d46dd1c 100644 (file)
@@ -1,5 +1,42 @@
 #pragma once\r
 \r
+#include <common/forward.h>\r
+#include <common/spl/memory.h>\r
+\r
+#include <core/mixer/image/blend_modes.h>\r
+#include <core/mixer/image/image_mixer.h>\r
+\r
+#include <core/frame/frame_visitor.h>\r
+\r
+FORWARD1(boost, template<typename> class shared_future);\r
+FORWARD1(boost, template<typename> class iterator_range);\r
+FORWARD2(caspar, core, struct write_frame);\r
+FORWARD2(caspar, core, struct pixel_format_desc);\r
+FORWARD2(caspar, core, struct video_format_desc);\r
+FORWARD2(caspar, core, struct data_Frame);\r
+FORWARD2(caspar, core, struct frame_transform);\r
+\r
 namespace caspar { namespace accelerator { namespace cpu {\r
+       \r
+class image_mixer sealed : public core::image_mixer\r
+{\r
+public:\r
+       image_mixer();\r
+       \r
+       virtual void push(core::frame_transform& frame);\r
+       virtual void visit(core::data_frame& frame);\r
+       virtual void pop();\r
+\r
+       void begin_layer(core::blend_mode blend_mode);\r
+       void end_layer();\r
+               \r
+       // NOTE: Content of return future is only valid while future is valid.\r
+       virtual ::boost::shared_future<::boost::iterator_range<const uint8_t*>> operator()(const core::video_format_desc& format_desc) override;\r
+               \r
+       virtual spl::shared_ptr<core::write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc) override;\r
+private:\r
+       struct impl;\r
+       spl::shared_ptr<impl> impl_;\r
+};\r
 \r
 }}}
\ No newline at end of file
diff --git a/accelerator/cpu/util/write_frame.cpp b/accelerator/cpu/util/write_frame.cpp
new file mode 100644 (file)
index 0000000..1d3e83f
--- /dev/null
@@ -0,0 +1,95 @@
+/*\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
+#include "../../stdafx.h"\r
+\r
+#include "write_frame.h"\r
+\r
+#include <common/except.h>\r
+#include <core/frame/frame_visitor.h>\r
+#include <core/frame/pixel_format.h>\r
+\r
+#include <boost/lexical_cast.hpp>\r
+\r
+namespace caspar { namespace accelerator { namespace cpu {\r
+                       \r
+struct write_frame::impl : boost::noncopyable\r
+{                      \r
+       std::vector<spl::shared_ptr<host_buffer>>       buffers_;\r
+       core::audio_buffer                                                      audio_data_;\r
+       const core::pixel_format_desc                           desc_;\r
+       const void*                                                                     tag_;\r
+\r
+       impl(const void* tag)\r
+               : desc_(core::pixel_format::invalid)\r
+               , tag_(tag)             \r
+       {\r
+       }\r
+\r
+       impl(const void* tag, const core::pixel_format_desc& desc) \r
+               : desc_(desc)\r
+               , tag_(tag)\r
+       {\r
+               std::transform(desc.planes.begin(), desc.planes.end(), std::back_inserter(buffers_), [&](const core::pixel_format_desc::plane& plane)\r
+               {\r
+                       return spl::make_shared<host_buffer>(plane.size);\r
+               });\r
+       }\r
+                       \r
+       void accept(write_frame& self, core::frame_visitor& visitor)\r
+       {\r
+               visitor.push(self.get_frame_transform());\r
+               visitor.visit(self);\r
+               visitor.pop();\r
+       }\r
+\r
+       boost::iterator_range<uint8_t*> image_data(int index)\r
+       {\r
+               if(index >= buffers_.size() || !buffers_[index]->data())\r
+                       BOOST_THROW_EXCEPTION(out_of_range());\r
+               auto ptr = buffers_[index]->data();\r
+               return boost::iterator_range<uint8_t*>(ptr, ptr+buffers_[index]->size());\r
+       }\r
+};\r
+       \r
+write_frame::write_frame(const void* tag) : impl_(new impl(tag)){}\r
+write_frame::write_frame(const void* tag, const core::pixel_format_desc& desc) \r
+       : impl_(new impl(tag, desc)){}\r
+write_frame::write_frame(write_frame&& other) : impl_(std::move(other.impl_)){}\r
+write_frame& write_frame::operator=(write_frame&& other)\r
+{\r
+       impl_ = std::move(other.impl_);\r
+       return *this;\r
+}\r
+void write_frame::swap(write_frame& other){impl_.swap(other.impl_);}\r
+void write_frame::accept(core::frame_visitor& visitor){impl_->accept(*this, visitor);}\r
+const core::pixel_format_desc& write_frame::get_pixel_format_desc() const{return impl_->desc_;}\r
+const boost::iterator_range<const uint8_t*> write_frame::image_data(int index) const{return impl_->image_data(index);}\r
+const core::audio_buffer& write_frame::audio_data() const{return impl_->audio_data_;}\r
+const boost::iterator_range<uint8_t*> write_frame::image_data(int index){return impl_->image_data(index);}\r
+core::audio_buffer& write_frame::audio_data(){return impl_->audio_data_;}\r
+double write_frame::get_frame_rate() const{return 0.0;} // TODO: what's this?\r
+int write_frame::width() const{return impl_->desc_.planes.at(0).width;}\r
+int write_frame::height() const{return impl_->desc_.planes.at(0).height;}                                              \r
+const void* write_frame::tag() const{return impl_->tag_;}      \r
+std::vector<spl::shared_ptr<host_buffer>> write_frame::get_buffers(){return impl_->buffers_;}\r
+\r
+}}}
\ No newline at end of file
diff --git a/accelerator/cpu/util/write_frame.h b/accelerator/cpu/util/write_frame.h
new file mode 100644 (file)
index 0000000..163e399
--- /dev/null
@@ -0,0 +1,85 @@
+/*\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
+#pragma once\r
+\r
+#include <common/spl/memory.h>\r
+#include <common/forward.h>\r
+\r
+#include <core/frame/write_frame.h>\r
+#include <core/video_format.h>\r
+#include <core/mixer/audio/audio_mixer.h>\r
+\r
+#include <boost/range/iterator_range.hpp>\r
+\r
+#include <stdint.h>\r
+#include <vector>\r
+\r
+FORWARD2(caspar, core, struct frame_visitor);\r
+FORWARD2(caspar, core, struct pixel_format_desc);\r
+\r
+typedef std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>> host_buffer;\r
+\r
+namespace caspar { namespace accelerator { namespace cpu {\r
+       \r
+class write_frame sealed : public core::write_frame\r
+{\r
+       write_frame(const write_frame&);\r
+       write_frame& operator=(const write_frame);\r
+public:        \r
+       explicit write_frame(const void* tag);\r
+       explicit write_frame(const void* tag, const core::pixel_format_desc& desc);\r
+\r
+       write_frame(write_frame&& other);\r
+       write_frame& operator=(write_frame&& other);\r
+\r
+       void swap(write_frame& other);\r
+                       \r
+       // draw_frame\r
+\r
+       virtual void accept(core::frame_visitor& visitor) override;\r
+\r
+       // data_frame\r
+               \r
+       virtual const core::pixel_format_desc& get_pixel_format_desc() const override;\r
+\r
+       virtual const boost::iterator_range<const uint8_t*> image_data(int index) const override;\r
+       virtual const core::audio_buffer& audio_data() const override;\r
+\r
+       virtual const boost::iterator_range<uint8_t*> image_data(int index) override;\r
+       virtual core::audio_buffer& audio_data() override;\r
+       \r
+       virtual double get_frame_rate() const override;\r
+\r
+       virtual int width() const override;\r
+       virtual int height() const override;\r
+                                                               \r
+       virtual const void* tag() const override;       \r
+\r
+       // write_frames\r
+\r
+       std::vector<spl::shared_ptr<host_buffer>> get_buffers();                \r
+private:\r
+       struct impl;\r
+       spl::shared_ptr<impl> impl_;\r
+};\r
+\r
+}}}
\ No newline at end of file
diff --git a/accelerator/factory.h b/accelerator/factory.h
new file mode 100644 (file)
index 0000000..c3b9f14
--- /dev/null
@@ -0,0 +1,17 @@
+#pragma once\r
+\r
+#include <common/forward.h>\r
+#include <common/spl/memory.h>\r
+\r
+#include <boost/noncopyable.hpp>\r
+\r
+FORWARD2(caspar, core, struct image_mixer);\r
+\r
+namespace caspar { namespace accelerator {\r
+       \r
+struct factory : boost::noncopyable\r
+{\r
+       virtual spl::shared_ptr<core::image_mixer> create_image_mixer() = 0;\r
+};\r
+\r
+}}
\ No newline at end of file
diff --git a/accelerator/ogl/factory.cpp b/accelerator/ogl/factory.cpp
new file mode 100644 (file)
index 0000000..54322d3
--- /dev/null
@@ -0,0 +1,23 @@
+#include "../StdAfx.h"\r
+\r
+#include "factory.h"\r
+\r
+#include "image/image_mixer.h"\r
+#include "util/context.h"\r
+\r
+namespace caspar { namespace accelerator { namespace ogl {\r
+       \r
+struct factory::impl\r
+{\r
+       spl::shared_ptr<context> ogl_;\r
+       \r
+       spl::shared_ptr<core::image_mixer> create_image_mixer()\r
+       {\r
+               return spl::make_shared<ogl::image_mixer>(ogl_);\r
+       }\r
+};\r
+\r
+factory::factory(){}\r
+spl::shared_ptr<core::image_mixer> factory::create_image_mixer(){return impl_->create_image_mixer();}\r
+\r
+}}}
\ No newline at end of file
diff --git a/accelerator/ogl/factory.h b/accelerator/ogl/factory.h
new file mode 100644 (file)
index 0000000..65e7447
--- /dev/null
@@ -0,0 +1,20 @@
+#pragma once\r
+\r
+#include "../factory.h"\r
+\r
+#include <common/spl/memory.h>\r
+\r
+namespace caspar { namespace accelerator { namespace ogl {\r
+       \r
+class factory : public accelerator::factory\r
+{\r
+public:\r
+       factory();\r
+\r
+       virtual spl::shared_ptr<core::image_mixer> create_image_mixer() override;\r
+private:\r
+       struct impl;\r
+       spl::shared_ptr<impl> impl_;\r
+};\r
+\r
+}}}
\ No newline at end of file
index 743f4322bab2edad4185513972807d161d29be92..d243d611af22376bd2b6c422f6fd1fec6f8ed4bd 100644 (file)
@@ -117,6 +117,7 @@ public:
                : ogl_(ogl)\r
                , kernel_(ogl_)\r
        {\r
+               CASPAR_LOG(info) << L"Initialized OpenGL GPU Accelerated Image Mixer";\r
        }\r
        \r
        boost::shared_future<boost::iterator_range<const uint8_t*>> operator()(std::vector<layer> layers, const core::video_format_desc& format_desc)\r
index f7c2a7a35d7aa228f99d4c2a0182f633f3184ed5..32163eef3cf25006a0d207d620fa2e94964cb253 100644 (file)
@@ -44,6 +44,9 @@
 \r
 #include <tbb/concurrent_unordered_map.h>\r
 #include <tbb/concurrent_queue.h>\r
+#include <tbb/atomic.h>\r
+\r
+tbb::atomic<int> g_count = tbb::atomic<int>();\r
 \r
 namespace caspar { namespace accelerator { namespace ogl {\r
                \r
@@ -64,6 +67,9 @@ struct context::impl : public std::enable_shared_from_this<impl>
                : executor_(executor)\r
                , host_alloc_executor_(L"OpenGL allocation context")\r
        {\r
+               if(g_count++ > 1)\r
+                       CASPAR_LOG(warning) << L"Multiple OGL contexts.";\r
+\r
                CASPAR_LOG(info) << L"Initializing OpenGL Device.";\r
                \r
                auto ctx1 = executor_.invoke([=]() -> HGLRC \r
index eb8566782bd0b29d1efb60dbe3dda8b9deee072e..b79bf7f5bdf2ae507df72e1d6ed970d19dd844e3 100644 (file)
@@ -21,8 +21,6 @@
 \r
 #pragma once\r
 \r
-#include "context.h"\r
-\r
 #include <common/spl/memory.h>\r
 #include <common/forward.h>\r
 \r
 #include <core/video_format.h>\r
 #include <core/mixer/audio/audio_mixer.h>\r
 \r
-#include <boost/range/iterator_range.hpp>\r
-\r
 #include <stdint.h>\r
 #include <vector>\r
 \r
+FORWARD1(boost, template <typename> class iterator_range);\r
 FORWARD2(caspar, core, struct frame_visitor);\r
 FORWARD2(caspar, core, struct pixel_format_desc);\r
 \r
index aadd39426186528072b7c6d591d967c5fdf8848e..f03343e1601469af5ab2745d6c678a4099c119f9 100644 (file)
@@ -411,9 +411,15 @@ public:
     typedef D deleter_type;\r
 \r
     unique_ptr()\r
-               : p_(new t())\r
+               : p_(new T())\r
        {\r
        }\r
+       \r
+    template<typename T2, typename D2>    \r
+    unique_ptr(unique_ptr<T2, D2>&& p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) \r
+        : p_(std::move(p))\r
+    {\r
+    }\r
                        \r
     template<typename T2, typename D2>    \r
     explicit unique_ptr(std::unique_ptr<T2, D2>&& p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) \r
@@ -439,12 +445,12 @@ public:
             throw std::invalid_argument("p");\r
     }\r
 \r
-    unique_ptr<T> operator=(unique_ptr&& other)\r
+    unique_ptr<T>& operator=(unique_ptr&& other)\r
     {\r
         other.swap(*this);\r
         return *this;\r
     }\r
-                       \r
+                               \r
     T& operator*() const \r
     { \r
         return *p_.get();\r
@@ -464,13 +470,7 @@ public:
     { \r
         p_.swap(other.p_); \r
     } \r
-\r
-       template<typename T2>\r
-    operator std::unique_ptr<T2>() const \r
-    { \r
-        return p_;\r
-    }\r
-\r
+       \r
     template<class D, class T2> \r
     D* get_deleter(shared_ptr<T2> const& ptr) \r
     { \r
index 681372a2dc62643f091355af964b95bfaee37c10..02d70467905a525eefaef46924f0be652925b9f1 100644 (file)
@@ -27,6 +27,7 @@
 #include <common/spl/memory.h>\r
 #include <common/tweener.h>\r
 \r
+#include <boost/optional.hpp>\r
 #include <boost/property_tree/ptree_fwd.hpp>\r
 \r
 #include <functional>\r
index af434adc6cd735a22bf5a567e361ba89cc3135f8..e6256557e0c678b8235c7bb9a29d95fd9b4a508d 100644 (file)
@@ -203,14 +203,17 @@ public:
 \r
        void init()\r
        {\r
-               if(!GLEW_VERSION_2_1)\r
-                       BOOST_THROW_EXCEPTION(not_supported() << msg_info("Missing OpenGL 2.1 support."));\r
-\r
                window_.Create(sf::VideoMode(screen_width_, screen_height_, 32), u8(print()), config_.windowed ? sf::Style::Resize | sf::Style::Close : sf::Style::Fullscreen);\r
                window_.ShowMouseCursor(false);\r
                window_.SetPosition(screen_x_, screen_y_);\r
                window_.SetSize(screen_width_, screen_height_);\r
                window_.SetActive();\r
+               \r
+               if(!GLEW_VERSION_2_1 && glewInit() != GLEW_OK)\r
+                       BOOST_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to initialize GLEW."));\r
+\r
+               if(!GLEW_VERSION_2_1)\r
+                       BOOST_THROW_EXCEPTION(not_supported() << msg_info("Missing OpenGL 2.1 support."));\r
 \r
                GL(glEnable(GL_TEXTURE_2D));\r
                GL(glDisable(GL_DEPTH_TEST));           \r
index b68d52946701e622032db43d60d9a8e288beb6a5..38f79444f0d60d7bb45b7013dd87b846a01fb097 100644 (file)
@@ -6,11 +6,12 @@
     <data-path>D:\casparcg\_data\</data-path>\r
     <template-path>D:\casparcg\_templates\</template-path>\r
   </paths>\r
+  <accelerator>cpu</accelerator>\r
   <blend-modes>true</blend-modes>\r
   <log-level>trace</log-level>\r
   <channels>\r
     <channel>\r
-      <video-mode>1080i5000</video-mode>\r
+      <video-mode>720p5000</video-mode>\r
       <consumers>\r
         <screen>\r
         </screen>\r
@@ -30,6 +31,7 @@
 <blend-modes>false [true|false]</blend-modes>\r
 <auto-transcode>true [true|false]</auto-transcode>\r
 <pipeline-tokens>2 [1..]</pipeline-tokens>\r
+<accelerator>auto [cpu|gpu|auto]</accelerator>\r
 <template-hosts>\r
   <template-host>\r
     <video-mode/>\r
index 6bddb2528807f096e075933131323e6f99192ae1..e05fea63ff8d9ef49cc88398fc3ace5cb5eb9683 100644 (file)
@@ -22,8 +22,9 @@
 \r
 #include "server.h"\r
 \r
-#include <accelerator/ogl/util/context.h>\r
-#include <accelerator/ogl/image/image_mixer.h>\r
+#include <accelerator/factory.h>\r
+#include <accelerator/ogl/factory.h>\r
+#include <accelerator/cpu/factory.h>\r
 \r
 #include <common/env.h>\r
 #include <common/except.h>\r
@@ -66,12 +67,30 @@ using namespace protocol;
 \r
 struct server::impl : boost::noncopyable\r
 {\r
-       spl::shared_ptr<accelerator::ogl::context>                      ogl_;\r
+       std::unique_ptr<accelerator::factory>                           accel_factory_;\r
        std::vector<spl::shared_ptr<IO::AsyncEventServer>>      async_servers_; \r
        std::vector<spl::shared_ptr<video_channel>>                     channels_;\r
 \r
        impl()          \r
-       {                       \r
+       {       \r
+               auto accel_str = env::properties().get(L"configuration.accelerator", L"auto");\r
+\r
+               if(accel_str == L"cpu")\r
+                       accel_factory_.reset(new accelerator::cpu::factory());\r
+               else\r
+               {\r
+                       try\r
+                       {\r
+                               accel_factory_.reset(new accelerator::ogl::factory());\r
+                       }\r
+                       catch(...)\r
+                       {\r
+                               CASPAR_LOG_CURRENT_EXCEPTION();\r
+                               accel_factory_.reset(new accelerator::cpu::factory());\r
+                               CASPAR_LOG(warning) << L"Using fallback CPU mixer.";\r
+                       }\r
+               }\r
+\r
                ffmpeg::init();\r
                CASPAR_LOG(info) << L"Initialized ffmpeg module.";\r
                                                          \r
@@ -118,7 +137,7 @@ struct server::impl : boost::noncopyable
                        if(format_desc.format == video_format::invalid)\r
                                BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Invalid video-mode."));\r
                        \r
-                       channels_.push_back(spl::make_shared<video_channel>(static_cast<int>(channels_.size()+1), format_desc, spl::make_shared<accelerator::ogl::image_mixer>(ogl_)));\r
+                       channels_.push_back(spl::make_shared<video_channel>(static_cast<int>(channels_.size()+1), format_desc, accel_factory_->create_image_mixer()));\r
                        \r
                        BOOST_FOREACH(auto& xml_consumer, xml_channel.second.get_child(L"consumers"))\r
                        {\r
@@ -147,7 +166,7 @@ struct server::impl : boost::noncopyable
 \r
                // Dummy diagnostics channel\r
                if(env::properties().get(L"configuration.channel-grid", false))\r
-                       channels_.push_back(spl::make_shared<video_channel>(static_cast<int>(channels_.size()+1), core::video_format_desc(core::video_format::x576p2500), spl::make_shared<accelerator::ogl::image_mixer>(ogl_)));\r
+                       channels_.push_back(spl::make_shared<video_channel>(static_cast<int>(channels_.size()+1), core::video_format_desc(core::video_format::x576p2500), accel_factory_->create_image_mixer()));\r
        }\r
                \r
        void setup_controllers(const boost::property_tree::wptree& pt)\r