1 #include "../StdAfx.h"
\r
3 #include "gpu_frame_processor.h"
\r
5 #include "gpu_frame.h"
\r
6 #include "gpu_composite_frame.h"
\r
7 #include "frame_format.h"
\r
9 #include "../../common/exception/exceptions.h"
\r
10 #include "../../common/concurrency/executor.h"
\r
11 #include "../../common/utility/memory.h"
\r
12 #include "../../common/gl/gl_check.h"
\r
13 #include "../../common/gl/frame_buffer_object.h"
\r
16 #include <SFML/Window.hpp>
\r
18 #include <tbb/concurrent_queue.h>
\r
19 #include <tbb/concurrent_unordered_map.h>
\r
21 #include <boost/lexical_cast.hpp>
\r
22 #include <boost/thread/once.hpp>
\r
23 #include <boost/thread.hpp>
\r
24 #include <boost/range.hpp>
\r
25 #include <boost/foreach.hpp>
\r
26 #include <boost/range/algorithm_ext/erase.hpp>
\r
27 #include <boost/range/algorithm.hpp>
\r
29 #include <functional>
\r
30 #include <unordered_map>
\r
33 namespace caspar { namespace core {
\r
35 struct gpu_frame_processor::implementation : boost::noncopyable
\r
37 implementation(const frame_format_desc& format_desc)
\r
38 : format_desc_(format_desc), index_(0)
\r
40 input_.set_capacity(2);
\r
42 executor_.begin_invoke([=]
\r
44 ogl_context_.reset(new sf::Context());
\r
45 ogl_context_->SetActive(true);
\r
46 GL(glEnable(GL_POLYGON_STIPPLE));
\r
47 GL(glEnable(GL_TEXTURE_2D));
\r
48 GL(glEnable(GL_BLEND));
\r
49 GL(glDisable(GL_DEPTH_TEST));
\r
50 GL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
\r
51 GL(glClearColor(0.0, 0.0, 0.0, 0.0));
\r
52 GL(glViewport(0, 0, format_desc_.width, format_desc_.height));
\r
55 fbo_.create(format_desc_.width, format_desc_.height);
\r
56 fbo_.bind_pixel_source();
\r
58 writing_.resize(2, std::make_shared<gpu_composite_frame>());
\r
61 for(int n = 0; n < 2; ++n)
\r
62 composite(std::vector<gpu_frame_ptr>());
\r
71 void composite(std::vector<gpu_frame_ptr> frames)
\r
73 boost::range::remove_erase(frames, nullptr);
\r
74 boost::range::remove_erase(frames, gpu_frame::null());
\r
75 auto composite_frame = std::make_shared<gpu_composite_frame>();
\r
76 boost::range::for_each(frames, std::bind(&gpu_composite_frame::add,
\r
78 std::placeholders::_1));
\r
80 input_.push(composite_frame);
\r
81 executor_.begin_invoke([=]
\r
85 gpu_frame_ptr frame;
\r
88 index_ = (index_ + 1) % 2;
\r
89 int next_index = (index_ + 1) % 2;
\r
91 // 1. Start asynchronous DMA transfer to video memory.
\r
92 writing_[index_] = std::move(frame);
\r
93 // Lock frame and give pointer ownership to OpenGL.
\r
94 writing_[index_]->begin_write();
\r
96 // 3. Output to external buffer.
\r
99 output_frame_->end_read();
\r
100 output_.push(output_frame_);
\r
103 // Clear framebuffer.
\r
104 GL(glClear(GL_COLOR_BUFFER_BIT));
\r
106 // 2. Draw to framebuffer and start asynchronous DMA transfer
\r
107 // to page-locked memory.
\r
108 writing_[next_index]->draw();
\r
110 // Create an output frame
\r
111 auto temp_frame = create_output_frame();
\r
113 // Read from framebuffer into page-locked memory.
\r
114 temp_frame->begin_read();
\r
115 temp_frame->audio_data() = std::move(writing_[next_index]->audio_data());
\r
117 output_frame_ = temp_frame;
\r
119 // Return frames to pool.
\r
120 writing_[next_index]->end_write();
\r
121 writing_[next_index] = nullptr;
\r
125 CASPAR_LOG_CURRENT_EXCEPTION();
\r
130 gpu_frame_ptr create_output_frame()
\r
132 gpu_frame_ptr frame;
\r
133 if(!reading_pool_.try_pop(frame))
\r
134 frame.reset(new gpu_frame(format_desc_.width, format_desc_.height));
\r
136 return gpu_frame_ptr(frame.get(), [=](gpu_frame*)
\r
139 reading_pool_.push(frame);
\r
143 gpu_frame_ptr create_frame(size_t width, size_t height)
\r
145 size_t key = width | (height << 16);
\r
146 auto& pool = writing_pools_[key];
\r
148 gpu_frame_ptr frame;
\r
149 if(!pool.try_pop(frame))
\r
151 frame = executor_.invoke([&]
\r
153 return std::shared_ptr<gpu_frame>(new gpu_frame(width, height));
\r
157 auto destructor = [=]
\r
160 writing_pools_[key].push(frame);
\r
163 return gpu_frame_ptr(frame.get(), [=](gpu_frame*)
\r
165 executor_.begin_invoke(destructor);
\r
169 void pop(gpu_frame_ptr& frame)
\r
171 output_.pop(frame);
\r
174 typedef tbb::concurrent_bounded_queue<gpu_frame_ptr> gpu_frame_queue;
\r
175 tbb::concurrent_unordered_map<size_t, gpu_frame_queue> writing_pools_;
\r
176 gpu_frame_queue reading_pool_;
\r
178 gpu_frame_queue input_;
\r
179 std::vector<gpu_frame_ptr> writing_;
\r
180 gpu_frame_queue output_;
\r
184 gpu_frame_ptr output_frame_;
\r
185 frame_format_desc format_desc_;
\r
187 std::unique_ptr<sf::Context> ogl_context_;
\r
189 common::executor executor_;
\r
191 common::gl::frame_buffer_object fbo_;
\r
194 gpu_frame_processor::gpu_frame_processor(const frame_format_desc& format_desc) : impl_(new implementation(format_desc)){}
\r
195 void gpu_frame_processor::push(const std::vector<gpu_frame_ptr>& frames){ impl_->composite(frames);}
\r
196 void gpu_frame_processor::pop(gpu_frame_ptr& frame){impl_->pop(frame);}
\r
197 gpu_frame_ptr gpu_frame_processor::create_frame(size_t width, size_t height){return impl_->create_frame(width, height);}
\r