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