How to turn off SendMouseEvents?

I’m not using any of the OnMouse* events anywhere in my codebase, but the SendMouseEvents class is still being called by the engine every frame, doing raycasts, wasting cycles, and allocating GC memory.

Is there a flag somewhere I can set to turn it off? I had a quick look with ILSpy but I don’t see anything.

I would love to know that as well… I so despise the GC Monster and its affects.

you guys using any Unity GUIs? Using uses SendMouseEvents() for gui processing.

-Jhoemar

In Unity 4.0, an empty scene will still have Monobehavior.OnMouse show up in the profiler.

Really? It doesn’t look like that from the code.

so…any progress with this? Certainly seems wasteful to have it called and allocating memory when mouse input isn’t needed.

Clearing the Camera.eventMask bit for the desired layer will disable SendMouseEvents processing.

1 Like

While great in theory, I haven’t actually been able to get this to work. For instance, setting the cullingMask to 0 disables the cullingMask for every layer, but setting the eventMask to 0 does not accomplish the same thing. Everything I’ve tried has been ineffective at disabling mouse events.

Have you actually gotten this to work? If so, please let us know how! Thanks!

bump!

I use camera.eventMask = ~camera.cullingMask to disable the SendMouseEvents processing for a particular camera.

In another instance, I’ve used the following to disable SendMouseEvents processing for all cameras, using the GameObject’s layer:

public void Start()
{


    var sceneCameras = FindObjectsOfType( typeof( Camera ) ) as Camera[];
    for( int i = 0; i < sceneCameras.Length; i++ )
    {


        // Get rid of Unity's extremely annoying tendency to print errors
        // about being unable to call SendMouseEventXXX because the event
        // signatures don't match. Whose idea was that, anyways? Sheesh.
        sceneCameras[ i ].eventMask = ~( 1 << gameObject.layer );


    }


}

I’m doing the same however I consistently have about 1k of data allocated by MonoBehaviour._OnMouse every frame.

See attached photo of profiler window:

That’s very odd, and does appear to indicate that it didn’t work, since the same line in my profiler window typically look like this:

This is fairly consistent for me. Even with hundreds of objects in the scene, there’s little variation in the amount of memory, and expanding the node never shows the lengthy list of subnodes that yours does.

I admit that I don’t know what the difference may be between your situation and mine. Your scene is clearly processing the DoSendMouseEvents(), though. If I can think of something significant that might apply I’ll be sure to post it. Maybe it’s because I clear the eventMask for all cameras instead of just the main camera? Not sure.

I’ve been working on trimming my allocations and am almost to zero (actually I am at zero in my own code), but even with all camera eventMaskS cleared I’m getting 0.6 - 1.2 Kb worth of allocations per frame. Maybe the profiler is counting it’s own OnGUI usage? Or maybe it’s just broken, which wouldn’t be surprising.

I’m on Unity 4.3.3f1 / OSX 10.8.5 btw.

I have decompiled the UnityEngine source code and have found what the issues are in the DoSendMouseEvents method(can source code be posted on these forums?).

The signature of the method is void DoSendMouseEvents(int mouseUsed, int skipRTCameras). I have no clue why ints are used, as these parameters are used as booleans. For the sake of this post, I am going to speak of them as if they were booleans.

The issues I have found (I think) are:

  1. If mouseUsed == true, then the mouse position is used to determine if anything was hit during the current frame . If mouseUsed == false, then nothing was hit. The first issue is that unnecessary garbage is generated even when mousedUsed == false.

Camera.allCameras (which creates 28 Bytes for me, but will create more for you if you have more enabled cameras in your scene. I think each extra camera is 4B’s) is called no matter what, even though if mouseUsed == false, the cameras ARE NOT USED.

In addition, the method allocates an array of length 2 to store two HitInfo objects, which are a struct type internal to the SendMouseEvents class. Normally structs are allocated on the Stack, but in this case because they are being copied to an array, heap allocation occurs (someone correct me if that info is not correct!). I believe in Unity’s case, each struct allocates 16B, and the array itself allocates another 8B (so 16 * 2 + 8 = 40).

In my case, these 68 Bytes make up all of the allocation that is produced by DoSendMouseEvents. I also believe it to be the minimum allocation possible.

