Line data Source code
1 :
2 : /* Copyright (c) 2009-2015, 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/image.h>
25 : #include <eq/gl.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 1634 : Texture( const GLenum tgt, const GLEWContext* const gl )
38 : : name( 0 )
39 : , target( tgt )
40 : , internalFormat( 0 )
41 : , format( 0 )
42 : , type( 0 )
43 : , width( 0 )
44 : , height( 0 )
45 : , defined( false )
46 1634 : , glewContext( gl )
47 1634 : {}
48 :
49 14 : ~Texture()
50 : {
51 14 : if( name != 0 )
52 0 : LBWARN << "OpenGL texture " << name << " not freed" << std::endl;
53 :
54 14 : name = 0;
55 14 : defined = false;
56 14 : }
57 :
58 : GLuint name;
59 : const GLenum target;
60 : GLuint internalFormat;
61 : GLuint format;
62 : GLuint type;
63 : int32_t width;
64 : int32_t height;
65 : bool defined;
66 : const GLEWContext* glewContext;
67 : };
68 : }
69 :
70 1634 : Texture::Texture( const unsigned target, const GLEWContext* const glewContext )
71 1634 : : _impl( new detail::Texture( target, glewContext ))
72 1634 : {}
73 :
74 28 : Texture::~Texture()
75 : {
76 14 : delete _impl;
77 14 : }
78 0 : bool Texture::isValid() const
79 : {
80 0 : return ( _impl->name != 0 && _impl->defined );
81 : }
82 :
83 0 : void Texture::flush()
84 : {
85 0 : if( _impl->name == 0 )
86 0 : return;
87 :
88 0 : LB_TS_THREAD( _thread );
89 0 : EQ_GL_CALL( glDeleteTextures( 1, &_impl->name ));
90 0 : _impl->name = 0;
91 0 : _impl->defined = false;
92 : }
93 :
94 0 : void Texture::flushNoDelete()
95 : {
96 0 : LB_TS_THREAD( _thread );
97 0 : _impl->name = 0;
98 0 : _impl->defined = false;
99 0 : }
100 :
101 0 : uint32_t Texture::getCompressorTarget() const
102 : {
103 0 : switch( _impl->target )
104 : {
105 : case GL_TEXTURE_RECTANGLE_ARB:
106 0 : return EQ_COMPRESSOR_USE_TEXTURE_RECT;
107 :
108 : default:
109 0 : LBUNIMPLEMENTED;
110 : case GL_TEXTURE_2D:
111 0 : return EQ_COMPRESSOR_USE_TEXTURE_2D;
112 : }
113 : }
114 :
115 0 : void Texture::_setInternalFormat( const GLuint internalFormat )
116 : {
117 0 : if( _impl->internalFormat == internalFormat )
118 0 : return;
119 :
120 0 : _impl->defined = false;
121 0 : _impl->internalFormat = internalFormat;
122 :
123 0 : switch( internalFormat )
124 : {
125 : // depth format
126 : case GL_DEPTH_COMPONENT:
127 0 : setExternalFormat( GL_DEPTH_COMPONENT, GL_UNSIGNED_INT );
128 0 : break;
129 : case GL_RGB10_A2:
130 0 : setExternalFormat( GL_RGBA, GL_UNSIGNED_INT_10_10_10_2 );
131 0 : break;
132 : case GL_RGBA:
133 : case GL_RGBA8:
134 0 : setExternalFormat( GL_RGBA, GL_UNSIGNED_BYTE );
135 0 : break;
136 : case GL_RGBA16F:
137 0 : setExternalFormat( GL_RGBA, GL_HALF_FLOAT );
138 0 : break;
139 : case GL_RGBA32F:
140 0 : setExternalFormat( GL_RGBA, GL_FLOAT );
141 0 : break;
142 : case GL_RGB:
143 : case GL_RGB8:
144 0 : setExternalFormat( GL_RGB, GL_UNSIGNED_BYTE );
145 0 : break;
146 : case GL_RGB16F:
147 0 : setExternalFormat( GL_RGB, GL_HALF_FLOAT );
148 0 : break;
149 : case GL_RGB32F:
150 0 : setExternalFormat( GL_RGB, GL_FLOAT );
151 0 : break;
152 : case GL_ALPHA32F_ARB:
153 0 : setExternalFormat( GL_ALPHA, GL_FLOAT );
154 0 : break;
155 : case GL_DEPTH24_STENCIL8:
156 0 : setExternalFormat( GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 );
157 0 : break;
158 : case GL_RGBA32UI:
159 0 : LBASSERT( _impl->glewContext );
160 0 : if( GLEW_EXT_texture_integer )
161 0 : setExternalFormat( GL_RGBA_INTEGER_EXT, GL_UNSIGNED_INT );
162 : else
163 0 : LBUNIMPLEMENTED;
164 0 : break;
165 :
166 : default:
167 0 : LBUNIMPLEMENTED;
168 0 : setExternalFormat( internalFormat, GL_UNSIGNED_BYTE );
169 : }
170 : }
171 :
172 0 : void Texture::setExternalFormat( const uint32_t format, const uint32_t type )
173 : {
174 0 : _impl->format = format;
175 0 : _impl->type = type;
176 0 : }
177 :
178 0 : void Texture::_generate()
179 : {
180 0 : LB_TS_THREAD( _thread );
181 0 : if( _impl->name != 0 )
182 0 : return;
183 :
184 0 : _impl->defined = false;
185 0 : EQ_GL_CALL( glGenTextures( 1, &_impl->name ));
186 : }
187 :
188 0 : void Texture::init( const GLuint format, const int32_t width,
189 : const int32_t height )
190 : {
191 0 : _generate();
192 0 : _setInternalFormat( format );
193 0 : resize( width, height );
194 0 : }
195 :
196 0 : void Texture::setGLData( const GLuint id, const GLuint internalFormat,
197 : const int32_t width, const int32_t height )
198 : {
199 0 : flush();
200 0 : _setInternalFormat( internalFormat );
201 0 : _impl->name = id;
202 0 : _impl->width = width;
203 0 : _impl->height = height;
204 0 : _impl->defined = true;
205 0 : }
206 :
207 : namespace
208 : {
209 : /* Check if the texture dimensions are power of two. */
210 0 : static bool _isPOT( const uint32_t width, const uint32_t height )
211 : {
212 0 : return ( width > 0 && height > 0 &&
213 0 : ( width & ( width - 1 )) == 0 &&
214 0 : ( height & ( height - 1 )) == 0 );
215 : }
216 : }
217 :
218 0 : void Texture::_grow( const int32_t width, const int32_t height )
219 : {
220 0 : if( _impl->width < width )
221 : {
222 0 : _impl->width = width;
223 0 : _impl->defined = false;
224 : }
225 :
226 0 : if( _impl->height < height )
227 : {
228 0 : _impl->height = height;
229 0 : _impl->defined = false;
230 : }
231 0 : }
232 :
233 0 : void Texture::applyZoomFilter( const ZoomFilter zoomFilter ) const
234 : {
235 0 : EQ_GL_CALL( glTexParameteri( _impl->target, GL_TEXTURE_MAG_FILTER,
236 : zoomFilter ));
237 0 : EQ_GL_CALL( glTexParameteri( _impl->target, GL_TEXTURE_MIN_FILTER,
238 : zoomFilter ));
239 0 : }
240 :
241 0 : void Texture::applyWrap() const
242 : {
243 0 : EQ_GL_CALL( glTexParameteri( _impl->target, GL_TEXTURE_WRAP_S,
244 : GL_CLAMP_TO_EDGE ));
245 0 : EQ_GL_CALL( glTexParameteri( _impl->target, GL_TEXTURE_WRAP_T,
246 : GL_CLAMP_TO_EDGE ));
247 0 : }
248 :
249 0 : void Texture::copyFromFrameBuffer( const GLuint internalFormat,
250 : const fabric::PixelViewport& pvp )
251 : {
252 0 : EQ_GL_ERROR( "before Texture::copyFromFrameBuffer" );
253 0 : LB_TS_THREAD( _thread );
254 :
255 0 : _generate();
256 0 : _setInternalFormat( internalFormat );
257 0 : _grow( pvp.w, pvp.h );
258 :
259 0 : if( _impl->defined )
260 0 : glBindTexture( _impl->target, _impl->name );
261 : else
262 0 : resize( _impl->width, _impl->height );
263 :
264 0 : EQ_GL_CALL( glCopyTexSubImage2D( _impl->target, 0, 0, 0, pvp.x, pvp.y,
265 : pvp.w, pvp.h ));
266 0 : EQ_GL_ERROR( "after Texture::copyFromFrameBuffer" );
267 0 : }
268 :
269 0 : void Texture::upload( const int32_t width, const int32_t height,
270 : 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( glGetTexImage( _impl->target, 0, _impl->format, _impl->type,
289 : 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 0 : void Texture::bindToFBO( const GLenum target, const int32_t width,
299 : const int32_t height, const int32_t samples )
300 : {
301 0 : LB_TS_THREAD( _thread );
302 0 : LBASSERT( _impl->internalFormat );
303 0 : LBASSERT( _impl->glewContext );
304 :
305 0 : _generate();
306 :
307 0 : EQ_GL_CALL( glBindTexture( _impl->target, _impl->name ));
308 0 : EQ_GL_CALL( glTexImage2D( _impl->target, 0, _impl->internalFormat, width,
309 : height, 0, _impl->format, _impl->type, 0 ));
310 0 : EQ_GL_CALL( glFramebufferTexture2DEXT( GL_FRAMEBUFFER, target,
311 : _impl->target, _impl->name, 0 ));
312 :
313 0 : if( samples > 1 )
314 : {
315 0 : EQ_GL_CALL( glTexImage2DMultisample( _impl->target, samples,
316 : _impl->internalFormat, width,
317 : height, false ));
318 : }
319 :
320 0 : _impl->width = width;
321 0 : _impl->height = height;
322 0 : _impl->defined = true;
323 0 : }
324 :
325 0 : void Texture::resize( const int32_t width, const int32_t height )
326 : {
327 0 : LB_TS_THREAD( _thread );
328 0 : LBASSERT( _impl->name );
329 0 : LBASSERT( _impl->internalFormat );
330 0 : LBASSERT( width > 0 && height > 0 );
331 :
332 0 : if( _impl->width == width && _impl->height == height && _impl->defined )
333 0 : return;
334 :
335 0 : 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 0 : EQ_GL_CALL( glBindTexture( _impl->target, _impl->name ));
342 0 : EQ_GL_CALL( glTexImage2D( _impl->target, 0, _impl->internalFormat, width,
343 : height, 0, _impl->format, _impl->type, 0 ));
344 0 : _impl->width = width;
345 0 : _impl->height = height;
346 0 : _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 : image.allocDownloader( Frame::BUFFER_COLOR,
361 : EQ_COMPRESSOR_TRANSFER_DEPTH_TO_DEPTH_UNSIGNED_INT,
362 0 : _impl->glewContext );
363 0 : break;
364 : case GL_RGB10_A2:
365 : image.allocDownloader( Frame::BUFFER_COLOR,
366 : EQ_COMPRESSOR_TRANSFER_RGB10_A2_TO_BGR10_A2,
367 0 : _impl->glewContext );
368 0 : break;
369 : case GL_RGBA:
370 : case GL_RGBA8:
371 : image.allocDownloader( Frame::BUFFER_COLOR,
372 : EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGRA,
373 0 : _impl->glewContext );
374 0 : break;
375 : case GL_RGBA16F:
376 : image.allocDownloader( Frame::BUFFER_COLOR,
377 : EQ_COMPRESSOR_TRANSFER_RGBA16F_TO_BGRA16F,
378 0 : _impl->glewContext );
379 0 : break;
380 : case GL_RGBA32F:
381 : image.allocDownloader( Frame::BUFFER_COLOR,
382 : EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_BGRA32F,
383 0 : _impl->glewContext );
384 0 : break;
385 : case GL_RGB:
386 : case GL_RGB8:
387 : image.allocDownloader( Frame::BUFFER_COLOR,
388 : EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGR,
389 0 : _impl->glewContext );
390 0 : break;
391 : case GL_RGB16F:
392 : image.allocDownloader( Frame::BUFFER_COLOR,
393 : EQ_COMPRESSOR_TRANSFER_RGBA16F_TO_BGR16F,
394 0 : _impl->glewContext );
395 0 : break;
396 : case GL_RGB32F:
397 : image.allocDownloader( Frame::BUFFER_COLOR,
398 : EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_BGR32F,
399 0 : _impl->glewContext );
400 0 : break;
401 : case GL_DEPTH24_STENCIL8:
402 : image.allocDownloader( Frame::BUFFER_COLOR,
403 : EQ_COMPRESSOR_TRANSFER_DEPTH_TO_DEPTH_UNSIGNED_INT,
404 0 : _impl->glewContext );
405 0 : break;
406 :
407 : default:
408 0 : LBUNIMPLEMENTED;
409 0 : return;
410 : }
411 :
412 : image.setPixelViewport( eq::PixelViewport( 0, 0,
413 0 : _impl->width, _impl->height ));
414 0 : if( image.startReadback( Frame::BUFFER_COLOR, this, _impl->glewContext ))
415 0 : image.finishReadback( _impl->glewContext );
416 0 : image.writeImage( filename + ".rgb", Frame::BUFFER_COLOR );
417 0 : image.resetPlugins();
418 : }
419 :
420 0 : GLenum Texture::getTarget() const { return _impl->target; }
421 0 : GLuint Texture::getInternalFormat() const { return _impl->internalFormat; }
422 0 : GLuint Texture::getFormat() const { return _impl->format; }
423 0 : GLuint Texture::getType() const { return _impl->type; }
424 0 : GLuint Texture::getName() const { return _impl->name; }
425 0 : int32_t Texture::getWidth() const { return _impl->width; }
426 0 : int32_t Texture::getHeight() const { return _impl->height; }
427 0 : const GLEWContext* Texture::glewGetContext() const{ return _impl->glewContext; }
428 :
429 0 : void Texture::setGLEWContext( const GLEWContext* context )
430 : {
431 0 : _impl->glewContext = context;
432 0 : }
433 :
434 0 : std::ostream& operator << ( std::ostream& os, const Texture& texture )
435 : {
436 : return os
437 0 : << "Texture " << texture.getWidth() << "x" << texture.getHeight()
438 0 : << " id " << texture.getName() << std::hex << " format "
439 0 : << texture.getFormat() << " type " << texture.getType() << std::dec
440 0 : << (texture.isValid() ? "" : " invalid");
441 : }
442 :
443 : }
444 42 : }
|