surge-synthesizer / surge

Synthesizer plug-in (previously released as Vember Audio Surge)
https://surge-synthesizer.github.io/
GNU General Public License v3.0
3.13k stars 400 forks source link

using high frequency LFO makes GUI unsuable #4593

Closed hems closed 3 years ago

hems commented 3 years ago

Bug Description: If i set an LFO to high frequency the entire UI on Surge becomes "slugglsh" and i can barely move any knob on the entire UI because of that.

Surge Version 1.9 also tested with 1.7, both had the same results

Reproduction Steps:

  1. assign LFO 1 to filter CUT OFF
  2. Setup LFO 1 like this setting: image
  3. change to this setting: image

Now when moving it mouse the mouse gets kinda stuttery

Expected Behavior: Constinuously have an smooth UI.

Screenshots: If applicable, add screenshots/GIF/videos to help explain your problem.

Computer Information (please complete the following information): OSX 10.12, 2.6 GHZ i7, 16 GB RAM

Additional Information: I got the impression the UI is having too much work drawing the LFO at high frequency or just have some sort of leak that makes the entire thing, incliuding my DAW unusable.

I don't remember having those issues on much earlier versions of Surge, let's say about 1 to 2 years ago..

I remember having played a lot with the LFOs at high req on this same computer and things were really smooth and that's one of the things that really impressed me.

Here is a link to a project file demonstrating this:

https://www.dropbox.com/s/ry4n79l58tol5bx/surge-lfo-test.als?dl=0

hems commented 3 years ago

If i close the UI and control it via ableton automation it sounds and works as expected.

image

baconpaul commented 3 years ago

So the immediate cause here is that your envelope is all the way open so we are showing 60 seconds of LFO. If you move Hold and Decay to zero you will get less drawn and it will improve

macOS AU though draws fine for me with your params on a new MBP. I'll profile it this cycle.

hems commented 3 years ago

So the immediate cause here is that your envelope is all the way open so we are showing 60 seconds of LFO. If you move Hold and Decay to zero you will get less drawn and it will improve

that's a workaround but that doesn't solve this bug : D

macOS AU though draws fine for me with your params on a new MBP. I'll profile it this cycle.

Have you tried VST 3 and compared how it behaves? Is it possible that the UI would have issues on VST but not on AU?

Also, my macbook isn't the problem, the CPU usage stays very low when this bug happens, it's clearly something inside of Surge, it's not my computer that is limiting Surge, my computer is good enough to draw an LFO on a tiny amount of pixels.

It's very possible there is a bug / leak / issue in here, and if there is not then still we have a lot of room for improvements, such as:

etcs...

mkruselj commented 3 years ago

Would be interesting if you'd try building Surge XT alpha from source and see if the same thing happens there, or if JUCE handles this better.

Don't think it's a bug, and I'm pretty sure there's no memory leak here. It's just a lot of LFO time to render. Surely could be optimized some perhaps, but first let's see if you can verify the same with Surge XT.

BTW, I cannot notice any sluggishness over here in Live 11 Win 10. However I am running a 4.5 GHz i7.

baconpaul commented 3 years ago

The thing that is taking time is: We are sampling the entire LFO for 60 seconds to draw; and we add more lines if the oscillations are hight. I test for leaks but it's just the LFOGui paint taking time because of the long envelope and high frequency.

Older versions of surge were faster here because (1) they didn't expand the axis with envelope and (2) they used a non-vector bitmap draw which didn't scale to retina displays or zoomed uis.

Some of your ideas are good ones though. What we should almost definitely do is draw to an offscreen image and only refresh if a parameter or screen size has changed. Welcome a PR which does that if you want!

baconpaul commented 3 years ago

