Line data Source code
1 :
2 : /* Copyright (c) 2012-2017, Maxim Makhinya <maxmah@gmail.com>
3 : * Stefan Eilemann <eile@eyescale.ch>
4 : *
5 : * This library is free software; you can redistribute it and/or modify it under
6 : * the terms of the GNU Lesser General Public License version 2.1 as published
7 : * by the Free Software Foundation.
8 : *
9 : * This library is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 : * details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public License
15 : * along with this library; if not, write to the Free Software Foundation, Inc.,
16 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 : */
18 :
19 : #include "pixelBufferObject.h"
20 :
21 : #include <eq/gl.h>
22 : #include <lunchbox/debug.h>
23 : #include <lunchbox/scopedMutex.h>
24 :
25 : namespace eq
26 : {
27 : namespace util
28 : {
29 : namespace detail
30 : {
31 : class PixelBufferObject
32 : {
33 : public:
34 1 : PixelBufferObject(const GLEWContext* glewContext)
35 1 : : pboID(0)
36 : , size(0)
37 : , _glewContext(glewContext)
38 1 : , _type(0)
39 : {
40 1 : LBVERB << (void*)this << backtrace << std::endl;
41 1 : }
42 :
43 1 : ~PixelBufferObject()
44 1 : {
45 1 : LBASSERTINFO(!isInitialized(), (void*)this << backtrace);
46 1 : if (isInitialized())
47 0 : LBWARN << "PBO was not freed" << std::endl;
48 1 : }
49 :
50 1 : const GLEWContext* glewGetContext() const { return _glewContext; }
51 10 : bool isInitialized() const { return pboID != 0; }
52 1 : Error setup(const size_t newSize, const GLuint type)
53 : {
54 1 : LBASSERT(_glewContext);
55 :
56 1 : if (!GLEW_ARB_pixel_buffer_object)
57 0 : return Error(ERROR_PBO_UNSUPPORTED);
58 :
59 1 : if (newSize == 0)
60 : {
61 0 : destroy();
62 0 : return Error(ERROR_PBO_SIZE_TOO_SMALL);
63 : }
64 :
65 1 : if (pboID == 0)
66 : {
67 1 : EQ_GL_CALL(glGenBuffersARB(1, &pboID));
68 : }
69 1 : if (pboID == 0)
70 0 : return Error(ERROR_PBO_NOT_INITIALIZED);
71 :
72 1 : if (_type == type && size >= newSize)
73 : {
74 0 : bind();
75 0 : return Error(ERROR_NONE);
76 : }
77 :
78 1 : _type = type;
79 1 : size = newSize;
80 1 : bind();
81 :
82 1 : switch (type)
83 : {
84 : case GL_READ_ONLY_ARB:
85 1 : EQ_GL_CALL(glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, newSize, 0,
86 : GL_STREAM_READ_ARB));
87 1 : return Error(ERROR_NONE);
88 :
89 : case GL_WRITE_ONLY_ARB:
90 0 : EQ_GL_CALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, newSize, 0,
91 : GL_STREAM_DRAW_ARB));
92 0 : return Error(ERROR_NONE);
93 :
94 : default:
95 0 : destroy();
96 0 : return Error(ERROR_PBO_TYPE_UNSUPPORTED);
97 : }
98 : }
99 :
100 1 : void destroy()
101 : {
102 1 : if (pboID != 0)
103 : {
104 1 : unbind();
105 1 : EQ_GL_CALL(glDeleteBuffersARB(1, &pboID));
106 : }
107 1 : pboID = 0;
108 1 : size = 0;
109 1 : _type = 0;
110 1 : }
111 :
112 1 : const void* mapRead() const
113 : {
114 1 : if (!isInitialized() || _type != GL_READ_ONLY_ARB)
115 0 : return 0;
116 :
117 1 : bind();
118 1 : return glMapBufferARB(_getName(), GL_READ_ONLY_ARB);
119 : }
120 :
121 0 : void* mapWrite()
122 : {
123 0 : if (!isInitialized() || _type != GL_WRITE_ONLY_ARB)
124 0 : return 0;
125 :
126 0 : bind();
127 : // cancel all draw operations on this buffer to prevent stalling
128 0 : EQ_GL_CALL(glBufferDataARB(_getName(), size, 0, GL_STREAM_DRAW_ARB));
129 0 : return glMapBufferARB(_getName(), GL_WRITE_ONLY_ARB);
130 : }
131 :
132 1 : void unmap() const
133 : {
134 1 : LBASSERT(isInitialized());
135 1 : EQ_GL_CALL(glUnmapBufferARB(_getName()));
136 1 : unbind();
137 1 : }
138 :
139 2 : bool bind() const
140 : {
141 2 : if (!isInitialized())
142 0 : return false;
143 :
144 2 : EQ_GL_CALL(glBindBufferARB(_getName(), pboID));
145 2 : return true;
146 : }
147 :
148 3 : void unbind() const
149 : {
150 3 : LBASSERT(isInitialized());
151 3 : EQ_GL_CALL(glBindBufferARB(_getName(), 0));
152 3 : }
153 :
154 : GLuint pboID; //!< the PBO GL name
155 : size_t size; //!< size of the allocated PBO buffer
156 : mutable std::mutex lock;
157 :
158 : private:
159 : const GLEWContext* const _glewContext;
160 : GLuint _type; //!< GL_READ_ONLY_ARB or GL_WRITE_ONLY_ARB
161 :
162 7 : GLuint _getName() const
163 : {
164 7 : return _type == GL_READ_ONLY_ARB ? GL_PIXEL_PACK_BUFFER_ARB
165 7 : : GL_PIXEL_UNPACK_BUFFER_ARB;
166 : }
167 : };
168 : }
169 :
170 1 : PixelBufferObject::PixelBufferObject(const GLEWContext* glewContext)
171 1 : : _impl(new detail::PixelBufferObject(glewContext))
172 : {
173 1 : }
174 :
175 3 : PixelBufferObject::~PixelBufferObject()
176 : {
177 1 : delete _impl;
178 2 : }
179 :
180 1 : Error PixelBufferObject::setup(const size_t size, const unsigned type)
181 : {
182 2 : lunchbox::ScopedWrite mutex(_impl->lock);
183 2 : return _impl->setup(size, type);
184 : }
185 :
186 1 : void PixelBufferObject::destroy()
187 : {
188 2 : lunchbox::ScopedWrite mutex(_impl->lock);
189 1 : _impl->destroy();
190 1 : }
191 :
192 1 : const void* PixelBufferObject::mapRead() const
193 : {
194 1 : _impl->lock.lock();
195 1 : return _impl->mapRead();
196 : }
197 :
198 0 : void* PixelBufferObject::mapWrite()
199 : {
200 0 : _impl->lock.lock();
201 0 : return _impl->mapWrite();
202 : }
203 :
204 1 : void PixelBufferObject::unmap() const
205 : {
206 1 : _impl->unmap();
207 1 : _impl->lock.unlock();
208 1 : }
209 :
210 0 : bool PixelBufferObject::bind() const
211 : {
212 0 : _impl->lock.lock();
213 0 : return _impl->bind();
214 : }
215 :
216 1 : void PixelBufferObject::unbind() const
217 : {
218 1 : _impl->unbind();
219 1 : _impl->lock.unlock();
220 1 : }
221 :
222 0 : size_t PixelBufferObject::getSize() const
223 : {
224 0 : return _impl->size;
225 : }
226 :
227 1 : bool PixelBufferObject::isInitialized() const
228 : {
229 1 : return _impl->isInitialized();
230 : }
231 :
232 0 : GLuint PixelBufferObject::getID() const
233 : {
234 0 : return _impl->pboID;
235 : }
236 : }
237 30 : }
|