diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/Prioritizer.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/Prioritizer.cs | 250 |
1 files changed, 95 insertions, 155 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index f9599f5..4694e2b 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs | |||
@@ -58,17 +58,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
58 | 58 | ||
59 | public class Prioritizer | 59 | public class Prioritizer |
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,17 +67,35 @@ namespace OpenSim.Region.Framework.Scenes | |||
76 | m_scene = scene; | 67 | m_scene = scene; |
77 | } | 68 | } |
78 | 69 | ||
79 | public double GetUpdatePriority(IClientAPI client, ISceneEntity entity) | 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 | { | 81 | { |
81 | double priority = 0; | 82 | // If entity is null we have a serious problem |
82 | |||
83 | if (entity == null) | 83 | if (entity == null) |
84 | return 100000; | 84 | { |
85 | m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity"); | ||
86 | throw new InvalidOperationException("Prioritization entity not defined"); | ||
87 | } | ||
88 | |||
89 | // If this is an update for our own avatar give it the highest priority | ||
90 | if (client.AgentId == entity.UUID) | ||
91 | return 0; | ||
92 | |||
93 | uint priority; | ||
85 | 94 | ||
86 | switch (m_scene.UpdatePrioritizationScheme) | 95 | switch (m_scene.UpdatePrioritizationScheme) |
87 | { | 96 | { |
88 | case UpdatePrioritizationSchemes.Time: | 97 | case UpdatePrioritizationSchemes.Time: |
89 | priority = GetPriorityByTime(); | 98 | priority = GetPriorityByTime(client, entity); |
90 | break; | 99 | break; |
91 | case UpdatePrioritizationSchemes.Distance: | 100 | case UpdatePrioritizationSchemes.Distance: |
92 | priority = GetPriorityByDistance(client, entity); | 101 | priority = GetPriorityByDistance(client, entity); |
@@ -104,180 +113,111 @@ namespace OpenSim.Region.Framework.Scenes | |||
104 | throw new InvalidOperationException("UpdatePrioritizationScheme not defined."); | 113 | throw new InvalidOperationException("UpdatePrioritizationScheme not defined."); |
105 | } | 114 | } |
106 | 115 | ||
107 | // Adjust priority so that root prims are sent to the viewer first. This is especially important for | ||
108 | // attachments acting as huds, since current viewers fail to display hud child prims if their updates | ||
109 | // arrive before the root one. | ||
110 | if (entity is SceneObjectPart) | ||
111 | { | ||
112 | SceneObjectPart sop = ((SceneObjectPart)entity); | ||
113 | |||
114 | if (sop.IsRoot) | ||
115 | { | ||
116 | if (priority >= double.MinValue + m_childPrimAdjustmentFactor) | ||
117 | priority -= m_childPrimAdjustmentFactor; | ||
118 | } | ||
119 | else | ||
120 | { | ||
121 | if (priority <= double.MaxValue - m_childPrimAdjustmentFactor) | ||
122 | priority += m_childPrimAdjustmentFactor; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | return priority; | 116 | return priority; |
127 | } | 117 | } |
128 | 118 | ||
129 | private double GetPriorityByTime() | 119 | |
120 | private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity) | ||
130 | { | 121 | { |
131 | return DateTime.UtcNow.ToOADate(); | 122 | return 1; |
132 | } | 123 | } |
133 | 124 | ||
134 | private double GetPriorityByDistance(IClientAPI client, ISceneEntity entity) | 125 | private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity) |
135 | { | 126 | { |
136 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); | 127 | return ComputeDistancePriority(client,entity,false); |
137 | if (presence != null) | 128 | } |
138 | { | 129 | |
139 | // If this is an update for our own avatar give it the highest priority | 130 | private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) |
140 | if (presence == entity) | 131 | { |
141 | return 0.0; | 132 | return ComputeDistancePriority(client,entity,true); |
142 | |||
143 | // Use the camera position for local agents and avatar position for remote agents | ||
144 | Vector3 presencePos = (presence.IsChildAgent) ? | ||
145 | presence.AbsolutePosition : | ||
146 | presence.CameraPosition; | ||
147 | |||
148 | // Use group position for child prims | ||
149 | Vector3 entityPos; | ||
150 | if (entity is SceneObjectPart) | ||
151 | { | ||
152 | // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene | ||
153 | // before its scheduled update was triggered | ||
154 | //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; | ||
155 | entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition; | ||
156 | } | ||
157 | else | ||
158 | { | ||
159 | entityPos = entity.AbsolutePosition; | ||
160 | } | ||
161 | |||
162 | return Vector3.DistanceSquared(presencePos, entityPos); | ||
163 | } | ||
164 | |||
165 | return double.NaN; | ||
166 | } | 133 | } |
167 | 134 | ||
168 | private double GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) | 135 | private uint GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) |
169 | { | 136 | { |
137 | uint pqueue = ComputeDistancePriority(client,entity,true); | ||
138 | |||
170 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); | 139 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); |
171 | if (presence != null) | 140 | if (presence != null) |
172 | { | 141 | { |
173 | // If this is an update for our own avatar give it the highest priority | ||
174 | if (presence == entity) | ||
175 | return 0.0; | ||
176 | |||
177 | // Use group position for child prims | ||
178 | Vector3 entityPos = entity.AbsolutePosition; | ||
179 | if (entity is SceneObjectPart) | ||
180 | { | ||
181 | // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene | ||
182 | // before its scheduled update was triggered | ||
183 | //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; | ||
184 | entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition; | ||
185 | } | ||
186 | else | ||
187 | { | ||
188 | entityPos = entity.AbsolutePosition; | ||
189 | } | ||
190 | |||
191 | if (!presence.IsChildAgent) | 142 | if (!presence.IsChildAgent) |
192 | { | 143 | { |
193 | // Root agent. Use distance from camera and a priority decrease for objects behind us | 144 | if (entity is SceneObjectPart) |
194 | Vector3 camPosition = presence.CameraPosition; | 145 | { |
195 | Vector3 camAtAxis = presence.CameraAtAxis; | 146 | // Non physical prims are lower priority than physical prims |
196 | 147 | PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; | |
197 | // Distance | 148 | if (physActor == null || !physActor.IsPhysical) |
198 | double priority = Vector3.DistanceSquared(camPosition, entityPos); | 149 | pqueue++; |
199 | |||
200 | // Plane equation | ||
201 | float d = -Vector3.Dot(camPosition, camAtAxis); | ||
202 | float p = Vector3.Dot(camAtAxis, entityPos) + d; | ||
203 | if (p < 0.0f) priority *= 2.0; | ||
204 | |||
205 | return priority; | ||
206 | } | ||
207 | else | ||
208 | { | ||
209 | // Child agent. Use the normal distance method | ||
210 | Vector3 presencePos = presence.AbsolutePosition; | ||
211 | 150 | ||
212 | 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 | } | ||
213 | } | 157 | } |
214 | } | 158 | } |
215 | 159 | ||
216 | return double.NaN; | 160 | return pqueue; |
217 | } | 161 | } |
218 | 162 | ||
219 | private double GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) | 163 | private uint ComputeDistancePriority(IClientAPI client, ISceneEntity entity, bool useFrontBack) |
220 | { | 164 | { |
221 | // If this is an update for our own avatar give it the highest priority | 165 | // Get this agent's position |
222 | if (client.AgentId == entity.UUID) | 166 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); |
223 | return 0.0; | 167 | if (presence == null) |
224 | if (entity == null) | 168 | { |
225 | return double.NaN; | 169 | m_log.WarnFormat("[PRIORITIZER] attempt to use agent {0} not in the scene",client.AgentId); |
226 | 170 | // throw new InvalidOperationException("Prioritization agent not defined"); | |
227 | // Use group position for child prims | 171 | return Int32.MaxValue; |
172 | } | ||
173 | |||
174 | // Use group position for child prims, since we are putting child prims in | ||
175 | // the same queue with the root of the group, the root prim (which goes into | ||
176 | // the queue first) should always be sent first, no need to adjust child prim | ||
177 | // priorities | ||
228 | Vector3 entityPos = entity.AbsolutePosition; | 178 | Vector3 entityPos = entity.AbsolutePosition; |
229 | if (entity is SceneObjectPart) | 179 | if (entity is SceneObjectPart) |
230 | { | 180 | { |
231 | SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; | 181 | SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; |
232 | if (group != null) | 182 | if (group != null) |
233 | entityPos = group.AbsolutePosition; | 183 | entityPos = group.AbsolutePosition; |
234 | else | ||
235 | entityPos = entity.AbsolutePosition; | ||
236 | } | 184 | } |
237 | else | ||
238 | entityPos = entity.AbsolutePosition; | ||
239 | 185 | ||
240 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); | 186 | // Use the camera position for local agents and avatar position for remote agents |
241 | if (presence != null) | 187 | Vector3 presencePos = (presence.IsChildAgent) ? |
242 | { | 188 | presence.AbsolutePosition : |
243 | if (!presence.IsChildAgent) | 189 | presence.CameraPosition; |
244 | { | ||
245 | if (entity is ScenePresence) | ||
246 | return 1.0; | ||
247 | |||
248 | // Root agent. Use distance from camera and a priority decrease for objects behind us | ||
249 | Vector3 camPosition = presence.CameraPosition; | ||
250 | Vector3 camAtAxis = presence.CameraAtAxis; | ||
251 | 190 | ||
252 | // Distance | 191 | // Compute the distance... |
253 | double priority = Vector3.DistanceSquared(camPosition, entityPos); | 192 | double distance = Vector3.Distance(presencePos, entityPos); |
254 | 193 | ||
255 | // Plane equation | 194 | // And convert the distance to a priority queue, this computation gives queues |
256 | float d = -Vector3.Dot(camPosition, camAtAxis); | 195 | // at 10, 20, 40, 80, 160, 320, 640, and 1280m |
257 | float p = Vector3.Dot(camAtAxis, entityPos) + d; | 196 | uint pqueue = 1; |
258 | if (p < 0.0f) priority *= 2.0; | 197 | for (int i = 0; i < 8; i++) |
259 | 198 | { | |
260 | if (entity is SceneObjectPart) | 199 | if (distance < 10 * Math.Pow(2.0,i)) |
261 | { | 200 | break; |
262 | PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; | 201 | pqueue++; |
263 | if (physActor == null || !physActor.IsPhysical) | 202 | } |
264 | priority += 100; | 203 | |
265 | 204 | // If this is a root agent, then determine front & back | |
266 | if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) | 205 | // Bump up the priority queue (drop the priority) for any objects behind the avatar |
267 | priority = 1.0; | 206 | if (useFrontBack && ! presence.IsChildAgent) |
268 | } | 207 | { |
269 | return priority; | 208 | // Root agent, decrease priority for objects behind us |
270 | } | 209 | Vector3 camPosition = presence.CameraPosition; |
271 | else | 210 | Vector3 camAtAxis = presence.CameraAtAxis; |
272 | { | 211 | |
273 | // Child agent. Use the normal distance method | 212 | // Plane equation |
274 | Vector3 presencePos = presence.AbsolutePosition; | 213 | float d = -Vector3.Dot(camPosition, camAtAxis); |
275 | 214 | float p = Vector3.Dot(camAtAxis, entityPos) + d; | |
276 | return Vector3.DistanceSquared(presencePos, entityPos); | 215 | if (p < 0.0f) |
277 | } | 216 | pqueue++; |
278 | } | 217 | } |
279 | 218 | ||
280 | return double.NaN; | 219 | return pqueue; |
281 | } | 220 | } |
221 | |||
282 | } | 222 | } |
283 | } | 223 | } |