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