1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * OpenSceneGraph Public License for more details.
12 */
13 #include <osg/GLExtensions>
14 #include <osg/Image>
15 #include <osg/Texture>
16 #include <osg/State>
17 #include <osg/Notify>
18 #include <osg/GLU>
19 #include <osg/Timer>
20 #include <osg/ApplicationUsage>
21 #include <osg/FrameBufferObject>
22 #include <osg/TextureRectangle>
23 #include <osg/Texture1D>
24
25 #include <OpenThreads/ScopedLock>
26 #include <OpenThreads/Mutex>
27
28 #ifndef GL_TEXTURE_WRAP_R
29 #define GL_TEXTURE_WRAP_R 0x8072
30 #endif
31
32 #ifndef GL_TEXTURE_MAX_LEVEL
33 #define GL_TEXTURE_MAX_LEVEL 0x813D
34 #endif
35
36
37 #ifndef GL_UNPACK_CLIENT_STORAGE_APPLE
38 #define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2
39 #endif
40
41 #ifndef GL_APPLE_vertex_array_range
42 #define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D
43 #define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E
44 #define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F
45 #define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521
46 #define GL_STORAGE_CACHED_APPLE 0x85BE
47 #define GL_STORAGE_SHARED_APPLE 0x85BF
48 #endif
49
50 #ifndef GL_RGB565
51 #define GL_RGB565 0x8D62
52 #endif
53
54 #if 0
55 #define CHECK_CONSISTENCY checkConsistency();
56 #else
57 #define CHECK_CONSISTENCY
58 #endif
59
60 namespace osg {
61
62 ApplicationUsageProxy Texture_e0(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_MAX_TEXTURE_SIZE","Set the maximum size of textures.");
63 ApplicationUsageProxy Texture_e1(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_GL_TEXTURE_STORAGE","ON|OFF or ENABLE|DISABLE, Enables/disables usage of glTexStorage for textures where supported, default is ENABLED.");
64
65 struct InternalPixelRelations
66 {
67 GLenum sizedInternalFormat;
68 GLint internalFormat;
69 GLenum type;
70 };
71
72
73 InternalPixelRelations sizedInternalFormats[] = {
74
75 { GL_R8UI , GL_RED_INTEGER_EXT , GL_UNSIGNED_BYTE }
76 , { GL_R8I , GL_RED_INTEGER_EXT , GL_BYTE }
77 , { GL_R16UI , GL_RED_INTEGER_EXT , GL_UNSIGNED_SHORT }
78 , { GL_R16I , GL_RED_INTEGER_EXT , GL_SHORT }
79 , { GL_R32UI , GL_RED_INTEGER_EXT , GL_UNSIGNED_INT }
80 , { GL_R32I , GL_RED_INTEGER_EXT , GL_INT }
81
82 , { GL_RG8UI , GL_RG_INTEGER , GL_UNSIGNED_BYTE }
83 , { GL_RG8I , GL_RG_INTEGER , GL_BYTE }
84 , { GL_RG16UI , GL_RG_INTEGER , GL_UNSIGNED_SHORT }
85 , { GL_RG16I , GL_RG_INTEGER , GL_SHORT }
86 , { GL_RG32UI , GL_RG_INTEGER , GL_UNSIGNED_INT }
87 , { GL_RG32I , GL_RG_INTEGER , GL_INT }
88
89 , { GL_RGB8UI_EXT , GL_RGB_INTEGER_EXT , GL_UNSIGNED_BYTE }
90 , { GL_RGB8I_EXT , GL_RGB_INTEGER_EXT , GL_BYTE }
91 , { GL_RGB16UI_EXT , GL_RGB_INTEGER_EXT , GL_UNSIGNED_SHORT }
92 , { GL_RGB16I_EXT , GL_RGB_INTEGER_EXT , GL_SHORT }
93 , { GL_RGB32UI_EXT , GL_RGB_INTEGER_EXT , GL_UNSIGNED_INT }
94 , { GL_RGB32I_EXT , GL_RGB_INTEGER_EXT , GL_INT }
95
96 , { GL_RGBA8UI_EXT , GL_RGBA_INTEGER_EXT , GL_UNSIGNED_BYTE }
97 , { GL_RGBA8I_EXT , GL_RGBA_INTEGER_EXT , GL_BYTE }
98 // , { GL_RGB10_A2UI_EXT , GL_RGBA_INTEGER_EXT , GL_UNSIGNED_INT_2_10_10_10_REV }
99 , { GL_RGBA16UI_EXT , GL_RGBA_INTEGER_EXT , GL_UNSIGNED_SHORT }
100 , { GL_RGBA16I_EXT , GL_RGBA_INTEGER_EXT , GL_SHORT }
101 , { GL_RGBA32I_EXT , GL_RGBA_INTEGER_EXT , GL_INT }
102 , { GL_RGBA32UI_EXT , GL_RGBA_INTEGER_EXT , GL_UNSIGNED_INT }
103
104 , { GL_R8 , GL_RED , GL_UNSIGNED_BYTE }
105 , { GL_R16F , GL_RED , GL_HALF_FLOAT }
106 , { GL_R32F , GL_RED , GL_FLOAT }
107 , { GL_R16F , GL_RED , GL_FLOAT }
108 , { GL_RG8 , GL_RG , GL_UNSIGNED_BYTE }
109 , { GL_RG16F , GL_RG , GL_HALF_FLOAT }
110 , { GL_RG16F , GL_RG , GL_FLOAT }
111 , { GL_RG32F , GL_RG , GL_FLOAT }
112 // , ( GL_RGBA2 , GL_RGB , UNKNOWN )
113 , { GL_R3_G3_B2 , GL_RGB , GL_UNSIGNED_BYTE_3_3_2 }
114 , { GL_R3_G3_B2 , GL_RGB , GL_UNSIGNED_BYTE_2_3_3_REV }
115 , { GL_RGB4 , GL_RGB , GL_UNSIGNED_SHORT_4_4_4_4 }
116 , { GL_RGB4 , GL_RGB , GL_UNSIGNED_SHORT_4_4_4_4_REV }
117 , { GL_RGB5 , GL_RGB , GL_UNSIGNED_SHORT_5_5_5_1 }
118 , { GL_RGB5 , GL_RGB , GL_UNSIGNED_SHORT_1_5_5_5_REV }
119 , { GL_RGB8 , GL_RGB , GL_UNSIGNED_BYTE }
120 , { GL_RGB565 , GL_RGB , GL_UNSIGNED_BYTE }
121 , { GL_RGB565 , GL_RGB , GL_UNSIGNED_SHORT_5_6_5 }
122 , { GL_RGB565 , GL_RGB , GL_UNSIGNED_SHORT_5_6_5_REV }
123 // , { GL_RGB9_E5 , GL_RGB , GL_UNSIGNED_INT_9_9_9_5, }
124 // , { GL_RGB9_E5 , GL_RGB , GL_UNSIGNED_INT_5_9_9_9_REV, }
125 // , { GL_RGB9_E5 , GL_RGB , GL_HALF_FLOAT }
126 // , { GL_RGB9_E5 , GL_RGB , GL_FLOAT }
127 // , { GL_R11F_G11F_B10F , GL_RGB , GL_UNSIGNED_INT_10F_11F_11F_REV }
128 // , { GL_R11F_G11F_B10F , GL_RGB , GL_HALF_FLOAT }
129 // , { GL_R11F_G11F_B10F , GL_RGB , GL_FLOAT }
130 , { GL_RGB10 , GL_RGB , GL_UNSIGNED_INT_2_10_10_10_REV }
131 , { GL_RGB10 , GL_RGB , GL_UNSIGNED_INT_10_10_10_2 }
132 , { GL_RGB12 , GL_RGB , GL_UNSIGNED_SHORT }
133 , { GL_RGB16F_ARB , GL_RGB , GL_HALF_FLOAT }
134 , { GL_RGB32F_ARB , GL_RGB , GL_FLOAT }
135 , { GL_RGB16F_ARB , GL_RGB , GL_FLOAT }
136
137
138 , { GL_RGBA8 , GL_RGBA , GL_UNSIGNED_BYTE }
139 , { GL_RGB10_A2 , GL_RGBA , GL_UNSIGNED_INT_10_10_10_2 }
140 , { GL_RGB10_A2 , GL_RGBA , GL_UNSIGNED_INT_2_10_10_10_REV }
141 , { GL_RGBA12 , GL_RGBA , GL_UNSIGNED_SHORT }
142 , { GL_RGBA4 , GL_RGBA , GL_UNSIGNED_BYTE }
143 , { GL_RGBA4 , GL_RGBA , GL_UNSIGNED_SHORT_4_4_4_4 }
144 , { GL_RGBA4 , GL_RGBA , GL_UNSIGNED_SHORT_4_4_4_4_REV }
145 , { GL_RGB5_A1 , GL_RGBA , GL_UNSIGNED_BYTE }
146 , { GL_RGB5_A1 , GL_RGBA , GL_UNSIGNED_SHORT_5_5_5_1 }
147 , { GL_RGB5_A1 , GL_RGBA , GL_UNSIGNED_SHORT_1_5_5_5_REV }
148 , { GL_RGB5_A1 , GL_RGBA , GL_UNSIGNED_INT_10_10_10_2 }
149 , { GL_RGB5_A1 , GL_RGBA , GL_UNSIGNED_INT_2_10_10_10_REV }
150 // , { GL_RGBA16F , GL_RGBA , GL_HALF_FLOAT }
151 // , { GL_RGBA16F , GL_RGBA , GL_FLOAT }
152 // , { GL_RGBA32F , GL_RGBA , GL_FLOAT }
153
154 , { GL_SRGB8 , GL_RGB , GL_UNSIGNED_BYTE }
155 , { GL_SRGB8_ALPHA8 , GL_RGBA , GL_UNSIGNED_BYTE }
156
157 , { GL_R8_SNORM , GL_RED , GL_BYTE }
158 , { GL_R16_SNORM , GL_RED , GL_SHORT }
159 , { GL_RG8_SNORM , GL_RG , GL_BYTE }
160 , { GL_RG16_SNORM , GL_RG , GL_SHORT }
161 , { GL_RGB8_SNORM , GL_RGB , GL_BYTE }
162 , { GL_RGB16_SNORM , GL_RGB , GL_SHORT }
163 , { GL_RGBA8_SNORM , GL_RGBA , GL_BYTE }
164 };
165
166 InternalPixelRelations sizedDepthAndStencilInternalFormats[] = {
167 { GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT , GL_UNSIGNED_SHORT }
168 , { GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT , GL_UNSIGNED_INT }
169 , { GL_DEPTH_COMPONENT24 , GL_DEPTH_COMPONENT , GL_UNSIGNED_INT }
170 , { GL_DEPTH_COMPONENT32 , GL_DEPTH_COMPONENT , GL_UNSIGNED_INT }
171 , { GL_DEPTH_COMPONENT32F , GL_DEPTH_COMPONENT , GL_FLOAT }
172 // , { GL_DEPTH24_STENCIL8 , GL_DEPTH_STENCIL , GL_UNSIGNED_INT_24_8 }
173 // , { GL_DEPTH32F_STENCIL8 , GL_DEPTH_STENCIL , GL_FLOAT_32_UNSIGNED_INT_24_8_REV }
174 };
175
176 InternalPixelRelations compressedInternalFormats[] = {
177 // , { GL_COMPRESSED_RED , GL_RED , GL_COMPRESSED_RED }
178 // , { GL_COMPRESSED_RG , GL_RG , GL_COMPRESSED_RG }
179 { GL_COMPRESSED_RGB , GL_RGB , GL_COMPRESSED_RGB }
180 , { GL_COMPRESSED_RGBA , GL_RGBA , GL_COMPRESSED_RGBA }
181 , { GL_COMPRESSED_SRGB , GL_RGB , GL_COMPRESSED_SRGB }
182 , { GL_COMPRESSED_SRGB_ALPHA , GL_RGBA , GL_COMPRESSED_SRGB_ALPHA }
183 , { GL_COMPRESSED_RED_RGTC1_EXT , GL_RED , GL_COMPRESSED_RED_RGTC1_EXT }
184 , { GL_COMPRESSED_SIGNED_RED_RGTC1_EXT , GL_RED , GL_COMPRESSED_SIGNED_RED_RGTC1_EXT }
185 // , { GL_COMPRESSED_RG_RGTC2 , GL_RG , GL_COMPRESSED_RG_RGTC2 }
186 // , { GL_COMPRESSED_SIGNED_RG_RGTC2 , GL_RG , GL_COMPRESSED_SIGNED_RG_RGTC2 }
187 // , { GL_COMPRESSED_RGBA_BPTC_UNORM , GL_RGBA , GL_COMPRESSED_RGBA_BPTC_UNORM }
188 // , { GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM , GL_RGBA , GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM }
189 // , { GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT , GL_RGB , GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT }
190 // , { GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT , GL_RGB , GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT }
191
192 , { GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGB , GL_COMPRESSED_RGB_S3TC_DXT1_EXT }
193 , { GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , GL_RGBA , GL_COMPRESSED_RGBA_S3TC_DXT1_EXT }
194 , { GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , GL_RGBA , GL_COMPRESSED_RGBA_S3TC_DXT3_EXT }
195 , { GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , GL_RGBA , GL_COMPRESSED_RGBA_S3TC_DXT5_EXT }
196
197 // , { GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , GL_RGB , GL_COMPRESSED_SRGB_S3TC_DXT1_EXT }
198 // , { GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT , GL_RGBA , GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT }
199 // , { GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT , GL_RGBA , GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT }
200 // , { GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT , GL_RGBA , GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT }
201 };
202
isSizedInternalFormat(GLint internalFormat)203 bool isSizedInternalFormat(GLint internalFormat)
204 {
205 const size_t formatsCount = sizeof(sizedInternalFormats) / sizeof(sizedInternalFormats[0]);
206
207 for (size_t i=0; i < formatsCount; ++i)
208 {
209 if((GLenum)internalFormat == sizedInternalFormats[i].sizedInternalFormat)
210 return true;
211 }
212
213 return false;
214 }
215
assumeSizedInternalFormat(GLint internalFormat,GLenum type)216 GLenum assumeSizedInternalFormat(GLint internalFormat, GLenum type)
217 {
218 const size_t formatsCount = sizeof(sizedInternalFormats) / sizeof(sizedInternalFormats[0]);
219
220 for (size_t i=0; i < formatsCount; ++i)
221 {
222 if(internalFormat == sizedInternalFormats[i].internalFormat && type == sizedInternalFormats[i].type)
223 return sizedInternalFormats[i].sizedInternalFormat;
224 }
225
226 return 0;
227 }
228
isCompressedInternalFormatSupportedByTexStorrage(GLint internalFormat)229 bool isCompressedInternalFormatSupportedByTexStorrage(GLint internalFormat)
230 {
231 const size_t formatsCount = sizeof(compressedInternalFormats) / sizeof(compressedInternalFormats[0]);
232
233 for (size_t i=0; i < formatsCount; ++i)
234 {
235 if((GLenum)internalFormat == compressedInternalFormats[i].sizedInternalFormat)
236 return true;
237 }
238
239 return false;
240 }
241
~TextureObject()242 Texture::TextureObject::~TextureObject()
243 {
244 // OSG_NOTICE<<"Texture::TextureObject::~TextureObject() "<<this<<std::endl;
245 }
246
bind()247 void Texture::TextureObject::bind()
248 {
249 glBindTexture( _profile._target, _id);
250 if (_set) _set->moveToBack(this);
251 }
252
setAllocated(GLint numMipmapLevels,GLenum internalFormat,GLsizei width,GLsizei height,GLsizei depth,GLint border)253 void Texture::TextureObject::setAllocated(GLint numMipmapLevels,
254 GLenum internalFormat,
255 GLsizei width,
256 GLsizei height,
257 GLsizei depth,
258 GLint border)
259 {
260 _allocated=true;
261 if (!match(_profile._target,numMipmapLevels,internalFormat,width,height,depth,border))
262 {
263 // keep previous size
264 unsigned int previousSize = _profile._size;
265
266 _profile.set(numMipmapLevels,internalFormat,width,height,depth,border);
267
268 if (_set)
269 {
270 _set->moveToSet(this, _set->getParent()->getTextureObjectSet(_profile));
271
272 // Update texture pool size
273 _set->getParent()->getCurrTexturePoolSize() -= previousSize;
274 _set->getParent()->getCurrTexturePoolSize() += _profile._size;
275 }
276 }
277 }
278
computeSize()279 void Texture::TextureProfile::computeSize()
280 {
281 unsigned int numBitsPerTexel = 32;
282
283 switch(_internalFormat)
284 {
285 case(1): numBitsPerTexel = 8; break;
286 case(GL_ALPHA): numBitsPerTexel = 8; break;
287 case(GL_LUMINANCE): numBitsPerTexel = 8; break;
288 case(GL_INTENSITY): numBitsPerTexel = 8; break;
289
290 case(GL_LUMINANCE_ALPHA): numBitsPerTexel = 16; break;
291 case(2): numBitsPerTexel = 16; break;
292
293 case(GL_RGB): numBitsPerTexel = 24; break;
294 case(GL_BGR): numBitsPerTexel = 24; break;
295 case(3): numBitsPerTexel = 24; break;
296
297 case(GL_RGBA): numBitsPerTexel = 32; break;
298 case(4): numBitsPerTexel = 32; break;
299
300 case(GL_COMPRESSED_ALPHA_ARB): numBitsPerTexel = 4; break;
301 case(GL_COMPRESSED_INTENSITY_ARB): numBitsPerTexel = 4; break;
302 case(GL_COMPRESSED_LUMINANCE_ALPHA_ARB): numBitsPerTexel = 4; break;
303 case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT): numBitsPerTexel = 4; break;
304 case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT): numBitsPerTexel = 4; break;
305
306 case(GL_COMPRESSED_RGB_ARB): numBitsPerTexel = 8; break;
307 case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): numBitsPerTexel = 8; break;
308 case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): numBitsPerTexel = 8; break;
309
310 case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT): numBitsPerTexel = 4; break;
311 case(GL_COMPRESSED_RED_RGTC1_EXT): numBitsPerTexel = 4; break;
312 case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT): numBitsPerTexel = 8; break;
313 case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT): numBitsPerTexel = 8; break;
314
315 case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG): numBitsPerTexel = 2; break;
316 case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG): numBitsPerTexel = 2; break;
317 case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG): numBitsPerTexel = 4; break;
318 case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG): numBitsPerTexel = 4; break;
319
320 case(GL_ETC1_RGB8_OES): numBitsPerTexel = 4; break;
321
322 case(GL_COMPRESSED_RGB8_ETC2): numBitsPerTexel = 4; break;
323 case(GL_COMPRESSED_SRGB8_ETC2): numBitsPerTexel = 4; break;
324 case(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2): numBitsPerTexel = 8; break;
325 case(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2): numBitsPerTexel = 8; break;
326 case(GL_COMPRESSED_RGBA8_ETC2_EAC): numBitsPerTexel = 8; break;
327 case(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC): numBitsPerTexel = 8; break;
328 case(GL_COMPRESSED_R11_EAC): numBitsPerTexel = 4; break;
329 case(GL_COMPRESSED_SIGNED_R11_EAC): numBitsPerTexel = 4; break;
330 case(GL_COMPRESSED_RG11_EAC): numBitsPerTexel = 8; break;
331 case(GL_COMPRESSED_SIGNED_RG11_EAC): numBitsPerTexel = 8; break;
332 }
333
334 _size = (unsigned int)(ceil(double(_width * _height * _depth * numBitsPerTexel)/8.0));
335
336 if (_numMipmapLevels>1)
337 {
338 unsigned int mipmapSize = _size / 4;
339 for(GLint i=0; i<_numMipmapLevels && mipmapSize!=0; ++i)
340 {
341 _size += mipmapSize;
342 mipmapSize /= 4;
343 }
344 }
345
346 // OSG_NOTICE<<"TO ("<<_width<<", "<<_height<<", "<<_depth<<") size="<<_size<<" numBitsPerTexel="<<numBitsPerTexel<<std::endl;
347 }
348
349 ///////////////////////////////////////////////////////////////////////////////////////////////////////////
350 //
351 // New texture object manager
352 //
TextureObjectSet(TextureObjectManager * parent,const TextureProfile & profile)353 Texture::TextureObjectSet::TextureObjectSet(TextureObjectManager* parent, const TextureProfile& profile):
354 _parent(parent),
355 _contextID(parent->getContextID()),
356 _profile(profile),
357 _numOfTextureObjects(0),
358 _head(0),
359 _tail(0)
360 {
361 }
362
~TextureObjectSet()363 Texture::TextureObjectSet::~TextureObjectSet()
364 {
365 #if 0
366 OSG_NOTICE<<"TextureObjectSet::~TextureObjectSet(), _numOfTextureObjects="<<_numOfTextureObjects<<std::endl;
367 OSG_NOTICE<<" _orphanedTextureObjects = "<<_orphanedTextureObjects.size()<<std::endl;
368 OSG_NOTICE<<" _head = "<<_head<<std::endl;
369 OSG_NOTICE<<" _tail = "<<_tail<<std::endl;
370 #endif
371 }
372
checkConsistency() const373 bool Texture::TextureObjectSet::checkConsistency() const
374 {
375 OSG_NOTICE<<"TextureObjectSet::checkConsistency()"<<std::endl;
376 // check consistency of linked list.
377 unsigned int numInList = 0;
378 Texture::TextureObject* to = _head;
379 while(to!=0)
380 {
381 ++numInList;
382
383 if (to->_next)
384 {
385 if ((to->_next)->_previous != to)
386 {
387 OSG_NOTICE<<"Texture::TextureObjectSet::checkConsistency() : Error (to->_next)->_previous != to "<<std::endl;
388 return false;
389 }
390 }
391 else
392 {
393 if (_tail != to)
394 {
395 OSG_NOTICE<<"Texture::TextureObjectSet::checkConsistency() : Error _tail != to"<<std::endl;
396 return false;
397 }
398 }
399
400 to = to->_next;
401 }
402
403 unsigned int totalNumber = numInList + _orphanedTextureObjects.size();
404 if (totalNumber != _numOfTextureObjects)
405 {
406 OSG_NOTICE<<"Error numInList + _orphanedTextureObjects.size() != _numOfTextureObjects"<<std::endl;
407 OSG_NOTICE<<" numInList = "<<numInList<<std::endl;
408 OSG_NOTICE<<" _orphanedTextureObjects.size() = "<<_orphanedTextureObjects.size()<<std::endl;
409 OSG_NOTICE<<" _pendingOrphanedTextureObjects.size() = "<<_pendingOrphanedTextureObjects.size()<<std::endl;
410 OSG_NOTICE<<" _numOfTextureObjects = "<<_numOfTextureObjects<<std::endl;
411 return false;
412 }
413
414 _parent->checkConsistency();
415
416 return true;
417 }
418
handlePendingOrphandedTextureObjects()419 void Texture::TextureObjectSet::handlePendingOrphandedTextureObjects()
420 {
421 // OSG_NOTICE<<"handlePendingOrphandedTextureObjects()"<<_pendingOrphanedTextureObjects.size()<<std::endl;
422
423 if (_pendingOrphanedTextureObjects.empty()) return;
424
425 unsigned int numOrphaned = _pendingOrphanedTextureObjects.size();
426
427 for(TextureObjectList::iterator itr = _pendingOrphanedTextureObjects.begin();
428 itr != _pendingOrphanedTextureObjects.end();
429 ++itr)
430 {
431 TextureObject* to = itr->get();
432
433 _orphanedTextureObjects.push_back(to);
434
435 remove(to);
436 }
437
438
439 // update the TextureObjectManager's running total of active + orphaned TextureObjects
440 _parent->getNumberOrphanedTextureObjects() += numOrphaned;
441 _parent->getNumberActiveTextureObjects() -= numOrphaned;
442
443 _pendingOrphanedTextureObjects.clear();
444
445 CHECK_CONSISTENCY
446 }
447
448
deleteAllTextureObjects()449 void Texture::TextureObjectSet::deleteAllTextureObjects()
450 {
451 // OSG_NOTICE<<"Texture::TextureObjectSet::deleteAllTextureObjects()"<<std::endl;
452
453 {
454 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
455 if (!_pendingOrphanedTextureObjects.empty())
456 {
457 // OSG_NOTICE<<"Texture::TextureObjectSet::flushDeletedTextureObjects(..) handling orphans"<<std::endl;
458 handlePendingOrphandedTextureObjects();
459 }
460 }
461
462 CHECK_CONSISTENCY
463
464 // detect all the active texture objects from their Textures
465 unsigned int numOrphaned = 0;
466 TextureObject* to = _head;
467 while(to!=0)
468 {
469 ref_ptr<TextureObject> glto = to;
470
471 to = to->_next;
472
473 _orphanedTextureObjects.push_back(glto.get());
474
475 remove(glto.get());
476
477 ++numOrphaned;
478
479 ref_ptr<Texture> original_texture = glto->getTexture();
480 if (original_texture.valid())
481 {
482 original_texture->setTextureObject(_contextID,0);
483 }
484 }
485
486 _parent->getNumberOrphanedTextureObjects() += numOrphaned;
487 _parent->getNumberActiveTextureObjects() -= numOrphaned;
488
489 // now do the actual delete.
490 flushAllDeletedTextureObjects();
491
492 // OSG_NOTICE<<"done GLBufferObjectSet::deleteAllGLBufferObjects()"<<std::endl;
493 }
494
discardAllTextureObjects()495 void Texture::TextureObjectSet::discardAllTextureObjects()
496 {
497 // OSG_NOTICE<<"Texture::TextureObjectSet::discardAllTextureObjects()."<<std::endl;
498
499 TextureObject* to = _head;
500 while(to!=0)
501 {
502 ref_ptr<TextureObject> glto = to;
503
504 to = to->_next;
505
506 ref_ptr<Texture> original_texture = glto->getTexture();
507
508 if (original_texture.valid())
509 {
510 original_texture->setTextureObject(_contextID,0);
511 }
512 }
513
514 // the linked list should now be empty
515 _head = 0;
516 _tail = 0;
517
518 _pendingOrphanedTextureObjects.clear();
519 _orphanedTextureObjects.clear();
520
521 unsigned int numDeleted = _numOfTextureObjects;
522 _numOfTextureObjects = 0;
523
524 // update the TextureObjectManager's running total of current pool size
525 _parent->getCurrTexturePoolSize() -= numDeleted*_profile._size;
526 _parent->getNumberOrphanedTextureObjects() -= numDeleted;
527 _parent->getNumberDeleted() += numDeleted;
528 }
529
flushAllDeletedTextureObjects()530 void Texture::TextureObjectSet::flushAllDeletedTextureObjects()
531 {
532 // OSG_NOTICE<<"Texture::TextureObjectSet::flushAllDeletedTextureObjects()"<<std::endl;
533 {
534 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
535 if (!_pendingOrphanedTextureObjects.empty())
536 {
537 // OSG_NOTICE<<"Texture::TextureObjectSet::flushDeletedTextureObjects(..) handling orphans"<<std::endl;
538 handlePendingOrphandedTextureObjects();
539 }
540 }
541
542 for(TextureObjectList::iterator itr = _orphanedTextureObjects.begin();
543 itr != _orphanedTextureObjects.end();
544 ++itr)
545 {
546
547 GLuint id = (*itr)->id();
548
549 // OSG_NOTICE<<" Deleting textureobject ptr="<<itr->get()<<" id="<<id<<std::endl;
550 glDeleteTextures( 1L, &id);
551 }
552
553 unsigned int numDeleted = _orphanedTextureObjects.size();
554 _numOfTextureObjects -= numDeleted;
555
556 // update the TextureObjectManager's running total of current pool size
557 _parent->getCurrTexturePoolSize() -= numDeleted*_profile._size;
558 _parent->getNumberOrphanedTextureObjects() -= numDeleted;
559 _parent->getNumberDeleted() += numDeleted;
560
561 _orphanedTextureObjects.clear();
562 }
563
discardAllDeletedTextureObjects()564 void Texture::TextureObjectSet::discardAllDeletedTextureObjects()
565 {
566 // OSG_NOTICE<<"Texture::TextureObjectSet::discardAllDeletedTextureObjects()"<<std::endl;
567
568 // clean up the pending orphans.
569 {
570 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
571 if (!_pendingOrphanedTextureObjects.empty())
572 {
573 // OSG_NOTICE<<"Texture::TextureObjectSet::flushDeletedTextureObjects(..) handling orphans"<<std::endl;
574 handlePendingOrphandedTextureObjects();
575 }
576 }
577
578 unsigned int numDiscarded = _orphanedTextureObjects.size();
579
580 _numOfTextureObjects -= numDiscarded;
581
582 // update the TextureObjectManager's running total of current pool size
583 _parent->getCurrTexturePoolSize() -= numDiscarded*_profile._size;
584
585 // update the number of active and orphaned TextureObjects
586 _parent->getNumberOrphanedTextureObjects() -= numDiscarded;
587 _parent->getNumberDeleted() += numDiscarded;
588
589 // just clear the list as there is nothing else we can do with them when discarding them
590 _orphanedTextureObjects.clear();
591 }
592
flushDeletedTextureObjects(double,double & availableTime)593 void Texture::TextureObjectSet::flushDeletedTextureObjects(double /*currentTime*/, double& availableTime)
594 {
595 // OSG_NOTICE<<"Texture::TextureObjectSet::flushDeletedTextureObjects(..)"<<std::endl;
596
597 {
598 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
599 if (!_pendingOrphanedTextureObjects.empty())
600 {
601 // OSG_NOTICE<<"Texture::TextureObjectSet::flushDeletedTextureObjects(..) handling orphans"<<std::endl;
602 handlePendingOrphandedTextureObjects();
603 }
604 }
605
606 if (_profile._size!=0 && _parent->getCurrTexturePoolSize()<=_parent->getMaxTexturePoolSize())
607 {
608 // OSG_NOTICE<<"Plenty of space in TextureObject pool"<<std::endl;
609 return;
610 }
611
612 // if nothing to delete return
613 if (_orphanedTextureObjects.empty())
614 {
615 return;
616 }
617
618 // if no time available don't try to flush objects.
619 if (availableTime<=0.0) return;
620
621 unsigned int numDeleted = 0;
622 unsigned int sizeRequired = _parent->getCurrTexturePoolSize() - _parent->getMaxTexturePoolSize();
623
624 unsigned int maxNumObjectsToDelete = _profile._size!=0 ?
625 static_cast<unsigned int>(ceil(double(sizeRequired) / double(_profile._size))):
626 _orphanedTextureObjects.size();
627
628 OSG_INFO<<"_parent->getCurrTexturePoolSize()="<<_parent->getCurrTexturePoolSize() <<" _parent->getMaxTexturePoolSize()="<< _parent->getMaxTexturePoolSize()<<std::endl;
629 OSG_INFO<<"Looking to reclaim "<<sizeRequired<<", going to look to remove "<<maxNumObjectsToDelete<<" from "<<_orphanedTextureObjects.size()<<" orphans"<<std::endl;
630
631 ElapsedTime timer;
632
633 TextureObjectList::iterator itr = _orphanedTextureObjects.begin();
634 for(;
635 itr != _orphanedTextureObjects.end() && timer.elapsedTime()<availableTime && numDeleted<maxNumObjectsToDelete;
636 ++itr)
637 {
638
639 GLuint id = (*itr)->id();
640
641 // OSG_NOTICE<<" Deleting textureobject ptr="<<itr->get()<<" id="<<id<<std::endl;
642 glDeleteTextures( 1L, &id);
643
644 ++numDeleted;
645 }
646
647 // OSG_NOTICE<<"Size before = "<<_orphanedTextureObjects.size();
648 _orphanedTextureObjects.erase(_orphanedTextureObjects.begin(), itr);
649 // OSG_NOTICE<<", after = "<<_orphanedTextureObjects.size()<<" numDeleted = "<<numDeleted<<std::endl;
650
651 // update the number of TO's in this TextureObjectSet
652 _numOfTextureObjects -= numDeleted;
653
654 _parent->getCurrTexturePoolSize() -= numDeleted*_profile._size;
655
656 // update the number of active and orphaned TextureObjects
657 _parent->getNumberOrphanedTextureObjects() -= numDeleted;
658 _parent->getNumberDeleted() += numDeleted;
659
660 availableTime -= timer.elapsedTime();
661 }
662
makeSpace(unsigned int & size)663 bool Texture::TextureObjectSet::makeSpace(unsigned int& size)
664 {
665 {
666 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
667 if (!_pendingOrphanedTextureObjects.empty())
668 {
669 // OSG_NOTICE<<"Texture::TextureObjectSet::Texture::TextureObjectSet::makeSpace(..) handling orphans"<<std::endl;
670 handlePendingOrphandedTextureObjects();
671 }
672 }
673
674 if (!_orphanedTextureObjects.empty())
675 {
676 unsigned int sizeAvailable = _orphanedTextureObjects.size() * _profile._size;
677 if (size>sizeAvailable) size -= sizeAvailable;
678 else size = 0;
679
680 flushAllDeletedTextureObjects();
681 }
682
683 return size==0;
684 }
685
takeFromOrphans(Texture * texture)686 osg::ref_ptr<Texture::TextureObject> Texture::TextureObjectSet::takeFromOrphans(Texture* texture)
687 {
688 // take front of orphaned list.
689 ref_ptr<TextureObject> to = _orphanedTextureObjects.front();
690
691 // remove from orphan list.
692 _orphanedTextureObjects.pop_front();
693
694 // assign to new texture
695 to->setTexture(texture);
696
697 // update the number of active and orphaned TextureObjects
698 _parent->getNumberOrphanedTextureObjects() -= 1;
699 _parent->getNumberActiveTextureObjects() += 1;
700
701 // place at back of active list
702 addToBack(to.get());
703
704 OSG_INFO<<"Reusing orphaned TextureObject, _numOfTextureObjects="<<_numOfTextureObjects<<std::endl;
705
706 return to;
707 }
708
709
takeOrGenerate(Texture * texture)710 osg::ref_ptr<Texture::TextureObject> Texture::TextureObjectSet::takeOrGenerate(Texture* texture)
711 {
712 // see if we can recyle TextureObject from the orphan list
713 {
714 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
715 if (!_pendingOrphanedTextureObjects.empty())
716 {
717 handlePendingOrphandedTextureObjects();
718 return takeFromOrphans(texture);
719 }
720 }
721
722 if (!_orphanedTextureObjects.empty())
723 {
724 return takeFromOrphans(texture);
725 }
726
727 unsigned int minFrameNumber = _parent->getFrameNumber();
728
729 // see if we can reuse TextureObject by taking the least recently used active TextureObject
730 if ((_parent->getMaxTexturePoolSize()!=0) &&
731 (!_parent->hasSpace(_profile._size)) &&
732 (_numOfTextureObjects>1) &&
733 (_head != 0) &&
734 (_head->_frameLastUsed<minFrameNumber))
735 {
736
737 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
738
739 ref_ptr<TextureObject> to = _head;
740
741 ref_ptr<Texture> original_texture = to->getTexture();
742
743 if (original_texture.valid())
744 {
745 original_texture->setTextureObject(_contextID,0);
746 OSG_INFO<<"TextureObjectSet="<<this<<": Reusing an active TextureObject "<<to.get()<<" _numOfTextureObjects="<<_numOfTextureObjects<<" width="<<_profile._width<<" height="<<_profile._height<<std::endl;
747 }
748 else
749 {
750 OSG_INFO<<"Reusing a recently orphaned active TextureObject "<<to.get()<<std::endl;
751 }
752
753 moveToBack(to.get());
754
755 // assign to new texture
756 to->setTexture(texture);
757
758 return to;
759 }
760
761 //
762 // no TextureObjects available to recycle so have to create one from scratch
763 //
764 GLuint id;
765 glGenTextures( 1L, &id );
766
767 osg::ref_ptr<TextureObject> to = new Texture::TextureObject(const_cast<Texture*>(texture),id,_profile);
768 to->_set = this;
769 ++_numOfTextureObjects;
770
771 // update the current texture pool size
772 _parent->getCurrTexturePoolSize() += _profile._size;
773 _parent->getNumberActiveTextureObjects() += 1;
774
775 addToBack(to.get());
776
777 OSG_INFO<<"Created new " << this << " TextureObject, _numOfTextureObjects "<<_numOfTextureObjects<<std::endl;
778
779 return to;
780 }
781
moveToBack(Texture::TextureObject * to)782 void Texture::TextureObjectSet::moveToBack(Texture::TextureObject* to)
783 {
784 #if 0
785 OSG_NOTICE<<"TextureObjectSet::moveToBack("<<to<<")"<<std::endl;
786 OSG_NOTICE<<" before _head = "<<_head<<std::endl;
787 OSG_NOTICE<<" before _tail = "<<_tail<<std::endl;
788 OSG_NOTICE<<" before to->_previous = "<<to->_previous<<std::endl;
789 OSG_NOTICE<<" before to->_next = "<<to->_next<<std::endl;
790 #endif
791
792 to->_frameLastUsed = _parent->getFrameNumber();
793
794 // nothing to do if we are already tail
795 if (to==_tail) return;
796
797 // if no tail exists then assign 'to' as tail and head
798 if (_tail==0)
799 {
800 OSG_NOTICE<<"Error ***************** Should not get here !!!!!!!!!"<<std::endl;
801 _head = to;
802 _tail = to;
803 return;
804 }
805
806 if (to->_next==0)
807 {
808 OSG_NOTICE<<"Error ***************** Should not get here either !!!!!!!!!"<<std::endl;
809 return;
810 }
811
812
813 if (to->_previous)
814 {
815 (to->_previous)->_next = to->_next;
816 }
817 else
818 {
819 // 'to' is the head, so moving it to the back will mean we need a new head
820 if (to->_next)
821 {
822 _head = to->_next;
823 }
824 }
825
826 (to->_next)->_previous = to->_previous;
827
828 _tail->_next = to;
829
830 to->_previous = _tail;
831 to->_next = 0;
832
833 _tail = to;
834
835 #if 0
836 OSG_NOTICE<<" m2B after _head = "<<_head<<std::endl;
837 OSG_NOTICE<<" m2B after _tail = "<<_tail<<std::endl;
838 OSG_NOTICE<<" m2B after to->_previous = "<<to->_previous<<std::endl;
839 OSG_NOTICE<<" m2B after to->_next = "<<to->_next<<std::endl;
840 #endif
841 CHECK_CONSISTENCY
842 }
843
addToBack(Texture::TextureObject * to)844 void Texture::TextureObjectSet::addToBack(Texture::TextureObject* to)
845 {
846 #if 0
847 OSG_NOTICE<<"TextureObjectSet::addToBack("<<to<<")"<<std::endl;
848 OSG_NOTICE<<" before _head = "<<_head<<std::endl;
849 OSG_NOTICE<<" before _tail = "<<_tail<<std::endl;
850 OSG_NOTICE<<" before to->_previous = "<<to->_previous<<std::endl;
851 OSG_NOTICE<<" before to->_next = "<<to->_next<<std::endl;
852 #endif
853
854 if (to->_previous !=0 || to->_next !=0)
855 {
856 moveToBack(to);
857 }
858 else
859 {
860 to->_frameLastUsed = _parent->getFrameNumber();
861
862 if (_tail) _tail->_next = to;
863 to->_previous = _tail;
864
865 if (!_head) _head = to;
866 _tail = to;
867 }
868 #if 0
869 OSG_NOTICE<<" a2B after _head = "<<_head<<std::endl;
870 OSG_NOTICE<<" a2B after _tail = "<<_tail<<std::endl;
871 OSG_NOTICE<<" a2B after to->_previous = "<<to->_previous<<std::endl;
872 OSG_NOTICE<<" a2B after to->_next = "<<to->_next<<std::endl;
873 #endif
874 CHECK_CONSISTENCY
875 }
876
orphan(Texture::TextureObject * to)877 void Texture::TextureObjectSet::orphan(Texture::TextureObject* to)
878 {
879 // OSG_NOTICE<<"TextureObjectSet::orphan("<<to<<")"<<std::endl;
880
881 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
882
883 // disconnect from original texture
884 to->setTexture(0);
885
886 // add orphan 'to' to the pending list of orphans, these will then be
887 // handled in the handlePendingOrphandedTextureObjects() where the TO's
888 // will be removed from the active list, and then placed in the orhpanTextureObject
889 // list. This double buffered approach to handling orphaned TO's is used
890 // to avoid having to mutex the process of appling active TO's.
891 _pendingOrphanedTextureObjects.push_back(to);
892
893 #if 0
894 OSG_NOTICE<<"TextureObjectSet::orphan("<<to<<") _pendingOrphanedTextureObjects.size()="<<_pendingOrphanedTextureObjects.size()<<std::endl;
895 OSG_NOTICE<<" _orphanedTextureObjects.size()="<<_orphanedTextureObjects.size()<<std::endl;
896 #endif
897 }
898
remove(Texture::TextureObject * to)899 void Texture::TextureObjectSet::remove(Texture::TextureObject* to)
900 {
901 if (to->_previous!=0)
902 {
903 (to->_previous)->_next = to->_next;
904 }
905 else
906 {
907 // 'to' was head so assign _head to the next in list
908 _head = to->_next;
909 }
910
911 if (to->_next!=0)
912 {
913 (to->_next)->_previous = to->_previous;
914 }
915 else
916 {
917 // 'to' was tail so assing tail to the previous in list
918 _tail = to->_previous;
919 }
920
921 // reset the 'to' list pointers as it's no longer in the active list.
922 to->_next = 0;
923 to->_previous = 0;
924 }
925
moveToSet(TextureObject * to,TextureObjectSet * set)926 void Texture::TextureObjectSet::moveToSet(TextureObject* to, TextureObjectSet* set)
927 {
928 if (set==this) return;
929 if (!set) return;
930
931 // remove 'to' from original set
932 --_numOfTextureObjects;
933 remove(to);
934
935 // register 'to' with new set.
936 to->_set = set;
937 ++set->_numOfTextureObjects;
938 set->addToBack(to);
939 }
940
computeNumTextureObjectsInList() const941 unsigned int Texture::TextureObjectSet::computeNumTextureObjectsInList() const
942 {
943 unsigned int num=0;
944 TextureObject* obj = _head;
945 while(obj!=NULL)
946 {
947 ++num;
948 obj = obj->_next;
949 }
950 return num;
951 }
952
953
TextureObjectManager(unsigned int contextID)954 Texture::TextureObjectManager::TextureObjectManager(unsigned int contextID):
955 _contextID(contextID),
956 _numActiveTextureObjects(0),
957 _numOrphanedTextureObjects(0),
958 _currTexturePoolSize(0),
959 _maxTexturePoolSize(0),
960 _frameNumber(0),
961 _numFrames(0),
962 _numDeleted(0),
963 _deleteTime(0.0),
964 _numGenerated(0),
965 _generateTime(0.0),
966 _numApplied(0),
967 _applyTime(0.0)
968 {
969 }
970
setMaxTexturePoolSize(unsigned int size)971 void Texture::TextureObjectManager::setMaxTexturePoolSize(unsigned int size)
972 {
973 if (_maxTexturePoolSize == size) return;
974
975 if (size<_currTexturePoolSize)
976 {
977 OSG_NOTICE<<"Warning: new MaxTexturePoolSize="<<size<<" is smaller than current TexturePoolSize="<<_currTexturePoolSize<<std::endl;
978 }
979
980 _maxTexturePoolSize = size;
981 }
982
makeSpace(unsigned int size)983 bool Texture::TextureObjectManager::makeSpace(unsigned int size)
984 {
985 for(TextureSetMap::iterator itr = _textureSetMap.begin();
986 itr != _textureSetMap.end() && size>0;
987 ++itr)
988 {
989 if ((*itr).second->makeSpace(size)) return true;
990 }
991
992 return size==0;
993 }
994
995
generateTextureObject(const Texture * texture,GLenum target)996 osg::ref_ptr<Texture::TextureObject> Texture::TextureObjectManager::generateTextureObject(const Texture* texture, GLenum target)
997 {
998 return generateTextureObject(texture, target, 0, 0, 0, 0, 0, 0);
999 }
1000
generateTextureObject(const Texture * texture,GLenum target,GLint numMipmapLevels,GLenum internalFormat,GLsizei width,GLsizei height,GLsizei depth,GLint border)1001 osg::ref_ptr<Texture::TextureObject> Texture::TextureObjectManager::generateTextureObject(const Texture* texture,
1002 GLenum target,
1003 GLint numMipmapLevels,
1004 GLenum internalFormat,
1005 GLsizei width,
1006 GLsizei height,
1007 GLsizei depth,
1008 GLint border)
1009 {
1010 ElapsedTime elapsedTime(&(getGenerateTime()));
1011 ++getNumberGenerated();
1012
1013 Texture::TextureProfile profile(target,numMipmapLevels,internalFormat,width,height,depth,border);
1014 TextureObjectSet* tos = getTextureObjectSet(profile);
1015 return tos->takeOrGenerate(const_cast<Texture*>(texture));
1016 }
1017
generateAndAssignTextureObject(unsigned int contextID,GLenum target) const1018 Texture::TextureObject* Texture::generateAndAssignTextureObject(unsigned int contextID, GLenum target) const
1019 {
1020 _textureObjectBuffer[contextID] = generateTextureObject(this, contextID, target);
1021 return _textureObjectBuffer[contextID].get();
1022 }
1023
generateAndAssignTextureObject(unsigned int contextID,GLenum target,GLint numMipmapLevels,GLenum internalFormat,GLsizei width,GLsizei height,GLsizei depth,GLint border) const1024 Texture::TextureObject* Texture::generateAndAssignTextureObject(
1025 unsigned int contextID,
1026 GLenum target,
1027 GLint numMipmapLevels,
1028 GLenum internalFormat,
1029 GLsizei width,
1030 GLsizei height,
1031 GLsizei depth,
1032 GLint border) const
1033 {
1034 _textureObjectBuffer[contextID] = generateTextureObject(this, contextID, target, numMipmapLevels, internalFormat, width, height, depth, border);
1035 return _textureObjectBuffer[contextID].get();
1036 }
1037
getTextureObjectSet(const TextureProfile & profile)1038 Texture::TextureObjectSet* Texture::TextureObjectManager::getTextureObjectSet(const TextureProfile& profile)
1039 {
1040 osg::ref_ptr<Texture::TextureObjectSet>& tos = _textureSetMap[profile];
1041 if (!tos) tos = new Texture::TextureObjectSet(this, profile);
1042 return tos.get();
1043 }
1044
handlePendingOrphandedTextureObjects()1045 void Texture::TextureObjectManager::handlePendingOrphandedTextureObjects()
1046 {
1047 for(TextureSetMap::iterator itr = _textureSetMap.begin();
1048 itr != _textureSetMap.end();
1049 ++itr)
1050 {
1051 (*itr).second->handlePendingOrphandedTextureObjects();
1052 }
1053 }
1054
deleteAllTextureObjects()1055 void Texture::TextureObjectManager::deleteAllTextureObjects()
1056 {
1057 // OSG_NOTICE<<"Texture::TextureObjectManager::deleteAllTextureObjects() _contextID="<<_contextID<<std::endl;
1058
1059 ElapsedTime elapsedTime(&(getDeleteTime()));
1060
1061 for(TextureSetMap::iterator itr = _textureSetMap.begin();
1062 itr != _textureSetMap.end();
1063 ++itr)
1064 {
1065 (*itr).second->deleteAllTextureObjects();
1066 }
1067 }
1068
discardAllTextureObjects()1069 void Texture::TextureObjectManager::discardAllTextureObjects()
1070 {
1071 // OSG_NOTICE<<"Texture::TextureObjectManager::discardAllTextureObjects() _contextID="<<_contextID<<" _numActiveTextureObjects="<<_numActiveTextureObjects<<std::endl;
1072
1073 for(TextureSetMap::iterator itr = _textureSetMap.begin();
1074 itr != _textureSetMap.end();
1075 ++itr)
1076 {
1077 (*itr).second->discardAllTextureObjects();
1078 }
1079 }
1080
flushAllDeletedTextureObjects()1081 void Texture::TextureObjectManager::flushAllDeletedTextureObjects()
1082 {
1083 // OSG_NOTICE<<"Texture::TextureObjectManager::flushAllDeletedTextureObjects() _contextID="<<_contextID<<std::endl;
1084
1085 ElapsedTime elapsedTime(&(getDeleteTime()));
1086
1087 for(TextureSetMap::iterator itr = _textureSetMap.begin();
1088 itr != _textureSetMap.end();
1089 ++itr)
1090 {
1091 (*itr).second->flushAllDeletedTextureObjects();
1092 }
1093 }
1094
discardAllDeletedTextureObjects()1095 void Texture::TextureObjectManager::discardAllDeletedTextureObjects()
1096 {
1097 // OSG_NOTICE<<"Texture::TextureObjectManager::discardAllDeletedTextureObjects() _contextID="<<_contextID<<" _numActiveTextureObjects="<<_numActiveTextureObjects<<std::endl;
1098
1099 for(TextureSetMap::iterator itr = _textureSetMap.begin();
1100 itr != _textureSetMap.end();
1101 ++itr)
1102 {
1103 (*itr).second->discardAllDeletedTextureObjects();
1104 }
1105 }
1106
flushDeletedTextureObjects(double currentTime,double & availableTime)1107 void Texture::TextureObjectManager::flushDeletedTextureObjects(double currentTime, double& availableTime)
1108 {
1109 ElapsedTime elapsedTime(&(getDeleteTime()));
1110
1111 for(TextureSetMap::iterator itr = _textureSetMap.begin();
1112 (itr != _textureSetMap.end()) && (availableTime > 0.0);
1113 ++itr)
1114 {
1115 (*itr).second->flushDeletedTextureObjects(currentTime, availableTime);
1116 }
1117 }
1118
releaseTextureObject(Texture::TextureObject * to)1119 void Texture::TextureObjectManager::releaseTextureObject(Texture::TextureObject* to)
1120 {
1121 if (to->_set) to->_set->orphan(to);
1122 else OSG_NOTICE<<"TextureObjectManager::releaseTextureObject(Texture::TextureObject* to) Not implemented yet"<<std::endl;
1123 }
1124
1125
newFrame(osg::FrameStamp * fs)1126 void Texture::TextureObjectManager::newFrame(osg::FrameStamp* fs)
1127 {
1128 if (fs) _frameNumber = fs->getFrameNumber();
1129 else ++_frameNumber;
1130
1131 ++_numFrames;
1132 }
1133
reportStats(std::ostream & out)1134 void Texture::TextureObjectManager::reportStats(std::ostream& out)
1135 {
1136 double numFrames(_numFrames==0 ? 1.0 : _numFrames);
1137 out<<"TextureObjectMananger::reportStats()"<<std::endl;
1138 out<<" total _numOfTextureObjects="<<_numActiveTextureObjects<<", _numOrphanedTextureObjects="<<_numOrphanedTextureObjects<<" _currTexturePoolSize="<<_currTexturePoolSize<<std::endl;
1139 out<<" total _numGenerated="<<_numGenerated<<", _generateTime="<<_generateTime<<", averagePerFrame="<<_generateTime/numFrames*1000.0<<"ms"<<std::endl;
1140 out<<" total _numDeleted="<<_numDeleted<<", _deleteTime="<<_deleteTime<<", averagePerFrame="<<_deleteTime/numFrames*1000.0<<"ms"<<std::endl;
1141 out<<" total _numApplied="<<_numApplied<<", _applyTime="<<_applyTime<<", averagePerFrame="<<_applyTime/numFrames*1000.0<<"ms"<<std::endl;
1142 out<<" getMaxTexturePoolSize()="<<getMaxTexturePoolSize()<<" current/max size = "<<double(_currTexturePoolSize)/double(getMaxTexturePoolSize())<<std::endl;
1143 recomputeStats(out);
1144 }
1145
resetStats()1146 void Texture::TextureObjectManager::resetStats()
1147 {
1148 _numFrames = 0;
1149 _numDeleted = 0;
1150 _deleteTime = 0;
1151
1152 _numGenerated = 0;
1153 _generateTime = 0;
1154
1155 _numApplied = 0;
1156 _applyTime = 0;
1157 }
1158
1159
recomputeStats(std::ostream & out) const1160 void Texture::TextureObjectManager::recomputeStats(std::ostream& out) const
1161 {
1162 out<<"Texture::TextureObjectManager::recomputeStats()"<<std::endl;
1163 unsigned int numObjectsInLists = 0;
1164 unsigned int numActive = 0;
1165 unsigned int numOrphans = 0;
1166 unsigned int numPendingOrphans = 0;
1167 unsigned int currentSize = 0;
1168 for(TextureSetMap::const_iterator itr = _textureSetMap.begin();
1169 itr != _textureSetMap.end();
1170 ++itr)
1171 {
1172 const TextureObjectSet* os = itr->second.get();
1173 numObjectsInLists += os->computeNumTextureObjectsInList();
1174 numActive += os->getNumOfTextureObjects();
1175 numOrphans += os->getNumOrphans();
1176 numPendingOrphans += os->getNumPendingOrphans();
1177 currentSize += os->getProfile()._size * (os->computeNumTextureObjectsInList()+os->getNumOrphans());
1178 out<<" size="<<os->getProfile()._size
1179 <<", os->computeNumTextureObjectsInList()"<<os->computeNumTextureObjectsInList()
1180 <<", os->getNumOfTextureObjects()"<<os->getNumOfTextureObjects()
1181 <<", os->getNumOrphans()"<<os->getNumOrphans()
1182 <<", os->getNumPendingOrphans()"<<os->getNumPendingOrphans()
1183 <<std::endl;
1184 }
1185 out<<" numObjectsInLists="<<numObjectsInLists<<", numActive="<<numActive<<", numOrphans="<<numOrphans<<" currentSize="<<currentSize<<std::endl;
1186 out<<" getMaxTexturePoolSize()="<<getMaxTexturePoolSize()<<" current/max size = "<<double(currentSize)/double(getMaxTexturePoolSize())<<std::endl;
1187 if (currentSize != _currTexturePoolSize) out<<" WARNING: _currTexturePoolSize("<<_currTexturePoolSize<<") != currentSize, delta = "<<int(_currTexturePoolSize)-int(currentSize)<<std::endl;
1188 }
1189
checkConsistency() const1190 bool Texture::TextureObjectManager::checkConsistency() const
1191 {
1192 unsigned int numObjectsInLists = 0;
1193 unsigned int numActive = 0;
1194 unsigned int numOrphans = 0;
1195 unsigned int numPendingOrphans = 0;
1196 unsigned int currentSize = 0;
1197 for(TextureSetMap::const_iterator itr = _textureSetMap.begin();
1198 itr != _textureSetMap.end();
1199 ++itr)
1200 {
1201 const TextureObjectSet* os = itr->second.get();
1202 numObjectsInLists += os->computeNumTextureObjectsInList();
1203 numActive += os->getNumOfTextureObjects();
1204 numOrphans += os->getNumOrphans();
1205 numPendingOrphans += os->getNumPendingOrphans();
1206 currentSize += os->getProfile()._size * (os->computeNumTextureObjectsInList()+os->getNumOrphans());
1207 }
1208
1209 if (currentSize != _currTexturePoolSize)
1210 {
1211 recomputeStats(osg::notify(osg::NOTICE));
1212
1213 throw "Texture::TextureObjectManager::checkConsistency() sizes inconsistent";
1214 return false;
1215 }
1216 return true;
1217 }
1218
1219
getTextureObjectManager(unsigned int contextID)1220 osg::ref_ptr<Texture::TextureObjectManager>& Texture::getTextureObjectManager(unsigned int contextID)
1221 {
1222 typedef osg::buffered_object< ref_ptr<Texture::TextureObjectManager> > TextureObjectManagerBuffer;
1223 static TextureObjectManagerBuffer s_TextureObjectManager;
1224 if (!s_TextureObjectManager[contextID]) s_TextureObjectManager[contextID] = new Texture::TextureObjectManager(contextID);
1225 return s_TextureObjectManager[contextID];
1226 }
1227
1228
generateTextureObject(const Texture * texture,unsigned int contextID,GLenum target)1229 osg::ref_ptr<Texture::TextureObject> Texture::generateTextureObject(const Texture* texture, unsigned int contextID, GLenum target)
1230 {
1231 return getTextureObjectManager(contextID)->generateTextureObject(texture, target);
1232 }
1233
generateTextureObject(const Texture * texture,unsigned int contextID,GLenum target,GLint numMipmapLevels,GLenum internalFormat,GLsizei width,GLsizei height,GLsizei depth,GLint border)1234 osg::ref_ptr<Texture::TextureObject> Texture::generateTextureObject(const Texture* texture, unsigned int contextID,
1235 GLenum target,
1236 GLint numMipmapLevels,
1237 GLenum internalFormat,
1238 GLsizei width,
1239 GLsizei height,
1240 GLsizei depth,
1241 GLint border)
1242 {
1243 return getTextureObjectManager(contextID)->generateTextureObject(texture,target,numMipmapLevels,internalFormat,width,height,depth,border);
1244 }
1245
deleteAllTextureObjects(unsigned int contextID)1246 void Texture::deleteAllTextureObjects(unsigned int contextID)
1247 {
1248 getTextureObjectManager(contextID)->deleteAllTextureObjects();
1249 }
1250
discardAllTextureObjects(unsigned int contextID)1251 void Texture::discardAllTextureObjects(unsigned int contextID)
1252 {
1253 getTextureObjectManager(contextID)->discardAllTextureObjects();
1254 }
1255
flushAllDeletedTextureObjects(unsigned int contextID)1256 void Texture::flushAllDeletedTextureObjects(unsigned int contextID)
1257 {
1258 getTextureObjectManager(contextID)->flushAllDeletedTextureObjects();
1259 }
1260
discardAllDeletedTextureObjects(unsigned int contextID)1261 void Texture::discardAllDeletedTextureObjects(unsigned int contextID)
1262 {
1263 getTextureObjectManager(contextID)->discardAllDeletedTextureObjects();
1264 }
1265
flushDeletedTextureObjects(unsigned int contextID,double currentTime,double & availbleTime)1266 void Texture::flushDeletedTextureObjects(unsigned int contextID,double currentTime, double& availbleTime)
1267 {
1268 getTextureObjectManager(contextID)->flushDeletedTextureObjects(currentTime, availbleTime);
1269 }
1270
releaseTextureObject(unsigned int contextID,Texture::TextureObject * to)1271 void Texture::releaseTextureObject(unsigned int contextID, Texture::TextureObject* to)
1272 {
1273 getTextureObjectManager(contextID)->releaseTextureObject(to);
1274 }
1275
1276 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
1277 //
1278 // Texture class implementation
1279 //
Texture()1280 Texture::Texture():
1281 _wrap_s(CLAMP),
1282 _wrap_t(CLAMP),
1283 _wrap_r(CLAMP),
1284 _min_filter(LINEAR_MIPMAP_LINEAR), // trilinear
1285 _mag_filter(LINEAR),
1286 _maxAnisotropy(1.0f),
1287 _swizzle(GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA),
1288 _useHardwareMipMapGeneration(true),
1289 _unrefImageDataAfterApply(false),
1290 _clientStorageHint(false),
1291 _resizeNonPowerOfTwoHint(true),
1292 _borderColor(0.0, 0.0, 0.0, 0.0),
1293 _borderWidth(0),
1294 _internalFormatMode(USE_IMAGE_DATA_FORMAT),
1295 _internalFormatType(NORMALIZED),
1296 _internalFormat(0),
1297 _sourceFormat(0),
1298 _sourceType(0),
1299 _use_shadow_comparison(false),
1300 _shadow_compare_func(LEQUAL),
1301 _shadow_texture_mode(LUMINANCE),
1302 _shadow_ambient(0)
1303 {
1304 }
1305
Texture(const Texture & text,const CopyOp & copyop)1306 Texture::Texture(const Texture& text,const CopyOp& copyop):
1307 StateAttribute(text,copyop),
1308 _wrap_s(text._wrap_s),
1309 _wrap_t(text._wrap_t),
1310 _wrap_r(text._wrap_r),
1311 _min_filter(text._min_filter),
1312 _mag_filter(text._mag_filter),
1313 _maxAnisotropy(text._maxAnisotropy),
1314 _swizzle(text._swizzle),
1315 _useHardwareMipMapGeneration(text._useHardwareMipMapGeneration),
1316 _unrefImageDataAfterApply(text._unrefImageDataAfterApply),
1317 _clientStorageHint(text._clientStorageHint),
1318 _resizeNonPowerOfTwoHint(text._resizeNonPowerOfTwoHint),
1319 _borderColor(text._borderColor),
1320 _borderWidth(text._borderWidth),
1321 _internalFormatMode(text._internalFormatMode),
1322 _internalFormatType(text._internalFormatType),
1323 _internalFormat(text._internalFormat),
1324 _sourceFormat(text._sourceFormat),
1325 _sourceType(text._sourceType),
1326 _use_shadow_comparison(text._use_shadow_comparison),
1327 _shadow_compare_func(text._shadow_compare_func),
1328 _shadow_texture_mode(text._shadow_texture_mode),
1329 _shadow_ambient(text._shadow_ambient)
1330 {
1331 }
1332
~Texture()1333 Texture::~Texture()
1334 {
1335 // delete old texture objects.
1336 dirtyTextureObject();
1337 }
1338
compareTexture(const Texture & rhs) const1339 int Texture::compareTexture(const Texture& rhs) const
1340 {
1341 COMPARE_StateAttribute_Parameter(_wrap_s)
1342 COMPARE_StateAttribute_Parameter(_wrap_t)
1343 COMPARE_StateAttribute_Parameter(_wrap_r)
1344 COMPARE_StateAttribute_Parameter(_min_filter)
1345 COMPARE_StateAttribute_Parameter(_mag_filter)
1346 COMPARE_StateAttribute_Parameter(_maxAnisotropy)
1347 COMPARE_StateAttribute_Parameter(_swizzle)
1348 COMPARE_StateAttribute_Parameter(_useHardwareMipMapGeneration)
1349 COMPARE_StateAttribute_Parameter(_internalFormatMode)
1350
1351 // only compare _internalFomat is it has alrady been set in both lhs, and rhs
1352 if (_internalFormat!=0 && rhs._internalFormat!=0)
1353 {
1354 COMPARE_StateAttribute_Parameter(_internalFormat)
1355 }
1356
1357 COMPARE_StateAttribute_Parameter(_sourceFormat)
1358 COMPARE_StateAttribute_Parameter(_sourceType)
1359
1360 COMPARE_StateAttribute_Parameter(_use_shadow_comparison)
1361 COMPARE_StateAttribute_Parameter(_shadow_compare_func)
1362 COMPARE_StateAttribute_Parameter(_shadow_texture_mode)
1363 COMPARE_StateAttribute_Parameter(_shadow_ambient)
1364
1365 COMPARE_StateAttribute_Parameter(_unrefImageDataAfterApply)
1366 COMPARE_StateAttribute_Parameter(_clientStorageHint)
1367 COMPARE_StateAttribute_Parameter(_resizeNonPowerOfTwoHint)
1368
1369 COMPARE_StateAttribute_Parameter(_internalFormatType);
1370
1371 return 0;
1372 }
1373
compareTextureObjects(const Texture & rhs) const1374 int Texture::compareTextureObjects(const Texture& rhs) const
1375 {
1376 if (_textureObjectBuffer.size()<rhs._textureObjectBuffer.size()) return -1;
1377 if (rhs._textureObjectBuffer.size()<_textureObjectBuffer.size()) return 1;
1378 for(unsigned int i=0; i<_textureObjectBuffer.size(); ++i)
1379 {
1380 if (_textureObjectBuffer[i] < rhs._textureObjectBuffer[i]) return -1;
1381 else if (rhs._textureObjectBuffer[i] < _textureObjectBuffer[i]) return 1;
1382 }
1383 return 0;
1384 }
1385
setWrap(WrapParameter which,WrapMode wrap)1386 void Texture::setWrap(WrapParameter which, WrapMode wrap)
1387 {
1388 switch( which )
1389 {
1390 case WRAP_S : _wrap_s = wrap; dirtyTextureParameters(); break;
1391 case WRAP_T : _wrap_t = wrap; dirtyTextureParameters(); break;
1392 case WRAP_R : _wrap_r = wrap; dirtyTextureParameters(); break;
1393 default : OSG_WARN<<"Error: invalid 'which' passed Texture::setWrap("<<(unsigned int)which<<","<<(unsigned int)wrap<<")"<<std::endl; break;
1394 }
1395
1396 }
1397
1398
getWrap(WrapParameter which) const1399 Texture::WrapMode Texture::getWrap(WrapParameter which) const
1400 {
1401 switch( which )
1402 {
1403 case WRAP_S : return _wrap_s;
1404 case WRAP_T : return _wrap_t;
1405 case WRAP_R : return _wrap_r;
1406 default : OSG_WARN<<"Error: invalid 'which' passed Texture::getWrap(which)"<<std::endl; return _wrap_s;
1407 }
1408 }
1409
1410
setFilter(FilterParameter which,FilterMode filter)1411 void Texture::setFilter(FilterParameter which, FilterMode filter)
1412 {
1413 switch( which )
1414 {
1415 case MIN_FILTER : _min_filter = filter; dirtyTextureParameters(); break;
1416 case MAG_FILTER : _mag_filter = filter; dirtyTextureParameters(); break;
1417 default : OSG_WARN<<"Error: invalid 'which' passed Texture::setFilter("<<(unsigned int)which<<","<<(unsigned int)filter<<")"<<std::endl; break;
1418 }
1419 }
1420
1421
getFilter(FilterParameter which) const1422 Texture::FilterMode Texture::getFilter(FilterParameter which) const
1423 {
1424 switch( which )
1425 {
1426 case MIN_FILTER : return _min_filter;
1427 case MAG_FILTER : return _mag_filter;
1428 default : OSG_WARN<<"Error: invalid 'which' passed Texture::getFilter(which)"<< std::endl; return _min_filter;
1429 }
1430 }
1431
setMaxAnisotropy(float anis)1432 void Texture::setMaxAnisotropy(float anis)
1433 {
1434 if (_maxAnisotropy!=anis)
1435 {
1436 _maxAnisotropy = anis;
1437 dirtyTextureParameters();
1438 }
1439 }
1440
bindToImageUnit(unsigned int unit,GLenum access,GLenum format,int level,bool layered,int layer)1441 void Texture::bindToImageUnit(unsigned int unit, GLenum access, GLenum format, int level, bool layered, int layer)
1442 {
1443 _imageAttachment.unit = unit;
1444 _imageAttachment.level = level;
1445 _imageAttachment.layered = layered ? GL_TRUE : GL_FALSE;
1446 _imageAttachment.layer = layer;
1447 _imageAttachment.access = access;
1448 _imageAttachment.format = format;
1449 dirtyTextureParameters();
1450 }
1451
1452 /** Force a recompile on next apply() of associated OpenGL texture objects.*/
dirtyTextureObject()1453 void Texture::dirtyTextureObject()
1454 {
1455 for(unsigned int i=0; i<_textureObjectBuffer.size();++i)
1456 {
1457 if (_textureObjectBuffer[i].valid())
1458 {
1459 Texture::releaseTextureObject(i, _textureObjectBuffer[i].get());
1460 _textureObjectBuffer[i] = 0;
1461 }
1462 }
1463 }
1464
dirtyTextureParameters()1465 void Texture::dirtyTextureParameters()
1466 {
1467 _texParametersDirtyList.setAllElementsTo(1);
1468 }
1469
allocateMipmapLevels()1470 void Texture::allocateMipmapLevels()
1471 {
1472 _texMipmapGenerationDirtyList.setAllElementsTo(1);
1473 }
1474
computeInternalFormatWithImage(const osg::Image & image) const1475 void Texture::computeInternalFormatWithImage(const osg::Image& image) const
1476 {
1477 GLint internalFormat = image.getInternalTextureFormat();
1478
1479 if (_internalFormatMode==USE_IMAGE_DATA_FORMAT)
1480 {
1481 internalFormat = image.getInternalTextureFormat();
1482 }
1483 else if (_internalFormatMode==USE_USER_DEFINED_FORMAT)
1484 {
1485 internalFormat = _internalFormat;
1486 }
1487 else
1488 {
1489
1490 const unsigned int contextID = 0; // state.getContextID(); // set to 0 right now, assume same parameters for each graphics context...
1491 const GLExtensions* extensions = GLExtensions::Get(contextID,true);
1492
1493 switch(_internalFormatMode)
1494 {
1495 case(USE_ARB_COMPRESSION):
1496 if (extensions->isTextureCompressionARBSupported)
1497 {
1498 switch(image.getPixelFormat())
1499 {
1500 case(1): internalFormat = GL_COMPRESSED_ALPHA_ARB; break;
1501 case(2): internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_ARB; break;
1502 case(3): internalFormat = GL_COMPRESSED_RGB_ARB; break;
1503 case(4): internalFormat = GL_COMPRESSED_RGBA_ARB; break;
1504 case(GL_RGB): internalFormat = GL_COMPRESSED_RGB_ARB; break;
1505 case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA_ARB; break;
1506 case(GL_ALPHA): internalFormat = GL_COMPRESSED_ALPHA_ARB; break;
1507 case(GL_LUMINANCE): internalFormat = GL_COMPRESSED_LUMINANCE_ARB; break;
1508 case(GL_LUMINANCE_ALPHA): internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_ARB; break;
1509 case(GL_INTENSITY): internalFormat = GL_COMPRESSED_INTENSITY_ARB; break;
1510 }
1511 }
1512 break;
1513
1514 case(USE_S3TC_DXT1_COMPRESSION):
1515 if (extensions->isTextureCompressionS3TCSupported)
1516 {
1517 switch(image.getPixelFormat())
1518 {
1519 case(3): internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
1520 case(4): internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
1521 case(GL_RGB): internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
1522 case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
1523 default: internalFormat = image.getInternalTextureFormat(); break;
1524 }
1525 }
1526 break;
1527
1528 case(USE_S3TC_DXT1c_COMPRESSION):
1529 if (extensions->isTextureCompressionS3TCSupported)
1530 {
1531 switch(image.getPixelFormat())
1532 {
1533 case(3):
1534 case(4):
1535 case(GL_RGB):
1536 case(GL_RGBA): internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
1537 default: internalFormat = image.getInternalTextureFormat(); break;
1538 }
1539 }
1540 break;
1541
1542 case(USE_S3TC_DXT1a_COMPRESSION):
1543 if (extensions->isTextureCompressionS3TCSupported)
1544 {
1545 switch(image.getPixelFormat())
1546 {
1547 case(3):
1548 case(4):
1549 case(GL_RGB):
1550 case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
1551 default: internalFormat = image.getInternalTextureFormat(); break;
1552 }
1553 }
1554 break;
1555
1556 case(USE_S3TC_DXT3_COMPRESSION):
1557 if (extensions->isTextureCompressionS3TCSupported)
1558 {
1559 switch(image.getPixelFormat())
1560 {
1561 case(3):
1562 case(GL_RGB): internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
1563 case(4):
1564 case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
1565 default: internalFormat = image.getInternalTextureFormat(); break;
1566 }
1567 }
1568 break;
1569
1570 case(USE_S3TC_DXT5_COMPRESSION):
1571 if (extensions->isTextureCompressionS3TCSupported)
1572 {
1573 switch(image.getPixelFormat())
1574 {
1575 case(3):
1576 case(GL_RGB): internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
1577 case(4):
1578 case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
1579 default: internalFormat = image.getInternalTextureFormat(); break;
1580 }
1581 }
1582 break;
1583
1584 case(USE_PVRTC_2BPP_COMPRESSION):
1585 if (extensions->isTextureCompressionPVRTC2BPPSupported)
1586 {
1587 switch(image.getPixelFormat())
1588 {
1589 case(3):
1590 case(GL_RGB): internalFormat = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; break;
1591 case(4):
1592 case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; break;
1593 default: internalFormat = image.getInternalTextureFormat(); break;
1594 }
1595 }
1596 break;
1597
1598 case(USE_PVRTC_4BPP_COMPRESSION):
1599 if (extensions->isTextureCompressionPVRTC4BPPSupported)
1600 {
1601 switch(image.getPixelFormat())
1602 {
1603 case(3):
1604 case(GL_RGB): internalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; break;
1605 case(4):
1606 case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break;
1607 default: internalFormat = image.getInternalTextureFormat(); break;
1608 }
1609 }
1610 break;
1611
1612 case(USE_ETC_COMPRESSION):
1613 if (extensions->isTextureCompressionETCSupported)
1614 {
1615 switch(image.getPixelFormat())
1616 {
1617 case(3):
1618 case(GL_RGB): internalFormat = GL_ETC1_RGB8_OES; break;
1619 default: internalFormat = image.getInternalTextureFormat(); break;
1620 }
1621 }
1622 break;
1623
1624 case(USE_ETC2_COMPRESSION):
1625 if (extensions->isTextureCompressionETC2Supported)
1626 {
1627 switch(image.getPixelFormat())
1628 {
1629 case(1):
1630 case(GL_RED): internalFormat = GL_COMPRESSED_R11_EAC; break;
1631 case(2):
1632 case(GL_RG): internalFormat = GL_COMPRESSED_RG11_EAC; break;
1633 case(3):
1634 case(GL_RGB): internalFormat = GL_COMPRESSED_RGB8_ETC2; break;
1635 case(4):
1636 case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; break;
1637 default: internalFormat = image.getInternalTextureFormat(); break;
1638 }
1639 }
1640 break;
1641
1642 case(USE_RGTC1_COMPRESSION):
1643 if (extensions->isTextureCompressionRGTCSupported)
1644 {
1645 switch(image.getPixelFormat())
1646 {
1647 case(3):
1648 case(GL_RGB): internalFormat = GL_COMPRESSED_RED_RGTC1_EXT; break;
1649 case(4):
1650 case(GL_RGBA): internalFormat = GL_COMPRESSED_RED_RGTC1_EXT; break;
1651 default: internalFormat = image.getInternalTextureFormat(); break;
1652 }
1653 }
1654 break;
1655
1656 case(USE_RGTC2_COMPRESSION):
1657 if (extensions->isTextureCompressionRGTCSupported)
1658 {
1659 switch(image.getPixelFormat())
1660 {
1661 case(3):
1662 case(GL_RGB): internalFormat = GL_COMPRESSED_RED_GREEN_RGTC2_EXT; break;
1663 case(4):
1664 case(GL_RGBA): internalFormat = GL_COMPRESSED_RED_GREEN_RGTC2_EXT; break;
1665 default: internalFormat = image.getInternalTextureFormat(); break;
1666 }
1667 }
1668 break;
1669
1670 default:
1671 break;
1672 }
1673 }
1674
1675 #if defined (OSG_GLES1_AVAILABLE) || defined (OSG_GLES2_AVAILABLE)
1676 // GLES doesn't cope with internal formats of 1,2,3 and 4 and glTexImage doesn't
1677 // handle the _OES pixel formats so map them to the appropriate equivilants.
1678 switch(internalFormat)
1679 {
1680 case(1) : internalFormat = GL_LUMINANCE; break;
1681 case(2) : internalFormat = GL_LUMINANCE_ALPHA; break;
1682 case(3) : internalFormat = GL_RGB; break;
1683 case(4) : internalFormat = GL_RGBA; break;
1684 case(GL_RGB8_OES) : internalFormat = GL_RGB; break;
1685 case(GL_RGBA8_OES) : internalFormat = GL_RGBA; break;
1686 default: break;
1687 }
1688 #elif defined(OSG_GL3_AVAILABLE)
1689 switch(internalFormat)
1690 {
1691 case(GL_INTENSITY) : internalFormat = GL_RED; break; // should it be swizzled to match RGBA(INTENSITY, INTENSITY, INTENSITY, INTENSITY)?
1692 case(GL_LUMINANCE) : internalFormat = GL_RED; break; // should it be swizzled to match RGBA(LUMINANCE, LUMINANCE, LUMINANCE, 1.0)?
1693 case(1) : internalFormat = GL_RED; break; // or sould this be GL_ALPHA?
1694 case(2) : internalFormat = GL_RG; break; // should we assume GL_LUMINANCE_ALPHA?
1695 case(GL_LUMINANCE_ALPHA) : internalFormat = GL_RG; break; // should it be swizlled to match RGAB(LUMUNIANCE, LUMINANCE, LUMINANCE, ALPHA)?
1696 case(3) : internalFormat = GL_RGB; break;
1697 case(4) : internalFormat = GL_RGBA; break;
1698 default: break;
1699 }
1700 #endif
1701
1702 _internalFormat = internalFormat;
1703
1704
1705 computeInternalFormatType();
1706
1707 //OSG_NOTICE<<"Internal format="<<std::hex<<internalFormat<<std::dec<<std::endl;
1708 }
1709
computeInternalFormatType() const1710 void Texture::computeInternalFormatType() const
1711 {
1712 // Here we could also precompute the _sourceFormat if it is not set,
1713 // since it is different for different internal formats
1714 // (i.e. rgba integer texture --> _sourceFormat = GL_RGBA_INTEGER_EXT)
1715 // Should we do this? ( Art, 09. Sept. 2007)
1716
1717 // compute internal format type based on the internal format
1718 switch(_internalFormat)
1719 {
1720 case GL_RGBA32UI_EXT:
1721 case GL_RGBA16UI_EXT:
1722 case GL_RGBA8UI_EXT:
1723
1724 case GL_RGB32UI_EXT:
1725 case GL_RGB16UI_EXT:
1726 case GL_RGB8UI_EXT:
1727
1728 case GL_LUMINANCE32UI_EXT:
1729 case GL_LUMINANCE16UI_EXT:
1730 case GL_LUMINANCE8UI_EXT:
1731
1732 case GL_INTENSITY32UI_EXT:
1733 case GL_INTENSITY16UI_EXT:
1734 case GL_INTENSITY8UI_EXT:
1735
1736 case GL_LUMINANCE_ALPHA32UI_EXT:
1737 case GL_LUMINANCE_ALPHA16UI_EXT:
1738 case GL_LUMINANCE_ALPHA8UI_EXT :
1739 _internalFormatType = UNSIGNED_INTEGER;
1740 break;
1741
1742 case GL_RGBA32I_EXT:
1743 case GL_RGBA16I_EXT:
1744 case GL_RGBA8I_EXT:
1745
1746 case GL_RGB32I_EXT:
1747 case GL_RGB16I_EXT:
1748 case GL_RGB8I_EXT:
1749
1750 case GL_LUMINANCE32I_EXT:
1751 case GL_LUMINANCE16I_EXT:
1752 case GL_LUMINANCE8I_EXT:
1753
1754 case GL_INTENSITY32I_EXT:
1755 case GL_INTENSITY16I_EXT:
1756 case GL_INTENSITY8I_EXT:
1757
1758 case GL_LUMINANCE_ALPHA32I_EXT:
1759 case GL_LUMINANCE_ALPHA16I_EXT:
1760 case GL_LUMINANCE_ALPHA8I_EXT:
1761 _internalFormatType = SIGNED_INTEGER;
1762 break;
1763
1764 case GL_RGBA32F_ARB:
1765 case GL_RGBA16F_ARB:
1766
1767 case GL_RGB32F_ARB:
1768 case GL_RGB16F_ARB:
1769
1770 case GL_LUMINANCE32F_ARB:
1771 case GL_LUMINANCE16F_ARB:
1772
1773 case GL_INTENSITY32F_ARB:
1774 case GL_INTENSITY16F_ARB:
1775
1776 case GL_LUMINANCE_ALPHA32F_ARB:
1777 case GL_LUMINANCE_ALPHA16F_ARB:
1778 _internalFormatType = FLOAT;
1779 break;
1780
1781 default:
1782 _internalFormatType = NORMALIZED;
1783 break;
1784 };
1785 }
1786
isCompressedInternalFormat() const1787 bool Texture::isCompressedInternalFormat() const
1788 {
1789 return isCompressedInternalFormat(getInternalFormat());
1790 }
1791
isCompressedInternalFormat(GLint internalFormat)1792 bool Texture::isCompressedInternalFormat(GLint internalFormat)
1793 {
1794 switch(internalFormat)
1795 {
1796 case(GL_COMPRESSED_ALPHA_ARB):
1797 case(GL_COMPRESSED_INTENSITY_ARB):
1798 case(GL_COMPRESSED_LUMINANCE_ALPHA_ARB):
1799 case(GL_COMPRESSED_LUMINANCE_ARB):
1800 case(GL_COMPRESSED_RGBA_ARB):
1801 case(GL_COMPRESSED_RGB_ARB):
1802 case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT):
1803 case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):
1804 case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):
1805 case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):
1806 case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT):
1807 case(GL_COMPRESSED_RED_RGTC1_EXT):
1808 case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT):
1809 case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT):
1810 case(GL_ETC1_RGB8_OES):
1811 case(GL_COMPRESSED_RGB8_ETC2):
1812 case(GL_COMPRESSED_SRGB8_ETC2):
1813 case(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2):
1814 case(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2):
1815 case(GL_COMPRESSED_RGBA8_ETC2_EAC):
1816 case(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC):
1817 case(GL_COMPRESSED_R11_EAC):
1818 case(GL_COMPRESSED_SIGNED_R11_EAC):
1819 case(GL_COMPRESSED_RG11_EAC):
1820 case(GL_COMPRESSED_SIGNED_RG11_EAC):
1821 case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG):
1822 case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG):
1823 case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG):
1824 case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG):
1825 return true;
1826 default:
1827 return false;
1828 }
1829 }
1830
getCompressedSize(GLenum internalFormat,GLint width,GLint height,GLint depth,GLint & blockSize,GLint & size)1831 void Texture::getCompressedSize(GLenum internalFormat, GLint width, GLint height, GLint depth, GLint& blockSize, GLint& size)
1832 {
1833 if (internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
1834 blockSize = 8;
1835 else if (internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT || internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
1836 blockSize = 16;
1837 else if (internalFormat == GL_ETC1_RGB8_OES)
1838 blockSize = 8;
1839 else if (internalFormat == GL_COMPRESSED_RGB8_ETC2 || internalFormat == GL_COMPRESSED_SRGB8_ETC2)
1840 blockSize = 8;
1841 else if (internalFormat == GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 || internalFormat == GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2)
1842 blockSize = 8;
1843 else if (internalFormat == GL_COMPRESSED_RGBA8_ETC2_EAC || internalFormat == GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC)
1844 blockSize = 16;
1845 else if (internalFormat == GL_COMPRESSED_R11_EAC || internalFormat == GL_COMPRESSED_SIGNED_R11_EAC)
1846 blockSize = 8;
1847 else if (internalFormat == GL_COMPRESSED_RG11_EAC || internalFormat == GL_COMPRESSED_SIGNED_RG11_EAC)
1848 blockSize = 16;
1849 else if (internalFormat == GL_COMPRESSED_RED_RGTC1_EXT || internalFormat == GL_COMPRESSED_SIGNED_RED_RGTC1_EXT)
1850 blockSize = 8;
1851 else if (internalFormat == GL_COMPRESSED_RED_GREEN_RGTC2_EXT || internalFormat == GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT)
1852 blockSize = 16;
1853 else if (internalFormat == GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG || internalFormat == GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG)
1854 {
1855 blockSize = 8 * 4; // Pixel by pixel block size for 2bpp
1856 GLint widthBlocks = width / 8;
1857 GLint heightBlocks = height / 4;
1858 GLint bpp = 2;
1859
1860 // Clamp to minimum number of blocks
1861 if(widthBlocks < 2)
1862 widthBlocks = 2;
1863 if(heightBlocks < 2)
1864 heightBlocks = 2;
1865
1866 size = widthBlocks * heightBlocks * ((blockSize * bpp) / 8);
1867 return;
1868 }
1869 else if (internalFormat == GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG || internalFormat == GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG)
1870 {
1871 blockSize = 4 * 4; // Pixel by pixel block size for 4bpp
1872 GLint widthBlocks = width / 4;
1873 GLint heightBlocks = height / 4;
1874 GLint bpp = 4;
1875
1876 // Clamp to minimum number of blocks
1877 if(widthBlocks < 2)
1878 widthBlocks = 2;
1879 if(heightBlocks < 2)
1880 heightBlocks = 2;
1881
1882 size = widthBlocks * heightBlocks * ((blockSize * bpp) / 8);
1883 return;
1884 }
1885 else
1886 {
1887 OSG_WARN<<"Texture::getCompressedSize(...) : cannot compute correct size of compressed format ("<<internalFormat<<") returning 0."<<std::endl;
1888 blockSize = 0;
1889 }
1890
1891 size = ((width+3)/4)*((height+3)/4)*depth*blockSize;
1892 }
1893
applyTexParameters(GLenum target,State & state) const1894 void Texture::applyTexParameters(GLenum target, State& state) const
1895 {
1896 // get the contextID (user defined ID of 0 upwards) for the
1897 // current OpenGL context.
1898 const unsigned int contextID = state.getContextID();
1899 const GLExtensions* extensions = state.get<GLExtensions>();
1900
1901 WrapMode ws = _wrap_s, wt = _wrap_t, wr = _wrap_r;
1902
1903 // GL_IBM_texture_mirrored_repeat, fall-back REPEAT
1904 if (!extensions->isTextureMirroredRepeatSupported)
1905 {
1906 if (ws == MIRROR)
1907 ws = REPEAT;
1908 if (wt == MIRROR)
1909 wt = REPEAT;
1910 if (wr == MIRROR)
1911 wr = REPEAT;
1912 }
1913
1914 // GL_EXT_texture_edge_clamp, fall-back CLAMP
1915 if (!extensions->isTextureEdgeClampSupported)
1916 {
1917 if (ws == CLAMP_TO_EDGE)
1918 ws = CLAMP;
1919 if (wt == CLAMP_TO_EDGE)
1920 wt = CLAMP;
1921 if (wr == CLAMP_TO_EDGE)
1922 wr = CLAMP;
1923 }
1924
1925 if(!extensions->isTextureBorderClampSupported)
1926 {
1927 if(ws == CLAMP_TO_BORDER)
1928 ws = CLAMP;
1929 if(wt == CLAMP_TO_BORDER)
1930 wt = CLAMP;
1931 if(wr == CLAMP_TO_BORDER)
1932 wr = CLAMP;
1933 }
1934
1935 #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) || defined(OSG_GL3_AVAILABLE)
1936 if (ws == CLAMP) ws = CLAMP_TO_EDGE;
1937 if (wt == CLAMP) wt = CLAMP_TO_EDGE;
1938 if (wr == CLAMP) wr = CLAMP_TO_EDGE;
1939 #endif
1940
1941 const Image * image = getImage(0);
1942 if( image &&
1943 image->isMipmap() &&
1944 extensions->isTextureMaxLevelSupported &&
1945 int( image->getNumMipmapLevels() ) <
1946 Image::computeNumberOfMipmapLevels( image->s(), image->t(), image->r() ) )
1947 glTexParameteri( target, GL_TEXTURE_MAX_LEVEL, image->getNumMipmapLevels() - 1 );
1948
1949
1950 glTexParameteri( target, GL_TEXTURE_WRAP_S, ws );
1951
1952 if (target!=GL_TEXTURE_1D) glTexParameteri( target, GL_TEXTURE_WRAP_T, wt );
1953
1954 if (target==GL_TEXTURE_3D) glTexParameteri( target, GL_TEXTURE_WRAP_R, wr );
1955
1956
1957 glTexParameteri( target, GL_TEXTURE_MIN_FILTER, _min_filter);
1958 glTexParameteri( target, GL_TEXTURE_MAG_FILTER, _mag_filter);
1959
1960 // Art: I think anisotropic filtering is not supported by the integer textures
1961 if (extensions->isTextureFilterAnisotropicSupported &&
1962 _internalFormatType != SIGNED_INTEGER && _internalFormatType != UNSIGNED_INTEGER)
1963 {
1964 // note, GL_TEXTURE_MAX_ANISOTROPY_EXT will either be defined
1965 // by gl.h (or via glext.h) or by include/osg/Texture.
1966 glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, _maxAnisotropy);
1967 }
1968
1969 if (extensions->isTextureSwizzleSupported)
1970 {
1971 // note, GL_TEXTURE_SWIZZLE_RGBA will either be defined
1972 // by gl.h (or via glext.h) or by include/osg/Texture.
1973 glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, _swizzle.ptr());
1974 }
1975
1976 if (extensions->isTextureBorderClampSupported)
1977 {
1978
1979 #ifndef GL_TEXTURE_BORDER_COLOR
1980 #define GL_TEXTURE_BORDER_COLOR 0x1004
1981 #endif
1982
1983
1984 if (_internalFormatType == SIGNED_INTEGER)
1985 {
1986 GLint color[4] = {(GLint)_borderColor.r(), (GLint)_borderColor.g(), (GLint)_borderColor.b(), (GLint)_borderColor.a()};
1987 extensions->glTexParameterIiv(target, GL_TEXTURE_BORDER_COLOR, color);
1988 }else if (_internalFormatType == UNSIGNED_INTEGER)
1989 {
1990 GLuint color[4] = {(GLuint)_borderColor.r(), (GLuint)_borderColor.g(), (GLuint)_borderColor.b(), (GLuint)_borderColor.a()};
1991 extensions->glTexParameterIuiv(target, GL_TEXTURE_BORDER_COLOR, color);
1992 }else{
1993 GLfloat color[4] = {(GLfloat)_borderColor.r(), (GLfloat)_borderColor.g(), (GLfloat)_borderColor.b(), (GLfloat)_borderColor.a()};
1994 glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, color);
1995 }
1996 }
1997
1998 // integer textures are not supported by the shadow
1999 // GL_TEXTURE_1D_ARRAY_EXT could be included in the check below but its not yet implemented in OSG
2000 if (extensions->isShadowSupported &&
2001 (target == GL_TEXTURE_2D || target == GL_TEXTURE_1D || target == GL_TEXTURE_RECTANGLE || target == GL_TEXTURE_CUBE_MAP || target == GL_TEXTURE_2D_ARRAY_EXT ) &&
2002 _internalFormatType != SIGNED_INTEGER && _internalFormatType != UNSIGNED_INTEGER)
2003 {
2004 if (_use_shadow_comparison)
2005 {
2006 glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
2007 glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC_ARB, _shadow_compare_func);
2008 #if defined(OSG_GL1_AVAILABLE) || defined(OSG_GL2_AVAILABLE)
2009 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, _shadow_texture_mode);
2010 #endif
2011
2012 // if ambient value is 0 - it is default behaviour of GL_ARB_shadow
2013 // no need for GL_ARB_shadow_ambient in this case
2014 if (extensions->isShadowAmbientSupported && _shadow_ambient > 0)
2015 {
2016 glTexParameterf(target, TEXTURE_COMPARE_FAIL_VALUE_ARB, _shadow_ambient);
2017 }
2018 }
2019 else
2020 {
2021 glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
2022 }
2023 }
2024
2025 // Apply image load/store attributes
2026 if (extensions->isBindImageTextureSupported() && _imageAttachment.access!=0)
2027 {
2028 TextureObject* tobj = getTextureObject(contextID);
2029 if (tobj)
2030 {
2031 extensions->glBindImageTexture(
2032 _imageAttachment.unit, tobj->id(), _imageAttachment.level,
2033 _imageAttachment.layered, _imageAttachment.layer, _imageAttachment.access,
2034 _imageAttachment.format!=0 ? _imageAttachment.format : _internalFormat);
2035 }
2036 }
2037
2038 getTextureParameterDirty(state.getContextID()) = false;
2039
2040 }
2041
computeRequiredTextureDimensions(State & state,const osg::Image & image,GLsizei & inwidth,GLsizei & inheight,GLsizei & numMipmapLevels) const2042 void Texture::computeRequiredTextureDimensions(State& state, const osg::Image& image,GLsizei& inwidth, GLsizei& inheight,GLsizei& numMipmapLevels) const
2043 {
2044 const GLExtensions* extensions = state.get<GLExtensions>();
2045
2046 int width,height;
2047
2048 if( !_resizeNonPowerOfTwoHint && extensions->isNonPowerOfTwoTextureSupported(_min_filter) )
2049 {
2050 width = image.s();
2051 height = image.t();
2052 }
2053 else
2054 {
2055 width = Image::computeNearestPowerOfTwo(image.s()-2*_borderWidth)+2*_borderWidth;
2056 height = Image::computeNearestPowerOfTwo(image.t()-2*_borderWidth)+2*_borderWidth;
2057 }
2058
2059 // cap the size to what the graphics hardware can handle.
2060 if (width>extensions->maxTextureSize) width = extensions->maxTextureSize;
2061 if (height>extensions->maxTextureSize) height = extensions->maxTextureSize;
2062
2063 inwidth = width;
2064 inheight = height;
2065
2066 if( _min_filter == LINEAR || _min_filter == NEAREST)
2067 {
2068 numMipmapLevels = 1;
2069 }
2070 else if( image.isMipmap() )
2071 {
2072 numMipmapLevels = image.getNumMipmapLevels();
2073 }
2074 else
2075 {
2076 numMipmapLevels = 1;
2077 for(int s=1; s<width || s<height; s <<= 1, ++numMipmapLevels) {}
2078 }
2079
2080 // OSG_NOTICE<<"Texture::computeRequiredTextureDimensions() image.s() "<<image.s()<<" image.t()="<<image.t()<<" width="<<width<<" height="<<height<<" numMipmapLevels="<<numMipmapLevels<<std::endl;
2081 // OSG_NOTICE<<" _resizeNonPowerOfTwoHint="<<_resizeNonPowerOfTwoHint<<" extensions->isNonPowerOfTwoTextureSupported(_min_filter)="<<extensions->isNonPowerOfTwoTextureSupported(_min_filter) <<std::endl;
2082 }
2083
areAllTextureObjectsLoaded() const2084 bool Texture::areAllTextureObjectsLoaded() const
2085 {
2086 for(unsigned int i=0;i<DisplaySettings::instance()->getMaxNumberOfGraphicsContexts();++i)
2087 {
2088 if (_textureObjectBuffer[i]==0) return false;
2089 }
2090 return true;
2091 }
2092
2093
applyTexImage2D_load(State & state,GLenum target,const Image * image,GLsizei inwidth,GLsizei inheight,GLsizei numMipmapLevels) const2094 void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* image, GLsizei inwidth, GLsizei inheight,GLsizei numMipmapLevels) const
2095 {
2096 // if we don't have a valid image we can't create a texture!
2097 if (!image || !image->data())
2098 return;
2099
2100 #ifdef DO_TIMING
2101 osg::Timer_t start_tick = osg::Timer::instance()->tick();
2102 OSG_NOTICE<<"glTexImage2D pixelFormat = "<<std::hex<<image->getPixelFormat()<<std::dec<<std::endl;
2103 #endif
2104
2105 // get extensions object
2106 const GLExtensions* extensions = state.get<GLExtensions>();
2107
2108 // select the internalFormat required for the texture.
2109 bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
2110
2111 // If the texture's internal format is a compressed type, then the
2112 // user is requesting that the graphics card compress the image if it's
2113 // not already compressed. However, if the image is not a multiple of
2114 // four in each dimension the subsequent calls to glTexSubImage* will
2115 // fail. Revert to uncompressed format in this case.
2116 if (isCompressedInternalFormat(_internalFormat) &&
2117 (((inwidth >> 2) << 2) != inwidth ||
2118 ((inheight >> 2) << 2) != inheight))
2119 {
2120 OSG_NOTICE<<"Received a request to compress an image, but image size is not a multiple of four ("<<inwidth<<"x"<<inheight<<"). Reverting to uncompressed.\n";
2121 switch(_internalFormat)
2122 {
2123 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
2124 case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
2125 case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
2126 case GL_ETC1_RGB8_OES:
2127 case(GL_COMPRESSED_RGB8_ETC2):
2128 case(GL_COMPRESSED_SRGB8_ETC2):
2129 case GL_COMPRESSED_RGB: _internalFormat = GL_RGB; break;
2130 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
2131 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
2132 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
2133 case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
2134 case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
2135 case(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2):
2136 case(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2):
2137 case(GL_COMPRESSED_RGBA8_ETC2_EAC):
2138 case(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC):
2139 case GL_COMPRESSED_RGBA: _internalFormat = GL_RGBA; break;
2140 case GL_COMPRESSED_ALPHA: _internalFormat = GL_ALPHA; break;
2141 case GL_COMPRESSED_LUMINANCE: _internalFormat = GL_LUMINANCE; break;
2142 case GL_COMPRESSED_LUMINANCE_ALPHA: _internalFormat = GL_LUMINANCE_ALPHA; break;
2143 case GL_COMPRESSED_INTENSITY: _internalFormat = GL_INTENSITY; break;
2144 case(GL_COMPRESSED_R11_EAC):
2145 case(GL_COMPRESSED_SIGNED_R11_EAC):
2146 case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT:
2147 case GL_COMPRESSED_RED_RGTC1_EXT: _internalFormat = GL_RED; break;
2148 case(GL_COMPRESSED_RG11_EAC):
2149 case(GL_COMPRESSED_SIGNED_RG11_EAC):
2150 case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
2151 case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: _internalFormat = GL_RG; break;
2152 }
2153 }
2154
2155 glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
2156 unsigned int rowLength = image->getRowLength();
2157
2158 bool useClientStorage = extensions->isClientStorageSupported && getClientStorageHint();
2159 if (useClientStorage)
2160 {
2161 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE,GL_TRUE);
2162
2163 #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)
2164 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_PRIORITY,0.0f);
2165 #endif
2166
2167 #ifdef GL_TEXTURE_STORAGE_HINT_APPLE
2168 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_CACHED_APPLE);
2169 #endif
2170 }
2171
2172 unsigned char* dataPtr = (unsigned char*)image->data();
2173
2174 // OSG_NOTICE<<"inwidth="<<inwidth<<" inheight="<<inheight<<" image->getFileName()"<<image->getFileName()<<std::endl;
2175
2176 bool needImageRescale = inwidth!=image->s() || inheight!=image->t();
2177 if (needImageRescale)
2178 {
2179 // resize the image to power of two.
2180
2181 if (image->isMipmap())
2182 {
2183 OSG_WARN<<"Warning:: Mipmapped osg::Image not a power of two, cannot apply to texture."<<std::endl;
2184 return;
2185 }
2186 else if (compressed_image)
2187 {
2188 OSG_WARN<<"Warning:: Compressed osg::Image not a power of two, cannot apply to texture."<<std::endl;
2189 return;
2190 }
2191
2192 unsigned int newTotalSize = osg::Image::computeRowWidthInBytes(inwidth,image->getPixelFormat(),image->getDataType(),image->getPacking())*inheight;
2193 dataPtr = new unsigned char [newTotalSize];
2194
2195 if (!dataPtr)
2196 {
2197 OSG_WARN<<"Warning:: Not enough memory to resize image, cannot apply to texture."<<std::endl;
2198 return;
2199 }
2200
2201 if (!image->getFileName().empty()) { OSG_NOTICE << "Scaling image '"<<image->getFileName()<<"' from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl; }
2202 else { OSG_NOTICE << "Scaling image from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl; }
2203
2204 PixelStorageModes psm;
2205 psm.pack_alignment = image->getPacking();
2206 psm.pack_row_length = image->getRowLength();
2207 psm.unpack_alignment = image->getPacking();
2208
2209 // rescale the image to the correct size.
2210 gluScaleImage(&psm, image->getPixelFormat(),
2211 image->s(),image->t(),image->getDataType(),image->data(),
2212 inwidth,inheight,image->getDataType(),
2213 dataPtr);
2214
2215 rowLength = 0;
2216 }
2217
2218 bool mipmappingRequired = _min_filter != LINEAR && _min_filter != NEAREST;
2219 bool useHardwareMipMapGeneration = mipmappingRequired && (!image->isMipmap() && isHardwareMipmapGenerationEnabled(state));
2220 bool useGluBuildMipMaps = mipmappingRequired && (!useHardwareMipMapGeneration && !image->isMipmap());
2221
2222 GLBufferObject* pbo = image->getOrCreateGLBufferObject(state.getContextID());
2223 if (pbo && !needImageRescale && !useGluBuildMipMaps)
2224 {
2225 state.bindPixelBufferObject(pbo);
2226 dataPtr = reinterpret_cast<unsigned char*>(pbo->getOffset(image->getBufferIndex()));
2227 rowLength = 0;
2228 #ifdef DO_TIMING
2229 OSG_NOTICE<<"after PBO "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
2230 #endif
2231 }
2232 else
2233 {
2234 pbo = 0;
2235 }
2236 #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)
2237 glPixelStorei(GL_UNPACK_ROW_LENGTH,rowLength);
2238 #endif
2239 if( !mipmappingRequired || useHardwareMipMapGeneration)
2240 {
2241
2242 GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, useHardwareMipMapGeneration);
2243
2244 if ( !compressed_image)
2245 {
2246 numMipmapLevels = 1;
2247
2248 glTexImage2D( target, 0, _internalFormat,
2249 inwidth, inheight, _borderWidth,
2250 (GLenum)image->getPixelFormat(),
2251 (GLenum)image->getDataType(),
2252 dataPtr);
2253
2254 }
2255 else if (extensions->isCompressedTexImage2DSupported())
2256 {
2257 numMipmapLevels = 1;
2258
2259 GLint blockSize, size;
2260 getCompressedSize(_internalFormat, inwidth, inheight, 1, blockSize,size);
2261
2262 extensions->glCompressedTexImage2D(target, 0, _internalFormat,
2263 inwidth, inheight,0,
2264 size,
2265 dataPtr);
2266 }
2267
2268 mipmapAfterTexImage(state, mipmapResult);
2269 }
2270 else
2271 {
2272 // we require mip mapping.
2273 if(image->isMipmap())
2274 {
2275
2276 // image is mip mapped so we take the mip map levels from the image.
2277
2278 numMipmapLevels = image->getNumMipmapLevels();
2279
2280 int width = inwidth;
2281 int height = inheight;
2282
2283 bool useTexStorrage = extensions->isTextureStorageEnabled;
2284 GLenum sizedInternalFormat = 0;
2285
2286 if(useTexStorrage)
2287 {
2288 if(extensions->isTexStorage2DSupported() && _borderWidth == 0)
2289 {
2290 //calculate sized internal format
2291 if(!compressed_image)
2292 {
2293 if(isSizedInternalFormat(_internalFormat))
2294 {
2295 sizedInternalFormat = _internalFormat;
2296 }
2297 else
2298 {
2299 sizedInternalFormat = assumeSizedInternalFormat((GLenum)image->getInternalTextureFormat(), (GLenum)image->getDataType());
2300 }
2301 }
2302 else
2303 {
2304 if(isCompressedInternalFormatSupportedByTexStorrage(_internalFormat))
2305 {
2306 sizedInternalFormat = _internalFormat;
2307 }
2308 }
2309 }
2310
2311 useTexStorrage &= sizedInternalFormat != 0;
2312 }
2313
2314 if(useTexStorrage)
2315 {
2316 extensions->glTexStorage2D(target, numMipmapLevels, sizedInternalFormat, width, height);
2317
2318 if( !compressed_image )
2319 {
2320 for( GLsizei k = 0 ; k < numMipmapLevels && (width || height) ;k++)
2321 {
2322
2323 if (width == 0)
2324 width = 1;
2325 if (height == 0)
2326 height = 1;
2327
2328 glTexSubImage2D( target, k,
2329 0, 0,
2330 width, height,
2331 (GLenum)image->getPixelFormat(),
2332 (GLenum)image->getDataType(),
2333 dataPtr + image->getMipmapOffset(k));
2334
2335 width >>= 1;
2336 height >>= 1;
2337 }
2338 }
2339 else if (extensions->isCompressedTexImage2DSupported())
2340 {
2341 GLint blockSize,size;
2342 for( GLsizei k = 0 ; k < numMipmapLevels && (width || height) ;k++)
2343 {
2344 if (width == 0)
2345 width = 1;
2346 if (height == 0)
2347 height = 1;
2348
2349 getCompressedSize(image->getInternalTextureFormat(), width, height, 1, blockSize,size);
2350
2351 //state.checkGLErrors("before extensions->glCompressedTexSubImage2D(");
2352
2353 extensions->glCompressedTexSubImage2D(target, k,
2354 0, 0,
2355 width, height,
2356 (GLenum)image->getPixelFormat(),
2357 size,
2358 dataPtr + image->getMipmapOffset(k));
2359
2360 //state.checkGLErrors("after extensions->glCompressedTexSubImage2D(");
2361
2362 width >>= 1;
2363 height >>= 1;
2364 }
2365 }
2366 }
2367 else
2368 {
2369 if( !compressed_image )
2370 {
2371 for( GLsizei k = 0 ; k < numMipmapLevels && (width || height) ;k++)
2372 {
2373
2374 if (width == 0)
2375 width = 1;
2376 if (height == 0)
2377 height = 1;
2378
2379 glTexImage2D( target, k, _internalFormat,
2380 width, height, _borderWidth,
2381 (GLenum)image->getPixelFormat(),
2382 (GLenum)image->getDataType(),
2383 dataPtr + image->getMipmapOffset(k));
2384
2385 width >>= 1;
2386 height >>= 1;
2387 }
2388 }
2389 else if (extensions->isCompressedTexImage2DSupported())
2390 {
2391 GLint blockSize, size;
2392
2393 for( GLsizei k = 0 ; k < numMipmapLevels && (width || height) ;k++)
2394 {
2395 if (width == 0)
2396 width = 1;
2397 if (height == 0)
2398 height = 1;
2399
2400 getCompressedSize(_internalFormat, width, height, 1, blockSize,size);
2401
2402 extensions->glCompressedTexImage2D(target, k, _internalFormat,
2403 width, height, _borderWidth,
2404 size, dataPtr + image->getMipmapOffset(k));
2405
2406 width >>= 1;
2407 height >>= 1;
2408 }
2409 }
2410 }
2411 }
2412 else
2413 {
2414 if ( !compressed_image)
2415 {
2416 numMipmapLevels = 0;
2417
2418 gluBuild2DMipmaps( target, _internalFormat,
2419 inwidth,inheight,
2420 (GLenum)image->getPixelFormat(), (GLenum)image->getDataType(),
2421 dataPtr);
2422
2423 int width = image->s();
2424 int height = image->t();
2425 for( numMipmapLevels = 0 ; (width || height) ; ++numMipmapLevels)
2426 {
2427 width >>= 1;
2428 height >>= 1;
2429 }
2430 }
2431 else
2432 {
2433 OSG_WARN<<"Warning:: Compressed image cannot be mip mapped"<<std::endl;
2434 }
2435
2436 }
2437
2438 }
2439
2440 if (pbo)
2441 {
2442 state.unbindPixelBufferObject();
2443
2444 const BufferObject* bo = image->getBufferObject();
2445 if (bo->getCopyDataAndReleaseGLBufferObject())
2446 {
2447 pbo->setBufferDataHasBeenRead(image);
2448 if (pbo->hasAllBufferDataBeenRead())
2449 {
2450 //OSG_NOTICE<<"Release PBO"<<std::endl;
2451 bo->releaseGLObjects(&state);
2452 }
2453 }
2454 }
2455
2456 #ifdef DO_TIMING
2457 static double s_total_time = 0.0;
2458 double delta_time = osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick());
2459 s_total_time += delta_time;
2460 OSG_NOTICE<<"glTexImage2D "<<delta_time<<"ms total "<<s_total_time<<"ms"<<std::endl;
2461 #endif
2462
2463 if (needImageRescale)
2464 {
2465 // clean up the resized image.
2466 delete [] dataPtr;
2467 }
2468
2469 if (useClientStorage)
2470 {
2471 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE,GL_FALSE);
2472 }
2473 }
2474
2475
2476
applyTexImage2D_subload(State & state,GLenum target,const Image * image,GLsizei inwidth,GLsizei inheight,GLint inInternalFormat,GLint numMipmapLevels) const2477 void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image* image, GLsizei inwidth, GLsizei inheight, GLint inInternalFormat, GLint numMipmapLevels) const
2478 {
2479 // if we don't have a valid image we can't create a texture!
2480 if (!image || !image->data())
2481 return;
2482
2483 // image size has changed so we have to re-load the image from scratch.
2484 if (image->s()!=inwidth || image->t()!=inheight || image->getInternalTextureFormat()!=inInternalFormat )
2485 {
2486 applyTexImage2D_load(state, target, image, inwidth, inheight,numMipmapLevels);
2487 return;
2488 }
2489 // else image size the same as when loaded so we can go ahead and subload
2490
2491 // If the texture's internal format is a compressed type, then the
2492 // user is requesting that the graphics card compress the image if it's
2493 // not already compressed. However, if the image is not a multiple of
2494 // four in each dimension the subsequent calls to glTexSubImage* will
2495 // fail. Revert to uncompressed format in this case.
2496 if (isCompressedInternalFormat(_internalFormat) &&
2497 (((inwidth >> 2) << 2) != inwidth ||
2498 ((inheight >> 2) << 2) != inheight))
2499 {
2500 applyTexImage2D_load(state, target, image, inwidth, inheight, numMipmapLevels);
2501 return;
2502 }
2503
2504 #ifdef DO_TIMING
2505 osg::Timer_t start_tick = osg::Timer::instance()->tick();
2506 OSG_NOTICE<<"glTexSubImage2D pixelFormat = "<<std::hex<<image->getPixelFormat()<<std::dec<<std::endl;
2507 #endif
2508
2509
2510 // get the contextID (user defined ID of 0 upwards) for the
2511 // current OpenGL context.
2512 const unsigned int contextID = state.getContextID();
2513 const GLExtensions* extensions = state.get<GLExtensions>();
2514
2515 // select the internalFormat required for the texture.
2516 bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
2517
2518 glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
2519 unsigned int rowLength = image->getRowLength();
2520
2521 unsigned char* dataPtr = (unsigned char*)image->data();
2522
2523 bool needImageRescale = inwidth!=image->s() || inheight!=image->t();
2524 if (needImageRescale)
2525 {
2526 // resize the image to power of two.
2527 if (image->isMipmap())
2528 {
2529 OSG_WARN<<"Warning:: Mipmapped osg::Image not a power of two, cannot apply to texture."<<std::endl;
2530 return;
2531 }
2532 else if (compressed_image)
2533 {
2534 OSG_WARN<<"Warning:: Compressed osg::Image not a power of two, cannot apply to texture."<<std::endl;
2535 return;
2536 }
2537
2538 unsigned int newTotalSize = osg::Image::computeRowWidthInBytes(inwidth,image->getPixelFormat(),image->getDataType(),image->getPacking())*inheight;
2539 dataPtr = new unsigned char [newTotalSize];
2540
2541 if (!dataPtr)
2542 {
2543 OSG_WARN<<"Warning:: Not enough memory to resize image, cannot apply to texture."<<std::endl;
2544 return;
2545 }
2546
2547 if (!image->getFileName().empty()) { OSG_NOTICE << "Scaling image '"<<image->getFileName()<<"' from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl; }
2548 else { OSG_NOTICE << "Scaling image from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl; }
2549
2550 // rescale the image to the correct size.
2551 PixelStorageModes psm;
2552 psm.pack_alignment = image->getPacking();
2553 psm.unpack_alignment = image->getPacking();
2554
2555 gluScaleImage(&psm, image->getPixelFormat(),
2556 image->s(),image->t(),image->getDataType(),image->data(),
2557 inwidth,inheight,image->getDataType(),
2558 dataPtr);
2559
2560 rowLength = 0;
2561 }
2562
2563
2564 bool mipmappingRequired = _min_filter != LINEAR && _min_filter != NEAREST;
2565 bool useHardwareMipMapGeneration = mipmappingRequired && (!image->isMipmap() && isHardwareMipmapGenerationEnabled(state));
2566 bool useGluBuildMipMaps = mipmappingRequired && (!useHardwareMipMapGeneration && !image->isMipmap());
2567
2568 GLBufferObject* pbo = image->getOrCreateGLBufferObject(contextID);
2569 if (pbo && !needImageRescale && !useGluBuildMipMaps)
2570 {
2571 state.bindPixelBufferObject(pbo);
2572 dataPtr = reinterpret_cast<unsigned char*>(pbo->getOffset(image->getBufferIndex()));
2573 rowLength = 0;
2574 #ifdef DO_TIMING
2575 OSG_NOTICE<<"after PBO "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
2576 #endif
2577 }
2578 else
2579 {
2580 pbo = 0;
2581 }
2582 #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)
2583 glPixelStorei(GL_UNPACK_ROW_LENGTH,rowLength);
2584 #endif
2585 if( !mipmappingRequired || useHardwareMipMapGeneration)
2586 {
2587
2588 GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, useHardwareMipMapGeneration);
2589
2590 if (!compressed_image)
2591 {
2592 glTexSubImage2D( target, 0,
2593 0, 0,
2594 inwidth, inheight,
2595 (GLenum)image->getPixelFormat(),
2596 (GLenum)image->getDataType(),
2597 dataPtr);
2598 }
2599 else if (extensions->isCompressedTexImage2DSupported())
2600 {
2601 GLint blockSize,size;
2602 getCompressedSize(image->getInternalTextureFormat(), inwidth, inheight, 1, blockSize,size);
2603
2604 extensions->glCompressedTexSubImage2D(target, 0,
2605 0,0,
2606 inwidth, inheight,
2607 (GLenum)image->getPixelFormat(),
2608 size,
2609 dataPtr);
2610 }
2611
2612 mipmapAfterTexImage(state, mipmapResult);
2613 }
2614 else
2615 {
2616 if (image->isMipmap())
2617 {
2618 numMipmapLevels = image->getNumMipmapLevels();
2619
2620 int width = inwidth;
2621 int height = inheight;
2622
2623 if( !compressed_image )
2624 {
2625 for( GLsizei k = 0 ; k < numMipmapLevels && (width || height) ;k++)
2626 {
2627
2628 if (width == 0)
2629 width = 1;
2630 if (height == 0)
2631 height = 1;
2632
2633 glTexSubImage2D( target, k,
2634 0, 0,
2635 width, height,
2636 (GLenum)image->getPixelFormat(),
2637 (GLenum)image->getDataType(),
2638 dataPtr + image->getMipmapOffset(k));
2639
2640 width >>= 1;
2641 height >>= 1;
2642 }
2643 }
2644 else if (extensions->isCompressedTexImage2DSupported())
2645 {
2646 GLint blockSize,size;
2647 for( GLsizei k = 0 ; k < numMipmapLevels && (width || height) ;k++)
2648 {
2649 if (width == 0)
2650 width = 1;
2651 if (height == 0)
2652 height = 1;
2653
2654 getCompressedSize(image->getInternalTextureFormat(), width, height, 1, blockSize,size);
2655
2656 //state.checkGLErrors("before extensions->glCompressedTexSubImage2D(");
2657
2658 extensions->glCompressedTexSubImage2D(target, k,
2659 0, 0,
2660 width, height,
2661 (GLenum)image->getPixelFormat(),
2662 size,
2663 dataPtr + image->getMipmapOffset(k));
2664
2665 //state.checkGLErrors("after extensions->glCompressedTexSubImage2D(");
2666
2667 width >>= 1;
2668 height >>= 1;
2669 }
2670
2671 }
2672 }
2673 else
2674 {
2675 //OSG_WARN<<"Warning:: cannot subload mip mapped texture from non mipmapped image."<<std::endl;
2676 applyTexImage2D_load(state, target, image, inwidth, inheight,numMipmapLevels);
2677 }
2678 }
2679
2680 if (pbo)
2681 {
2682 state.unbindPixelBufferObject();
2683 }
2684 #ifdef DO_TIMING
2685 OSG_NOTICE<<"glTexSubImage2D "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
2686 #endif
2687
2688 if (needImageRescale)
2689 {
2690 // clean up the resized image.
2691 delete [] dataPtr;
2692 }
2693 }
2694
isHardwareMipmapGenerationEnabled(const State & state) const2695 bool Texture::isHardwareMipmapGenerationEnabled(const State& state) const
2696 {
2697 if (_useHardwareMipMapGeneration)
2698 {
2699 const GLExtensions* extensions = state.get<GLExtensions>();
2700 if (extensions->isGenerateMipMapSupported)
2701 {
2702 return true;
2703 }
2704
2705 // FrameBufferObjects are required for glGenerateMipmap
2706 if (extensions->isFrameBufferObjectSupported && extensions->glGenerateMipmap)
2707 {
2708 return true;
2709 }
2710 }
2711
2712 return false;
2713 }
2714
mipmapBeforeTexImage(const State & state,bool hardwareMipmapOn) const2715 Texture::GenerateMipmapMode Texture::mipmapBeforeTexImage(const State& state, bool hardwareMipmapOn) const
2716 {
2717 if (hardwareMipmapOn)
2718 {
2719 #if defined( OSG_GLES2_AVAILABLE ) || defined( OSG_GL3_AVAILABLE )
2720 return GENERATE_MIPMAP;
2721 #else
2722
2723 const GLExtensions* extensions = state.get<GLExtensions>();
2724 bool useGenerateMipMap = extensions->isFrameBufferObjectSupported && extensions->glGenerateMipmap;
2725
2726 if (useGenerateMipMap)
2727 {
2728 if (extensions->preferGenerateMipmapSGISForPowerOfTwo)
2729 {
2730 int width = getTextureWidth();
2731 int height = getTextureHeight();
2732 useGenerateMipMap = ((width & (width - 1)) || (height & (height - 1)));
2733 }
2734
2735 if (useGenerateMipMap)
2736 {
2737 useGenerateMipMap = (_internalFormatType != SIGNED_INTEGER && _internalFormatType != UNSIGNED_INTEGER);
2738 }
2739
2740 if (useGenerateMipMap) return GENERATE_MIPMAP;
2741 }
2742
2743 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
2744 return GENERATE_MIPMAP_TEX_PARAMETER;
2745 #endif
2746 }
2747 return GENERATE_MIPMAP_NONE;
2748 }
2749
mipmapAfterTexImage(State & state,GenerateMipmapMode beforeResult) const2750 void Texture::mipmapAfterTexImage(State& state, GenerateMipmapMode beforeResult) const
2751 {
2752 switch (beforeResult)
2753 {
2754 case GENERATE_MIPMAP:
2755 {
2756 unsigned int contextID = state.getContextID();
2757 TextureObject* textureObject = getTextureObject(contextID);
2758 if (textureObject)
2759 {
2760 osg::GLExtensions* ext = state.get<GLExtensions>();
2761 ext->glGenerateMipmap(textureObject->target());
2762 }
2763 break;
2764 }
2765 case GENERATE_MIPMAP_TEX_PARAMETER:
2766 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
2767 break;
2768 case GENERATE_MIPMAP_NONE:
2769 break;
2770 }
2771 }
2772
generateMipmap(State & state) const2773 void Texture::generateMipmap(State& state) const
2774 {
2775 const unsigned int contextID = state.getContextID();
2776
2777 // get the texture object for the current contextID.
2778 TextureObject* textureObject = getTextureObject(contextID);
2779
2780 // if not initialized before, then do nothing
2781 if (textureObject == NULL) return;
2782
2783 _texMipmapGenerationDirtyList[contextID] = 0;
2784
2785 // if internal format does not provide automatic mipmap generation, then do manual allocation
2786 if (_internalFormatType == SIGNED_INTEGER || _internalFormatType == UNSIGNED_INTEGER)
2787 {
2788 allocateMipmap(state);
2789 return;
2790 }
2791
2792 // get fbo extension which provides us with the glGenerateMipmapEXT function
2793 osg::GLExtensions* ext = state.get<GLExtensions>();
2794
2795 // FrameBufferObjects are required for glGenerateMipmap
2796 if (ext->isFrameBufferObjectSupported && ext->glGenerateMipmap)
2797 {
2798 textureObject->bind();
2799 ext->glGenerateMipmap(textureObject->target());
2800
2801 // inform state that this texture is the current one bound.
2802 state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);
2803
2804 // if the function is not supported, then do manual allocation
2805 }else
2806 {
2807 allocateMipmap(state);
2808 }
2809
2810 }
2811
compileGLObjects(State & state) const2812 void Texture::compileGLObjects(State& state) const
2813 {
2814 apply(state);
2815 }
2816
resizeGLObjectBuffers(unsigned int maxSize)2817 void Texture::resizeGLObjectBuffers(unsigned int maxSize)
2818 {
2819 _textureObjectBuffer.resize(maxSize);
2820 _texParametersDirtyList.resize(maxSize);
2821 _texMipmapGenerationDirtyList.resize(maxSize);
2822 }
2823
releaseGLObjects(State * state) const2824 void Texture::releaseGLObjects(State* state) const
2825 {
2826 // if (state) OSG_NOTICE<<"Texture::releaseGLObjects contextID="<<state->getContextID()<<std::endl;
2827 // else OSG_NOTICE<<"Texture::releaseGLObjects no State "<<std::endl;
2828
2829 if (!state) const_cast<Texture*>(this)->dirtyTextureObject();
2830 else
2831 {
2832 unsigned int contextID = state->getContextID();
2833 if (_textureObjectBuffer[contextID].valid())
2834 {
2835 Texture::releaseTextureObject(contextID, _textureObjectBuffer[contextID].get());
2836
2837 _textureObjectBuffer[contextID] = 0;
2838 }
2839 }
2840 }
2841
2842 }
2843