(oh thinking of it - don't put in a PR that does that. I have these widgets slated to rewrite anyway and will do an offscreen cache as part of that).

hems commented 3 years ago

Would be interesting if you'd try building Surge XT alpha from source and see if the same thing happens there, or if JUCE handles this better.

unfortunately i can't build from source on my mac at the moment, would it be possible for you guys to publish a build?

Don't think it's a bug, and I'm pretty sure there's no memory leak here.

that's great

It's just a lot of LFO time to render.

i don't remember having this problem before and i'm pretty sure i have used very similar LFO settings.. something is weird, maybe it's my machine maybe it's surge, but i suspect it's likely to be surge.

also i always used AU but now that i have a PC i'm using VST so i can share projects between the two machines, could that be part of the issue?

Surely could be optimized some perhaps, but first let's see if you can verify the same with Surge XT.

sure, if we're moving to XT then better try it out on XT.

BTW, I cannot notice any sluggishness over here in Live 11 Win 10. However I am running a 4.5 GHz i7.

I have a much more powerful PC than a mac running Windows 10, so it would be unfair to compare. Still even on Windows if i'm using several instances of Surge ( which sometimes i do ) then this drawing problem will eventually happen.

it would be a good idea to optimise as there are some easy optimisations that can be done

baconpaul commented 3 years ago

i look forward to you doing the optimizations if they are easy! :)

But I am still not sure there's a problem in surge here. On my mac both the 1.9 VST3 and AU have no sluggishness when at the timescale you show (I tried mac in LPX and Hosting AU and Reaper). And Evil didn't see it either.

So I guess: How sure are you your machine graphic subsystem is OK? I looked at the code again and it is not awesome when you get the 60 second envelope but it is not crazy.

Wonder if live is doing something dumb. Let me try and fire up the live 10 trial here and see.

baconpaul commented 3 years ago

Nope. Live10 no problem with the LFO all the way open with any drawing lags here on my mac. Hmm. Wonder what it could be.

baconpaul commented 3 years ago

Oh and we publish an XT build https://github.com/surge-synthesizer/releases-xt/releases/tag/Nightly but it is very very very (very (very)) alpha.

It does use a different ID though ("Surge XT" not "Surge") so can live side by side with Surge 1.9

hems commented 3 years ago

i look forward to you doing the optimizations if they are easy! :)

ooops, you win : D

But I am still not sure there's a problem in surge here.

There is surely a problem as no other VST or plugin i have does that.

Also i just tried the AU and it does have the same issue even tough my CPU is just at 3% and i'm not doing any work with my GFX card.

image

On my mac both the 1.9 VST3 and AU have no sluggishness when at the timescale you show (I tried mac in LPX and Hosting AU and Reaper). And Evil didn't see it either.

very weird.

So I guess: How sure are you your machine graphic subsystem is OK? I looked at the code again and it is not awesome when you get the 60 second envelope but it is not crazy.

it looks pretty OK to me on everything else i do.

It's a Radeon Pro 455 2048 MB

For instance i can run this 3D world in full screen which is much more complex than drawing that LFO without any FPS or sluggish issues:

http://hems.io/workz/colours/two/index.html

Is Surge using GPU acceleration to draw the LFO?

Wonder if live is doing something dumb. Let me try and fire up the live 10 trial here and see.

I just tried on Reaper64 and i have exactly same issue. It seems to be somehow less sluggish but still unusable

baconpaul commented 3 years ago

Right. So a couple of other questions

if you take rate down super low to like 0.05hz or some such does it still slug? That’s the same number of points. How about if you set amplitude to zero? And amplitude to zero with the ghost zone off in the menu user displays?

inwonder if there’s a 10.12 vs 10.15 difference also. It almost sounds like the system is going quadratic with points drawn.

On mac surge uses core graphics directly. What we need to do is determine why your system experiences surge as broken and ours do not.

baconpaul commented 3 years ago

And one other Take the LFO and make it a black box switch to LFo2 (so the black box is hidden and the LFO looks normal) UI all OK then?

hems commented 3 years ago

