on per client terrain taint control replace bad 2d bool array by a bitarray. 1d bool could be another option. bitarray uses a lot less mem but a bit more cpu, except on full set/clear, less mem is also less cpu cache pressure so lets use it, specially on linear scans on X

This commit is contained in:
UbitUmarov
2020-09-08 21:58:38 +01:00
parent 4af5a217b3
commit 150ad80f6f

View File

@@ -25,6 +25,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
@@ -98,70 +99,89 @@ namespace OpenSim.Region.CoreModules.World.Terrain
// patch packet is queued to the client, the bit for that patch is set to 'false'.
private class PatchUpdates
{
private bool[,] updated; // for each patch, whether it needs to be sent to this client
private BitArray updated; // for each patch, whether it needs to be sent to this client
private int updateCount; // number of patches that need to be sent
public ScenePresence Presence; // a reference to the client to send to
public bool sendAll;
public int sendAllcurrentX;
public int sendAllcurrentY;
private int xsize;
private int ysize;
public PatchUpdates(TerrainData terrData, ScenePresence pPresence)
{
updated = new bool[terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize];
updateCount = 0;
xsize = terrData.SizeX / Constants.TerrainPatchSize;
ysize = terrData.SizeY / Constants.TerrainPatchSize;
updated = new BitArray(xsize * ysize, true);
updateCount = xsize * ysize;
Presence = pPresence;
// Initially, send all patches to the client
SetAll(true);
sendAll = true;
sendAllcurrentX = 0;
sendAllcurrentY = 0;
}
// Returns 'true' if there are any patches marked for sending
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public bool HasUpdates()
{
return (updateCount > 0);
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public void SetByXY(int x, int y, bool state)
{
this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state);
SetByPatch(x / Constants.TerrainPatchSize , y / Constants.TerrainPatchSize, state);
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public bool GetByPatch(int patchX, int patchY)
{
return updated[patchX, patchY];
return updated[patchX + xsize * patchY];
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public void SetByPatch(int patchX, int patchY, bool state)
{
bool prevState = updated[patchX, patchY];
if (!prevState && state)
updateCount++;
if (prevState && !state)
updateCount--;
updated[patchX, patchY] = state;
int indx = patchX + xsize * patchY;
bool prevState = updated[indx];
updated[indx] = state;
if (state)
{
if (!prevState)
updateCount++;
}
else
{
if (prevState)
updateCount--;
}
}
public void SetAll(bool state)
{
updateCount = 0;
for (int xx = 0; xx < updated.GetLength(0); xx++)
for (int yy = 0; yy < updated.GetLength(1); yy++)
updated[xx, yy] = state;
updated.SetAll(state);
if (state)
updateCount = updated.GetLength(0) * updated.GetLength(1);
{
sendAll = true;
updateCount = xsize * ysize;
}
else updateCount = 0;
sendAllcurrentX = 0;
sendAllcurrentY = 0;
sendAll = true;
}
// Logically OR's the terrain data's patch taint map into this client's update map.
public void SetAll(TerrainData terrData)
{
if (updated.GetLength(0) != (terrData.SizeX / Constants.TerrainPatchSize)
|| updated.GetLength(1) != (terrData.SizeY / Constants.TerrainPatchSize))
if (xsize != (terrData.SizeX / Constants.TerrainPatchSize)
|| ysize != (terrData.SizeY / Constants.TerrainPatchSize))
{
throw new Exception(
String.Format("{0} PatchUpdates.SetAll: patch array not same size as terrain. arr=<{1},{2}>, terr=<{3},{4}>",
LogHeader, updated.GetLength(0), updated.GetLength(1),
LogHeader, xsize, ysize,
terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize)
);
}
@@ -173,7 +193,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
// Only set tainted. The patch bit may be set if the patch was to be sent later.
if (terrData.IsTaintedAt(xx, yy, false))
{
this.SetByXY(xx, yy, true);
SetByXY(xx, yy, true);
}
}
}
@@ -1119,48 +1139,33 @@ namespace OpenSim.Region.CoreModules.World.Terrain
{
foreach (PatchUpdates pups in m_perClientPatchUpdates.Values)
{
if(pups.Presence.IsDeleted)
if(pups.Presence.IsDeleted || !pups.HasUpdates() || !pups.Presence.ControllingClient.CanSendLayerData())
continue;
// limit rate acording to udp land queue state
if (!pups.Presence.ControllingClient.CanSendLayerData())
continue;
if (pups.HasUpdates())
if (m_sendTerrainUpdatesByViewDistance)
{
if (m_sendTerrainUpdatesByViewDistance)
// There is something that could be sent to this client.
List<PatchesToSend> toSend = GetModifiedPatchesInViewDistance(pups);
if (toSend.Count > 0)
{
// There is something that could be sent to this client.
List<PatchesToSend> toSend = GetModifiedPatchesInViewDistance(pups);
if (toSend.Count > 0)
// m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}",
// LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName);
// Sort the patches to send by the distance from the presence
toSend.Sort();
int[] patchPieces = new int[toSend.Count * 2];
int pieceIndex = 0;
foreach (PatchesToSend pts in toSend)
{
// m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}",
// LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName);
// Sort the patches to send by the distance from the presence
toSend.Sort();
/*
foreach (PatchesToSend pts in toSend)
{
pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null);
// presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land);
}
*/
int[] patchPieces = new int[toSend.Count * 2];
int pieceIndex = 0;
foreach (PatchesToSend pts in toSend)
{
patchPieces[pieceIndex++] = pts.PatchX;
patchPieces[pieceIndex++] = pts.PatchY;
}
pups.Presence.ControllingClient.SendLayerData(patchPieces);
patchPieces[pieceIndex++] = pts.PatchX;
patchPieces[pieceIndex++] = pts.PatchY;
}
if (pups.sendAll && toSend.Count < 1024)
SendAllModifiedPatchs(pups);
pups.Presence.ControllingClient.SendLayerData(patchPieces);
}
else
if (pups.sendAll && toSend.Count < 1024)
SendAllModifiedPatchs(pups);
}
else
SendAllModifiedPatchs(pups);
}
}
}