]> git.sesse.net Git - casparcg/commitdiff
2.0.0.2:
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Fri, 5 Nov 2010 15:29:39 +0000 (15:29 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Fri, 5 Nov 2010 15:29:39 +0000 (15:29 +0000)
- Refactoring.
- Started creating some test for transition_producer.

git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@230 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

27 files changed:
common/common.vcxproj
common/common.vcxproj.filters
common/gl/frame_buffer_object.cpp [new file with mode: 0644]
common/gl/frame_buffer_object.h [new file with mode: 0644]
common/gl/pixel_buffer_object.cpp [new file with mode: 0644]
common/gl/pixel_buffer_object.h [new file with mode: 0644]
common/utility/memory.cpp
common/utility/memory.h
core/consumer/decklink/DecklinkVideoConsumer.cpp
core/consumer/ogl/ogl_consumer.cpp
core/frame/gpu_composite_frame.cpp
core/frame/gpu_composite_frame.h
core/frame/gpu_frame.cpp
core/frame/gpu_frame.h
core/frame/gpu_frame_processor.cpp
core/producer/color/color_producer.cpp
core/producer/flash/flash_producer.cpp
core/producer/image/image_producer.cpp
core/producer/image/image_scroll_producer.cpp
core/producer/transition/transition_producer.cpp
shell/caspar.config
test/mock/mock_frame.h [new file with mode: 0644]
test/mock/mock_frame_factory.h [new file with mode: 0644]
test/mock/mock_frame_producer.h
test/producer/transition/transition_producer_test.cpp [new file with mode: 0644]
test/test.vcxproj
test/test.vcxproj.filters

index 8d1421d3a692dfd725ca061f90b534ac5185ef87..347e08e8d0908a661af536cf84871d5d3deb3055 100644 (file)
@@ -97,7 +97,9 @@
     <ClInclude Include="config.h" />\r
     <ClInclude Include="exception\exceptions.h" />\r
     <ClInclude Include="exception\win32_exception.h" />\r
+    <ClInclude Include="gl\frame_buffer_object.h" />\r
     <ClInclude Include="gl\gl_check.h" />\r
+    <ClInclude Include="gl\pixel_buffer_object.h" />\r
     <ClInclude Include="io\AsyncEventServer.h" />\r
     <ClInclude Include="io\ClientInfo.h" />\r
     <ClInclude Include="io\ProtocolStrategy.h" />\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
+    <ClCompile Include="gl\frame_buffer_object.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
+    <ClCompile Include="gl\pixel_buffer_object.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
     <ClCompile Include="io\AsyncEventServer.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
index 4c4210e22e92d82b046d25d8236dd5a80e7c925c..ea6f5f56de4be552fec563678d6664d3afa485f4 100644 (file)
     <ClCompile Include="utility\memory.cpp">\r
       <Filter>Source\utility</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="gl\frame_buffer_object.cpp">\r
+      <Filter>Source\gl</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="gl\pixel_buffer_object.cpp">\r
+      <Filter>Source\gl</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="stdafx.h">\r
     <ClInclude Include="gl\gl_check.h">\r
       <Filter>Source\gl</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="gl\pixel_buffer_object.h">\r
+      <Filter>Source\gl</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="gl\frame_buffer_object.h">\r
+      <Filter>Source\gl</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
diff --git a/common/gl/frame_buffer_object.cpp b/common/gl/frame_buffer_object.cpp
new file mode 100644 (file)
index 0000000..403d6bf
--- /dev/null
@@ -0,0 +1,54 @@
+#include "../StdAfx.h"\r
+\r
+#include "frame_buffer_object.h"\r
+\r
+#include "../../common/gl/gl_check.h"\r
+\r
+#include <Glee.h>\r
+\r
+#include <memory>\r
+\r
+namespace caspar { namespace common { namespace gl {\r
+\r
+struct frame_buffer_object::implementation\r
+{\r
+public:\r
+       implementation(size_t width, size_t height, GLenum mode) : mode_(mode)\r
+       {\r
+               GL(glGenTextures(1, &texture_));        \r
+               GL(glBindTexture(GL_TEXTURE_2D, texture_));                     \r
+               GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, \r
+                                                       GL_UNSIGNED_BYTE, NULL));\r
+               GL(glGenFramebuffersEXT(1, &fbo_));             \r
+               GL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_));\r
+               GL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, mode_, GL_TEXTURE_2D, \r
+                                                                               texture_, 0));\r
+       }\r
+       \r
+       ~implementation()\r
+       {\r
+               glDeleteFramebuffersEXT(1, &fbo_);\r
+               glDeleteTextures(1, &texture_);\r
+       }\r
+\r
+       void bind_pixel_source()\r
+       {\r
+               GL(glReadBuffer(mode_));\r
+       }\r
+\r
+       GLuint texture_;\r
+       GLuint fbo_;\r
+       GLenum mode_;\r
+       size_t width_;\r
+       size_t height_;\r
+};\r
+\r
+frame_buffer_object::frame_buffer_object(){}\r
+frame_buffer_object::frame_buffer_object(size_t width, size_t height, GLenum mode)\r
+       : impl_(new implementation(width, height, mode)){}\r
+void frame_buffer_object::create(size_t width, size_t height, GLenum mode)\r
+{\r
+       impl_.reset(new implementation(width, height, mode));\r
+}\r
+void frame_buffer_object::bind_pixel_source() {impl_->bind_pixel_source();}\r
+}}}
\ No newline at end of file
diff --git a/common/gl/frame_buffer_object.h b/common/gl/frame_buffer_object.h
new file mode 100644 (file)
index 0000000..8859927
--- /dev/null
@@ -0,0 +1,21 @@
+#pragma once\r
+\r
+#include <Glee.h>\r
+\r
+#include <memory>\r
+\r
+namespace caspar { namespace common { namespace gl {\r
+\r
+class frame_buffer_object\r
+{\r
+public:\r
+       frame_buffer_object();\r
+       frame_buffer_object(size_t width, size_t height, GLenum mode = GL_COLOR_ATTACHMENT0_EXT);\r
+       void create(size_t width, size_t height, GLenum mode = GL_COLOR_ATTACHMENT0_EXT);\r
+       void bind_pixel_source();\r
+private:\r
+       struct implementation;\r
+       std::shared_ptr<implementation> impl_;\r
+};\r
+\r
+}}}
\ No newline at end of file
diff --git a/common/gl/pixel_buffer_object.cpp b/common/gl/pixel_buffer_object.cpp
new file mode 100644 (file)
index 0000000..e3e6b7a
--- /dev/null
@@ -0,0 +1,140 @@
+#include "../StdAfx.h"\r
+\r
+#include "pixel_buffer_object.h"\r
+\r
+#include "../../common/exception/exceptions.h"\r
+#include "../../common/gl/gl_check.h"\r
+#include "../../common/utility/memory.h"\r
+\r
+namespace caspar { namespace common { namespace gl {\r
+                                                                                                                                                                                                                                                                                                                       \r
+struct pixel_buffer_object::implementation : boost::noncopyable\r
+{\r
+       implementation(size_t width, size_t height) \r
+               : width_(width), height_(height), size_(width*height*4), pbo_(0),\r
+                       texture_(0), writing_(false), reading_(false), mapped_(false){}\r
+\r
+       ~implementation()\r
+       {\r
+               if(pbo_ != 0)\r
+                       glDeleteBuffers(1, &pbo_);\r
+       }       \r
+\r
+       void bind_pbo(GLenum mode)\r
+       {\r
+               if(pbo_ == 0)\r
+                       GL(glGenBuffers(1, &pbo_));\r
+               GL(glBindBuffer(mode, pbo_));\r
+       }\r
+\r
+       void unbind_pbo(GLenum mode)\r
+       {\r
+               GL(glBindBuffer(mode, 0));\r
+       }\r
+       \r
+       void bind_texture()\r
+       {\r
+               if(texture_ == 0)\r
+               {\r
+                       GL(glGenTextures(1, &texture_));\r
+\r
+                       GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
+\r
+                       GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));\r
+                       GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));\r
+                       GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));\r
+                       GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));\r
+\r
+                       GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width_, height_, 0, GL_BGRA, \r
+                                                               GL_UNSIGNED_BYTE, NULL));\r
+               }\r
+               GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
+       }\r
+\r
+       void begin_write()\r
+       {\r
+               bind_pbo(GL_PIXEL_UNPACK_BUFFER);\r
+               if(mapped_)\r
+                       GL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));\r
+               mapped_ = false;\r
+               bind_texture();\r
+               GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA, \r
+                                                       GL_UNSIGNED_BYTE, NULL));\r
+               unbind_pbo(GL_PIXEL_UNPACK_BUFFER);\r
+               writing_ = true;\r
+       }\r
+\r
+       void* end_write()\r
+       {\r
+               if(mapped_)\r
+                       BOOST_THROW_EXCEPTION(invalid_operation());\r
+\r
+               bind_pbo(GL_PIXEL_UNPACK_BUFFER);\r
+               GL(glBufferData(GL_PIXEL_UNPACK_BUFFER, size_, NULL, GL_STREAM_DRAW));\r
+               auto data = static_cast<unsigned char*>(glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));\r
+               unbind_pbo(GL_PIXEL_UNPACK_BUFFER);             \r
+               if(!data)\r
+                       BOOST_THROW_EXCEPTION(invalid_operation() \r
+                                                                       << msg_info("glMapBuffer failed"));\r
+               writing_ = false;\r
+               mapped_ = true;\r
+               return data;\r
+       }\r
+       \r
+       void begin_read()\r
+       {       \r
+               bind_pbo(GL_PIXEL_PACK_BUFFER);\r
+               if(mapped_)\r
+                       GL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));        \r
+               mapped_ = false;\r
+               GL(glBufferData(GL_PIXEL_PACK_BUFFER, size_, NULL, GL_STREAM_READ));    \r
+               GL(glReadPixels(0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
+               unbind_pbo(GL_PIXEL_PACK_BUFFER);\r
+               reading_ = true;\r
+       }\r
+\r
+       void* end_read()\r
+       {\r
+               if(mapped_)\r
+                       BOOST_THROW_EXCEPTION(invalid_operation());\r
+\r
+               bind_pbo(GL_PIXEL_PACK_BUFFER);\r
+               auto data = static_cast<unsigned char*>(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY));   \r
+               unbind_pbo(GL_PIXEL_PACK_BUFFER);\r
+               if(!data)\r
+                       BOOST_THROW_EXCEPTION(std::bad_alloc());\r
+               reading_ = false;\r
+               mapped_ = true;\r
+               return data;\r
+       }\r
+\r
+       \r
+       GLuint pbo_;\r
+       GLuint texture_;\r
+       size_t width_;\r
+       size_t height_;\r
+       size_t size_;\r
+\r
+       bool mapped_;\r
+       bool writing_;\r
+       bool reading_;\r
+};\r
+\r
+pixel_buffer_object::pixel_buffer_object(){}\r
+pixel_buffer_object::pixel_buffer_object(size_t width, size_t height) \r
+       : impl_(new implementation(width, height)){}\r
+void pixel_buffer_object::create(size_t width, size_t height)\r
+{\r
+       impl_.reset(new implementation(width, height));\r
+}\r
+void pixel_buffer_object::begin_write() { impl_->begin_write();}\r
+void* pixel_buffer_object::end_write() {return impl_->end_write();} \r
+void pixel_buffer_object::begin_read() { impl_->begin_read();}\r
+void* pixel_buffer_object::end_read(){return impl_->end_read();}\r
+void pixel_buffer_object::bind_texture() {impl_->bind_texture();}\r
+size_t pixel_buffer_object::width() const {return impl_->width_;}\r
+size_t pixel_buffer_object::heigth() const {return impl_->height_;}\r
+size_t pixel_buffer_object::size() const {return impl_->size_;}\r
+bool pixel_buffer_object::is_reading() const { return impl_->reading_;}\r
+bool pixel_buffer_object::is_writing() const { return impl_->writing_;}\r
+}}}
\ No newline at end of file
diff --git a/common/gl/pixel_buffer_object.h b/common/gl/pixel_buffer_object.h
new file mode 100644 (file)
index 0000000..858c244
--- /dev/null
@@ -0,0 +1,43 @@
+#pragma once\r
+\r
+#include <memory>\r
+\r
+#include <boost/noncopyable.hpp>\r
+\r
+#include <Glee.h>\r
+\r
+#include <boost/tuple/tuple.hpp>\r
+#include <boost/thread/future.hpp>\r
+\r
+namespace caspar { namespace common { namespace gl {\r
+       \r
+class pixel_buffer_object : boost::noncopyable\r
+{\r
+public:\r
+       pixel_buffer_object();\r
+       pixel_buffer_object(size_t width, size_t height);\r
+       void create(size_t width, size_t height);\r
+       ~pixel_buffer_object(){}\r
+\r
+       void begin_write();\r
+       void* end_write();\r
+\r
+       void begin_read();\r
+       void* end_read();\r
+\r
+       void bind_texture();\r
+\r
+       size_t width() const;\r
+       size_t heigth() const;\r
+       size_t size() const;\r
+\r
+       bool is_reading() const;\r
+       bool is_writing() const;\r
+               \r
+private:\r
+       struct implementation;\r
+       std::shared_ptr<implementation> impl_;\r
+};\r
+typedef std::shared_ptr<pixel_buffer_object> pixel_buffer_object_ptr;\r
+       \r
+}}}
\ No newline at end of file
index 0be280d318873aea14f9f0a3044c833adf2cb3e4..7f6d38391e265849d1a958886a9efc94f524b455 100644 (file)
@@ -53,8 +53,11 @@ void* memcpy_SSE2(void* dest, const void* source, size_t num)
        return dest;\r
 }\r
 \r