will test on my mac soon and answer all your questions, for now I just tested on Windows 10 it's working perfectly

image

so it seems like it's probably a mac thing.. although my PC is much much higher spec so it's unfair to compare.

mkruselj commented 3 years ago

Actually I wonder if it's one of those colorspce issues that happen on Mac... Certain colorspaces in certain cases chug the CPU up.

baconpaul commented 3 years ago

I mean it also works great on my Mac? And the color space here is black.

So what is it about hems mac setup which is tickling a problem. That’s what we need to find.

hems do you have access to another Mac at all?

baconpaul commented 3 years ago

Or can you dual boot into an os other than 10.12?

mkruselj commented 3 years ago

When I say colorspace I mean this:

https://www.bluecataudio.com/Blog/tip-of-the-day/slow-mac-how-to-fix-mac-gui-performance-issues/?utm_campaign=How+to+Fix+Mac+OS+GUI+Performance+Issues&utm_source=facebook.com&utm_medium=organic_post&utm_content=blog

baconpaul commented 3 years ago

Oh interesting. I didn't know about that. Definitely worth a try for @hems also!

hems commented 3 years ago

if you take rate down super low to like 0.05hz or some such does it still slug? That’s the same number of points.

The problem doesn't happen at low rate.

Also keep in mind this is without assigning the LFO to any parameter, pressing play on the DAW, that's purely from starting a fresh session on my DAW, starting SURGE and moving LFO 1.

In other words, i have my entire DAW / computer resources to render this LFO but somehow it fails to do so, which in my point of view proofs that there is some sort of bug / ui rendering issue at high frequencies.

https://www.dropbox.com/s/l41elxvhjhknckg/surge-ui-problem.mov?dl=0

How about if you set amplitude to zero? And amplitude to zero with the ghost zone off in the menu user displays?

The problem doesn't get any better with amplitude at 0, it seems it's somehow drawing loads of things .

image

inwonder if there’s a 10.12 vs 10.15 difference also.

Unfortunately i don't have a mac with 10.15, but i'll ask a friend and see which version they have and see if it happens to them as well.

It almost sounds like the system is going quadratic with points drawn.

For me it sounds like you drawing a vector which way too many points in them and you're trying to redraw them before the previous draw have finished in a blocking thread that used by the GUI and that ends up making the GUI irresponsive.

Another funny thing i noticed is that only the GUI for the LFO parameters is getting irresponsive on Surge 1.9, if i try to move the CUTOFF frequency it actually moves as expected.

On mac surge uses core graphics directly. What we need to do is determine why your system experiences surge as broken and ours do not.

It might be that on earlier versions of OSX core graphics is more optimised and ends up not creating this issue.

There is definitely some black box elements to OSX a graphics as i have seen iphones processing some 3D graphics way faster than desktop macs in some cases even tough the "source code" for the 3D app was the same. Not sure if it's related to what we are experiencing here, but i think it's worth mentioning.

hems commented 3 years ago

And one other Take the LFO and make it a black box switch to LFo2 (so the black box is hidden and the LFO looks normal) UI all OK then?

yes, once i switch to LFO2 the problem goes away. same if i close the GUI and automate the same parameters via DAW automation.

It's definitely a GUI drawing issue.

Actually now that i'm thinking i remembered of another plugin who had the same issue when i would have LFOs connected to some parameters that were supposed to update the UI. I think it's a common problem that can be forgotten specially if the developer machines are extremely fast ( which generally is the case ) which is one of the reasons softwares are less and less optimised those days : D

hems commented 3 years ago

hems do you have access to another Mac at all?

i do have a few friends with MACS i can try it out on their macs and see what happens for them.

hems commented 3 years ago

https://www.bluecataudio.com/Blog/tip-of-the-day/slow-mac-how-to-fix-mac-gui-performance-issues/?utm_campaign=How+to+Fix+Mac+OS+GUI+Performance+Issues&utm_source=facebook.com&utm_medium=organic_post&utm_content=blog

