]> git.sesse.net Git - casparcg/blob - core/frame/gpu_frame.cpp
ddb085b758e4cc3bd0db4a9d2acd74b9a337ae5d
[casparcg] / core / frame / gpu_frame.cpp
1 #include "../StdAfx.h"\r
2 \r
3 #include "gpu_frame.h"\r
4 #include "../../common/image/copy.h"\r
5 #include "../../common/gl/utility.h"\r
6 \r
7 namespace caspar {\r
8         \r
9 struct gpu_frame::implementation\r
10 {\r
11         implementation(size_t width, size_t height) \r
12                 : pbo_(0), data_(nullptr), width_(width), height_(height), size_(width*height*4), reading_(false), texture_(0), alpha_(1.0f)\r
13         {       \r
14         }\r
15 \r
16         ~implementation()\r
17         {\r
18                 if(pbo_ != 0)\r
19                         glDeleteBuffers(1, &pbo_);\r
20                 if(texture_ != 0)\r
21                         glDeleteTextures(1, &texture_);\r
22         }\r
23 \r
24         GLuint pbo()\r
25         {               \r
26                 if(pbo_ == 0)\r
27                         CASPAR_GL_CHECK(glGenBuffers(1, &pbo_));\r
28                 return pbo_;\r
29         }\r
30 \r
31         void write_lock()\r
32         {\r
33                 if(texture_ == 0)\r
34                 {\r
35                         CASPAR_GL_CHECK(glGenTextures(1, &texture_));\r
36 \r
37                         CASPAR_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture_));\r
38 \r
39                         CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));\r
40                         CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));\r
41                         CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));\r
42                         CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));\r
43 \r
44                         CASPAR_GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width_, height_, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
45                 }\r
46 \r
47                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo()));\r
48                 if(data_ != nullptr)\r
49                 {\r
50                         CASPAR_GL_CHECK(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));\r
51                         data_ = nullptr;\r
52                 }\r
53                 CASPAR_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture_));\r
54                 CASPAR_GL_CHECK(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
55                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));\r
56         }\r
57 \r
58         bool write_unlock()\r
59         {\r
60                 if(data_ != nullptr)\r
61                         return false;\r
62                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo()));\r
63                 CASPAR_GL_CHECK(glBufferData(GL_PIXEL_UNPACK_BUFFER, size_, NULL, GL_STREAM_DRAW));\r
64                 void* ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);\r
65                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));\r
66                 data_ = reinterpret_cast<unsigned char*>(ptr);\r
67                 if(!data_)\r
68                         BOOST_THROW_EXCEPTION(std::bad_alloc());\r
69                 return true;\r
70         }\r
71         \r
72         void read_lock(GLenum mode)\r
73         {       \r
74                 CASPAR_GL_CHECK(glReadBuffer(mode));\r
75                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo()));\r
76                 if(data_ != nullptr)    \r
77                 {       \r
78                         CASPAR_GL_CHECK(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));   \r
79                         data_ = nullptr;\r
80                 }\r
81                 CASPAR_GL_CHECK(glBufferData(GL_PIXEL_PACK_BUFFER, size_, NULL, GL_STREAM_READ));       \r
82                 CASPAR_GL_CHECK(glReadPixels(0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
83                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));\r
84                 reading_ = true;\r
85         }\r
86 \r
87         bool read_unlock()\r
88         {\r
89                 if(data_ != nullptr || !reading_)\r
90                         return false;\r
91                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo()));\r
92                 void* ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);   \r
93                 CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));\r
94                 data_ = reinterpret_cast<unsigned char*>(ptr);\r
95                 if(!data_)\r
96                         BOOST_THROW_EXCEPTION(std::bad_alloc());\r
97                 reading_ = false;\r
98                 return true;\r
99         }\r
100 \r
101         void draw()\r
102         {\r
103                 glPushMatrix();\r
104                 glTranslatef(x_*2.0f, y_*2.0f, 0.0f);\r
105                 glColor4f(1.0f, 1.0f, 1.0f, alpha_);\r
106                 CASPAR_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture_));\r
107                 glBegin(GL_QUADS);\r
108                         glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f);\r
109                         glTexCoord2f(1.0f, 0.0f); glVertex2f( 1.0f, -1.0f);\r
110                         glTexCoord2f(1.0f, 1.0f); glVertex2f( 1.0f,  1.0f);\r
111                         glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f,  1.0f);\r
112                 glEnd();\r
113                 glPopMatrix();\r
114         }\r
115                 \r
116         unsigned char* data()\r
117         {\r
118                 if(data_ == nullptr)\r
119                         BOOST_THROW_EXCEPTION(invalid_operation());\r
120                 return data_;\r
121         }\r
122 \r
123         void reset()\r
124         {\r
125                 audio_data_.clear();\r
126                 alpha_ = 1.0f;\r
127                 x_ = 0.0f;\r
128                 y_ = 0.0f;\r
129         }\r
130 \r
131         gpu_frame* self_;\r
132         GLuint pbo_;\r
133         GLuint texture_;\r
134         unsigned char* data_;\r
135         size_t width_;\r
136         size_t height_;\r
137         size_t size_;\r
138         bool reading_;\r
139         std::vector<short> audio_data_;\r
140 \r
141         float alpha_;\r
142         float x_;\r
143         float y_;\r
144 };\r
145 \r
146 gpu_frame::gpu_frame(size_t width, size_t height) : impl_(new implementation(width, height)){}\r
147 void gpu_frame::write_lock(){impl_->write_lock();}\r
148 bool gpu_frame::write_unlock(){return impl_->write_unlock();}   \r
149 void gpu_frame::read_lock(GLenum mode){impl_->read_lock(mode);}\r
150 bool gpu_frame::read_unlock(){return impl_->read_unlock();}\r
151 void gpu_frame::draw(){impl_->draw();}\r
152 unsigned char* gpu_frame::data(){return impl_->data();}\r
153 size_t gpu_frame::size() const { return impl_->size_; }\r
154 size_t gpu_frame::width() const { return impl_->width_;}\r
155 size_t gpu_frame::height() const { return impl_->height_;}\r
156 const std::vector<short>& gpu_frame::audio_data() const { return impl_->audio_data_; }  \r
157 std::vector<short>& gpu_frame::audio_data() { return impl_->audio_data_; }\r
158 void gpu_frame::reset(){impl_->reset();}\r
159 float gpu_frame::alpha() const{ return impl_->alpha_;}\r
160 void gpu_frame::alpha(float value){ impl_->alpha_ = value;}\r
161 float gpu_frame::x() const { return impl_->x_;}\r
162 float gpu_frame::y() const { return impl_->y_;}\r
163 void gpu_frame::translate(float x, float y) { impl_->x_ += x; impl_->y_ += y; }\r
164 }