-void* copy(void* dest, const void* source, size_t num)\r
+void* aligned_memcpy(void* dest, const void* source, size_t num)\r
 {      \r
+       if(num < 128)\r
+               return memcpy(dest, source, num);\r
+\r
        tbb::parallel_for(tbb::blocked_range<size_t>(0, num/128), [&](const tbb::blocked_range<size_t>& r)\r
        {\r
                memcpy_SSE2(reinterpret_cast<char*>(dest) + r.begin()*128, reinterpret_cast<const char*>(source) + r.begin()*128, r.size()*128);\r
index 6c9b7671f4b2f158db7ab7f229117cdcba4b3a91..56ff5a17a16c3f2e48af0400c295468e4231a73d 100644 (file)
@@ -2,7 +2,7 @@
 \r
 namespace caspar { namespace common {\r
                \r
-void* copy(void* dest, const void* source, size_t size);\r
+void* aligned_memcpy(void* dest, const void* source, size_t size);\r
 void* clear(void* dest, size_t size);\r
 \r
 }}
\ No newline at end of file
index bdff0d80ecdfdc76e1d80d87c57b42d23ec970ea..36de5f8e0f14fb823a8b3ceb1ea4714f426d8847 100644 (file)
@@ -129,7 +129,7 @@ struct DecklinkVideoConsumer::Implementation : public IDeckLinkVideoOutputCallba
                                std::shared_ptr<DecklinkVideoFrame> pTempFrame = GetReservedFrame();\r
                                if(pTempFrame && frame->size() == pTempFrame->size())\r
                                {\r
-                                       common::copy(pTempFrame->data(), frame->data(), pTempFrame->size());\r
+                                       common::aligned_memcpy(pTempFrame->data(), frame->data(), pTempFrame->size());\r
                                        DoRender(pTempFrame);\r
                                }\r
                                else\r
index 968d25fc7953f8f5cf6af0bd518a060f9da9233a..f6396ee932b81839eef8e5b55331e8743bbc6df6 100644 (file)
 #include "../../frame/gpu_frame.h"\r
 #include "../../../common/utility/memory.h"\r
 #include "../../../common/gl/gl_check.h"\r
+#include "../../../common/gl/pixel_buffer_object.h"\r
 \r
 #include <boost/thread.hpp>\r
 \r
 #include <Glee.h>\r
 #include <SFML/Window.hpp>\r
-#include <SFML/Graphics.hpp>\r
 \r
 #include <windows.h>\r
 \r
@@ -44,10 +44,8 @@ namespace caspar { namespace core { namespace ogl{
 struct consumer::implementation : boost::noncopyable\r
 {      \r
        implementation(const frame_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed) \r
-               : format_desc_(format_desc), stretch_(stretch), pbo_index_(0), screen_width_(0), screen_height_(0), windowed_(windowed)\r
-       {\r
-               pbos_[0] = pbos_[1] = 0;\r
-               \r
+               : index_(0), format_desc_(format_desc), stretch_(stretch), screen_width_(0), screen_height_(0), windowed_(windowed)\r
+       {               \r
 #ifdef _WIN32\r
                DISPLAY_DEVICE dDevice;                 \r
                memset(&dDevice,0,sizeof(dDevice));\r
@@ -94,9 +92,6 @@ struct consumer::implementation : boost::noncopyable
        {\r
                frame_buffer_.push(nullptr),\r
                thread_.join();\r
-\r
-               if(pbos_[0] && pbos_[1])\r
-                       glDeleteBuffers(2, pbos_);\r
        }\r
 \r
        void init()     \r
@@ -106,7 +101,15 @@ struct consumer::implementation : boost::noncopyable
                window_.SetPosition(screenX_, screenY_);\r
                window_.SetSize(screen_width_, screen_height_);\r
                window_.SetActive();\r
-                                               \r
+               GL(glEnable(GL_TEXTURE_2D));\r
+               GL(glDisable(GL_DEPTH_TEST));           \r
+               GL(glClearColor(0.0, 0.0, 0.0, 0.0));\r
+               GL(glViewport(0, 0, format_desc_.width, format_desc_.height));\r
+               glLoadIdentity();\r
+                               \r
+               wratio_ = static_cast<float>(format_desc_.width)/static_cast<float>(format_desc_.width);\r
+               hratio_ = static_cast<float>(format_desc_.height)/static_cast<float>(format_desc_.height);\r
+\r
                std::pair<float, float> target_ratio = None();\r
                if(stretch_ == ogl::fill)\r
                        target_ratio = Fill();\r
@@ -115,19 +118,11 @@ struct consumer::implementation : boost::noncopyable
                else if(stretch_ == ogl::uniform_to_fill)\r
                        target_ratio = UniformToFill();\r
 \r
-               float wSize = target_ratio.first;\r
-               float hSize = target_ratio.second;\r
+               wSize_ = target_ratio.first;\r
+               hSize_ = target_ratio.second;\r
                                        \r
-               image_.Create(format_desc_.width, format_desc_.height);\r
-               sprite_.SetImage(image_);\r
-               \r
-               GL(glGenBuffersARB(2, pbos_));\r
-               GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbos_[0]));\r
-               GL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, format_desc_.size, 0, GL_STREAM_DRAW));\r
-               GL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbos_[1]));\r
-               GL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, format_desc_.size, 0, GL_STREAM_DRAW));          \r
-\r
-               pbo_index_ = 0;\r
+               pbos_[0].create(format_desc_.width, format_desc_.height);\r
+               pbos_[1].create(format_desc_.width, format_desc_.height);\r
        }\r
 \r
        std::pair<float, float> None()\r
