#define CASPAR_GL_EXPR_STR(expr) #expr\r
\r
#define GL(expr) \\r
- do \\r
+ [&] \\r
{ \\r
(expr); \\r
caspar::gl::SMFL_GLCheckError(CASPAR_GL_EXPR_STR(expr), __FILE__, __LINE__);\\r
- }while(0);\r
+ }()\r
\r
#define GL2(expr) \\r
[&]() -> decltype(expr)\\r
\r
std::string vertex_;\r
std::string fragment_;\r
+\r
+ core::video_mode::type last_mode_;\r
+ size_t last_width_;\r
+ size_t last_height_;\r
\r
- implementation()\r
+ implementation() \r
+ : last_mode_(core::video_mode::progressive)\r
+ , last_width_(0)\r
+ , last_height_(0)\r
{\r
vertex_ = \r
"void main() \n"\r
{\r
shader_.reset(new shader(vertex_, fragment_));\r
GL(glEnable(GL_TEXTURE_2D));\r
- GL(glEnable(GL_SCISSOR_TEST));\r
}\r
- \r
- if(item.mode == core::video_mode::upper)\r
+\r
+ if(last_mode_ != item.mode)\r
{\r
- GL(glEnable(GL_POLYGON_STIPPLE));\r
- glPolygonStipple(upper_pattern);\r
+ last_mode_ = item.mode;\r
+ \r
+ if(item.mode == core::video_mode::progressive) \r
+ GL(glDisable(GL_POLYGON_STIPPLE)); \r
+ else \r
+ {\r
+ GL(glEnable(GL_POLYGON_STIPPLE)); \r
+\r
+ if(item.mode == core::video_mode::upper)\r
+ glPolygonStipple(upper_pattern);\r
+ else if(item.mode == core::video_mode::lower)\r
+ glPolygonStipple(lower_pattern);\r
+ }\r
}\r
- else if(item.mode == core::video_mode::lower)\r
+\r
+ if(last_width_ != background->width() || last_height_ != background->height())\r
{\r
- GL(glEnable(GL_POLYGON_STIPPLE));\r
- glPolygonStipple(lower_pattern);\r
+ last_width_ = background->width();\r
+ last_height_ = background->height();\r
+ GL(glViewport(0, 0, background->width(), background->height()));\r
}\r
- else\r
- GL(glDisable(GL_POLYGON_STIPPLE));\r
\r
// Bind textures\r
\r
// Setup drawing area\r
\r
GL(glColor4d(item.transform.get_gain(), item.transform.get_gain(), item.transform.get_gain(), item.transform.get_opacity()));\r
- GL(glViewport(0, 0, background->width(), background->height()));\r
\r
auto m_p = item.transform.get_clip_translation();\r
auto m_s = item.transform.get_clip_scale();\r
double w = static_cast<double>(background->width());\r
double h = static_cast<double>(background->height());\r
\r
+ GL(glEnable(GL_SCISSOR_TEST));\r
GL(glScissor(static_cast<size_t>(m_p[0]*w), static_cast<size_t>(m_p[1]*h), static_cast<size_t>(m_s[0]*w), static_cast<size_t>(m_s[1]*h)));\r
\r
auto f_p = item.transform.get_fill_translation();\r
glMultiTexCoord2d(GL_TEXTURE0, 1.0, 1.0); glMultiTexCoord2d(GL_TEXTURE1, (f_p[0]+f_s[0]), (f_p[1]+f_s[1])); glVertex2d((f_p[0]+f_s[0])*2.0-1.0, (f_p[1]+f_s[1])*2.0-1.0);\r
glMultiTexCoord2d(GL_TEXTURE0, 0.0, 1.0); glMultiTexCoord2d(GL_TEXTURE1, f_p[0] , (f_p[1]+f_s[1])); glVertex2d( f_p[0] *2.0-1.0, (f_p[1]+f_s[1])*2.0-1.0);\r
glEnd();\r
+\r
+ GL(glDisable(GL_SCISSOR_TEST)); \r
}\r
};\r
\r
{\r
auto frame2 = make_safe<core::basic_frame>(frame.second);\r
frame2->get_image_transform() = image_transforms[frame.first].fetch_and_tick(1);\r
- frame1 = core::basic_frame::interlace(frame1, frame2, channel_.get_format_desc().mode); // image_mixer optimizes away unecessary interlacing. No need to worry about it here.\r
+ if(frame1->get_image_transform() != frame2->get_image_transform())\r
+ frame1 = core::basic_frame::interlace(frame1, frame2, channel_.get_format_desc().mode);\r
}\r
\r
frame1->accept(image_mixer_);\r
\r
return frame;\r
}\r
+\r
+ bool empty() const\r
+ {\r
+ return background_ == core::frame_producer::empty() && foreground_ == core::frame_producer::empty();\r
+ }\r
};\r
\r
layer::layer() : impl_(new implementation()){}\r
safe_ptr<basic_frame> layer::receive() {return impl_->receive();}\r
safe_ptr<frame_producer> layer::foreground() const { return impl_->foreground_;}\r
safe_ptr<frame_producer> layer::background() const { return impl_->background_;}\r
+bool layer::empty() const {return impl_->empty();}\r
}}
\ No newline at end of file
void stop(); // nothrow\r
void param(const std::wstring& param);\r
\r
+ bool empty() const;\r
+\r
safe_ptr<frame_producer> foreground() const; // nothrow\r
safe_ptr<frame_producer> background() const; // nothrow\r
\r
\r
#include <core/producer/frame/basic_frame.h>\r
\r
-#include <tbb/parallel_invoke.h>\r
-\r
namespace caspar { namespace core { \r
\r
struct separated_producer : public frame_producer\r
\r
virtual safe_ptr<basic_frame> receive(int hints)\r
{\r
- tbb::parallel_invoke\r
- (\r
- [&]\r
- {\r
- if(fill_ == core::basic_frame::late())\r
- fill_ = receive_and_follow(fill_producer_, hints);\r
- },\r
- [&]\r
- {\r
- if(key_ == core::basic_frame::late())\r
- key_ = receive_and_follow(key_producer_, hints | ALPHA_HINT);\r
- }\r
- );\r
+ if(fill_ == core::basic_frame::late())\r
+ fill_ = receive_and_follow(fill_producer_, hints);\r
+ \r
+ if(key_ == core::basic_frame::late())\r
+ key_ = receive_and_follow(key_producer_, hints | ALPHA_HINT);\r
\r
if(fill_ == basic_frame::eof())\r
return basic_frame::eof();\r
\r
#include <boost/range/algorithm.hpp>\r
\r
-#include <tbb/parallel_for.h>\r
-\r
#include <map>\r
\r
namespace caspar { namespace core {\r
\r
void destroy_producer(safe_ptr<frame_producer>& producer)\r
{\r
- if(!producer.unique())\r
+ bool unique = producer.unique();\r
+\r
+ if(!unique)\r
CASPAR_LOG(warning) << producer->print() << L" Not destroyed on safe asynchronous destruction thread.";\r
- \r
+ \r
producer = frame_producer::empty();\r
+ \r
+ if(unique)\r
+ CASPAR_LOG(debug) << producer->print() << L" Destroyed.";\r
}\r
\r
class destroy_producer_proxy : public frame_producer\r
\r
try\r
{\r
- // Allocate placeholders.\r
- BOOST_FOREACH(auto layer, layers_)\r
- frames[layer.first] = basic_frame::empty();\r
+ auto layers2 = std::move(layers_);\r
+ std::remove_copy_if(layers2.begin(), layers2.end(), std::inserter(layers_, layers_.begin()), [](layer_t& layer){return layer.second.empty();});\r
\r
- // Render layers\r
- tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](layer_t& layer)\r
- {\r
+ BOOST_FOREACH(auto& layer, layers_)\r
frames[layer.first] = layer.second.receive();\r
- });\r
}\r
catch(...)\r
{\r
if(current_frame_++ >= info_.duration)\r
return basic_frame::eof();\r
\r
- auto dest = core::basic_frame::empty();\r
- auto source = core::basic_frame::empty();\r
-\r
- tbb::parallel_invoke\r
- (\r
- [&]\r
- {\r
- dest = receive_and_follow(dest_producer_, hints);\r
- if(dest == core::basic_frame::late())\r
- dest = dest_producer_->last_frame();\r
- },\r
- [&]\r
- {\r
- source = receive_and_follow(source_producer_, hints);\r
- if(source == core::basic_frame::late())\r
- source = source_producer_->last_frame();\r
- }\r
- );\r
+ auto dest = receive_and_follow(dest_producer_, hints);\r
+ if(dest == core::basic_frame::late())\r
+ dest = dest_producer_->last_frame();\r
+ \r
+ auto source = receive_and_follow(source_producer_, hints);\r
+ if(source == core::basic_frame::late())\r
+ source = source_producer_->last_frame();\r
\r
return last_frame_ = compose(dest, source);\r
}\r