i really hoped that was the problem, but unfortunately it wasn't :(

hems commented 3 years ago

Oh and we publish an XT build https://github.com/surge-synthesizer/releases-xt/releases/tag/Nightly but it is very very very (very (very)) alpha.

It does use a different ID though ("Surge XT" not "Surge") so can live side by side with Surge 1.9

exactly same problem :(

baconpaul commented 3 years ago

Right OK so this comment:

Another funny thing i noticed is that only the GUI for the LFO parameters is getting irresponsive on Surge 1.9, if i try to move the CUTOFF frequency it actually moves as expected.

was super useful because it is what I see and what I was testing (namely "The UI was perfectly responsive"). But when I modify an LFO param with the LFO opened up as you say I get the same problem. This is also totally consistent since changing the cutoff doesn't force an lfo repaint.

You are correct that the UI thread repaint is getting slow of course (we knew that all along) but It's not point count - the points are the same - it's something about the overpaint. Very mysterious. I'll have to profile it but I'll put in profiling hooks when I rewrite.

But short version is: I can reproduce this now and we can figure out how to fix it in the XT cycle. If you really need an LFO opened up all this way on screen, you'll get slowness unless you click it of screen or close down the env in 1.9. I'll update this issue if/when I have a fix for the next release.

baconpaul commented 3 years ago

Oh and as always thanks for the detailed testing and responses.

hems commented 3 years ago

Right OK so this comment:

Another funny thing i noticed is that only the GUI for the LFO parameters is getting irresponsive on Surge 1.9, if i try to move the CUTOFF frequency it actually moves as expected. was super useful because it is what I see and what I was testing (namely "The UI was perfectly responsive").

Sorry i should have been more clear all the way about this.

But to be honest it takes a little bit of time for the CUT OFF to become useable after the LFO is set to max, so it's also about timing when testing.

But when I modify an LFO param with the LFO opened up as you say I get the same problem. This is also totally consistent since changing the cutoff doesn't force an lfo repaint. You are correct that the UI thread repaint is getting slow of course (we knew that all along) but It's not point count - the points are the same - it's something about the overpaint. Very mysterious. I'll have to profile it but I'll put in profiling hooks when I rewrite.

Does the frequency of the LFO actually influences how often the LFO gets draw? I believe it doesn't or at least shouldn't as the audio and GUI threads are likely complete separate?

Maybe the solution is to simply "downsample" the LFO before drawing, in the end of the day there are just like 400-500 pixels on the preview so it makes no sense to be using more than 400-500 points when drawing the LFO... ? Does that make any sense / apply to the code?

I'm not sure what's the "Framewrate" of your GUI but rule of thumb is if you want to get 60 fps ( refresh rate of a retina display on mac ) is that you would need to keep the drawing loop to max of 16ms. ( For modern 300 fps screens would have to keep at 3ms, lol )

So anything computationally slow can't be triggered on every loop.

Another workaround i see is to don't allow a an LFO draw to be executed before the previous LFO draw was complete, this would decrease the FPS of the drawing but it probably wouldn't make the UI sluggish, it would just "drop frames" of the "animation" as you slide.. ( that's how high performance UI animation frameworks i read the source drop their frames ).

But short version is: I can reproduce this now and we can figure out how to fix it in the XT cycle. If you really need an LFO opened up all this way on screen, you'll get slowness unless you click it of screen or close down the env in 1.9. I'll update this issue if/when I have a fix for the next release.

awesome!

Oh and as always thanks for the detailed testing and responses.

You're more than welcome! I hope this helps!

Thanks a lot for working on the code!!

Also, I'm sorry i haven't be able to actually contribute on the CODE, I'm doing my best to make it easier for you guys on the bug reports tough ( :

thanks again

baconpaul commented 3 years ago

Maybe the solution is to simply "downsample" the LFO before drawing, in the end of the day there are just like 400-500 pixels on the preview so it makes no sense to be using more than 400-500 points when drawing the LFO... ? Does that make any sense / apply to the code?

this makes perfect sense. Which is why the code does it now. The problem is at this high frequency something is going wrong in the graphics subsystem. Same number of points at low rate as high rate.

baconpaul commented 3 years ago

(or the downsample s buggy but I actually printed out the point count. It is 900 or so in each case which makes sense - each pixel can have a distinct start and end to get a square verticalized)

hems commented 3 years ago

this makes perfect sense. Which is why the code does it now. The problem is at this high frequency something is going wrong in the graphics subsystem.

well, i have my guesses in here but i'm not familiar with the code so i can't tell. also i think by now i gave you all the information and suggestions i could so better not add more noise to this thread.

Just out of curiosity, if you point me out to the relevant pieces of code i could have a look myself and try to be a little bit more concrete on my suggestions. It's a long shot here that i would be able to spot a bug you didn't, but hey, i'll never hit it if i never try : D

thanks again

baconpaul commented 3 years ago

https://github.com/surge-synthesizer/surge/blob/ce40377ba611912249ec9e5aeb6a7a7e1297bf6b/src/gui/CLFOGui.cpp#L218

hems commented 3 years ago

https://github.com/surge-synthesizer/surge/blob/ce40377ba611912249ec9e5aeb6a7a7e1297bf6b/src/gui/CLFOGui.cpp#L218

couple things here:

  1. is the LFO is being draw every "frame" even if the parameters doesn't change?
  2. hypothetically if LFO draw function takes too long to draw are we allowing the LFO draw function to be called again ( i.e. on a rendering loop ) ? before the previous execution was no finished ( i.e. we're not dropping frames )

From reading the code my assumption is that both cases answers are "yes" ? ( i might be wrong tough? )

The good news are, number 2 is theoretically easy to solve by having a simple boolean

For number 1 i guess it will get a little more complicated but basically you would need to save the previous state drawn and not redraw if the state did not change.

Of course those are my assumptions based on the little i understand about how Surge source code / GUI works, it could be that there are other problems, but from my experience implementing those 2 optimisations are generally a big deal when developing GUIs.

Specially what i explained on item 2, back in the day when i used to work with open source animation frameworks this was the number 1 feature needed to be implemented in order to keep the animation smooth and looking pretty much the same in all computer specs.

Even computers with high specs would benefit from that as sometimes drawing the GUI could end up with a "background thread" due to the way OS works, which would lags the animations even on high spec computers because frames were not being dropped by the rendering code.

mkruselj commented 3 years ago

AFAIK Surge only redraws things if values change.

baconpaul commented 3 years ago
  1. No
  2. The ui is single threaded so that won’t help
baconpaul commented 3 years ago

and i'm a day or so away from pushing a rewrite of this (which shows the same problem) which we can then profile I think what happens is the graphics draw functions on highly oscillatory paths are slow but port; profile; fix has to be the answer

baconpaul commented 3 years ago

In further bad news I put a little timer in the code at the head of paint the time spent in the LFO paint code is a constant independent of slider position, even though the UI lags. About 6300us per paint independent of rate.

This means the time is not being spent in the surge code

So this will require real profiling. And probably the fix is to determine and detect the pathological condition and draw something different.

baconpaul commented 3 years ago

Alright in my rewrite branch I've worked around this by adding an extra constraint that, in no circumstance, do we show more than 50 cycles of the waveform.

baconpaul/lfo

it changes what is drawn but also fixes the performance problem

hems commented 3 years ago

Alright in my rewrite branch I've worked around this by adding an extra constraint that, in no circumstance, do we show more than 50 cycles of the waveform.

baconpaul/lfo

it changes what is drawn but also fixes the performance problem

very intersting!

mkruselj commented 3 years ago

4704 should fix this, closing.