]> git.sesse.net Git - casparcg/blob - accelerator/ogl/util/buffer.cpp
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
[casparcg] / accelerator / ogl / util / buffer.cpp
1 /*\r
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
3 *\r
4 * This file is part of CasparCG (www.casparcg.com).\r
5 *\r
6 * CasparCG is free software: you can redistribute it and/or modify\r
7 * it under the terms of the GNU General Public License as published by\r
8 * the Free Software Foundation, either version 3 of the License, or\r
9 * (at your option) any later version.\r
10 *\r
11 * CasparCG is distributed in the hope that it will be useful,\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14 * GNU General Public License for more details.\r
15 *\r
16 * You should have received a copy of the GNU General Public License\r
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
18 *\r
19 * Author: Robert Nagy, ronag89@gmail.com\r
20 */\r
21 \r
22 #include "../../stdafx.h"\r
23 \r
24 #include "buffer.h"\r
25 \r
26 #include "texture.h"\r
27 #include "device.h"\r
28 \r
29 #include <common/except.h>\r
30 #include <common/gl/gl_check.h>\r
31 \r
32 #include <gl/glew.h>\r
33 \r
34 #include <tbb/atomic.h>\r
35 \r
36 namespace caspar { namespace accelerator { namespace ogl {\r
37 \r
38 static tbb::atomic<int> g_w_total_count;\r
39 static tbb::atomic<int> g_r_total_count;\r
40                                                                                                                                                                                                                                                                                                                                 \r
41 struct buffer::impl : boost::noncopyable\r
42 {       \r
43         GLuint                                          pbo_;\r
44         const std::size_t                       size_;\r
45         tbb::atomic<uint8_t*>           data_;\r
46         GLenum                                          usage_;\r
47         GLenum                                          target_;\r
48 \r
49 public:\r
50         impl(std::size_t size, buffer::usage usage) \r
51                 : size_(size)\r
52                 , target_(usage == buffer::usage::write_only ? GL_PIXEL_UNPACK_BUFFER : GL_PIXEL_PACK_BUFFER)\r
53                 , usage_(usage == buffer::usage::write_only ? GL_STREAM_DRAW : GL_STREAM_READ)\r
54         {\r
55                 data_ = nullptr;\r
56                 GL(glGenBuffers(1, &pbo_));\r
57                 bind(); \r
58                 GL(glBufferData(target_, size_, NULL, usage_));         \r
59                 if(usage_ == GL_STREAM_DRAW)    \r
60                         data_ = (uint8_t*)GL2(glMapBuffer(target_, usage_ == GL_STREAM_DRAW ? GL_WRITE_ONLY : GL_READ_ONLY));  \r
61                 unbind();\r
62 \r
63                 if(!pbo_)\r
64                         BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to allocate buffer."));\r
65 \r
66                 //CASPAR_LOG(trace) << "[buffer] [" << ++(usage_ == buffer::usage::write_only ? g_w_total_count : g_r_total_count) << L"] allocated size:" << size_ << " usage: " << (usage == buffer::usage::write_only ? "write_only" : "read_only");\r
67         }       \r
68 \r
69         ~impl()\r
70         {\r
71                 glDeleteBuffers(1, &pbo_);\r
72         }\r
73 \r
74         void* map()\r
75         {\r
76                 if(data_ != nullptr)\r
77                         return data_;\r
78 \r
79                 GL(glBindBuffer(target_, pbo_));\r
80                 if(usage_ == GL_STREAM_DRAW)                    \r
81                         GL(glBufferData(target_, size_, NULL, usage_)); // Notify OpenGL that we don't care about previous data.\r
82                 \r
83                 boost::timer timer;\r
84 \r
85                 data_ = (uint8_t*)GL2(glMapBuffer(target_, usage_ == GL_STREAM_DRAW ? GL_WRITE_ONLY : GL_READ_ONLY));  \r
86 \r
87                 if(timer.elapsed() > 0.02)\r
88                         CASPAR_LOG(debug) << L"[buffer] Performance warning. Buffer mapping blocked more than 20 ms: " << timer.elapsed();\r
89 \r
90                 GL(glBindBuffer(target_, 0));\r
91                 if(!data_)\r
92                         BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Failed to map target OpenGL Pixel Buffer Object."));\r
93 \r
94                 return data_;\r
95         }\r
96         \r
97         void unmap()\r
98         {\r
99                 if(data_ == nullptr)\r
100                         return;\r
101                 \r
102                 GL(glBindBuffer(target_, pbo_));\r
103                 GL(glUnmapBuffer(target_));     \r
104                 if(usage_ == GL_STREAM_READ)                    \r
105                         GL(glBufferData(target_, size_, NULL, usage_)); // Notify OpenGL that we don't care about previous data.\r
106                 data_ = nullptr;        \r
107                 GL(glBindBuffer(target_, 0));\r
108         }\r
109 \r
110         void bind()\r
111         {\r
112                 GL(glBindBuffer(target_, pbo_));\r
113         }\r
114 \r
115         void unbind()\r
116         {\r
117                 GL(glBindBuffer(target_, 0));\r
118         }\r
119 };\r
120 \r
121 buffer::buffer(std::size_t size, usage usage) : impl_(new impl(size, usage)){}\r
122 buffer::buffer(buffer&& other) : impl_(std::move(other.impl_)){}\r
123 buffer::~buffer(){}\r
124 buffer& buffer::operator=(buffer&& other){impl_ = std::move(other.impl_); return *this;}\r
125 uint8_t* buffer::data(){return impl_->data_;}\r
126 void buffer::map(){impl_->map();}\r
127 void buffer::unmap(){impl_->unmap();}\r
128 void buffer::bind() const{impl_->bind();}\r
129 void buffer::unbind() const{impl_->unbind();}\r
130 std::size_t buffer::size() const { return impl_->size_; }\r
131 int buffer::id() const {return impl_->pbo_;}\r
132 \r
133 }}}