aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/Prioritizer.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Framework/Scenes/Prioritizer.cs264
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}