@@ -165,31 +160,23 @@ struct consumer::implementation : boost::noncopyable
        }\r
 \r
        void render(const gpu_frame_ptr& frame)\r
-       {                                       \r
-               // Render\r
-               window_.Clear();\r
-       \r
-               image_.Bind();\r
-               GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbos_[pbo_index_]));    \r
-               GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, format_desc_.width, format_desc_.height, GL_BGRA, GL_UNSIGNED_BYTE, 0));\r
-\r
-               window_.Draw(sprite_);\r
-\r
-               // Update\r
-               int nextPboIndex = pbo_index_ ^ 1;\r
-\r
-               GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbos_[nextPboIndex]));\r
-               GL(glBufferData(GL_PIXEL_UNPACK_BUFFER, format_desc_.size, NULL, GL_STREAM_DRAW));\r
-               GLubyte* ptr = static_cast<GLubyte*>(glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));\r
-\r
-               if(ptr != NULL)                 \r
-               {\r
-                       common::copy(ptr, frame->data(), frame->size());\r
-                       GL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));\r
-               }\r
-\r
-               // Swap\r
-               pbo_index_ = nextPboIndex;\r
+       {               \r
+               index_ = (index_ + 1) % 2;\r
+               int next_index = (index_ + 1) % 2;\r
+                               \r
+               auto ptr = pbos_[index_].end_write();\r
+               common::aligned_memcpy(ptr, frame->data(), frame->size());\r
+\r
+               GL(glClear(GL_COLOR_BUFFER_BIT));       \r
+               pbos_[next_index].bind_texture();                               \r
+               glBegin(GL_QUADS);\r
+                               glTexCoord2f(0.0f,        hratio_);     glVertex2f(-wSize_, -hSize_);\r
+                               glTexCoord2f(wratio_, hratio_); glVertex2f( wSize_, -hSize_);\r
+                               glTexCoord2f(wratio_, 0.0f);    glVertex2f( wSize_,  hSize_);\r
+                               glTexCoord2f(0.0f,        0.0f);        glVertex2f(-wSize_,  hSize_);\r
+               glEnd();\r
+\r
+               pbos_[next_index].begin_write();\r
        }\r
                        \r
        void display(const gpu_frame_ptr& frame)\r
