diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/Prioritizer.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/Prioritizer.cs | 264 |
1 files changed, 105 insertions, 159 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index cde8d3f..cd6dc95 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,182 +113,119 @@ 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 | { |
170 | if (entity == null) return double.NaN; | 137 | if (entity == null) return 0; |
138 | |||
139 | uint pqueue = ComputeDistancePriority(client,entity,true); | ||
140 | |||
171 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); | 141 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); |
172 | if (presence != null) | 142 | if (presence != null) |
173 | { | 143 | { |
174 | // If this is an update for our own avatar give it the highest priority | ||
175 | if (presence == entity) | ||
176 | return 0.0; | ||
177 | |||
178 | // Use group position for child prims | ||
179 | Vector3 entityPos = entity.AbsolutePosition; | ||
180 | if (entity is SceneObjectPart) | ||
181 | { | ||
182 | // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene | ||
183 | // before its scheduled update was triggered | ||
184 | //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; | ||
185 | entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition; | ||
186 | } | ||
187 | else | ||
188 | { | ||
189 | entityPos = entity.AbsolutePosition; | ||
190 | } | ||
191 | |||
192 | if (!presence.IsChildAgent) | 144 | if (!presence.IsChildAgent) |
193 | { | 145 | { |
194 | // Root agent. Use distance from camera and a priority decrease for objects behind us | 146 | if (entity is SceneObjectPart) |
195 | Vector3 camPosition = presence.CameraPosition; | 147 | { |
196 | Vector3 camAtAxis = presence.CameraAtAxis; | 148 | // Non physical prims are lower priority than physical prims |
197 | 149 | PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; | |
198 | // Distance | 150 | if (physActor == null || !physActor.IsPhysical) |
199 | double priority = Vector3.DistanceSquared(camPosition, entityPos); | 151 | pqueue++; |
200 | 152 | ||
201 | // Plane equation | 153 | // Attachments are high priority, |
202 | float d = -Vector3.Dot(camPosition, camAtAxis); | 154 | // MIC: shouldn't these already be in the highest priority queue already |
203 | float p = Vector3.Dot(camAtAxis, entityPos) + d; | 155 | // since their root position is same as the avatars? |
204 | if (p < 0.0f) priority *= 2.0; | 156 | if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) |
205 | 157 | pqueue = 1; | |
206 | return priority; | 158 | } |
207 | } | ||
208 | else | ||
209 | { | ||
210 | // Child agent. Use the normal distance method | ||
211 | Vector3 presencePos = presence.AbsolutePosition; | ||
212 | |||
213 | return Vector3.DistanceSquared(presencePos, entityPos); | ||
214 | } | 159 | } |
215 | } | 160 | } |
216 | 161 | ||
217 | return double.NaN; | 162 | return pqueue; |
218 | } | 163 | } |
219 | 164 | ||
220 | private double GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) | 165 | private uint ComputeDistancePriority(IClientAPI client, ISceneEntity entity, bool useFrontBack) |
221 | { | 166 | { |
222 | // If this is an update for our own avatar give it the highest priority | 167 | // If this is an update for our own avatar give it the highest priority |
223 | if (client.AgentId == entity.UUID) | 168 | if (client.AgentId == entity.UUID) |
224 | return 0.0; | 169 | return 0; |
225 | if (entity == null) | 170 | if (entity == null) |
226 | return double.NaN; | 171 | return 0; |
227 | 172 | ||
173 | // Get this agent's position | ||
228 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); | 174 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); |
229 | if (presence != null) | 175 | if (presence == null) |
230 | { | 176 | { |
231 | // Use group position for child prims | 177 | m_log.WarnFormat("[PRIORITIZER] attempt to use agent {0} not in the scene",client.AgentId); |
232 | Vector3 entityPos; | 178 | // throw new InvalidOperationException("Prioritization agent not defined"); |
233 | if (entity is SceneObjectPart) | 179 | return Int32.MaxValue; |
234 | entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition; | 180 | } |
235 | else | 181 | |
236 | entityPos = entity.AbsolutePosition; | 182 | // Use group position for child prims, since we are putting child prims in |
237 | 183 | // the same queue with the root of the group, the root prim (which goes into | |
238 | if (!presence.IsChildAgent) | 184 | // the queue first) should always be sent first, no need to adjust child prim |
239 | { | 185 | // priorities |
240 | if (entity is ScenePresence) | 186 | Vector3 entityPos = entity.AbsolutePosition; |
241 | return 1.0; | 187 | if (entity is SceneObjectPart) |
242 | 188 | { | |
243 | // Root agent. Use distance from camera and a priority decrease for objects behind us | 189 | SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; |
244 | Vector3 camPosition = presence.CameraPosition; | 190 | if (group != null) |
245 | Vector3 camAtAxis = presence.CameraAtAxis; | 191 | entityPos = group.AbsolutePosition; |
246 | 192 | } | |
247 | // Distance | ||
248 | double priority = Vector3.DistanceSquared(camPosition, entityPos); | ||
249 | |||
250 | // Plane equation | ||
251 | float d = -Vector3.Dot(camPosition, camAtAxis); | ||
252 | float p = Vector3.Dot(camAtAxis, entityPos) + d; | ||
253 | if (p < 0.0f) priority *= 2.0; | ||
254 | 193 | ||
255 | if (entity is SceneObjectPart) | 194 | // Use the camera position for local agents and avatar position for remote agents |
256 | { | 195 | Vector3 presencePos = (presence.IsChildAgent) ? |
257 | if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) | 196 | presence.AbsolutePosition : |
258 | { | 197 | presence.CameraPosition; |
259 | priority = 1.0; | ||
260 | } | ||
261 | else | ||
262 | { | ||
263 | PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; | ||
264 | if (physActor == null || !physActor.IsPhysical) | ||
265 | priority += 100; | ||
266 | } | ||
267 | 198 | ||
268 | if (((SceneObjectPart)entity).ParentGroup.RootPart != (SceneObjectPart)entity) | 199 | // Compute the distance... |
269 | priority +=1; | 200 | double distance = Vector3.Distance(presencePos, entityPos); |
270 | } | ||
271 | return priority; | ||
272 | } | ||
273 | else | ||
274 | { | ||
275 | // Child agent. Use the normal distance method | ||
276 | Vector3 presencePos = presence.AbsolutePosition; | ||
277 | 201 | ||
278 | return Vector3.DistanceSquared(presencePos, entityPos); | 202 | // And convert the distance to a priority queue, this computation gives queues |
279 | } | 203 | // at 10, 20, 40, 80, 160, 320, 640, and 1280m |
204 | uint pqueue = 1; | ||
205 | for (int i = 0; i < 8; i++) | ||
206 | { | ||
207 | if (distance < 10 * Math.Pow(2.0,i)) | ||
208 | break; | ||
209 | pqueue++; | ||
210 | } | ||
211 | |||
212 | // If this is a root agent, then determine front & back | ||
213 | // Bump up the priority queue (drop the priority) for any objects behind the avatar | ||
214 | if (useFrontBack && ! presence.IsChildAgent) | ||
215 | { | ||
216 | // Root agent, decrease priority for objects behind us | ||
217 | Vector3 camPosition = presence.CameraPosition; | ||
218 | Vector3 camAtAxis = presence.CameraAtAxis; | ||
219 | |||
220 | // Plane equation | ||
221 | float d = -Vector3.Dot(camPosition, camAtAxis); | ||
222 | float p = Vector3.Dot(camAtAxis, entityPos) + d; | ||
223 | if (p < 0.0f) | ||
224 | pqueue++; | ||
280 | } | 225 | } |
281 | 226 | ||
282 | return double.NaN; | 227 | return pqueue; |
283 | } | 228 | } |
229 | |||
284 | } | 230 | } |
285 | } | 231 | } |