Line data Source code
1 :
2 : /* Copyright (c) 2009-2017, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Cedric Stalder <cedric.stalder@gmail.com>
4 : * Daniel Nachbaur <danielnachbaur@gmail.com>
5 : *
6 : * This library is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU Lesser General Public License version 2.1 as published
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "texture.h"
21 :
22 : #include <eq/fabric/pixelViewport.h>
23 :
24 : #include <eq/gl.h>
25 : #include <eq/image.h>
26 : #include <pression/plugins/compressor.h>
27 :
28 : namespace eq
29 : {
30 : namespace util
31 : {
32 : namespace detail
33 : {
34 : class Texture
35 : {
36 : public:
37 22 : Texture(const GLenum tgt, const GLEWContext* const gl)
38 22 : : name(0)
39 : , target(tgt)
40 : , internalFormat(0)
41 : , format(0)
42 : , type(0)
43 : , width(0)
44 : , height(0)
45 : , defined(false)
46 22 : , glewContext(gl)
47 : {
48 22 : }
49 :
50 22 : ~Texture()
51 22 : {
52 22 : if (name != 0)
53 0 : LBWARN << "OpenGL texture " << name << " not freed" << std::endl;
54 :
55 22 : name = 0;
56 22 : defined = false;
57 22 : }
58 :
59 : GLuint name;
60 : const GLenum target;
61 : GLuint internalFormat;
62 : GLuint format;
63 : GLuint type;
64 : int32_t width;
65 : int32_t height;
66 : bool defined;
67 : const GLEWContext* glewContext;
68 : };
69 : }
70 :
71 22 : Texture::Texture(const unsigned target, const GLEWContext* const glewContext)
72 22 : : _impl(new detail::Texture(target, glewContext))
73 : {
74 22 : }
75 :
76 45 : Texture::~Texture()
77 : {
78 22 : delete _impl;
79 23 : }
80 0 : bool Texture::isValid() const
81 : {
82 0 : return (_impl->name != 0 && _impl->defined);
83 : }
84 :
85 8 : void Texture::flush()
86 : {
87 8 : if (_impl->name == 0)
88 6 : return;
89 :
90 2 : LB_TS_THREAD(_thread);
91 2 : EQ_GL_CALL(glDeleteTextures(1, &_impl->name));
92 2 : _impl->name = 0;
93 2 : _impl->defined = false;
94 : }
95 :
96 0 : void Texture::flushNoDelete()
97 : {
98 0 : LB_TS_THREAD(_thread);
99 0 : _impl->name = 0;
100 0 : _impl->defined = false;
101 0 : }
102 :
103 0 : uint32_t Texture::getCompressorTarget() const
104 : {
105 0 : switch (_impl->target)
106 : {
107 : case GL_TEXTURE_RECTANGLE_ARB:
108 0 : return EQ_COMPRESSOR_USE_TEXTURE_RECT;
109 :
110 : default:
111 0 : LBUNIMPLEMENTED;
112 : case GL_TEXTURE_2D:
113 0 : return EQ_COMPRESSOR_USE_TEXTURE_2D;
114 : }
115 : }
116 :
117 2 : void Texture::_setInternalFormat(const GLuint internalFormat)
118 : {
119 2 : if (_impl->internalFormat == internalFormat)
120 0 : return;
121 :
122 2 : _impl->defined = false;
123 2 : _impl->internalFormat = internalFormat;
124 :
125 2 : switch (internalFormat)
126 : {
127 : // depth format
128 : case GL_DEPTH_COMPONENT:
129 0 : setExternalFormat(GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
130 0 : break;
131 : case GL_RGB10_A2:
132 0 : setExternalFormat(GL_RGBA, GL_UNSIGNED_INT_10_10_10_2);
133 0 : break;
134 : case GL_RGBA:
135 : case GL_RGBA8:
136 1 : setExternalFormat(GL_RGBA, GL_UNSIGNED_BYTE);
137 1 : break;
138 : case GL_RGBA16F:
139 0 : setExternalFormat(GL_RGBA, GL_HALF_FLOAT);
140 0 : break;
141 : case GL_RGBA32F:
142 0 : setExternalFormat(GL_RGBA, GL_FLOAT);
143 0 : break;
144 : case GL_RGB:
145 : case GL_RGB8:
146 0 : setExternalFormat(GL_RGB, GL_UNSIGNED_BYTE);
147 0 : break;
148 : case GL_RGB16F:
149 0 : setExternalFormat(GL_RGB, GL_HALF_FLOAT);
150 0 : break;
151 : case GL_RGB32F:
152 0 : setExternalFormat(GL_RGB, GL_FLOAT);
153 0 : break;
154 : case GL_ALPHA32F_ARB:
155 0 : setExternalFormat(GL_ALPHA, GL_FLOAT);
156 0 : break;
157 : case GL_DEPTH24_STENCIL8:
158 1 : setExternalFormat(GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
159 1 : break;
160 : case GL_RGBA32UI:
161 0 : LBASSERT(_impl->glewContext);
162 0 : if (GLEW_EXT_texture_integer)
163 0 : setExternalFormat(GL_RGBA_INTEGER_EXT, GL_UNSIGNED_INT);
164 : else
165 0 : LBUNIMPLEMENTED;
166 0 : break;
167 :
168 : default:
169 0 : LBUNIMPLEMENTED;
170 0 : setExternalFormat(internalFormat, GL_UNSIGNED_BYTE);
171 : }
172 : }
173 :
174 2 : void Texture::setExternalFormat(const uint32_t format, const uint32_t type)
175 : {
176 2 : _impl->format = format;
177 2 : _impl->type = type;
178 2 : }
179 :
180 4 : void Texture::_generate()
181 : {
182 4 : LB_TS_THREAD(_thread);
183 4 : if (_impl->name != 0)
184 2 : return;
185 :
186 2 : _impl->defined = false;
187 2 : EQ_GL_CALL(glGenTextures(1, &_impl->name));
188 : }
189 :
190 2 : void Texture::init(const GLuint format, const int32_t width,
191 : const int32_t height)
192 : {
193 2 : _generate();
194 2 : _setInternalFormat(format);
195 2 : resize(width, height);
196 2 : }
197 :
198 0 : void Texture::setGLData(const GLuint id, const GLuint internalFormat,
199 : const int32_t width, const int32_t height)
200 : {
201 0 : flush();
202 0 : _setInternalFormat(internalFormat);
203 0 : _impl->name = id;
204 0 : _impl->width = width;
205 0 : _impl->height = height;
206 0 : _impl->defined = true;
207 0 : }
208 :
209 : namespace
210 : {
211 : /* Check if the texture dimensions are power of two. */
212 0 : static bool _isPOT(const uint32_t width, const uint32_t height)
213 : {
214 0 : return (width > 0 && height > 0 && (width & (width - 1)) == 0 &&
215 0 : (height & (height - 1)) == 0);
216 : }
217 : }
218 :
219 0 : void Texture::_grow(const int32_t width, const int32_t height)
220 : {
221 0 : if (_impl->width < width)
222 : {
223 0 : _impl->width = width;
224 0 : _impl->defined = false;
225 : }
226 :
227 0 : if (_impl->height < height)
228 : {
229 0 : _impl->height = height;
230 0 : _impl->defined = false;
231 : }
232 0 : }
233 :
234 0 : void Texture::applyZoomFilter(const ZoomFilter zoomFilter) const
235 : {
236 0 : EQ_GL_CALL(
237 : glTexParameteri(_impl->target, GL_TEXTURE_MAG_FILTER, zoomFilter));
238 0 : EQ_GL_CALL(
239 : glTexParameteri(_impl->target, GL_TEXTURE_MIN_FILTER, zoomFilter));
240 0 : }
241 :
242 0 : void Texture::applyWrap() const
243 : {
244 0 : EQ_GL_CALL(
245 : glTexParameteri(_impl->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
246 0 : EQ_GL_CALL(
247 : glTexParameteri(_impl->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
248 0 : }
249 :
250 0 : void Texture::copyFromFrameBuffer(const GLuint internalFormat,
251 : const fabric::PixelViewport& pvp)
252 : {
253 0 : EQ_GL_ERROR("before Texture::copyFromFrameBuffer");
254 0 : LB_TS_THREAD(_thread);
255 :
256 0 : _generate();
257 0 : _setInternalFormat(internalFormat);
258 0 : _grow(pvp.w, pvp.h);
259 :
260 0 : if (_impl->defined)
261 0 : glBindTexture(_impl->target, _impl->name);
262 : else
263 0 : resize(_impl->width, _impl->height);
264 :
265 0 : EQ_GL_CALL(glCopyTexSubImage2D(_impl->target, 0, 0, 0, pvp.x, pvp.y, pvp.w,
266 : pvp.h));
267 0 : EQ_GL_ERROR("after Texture::copyFromFrameBuffer");
268 0 : }
269 :
270 0 : void Texture::upload(const int32_t width, const int32_t height, const void* ptr)
271 : {
272 0 : _generate();
273 0 : _grow(width, height);
274 :
275 0 : if (_impl->defined)
276 0 : glBindTexture(_impl->target, _impl->name);
277 : else
278 0 : resize(_impl->width, _impl->height);
279 :
280 0 : EQ_GL_CALL(glTexSubImage2D(_impl->target, 0, 0, 0, width, height,
281 : _impl->format, _impl->type, ptr));
282 0 : }
283 :
284 0 : void Texture::download(void* buffer) const
285 : {
286 0 : LBASSERT(isValid());
287 0 : EQ_GL_CALL(glBindTexture(_impl->target, _impl->name));
288 0 : EQ_GL_CALL(
289 : glGetTexImage(_impl->target, 0, _impl->format, _impl->type, buffer));
290 0 : }
291 :
292 0 : void Texture::bind() const
293 : {
294 0 : LBASSERT(_impl->name);
295 0 : EQ_GL_CALL(glBindTexture(_impl->target, _impl->name));
296 0 : }
297 :
298 2 : void Texture::bindToFBO(const GLenum target, const int32_t width,
299 : const int32_t height, const int32_t samples)
300 : {
301 2 : LB_TS_THREAD(_thread);
302 2 : LBASSERT(_impl->internalFormat);
303 2 : LBASSERT(_impl->glewContext);
304 :
305 2 : _generate();
306 :
307 2 : EQ_GL_CALL(glBindTexture(_impl->target, _impl->name));
308 2 : EQ_GL_CALL(glTexImage2D(_impl->target, 0, _impl->internalFormat, width,
309 : height, 0, _impl->format, _impl->type, 0));
310 2 : EQ_GL_CALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER, target, _impl->target,
311 : _impl->name, 0));
312 :
313 2 : if (samples > 1)
314 : {
315 0 : EQ_GL_CALL(glTexImage2DMultisample(_impl->target, samples,
316 : _impl->internalFormat, width, height,
317 : false));
318 : }
319 :
320 2 : _impl->width = width;
321 2 : _impl->height = height;
322 2 : _impl->defined = true;
323 2 : }
324 :
325 2 : void Texture::resize(const int32_t width, const int32_t height)
326 : {
327 2 : LB_TS_THREAD(_thread);
328 2 : LBASSERT(_impl->name);
329 2 : LBASSERT(_impl->internalFormat);
330 2 : LBASSERT(width > 0 && height > 0);
331 :
332 2 : if (_impl->width == width && _impl->height == height && _impl->defined)
333 0 : return;
334 :
335 2 : if (_impl->target == GL_TEXTURE_2D && !_isPOT(width, height))
336 : {
337 0 : LBASSERT(_impl->glewContext);
338 0 : LBASSERT(GLEW_ARB_texture_non_power_of_two);
339 : }
340 :
341 2 : EQ_GL_CALL(glBindTexture(_impl->target, _impl->name));
342 2 : EQ_GL_CALL(glTexImage2D(_impl->target, 0, _impl->internalFormat, width,
343 : height, 0, _impl->format, _impl->type, 0));
344 2 : _impl->width = width;
345 2 : _impl->height = height;
346 2 : _impl->defined = true;
347 : }
348 :
349 0 : void Texture::writeRGB(const std::string& filename) const
350 : {
351 0 : LBASSERT(_impl->defined);
352 0 : if (!_impl->defined)
353 0 : return;
354 :
355 0 : eq::Image image;
356 :
357 0 : switch (_impl->internalFormat)
358 : {
359 : case GL_DEPTH_COMPONENT:
360 0 : image.allocDownloader(
361 : Frame::Buffer::color,
362 : EQ_COMPRESSOR_TRANSFER_DEPTH_TO_DEPTH_UNSIGNED_INT,
363 0 : _impl->glewContext);
364 0 : break;
365 : case GL_RGB10_A2:
366 0 : image.allocDownloader(Frame::Buffer::color,
367 : EQ_COMPRESSOR_TRANSFER_RGB10_A2_TO_BGR10_A2,
368 0 : _impl->glewContext);
369 0 : break;
370 : case GL_RGBA:
371 : case GL_RGBA8:
372 0 : image.allocDownloader(Frame::Buffer::color,
373 : EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGRA,
374 0 : _impl->glewContext);
375 0 : break;
376 : case GL_RGBA16F:
377 0 : image.allocDownloader(Frame::Buffer::color,
378 : EQ_COMPRESSOR_TRANSFER_RGBA16F_TO_BGRA16F,
379 0 : _impl->glewContext);
380 0 : break;
381 : case GL_RGBA32F:
382 0 : image.allocDownloader(Frame::Buffer::color,
383 : EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_BGRA32F,
384 0 : _impl->glewContext);
385 0 : break;
386 : case GL_RGB:
387 : case GL_RGB8:
388 0 : image.allocDownloader(Frame::Buffer::color,
389 : EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGR,
390 0 : _impl->glewContext);
391 0 : break;
392 : case GL_RGB16F:
393 0 : image.allocDownloader(Frame::Buffer::color,
394 : EQ_COMPRESSOR_TRANSFER_RGBA16F_TO_BGR16F,
395 0 : _impl->glewContext);
396 0 : break;
397 : case GL_RGB32F:
398 0 : image.allocDownloader(Frame::Buffer::color,
399 : EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_BGR32F,
400 0 : _impl->glewContext);
401 0 : break;
402 : case GL_DEPTH24_STENCIL8:
403 0 : image.allocDownloader(
404 : Frame::Buffer::color,
405 : EQ_COMPRESSOR_TRANSFER_DEPTH_TO_DEPTH_UNSIGNED_INT,
406 0 : _impl->glewContext);
407 0 : break;
408 :
409 : default:
410 0 : LBUNIMPLEMENTED;
411 0 : return;
412 : }
413 :
414 : image.setPixelViewport(
415 0 : eq::PixelViewport(0, 0, _impl->width, _impl->height));
416 0 : if (image.startReadback(Frame::Buffer::color, this, _impl->glewContext))
417 0 : image.finishReadback(_impl->glewContext);
418 0 : image.writeImage(filename + ".rgb", Frame::Buffer::color);
419 0 : image.resetPlugins();
420 : }
421 :
422 0 : GLenum Texture::getTarget() const
423 : {
424 0 : return _impl->target;
425 : }
426 0 : GLuint Texture::getInternalFormat() const
427 : {
428 0 : return _impl->internalFormat;
429 : }
430 0 : GLuint Texture::getFormat() const
431 : {
432 0 : return _impl->format;
433 : }
434 0 : GLuint Texture::getType() const
435 : {
436 0 : return _impl->type;
437 : }
438 0 : GLuint Texture::getName() const
439 : {
440 0 : return _impl->name;
441 : }
442 0 : int32_t Texture::getWidth() const
443 : {
444 0 : return _impl->width;
445 : }
446 0 : int32_t Texture::getHeight() const
447 : {
448 0 : return _impl->height;
449 : }
450 0 : const GLEWContext* Texture::glewGetContext() const
451 : {
452 0 : return _impl->glewContext;
453 : }
454 :
455 0 : void Texture::setGLEWContext(const GLEWContext* context)
456 : {
457 0 : _impl->glewContext = context;
458 0 : }
459 :
460 0 : std::ostream& operator<<(std::ostream& os, const Texture& texture)
461 : {
462 0 : return os << "Texture " << texture.getWidth() << "x" << texture.getHeight()
463 0 : << " id " << texture.getName() << std::hex << " format "
464 0 : << texture.getFormat() << " type " << texture.getType()
465 0 : << std::dec << (texture.isValid() ? "" : " invalid");
466 : }
467 : }
468 30 : }
|