Is the ResourceCache known to be buggy?


#1

Using SharpReality/C#, running on Hololens.

Have been working a lot with this sample, and about every other launch, there is an exception thrown when working with the ResourceCache on the fly.

So if running in a loop, code like this frequently throws an exception:

earthModel.SetMaterial(ResourceCache.GetMaterial($"Sample43/Mat{material}.xml", sendEventOnFailure: false));

However, if I pre-populate the ResourceCache with code like this:

            var materials = new string[,]
            {
                { "NoTexture", "NoTextureUnlit", "NoTextureNormal", "NoTextureAdd", "NoTextureMultiply" },
                { "Diff", "DiffUnlit", "DiffNormal", "DiffAlpha", "DiffAdd" },
                { "DiffEmissive", "DiffSpec", "DiffNormalSpec", "DiffAO", "DiffEnvCube" },
                { "Water", "Terrain", "NoTextureVCol", "Default", "CustomShader" },
            };

            for (int i = 0; i < materials.GetLength(1); i++)
                for (int j = 0; j < materials.GetLength(0); j++)
                    var throwMeAway = Application.ResourceCache.GetMaterial($"Sample43/Mat{materials[j, i]}.xml", sendEventOnFailure: false);
'''

Then the exceptions go away.

#2

Last time I checked, Urho does not throw exceptions. So if there is an exception, it could be thrown by the bindings that you’re using. In which case you can’t really blame Urho since it isn’t something from the engine itself.

Also throws an exception is a bit vague. As sometimes different exceptions have different meanings. Which is supposed to narrow the hunt for issues.


#3

My hurried description … actually it results in memory access violations. But here’s how Visual Studio outputs the error in debug mode:

Exception thrown: ‘System.AccessViolationException’ in Urho.dll
An unhandled exception of type ‘System.AccessViolationException’ occurred in Urho.dll
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

In order to generate this error, on demand, in the Feature Sample Huge Object count, at this point:

I inserted this line:

lastGroup.Material = Material.FromColor(Randoms.NextColor());

And sure enough, out pops the violation.

I’m starting to suspect it’s not related to the ResourceCache, but to the Material class.

This is that code:

		{
			var material = new Material();
			var cache = Application.Current.ResourceCache;
			float tolerance = 0.001f;
			if (unlit)
				material.SetTechnique(0, Math.Abs(color.A - 1) < tolerance ? CoreAssets.Techniques.NoTextureUnlit : CoreAssets.Techniques.NoTextureUnlitAlpha, 1, 1);
			else
				material.SetTechnique(0, Math.Abs(color.A - 1) < tolerance ? CoreAssets.Techniques.NoTexture : CoreAssets.Techniques.NoTextureAlpha, 1, 1);
			material.SetShaderParameter("MatDiffColor", color);
			return material;
		}

Then .SetTechnique

public void SetTechnique (uint index, Technique tech, uint qualityLevel = 0, float lodDistance = 0f)
		{
			Runtime.ValidateRefCounted (this);
			Material_SetTechnique (handle, index, (object)tech == null ? IntPtr.Zero : tech.Handle, qualityLevel, lodDistance);
		}

And SetShaderParameter

		{
			Runtime.ValidateRefCounted (this);
			Material_SetShaderParameter2 (handle, name, ref value);
		}

And the ValidateRefCounted

		// for RefCounted, UrhoObjects
		internal static void ValidateRefCounted<T>(T obj, [CallerMemberName] string name = "") where T : RefCounted
		{
			//TODO: remove ValidateRefCounted from IsExiting in the Binder
			if (name == "IsExisting")
				return;

			if (IsClosing)
			{
				var errorText = $"{typeof(T).Name}.{name} (Handle={obj.Handle}) was invoked after Application.Stop";
				LogSharp.Error(errorText);
				throw new InvalidOperationException(errorText);
			}
			if (obj.IsDeleted) //IsDeleted is set to True when we receive a native callback from RefCounted::~RefCounted
			{
				var errorText = $"Underlying native object was deleted for Handle={obj.Handle}. {typeof(T).Name}.{name}";
				LogSharp.Error(errorText);
				throw new InvalidOperationException(errorText);
			}
			//if (obj.Handle == IntPtr.Zero)
			//{
			//}
			//TODO: check current thread?
		}

#4

Haven’t researched this through the SharpReality implementation but notice this:

using for example:

var mat = Material.FromColor(Randoms.NextColor());
object.Material = mat;

is more stable than using

object.SetMaterial(Material.FromColor(Randoms.NextColor());

Meaning, some seemingly random exceptions stop when all the .SetMaterial() calls are converted to Material =.

Still prepopulating the ResourceCache though.

And a second area of random exceptions is around execution on the main thread vs background threads. This exception isn’t well exposed to the developer when it happens. I tend to see memory access violations as the clue that it’s happening, and go look in the code for something affecting the GUI running on a background thread.