@@ -228,10 +215,16 @@ struct consumer::implementation : boost::noncopyable
                        }\r
                }               \r
                while(frame != nullptr);\r
-       }\r
-               \r
+       }               \r
 \r
-       GLuint dlist_;\r
+       float wratio_;\r
+       float hratio_;\r
+       \r
+       float wSize_;\r
+       float hSize_;\r
+\r
+       int index_;\r
+       common::gl::pixel_buffer_object pbos_[2];\r
 \r
        bool windowed_;\r
        unsigned int screen_width_;\r
@@ -239,9 +232,6 @@ struct consumer::implementation : boost::noncopyable
        unsigned int screenX_;\r
        unsigned int screenY_;\r
                                \r
-       GLuint pbos_[2];\r
-       int pbo_index_;\r
-\r
        stretch stretch_;\r
        frame_format_desc format_desc_;\r
 \r
@@ -249,9 +239,7 @@ struct consumer::implementation : boost::noncopyable
        boost::thread thread_;\r
        tbb::concurrent_bounded_queue<gpu_frame_ptr> frame_buffer_;\r
 \r
-       sf::Image image_;\r
-       sf::Sprite sprite_;\r
-       sf::RenderWindow window_;\r
+       sf::Window window_;\r
 };\r
 \r
 consumer::consumer(const frame_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed)\r
index defc90e9ff71a77ab74b0315330ab420b799e043..917fb1f3428703d32ab4a5fe3a6b75cd4c6dcc69 100644 (file)
@@ -17,27 +17,24 @@ struct gpu_composite_frame::implementation : boost::noncopyable
 {\r
        implementation(gpu_composite_frame* self) : self_(self){}\r
 \r
-       void write_lock()\r
+       void begin_write()\r
        {\r
-               boost::range::for_each(frames_, std::mem_fn(&gpu_frame::write_lock));           \r
+               boost::range::for_each(frames_, std::mem_fn(&gpu_frame::begin_write));          \r
        }\r
 \r
-       bool write_unlock()\r
+       void end_write()\r
        {\r
-               return std::all_of(frames_.begin(), frames_.end(), \r
-                                                       std::mem_fn(&gpu_frame::write_unlock));                 \r
+               boost::range::for_each(frames_, std::mem_fn(&gpu_frame::end_write));                            \r
        }\r
        \r
-       void read_lock(GLenum mode)\r
+       void begin_read()\r
        {       \r
-               boost::range::for_each(frames_, std::bind(&gpu_frame::read_lock, \r
-                                                                                                       std::placeholders::_1, mode));          \r
+               boost::range::for_each(frames_, std::mem_fn(&gpu_frame::begin_read));           \r
        }\r
 \r
-       bool read_unlock()\r
+       void end_read()\r
        {\r
-               return std::all_of(frames_.begin(), frames_.end(), \r
-                                                       std::mem_fn(&gpu_frame::read_unlock));          \r
+               boost::range::for_each(frames_, std::mem_fn(&gpu_frame::end_read));     \r
        }\r
 \r
        void draw()\r
@@ -86,10 +83,10 @@ struct gpu_composite_frame::implementation : boost::noncopyable
 \r
 gpu_composite_frame::gpu_composite_frame() \r
        : gpu_frame(0, 0), impl_(new implementation(this)){}\r
-void gpu_composite_frame::write_lock(){impl_->write_lock();}\r
-bool gpu_composite_frame::write_unlock(){return impl_->write_unlock();}        \r
-void gpu_composite_frame::read_lock(GLenum mode){impl_->read_lock(mode);}\r
-bool gpu_composite_frame::read_unlock(){return impl_->read_unlock();}\r
+void gpu_composite_frame::begin_write(){impl_->begin_write();}\r
+void gpu_composite_frame::end_write(){impl_->end_write();}     \r
+void gpu_composite_frame::begin_read(){impl_->begin_read();}\r
+void gpu_composite_frame::end_read(){impl_->end_read();}\r
 void gpu_composite_frame::draw(){impl_->draw();}\r
 unsigned char* gpu_composite_frame::data(){return impl_->data();}\r
 void gpu_composite_frame::add(const gpu_frame_ptr& frame){impl_->add(frame);}\r
index dc77548116e3369c4a0975eb0d705a801ef5115b..e9f76a250817b1f93f922746f92801f64ad305f6 100644 (file)
@@ -20,10 +20,10 @@ public:
        \r
 private:\r
        virtual unsigned char* data();\r
-       virtual void write_lock();\r
-       virtual bool write_unlock();\r
-       virtual void read_lock(GLenum mode);\r
-       virtual bool read_unlock();\r
+       virtual void begin_write();\r
+       virtual void end_write();\r
+       virtual void begin_read();\r
+       virtual void end_read();\r
        virtual void draw();\r
 \r
        struct implementation;\r
index 2bbc4d5e8d47fca9e271a86518e22e36f90eb944..f66b3581536f3bd2a511db68cf24ad0cfed6702a 100644 (file)
@@ -3,6 +3,7 @@
 #include "gpu_frame.h"\r
 #include "../../common/utility/memory.h"\r
 #include "../../common/gl/gl_check.h"\r
+#include "../../common/gl/pixel_buffer_object.h"\r
 \r
 namespace caspar { namespace core {\r
        \r
@@ -64,99 +65,35 @@ GLubyte lower_pattern[] = {
 struct gpu_frame::implementation : boost::noncopyable\r
 {\r
        implementation(size_t width, size_t height) \r
-               : pbo_(0), data_(nullptr), width_(width), height_(height), \r
-                       size_(width*height*4), reading_(false), texture_(0), alpha_(1.0f), \r
+               : pbo_(width, height), data_(nullptr), width_(width), height_(height), \r
+                       size_(width*height*4), reading_(false), alpha_(1.0f), \r
                        x_(0.0f), y_(0.0f), mode_(video_mode::progressive), \r
-                       texcoords_(0.0, 1.0, 1.0, 0.0)\r
+                       texcoords_(0.0, 1.0, 1.0, 0.0), writing_(false), mapped_(false)\r
        {       \r
+               if(width > 0 && height > 0)\r
+                       end_write();\r
        }\r
-\r
-       ~implementation()\r
+       \r
+       void begin_write()\r
        {\r
-               if(pbo_ != 0)\r
-                       glDeleteBuffers(1, &pbo_);\r
-               if(texture_ != 0)\r
-                       glDeleteTextures(1, &texture_);\r
-       }\r
-\r
-       GLuint pbo()\r
-       {               \r
-               if(pbo_ == 0)\r
-                       GL(glGenBuffers(1, &pbo_));\r
-               return pbo_;\r
+               data_ = nullptr;\r
+               pbo_.begin_write();             \r
        }\r
 \r
-       void write_lock()\r
+       void end_write()\r
        {\r
-               if(texture_ == 0)\r
-               {\r
-                       GL(glGenTextures(1, &texture_));\r
-\r
-                       GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
-\r
-                       GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));\r
-                       GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));\r
-                       GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));\r
-                       GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));\r
-\r
-                       GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width_, height_, 0, GL_BGRA, \r
-                                                               GL_UNSIGNED_BYTE, NULL));\r
-               }\r
-\r
-               GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo()));\r
-               if(data_ != nullptr)\r
-               {\r
-                       GL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));\r
-                       data_ = nullptr;\r
-               }\r
-               GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
-               GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA, \r
-                                                       GL_UNSIGNED_BYTE, NULL));\r
-               GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));\r
-       }\r
-\r
-       bool write_unlock()\r
-       {\r
-               if(data_ != nullptr)\r
-                       return false;\r
-               GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo()));\r
-               GL(glBufferData(GL_PIXEL_UNPACK_BUFFER, size_, NULL, GL_STREAM_DRAW));\r
-               void* ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);\r
-               GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));\r
-               data_ = reinterpret_cast<unsigned char*>(ptr);\r
-               if(!data_)\r
-                       BOOST_THROW_EXCEPTION(invalid_operation() \r
-                                                                       << msg_info("glMapBuffer failed"));\r
-               return true;\r
+               data_ = static_cast<unsigned char*>(pbo_.end_write());\r
        }\r
        \r