An array in this case is absolutely unnecessary, as there are always only 2 hit info objects, so two separate variables could just as easily be used to store the HitInfo.

It’s important to note that “mouseUsed” does not equate to “mouse events enabled.” Instead, mouseUsed appears to simply indicate whether the mouse should be used to determine if anything was hit during the current frame. If mouseUsed == false, then the HitInfo structs are left empty (indicated nothing was hit for that frame).

This hit info is then sent to another method which determines what methods need to be called based on the current mouse state (left mouse button clicked or released?) and hit info for this frame and the last frame (aka, if a hit occurs and the left mouse button was clicked, call the “OnMouseDown” method of the hit game object).

  1. Now let’s talk about what happens when mouseUsed == true. The array of enabled cameras is looped through, and for each camera, if skipRTCameras (which I believe means skip RenderTexture Cameras) is true or the current camera’s targetTexture field (which is a RenderTexture) is null, the mouse position is used to determine if the mouse is currently on the camera’s rendered screen.

If it is, then the method tries to get the camera’s GUILayout component, in order to determine if the mouse is hovering over any GUI Elements. This step is always executed, regardless of whether you are actually using a GUILayout component or you have set the eventMask to 0. This may be producing garbage, as I have read somewhere that GetComponent produces garbage when no component of that type is on the game object. The Hit Info for this step is stored at index 0 of the array I mentioned above.

Once the GUI is processed, the mouse position is used to determine if any game object was hit on the screen, but only if eventMask for the camera != 0 (yay, eventMask finally did something!). The code looks something like this:

if (camera.eventMask != 0)
{
    if (camera.farClipPlane > 0f  Physics.Raycast(camera.ScreenPointToRay(mousePosition), out raycastHit, camera.farClipPlane, camera.cullingMask  camera.eventMask  -5))
    {
        StoreCameraAndObjectHitInHitInfo();
    }
    else if (camera.farClipPlane > 0f)
    {
        if (Physics2D.GetRayIntersectionNonAlloc(camera.ScreenPointToRay(mousePosition), SendMouseEvents.m_MouseRayHits2D, camera.farClipPlane, camera.cullingMask  camera.eventMask  -5) == 1)
        {
            StoreCameraAndObjectHitInHitInfo();
        }
    }
    else if (camera.clearFlags == CameraClearFlags.Skybox || camera.clearFlags == CameraClearFlags.Color)
    {
        //Don't get the point of this, isn't HitInfo already null?
        SetHitInfoToNull();
    }
}

It then sends the hit info to the other method I mentioned earlier.

The main thing to take away from all this is that there is no way to tell Unity to not use Mouse Events. Event Mask’s will stop raycast from being cast for individual cameras, but will not actually stop mouse event processing. In fact, GUI Elements are processed regardless of the event’s mask (which is probably a good thing).

They need to add some way to just disable the call to DoSendMouseEvents, although it would also be a good idea to clean up that method a bit (I am guessing whoever wrote it either a) didn’t realize it would generate garbage or b) didn’t care - which makes sense, since with a solid GC, this shouldn’t be an issue).

One final thing. From my understanding, only one camera can hold the mouse at any given time. Thus, it doesn’t make sense to loop through every camera. When a hit is detected on a camera, the loop could exit rather than checking the next camera.

3 Likes

I’m not using OnMouse calls too, but on WP8 (Lumia 930) the spikes reach 25ms.
In the editor the allocation is 1.7 KBs. I tried the indicated solutions (setting the eventMasks of the cameras)
but anyone works. However, I’m using one call to get the touchInput (Physics.raycast(…)

I guess that only way to decrease the allocation and maybe avoid the spikes is disabling the camera objects in the scene.

Has anyone found a solution to this?

I’m in Unity 5 and it seems that adding a GUILayer component to every camera solves the issue.

Component GUILayer is on camera by default. Sometimes I am able to see huge spikes on method SendMouseEvents.DoSendMouseEvents and it takes 64 ms.

2403729--164095--lag.PNG

No solution to this yet?

1 Like

I just like how the original poster now seems to work at Unity (but probably did not at the time, or else why would he/she ask on here?)

3 Likes