]> git.sesse.net Git - casparcg/blob - common/gl/pixel_buffer_object.cpp
2.0.0.2:
[casparcg] / common / gl / pixel_buffer_object.cpp
1 #include "../StdAfx.h"\r
2 \r
3 #include "pixel_buffer_object.h"\r
4 \r
5 #include "../../common/exception/exceptions.h"\r
6 #include "../../common/gl/gl_check.h"\r
7 #include "../../common/utility/memory.h"\r
8 \r
9 namespace caspar { namespace common { namespace gl {\r
10                                                                                                                                                                                                                                                                                                                         \r
11 struct pixel_buffer_object::implementation : boost::noncopyable\r
12 {\r
13         implementation(size_t width, size_t height, GLenum format) \r
14                 : width_(width), height_(height), pbo_(0), format_(format),\r
15                         texture_(0), writing_(false), reading_(false), mapped_(false)\r
16         {\r
17                 switch(format)\r
18                 {\r
19                 case GL_RGBA:\r
20                 case GL_BGRA:\r
21                         internal_ = GL_RGBA8;\r
22                         size_ = width*height*4;\r
23                         break;\r
24                 case GL_BGR:\r
25                         internal_ = GL_RGB8;\r
26                         size_ = width*height*3;\r
27                         break;\r
28                 case GL_LUMINANCE_ALPHA:\r
29                         internal_ = GL_LUMINANCE_ALPHA;\r
30                         size_ = width*height*2;\r
31                         break;\r
32                 case GL_LUMINANCE:\r
33                 case GL_ALPHA:\r
34                         internal_ = GL_LUMINANCE;\r
35                         size_ = width*height*1;\r
36                         break;\r
37                 default:\r
38                         BOOST_THROW_EXCEPTION(invalid_argument() << msg_info("format"));\r
39                 }\r
40         }\r
41 \r
42         ~implementation()\r
43         {\r
44                 if(pbo_ != 0)\r
45                         glDeleteBuffers(1, &pbo_);\r
46         }       \r
47 \r
48         void bind_pbo(GLenum mode)\r
49         {\r
50                 if(pbo_ == 0)\r
51                         GL(glGenBuffers(1, &pbo_));\r
52                 GL(glBindBuffer(mode, pbo_));\r
53         }\r
54 \r
55         void unbind_pbo(GLenum mode)\r
56         {\r
57                 GL(glBindBuffer(mode, 0));\r
58         }\r
59         \r
60         void bind_texture()\r
61         {\r
62                 if(texture_ == 0)\r
63                 {\r
64                         GL(glGenTextures(1, &texture_));\r
65 \r
66                         GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
67 \r
68                         GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));\r
69                         GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));\r
70                         GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));\r
71                         GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));\r
72 \r
73                         GL(glTexImage2D(GL_TEXTURE_2D, 0, internal_, width_, height_, 0, format_, \r
74                                                                 GL_UNSIGNED_BYTE, NULL));\r
75                 }\r
76                 GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
77         }\r
78 \r
79         void begin_write()\r
80         {\r
81                 bind_pbo(GL_PIXEL_UNPACK_BUFFER);\r
82                 if(mapped_)\r
83                         GL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));\r
84                 mapped_ = false;\r
85                 bind_texture();\r
86                 GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, format_, \r
87                                                         GL_UNSIGNED_BYTE, NULL));\r
88                 unbind_pbo(GL_PIXEL_UNPACK_BUFFER);\r
89                 writing_ = true;\r
90         }\r
91 \r
92         void* end_write()\r
93         {\r
94                 if(mapped_)\r
95                         BOOST_THROW_EXCEPTION(invalid_operation());\r
96 \r
97                 bind_pbo(GL_PIXEL_UNPACK_BUFFER);\r
98                 GL(glBufferData(GL_PIXEL_UNPACK_BUFFER, size_, NULL, GL_STREAM_DRAW));\r
99                 auto data = static_cast<unsigned char*>(glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));\r
100                 unbind_pbo(GL_PIXEL_UNPACK_BUFFER);             \r
101                 if(!data)\r
102                         BOOST_THROW_EXCEPTION(invalid_operation() \r
103                                                                         << msg_info("glMapBuffer failed"));\r
104                 writing_ = false;\r
105                 mapped_ = true;\r
106                 return data;\r
107         }\r
108         \r
109         void begin_read()\r
110         {       \r
111                 bind_pbo(GL_PIXEL_PACK_BUFFER);\r
112                 if(mapped_)\r
113                         GL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));        \r
114                 mapped_ = false;\r
115                 GL(glBufferData(GL_PIXEL_PACK_BUFFER, size_, NULL, GL_STREAM_READ));    \r
116                 GL(glReadPixels(0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
117                 unbind_pbo(GL_PIXEL_PACK_BUFFER);\r
118                 reading_ = true;\r
119         }\r
120 \r
121         void* end_read()\r
122         {\r
123                 if(mapped_)\r
124                         BOOST_THROW_EXCEPTION(invalid_operation());\r
125 \r
126                 bind_pbo(GL_PIXEL_PACK_BUFFER);\r
127                 auto data = static_cast<unsigned char*>(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY));   \r
128                 unbind_pbo(GL_PIXEL_PACK_BUFFER);\r
129                 if(!data)\r
130                         BOOST_THROW_EXCEPTION(std::bad_alloc());\r
131                 reading_ = false;\r
132                 mapped_ = true;\r
133                 return data;\r
134         }\r
135 \r
136         \r
137         GLuint pbo_;\r
138         GLuint texture_;\r
139         size_t width_;\r
140         size_t height_;\r
141         size_t size_;\r
142 \r
143         bool mapped_;\r
144         bool writing_;\r
145         bool reading_;\r
146 \r
147         GLint internal_;\r
148         GLenum format_;\r
149 };\r
150 \r
151 pixel_buffer_object::pixel_buffer_object(){}\r
152 pixel_buffer_object::pixel_buffer_object(size_t width, size_t height, GLenum format) \r
153         : impl_(new implementation(width, height, format)){}\r
154 void pixel_buffer_object::create(size_t width, size_t height, GLenum format)\r
155 {\r
156         impl_.reset(new implementation(width, height, format));\r
157 }\r
158 void pixel_buffer_object::begin_write() { impl_->begin_write();}\r
159 void* pixel_buffer_object::end_write() {return impl_->end_write();} \r
160 void pixel_buffer_object::begin_read() { impl_->begin_read();}\r
161 void* pixel_buffer_object::end_read(){return impl_->end_read();}\r
162 void pixel_buffer_object::bind_texture() {impl_->bind_texture();}\r
163 size_t pixel_buffer_object::width() const {return impl_->width_;}\r
164 size_t pixel_buffer_object::height() const {return impl_->height_;}\r
165 size_t pixel_buffer_object::size() const {return impl_->size_;}\r
166 bool pixel_buffer_object::is_reading() const { return impl_->reading_;}\r
167 bool pixel_buffer_object::is_writing() const { return impl_->writing_;}\r
168 }}}