]> 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/utility.h"\r
6 \r
7 namespace caspar {\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\r
65 {\r
66         implementation(size_t width, size_t height) \r
67                 : pbo_(0), data_(nullptr), width_(width), height_(height), size_(width*height*4), \r
68                 reading_(false), texture_(0), alpha_(1.0f), x_(0.0f), y_(0.0f), mode_(video_mode::progressive)\r
69         {       \r
70         }\r
71 \r
72         ~implementation()\r
73         {\r
74                 if(pbo_ != 0)\r
75                         glDeleteBuffers(1, &pbo_);\r
76                 if(texture_ != 0)\r
77                         glDeleteTextures(1, &texture_);\r
78         }\r
79 \r
80         GLuint pbo()\r
81         {               \r
82                 if(pbo_ == 0)\r
83                         CASPAR_GL_CHECK(glGenBuffers(1, &pbo_));\r
84                 return pbo_;\r
85         }\r
86 \r
87         void write_lock()\r
88         {\r
89                 if(texture_ == 0)\r
90                 {\r
91                         CASPAR_GL_CHECK(glGenTextures(1, &texture_));\r
92 \r
93                         CASPAR_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture_));\r
94 \r
95                         CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));\r
96                         CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));\r
97                         CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));\r
98                         CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));\r
99 \r
100                         CASPAR_GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width_, height_, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
101                 }\r
102 \r
103                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo()));\r
104                 if(data_ != nullptr)\r
105                 {\r
106                         CASPAR_GL_CHECK(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));\r
107                         data_ = nullptr;\r
108                 }\r
109                 CASPAR_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture_));\r
110                 CASPAR_GL_CHECK(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
111                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));\r
112         }\r
113 \r
114         bool write_unlock()\r
115         {\r
116                 if(data_ != nullptr)\r
117                         return false;\r
118                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo()));\r
119                 CASPAR_GL_CHECK(glBufferData(GL_PIXEL_UNPACK_BUFFER, size_, NULL, GL_STREAM_DRAW));\r
120                 void* ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);\r
121                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));\r
122                 data_ = reinterpret_cast<unsigned char*>(ptr);\r
123                 if(!data_)\r
124                         BOOST_THROW_EXCEPTION(std::bad_alloc());\r
125                 return true;\r
126         }\r
127         \r
128         void read_lock(GLenum mode)\r
129         {       \r
130                 CASPAR_GL_CHECK(glReadBuffer(mode));\r
131                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo()));\r
132                 if(data_ != nullptr)    \r
133                 {       \r
134                         CASPAR_GL_CHECK(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));   \r
135                         data_ = nullptr;\r
136                 }\r
137                 CASPAR_GL_CHECK(glBufferData(GL_PIXEL_PACK_BUFFER, size_, NULL, GL_STREAM_READ));       \r
138                 CASPAR_GL_CHECK(glReadPixels(0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
139                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));\r
140                 reading_ = true;\r
141         }\r
142 \r
143         bool read_unlock()\r
144         {\r
145                 if(data_ != nullptr || !reading_)\r
146                         return false;\r
147                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo()));\r
148                 void* ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);   \r
149                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));\r
150                 data_ = reinterpret_cast<unsigned char*>(ptr);\r
151                 if(!data_)\r
152                         BOOST_THROW_EXCEPTION(std::bad_alloc());\r
153                 reading_ = false;\r
154                 return true;\r
155         }\r
156 \r
157         void draw()\r
158         {\r
159                 glPushMatrix();\r
160                 glTranslatef(x_*2.0f, y_*2.0f, 0.0f);\r
161                 glColor4f(1.0f, 1.0f, 1.0f, alpha_);\r
162 \r
163                 if(mode_ == video_mode::progressive)\r
164                         glPolygonStipple(progressive_pattern);\r
165                 else if(mode_ == video_mode::upper)\r
166                         glPolygonStipple(upper_pattern);\r
167                 else if(mode_ == video_mode::lower)\r
168                         glPolygonStipple(lower_pattern);\r
169 \r
170                 CASPAR_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture_));\r
171                 glBegin(GL_QUADS);\r
172                         glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f);\r
173                         glTexCoord2f(1.0f, 0.0f); glVertex2f( 1.0f, -1.0f);\r
174                         glTexCoord2f(1.0f, 1.0f); glVertex2f( 1.0f,  1.0f);\r
175                         glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f,  1.0f);\r
176                 glEnd();\r
177                 glPopMatrix();\r
178         }\r
179                 \r
180         unsigned char* data()\r
181         {\r
182                 if(data_ == nullptr)\r
183                         BOOST_THROW_EXCEPTION(invalid_operation());\r
184                 return data_;\r
185         }\r
186 \r
187         void reset()\r
188         {\r
189                 audio_data_.clear();\r
190                 alpha_ = 1.0f;\r
191                 x_ = 0.0f;\r
192                 y_ = 0.0f;\r
193                 mode_ = video_mode::progressive;\r
194         }\r
195 \r
196         gpu_frame* self_;\r
197         GLuint pbo_;\r
198         GLuint texture_;\r
199         unsigned char* data_;\r
200         size_t width_;\r
201         size_t height_;\r
202         size_t size_;\r
203         bool reading_;\r
204         std::vector<short> audio_data_;\r
205 \r
206         float alpha_;\r
207         float x_;\r
208         float y_;\r
209         video_mode mode_;\r
210 };\r
211 \r
212 gpu_frame::gpu_frame(size_t width, size_t height) : impl_(new implementation(width, height)){}\r
213 void gpu_frame::write_lock(){impl_->write_lock();}\r
214 bool gpu_frame::write_unlock(){return impl_->write_unlock();}   \r
215 void gpu_frame::read_lock(GLenum mode){impl_->read_lock(mode);}\r
216 bool gpu_frame::read_unlock(){return impl_->read_unlock();}\r
217 void gpu_frame::draw(){impl_->draw();}\r
218 unsigned char* gpu_frame::data(){return impl_->data();}\r
219 size_t gpu_frame::size() const { return impl_->size_; }\r
220 size_t gpu_frame::width() const { return impl_->width_;}\r
221 size_t gpu_frame::height() const { return impl_->height_;}\r
222 const std::vector<short>& gpu_frame::audio_data() const { return impl_->audio_data_; }  \r
223 std::vector<short>& gpu_frame::audio_data() { return impl_->audio_data_; }\r
224 void gpu_frame::reset(){impl_->reset();}\r
225 float gpu_frame::alpha() const{ return impl_->alpha_;}\r
226 void gpu_frame::alpha(float value){ impl_->alpha_ = value;}\r
227 float gpu_frame::x() const { return impl_->x_;}\r
228 float gpu_frame::y() const { return impl_->y_;}\r
229 void gpu_frame::translate(float x, float y) { impl_->x_ += x; impl_->y_ += y; }\r
230 void gpu_frame::mode(video_mode mode){ impl_->mode_ = mode;}\r
231 video_mode gpu_frame::mode() const{ return impl_->mode_;}\r
232 }