]> 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) \r
14                 : width_(width), height_(height), size_(width*height*4), pbo_(0),\r
15                         texture_(0), writing_(false), reading_(false), mapped_(false){}\r
16 \r
17         ~implementation()\r
18         {\r
19                 if(pbo_ != 0)\r
20                         glDeleteBuffers(1, &pbo_);\r
21         }       \r
22 \r
23         void bind_pbo(GLenum mode)\r
24         {\r
25                 if(pbo_ == 0)\r
26                         GL(glGenBuffers(1, &pbo_));\r
27                 GL(glBindBuffer(mode, pbo_));\r
28         }\r
29 \r
30         void unbind_pbo(GLenum mode)\r
31         {\r
32                 GL(glBindBuffer(mode, 0));\r
33         }\r
34         \r
35         void bind_texture()\r
36         {\r
37                 if(texture_ == 0)\r
38                 {\r
39                         GL(glGenTextures(1, &texture_));\r
40 \r
41                         GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
42 \r
43                         GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));\r
44                         GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));\r
45                         GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));\r
46                         GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));\r
47 \r
48                         GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width_, height_, 0, GL_BGRA, \r
49                                                                 GL_UNSIGNED_BYTE, NULL));\r
50                 }\r
51                 GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
52         }\r
53 \r
54         void begin_write()\r
55         {\r
56                 bind_pbo(GL_PIXEL_UNPACK_BUFFER);\r
57                 if(mapped_)\r
58                         GL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));\r
59                 mapped_ = false;\r
60                 bind_texture();\r
61                 GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA, \r
62                                                         GL_UNSIGNED_BYTE, NULL));\r
63                 unbind_pbo(GL_PIXEL_UNPACK_BUFFER);\r
64                 writing_ = true;\r
65         }\r
66 \r
67         void* end_write()\r
68         {\r
69                 if(mapped_)\r
70                         BOOST_THROW_EXCEPTION(invalid_operation());\r
71 \r
72                 bind_pbo(GL_PIXEL_UNPACK_BUFFER);\r
73                 GL(glBufferData(GL_PIXEL_UNPACK_BUFFER, size_, NULL, GL_STREAM_DRAW));\r
74                 auto data = static_cast<unsigned char*>(glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));\r
75                 unbind_pbo(GL_PIXEL_UNPACK_BUFFER);             \r
76                 if(!data)\r
77                         BOOST_THROW_EXCEPTION(invalid_operation() \r
78                                                                         << msg_info("glMapBuffer failed"));\r
79                 writing_ = false;\r
80                 mapped_ = true;\r
81                 return data;\r
82         }\r
83         \r
84         void begin_read()\r
85         {       \r
86                 bind_pbo(GL_PIXEL_PACK_BUFFER);\r
87                 if(mapped_)\r
88                         GL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));        \r
89                 mapped_ = false;\r
90                 GL(glBufferData(GL_PIXEL_PACK_BUFFER, size_, NULL, GL_STREAM_READ));    \r
91                 GL(glReadPixels(0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
92                 unbind_pbo(GL_PIXEL_PACK_BUFFER);\r
93                 reading_ = true;\r
94         }\r
95 \r
96         void* end_read()\r
97         {\r
98                 if(mapped_)\r
99                         BOOST_THROW_EXCEPTION(invalid_operation());\r
100 \r
101                 bind_pbo(GL_PIXEL_PACK_BUFFER);\r
102                 auto data = static_cast<unsigned char*>(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY));   \r
103                 unbind_pbo(GL_PIXEL_PACK_BUFFER);\r
104                 if(!data)\r
105                         BOOST_THROW_EXCEPTION(std::bad_alloc());\r
106                 reading_ = false;\r
107                 mapped_ = true;\r
108                 return data;\r
109         }\r
110 \r
111         \r
112         GLuint pbo_;\r
113         GLuint texture_;\r
114         size_t width_;\r
115         size_t height_;\r
116         size_t size_;\r
117 \r
118         bool mapped_;\r
119         bool writing_;\r
120         bool reading_;\r
121 };\r
122 \r
123 pixel_buffer_object::pixel_buffer_object(){}\r
124 pixel_buffer_object::pixel_buffer_object(size_t width, size_t height) \r
125         : impl_(new implementation(width, height)){}\r
126 void pixel_buffer_object::create(size_t width, size_t height)\r
127 {\r
128         impl_.reset(new implementation(width, height));\r
129 }\r
130 void pixel_buffer_object::begin_write() { impl_->begin_write();}\r
131 void* pixel_buffer_object::end_write() {return impl_->end_write();} \r
132 void pixel_buffer_object::begin_read() { impl_->begin_read();}\r
133 void* pixel_buffer_object::end_read(){return impl_->end_read();}\r
134 void pixel_buffer_object::bind_texture() {impl_->bind_texture();}\r
135 size_t pixel_buffer_object::width() const {return impl_->width_;}\r
136 size_t pixel_buffer_object::heigth() const {return impl_->height_;}\r
137 size_t pixel_buffer_object::size() const {return impl_->size_;}\r
138 bool pixel_buffer_object::is_reading() const { return impl_->reading_;}\r
139 bool pixel_buffer_object::is_writing() const { return impl_->writing_;}\r
140 }}}