]> git.sesse.net Git - casparcg/blob - core/frame/gpu_frame.cpp
2.0.0.2:
[casparcg] / core / frame / gpu_frame.cpp
1 #include "../StdAfx.h"\r
2 \r
3 #include "gpu_frame.h"\r
4 #include "../../common/utility/memory.h"\r
5 #include "../../common/gl/gl_check.h"\r
6 \r
7 namespace caspar { namespace core {\r
8         \r
9 GLubyte progressive_pattern[] = {\r
10         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
11         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
12         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
13         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
14         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
15         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
16         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
17         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
18         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
19         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
20         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
21         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
22         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
23         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
24         0xff, 0xff, 0xFF, 0xff, 0xff, 0xff, 0xff, 0xff,\r
25         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
26         \r
27 GLubyte upper_pattern[] = {\r
28         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
29         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
30         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
31         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
32         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
33         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
34         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
35         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
36         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
37         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
38         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
39         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
40         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
41         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
42         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
43         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00};\r
44                 \r
45 GLubyte lower_pattern[] = {\r
46                                                         0x00, 0x00, 0x00, 0x00,\r
47         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
48         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
49         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
50         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
51         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
52         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
53         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
54         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
55         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
56         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
57         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
58         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
59         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
60         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
61         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
62         0xff, 0xff, 0xff, 0xff};\r
63                                                                                                                                                                                                                                                                                                                 \r
64 struct gpu_frame::implementation : boost::noncopyable\r
65 {\r
66         implementation(size_t width, size_t height) \r
67                 : pbo_(0), data_(nullptr), width_(width), height_(height), \r
68                         size_(width*height*4), reading_(false), texture_(0), alpha_(1.0f), \r
69                         x_(0.0f), y_(0.0f), mode_(video_mode::progressive)\r
70         {       \r
71         }\r
72 \r
73         ~implementation()\r
74         {\r
75                 if(pbo_ != 0)\r
76                         glDeleteBuffers(1, &pbo_);\r
77                 if(texture_ != 0)\r
78                         glDeleteTextures(1, &texture_);\r
79         }\r
80 \r
81         GLuint pbo()\r
82         {               \r
83                 if(pbo_ == 0)\r
84                         GL(glGenBuffers(1, &pbo_));\r
85                 return pbo_;\r
86         }\r
87 \r
88         void write_lock()\r
89         {\r
90                 if(texture_ == 0)\r
91                 {\r
92                         GL(glGenTextures(1, &texture_));\r
93 \r
94                         GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
95 \r
96                         GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));\r
97                         GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));\r
98                         GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));\r
99                         GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));\r
100 \r
101                         GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width_, height_, 0, GL_BGRA, \r
102                                                                 GL_UNSIGNED_BYTE, NULL));\r
103                 }\r
104 \r
105                 GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo()));\r
106                 if(data_ != nullptr)\r
107                 {\r
108                         GL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));\r
109                         data_ = nullptr;\r
110                 }\r
111                 GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
112                 GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA, \r
113                                                         GL_UNSIGNED_BYTE, NULL));\r
114                 GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));\r
115         }\r
116 \r
117         bool write_unlock()\r
118         {\r
119                 if(data_ != nullptr)\r
120                         return false;\r
121                 GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo()));\r
122                 GL(glBufferData(GL_PIXEL_UNPACK_BUFFER, size_, NULL, GL_STREAM_DRAW));\r
123                 void* ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);\r
124                 GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));\r
125                 data_ = reinterpret_cast<unsigned char*>(ptr);\r
126                 if(!data_)\r
127                         BOOST_THROW_EXCEPTION(invalid_operation() \r
128                                                                         << msg_info("glMapBuffer failed"));\r
129                 return true;\r
130         }\r
131         \r
132         void read_lock(GLenum mode)\r
133         {       \r
134                 GL(glReadBuffer(mode));\r
135                 GL(glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo()));\r
136                 if(data_ != nullptr)    \r
137                 {       \r
138                         GL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));        \r
139                         data_ = nullptr;\r
140                 }\r
141                 GL(glBufferData(GL_PIXEL_PACK_BUFFER, size_, NULL, GL_STREAM_READ));    \r
142                 GL(glReadPixels(0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
143                 GL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));\r
144                 reading_ = true;\r
145         }\r
146 \r
147         bool read_unlock()\r
148         {\r
149                 if(data_ != nullptr || !reading_)\r
150                         return false;\r
151                 GL(glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo()));\r
152                 void* ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);   \r
153                 GL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));\r
154                 data_ = reinterpret_cast<unsigned char*>(ptr);\r
155                 if(!data_)\r
156                         BOOST_THROW_EXCEPTION(std::bad_alloc());\r
157                 reading_ = false;\r
158                 return true;\r
159         }\r
160 \r
161         void draw()\r
162         {\r
163                 glPushMatrix();\r
164                 glTranslated(x_*2.0, y_*2.0, 0.0);\r
165                 glColor4d(1.0, 1.0, 1.0, alpha_);\r
166 \r
167                 if(mode_ == video_mode::progressive)\r
168                         glPolygonStipple(progressive_pattern);\r
169                 else if(mode_ == video_mode::upper)\r
170                         glPolygonStipple(upper_pattern);\r
171                 else if(mode_ == video_mode::lower)\r
172                         glPolygonStipple(lower_pattern);\r
173 \r
174                 GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
175                 glBegin(GL_QUADS);\r
176                         glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f);\r
177                         glTexCoord2f(1.0f, 0.0f); glVertex2f( 1.0f, -1.0f);\r
178                         glTexCoord2f(1.0f, 1.0f); glVertex2f( 1.0f,  1.0f);\r
179                         glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f,  1.0f);\r
180                 glEnd();\r
181                 glPopMatrix();\r
182         }\r
183                 \r
184         unsigned char* data()\r
185         {\r
186                 if(data_ == nullptr)\r
187                         BOOST_THROW_EXCEPTION(invalid_operation());\r
188                 return data_;\r
189         }\r
190 \r
191         void reset()\r
192         {\r
193                 audio_data_.clear();\r
194                 alpha_ = 1.0f;\r
195                 x_     = 0.0f;\r
196                 y_     = 0.0f;\r
197                 mode_  = video_mode::progressive;\r
198         }\r
199 \r
200         gpu_frame* self_;\r
201         GLuint pbo_;\r
202         GLuint texture_;\r
203         unsigned char* data_;\r
204         size_t width_;\r
205         size_t height_;\r
206         size_t size_;\r
207         bool reading_;\r
208         std::vector<short> audio_data_;\r
209 \r
210         double alpha_;\r
211         double x_;\r
212         double y_;\r
213         video_mode mode_;\r
214 };\r
215 \r
216 gpu_frame::gpu_frame(size_t width, size_t height) \r
217         : impl_(new implementation(width, height)){}\r
218 void gpu_frame::write_lock(){impl_->write_lock();}\r
219 bool gpu_frame::write_unlock(){return impl_->write_unlock();}   \r
220 void gpu_frame::read_lock(GLenum mode){impl_->read_lock(mode);}\r
221 bool gpu_frame::read_unlock(){return impl_->read_unlock();}\r
222 void gpu_frame::draw(){impl_->draw();}\r
223 unsigned char* gpu_frame::data(){return impl_->data();}\r
224 size_t gpu_frame::size() const { return impl_->size_; }\r
225 size_t gpu_frame::width() const { return impl_->width_;}\r
226 size_t gpu_frame::height() const { return impl_->height_;}\r
227 const std::vector<short>& gpu_frame::audio_data() const{return impl_->audio_data_;}     \r
228 std::vector<short>& gpu_frame::audio_data() { return impl_->audio_data_; }\r
229 void gpu_frame::reset(){impl_->reset();}\r
230 double gpu_frame::alpha() const{ return impl_->alpha_;}\r
231 void gpu_frame::alpha(double value){ impl_->alpha_ = value;}\r
232 double gpu_frame::x() const { return impl_->x_;}\r
233 double gpu_frame::y() const { return impl_->y_;}\r
234 void gpu_frame::translate(double x, double y) { impl_->x_ += x; impl_->y_ += y; }\r
235 void gpu_frame::mode(video_mode mode){ impl_->mode_ = mode;}\r
236 video_mode gpu_frame::mode() const{ return impl_->mode_;}\r
237 }}