diff --git a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
index e09f1a9613..1f340df1b1 100644
--- a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
@@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
{
public class DynamicTextureModule : IRegionModule, IDynamicTextureManager
{
-// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private const int ALL_SIDES = -1;
@@ -54,6 +54,17 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
///
public bool ReuseTextures { get; set; }
+ ///
+ /// If false, then textures which have a low data size are not reused when ReuseTextures = true.
+ ///
+ ///
+ /// LL viewers 3.3.4 and before appear to not fully render textures pulled from the viewer cache if those
+ /// textures have a relatively high pixel surface but a small data size. Typically, this appears to happen
+ /// if the data size is smaller than the viewer's discard level 2 size estimate. So if this is setting is
+ /// false, textures smaller than the calculation in IsSizeReuseable are always regenerated rather than reused
+ /// to work around this problem.
+ public bool ReuseLowDataTextures { get; set; }
+
private Dictionary RegisteredScenes = new Dictionary();
private Dictionary RenderPlugins =
@@ -83,18 +94,17 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
///
/// Called by code which actually renders the dynamic texture to supply texture data.
///
- ///
- ///
- /// True if the data generated can be reused for subsequent identical requests
- public void ReturnData(UUID id, byte[] data, bool isReuseable)
+ ///
+ ///
+ public void ReturnData(UUID updaterId, IDynamicTexture texture)
{
DynamicTextureUpdater updater = null;
lock (Updaters)
{
- if (Updaters.ContainsKey(id))
+ if (Updaters.ContainsKey(updaterId))
{
- updater = Updaters[id];
+ updater = Updaters[updaterId];
}
}
@@ -103,11 +113,16 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
if (RegisteredScenes.ContainsKey(updater.SimUUID))
{
Scene scene = RegisteredScenes[updater.SimUUID];
- UUID newTextureID = updater.DataReceived(data, scene);
+ UUID newTextureID = updater.DataReceived(texture.Data, scene);
- if (ReuseTextures && isReuseable && !updater.BlendWithOldTexture)
+ if (ReuseTextures
+ && !updater.BlendWithOldTexture
+ && texture.IsReuseable
+ && (ReuseLowDataTextures || IsDataSizeReuseable(texture)))
+ {
m_reuseableDynamicTextures.Store(
- GenerateReusableTextureKey(updater.BodyData, updater.Params), newTextureID);
+ GenerateReusableTextureKey(texture.InputCommands, texture.InputParams), newTextureID);
+ }
}
}
@@ -123,6 +138,27 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
}
}
+ ///
+ /// Determines whether the texture is reuseable based on its data size.
+ ///
+ ///
+ /// This is a workaround for a viewer bug where very small data size textures relative to their pixel size
+ /// are not redisplayed properly when pulled from cache. The calculation here is based on the typical discard
+ /// level of 2, a 'rate' of 0.125 and 4 components (which makes for a factor of 0.5).
+ ///
+ ///
+ private bool IsDataSizeReuseable(IDynamicTexture texture)
+ {
+// Console.WriteLine("{0} {1}", texture.Size.Width, texture.Size.Height);
+ int discardLevel2DataThreshold = (int)Math.Ceiling((texture.Size.Width >> 2) * (texture.Size.Height >> 2) * 0.5);
+
+// m_log.DebugFormat(
+// "[DYNAMIC TEXTURE MODULE]: Discard level 2 threshold {0}, texture data length {1}",
+// discardLevel2DataThreshold, texture.Data.Length);
+
+ return discardLevel2DataThreshold < texture.Data.Length;
+ }
+
public UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url,
string extraParams, int updateTimer)
{
@@ -293,7 +329,10 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
{
IConfig texturesConfig = config.Configs["Textures"];
if (texturesConfig != null)
+ {
ReuseTextures = texturesConfig.GetBoolean("ReuseDynamicTextures", false);
+ ReuseLowDataTextures = texturesConfig.GetBoolean("ReuseDynamicLowDataTextures", false);
+ }
if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID))
{
diff --git a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
index 2b3a0f29ff..45e652788a 100644
--- a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
@@ -32,6 +32,7 @@ using System.Net;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.Imaging;
+using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using log4net;
@@ -73,12 +74,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
// return false;
// }
- public byte[] ConvertUrl(string url, string extraParams)
+ public IDynamicTexture ConvertUrl(string url, string extraParams)
{
return null;
}
- public byte[] ConvertData(string bodyData, string extraParams)
+ public IDynamicTexture ConvertData(string bodyData, string extraParams)
{
return null;
}
@@ -171,11 +172,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
private void HttpRequestReturn(IAsyncResult result)
{
-
RequestState state = (RequestState) result.AsyncState;
WebRequest request = (WebRequest) state.Request;
Stream stream = null;
byte[] imageJ2000 = new byte[0];
+ Size newSize = new Size(0, 0);
try
{
@@ -188,37 +189,43 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
try
{
Bitmap image = new Bitmap(stream);
- Size newsize;
// TODO: make this a bit less hard coded
if ((image.Height < 64) && (image.Width < 64))
{
- newsize = new Size(32, 32);
+ newSize.Width = 32;
+ newSize.Height = 32;
}
else if ((image.Height < 128) && (image.Width < 128))
{
- newsize = new Size(64, 64);
+ newSize.Width = 64;
+ newSize.Height = 64;
}
else if ((image.Height < 256) && (image.Width < 256))
{
- newsize = new Size(128, 128);
+ newSize.Width = 128;
+ newSize.Height = 128;
}
else if ((image.Height < 512 && image.Width < 512))
{
- newsize = new Size(256, 256);
+ newSize.Width = 256;
+ newSize.Height = 256;
}
else if ((image.Height < 1024 && image.Width < 1024))
{
- newsize = new Size(512, 512);
+ newSize.Width = 512;
+ newSize.Height = 512;
}
else
{
- newsize = new Size(1024, 1024);
+ newSize.Width = 1024;
+ newSize.Height = 1024;
}
- Bitmap resize = new Bitmap(image, newsize);
-
- imageJ2000 = OpenJPEG.EncodeFromImage(resize, true);
+ using (Bitmap resize = new Bitmap(image, newSize))
+ {
+ imageJ2000 = OpenJPEG.EncodeFromImage(resize, true);
+ }
}
catch (Exception)
{
@@ -233,7 +240,6 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
}
catch (WebException)
{
-
}
finally
{
@@ -243,10 +249,13 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
}
}
- m_log.DebugFormat("[LOADIMAGEURLMODULE] Returning {0} bytes of image data for request {1}",
+ m_log.DebugFormat("[LOADIMAGEURLMODULE]: Returning {0} bytes of image data for request {1}",
imageJ2000.Length, state.RequestID);
- m_textureManager.ReturnData(state.RequestID, imageJ2000, false);
+ m_textureManager.ReturnData(
+ state.RequestID,
+ new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture(
+ request.RequestUri, null, imageJ2000, newSize, false));
}
#region Nested type: RequestState
diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs
index b50c0bd7cd..41bacccf9e 100644
--- a/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs
@@ -57,6 +57,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
m_dtm = new DynamicTextureModule();
m_dtm.ReuseTextures = reuseTextures;
+// m_dtm.ReuseLowDataTextures = reuseTextures;
m_vrm = new VectorRenderModule();
@@ -201,6 +202,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
public void TestRepeatSameDrawReusingTexture()
{
TestHelpers.InMethod();
+// TestHelpers.EnableLogging();
string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
@@ -228,6 +230,46 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
Assert.That(firstDynamicTextureID, Is.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
}
+ ///
+ /// Test a low data dynamically generated texture such that it is treated as a low data texture that causes
+ /// problems for current viewers.
+ ///
+ ///
+ /// As we do not set DynamicTextureModule.ReuseLowDataTextures = true in this test, it should not reuse the
+ /// texture
+ ///
+ [Test]
+ public void TestRepeatSameDrawLowDataTexture()
+ {
+ TestHelpers.InMethod();
+// TestHelpers.EnableLogging();
+
+ string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
+
+ SetupScene(true);
+ SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
+
+ m_dtm.AddDynamicTextureData(
+ m_scene.RegionInfo.RegionID,
+ so.UUID,
+ m_vrm.GetContentType(),
+ dtText,
+ "1024",
+ 0);
+
+ UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
+
+ m_dtm.AddDynamicTextureData(
+ m_scene.RegionInfo.RegionID,
+ so.UUID,
+ m_vrm.GetContentType(),
+ dtText,
+ "1024",
+ 0);
+
+ Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
+ }
+
[Test]
public void TestRepeatSameDrawDifferentExtraParamsReusingTexture()
{
diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
index 0e7051ee0d..d82551efe7 100644
--- a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
@@ -35,6 +35,7 @@ using System.Net;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.Imaging;
+using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using log4net;
@@ -85,20 +86,14 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
// return lines.Any((str, r) => str.StartsWith("Image"));
// }
- public byte[] ConvertUrl(string url, string extraParams)
+ public IDynamicTexture ConvertUrl(string url, string extraParams)
{
return null;
}
- public byte[] ConvertData(string bodyData, string extraParams)
+ public IDynamicTexture ConvertData(string bodyData, string extraParams)
{
- bool reuseable;
- return Draw(bodyData, extraParams, out reuseable);
- }
-
- private byte[] ConvertData(string bodyData, string extraParams, out bool reuseable)
- {
- return Draw(bodyData, extraParams, out reuseable);
+ return Draw(bodyData, extraParams);
}
public bool AsyncConvertUrl(UUID id, string url, string extraParams)
@@ -109,10 +104,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
public bool AsyncConvertData(UUID id, string bodyData, string extraParams)
{
// XXX: This isn't actually being done asynchronously!
- bool reuseable;
- byte[] data = ConvertData(bodyData, extraParams, out reuseable);
-
- m_textureManager.ReturnData(id, data, reuseable);
+ m_textureManager.ReturnData(id, ConvertData(bodyData, extraParams));
return true;
}
@@ -191,7 +183,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
#endregion
- private byte[] Draw(string data, string extraParams, out bool reuseable)
+ private IDynamicTexture Draw(string data, string extraParams)
{
// We need to cater for old scripts that didnt use extraParams neatly, they use either an integer size which represents both width and height, or setalpha
// we will now support multiple comma seperated params in the form width:256,height:512,alpha:255
@@ -334,6 +326,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
Bitmap bitmap = null;
Graphics graph = null;
+ bool reuseable = false;
try
{
@@ -396,7 +389,8 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
e.Message, e.StackTrace);
}
- return imageJ2000;
+ return new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture(
+ data, extraParams, imageJ2000, new Size(width, height), reuseable);
}
finally
{
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
index b286d172e4..57ae5497ee 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
@@ -43,7 +43,7 @@ using OpenSim.Tests.Common;
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
{
[TestFixture]
- public class GridConnectorsTests
+ public class GridConnectorsTests : OpenSimTestCase
{
LocalGridServicesConnector m_LocalConnector;
private void SetUp()
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
index 5deaf5264b..904110e457 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
@@ -51,7 +51,7 @@ using RegionSettings = OpenSim.Framework.RegionSettings;
namespace OpenSim.Region.CoreModules.World.Archiver.Tests
{
[TestFixture]
- public class ArchiverTests
+ public class ArchiverTests : OpenSimTestCase
{
private Guid m_lastRequestId;
private string m_lastErrorMessage;
diff --git a/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs b/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs
index 1a3bcbbc71..6df5cc2ac5 100644
--- a/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs
+++ b/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs
@@ -25,6 +25,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+using System;
+using System.Drawing;
using System.IO;
using OpenMetaverse;
@@ -33,7 +35,14 @@ namespace OpenSim.Region.Framework.Interfaces
public interface IDynamicTextureManager
{
void RegisterRender(string handleType, IDynamicTextureRender render);
- void ReturnData(UUID id, byte[] data, bool isReuseable);
+
+ ///
+ /// Used by IDynamicTextureRender implementations to return renders
+ ///
+ ///
+ ///
+ ///
+ void ReturnData(UUID id, IDynamicTexture texture);
UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, string extraParams,
int updateTimer);
@@ -125,11 +134,53 @@ namespace OpenSim.Region.Framework.Interfaces
// ///
// bool AlwaysIdenticalConversion(string bodyData, string extraParams);
- byte[] ConvertUrl(string url, string extraParams);
- byte[] ConvertData(string bodyData, string extraParams);
+ IDynamicTexture ConvertUrl(string url, string extraParams);
+ IDynamicTexture ConvertData(string bodyData, string extraParams);
+
bool AsyncConvertUrl(UUID id, string url, string extraParams);
bool AsyncConvertData(UUID id, string bodyData, string extraParams);
+
void GetDrawStringSize(string text, string fontName, int fontSize,
out double xSize, out double ySize);
}
+
+ public interface IDynamicTexture
+ {
+ ///
+ /// Input commands used to generate this data.
+ ///
+ ///
+ /// Null if input commands were not used.
+ ///
+ string InputCommands { get; }
+
+ ///
+ /// Uri used to generate this data.
+ ///
+ ///
+ /// Null if a uri was not used.
+ ///
+ Uri InputUri { get; }
+
+ ///
+ /// Extra input params used to generate this data.
+ ///
+ string InputParams { get; }
+
+ ///
+ /// Texture data.
+ ///
+ byte[] Data { get; }
+
+ ///
+ /// Size of texture.
+ ///
+ Size Size { get; }
+
+ ///
+ /// Signal whether the texture is reuseable (i.e. whether the same input data will always generate the same
+ /// texture).
+ ///
+ bool IsReuseable { get; }
+ }
}
diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini
index ac75d63da8..dc72bf9c47 100644
--- a/bin/OpenSimDefaults.ini
+++ b/bin/OpenSimDefaults.ini
@@ -703,6 +703,13 @@
; Default is false.
ReuseDynamicTextures = false
+ ; If true, then textures generated dynamically that have a low data size relative to their pixel size are not reused
+ ; This is to workaround an apparent LL 3.3.4 and earlier viewer bug where such textures are not redisplayed properly when pulled from the viewer cache.
+ ; Only set this to true if you are sure that all the viewers using your simulator will not suffer from this problem.
+ ; This setting only has an affect is ReuseDynamicTextures = true
+ ; Default is false
+ ReuseDynamicLowDataTextures = false
+
[ODEPhysicsSettings]
; ##