diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index 2764b05f1a..a14bb7001c 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs @@ -60,15 +60,6 @@ namespace OpenSim.Region.Framework.Scenes { private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - /// - /// This is added to the priority of all child prims, to make sure that the root prim update is sent to the - /// viewer before child prim updates. - /// The adjustment is added to child prims and subtracted from root prims, so the gap ends up - /// being double. We do it both ways so that there is a still a priority delta even if the priority is already - /// double.MinValue or double.MaxValue. - /// - private double m_childPrimAdjustmentFactor = 0.05; - private Scene m_scene; public Prioritizer(Scene scene) @@ -76,9 +67,19 @@ namespace OpenSim.Region.Framework.Scenes m_scene = scene; } -// + /// + /// Returns the priority queue into which the update should be placed. Updates within a + /// queue will be processed in arrival order. There are currently 12 priority queues + /// implemented in PriorityQueue class in LLClientView. Queue 0 is generally retained + /// for avatar updates. The fair queuing discipline for processing the priority queues + /// assumes that the number of entities in each priority queues increases exponentially. + /// So for example... if queue 1 contains all updates within 10m of the avatar or camera + /// then queue 2 at 20m is about 3X bigger in space & about 3X bigger in total number + /// of updates. + /// public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity) { + // If entity is null we have a serious problem if (entity == null) { m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity"); @@ -89,6 +90,78 @@ namespace OpenSim.Region.Framework.Scenes if (client.AgentId == entity.UUID) return 0; + uint priority; + + switch (m_scene.UpdatePrioritizationScheme) + { + case UpdatePrioritizationSchemes.Time: + priority = GetPriorityByTime(client, entity); + break; + case UpdatePrioritizationSchemes.Distance: + priority = GetPriorityByDistance(client, entity); + break; + case UpdatePrioritizationSchemes.SimpleAngularDistance: + priority = GetPriorityByDistance(client, entity); // TODO: Reimplement SimpleAngularDistance + break; + case UpdatePrioritizationSchemes.FrontBack: + priority = GetPriorityByFrontBack(client, entity); + break; + case UpdatePrioritizationSchemes.BestAvatarResponsiveness: + priority = GetPriorityByBestAvatarResponsiveness(client, entity); + break; + default: + throw new InvalidOperationException("UpdatePrioritizationScheme not defined."); + } + + return priority; + } + + + private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity) + { + return 1; + } + + private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity) + { + return ComputeDistancePriority(client,entity,false); + } + + private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) + { + return ComputeDistancePriority(client,entity,true); + } + + private uint GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) + { + uint pqueue = ComputeDistancePriority(client,entity,true); + + ScenePresence presence = m_scene.GetScenePresence(client.AgentId); + if (presence != null) + { + if (!presence.IsChildAgent) + { + if (entity is SceneObjectPart) + { + // Non physical prims are lower priority than physical prims + PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; + if (physActor == null || !physActor.IsPhysical) + pqueue++; + + // Attachments are high priority, + // MIC: shouldn't these already be in the highest priority queue already + // since their root position is same as the avatars? + if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) + pqueue = 1; + } + } + } + + return pqueue; + } + + private uint ComputeDistancePriority(IClientAPI client, ISceneEntity entity, bool useFrontBack) + { // Get this agent's position ScenePresence presence = m_scene.GetScenePresence(client.AgentId); if (presence == null) @@ -97,7 +170,10 @@ namespace OpenSim.Region.Framework.Scenes throw new InvalidOperationException("Prioritization agent not defined"); } - // Use group position for child prims + // Use group position for child prims, since we are putting child prims in + // the same queue with the root of the group, the root prim (which goes into + // the queue first) should always be sent first, no need to adjust child prim + // priorities Vector3 entityPos = entity.AbsolutePosition; if (entity is SceneObjectPart) { @@ -125,8 +201,8 @@ namespace OpenSim.Region.Framework.Scenes } // If this is a root agent, then determine front & back - // Bump up the priority queue for any objects behind the avatar - if (! presence.IsChildAgent) + // Bump up the priority queue (drop the priority) for any objects behind the avatar + if (useFrontBack && ! presence.IsChildAgent) { // Root agent, decrease priority for objects behind us Vector3 camPosition = presence.CameraPosition; @@ -141,210 +217,6 @@ namespace OpenSim.Region.Framework.Scenes return pqueue; } -// - public double bGetUpdatePriority(IClientAPI client, ISceneEntity entity) - { - double priority = 0; - - if (entity == null) - return 100000; - - switch (m_scene.UpdatePrioritizationScheme) - { - case UpdatePrioritizationSchemes.Time: - priority = GetPriorityByTime(); - break; - case UpdatePrioritizationSchemes.Distance: - priority = GetPriorityByDistance(client, entity); - break; - case UpdatePrioritizationSchemes.SimpleAngularDistance: - priority = GetPriorityByDistance(client, entity); // TODO: Reimplement SimpleAngularDistance - break; - case UpdatePrioritizationSchemes.FrontBack: - priority = GetPriorityByFrontBack(client, entity); - break; - case UpdatePrioritizationSchemes.BestAvatarResponsiveness: - priority = GetPriorityByBestAvatarResponsiveness(client, entity); - break; - default: - throw new InvalidOperationException("UpdatePrioritizationScheme not defined."); - } - - // Adjust priority so that root prims are sent to the viewer first. This is especially important for - // attachments acting as huds, since current viewers fail to display hud child prims if their updates - // arrive before the root one. - if (entity is SceneObjectPart) - { - SceneObjectPart sop = ((SceneObjectPart)entity); - - if (sop.IsRoot) - { - if (priority >= double.MinValue + m_childPrimAdjustmentFactor) - priority -= m_childPrimAdjustmentFactor; - } - else - { - if (priority <= double.MaxValue - m_childPrimAdjustmentFactor) - priority += m_childPrimAdjustmentFactor; - } - } - - return priority; - } - - private double GetPriorityByTime() - { - return DateTime.UtcNow.ToOADate(); - } - - private double GetPriorityByDistance(IClientAPI client, ISceneEntity entity) - { - ScenePresence presence = m_scene.GetScenePresence(client.AgentId); - if (presence != null) - { - // If this is an update for our own avatar give it the highest priority - if (presence == entity) - return 0.0; - - // Use the camera position for local agents and avatar position for remote agents - Vector3 presencePos = (presence.IsChildAgent) ? - presence.AbsolutePosition : - presence.CameraPosition; - - // Use group position for child prims - Vector3 entityPos; - if (entity is SceneObjectPart) - { - // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene - // before its scheduled update was triggered - //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; - entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition; - } - else - { - entityPos = entity.AbsolutePosition; - } - - return Vector3.DistanceSquared(presencePos, entityPos); - } - - return double.NaN; - } - - private double GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) - { - ScenePresence presence = m_scene.GetScenePresence(client.AgentId); - if (presence != null) - { - // If this is an update for our own avatar give it the highest priority - if (presence == entity) - return 0.0; - - // Use group position for child prims - Vector3 entityPos = entity.AbsolutePosition; - if (entity is SceneObjectPart) - { - // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene - // before its scheduled update was triggered - //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; - entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition; - } - else - { - entityPos = entity.AbsolutePosition; - } - - if (!presence.IsChildAgent) - { - // Root agent. Use distance from camera and a priority decrease for objects behind us - Vector3 camPosition = presence.CameraPosition; - Vector3 camAtAxis = presence.CameraAtAxis; - - // Distance - double priority = Vector3.DistanceSquared(camPosition, entityPos); - - // Plane equation - float d = -Vector3.Dot(camPosition, camAtAxis); - float p = Vector3.Dot(camAtAxis, entityPos) + d; - if (p < 0.0f) priority *= 2.0; - - return priority; - } - else - { - // Child agent. Use the normal distance method - Vector3 presencePos = presence.AbsolutePosition; - - return Vector3.DistanceSquared(presencePos, entityPos); - } - } - - return double.NaN; - } - - private double GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) - { - // If this is an update for our own avatar give it the highest priority - if (client.AgentId == entity.UUID) - return 0.0; - if (entity == null) - return double.NaN; - - // Use group position for child prims - Vector3 entityPos = entity.AbsolutePosition; - if (entity is SceneObjectPart) - { - SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; - if (group != null) - entityPos = group.AbsolutePosition; - else - entityPos = entity.AbsolutePosition; - } - else - entityPos = entity.AbsolutePosition; - - ScenePresence presence = m_scene.GetScenePresence(client.AgentId); - if (presence != null) - { - if (!presence.IsChildAgent) - { - if (entity is ScenePresence) - return 1.0; - - // Root agent. Use distance from camera and a priority decrease for objects behind us - Vector3 camPosition = presence.CameraPosition; - Vector3 camAtAxis = presence.CameraAtAxis; - - // Distance - double priority = Vector3.DistanceSquared(camPosition, entityPos); - - // Plane equation - float d = -Vector3.Dot(camPosition, camAtAxis); - float p = Vector3.Dot(camAtAxis, entityPos) + d; - if (p < 0.0f) priority *= 2.0; - - if (entity is SceneObjectPart) - { - PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; - if (physActor == null || !physActor.IsPhysical) - priority += 100; - - if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) - priority = 1.0; - } - return priority; - } - else - { - // Child agent. Use the normal distance method - Vector3 presencePos = presence.AbsolutePosition; - - return Vector3.DistanceSquared(presencePos, entityPos); - } - } - - return double.NaN; - } } }