]> git.sesse.net Git - casparcg/blob - core/mixer/gpu/host_buffer.cpp
- Increased consumer timeout to 10 seconds.
[casparcg] / core / mixer / gpu / host_buffer.cpp
1 /*\r
2 * Copyright 2013 Sveriges Television AB http://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 "host_buffer.h"\r
25 \r
26 #include "fence.h"\r
27 #include "device_buffer.h"\r
28 #include "ogl_device.h"\r
29 \r
30 #include <common/exception/exceptions.h>\r
31 #include <common/gl/gl_check.h>\r
32 \r
33 #include <gl/glew.h>\r
34 \r
35 #include <tbb/atomic.h>\r
36 \r
37 #include <boost/property_tree/ptree.hpp>\r
38 \r
39 namespace caspar { namespace core {\r
40 \r
41 static tbb::atomic<int> g_w_instance_id;\r
42 static tbb::atomic<int> g_w_total_count;\r
43 static tbb::atomic<int> g_w_total_size;\r
44 static tbb::atomic<int> g_r_instance_id;\r
45 static tbb::atomic<int> g_r_total_count;\r
46 static tbb::atomic<int> g_r_total_size;\r
47                                                                                                                                                                                                                                                                                                                                 \r
48 struct host_buffer::implementation : boost::noncopyable\r
49 {\r
50         int                             instance_id_;\r
51         GLuint                  pbo_;\r
52         const size_t    size_;\r
53         void*                   data_;\r
54         usage_t                 usage_;\r
55         GLenum                  target_;\r
56         fence                   fence_;\r
57 \r
58 public:\r
59         implementation(size_t size, usage_t usage) \r
60                 : instance_id_(++(usage == write_only ? g_w_instance_id : g_r_instance_id))\r
61                 , size_(size)\r
62                 , data_(nullptr)\r
63                 , pbo_(0)\r
64                 , target_(usage == write_only ? GL_PIXEL_UNPACK_BUFFER : GL_PIXEL_PACK_BUFFER)\r
65                 , usage_(usage)\r
66         {\r
67                 GL(glGenBuffers(1, &pbo_));\r
68                 GL(glBindBuffer(target_, pbo_));\r
69                 GL(glBufferData(target_, size_, NULL, usage_ == write_only ? GL_STREAM_DRAW : GL_STREAM_READ));\r
70                 GL(glBindBuffer(target_, 0));\r
71 \r
72                 if(!pbo_)\r
73                         BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to allocate buffer."));\r
74 \r
75                 ++(usage_ == write_only ? g_w_total_count : g_r_total_count);\r
76                 auto total_size = (usage_ == write_only ? g_w_total_size : g_r_total_size) += size_;\r
77                 CASPAR_LOG(trace) << "[host_buffer] [" << instance_id_ << L"] allocated size:" << size_ << " (total: " << total_size << ") usage: " << (usage_ == write_only ? "write_only" : "read_only");\r
78         }       \r
79 \r
80         ~implementation()\r
81         {\r
82                 try\r
83                 {\r
84                         GL(glDeleteBuffers(1, &pbo_));\r
85                         --(usage_ == write_only ? g_w_total_count : g_r_total_count);\r
86                         auto total_size = (usage_ == write_only ? g_w_total_size : g_r_total_size) -= size_;\r
87                         CASPAR_LOG(trace) << "[host_buffer] [" << instance_id_ << L"] deallocated size:" << size_ << "(remaining total: " << total_size << ") usage: " << (usage_ == write_only ? "write_only" : "read_only");\r
88                 }\r
89                 catch(...)\r
90                 {\r
91                         CASPAR_LOG_CURRENT_EXCEPTION();\r
92                 }\r
93         }\r
94 \r
95         void map()\r
96         {\r
97                 if(data_)\r
98                         return;\r
99 \r
100                 GL(glBindBuffer(target_, pbo_));\r
101 \r
102                 if(usage_ == write_only)                        \r
103                         GL(glBufferData(target_, size_, NULL, GL_STREAM_DRAW)); // Notify OpenGL that we don't care about previous data.\r
104                 \r
105                 data_ = GL2(glMapBuffer(target_, usage_ == host_buffer::write_only ? GL_WRITE_ONLY : GL_READ_ONLY));\r
106                 GL(glBindBuffer(target_, 0)); \r
107                 if(!data_)\r
108                         BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Failed to map target_ OpenGL Pixel Buffer Object."));\r
109         }\r
110 \r
111         void wait(ogl_device& ogl)\r
112         {\r
113                 fence_.wait(ogl);\r
114         }\r
115 \r
116         void unmap()\r
117         {\r
118                 if(!data_)\r
119                         return;\r
120                 \r
121                 GL(glBindBuffer(target_, pbo_));\r
122                 GL(glUnmapBuffer(target_));     \r
123                 data_ = nullptr;                \r
124                 GL(glBindBuffer(target_, 0));\r
125         }\r
126 \r
127         void bind()\r
128         {\r
129                 GL(glBindBuffer(target_, pbo_));\r
130         }\r
131 \r
132         void unbind()\r
133         {\r
134                 GL(glBindBuffer(target_, 0));\r
135         }\r
136 \r
137         void begin_read(size_t width, size_t height, GLuint format)\r
138         {\r
139                 unmap();\r
140                 bind();\r
141                 GL(glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, NULL));\r
142                 unbind();\r
143                 fence_.set();\r
144         }\r
145 \r
146         bool ready() const\r
147         {\r
148                 return fence_.ready();\r
149         }\r
150 };\r
151 \r
152 host_buffer::host_buffer(size_t size, usage_t usage) : impl_(new implementation(size, usage)){}\r
153 const void* host_buffer::data() const {return impl_->data_;}\r
154 void* host_buffer::data() {return impl_->data_;}\r
155 void host_buffer::map(){impl_->map();}\r
156 void host_buffer::unmap(){impl_->unmap();}\r
157 void host_buffer::bind(){impl_->bind();}\r
158 void host_buffer::unbind(){impl_->unbind();}\r
159 void host_buffer::begin_read(size_t width, size_t height, GLuint format){impl_->begin_read(width, height, format);}\r
160 size_t host_buffer::size() const { return impl_->size_; }\r
161 bool host_buffer::ready() const{return impl_->ready();}\r
162 void host_buffer::wait(ogl_device& ogl){impl_->wait(ogl);}\r
163 \r
164 boost::property_tree::wptree host_buffer::info()\r
165 {\r
166         boost::property_tree::wptree info;\r
167 \r
168         info.add(L"total_read_count", g_r_total_count);\r
169         info.add(L"total_write_count", g_w_total_count);\r
170         info.add(L"total_read_size", g_r_total_size);\r
171         info.add(L"total_write_size", g_w_total_size);\r
172 \r
173         return info;\r
174 }\r
175 \r
176 }}