1 /* -*-c++-*- */
2 /* osgEarth - Geospatial SDK for OpenSceneGraph
3  * Copyright 2019 Pelican Mapping
4  * http://osgearth.org
5  *
6  * osgEarth is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>
18  */
19 
20 #include <osgEarth/TerrainResources>
21 #include <osgEarth/Registry>
22 #include <osgEarth/Capabilities>
23 #include <osgEarth/Layer>
24 
25 using namespace osgEarth;
26 
27 #define LC "[TerrainResources] "
28 
29 
TerrainResources()30 TerrainResources::TerrainResources()
31 {
32     //nop
33 }
34 
35 bool
reserveTextureImageUnit(int & out_unit,const char * requestor)36 TerrainResources::reserveTextureImageUnit(int&        out_unit,
37                                           const char* requestor)
38 {
39     out_unit = -1;
40     unsigned maxUnits = osgEarth::Registry::instance()->getCapabilities().getMaxGPUTextureUnits();
41 
42     Threading::ScopedMutexLock exclusiveLock( _reservedUnitsMutex );
43 
44     // first collect a list of units that are already in use.
45     std::set<int> taken;
46     taken.insert(_globallyReservedUnits.begin(), _globallyReservedUnits.end());
47     for (PerLayerReservedUnits::const_iterator i = _perLayerReservedUnits.begin();
48         i != _perLayerReservedUnits.end();
49         ++i)
50     {
51         taken.insert(i->second.begin(), i->second.end());
52     }
53 
54     // now find the first unused one.
55     for( unsigned i=0; i<maxUnits; ++i )
56     {
57         if (taken.find(i) == taken.end())
58         {
59             _globallyReservedUnits.insert( i );
60             out_unit = i;
61             if ( requestor )
62             {
63                 OE_INFO << LC << "Texture unit " << i << " reserved for " << requestor << std::endl;
64             }
65             return true;
66         }
67     }
68     return false;
69 }
70 
71 bool
reserveTextureImageUnit(TextureImageUnitReservation & reservation,const char * requestor)72 TerrainResources::reserveTextureImageUnit(TextureImageUnitReservation& reservation,
73                                           const char* requestor)
74 {
75     reservation._unit = -1;
76     unsigned maxUnits = osgEarth::Registry::instance()->getCapabilities().getMaxGPUTextureUnits();
77 
78     Threading::ScopedMutexLock exclusiveLock( _reservedUnitsMutex );
79 
80     // first collect a list of units that are already in use.
81     std::set<int> taken;
82     taken.insert(_globallyReservedUnits.begin(), _globallyReservedUnits.end());
83     for (PerLayerReservedUnits::const_iterator i = _perLayerReservedUnits.begin();
84         i != _perLayerReservedUnits.end();
85         ++i)
86     {
87         taken.insert(i->second.begin(), i->second.end());
88     }
89 
90     for( unsigned i=0; i<maxUnits; ++i )
91     {
92         if (taken.find(i) == taken.end())
93         {
94             _globallyReservedUnits.insert( i );
95             reservation._unit = i;
96             reservation._layer = 0L;
97             reservation._res = this;
98             if ( requestor )
99             {
100                 OE_INFO << LC << "Texture unit " << i << " reserved for " << requestor << std::endl;
101             }
102             return true;
103         }
104     }
105     return false;
106 }
107 
108 bool
reserveTextureImageUnitForLayer(TextureImageUnitReservation & reservation,const Layer * layer,const char * requestor)109 TerrainResources::reserveTextureImageUnitForLayer(TextureImageUnitReservation& reservation,
110                                                   const Layer* layer,
111                                                   const char* requestor)
112 {
113     if (layer == 0L)
114     {
115         OE_WARN << LC << "ILLEGAL USAGE: layer must be non-null\n";
116         return false;
117     }
118 
119     reservation._unit = -1;
120     unsigned maxUnits = osgEarth::Registry::instance()->getCapabilities().getMaxGPUTextureUnits();
121 
122     Threading::ScopedMutexLock exclusiveLock( _reservedUnitsMutex );
123 
124     // first collect a list of units that are already in use.
125     std::set<int> taken;
126     taken.insert(_globallyReservedUnits.begin(), _globallyReservedUnits.end());
127     ReservedUnits& layerReservedUnits = _perLayerReservedUnits[layer];
128     taken.insert(layerReservedUnits.begin(), layerReservedUnits.end());
129 
130     for( unsigned i=0; i<maxUnits; ++i )
131     {
132         if (taken.find(i) == taken.end())
133         {
134             layerReservedUnits.insert( i );
135             reservation._unit = i;
136             reservation._layer = layer;
137             reservation._res = this;
138             if ( requestor )
139             {
140                 OE_INFO << LC << "Texture unit " << i << " reserved (on layer "
141                     << layer->getName() << ") for " << requestor << std::endl;
142             }
143             return true;
144         }
145     }
146     return false;
147 }
148 
149 void
releaseTextureImageUnit(int unit)150 TerrainResources::releaseTextureImageUnit(int unit)
151 {
152     Threading::ScopedMutexLock exclusiveLock( _reservedUnitsMutex );
153     _globallyReservedUnits.erase( unit );
154     OE_INFO << LC << "Texture unit " << unit << " released\n";
155 }
156 
157 void
releaseTextureImageUnit(int unit,const Layer * layer)158 TerrainResources::releaseTextureImageUnit(int unit, const Layer* layer)
159 {
160     if (layer == 0L)
161         releaseTextureImageUnit(unit);
162 
163     Threading::ScopedMutexLock exclusiveLock( _reservedUnitsMutex );
164     PerLayerReservedUnits::iterator i = _perLayerReservedUnits.find(layer);
165     if (i != _perLayerReservedUnits.end())
166     {
167         ReservedUnits& reservedUnits = i->second;
168         reservedUnits.erase(unit);
169 
170         // if there are no more units reserved for this layer, remove the record entirely
171         if (reservedUnits.empty())
172         {
173             _perLayerReservedUnits.erase(i);
174         }
175 
176         OE_INFO << LC << "Texture unit " << unit << " released (by layer " << layer->getName() << ")" << std::endl;
177     }
178 }
179 
180 bool
setTextureImageUnitOffLimits(int unit)181 TerrainResources::setTextureImageUnitOffLimits(int unit)
182 {
183     Threading::ScopedMutexLock exclusiveLock( _reservedUnitsMutex );
184 
185     // Make sure it's not already reserved:
186     if (_globallyReservedUnits.find(unit) != _globallyReservedUnits.end())
187     {
188         // no good! Already in use globally.
189         return false;
190     }
191 
192     for (PerLayerReservedUnits::const_iterator i = _perLayerReservedUnits.begin();
193         i != _perLayerReservedUnits.end();
194         ++i)
195     {
196         if (i->second.find(unit) != i->second.end())
197         {
198             // no good! Already in use by a layer.
199             return false;
200         }
201     }
202 
203     _globallyReservedUnits.insert( unit );
204     return true;
205 }
206 
207 //........................................................................
TextureImageUnitReservation()208 TextureImageUnitReservation::TextureImageUnitReservation()
209 {
210     _unit = -1;
211     _layer = 0L;
212 }
213 
~TextureImageUnitReservation()214 TextureImageUnitReservation::~TextureImageUnitReservation()
215 {
216     osg::ref_ptr<TerrainResources> res;
217     if (_unit >= 0 && _res.lock(res))
218     {
219         res->releaseTextureImageUnit(_unit, _layer);
220     }
221 }
222