-       void read_lock(GLenum mode)\r
+       void begin_read()\r
        {       \r
-               GL(glReadBuffer(mode));\r
-               GL(glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo()));\r
-               if(data_ != nullptr)    \r
-               {       \r
-                       GL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));        \r
-                       data_ = nullptr;\r
-               }\r
-               GL(glBufferData(GL_PIXEL_PACK_BUFFER, size_, NULL, GL_STREAM_READ));    \r
-               GL(glReadPixels(0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
-               GL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));\r
-               reading_ = true;\r
+               data_ = nullptr;\r
+               pbo_.begin_read();\r
        }\r
 \r
-       bool read_unlock()\r
+       void end_read()\r
        {\r
-               if(data_ != nullptr || !reading_)\r
-                       return false;\r
-               GL(glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo()));\r
-               void* ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);   \r
-               GL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));\r
-               data_ = reinterpret_cast<unsigned char*>(ptr);\r
-               if(!data_)\r
-                       BOOST_THROW_EXCEPTION(std::bad_alloc());\r
-               reading_ = false;\r
-               return true;\r
+               data_ = static_cast<unsigned char*>(pbo_.end_read());\r
        }\r
 \r
        void draw()\r
@@ -172,7 +109,7 @@ struct gpu_frame::implementation : boost::noncopyable
                else if(mode_ == video_mode::lower)\r
                        glPolygonStipple(lower_pattern);\r
 \r
-               GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
+               pbo_.bind_texture();\r
                glBegin(GL_QUADS);\r
                        glTexCoord2d(texcoords_.left,   texcoords_.bottom); glVertex2d(-1.0, -1.0);\r
                        glTexCoord2d(texcoords_.right,  texcoords_.bottom); glVertex2d( 1.0, -1.0);\r
@@ -199,14 +136,17 @@ struct gpu_frame::implementation : boost::noncopyable
                mode_      = video_mode::progressive;\r
        }\r
 \r
+       common::gl::pixel_buffer_object pbo_;\r
        gpu_frame* self_;\r
-       GLuint pbo_;\r
-       GLuint texture_;\r
        unsigned char* data_;\r
        size_t width_;\r
        size_t height_;\r
        size_t size_;\r
+\r
        bool reading_;\r
+       bool writing_;\r
+       bool mapped_;\r
+\r
        std::vector<short> audio_data_;\r
 \r
        double alpha_;\r
@@ -218,12 +158,11 @@ struct gpu_frame::implementation : boost::noncopyable
 \r
 gpu_frame::gpu_frame(size_t width, size_t height) \r
        : impl_(new implementation(width, height)){}\r
-void gpu_frame::write_lock(){impl_->write_lock();}\r
-bool gpu_frame::write_unlock(){return impl_->write_unlock();}  \r
-void gpu_frame::read_lock(GLenum mode){impl_->read_lock(mode);}\r
-bool gpu_frame::read_unlock(){return impl_->read_unlock();}\r
+void gpu_frame::begin_write(){impl_->begin_write();}\r
+void gpu_frame::end_write(){impl_->end_write();}       \r
+void gpu_frame::begin_read(){impl_->begin_read();}\r
+void gpu_frame::end_read(){impl_->end_read();}\r
 void gpu_frame::draw(){impl_->draw();}\r
-bool gpu_frame::valid() const { return impl_->data_ != nullptr;}\r
 unsigned char* gpu_frame::data(){return impl_->data();}\r
 size_t gpu_frame::size() const { return impl_->size_; }\r
 size_t gpu_frame::width() const { return impl_->width_;}\r
index 4759d518a614c206a3985137a8d88dcab74d2b82..fffe00c894b1e23e113c934c4099d928fb8179a9 100644 (file)
@@ -26,23 +26,13 @@ struct rectangle
 class gpu_frame : boost::noncopyable\r
 {\r
 public:\r
-       gpu_frame(size_t width, size_t height);\r
        virtual ~gpu_frame(){}\r
-       virtual void write_lock();\r
-       virtual bool write_unlock();\r
-       virtual void read_lock(GLenum mode);\r
-       virtual bool read_unlock();\r
-       virtual void draw();\r
-\r
-       virtual bool valid() const;\r
-               \r
+                       \r
        virtual unsigned char* data();\r
        virtual size_t size() const;\r
        virtual size_t width() const;\r
        virtual size_t height() const;\r
-       \r
-       virtual void reset();\r
-                       \r
+                               \r
        virtual const std::vector<short>& audio_data() const;   \r
        virtual std::vector<short>& audio_data();\r
 \r
@@ -59,10 +49,22 @@ public:
 \r
        static std::shared_ptr<gpu_frame> null()\r
        {\r
-               static auto my_null_frame = std::make_shared<gpu_frame>(0,0);\r
+               static auto my_null_frame = std::shared_ptr<gpu_frame>(new gpu_frame(0,0));\r
                return my_null_frame;\r
        }\r
                \r
+protected:\r
+       gpu_frame(size_t width, size_t height);\r
+\r
+       friend class gpu_frame_processor;\r
+       \r
+       virtual void begin_write();\r
+       virtual void end_write();\r
+       virtual void begin_read();\r
+       virtual void end_read();\r
+       virtual void draw();\r
+       virtual void reset();\r
+\r
 private:\r
        struct implementation;\r
        std::shared_ptr<implementation> impl_;\r
index 82d674e73e5283ff0c8c4c2e95c9956f2c15d662..73183644a0f663056efe98ae576887d973f8b582 100644 (file)
@@ -10,6 +10,7 @@
 #include "../../common/concurrency/executor.h"\r
 #include "../../common/utility/memory.h"\r
 #include "../../common/gl/gl_check.h"\r
+#include "../../common/gl/frame_buffer_object.h"\r
 \r
 #include <Glee.h>\r
 #include <SFML/Window.hpp>\r
@@ -49,33 +50,21 @@ struct gpu_frame_processor::implementation : boost::noncopyable
                        GL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));                  \r
                        GL(glClearColor(0.0, 0.0, 0.0, 0.0));\r
                        GL(glViewport(0, 0, format_desc_.width, format_desc_.height));\r
