diff options
-rw-r--r-- | OpenSim/Region/Framework/Scenes/Prioritizer.cs | 292 |
1 files changed, 82 insertions, 210 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index 2764b05..a14bb70 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs | |||
@@ -60,15 +60,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
60 | { | 60 | { |
61 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | 61 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); |
62 | 62 | ||
63 | /// <summary> | ||
64 | /// This is added to the priority of all child prims, to make sure that the root prim update is sent to the | ||
65 | /// viewer before child prim updates. | ||
66 | /// The adjustment is added to child prims and subtracted from root prims, so the gap ends up | ||
67 | /// being double. We do it both ways so that there is a still a priority delta even if the priority is already | ||
68 | /// double.MinValue or double.MaxValue. | ||
69 | /// </summary> | ||
70 | private double m_childPrimAdjustmentFactor = 0.05; | ||
71 | |||
72 | private Scene m_scene; | 63 | private Scene m_scene; |
73 | 64 | ||
74 | public Prioritizer(Scene scene) | 65 | public Prioritizer(Scene scene) |
@@ -76,9 +67,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
76 | m_scene = scene; | 67 | m_scene = scene; |
77 | } | 68 | } |
78 | 69 | ||
79 | //<mic> | 70 | /// <summary> |
71 | /// Returns the priority queue into which the update should be placed. Updates within a | ||
72 | /// queue will be processed in arrival order. There are currently 12 priority queues | ||
73 | /// implemented in PriorityQueue class in LLClientView. Queue 0 is generally retained | ||
74 | /// for avatar updates. The fair queuing discipline for processing the priority queues | ||
75 | /// assumes that the number of entities in each priority queues increases exponentially. | ||
76 | /// So for example... if queue 1 contains all updates within 10m of the avatar or camera | ||
77 | /// then queue 2 at 20m is about 3X bigger in space & about 3X bigger in total number | ||
78 | /// of updates. | ||
79 | /// </summary> | ||
80 | public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity) | 80 | public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity) |
81 | { | 81 | { |
82 | // If entity is null we have a serious problem | ||
82 | if (entity == null) | 83 | if (entity == null) |
83 | { | 84 | { |
84 | m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity"); | 85 | m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity"); |
@@ -89,71 +90,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
89 | if (client.AgentId == entity.UUID) | 90 | if (client.AgentId == entity.UUID) |
90 | return 0; | 91 | return 0; |
91 | 92 | ||
92 | // Get this agent's position | 93 | uint priority; |
93 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); | ||
94 | if (presence == null) | ||
95 | { | ||
96 | m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene"); | ||
97 | throw new InvalidOperationException("Prioritization agent not defined"); | ||
98 | } | ||
99 | |||
100 | // Use group position for child prims | ||
101 | Vector3 entityPos = entity.AbsolutePosition; | ||
102 | if (entity is SceneObjectPart) | ||
103 | { | ||
104 | SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; | ||
105 | if (group != null) | ||
106 | entityPos = group.AbsolutePosition; | ||
107 | } | ||
108 | |||
109 | // Use the camera position for local agents and avatar position for remote agents | ||
110 | Vector3 presencePos = (presence.IsChildAgent) ? | ||
111 | presence.AbsolutePosition : | ||
112 | presence.CameraPosition; | ||
113 | |||
114 | // Compute the distance... | ||
115 | double distance = Vector3.Distance(presencePos, entityPos); | ||
116 | |||
117 | // And convert the distance to a priority queue, this computation gives queues | ||
118 | // at 10, 20, 40, 80, 160, 320, 640, and 1280m | ||
119 | uint pqueue = 1; | ||
120 | for (int i = 0; i < 8; i++) | ||
121 | { | ||
122 | if (distance < 10 * Math.Pow(2.0,i)) | ||
123 | break; | ||
124 | pqueue++; | ||
125 | } | ||
126 | |||
127 | // If this is a root agent, then determine front & back | ||
128 | // Bump up the priority queue for any objects behind the avatar | ||
129 | if (! presence.IsChildAgent) | ||
130 | { | ||
131 | // Root agent, decrease priority for objects behind us | ||
132 | Vector3 camPosition = presence.CameraPosition; | ||
133 | Vector3 camAtAxis = presence.CameraAtAxis; | ||
134 | |||
135 | // Plane equation | ||
136 | float d = -Vector3.Dot(camPosition, camAtAxis); | ||
137 | float p = Vector3.Dot(camAtAxis, entityPos) + d; | ||
138 | if (p < 0.0f) | ||
139 | pqueue++; | ||
140 | } | ||
141 | |||
142 | return pqueue; | ||
143 | } | ||
144 | //</mic> | ||
145 | |||
146 | public double bGetUpdatePriority(IClientAPI client, ISceneEntity entity) | ||
147 | { | ||
148 | double priority = 0; | ||
149 | |||
150 | if (entity == null) | ||
151 | return 100000; | ||
152 | 94 | ||
153 | switch (m_scene.UpdatePrioritizationScheme) | 95 | switch (m_scene.UpdatePrioritizationScheme) |
154 | { | 96 | { |
155 | case UpdatePrioritizationSchemes.Time: | 97 | case UpdatePrioritizationSchemes.Time: |
156 | priority = GetPriorityByTime(); | 98 | priority = GetPriorityByTime(client, entity); |
157 | break; | 99 | break; |
158 | case UpdatePrioritizationSchemes.Distance: | 100 | case UpdatePrioritizationSchemes.Distance: |
159 | priority = GetPriorityByDistance(client, entity); | 101 | priority = GetPriorityByDistance(client, entity); |
@@ -171,180 +113,110 @@ namespace OpenSim.Region.Framework.Scenes | |||
171 | throw new InvalidOperationException("UpdatePrioritizationScheme not defined."); | 113 | throw new InvalidOperationException("UpdatePrioritizationScheme not defined."); |
172 | } | 114 | } |
173 | 115 | ||
174 | // Adjust priority so that root prims are sent to the viewer first. This is especially important for | ||
175 | // attachments acting as huds, since current viewers fail to display hud child prims if their updates | ||
176 | // arrive before the root one. | ||
177 | if (entity is SceneObjectPart) | ||
178 | { | ||
179 | SceneObjectPart sop = ((SceneObjectPart)entity); | ||
180 | |||
181 | if (sop.IsRoot) | ||
182 | { | ||
183 | if (priority >= double.MinValue + m_childPrimAdjustmentFactor) | ||
184 | priority -= m_childPrimAdjustmentFactor; | ||
185 | } | ||
186 | else | ||
187 | { | ||
188 | if (priority <= double.MaxValue - m_childPrimAdjustmentFactor) | ||
189 | priority += m_childPrimAdjustmentFactor; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | return priority; | 116 | return priority; |
194 | } | 117 | } |
195 | 118 | ||
196 | private double GetPriorityByTime() | 119 | |
120 | private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity) | ||
197 | { | 121 | { |
198 | return DateTime.UtcNow.ToOADate(); | 122 | return 1; |
199 | } | 123 | } |
200 | 124 | ||
201 | private double GetPriorityByDistance(IClientAPI client, ISceneEntity entity) | 125 | private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity) |
202 | { | 126 | { |
203 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); | 127 | return ComputeDistancePriority(client,entity,false); |
204 | if (presence != null) | 128 | } |
205 | { | 129 | |
206 | // If this is an update for our own avatar give it the highest priority | 130 | private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) |
207 | if (presence == entity) | 131 | { |
208 | return 0.0; | 132 | return ComputeDistancePriority(client,entity,true); |
209 | |||
210 | // Use the camera position for local agents and avatar position for remote agents | ||
211 | Vector3 presencePos = (presence.IsChildAgent) ? | ||
212 | presence.AbsolutePosition : | ||
213 | presence.CameraPosition; | ||
214 | |||
215 | // Use group position for child prims | ||
216 | Vector3 entityPos; | ||
217 | if (entity is SceneObjectPart) | ||
218 | { | ||
219 | // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene | ||
220 | // before its scheduled update was triggered | ||
221 | //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; | ||
222 | entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition; | ||
223 | } | ||
224 | else | ||
225 | { | ||
226 | entityPos = entity.AbsolutePosition; | ||
227 | } | ||
228 | |||
229 | return Vector3.DistanceSquared(presencePos, entityPos); | ||
230 | } | ||
231 | |||
232 | return double.NaN; | ||
233 | } | 133 | } |
234 | 134 | ||
235 | private double GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) | 135 | private uint GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) |
236 | { | 136 | { |
137 | uint pqueue = ComputeDistancePriority(client,entity,true); | ||
138 | |||
237 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); | 139 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); |
238 | if (presence != null) | 140 | if (presence != null) |
239 | { | 141 | { |
240 | // If this is an update for our own avatar give it the highest priority | ||
241 | if (presence == entity) | ||
242 | return 0.0; | ||
243 | |||
244 | // Use group position for child prims | ||
245 | Vector3 entityPos = entity.AbsolutePosition; | ||
246 | if (entity is SceneObjectPart) | ||
247 | { | ||
248 | // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene | ||
249 | // before its scheduled update was triggered | ||
250 | //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; | ||
251 | entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition; | ||
252 | } | ||
253 | else | ||
254 | { | ||
255 | entityPos = entity.AbsolutePosition; | ||
256 | } | ||
257 | |||
258 | if (!presence.IsChildAgent) | 142 | if (!presence.IsChildAgent) |
259 | { | 143 | { |
260 | // Root agent. Use distance from camera and a priority decrease for objects behind us | 144 | if (entity is SceneObjectPart) |
261 | Vector3 camPosition = presence.CameraPosition; | 145 | { |
262 | Vector3 camAtAxis = presence.CameraAtAxis; | 146 | // Non physical prims are lower priority than physical prims |
263 | 147 | PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; | |
264 | // Distance | 148 | if (physActor == null || !physActor.IsPhysical) |
265 | double priority = Vector3.DistanceSquared(camPosition, entityPos); | 149 | pqueue++; |
266 | |||
267 | // Plane equation | ||
268 | float d = -Vector3.Dot(camPosition, camAtAxis); | ||
269 | float p = Vector3.Dot(camAtAxis, entityPos) + d; | ||
270 | if (p < 0.0f) priority *= 2.0; | ||
271 | |||
272 | return priority; | ||
273 | } | ||
274 | else | ||
275 | { | ||
276 | // Child agent. Use the normal distance method | ||
277 | Vector3 presencePos = presence.AbsolutePosition; | ||
278 | 150 | ||
279 | return Vector3.DistanceSquared(presencePos, entityPos); | 151 | // Attachments are high priority, |
152 | // MIC: shouldn't these already be in the highest priority queue already | ||
153 | // since their root position is same as the avatars? | ||
154 | if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) | ||
155 | pqueue = 1; | ||
156 | } | ||
280 | } | 157 | } |
281 | } | 158 | } |
282 | 159 | ||
283 | return double.NaN; | 160 | return pqueue; |
284 | } | 161 | } |
285 | 162 | ||
286 | private double GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) | 163 | private uint ComputeDistancePriority(IClientAPI client, ISceneEntity entity, bool useFrontBack) |
287 | { | 164 | { |
288 | // If this is an update for our own avatar give it the highest priority | 165 | // Get this agent's position |
289 | if (client.AgentId == entity.UUID) | 166 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); |
290 | return 0.0; | 167 | if (presence == null) |
291 | if (entity == null) | 168 | { |
292 | return double.NaN; | 169 | m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene"); |
293 | 170 | throw new InvalidOperationException("Prioritization agent not defined"); | |
294 | // Use group position for child prims | 171 | } |
172 | |||
173 | // Use group position for child prims, since we are putting child prims in | ||
174 | // the same queue with the root of the group, the root prim (which goes into | ||
175 | // the queue first) should always be sent first, no need to adjust child prim | ||
176 | // priorities | ||
295 | Vector3 entityPos = entity.AbsolutePosition; | 177 | Vector3 entityPos = entity.AbsolutePosition; |
296 | if (entity is SceneObjectPart) | 178 | if (entity is SceneObjectPart) |
297 | { | 179 | { |
298 | SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; | 180 | SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; |
299 | if (group != null) | 181 | if (group != null) |
300 | entityPos = group.AbsolutePosition; | 182 | entityPos = group.AbsolutePosition; |
301 | else | ||
302 | entityPos = entity.AbsolutePosition; | ||
303 | } | 183 | } |
304 | else | ||
305 | entityPos = entity.AbsolutePosition; | ||
306 | |||
307 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); | ||
308 | if (presence != null) | ||
309 | { | ||
310 | if (!presence.IsChildAgent) | ||
311 | { | ||
312 | if (entity is ScenePresence) | ||
313 | return 1.0; | ||
314 | 184 | ||
315 | // Root agent. Use distance from camera and a priority decrease for objects behind us | 185 | // Use the camera position for local agents and avatar position for remote agents |
316 | Vector3 camPosition = presence.CameraPosition; | 186 | Vector3 presencePos = (presence.IsChildAgent) ? |
317 | Vector3 camAtAxis = presence.CameraAtAxis; | 187 | presence.AbsolutePosition : |
318 | 188 | presence.CameraPosition; | |
319 | // Distance | ||
320 | double priority = Vector3.DistanceSquared(camPosition, entityPos); | ||
321 | |||
322 | // Plane equation | ||
323 | float d = -Vector3.Dot(camPosition, camAtAxis); | ||
324 | float p = Vector3.Dot(camAtAxis, entityPos) + d; | ||
325 | if (p < 0.0f) priority *= 2.0; | ||
326 | 189 | ||
327 | if (entity is SceneObjectPart) | 190 | // Compute the distance... |
328 | { | 191 | double distance = Vector3.Distance(presencePos, entityPos); |
329 | PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; | ||
330 | if (physActor == null || !physActor.IsPhysical) | ||
331 | priority += 100; | ||
332 | 192 | ||
333 | if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) | 193 | // And convert the distance to a priority queue, this computation gives queues |
334 | priority = 1.0; | 194 | // at 10, 20, 40, 80, 160, 320, 640, and 1280m |
335 | } | 195 | uint pqueue = 1; |
336 | return priority; | 196 | for (int i = 0; i < 8; i++) |
337 | } | 197 | { |
338 | else | 198 | if (distance < 10 * Math.Pow(2.0,i)) |
339 | { | 199 | break; |
340 | // Child agent. Use the normal distance method | 200 | pqueue++; |
341 | Vector3 presencePos = presence.AbsolutePosition; | 201 | } |
202 | |||
203 | // If this is a root agent, then determine front & back | ||
204 | // Bump up the priority queue (drop the priority) for any objects behind the avatar | ||
205 | if (useFrontBack && ! presence.IsChildAgent) | ||
206 | { | ||
207 | // Root agent, decrease priority for objects behind us | ||
208 | Vector3 camPosition = presence.CameraPosition; | ||
209 | Vector3 camAtAxis = presence.CameraAtAxis; | ||
342 | 210 | ||
343 | return Vector3.DistanceSquared(presencePos, entityPos); | 211 | // Plane equation |
344 | } | 212 | float d = -Vector3.Dot(camPosition, camAtAxis); |
213 | float p = Vector3.Dot(camAtAxis, entityPos) + d; | ||
214 | if (p < 0.0f) | ||
215 | pqueue++; | ||
345 | } | 216 | } |
346 | 217 | ||
347 | return double.NaN; | 218 | return pqueue; |
348 | } | 219 | } |
220 | |||
349 | } | 221 | } |
350 | } | 222 | } |