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