Fixed the prioritizer functions for the new priority queues

bulletsim
Mic Bowman 2011-04-04 13:19:45 -07:00
parent 77cf9405de
commit 0bd06d8ba8
1 changed files with 89 additions and 217 deletions

View File

@ -60,15 +60,6 @@ namespace OpenSim.Region.Framework.Scenes
{ {
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// 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.
/// </summary>
private double m_childPrimAdjustmentFactor = 0.05;
private Scene m_scene; private Scene m_scene;
public Prioritizer(Scene scene) public Prioritizer(Scene scene)
@ -76,9 +67,19 @@ namespace OpenSim.Region.Framework.Scenes
m_scene = scene; m_scene = scene;
} }
//<mic> /// <summary>
/// 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.
/// </summary>
public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity) public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity)
{ {
// If entity is null we have a serious problem
if (entity == null) if (entity == null)
{ {
m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity"); m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity");
@ -89,6 +90,78 @@ namespace OpenSim.Region.Framework.Scenes
if (client.AgentId == entity.UUID) if (client.AgentId == entity.UUID)
return 0; 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 // Get this agent's position
ScenePresence presence = m_scene.GetScenePresence(client.AgentId); ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
if (presence == null) if (presence == null)
@ -97,7 +170,10 @@ namespace OpenSim.Region.Framework.Scenes
throw new InvalidOperationException("Prioritization agent not defined"); 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; Vector3 entityPos = entity.AbsolutePosition;
if (entity is SceneObjectPart) if (entity is SceneObjectPart)
{ {
@ -125,8 +201,8 @@ namespace OpenSim.Region.Framework.Scenes
} }
// If this is a root agent, then determine front & back // If this is a root agent, then determine front & back
// Bump up the priority queue for any objects behind the avatar // Bump up the priority queue (drop the priority) for any objects behind the avatar
if (! presence.IsChildAgent) if (useFrontBack && ! presence.IsChildAgent)
{ {
// Root agent, decrease priority for objects behind us // Root agent, decrease priority for objects behind us
Vector3 camPosition = presence.CameraPosition; Vector3 camPosition = presence.CameraPosition;
@ -141,210 +217,6 @@ namespace OpenSim.Region.Framework.Scenes
return pqueue; return pqueue;
} }
//</mic>
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;
}
} }
} }