detail::SetThreadName(GetCurrentThreadId(), name_.c_str());\r
while(is_running_)\r
execute();\r
- is_running_ = false;\r
} \r
};\r
\r
transform_stack_.pop();\r
}\r
\r
- std::vector<short> begin_pass()\r
+ void begin_pass()\r
{\r
- auto result = std::move(audio_data_.front());\r
- audio_data_.pop_front();\r
- \r
audio_data_.push_back(std::vector<short>());\r
-\r
- return result;\r
}\r
\r
- void end_pass()\r
+ std::vector<short> end_pass()\r
{\r
prev_audio_transforms_ = std::move(next_audio_transforms_);\r
+\r
+ auto result = std::move(audio_data_.front());\r
+ audio_data_.pop_front(); \r
+ return result;\r
}\r
};\r
\r
void audio_mixer::begin(const core::basic_frame& frame){impl_->begin(frame);}\r
void audio_mixer::visit(core::write_frame& frame){impl_->visit(frame);}\r
void audio_mixer::end(){impl_->end();}\r
-std::vector<short> audio_mixer::begin_pass(){return impl_->begin_pass();} \r
-void audio_mixer::end_pass(){impl_->end_pass();}\r
+void audio_mixer::begin_pass(){ impl_->begin_pass();} \r
+std::vector<short> audio_mixer::end_pass(){return impl_->end_pass();}\r
\r
}}
\ No newline at end of file
virtual void visit(core::write_frame& frame);\r
virtual void end();\r
\r
- std::vector<short> begin_pass();\r
- void end_pass();\r
+ void begin_pass();\r
+ std::vector<short> end_pass();\r
\r
private:\r
struct implementation;\r
auto& root_audio_transform = boost::fusion::at_key<core::audio_transform>(root_transforms_);\r
auto& audio_transforms = boost::fusion::at_key<core::audio_transform>(transforms_);\r
\r
- auto audio = audio_mixer_.begin_pass();\r
+ audio_mixer_.begin_pass();\r
BOOST_FOREACH(auto& frame, frames)\r
{\r
int num = format_desc_.mode == core::video_mode::progressive ? 1 : 2;\r
frame1->get_audio_transform() = root_audio_transform.fetch_and_tick(num)*audio_transforms[frame.first].fetch_and_tick(num);\r
frame1->accept(audio_mixer_);\r
}\r
- audio_mixer_.end_pass();\r
- return audio;\r
+ return audio_mixer_.end_pass();\r
}\r
\r
void send(const std::map<int, safe_ptr<core::basic_frame>>& frames)\r
}\r
\r
safe_ptr<core::write_frame> create_frame(void* tag, const core::pixel_format_desc& desc)\r
- {\r
- return make_safe<write_frame>(reinterpret_cast<int>(tag), desc, image_mixer_.create_buffers(desc));\r
+ { \r
+ return image_mixer_.create_frame(tag, desc);\r
}\r
\r
template<typename T> \r
{\r
GL(glGenBuffers(1, &pbo_));\r
GL(glBindBuffer(target_, pbo_));\r
- GL(glBufferData(target_, size_, NULL, usage_)); \r
+ if(usage_ != write_only) \r
+ GL(glBufferData(target_, size_, NULL, usage_)); \r
GL(glBindBuffer(target_, 0));\r
\r
if(!pbo_)\r
{\r
if(data_)\r
return;\r
+\r
+ if(usage_ == write_only) \r
+ GL(glBufferData(target_, size_, NULL, usage_)); // Notify OpenGL that we don't care about previous data.\r
\r
GL(glBindBuffer(target_, pbo_));\r
data_ = glMapBuffer(target_, usage_ == GL_STREAM_DRAW ? GL_WRITE_ONLY : GL_READ_ONLY); \r
\r
struct render_item\r
{\r
- core::pixel_format_desc desc;\r
+ pixel_format_desc desc;\r
std::vector<safe_ptr<device_buffer>> textures;\r
- core::image_transform transform;\r
+ core::image_transform transform;\r
};\r
\r
const core::video_format_desc format_desc_;\r
\r
std::stack<core::image_transform> transform_stack_;\r
- std::vector<std::vector<render_item>> transferring_queue_;\r
- std::vector<std::vector<render_item>> render_queue_;\r
+ std::queue<std::queue<render_item>> render_queue_;\r
\r
image_kernel kernel_;\r
\r
}\r
\r
void visit(core::write_frame& frame)\r
- { \r
- auto desc = frame.get_pixel_format_desc();\r
- auto buffers = frame.get_plane_buffers();\r
- auto transform = transform_stack_.top()*frame.get_image_transform();\r
-\r
- ogl_device::begin_invoke([=]\r
- {\r
- render_item item;\r
-\r
- item.desc = desc;\r
- item.transform = transform;\r
- \r
- // Start transfer from host to device.\r
-\r
- for(size_t n = 0; n < buffers.size(); ++n)\r
- {\r
- auto texture = ogl_device::create_device_buffer(desc.planes[n].width, desc.planes[n].height, desc.planes[n].channels);\r
- texture->read(*buffers[n]);\r
- item.textures.push_back(texture);\r
- } \r
-\r
- transferring_queue_.back().push_back(item);\r
- });\r
+ { \r
+ render_item item = {frame.get_pixel_format_desc(), frame.get_textures(), transform_stack_.top()*frame.get_image_transform()}; \r
+ render_queue_.back().push(item);\r
}\r
\r
void end()\r
\r
void begin_layer()\r
{\r
- ogl_device::begin_invoke([=]\r
- {\r
- transferring_queue_.push_back(std::vector<render_item>());\r
- });\r
+ render_queue_.push(std::queue<render_item>());\r
}\r
\r
void end_layer()\r
boost::unique_future<safe_ptr<const host_buffer>> render()\r
{\r
auto result = ogl_device::create_host_buffer(format_desc_.size, host_buffer::read_only);\r
- \r
- ogl_device::begin_invoke([=]\r
+ \r
+ auto render_queue = std::move(render_queue_);\r
+\r
+ ogl_device::begin_invoke([=]() mutable\r
{\r
local_key_ = false;\r
layer_key_ = false;\r
\r
// Draw items in device.\r
\r
- BOOST_FOREACH(auto layer, render_queue_)\r
+ while(!render_queue.empty())\r
{\r
+ auto layer = render_queue.front();\r
+ render_queue.pop();\r
+ \r
draw_buffer_->attach(); \r
\r
- BOOST_FOREACH(auto item, layer) \r
- { \r
+ while(!layer.empty())\r
+ {\r
+ draw(layer.front());\r
+ layer.pop();\r
ogl_device::yield(); // Allow quick buffer allocation to execute.\r
- draw(item); \r
}\r
\r
layer_key_ = local_key_; // If there was only key in last layer then use it as key for the entire next layer.\r
std::swap(local_key_buffer_, layer_key_buffer_);\r
}\r
\r
- // Move waiting items to queue.\r
-\r
- render_queue_ = std::move(transferring_queue_);\r
-\r
// Start transfer from device to host.\r
\r
draw_buffer_->write(*result);\r
kernel_.draw(format_desc_.width, format_desc_.height, item.desc, item.transform, local_key, layer_key); \r
}\r
\r
- std::vector<safe_ptr<host_buffer>> create_buffers(const core::pixel_format_desc& format)\r
+ safe_ptr<write_frame> create_frame(void* tag, const core::pixel_format_desc& desc)\r
{\r
std::vector<safe_ptr<host_buffer>> buffers;\r
- std::transform(format.planes.begin(), format.planes.end(), std::back_inserter(buffers), [&](const core::pixel_format_desc::plane& plane)\r
+ std::vector<safe_ptr<device_buffer>> textures;\r
+ ogl_device::invoke([&]\r
{\r
- return ogl_device::create_host_buffer(plane.size, host_buffer::write_only);\r
+ std::transform(desc.planes.begin(), desc.planes.end(), std::back_inserter(buffers), [&](const core::pixel_format_desc::plane& plane)\r
+ {\r
+ return ogl_device::create_host_buffer(plane.size, host_buffer::write_only);\r
+ });\r
+ std::transform(desc.planes.begin(), desc.planes.end(), std::back_inserter(textures), [&](const core::pixel_format_desc::plane& plane)\r
+ {\r
+ return ogl_device::create_device_buffer(plane.width, plane.height, plane.channels);\r
+ });\r
});\r
- return buffers;\r
+\r
+ return make_safe<write_frame>(reinterpret_cast<int>(tag), desc, buffers, textures);\r
}\r
};\r
\r
void image_mixer::visit(core::write_frame& frame){impl_->visit(frame);}\r
void image_mixer::end(){impl_->end();}\r
boost::unique_future<safe_ptr<const host_buffer>> image_mixer::render(){return impl_->render();}\r
-std::vector<safe_ptr<host_buffer>> image_mixer::create_buffers(const core::pixel_format_desc& format){return impl_->create_buffers(format);}\r
+safe_ptr<write_frame> image_mixer::create_frame(void* tag, const core::pixel_format_desc& desc){return impl_->create_frame(tag, desc);}\r
void image_mixer::begin_layer(){impl_->begin_layer();}\r
void image_mixer::end_layer(){impl_->end_layer();}\r
\r
\r
boost::unique_future<safe_ptr<const host_buffer>> render();\r
\r
- std::vector<safe_ptr<host_buffer>> create_buffers(const core::pixel_format_desc& format);\r
+ safe_ptr<write_frame> create_frame(void* tag, const core::pixel_format_desc& format);\r
\r
private:\r
struct implementation;\r
\r
#include "write_frame.h"\r
\r
+#include "gpu/ogl_device.h"\r
+\r
#include <core/producer/frame/pixel_format.h>\r
\r
#include <common/gl/gl_check.h>\r
struct write_frame::implementation : boost::noncopyable\r
{ \r
std::vector<safe_ptr<host_buffer>> buffers_;\r
+ std::vector<safe_ptr<device_buffer>> textures_;\r
std::vector<short> audio_data_;\r
const core::pixel_format_desc desc_;\r
int tag_;\r
\r
public:\r
- implementation(int tag, const core::pixel_format_desc& desc, const std::vector<safe_ptr<host_buffer>>& buffers) \r
+ implementation(int tag, const core::pixel_format_desc& desc, const std::vector<safe_ptr<host_buffer>>& buffers, const std::vector<safe_ptr<device_buffer>>& textures) \r
: desc_(desc)\r
, buffers_(buffers)\r
- , tag_(tag){}\r
+ , textures_(textures)\r
+ , tag_(tag)\r
+ {}\r
\r
void accept(write_frame& self, core::frame_visitor& visitor)\r
{\r
auto ptr = static_cast<const unsigned char*>(buffers_[index]->data());\r
return boost::iterator_range<const unsigned char*>(ptr, ptr+buffers_[index]->size());\r
}\r
+\r
+ void commit()\r
+ {\r
+ for(size_t n = 0; n < buffers_.size(); ++n)\r
+ commit(n);\r
+ }\r
+\r
+ void commit(size_t plane_index)\r
+ {\r
+ if(plane_index >= buffers_.size())\r
+ return;\r
+ \r
+ auto texture = textures_[plane_index];\r
+ auto buffer = std::move(buffers_[plane_index]);\r
+\r
+ ogl_device::begin_invoke([=]\r
+ {\r
+ texture->read(*buffer);\r
+ });\r
+ }\r
};\r
\r
-write_frame::write_frame(int tag, const core::pixel_format_desc& desc, const std::vector<safe_ptr<host_buffer>>& buffers) : impl_(new implementation(tag, desc, buffers)){}\r
+write_frame::write_frame(int tag, const core::pixel_format_desc& desc, const std::vector<safe_ptr<host_buffer>>& buffers, const std::vector<safe_ptr<device_buffer>>& textures) : impl_(new implementation(tag, desc, buffers, textures)){}\r
void write_frame::accept(core::frame_visitor& visitor){impl_->accept(*this, visitor);}\r
\r
boost::iterator_range<unsigned char*> write_frame::image_data(size_t index){return impl_->image_data(index);}\r
}\r
int write_frame::tag() const {return impl_->tag_;}\r
const core::pixel_format_desc& write_frame::get_pixel_format_desc() const{return impl_->desc_;}\r
-const std::vector<safe_ptr<host_buffer>>& write_frame::get_plane_buffers() const{return impl_->buffers_;}\r
+const std::vector<safe_ptr<device_buffer>>& write_frame::get_textures() const{return impl_->textures_;}\r
+const std::vector<safe_ptr<host_buffer>>& write_frame::get_buffers() const{return impl_->buffers_;}\r
+void write_frame::commit(size_t plane_index){impl_->commit(plane_index);}\r
+void write_frame::commit(){impl_->commit();}\r
}}
\ No newline at end of file
#include <core/producer/frame/pixel_format.h>\r
\r
#include "gpu/host_buffer.h"\r
+#include "gpu/device_buffer.h"\r
\r
#include <boost/noncopyable.hpp>\r
#include <boost/range/iterator_range.hpp>\r
class write_frame : public core::basic_frame, boost::noncopyable\r
{\r
public: \r
- explicit write_frame(int tag, const core::pixel_format_desc& desc, const std::vector<safe_ptr<host_buffer>>& buffers);\r
+ explicit write_frame(int tag, const core::pixel_format_desc& desc, const std::vector<safe_ptr<host_buffer>>& buffers, const std::vector<safe_ptr<device_buffer>>& textures);\r
\r
// core::write_frame\r
virtual boost::iterator_range<unsigned char*> image_data(size_t plane_index = 0); \r
virtual const boost::iterator_range<const unsigned char*> image_data(size_t plane_index = 0) const;\r
virtual const boost::iterator_range<const short*> audio_data() const;\r
\r
+ void commit(size_t plane_index);\r
+ void commit();\r
+\r
virtual void accept(core::frame_visitor& visitor);\r
\r
virtual int tag() const;\r
friend class image_mixer;\r
\r
const core::pixel_format_desc& get_pixel_format_desc() const;\r
- const std::vector<safe_ptr<host_buffer>>& get_plane_buffers() const;\r
+ const std::vector<safe_ptr<device_buffer>>& get_textures() const;\r
+ const std::vector<safe_ptr<host_buffer>>& get_buffers() const;\r
\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
}\r
});\r
\r
+ frame->commit();\r
+\r
// It is assumed that audio is always equal or ahead of video.\r
if(audio && SUCCEEDED(audio->GetBytes(&bytes)))\r
{\r
(\r
[&]\r
{\r
- if(video_decoder_ && video_frames_.empty())\r
+ if(video_decoder_ && video_frames_.size() < 2)\r
video_frames_ = video_decoder_->receive(); \r
}, \r
[&]\r
{\r
- if(audio_decoder_ && audio_chunks_.empty())\r
+ if(audio_decoder_ && audio_chunks_.size() < 2)\r
audio_chunks_ = audio_decoder_->receive(); \r
}\r
);\r
\r
#include <tbb/parallel_for.h>\r
\r
+#include <boost/range/algorithm_ext.hpp>\r
+\r
#if defined(_MSC_VER)\r
#pragma warning (push)\r
#pragma warning (disable : 4244)\r
\r
std::shared_ptr<AVPacket> pkt;\r
for(int n = 0; n < 32 && result.empty() && input_.try_pop_video_packet(pkt); ++n) \r
- result = decode(pkt);\r
+ boost::range::push_back(result, decode(pkt));\r
\r
return result;\r
}\r
for(size_t y = r.begin(); y != r.end(); ++y)\r
memcpy(result + y*plane.linesize, decoded + y*decoded_linesize, plane.linesize);\r
});\r
+\r
+ write->commit(n);\r
});\r
}\r
else\r
avpicture_fill(reinterpret_cast<AVPicture*>(av_frame.get()), write->image_data().begin(), PIX_FMT_BGRA, width_, height_);\r
\r
sws_scale(sws_context_.get(), decoded_frame->data, decoded_frame->linesize, 0, height_, av_frame->data, av_frame->linesize); \r
+\r
+ write->commit();\r
} \r
\r
// DVVIDEO is in lower field. Make it upper field if needed.\r
\r
auto frame = frame_factory_->create_frame(this);\r
fast_memcpy(frame->image_data().begin(), bmp_.data(), format_desc_.size);\r
+ frame->commit();\r
head_ = frame;\r
} \r
\r
FreeImage_FlipVertical(bitmap.get());\r
auto frame = frame_factory->create_frame(this, FreeImage_GetWidth(bitmap.get()), FreeImage_GetHeight(bitmap.get()));\r
std::copy_n(FreeImage_GetBits(bitmap.get()), frame->image_data().size(), frame->image_data().begin());\r
+ frame->commit();\r
frame_ = std::move(frame);\r
}\r
\r