ValveSoftware / steamvr_unity_plugin

SteamVR Unity Plugin - Documentation at: https://valvesoftware.github.io/steamvr_unity_plugin/
BSD 3-Clause "New" or "Revised" License
1.04k stars 259 forks source link

SteamVR 2.2 + nvidia Flex errors #337

Closed doukasd closed 5 years ago

doukasd commented 5 years ago

I am trying to use the SteamVR Plugin with the nvidia Flex fluid renderer. On their own, they all work fine. But when combined, there are runtime errors.

Setup:

Steps to reproduce:

ArgumentException: ComputeBuffer.SetData() : Accessing 35100 bytes at offset 0 for Compute Buffer of size 35000 bytes is not possible.
UnityEngine.ComputeBuffer.SetData (System.Array data) (at C:/buildslave/unity/build/Runtime/Export/ComputeShader.bindings.cs:124)
NVIDIA.Flex._auxFlexDrawFluid.UpdateMesh (NVIDIA.Flex.FlexContainer+ParticleData _particleData) (at Assets/NVIDIA/Flex/Auxiliary/_auxFlexDrawFluid.cs:247)
NVIDIA.Flex.FlexContainer.UpdateDrawFluid (NVIDIA.Flex.FlexContainer+ParticleData _particleData) (at Assets/NVIDIA/Flex/Assets/FlexContainer.cs:788)
NVIDIA.Flex.FlexContainer.UpdateSolver () (at Assets/NVIDIA/Flex/Assets/FlexContainer.cs:696)
NVIDIA.Flex.FlexContainer.FixedUpdate () (at Assets/NVIDIA/Flex/Assets/FlexContainer.cs:605)
NVIDIA.Flex.FlexScene.FixedUpdate () (at Assets/NVIDIA/Flex/Helpers/FlexScene.cs:68)
LogWarning - Mapping a buffer that was already mapped
File - ..\..\dx\utils.cpp (62)
UnityEngine.Debug:LogError(Object)
NVIDIA.Flex.FlexContainer:ErrorCallback(ErrorSeverity, IntPtr, IntPtr, Int32) (at Assets/NVIDIA/Flex/Assets/FlexContainer.cs:491)
NVIDIA.Flex.FlexExt:MapParticleData()
NVIDIA.Flex.FlexContainer:UpdateSolver() (at Assets/NVIDIA/Flex/Assets/FlexContainer.cs:688)
NVIDIA.Flex.FlexContainer:FixedUpdate() (at Assets/NVIDIA/Flex/Assets/FlexContainer.cs:605)
NVIDIA.Flex.FlexScene:FixedUpdate() (at Assets/NVIDIA/Flex/Helpers/FlexScene.cs:68)

I understand that it seems to be Flex "crashing" here and not SteamVR, which is why I first posted this issue on the nvidia forums, however as SteamVR is implicated (Flex works fine without it) I am here to see if SteamVR Plugin could be improved in some way to not affect other such systems.

rt974 commented 5 years ago

Hi, i am a bit familiar with compute shaders, this is due to the computebuffer size that was containing xxx amount of particles when initilialzed earlier, and then the flex source actor added more particles, but the buffer size wasnt updated. im having the same issue in unity and the flex plugin. i think i can debug this, did some compute shader coding last month. if i manage to fix that ill post the solution there.

For example, if you set the fluid source actor particle life to a high number like : 999, when the source actor spawns its particles, it has to wait 999 seconds before adding anymore particles to the simulation, and having to update the compute buffer size, so it runs fine as long as no new particles are added.

But i need this to be fixed so ill take a look and see if i can resize the compute buffer according to the new particles count. This shouldnt require any PHD in Astrophysics, because i got none.

:-)

rt974 commented 5 years ago

here for example in _auxFlexDrawFluid.cs at the line 247 :

if you replace m_indexBuffer.SetData(indices);

by

if(indices.Length != m_indexBuffer.count)
{
    m_indexBuffer = new ComputeBuffer(indices.Length, sizeof(int));

}
else
{
    m_indexBuffer.SetData(indices);
}

Now the error is gone, but because we recreate the buffer every single time we add a particle, this creates a flickering. Ill see if i can fix that, with my poor understanding of computer graphics.

I guess they use some kind of pre-allocation system for x number of particles, and update that buffer only once in a while.

rt974 commented 5 years ago

Wow i managed to fix this :

//ORIGINAL
//m_indexBuffer.SetData(indices);
//ORIGINAL
//NEW
if(indices.Length != m_indexBuffer.count)
{
    m_indexBuffer = new ComputeBuffer(indices.Length, sizeof(int));
    m_indexBuffer.SetData(indices);
}
else
{
    m_indexBuffer.SetData(indices);
}
//NEW

The flicker happened because the SetData needs to be called in all cases, the code can be simplified by removing the else, and writing only one SetData at the end.

Now for me this works, i dont really know if this doesnt create side effects, i've read somewhere on unity forums that recreating ComputeBuffer every frame is not a good idea. Thats as far as my knowledge goes on this topic.

I hope this helps.

reforia commented 5 years ago

@rt974 Thanks for the solution! that helps me solve the problem!

After a lil' bit investigation I think your solution can be better by adding another line m_indexBuffer.Release(); before: m_indexBuffer = new ComputeBuffer(indices.Length, sizeof(int));

Which releases the buffer created at line 242 before recreating it, otherwise it will throw back some warnings by Unity Garbage Collection

The code will then be:

                    if (indices.Length != m_indexBuffer.count)
                    {
                        m_indexBuffer.Release();
                        m_indexBuffer = new ComputeBuffer(indices.Length, sizeof(int));
                    }
                    m_indexBuffer.SetData(indices);
zite commented 5 years ago

Thanks for the help!

oli414 commented 4 years ago

The solution by @reforia keeps the number of drawn particles at the maximum. This becomes a problem when deactivating the fluid source, as the fluids will not despawn until every single one of them has reached the end of its lifetime. Instead I propose this workaround.

Start with a fresh (unmodified) _auxFlexDrawFluid.cs, and simply replace:

if (m_indexBuffer != null)
{
    m_indexBuffer.SetData(indices);
}

at line 245 with:

if (m_indexBuffer != null)
{
    m_indexBuffer.SetData(indices, 0, 0, m_indexBuffer.count);
}

The crash happened because indices doesn't appear to dynamically change size. So if our max particles is 4000, then indices will have a length of 4000 as long as there're any particles around. indexCount on the other hand directly reflects how many particles are alive, which may for instance be 3672. So when copying the indices we need to limit what we're copying by the size of m_indexBuffer. Creating a new m_indexBuffer to match the maximum amount of particles on the other hand causes particles to visually stay in the scene.

lokeshkumar16061993 commented 3 years ago

Hi, i am a bit familiar with compute shaders, this is due to the computebuffer size that was containing xxx amount of particles when initilialzed earlier, and then the flex source actor added more particles, but the buffer size wasnt updated. im having the same issue in unity and the flex plugin. i think i can debug this, did some compute shader coding last month. if i manage to fix that ill post the solution there.

For example, if you set the fluid source actor particle life to a high number like : 999, when the source actor spawns its particles, it has to wait 999 seconds before adding anymore particles to the simulation, and having to update the compute buffer size, so it runs fine as long as no new particles are added.

But i need this to be fixed so ill take a look and see if i can resize the compute buffer according to the new particles count. This shouldnt require any PHD in Astrophysics, because i got none.

:-)

its perfectly worked for me thank you