-                       glLoadIdentity();       \r
-                                               \r
-                       // Create and bind a framebuffer\r
-                       GL(glGenTextures(1, &render_texture_)); \r
-                       GL(glBindTexture(GL_TEXTURE_2D, render_texture_));                      \r
-                       GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, format_desc_.width, \r
-                                                               format_desc_.height, 0, GL_BGRA, \r
-                                                               GL_UNSIGNED_BYTE, NULL));\r
-                       GL(glGenFramebuffersEXT(1, &fbo_));             \r
-                       GL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_));\r
-                       GL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, \r
-                                                                                       GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, \r
-                                                                                       render_texture_, 0));\r
-                       \r
+                       glLoadIdentity();   \r
+\r
+                       fbo_.create(format_desc_.width, format_desc_.height);\r
+                       fbo_.bind_pixel_source();\r
+\r
                        writing_.resize(2, std::make_shared<gpu_composite_frame>());\r
-                       output_frame_ = std::make_shared<gpu_frame>(format_desc_.width, \r
-                                                                                                                       format_desc_.height);\r
+\r
+                       // Fill pipeline\r
+                       for(int n = 0; n < 2; ++n)\r
+                               composite(std::vector<gpu_frame_ptr>());\r
                });\r
-               // Fill pipeline\r
-               composite(std::vector<gpu_frame_ptr>());\r
-               composite(std::vector<gpu_frame_ptr>());\r
-               composite(std::vector<gpu_frame_ptr>());\r
        }\r
 \r
        ~implementation()\r
        {\r
-               glDeleteFramebuffersEXT(1, &fbo_);\r
                executor_.stop();\r
        }\r
                        \r
@@ -102,27 +91,33 @@ struct gpu_frame_processor::implementation : boost::noncopyable
                                // 1. Start asynchronous DMA transfer to video memory.\r
                                writing_[index_] = std::move(frame);            \r
                                // Lock frame and give pointer ownership to OpenGL.\r
-                               writing_[index_]->write_lock();\r
+                               writing_[index_]->begin_write();\r
                                \r
                                // 3. Output to external buffer.\r
-                               if(output_frame_->read_unlock())\r
+                               if(output_frame_)\r
+                               {       \r
+                                       output_frame_->end_read();\r
                                        output_.push(output_frame_);\r
-               \r
+                               }\r
+\r
                                // Clear framebuffer.\r
-                               glClear(GL_COLOR_BUFFER_BIT);   \r
+                               GL(glClear(GL_COLOR_BUFFER_BIT));       \r
 \r
                                // 2. Draw to framebuffer and start asynchronous DMA transfer \r
                                // to page-locked memory.\r
                                writing_[next_index]->draw();\r
                                \r
                                // Create an output frame\r
-                               output_frame_ = create_output_frame();\r
+                               auto temp_frame = create_output_frame();\r
                        \r
                                // Read from framebuffer into page-locked memory.\r
-                               output_frame_->read_lock(GL_COLOR_ATTACHMENT0_EXT);\r
-                               output_frame_->audio_data() = std::move(writing_[next_index]->audio_data());\r
+                               temp_frame->begin_read();\r
+                               temp_frame->audio_data() = std::move(writing_[next_index]->audio_data());\r
+\r
+                               output_frame_ = temp_frame;\r
 \r
                                // Return frames to pool.\r
+                               writing_[next_index]->end_write();\r
                                writing_[next_index] = nullptr;\r
                        }\r
                        catch(...)\r
@@ -136,8 +131,7 @@ struct gpu_frame_processor::implementation : boost::noncopyable
        {\r
                gpu_frame_ptr frame;\r
                if(!reading_pool_.try_pop(frame))\r
-                       frame = std::make_shared<gpu_frame>(format_desc_.width, \r
-                                                                                                       format_desc_.height);\r
+                       frame.reset(new gpu_frame(format_desc_.width, format_desc_.height));\r
 \r
                return gpu_frame_ptr(frame.get(), [=](gpu_frame*)\r
                {\r
@@ -154,17 +148,14 @@ struct gpu_frame_processor::implementation : boost::noncopyable
                gpu_frame_ptr frame;\r
                if(!pool.try_pop(frame))\r
                {\r
-                       frame = executor_.invoke([=]() -> gpu_frame_ptr\r
+                       frame = executor_.invoke([&]\r
                        {\r
-                               auto frame = std::make_shared<gpu_frame>(width, height);\r
-                               frame->write_unlock();\r
-                               return frame;\r
+                               return std::shared_ptr<gpu_frame>(new gpu_frame(width, height));\r
                        });\r
                }\r
                \r
                auto destructor = [=]\r
                {\r
-                       frame->write_unlock();\r
                        frame->reset();\r
                        writing_pools_[key].push(frame);\r
                };\r
@@ -197,8 +188,7 @@ struct gpu_frame_processor::implementation : boost::noncopyable
        \r
        common::executor executor_;\r
 \r
-       GLuint render_texture_;\r
-       GLuint fbo_;\r
+       common::gl::frame_buffer_object fbo_;\r
 };\r
        \r
 gpu_frame_processor::gpu_frame_processor(const frame_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
index 0164daecef2f6172ccbfda1f2849a153706165b6..58d2fd5315d1f7ab3e5d3cfdc8f7905ecc29e44e 100644 (file)
@@ -37,21 +37,19 @@ public:
 \r
        gpu_frame_ptr get_frame()\r
        { \r
-               frame_ = factory_->create_frame(format_desc_);\r
-               __stosd(reinterpret_cast<unsigned long*>(frame_->data()), color_value_, frame_->size() / sizeof(unsigned long));\r
                return frame_;\r
        }\r
        const frame_format_desc& get_frame_format_desc() const { return format_desc_; }\r
        \r
        void initialize(const frame_factory_ptr& factory)\r
        {\r
-               factory_ = factory;\r
+               frame_ = factory->create_frame(format_desc_);\r
+               __stosd(reinterpret_cast<unsigned long*>(frame_->data()), color_value_, frame_->size() / sizeof(unsigned long));\r
        }\r
 \r
        frame_format_desc format_desc_;\r
        gpu_frame_ptr frame_;\r
        unsigned int color_value_;\r
-       frame_factory_ptr factory_;\r
 };\r
 \r
 union Color \r
index 9e3502ed0ea4c43e23f6358fb0e12f24c04cb9c7..eddbe023f8c74f75c54adc76c347a29b033b1596 100644 (file)
@@ -268,7 +268,7 @@ struct flash_producer::implementation
                }       \r
 \r
                auto frame = factory_->create_frame(format_desc_);\r
-               common::copy(frame->data(), current_frame_->data(), current_frame_->size());    \r
+               common::aligned_memcpy(frame->data(), current_frame_->data(), current_frame_->size());  \r
 \r
                return frame;\r
        }\r
index 69ce620bb04a3b5e12483432c90e93d15822782b..07135b9ae105621fa3f65a99f1219336412a3c1a 100644 (file)
@@ -33,7 +33,7 @@ struct image_producer : public frame_producer
 \r
                FreeImage_FlipVertical(bitmap.get());\r
                frame_ = factory->create_frame(format_desc_);\r
-               common::copy(frame_->data(), FreeImage_GetBits(bitmap.get()), frame_->size());\r
+               common::aligned_memcpy(frame_->data(), FreeImage_GetBits(bitmap.get()), frame_->size());\r
        }\r
 \r
        const frame_format_desc& get_frame_format_desc() const { return format_desc_; } \r
