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
33 #include <boost/thread.hpp>
\r
36 #include <SFML/Window.hpp>
\r
38 #include <windows.h>
\r
40 namespace caspar{ namespace ogl{
\r
44 if(glGetError() != GL_NO_ERROR)
\r
45 BOOST_THROW_EXCEPTION(ogl_error() << msg_info(boost::lexical_cast<std::string>(glGetError())));
\r
48 struct consumer::implementation : boost::noncopyable
\r
50 implementation(const frame_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed)
\r
51 : format_desc_(format_desc), stretch_(stretch), texture_(0), pbo_index_(0), screen_width_(0), screen_height_(0), windowed_(windowed)
\r
53 pbos_[0] = pbos_[1] = 0;
\r
56 DISPLAY_DEVICE dDevice;
\r
57 memset(&dDevice,0,sizeof(dDevice));
\r
58 dDevice.cb = sizeof(dDevice);
\r
60 std::vector<DISPLAY_DEVICE> displayDevices;
\r
61 for(int n = 0; EnumDisplayDevices(NULL, n, &dDevice, NULL); ++n)
\r
63 displayDevices.push_back(dDevice);
\r
64 memset(&dDevice,0,sizeof(dDevice));
\r
65 dDevice.cb = sizeof(dDevice);
\r
68 if(screen_index >= displayDevices.size())
\r
69 BOOST_THROW_EXCEPTION(out_of_range() << arg_name_info("screen_index_"));
\r
72 memset(&devmode,0,sizeof(devmode));
\r
74 if(!EnumDisplaySettings(displayDevices[screen_index].DeviceName, ENUM_CURRENT_SETTINGS, &devmode))
\r
75 BOOST_THROW_EXCEPTION(invalid_operation() << arg_name_info("screen_index") << msg_info("EnumDisplaySettings"));
\r
77 screen_width_ = windowed ? format_desc_.width : devmode.dmPelsWidth;
\r
78 screen_height_ = windowed ? format_desc_.height : devmode.dmPelsHeight;
\r
79 screenX_ = devmode.dmPosition.x;
\r
80 screenY_ = devmode.dmPosition.y;
\r
83 BOOST_THROW_EXCEPTION(not_supported() << msg_info("OGLConsumer doesn't support non-Win32 fullscreen"));
\r
85 if(screen_index != 0)
\r
86 CASPAR_LOG(warning) << "OGLConsumer only supports screen_index=0 for non-Win32";
\r
88 screen_width_ = format_desc_.width;
\r
89 screen_height_ = format_desc_.height;
\r
93 frame_buffer_.set_capacity(1);
\r
94 thread_ = boost::thread([=]{run();});
\r
99 frame_buffer_.push(nullptr),
\r
103 glDeleteTextures(1, &texture_);
\r
104 if(pbos_[0] && pbos_[1])
\r
105 glDeleteBuffers(2, pbos_);
\r
110 window_.reset(new sf::Window());
\r
111 window_->Create(sf::VideoMode(format_desc_.width, format_desc_.height, 32), "CasparCG", windowed_ ? sf::Style::Titlebar : sf::Style::Fullscreen);
\r
112 window_->ShowMouseCursor(false);
\r
113 window_->SetPosition(screenX_, screenY_);
\r
114 window_->SetSize(screen_width_, screen_height_);
\r
115 window_->SetActive();
\r
117 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
\r
118 glEnable(GL_TEXTURE_2D);
\r
120 glViewport(0, 0, screen_width_, screen_height_);
\r
124 std::pair<float, float> target_ratio = None();
\r
125 if(stretch_ == ogl::fill)
\r
126 target_ratio = Fill();
\r
127 else if(stretch_ == ogl::uniform)
\r
128 target_ratio = Uniform();
\r
129 else if(stretch_ == ogl::uniform_to_fill)
\r
130 target_ratio = UniformToFill();
\r
132 float wSize = target_ratio.first;
\r
133 float hSize = target_ratio.second;
\r
135 dlist_ = glGenLists(1);
\r
138 glNewList(dlist_, GL_COMPILE);
\r
140 glTexCoord2f(0.0f, 1.0f); glVertex2f(-wSize, -hSize);
\r
141 glTexCoord2f(1.0f, 1.0f); glVertex2f( wSize, -hSize);
\r
142 glTexCoord2f(1.0f, 0.0f); glVertex2f( wSize, hSize);
\r
143 glTexCoord2f(0.0f, 0.0f); glVertex2f(-wSize, hSize);
\r
148 glGenTextures(1, &texture_);
\r
151 glBindTexture( GL_TEXTURE_2D, texture_);
\r
154 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
\r
155 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
\r
156 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
\r
157 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
\r
159 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, format_desc_.width, format_desc_.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
\r
162 glGenBuffersARB(2, pbos_);
\r
164 glBindBuffer(GL_PIXEL_PACK_BUFFER, pbos_[0]);
\r
165 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, format_desc_.size, 0, GL_STREAM_DRAW);
\r
166 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbos_[1]);
\r
167 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, format_desc_.size, 0, GL_STREAM_DRAW);
\r
172 std::pair<float, float> None()
\r
174 float width = static_cast<float>(format_desc_.width)/static_cast<float>(screen_width_);
\r
175 float height = static_cast<float>(format_desc_.height)/static_cast<float>(screen_height_);
\r
177 return std::make_pair(width, height);
\r
180 std::pair<float, float> Uniform()
\r
182 float aspect = static_cast<float>(format_desc_.width)/static_cast<float>(format_desc_.height);
\r
183 float width = std::min(1.0f, static_cast<float>(screen_height_)*aspect/static_cast<float>(screen_width_));
\r
184 float height = static_cast<float>(screen_width_*width)/static_cast<float>(screen_height_*aspect);
\r
186 return std::make_pair(width, height);
\r
189 std::pair<float, float> Fill()
\r
191 return std::make_pair(1.0f, 1.0f);
\r
194 std::pair<float, float> UniformToFill()
\r
196 float wr = static_cast<float>(format_desc_.width)/static_cast<float>(screen_width_);
\r
197 float hr = static_cast<float>(format_desc_.height)/static_cast<float>(screen_height_);
\r
198 float r_inv = 1.0f/std::min(wr, hr);
\r
200 float width = wr*r_inv;
\r
201 float height = hr*r_inv;
\r
203 return std::make_pair(width, height);
\r
206 void render(const gpu_frame_ptr& frame)
\r
209 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
\r
210 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
\r
213 glBindTexture(GL_TEXTURE_2D, texture_);
\r
214 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbos_[pbo_index_]);
\r
216 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, format_desc_.width, format_desc_.height, GL_BGRA, GL_UNSIGNED_BYTE, 0);
\r
218 glCallList(dlist_);
\r
221 int nextPboIndex = pbo_index_ ^ 1;
\r
223 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbos_[nextPboIndex]);
\r
224 glBufferData(GL_PIXEL_UNPACK_BUFFER, format_desc_.size, NULL, GL_STREAM_DRAW);
\r
225 GLubyte* ptr = static_cast<GLubyte*>(glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));
\r
229 common::copy(ptr, frame->data(), frame->size());
\r
230 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
\r
234 pbo_index_ = nextPboIndex;
\r
237 void display(const gpu_frame_ptr& frame)
\r
239 if(frame == nullptr)
\r
242 if(exception_ != nullptr)
\r
243 std::rethrow_exception(exception_);
\r
245 frame_buffer_.push(frame);
\r
252 gpu_frame_ptr frame;
\r
257 frame_buffer_.pop(frame);
\r
258 if(frame != nullptr)
\r
261 while(window_->GetEvent(e)){}
\r
262 window_->SetActive();
\r
264 window_->Display();
\r
269 exception_ = std::current_exception();
\r
272 while(frame != nullptr);
\r
280 unsigned int screen_width_;
\r
281 unsigned int screen_height_;
\r
282 unsigned int screenX_;
\r
283 unsigned int screenY_;
\r
288 std::unique_ptr<sf::Window> window_;
\r
290 caspar::frame_format_desc format_desc_;
\r
292 std::exception_ptr exception_;
\r
293 boost::thread thread_;
\r
294 tbb::concurrent_bounded_queue<gpu_frame_ptr> frame_buffer_;
\r
297 consumer::consumer(const caspar::frame_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed)
\r
298 : impl_(new implementation(format_desc, screen_index, stretch, windowed)){}
\r
299 const caspar::frame_format_desc& consumer::get_frame_format_desc() const{return impl_->format_desc_;}
\r
300 void consumer::display(const gpu_frame_ptr& frame){impl_->display(frame);}
\r