]> git.sesse.net Git - casparcg/blob - accelerator/ogl/util/buffer.cpp
5efdd2f4c3f1379505082a4e9b8edc151fe3ea5f
[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                 boost::timer timer;\r
56 \r
57                 data_ = nullptr;\r
58                 GL(glGenBuffers(1, &pbo_));\r
59                 bind(); \r
60                 GL(glBufferData(target_, size_, NULL, usage_));         \r
61                 if(usage_ == GL_STREAM_DRAW)    \r
62                         data_ = (uint8_t*)GL2(glMapBuffer(target_, usage_ == GL_STREAM_DRAW ? GL_WRITE_ONLY : GL_READ_ONLY));  \r
63                 unbind();\r
64 \r
65                 if(!pbo_)\r
66                         CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to allocate buffer."));\r
67                 \r
68                 if(timer.elapsed() > 0.02)\r
69                         CASPAR_LOG(debug) << L"[buffer] Performance warning. Buffer allocation blocked more than 20 ms: " << timer.elapsed();\r
70         \r
71                 //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
72         }       \r
73 \r
74         ~impl()\r
75         {\r
76                 glDeleteBuffers(1, &pbo_);\r
77         }\r
78 \r
79         void* map()\r
80         {\r
81                 if(data_ != nullptr)\r
82                         return data_;\r
83 \r
84                 GL(glBindBuffer(target_, pbo_));\r
85                 if(usage_ == GL_STREAM_DRAW)                    \r
86                         GL(glBufferData(target_, size_, NULL, usage_)); // Notify OpenGL that we don't care about previous data.\r
87                 \r
88                 boost::timer timer;\r
89 \r
90                 data_ = (uint8_t*)GL2(glMapBuffer(target_, usage_ == GL_STREAM_DRAW ? GL_WRITE_ONLY : GL_READ_ONLY));  \r
91 \r
92                 if(timer.elapsed() > 0.02)\r
93                         CASPAR_LOG(debug) << L"[buffer] Performance warning. Buffer mapping blocked more than 20 ms: " << timer.elapsed();\r
94 \r
95                 GL(glBindBuffer(target_, 0));\r
96                 if(!data_)\r
97                         CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Failed to map target OpenGL Pixel Buffer Object."));\r
98 \r
99                 return data_;\r
100         }\r
101         \r
102         void unmap()\r
103         {\r
104                 if(data_ == nullptr)\r
105                         return;\r
106                 \r
107                 GL(glBindBuffer(target_, pbo_));\r
108                 GL(glUnmapBuffer(target_));     \r
109                 if(usage_ == GL_STREAM_READ)                    \r
110                         GL(glBufferData(target_, size_, NULL, usage_)); // Notify OpenGL that we don't care about previous data.\r
111                 data_ = nullptr;        \r
112                 GL(glBindBuffer(target_, 0));\r
113         }\r
114 \r
115         void bind()\r
116         {\r
117                 GL(glBindBuffer(target_, pbo_));\r
118         }\r
119 \r
120         void unbind()\r
121         {\r
122                 GL(glBindBuffer(target_, 0));\r
123         }\r
124 };\r
125 \r
126 buffer::buffer(std::size_t size, usage usage) : impl_(new impl(size, usage)){}\r
127 buffer::buffer(buffer&& other) : impl_(std::move(other.impl_)){}\r
128 buffer::~buffer(){}\r
129 buffer& buffer::operator=(buffer&& other){impl_ = std::move(other.impl_); return *this;}\r
130 uint8_t* buffer::data(){return impl_->data_;}\r
131 void buffer::map(){impl_->map();}\r
132 void buffer::unmap(){impl_->unmap();}\r
133 void buffer::bind() const{impl_->bind();}\r
134 void buffer::unbind() const{impl_->unbind();}\r
135 std::size_t buffer::size() const { return impl_->size_; }\r
136 int buffer::id() const {return impl_->pbo_;}\r
137 \r
138 }}}