index 47d909f0000e876e20634fd17d6bf10f0c650c0c..ee1243a3283650d081704ee19efb5cae6795033e 100644 (file)
@@ -80,7 +80,7 @@ struct image_scroll_producer : public frame_producer
                unsigned char* pBits = FreeImage_GetBits(pBitmap.get());\r
                \r
                for (size_t i = 0; i < height; ++i)\r
-                       common::copy(&image_.get()[i * image_width_ * 4], &pBits[i* width * 4], width * 4);\r
+                       common::aligned_memcpy(&image_.get()[i * image_width_ * 4], &pBits[i* width * 4], width * 4);\r
        }\r
 \r
        gpu_frame_ptr render_frame()\r
index 17faf10be63d6bcc01052c5645fe1e6d7d5eaaee..81b86af1debe7aa2481aa22ab06cd63ddab0f353 100644 (file)
@@ -55,7 +55,7 @@ struct transition_producer::implementation : boost::noncopyable
                \r
        gpu_frame_ptr get_frame()\r
        {\r
-               if(++current_frame_ >= info_.duration)\r
+               if(current_frame_++ >= info_.duration)\r
                        return nullptr;\r
 \r
                gpu_frame_ptr source;\r
@@ -128,31 +128,42 @@ struct transition_producer::implementation : boost::noncopyable
                auto composite = std::make_shared<gpu_composite_frame>();\r
                if(src_frame)\r
                        composite->add(src_frame);\r
-               else\r
-                       src_frame = std::make_shared<gpu_frame>(0, 0);\r
                composite->add(dest_frame);\r
 \r
-               if(info_.type == transition_type::mix)\r
-                       dest_frame->alpha(alpha);               \r
-               else if(info_.type == transition_type::slide)\r
+               switch(info_.type)\r
                {\r
+               case transition_type::mix: \r
+                       dest_frame->alpha(alpha);       \r
+                       break;\r
+               case transition_type::slide:                    \r
                        if(info_.direction == transition_direction::from_left)                  \r
                                dest_frame->translate(-1.0+alpha, 0.0);                 \r
                        else if(info_.direction == transition_direction::from_right)\r
-                               dest_frame->translate(1.0-alpha, 0.0);                  \r
-               }\r
-               else if(info_.type == transition_type::push)\r
-               {\r
+                               dest_frame->translate(1.0-alpha, 0.0);          \r
+                       break;\r
+               case transition_type::push:\r
                        if(info_.direction == transition_direction::from_left)          \r
                        {\r
                                dest_frame->translate(-1.0+alpha, 0.0);\r
-                               src_frame->translate(0.0+alpha, 0.0);\r
+                               if(src_frame)\r
+                                       src_frame->translate(0.0+alpha, 0.0);\r
                        }\r
                        else if(info_.direction == transition_direction::from_right)\r
                        {\r
                                dest_frame->translate(1.0-alpha, 0.0);\r
-                               src_frame->translate(0.0-alpha, 0.0);\r
+                               if(src_frame)\r
+                                       src_frame->translate(0.0-alpha, 0.0);\r
                        }\r
+                       break;\r
+               }\r
+\r
+               if(info_.type == transition_type::mix)\r
+                       dest_frame->alpha(alpha);               \r
+               else if(info_.type == transition_type::slide)\r
+               {       \r
+               }\r
+               else if(info_.type == transition_type::push)\r
+               {\r
                }\r
                else if(info_.type == transition_type::wipe)\r
                {\r
index 195f1ee0c1d098d5272f658f4620c80b54744321..6678d2514b9094deee90bf6ac562c7ba57ed1097 100644 (file)
@@ -8,7 +8,7 @@
   </paths>\r
   <channels>\r
     <channel>\r
-      <videomode>PAL</videomode>\r
+      <videomode>1080p2500</videomode>\r
       <consumers>\r
         <ogl>\r
           <device>1</device>\r
diff --git a/test/mock/mock_frame.h b/test/mock/mock_frame.h
new file mode 100644 (file)
index 0000000..85f9fc9
--- /dev/null
@@ -0,0 +1,12 @@
+#pragma once\r
+\r
+#include <core/frame/gpu_frame.h>\r
+\r
+struct mock_frame : public caspar::core::gpu_frame\r
+{\r
+       mock_frame(void* tag, short volume = 100) : caspar::core::gpu_frame(0,0), tag(tag)\r
+       {\r
+               audio_data().resize(100, volume);\r
+       }\r
+       void* tag;\r
+};
\ No newline at end of file
diff --git a/test/mock/mock_frame_factory.h b/test/mock/mock_frame_factory.h
new file mode 100644 (file)
index 0000000..483f386
--- /dev/null
@@ -0,0 +1,12 @@
+#pragma once\r
+\r
+#include <core/frame/frame_factory.h>\r
+#include <core/frame/gpu_frame.h>\r
+\r
+struct mock_frame_factory : public caspar::core::frame_factory\r
+{\r
+       virtual gpu_frame_ptr create_frame(size_t width, size_t height)\r
+       {\r
+               return std::make_shared<mock_frame>();\r
+       }\r
+};
\ No newline at end of file
index 0f8eded66dcf41895fa12abe78f9b527525f3df6..8c8b551ebff1080c6d0f820e28d040462d089238 100644 (file)
@@ -1,6 +1,7 @@
 #pragma once\r
 \r
-#include <core/frame/gpu_frame.h>\r
+#include "mock_frame.h"\r
+\r
 #include <core/producer/frame_producer.h>\r
 #include <common/exception/exceptions.h>\r
 \r
@@ -11,7 +12,8 @@ class mock_frame_producer : public frame_producer
 {\r
 public:\r
        mock_frame_producer(bool null = false, bool throws = false) \r
-               : null_(null), throws_(throws){}\r
+               : null_(null), throws_(throws), initialized_(false), volume_(100){}\r
+       void set_volume(short volume) { volume_ = volume;}\r
        gpu_frame_ptr get_frame()\r
        { \r
                if(throws_)\r
@@ -19,7 +21,7 @@ public:
                if(leading_)\r
                        return leading_->get_frame();\r
                if(!null_)\r
-                       return std::make_shared<gpu_frame>(0, 0);\r
+                       return std::make_shared<mock_frame>(this, volume_);\r
                return nullptr;\r
        }\r
        std::shared_ptr<frame_producer> get_following_producer() const \r
@@ -32,12 +34,16 @@ public:
                return format;\r
        }\r
        void initialize(const frame_factory_ptr& factory)\r
-       {}\r
+       {initialized_ = true;}\r
        void set_following_producer(const std::shared_ptr<frame_producer>& following)\r
        {following_ = following;}\r
+\r
+       bool is_initialized() const { return initialized_;}\r
 private:\r
        std::shared_ptr<frame_producer> following_;\r
        std::shared_ptr<frame_producer> leading_;\r
        bool null_;\r
        bool throws_;\r
+       bool initialized_;\r
+       short volume_;\r
 };
\ No newline at end of file
diff --git a/test/producer/transition/transition_producer_test.cpp b/test/producer/transition/transition_producer_test.cpp
new file mode 100644 (file)
index 0000000..d80cd06
--- /dev/null
@@ -0,0 +1,90 @@
+#include <gtest/gtest.h>\r
+\r
+#include "../../mock/mock_frame_producer.h"\r
+#include "../../mock/mock_frame.h"\r
+\r
+#include <core/frame/frame_format.h>\r
+#include <core/frame/gpu_frame.h>\r
+#include <core/producer/transition/transition_producer.h>\r
+#include <common/exception/exceptions.h>\r
+\r
+using namespace caspar;\r
+using namespace caspar::core;\r
+\r
+frame_format_desc test_format = frame_format_desc::format_descs[frame_format::pal];\r
+\r
+TEST(transition_producer, constructor_dest_nullptr) \r
+{\r
+       ASSERT_THROW(transition_producer(nullptr, transition_info(), test_format);\r
+                                       , null_argument);       \r
+}\r
+\r
+TEST(transition_producer, get_following_producer) \r
+{\r
+       auto dest = std::make_shared<mock_frame_producer>();\r
+       \r
+       transition_producer producer(dest, transition_info(), test_format);\r
+\r
+       ASSERT_TRUE(producer.get_following_producer() == dest);\r
+}\r
+\r
+TEST(transition_producer, get_frame_format_desc) \r
+{\r
+       auto dest = std::make_shared<mock_frame_producer>();\r
+       \r
+       transition_producer producer(dest, transition_info(), test_format);\r
+\r
+       ASSERT_TRUE(producer.get_frame_format_desc() == test_format);\r
+}\r
+\r
+TEST(transition_producer, null_dest_get_frame) \r
+{\r
+       auto source = std::make_shared<mock_frame_producer>();\r
+       \r
+       transition_producer producer(nullptr, transition_info(), test_format);\r
+       producer.set_leading_producer(source);\r
+\r
+       ASSERT_TRUE(producer.get_frame() == nullptr);\r
+}\r
+\r
+TEST(transition_producer, null_source_get_frame_cut) \r
+{\r
+       auto dest = std::make_shared<mock_frame_producer>();\r
+       \r
+       transition_info info;\r
+       info.type = transition_type::cut;\r
+\r
+       transition_producer producer(dest, info, test_format);\r
+\r
+       ASSERT_TRUE(producer.get_frame() == nullptr);\r
+}\r
+\r
+TEST(transition_producer, initialize) \r
+{\r
+       auto dest = std::make_shared<mock_frame_producer>();\r
+       \r
+       transition_producer producer(dest, transition_info(), test_format);\r
+       producer.initialize(nullptr);\r
+       \r
+       ASSERT_TRUE(dest->is_initialized());\r
+}\r
+\r
+TEST(transition_producer, duration) \r
+{\r
+       auto dest = std::make_shared<mock_frame_producer>();\r
+       auto source = std::make_shared<mock_frame_producer>();\r
+       \r
+       transition_info info;\r
+       info.type = transition_type::cut;\r
+       info.duration = 3;\r
+\r
+       transition_producer producer(dest, info, test_format);\r
+       producer.set_leading_producer(source);\r
+\r
+       for(int n = 0; n < info.duration; ++n)\r
+       {\r
+               auto frame = producer.get_frame();\r
+               ASSERT_TRUE(std::static_pointer_cast<mock_frame>(frame)->tag == source.get());\r
+       }\r
+       ASSERT_TRUE(producer.get_frame() == nullptr);\r
+}
\ No newline at end of file
index 23bd65c68b1be8e97cf2df991ec1861e5d71deea..413cd2a214930c4e22abd58b00887eff07790cb2 100644 (file)
@@ -15,6 +15,7 @@
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>\r
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>\r
     </ClCompile>\r
+    <ClCompile Include="producer\transition\transition_producer_test.cpp" />\r
     <ClCompile Include="renderer\layer_test.cpp" />\r
   </ItemGroup>\r
   <ItemGroup>\r
@@ -26,6 +27,8 @@
     </ProjectReference>\r
   </ItemGroup>\r
   <ItemGroup>\r
+    <ClInclude Include="mock\mock_frame.h" />\r
+    <ClInclude Include="mock\mock_frame_factory.h" />\r
     <ClInclude Include="mock\mock_frame_producer.h" />\r
   </ItemGroup>\r
   <PropertyGroup Label="Globals">\r
index 6b0544b29bbb508f3191ae257469f315fdcb1122..e7367252d296d9bc8af0b90458095ded7cdfd1f6 100644 (file)
     <Filter Include="Source\mock">\r
       <UniqueIdentifier>{420ab80e-66c8-477b-b8c6-d8f4ceb08102}</UniqueIdentifier>\r
     </Filter>\r
+    <Filter Include="Source\producer">\r
+      <UniqueIdentifier>{2d766f33-578d-40a7-a018-8a0a8b031e08}</UniqueIdentifier>\r
+    </Filter>\r
+    <Filter Include="Source\producer\transition">\r
+      <UniqueIdentifier>{cb38fc85-f618-4461-94bf-d7eff61b49fe}</UniqueIdentifier>\r
+    </Filter>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="main.cpp">\r
     <ClCompile Include="renderer\layer_test.cpp">\r
       <Filter>Source\renderer</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="producer\transition\transition_producer_test.cpp">\r
+      <Filter>Source\producer\transition</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="mock\mock_frame_producer.h">\r
       <Filter>Source\mock</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="mock\mock_frame.h">\r
+      <Filter>Source\mock</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="mock\mock_frame_factory.h">\r
+      <Filter>Source\mock</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file