2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>
\r
4 * This file is part of CasparCG.
\r
6 * CasparCG is free software: you can redistribute it and/or modify
\r
7 * it under the terms of the GNU General Public License as published by
\r
8 * the Free Software Foundation, either version 3 of the License, or
\r
9 * (at your option) any later version.
\r
11 * CasparCG is distributed in the hope that it will be useful,
\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 * GNU General Public License for more details.
\r
16 * You should have received a copy of the GNU General Public License
\r
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
\r
21 #include "../../StdAfx.h"
\r
23 #if defined(_MSC_VER)
\r
24 #pragma warning (disable : 4244)
\r
27 #include "ogl_consumer.h"
\r
29 #include "../../frame/frame_format.h"
\r
30 #include "../../frame/gpu_frame.h"
\r
31 #include "../../../common/utility/memory.h"
\r
32 #include "../../../common/gl/gl_check.h"
\r
33 #include "../../../common/gl/pixel_buffer_object.h"
\r
35 #include <boost/thread.hpp>
\r
38 #include <SFML/Window.hpp>
\r
40 #include <windows.h>
\r
42 namespace caspar { namespace core { namespace ogl{
\r
44 struct consumer::implementation : boost::noncopyable
\r
46 implementation(const frame_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed)
\r
47 : index_(0), format_desc_(format_desc), stretch_(stretch), screen_width_(0), screen_height_(0), windowed_(windowed)
\r
50 DISPLAY_DEVICE dDevice;
\r
51 memset(&dDevice,0,sizeof(dDevice));
\r
52 dDevice.cb = sizeof(dDevice);
\r
54 std::vector<DISPLAY_DEVICE> displayDevices;
\r
55 for(int n = 0; EnumDisplayDevices(NULL, n, &dDevice, NULL); ++n)
\r
57 displayDevices.push_back(dDevice);
\r
58 memset(&dDevice,0,sizeof(dDevice));
\r
59 dDevice.cb = sizeof(dDevice);
\r
62 if(screen_index >= displayDevices.size())
\r
63 BOOST_THROW_EXCEPTION(out_of_range() << arg_name_info("screen_index_"));
\r
66 memset(&devmode,0,sizeof(devmode));
\r
68 if(!EnumDisplaySettings(displayDevices[screen_index].DeviceName, ENUM_CURRENT_SETTINGS, &devmode))
\r
69 BOOST_THROW_EXCEPTION(invalid_operation() << arg_name_info("screen_index") << msg_info("EnumDisplaySettings"));
\r
71 screen_width_ = windowed ? format_desc_.width : devmode.dmPelsWidth;
\r
72 screen_height_ = windowed ? format_desc_.height : devmode.dmPelsHeight;
\r
73 screenX_ = devmode.dmPosition.x;
\r
74 screenY_ = devmode.dmPosition.y;
\r
77 BOOST_THROW_EXCEPTION(not_supported() << msg_info("OGLConsumer doesn't support non-Win32 fullscreen"));
\r
79 if(screen_index != 0)
\r
80 CASPAR_LOG(warning) << "OGLConsumer only supports screen_index=0 for non-Win32";
\r
82 screen_width_ = format_desc_.width;
\r
83 screen_height_ = format_desc_.height;
\r
87 frame_buffer_.set_capacity(1);
\r
88 thread_ = boost::thread([=]{run();});
\r
93 frame_buffer_.push(nullptr),
\r
99 window_.Create(sf::VideoMode(format_desc_.width, format_desc_.height, 32), "CasparCG", windowed_ ? sf::Style::Titlebar : sf::Style::Fullscreen);
\r
100 window_.ShowMouseCursor(false);
\r
101 window_.SetPosition(screenX_, screenY_);
\r
102 window_.SetSize(screen_width_, screen_height_);
\r
103 window_.SetActive();
\r
104 GL(glEnable(GL_TEXTURE_2D));
\r
105 GL(glDisable(GL_DEPTH_TEST));
\r
106 GL(glClearColor(0.0, 0.0, 0.0, 0.0));
\r
107 GL(glViewport(0, 0, format_desc_.width, format_desc_.height));
\r
110 wratio_ = static_cast<float>(format_desc_.width)/static_cast<float>(format_desc_.width);
\r
111 hratio_ = static_cast<float>(format_desc_.height)/static_cast<float>(format_desc_.height);
\r
113 std::pair<float, float> target_ratio = None();
\r
114 if(stretch_ == ogl::fill)
\r
115 target_ratio = Fill();
\r
116 else if(stretch_ == ogl::uniform)
\r
117 target_ratio = Uniform();
\r
118 else if(stretch_ == ogl::uniform_to_fill)
\r
119 target_ratio = UniformToFill();
\r
121 wSize_ = target_ratio.first;
\r
122 hSize_ = target_ratio.second;
\r
124 pbos_[0].create(format_desc_.width, format_desc_.height);
\r
125 pbos_[1].create(format_desc_.width, format_desc_.height);
\r
128 std::pair<float, float> None()
\r
130 float width = static_cast<float>(format_desc_.width)/static_cast<float>(screen_width_);
\r
131 float height = static_cast<float>(format_desc_.height)/static_cast<float>(screen_height_);
\r
133 return std::make_pair(width, height);
\r
136 std::pair<float, float> Uniform()
\r
138 float aspect = static_cast<float>(format_desc_.width)/static_cast<float>(format_desc_.height);
\r
139 float width = std::min(1.0f, static_cast<float>(screen_height_)*aspect/static_cast<float>(screen_width_));
\r
140 float height = static_cast<float>(screen_width_*width)/static_cast<float>(screen_height_*aspect);
\r
142 return std::make_pair(width, height);
\r
145 std::pair<float, float> Fill()
\r
147 return std::make_pair(1.0f, 1.0f);
\r
150 std::pair<float, float> UniformToFill()
\r
152 float wr = static_cast<float>(format_desc_.width)/static_cast<float>(screen_width_);
\r
153 float hr = static_cast<float>(format_desc_.height)/static_cast<float>(screen_height_);
\r
154 float r_inv = 1.0f/std::min(wr, hr);
\r
156 float width = wr*r_inv;
\r
157 float height = hr*r_inv;
\r
159 return std::make_pair(width, height);
\r
162 void render(const gpu_frame_ptr& frame)
\r
164 index_ = (index_ + 1) % 2;
\r
165 int next_index = (index_ + 1) % 2;
\r
167 auto ptr = pbos_[index_].end_write();
\r
168 common::aligned_memcpy(ptr, frame->data(), frame->size());
\r
170 GL(glClear(GL_COLOR_BUFFER_BIT));
\r
171 pbos_[next_index].bind_texture();
\r
173 glTexCoord2f(0.0f, hratio_); glVertex2f(-wSize_, -hSize_);
\r
174 glTexCoord2f(wratio_, hratio_); glVertex2f( wSize_, -hSize_);
\r
175 glTexCoord2f(wratio_, 0.0f); glVertex2f( wSize_, hSize_);
\r
176 glTexCoord2f(0.0f, 0.0f); glVertex2f(-wSize_, hSize_);
\r
179 pbos_[next_index].begin_write();
\r
182 void display(const gpu_frame_ptr& frame)
\r
184 if(frame == nullptr)
\r
187 if(exception_ != nullptr)
\r
188 std::rethrow_exception(exception_);
\r
190 frame_buffer_.push(frame);
\r
197 gpu_frame_ptr frame;
\r
202 frame_buffer_.pop(frame);
\r
203 if(frame != nullptr)
\r
206 while(window_.GetEvent(e)){}
\r
207 window_.SetActive();
\r
214 exception_ = std::current_exception();
\r
217 while(frame != nullptr);
\r
227 common::gl::pixel_buffer_object pbos_[2];
\r
230 unsigned int screen_width_;
\r
231 unsigned int screen_height_;
\r
232 unsigned int screenX_;
\r
233 unsigned int screenY_;
\r
236 frame_format_desc format_desc_;
\r
238 std::exception_ptr exception_;
\r
239 boost::thread thread_;
\r
240 tbb::concurrent_bounded_queue<gpu_frame_ptr> frame_buffer_;
\r
242 sf::Window window_;
\r
245 consumer::consumer(const frame_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed)
\r
246 : impl_(new implementation(format_desc, screen_index, stretch, windowed)){}
\r
247 const frame_format_desc& consumer::get_frame_format_desc() const{return impl_->format_desc_;}
\r
248 void consumer::display(const gpu_frame_ptr& frame){impl_->display(frame);}
\r