VSTGUI 3.6 Windows 7 GDI+ Sluggishness: A Workaround...
- KVRAF
- 12615 posts since 7 Dec, 2004
you "hide" windows in your host?
i don't care if the window is off screen or behind another window, i need to keep things up to date for animation that happens only once in a while - otherwise i suppose things could be extrapolated, but it's generally not an issue. if the window is behind another one, the knobs aren't moving anyway, and filling the leds out takes hardly any time - assuming the gui even shows leds.
most hosts call open/close rather than just hiding the window, in which case i don't think you can get a dc. (not to mention i never update a gui that's closed anyway, and the host can never call idle either.) so the blit would never happen, but the updates still would apply to the cache. if it were needed (i've never seen a case where it is) i could add a single line of code to check if the window is visible when the canvas is locked, and refuse if not - then the update would be skipped.
btw: if you hide my window - don't call my idle.
most guis seem to redraw directly when controls are moved - vstgui used to do this, i'm not sure if it still does. i can name a few fairly major products which i know for a fact do this. that i agree is very stupid, if you're calling invalidaterect on a control movement it's the same thing too. that comes down to the same issue though - the gui is probably already on the screen anyway. if saving 100us to the next idle() call is so important that's ok i guess, but then you're over-riding the host's control of idle frequency and ruining the whole system.
(vst related stuff seems to be half written by a competent, and half [or more?] by an incompetent programmer.)
if close() is called as it's supposed to be called (if you take cubase as the example of the standard) none of this is an issue.
i don't really care if part of the window is off-screen, why would it be there in the first place, and if so why didn't the user close it? i don't think any of my guis have any elements that can be used on half the gui, nor is the time it takes to redraw so long as to require the use of merging rects. since i composite my graphics myself due to windows' inability to do so, i need to manage rect merging myself anyway - it's possible to get the window rect, then get the display rect and clip the window rect to the display - i don't really see the point though. i've never used my software with the guis half-way off the screen. are we talking about wastefully drawing a couple pixels along the edge that aren't animated and only redraw once anyway?
i don't care if the window is off screen or behind another window, i need to keep things up to date for animation that happens only once in a while - otherwise i suppose things could be extrapolated, but it's generally not an issue. if the window is behind another one, the knobs aren't moving anyway, and filling the leds out takes hardly any time - assuming the gui even shows leds.
most hosts call open/close rather than just hiding the window, in which case i don't think you can get a dc. (not to mention i never update a gui that's closed anyway, and the host can never call idle either.) so the blit would never happen, but the updates still would apply to the cache. if it were needed (i've never seen a case where it is) i could add a single line of code to check if the window is visible when the canvas is locked, and refuse if not - then the update would be skipped.
btw: if you hide my window - don't call my idle.
most guis seem to redraw directly when controls are moved - vstgui used to do this, i'm not sure if it still does. i can name a few fairly major products which i know for a fact do this. that i agree is very stupid, if you're calling invalidaterect on a control movement it's the same thing too. that comes down to the same issue though - the gui is probably already on the screen anyway. if saving 100us to the next idle() call is so important that's ok i guess, but then you're over-riding the host's control of idle frequency and ruining the whole system.
(vst related stuff seems to be half written by a competent, and half [or more?] by an incompetent programmer.)
if close() is called as it's supposed to be called (if you take cubase as the example of the standard) none of this is an issue.
i don't really care if part of the window is off-screen, why would it be there in the first place, and if so why didn't the user close it? i don't think any of my guis have any elements that can be used on half the gui, nor is the time it takes to redraw so long as to require the use of merging rects. since i composite my graphics myself due to windows' inability to do so, i need to manage rect merging myself anyway - it's possible to get the window rect, then get the display rect and clip the window rect to the display - i don't really see the point though. i've never used my software with the guis half-way off the screen. are we talking about wastefully drawing a couple pixels along the edge that aren't animated and only redraw once anyway?
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
-
tony tony chopper tony tony chopper https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=3103
- KVRAF
- 3561 posts since 20 Jun, 2002
when the user closes a window it doesn't stop existingyou "hide" windows in your host?
why not?if the window is behind another one, the knobs aren't moving anyway
& a lot of plugins take ages to create their editor or don't restore stuff properlymost hosts call open/close rather than just hiding the window, in which case i don't think you can get a dc.
if you keep a giant cache even for editors that aren't visible, it's worse than I thoughtso the blit would never happen, but the updates still would apply to the cache.
with the size of today's GUIs, most of the time they will be either hidden or behind another big window, and only fully visible when the user is working on that plugini don't really care if part of the window is off-screen, why would it be there in the first place, and if so why didn't the user close it?
at the beginning of this thread you were pimping your caching method because it allowed reusing something that was drawn once and I said that I saw no reason for stuff to be repainted if their content didn't change. Now why are you saying that things are redrawn once anyway?are we talking about wastefully drawing a couple pixels along the edge that aren't animated and only redraw once anyway?
DOLPH WILL PWNZ0R J00r LAWZ!!!!
- KVRAF
- 12615 posts since 7 Dec, 2004
that's what i'm talking about. if the element isn't animated, the cache holds it, so an update only involves a blit, and on vista/win7 it doesn't do anything at all, ever, after the initial draw.
do you call idle() while windows are hidden? if not, problem solved.
guess what - gasp - i also don't delete my delay buffers while the audio is paused.
how much memory does your machine have? mine has four gig, and you're concerned about using up 500kb.
you should try writing code for a 1kb embedded system.
do you call idle() while windows are hidden? if not, problem solved.
guess what - gasp - i also don't delete my delay buffers while the audio is paused.
how much memory does your machine have? mine has four gig, and you're concerned about using up 500kb.
you should try writing code for a 1kb embedded system.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
-
- KVRian
- 1153 posts since 10 Dec, 2003
That's my point, WM_PAINTs dont happen every frame, or even predictably, under heavy load they will happen far less often. So if you set the frame rate on the timer to say 25hz, you could be getting that callback multiple times in between getting WM_PAINTs, so there will be buffer redraws that never actually get blitted if as you say you blit in response to WM_PAINT.aciddose wrote: 1) limit frame-rate to below the display refresh rate (using the right flags, windows can frame-sync your blits if needed, but it isn't unless you only partially update an animation, which wouldn't make any sense)
2) wm_paint doesn't happen every frame anyway, so it's pointless to use this to meter anything
I can see that such a setup would help keep your GUI 'fresh' and responsive, and ease the load on the GUI thread. But if the system is under heavy load it seems like it would make things worse not better because it completely bypasses windows ability to limit repainting when it has more important stuff to do. But maybe it doesnt matter so much with most people having multicore cpus these days.
I meant what do you do if you get a WM_PAINT while your timer callback is in the middle of redrawing the buffer. You blit in one thread, and do the drawing to the buffer in another IIUYC. So how do you synchronize that so that so that you dont blit the buffer while it's part drawn?what if wm_paint occurs during the blit? i'm not sure if windows allows that or how it's handled if you're inside a blit while a redraw occurs - if it causes corruption i've never seen it, and if i had to fix it only a mutex could take care of that where you'd refuse to do anything in wm_paint if a blut was taking place already.
- KVRAF
- 8476 posts since 12 Feb, 2006 from Helsinki, Finland
If you use WM_TIMERs, then they have the nice property that there can only be at most one pending message per timer, and those messages have the lowest possible priority, which means you will never be handling any WM_TIMER messages until you have handled all other messages in the queue. So if you trigger a redraw from the timer, then the WM_PAINT will always get handled first, before you get another WM_TIMER (which will still get queued as soon as the interval has passed again).nollock wrote:How do you prevent the timer update repainting unnecessarily? It could get called multiple times between WM_PAINT messages, maybe more so if the system is under heavy load. So you could redraw multiple times but only blit the last redraw. And as you have little control over when you get WM_PAINT messages, you cant actually know whether a timer redraw will be wasted effort or not.aciddose wrote: i never redraw anything due to wm_paint unless the buffer is empty. outdated buffers are kept outdated and redrawn during my next timer update.
i just checked - actually i never redraw anything from wm_paint, ever. only a blit happens there.
WM_PAINT messages actually have the second lowest priority, so any messages that could potentially cause the logical window contents the change would get handled before the WM_PAINT (potentially saving you useless redraws). This is the main reason you would usually want to defer any drawing into the next WM_PAINT.
Now, if you really want to draw (well, update backbuffers, whatever) outside WM_PAINT, then WM_TIMER is probably the least harmful place to do it (since it's low priority).
- KVRAF
- 12615 posts since 7 Dec, 2004
i also blit on wm_paint, because you must. that's what wm_paint is for - it's a notification that you must fill the client rect.nollock wrote:That's my point, WM_PAINTs dont happen every frame, or even predictably, under heavy load they will happen far less often. So if you set the frame rate on the timer to say 25hz, you could be getting that callback multiple times in between getting WM_PAINTs, so there will be buffer redraws that never actually get blitted if as you say you blit in response to WM_PAINT.
that's exactly what i was talking about - you'd need to double buffer anyway to solve that issue. yes it's a valid concern, i'd need to combine my rects, then call an invalidate rect for each one, then delay the update from idle until the message has been dispatched through the windows dispatching methods - that assumes windows does a mutex lock to prevent itself calling wm_paint from multiple threads at the same time so would in essence be the same as me applying a mutex lock on my own with a async read on the key state.nollock wrote: I meant what do you do if you get a WM_PAINT while your timer callback is in the middle of redrawing the buffer. You blit in one thread, and do the drawing to the buffer in another IIUYC. So how do you synchronize that so that so that you dont blit the buffer while it's part drawn?
i'm not sure if windows applies a lock - it's entirely possible windows allows two wm_paint messages, one triggered by yourself in your own thread and one passed from another thread anyway. in fact idle() is called from that same thread, blocking the dispatch in that thread in the first place. so you'd think there couldn't possibly be two threads one to trigger idle, and one to trigger wm_paint at the same time anyway.
i'd think it isn't actually a problem in the first place. all graphical operations occur in the same thread.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
-
tony tony chopper tony tony chopper https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=3103
- KVRAF
- 3561 posts since 20 Jun, 2002
the messaging system works in the GUI thread, not per-thread, and you're not "triggering" but posting. Whatever thread you invalidate from, the wm_paint is still a normal message ending up in the GUI thread.i'm not sure if windows applies a lock - it's entirely possible windows allows two wm_paint messages, one triggered by yourself in your own thread and one passed from another thread anyway. in fact idle() is called from that same thread, blocking the dispatch in that thread in the first place. so you'd think there couldn't possibly be two threads one to trigger idle, and one to trigger wm_paint at the same time anyway.
But that's not what he was saying. He was talking about your same cache bitmap being accessed from the GUI thread (in wm_paint) & your updating thread at the same time. If you don't lock yourself, it's not Windows that will (it doesn't know when you're accessing your DIB).
you said you were painting in your cache from another threadi'd think it isn't actually a problem in the first place. all graphical operations occur in the same thread.
DOLPH WILL PWNZ0R J00r LAWZ!!!!
- KVRAF
- 12615 posts since 7 Dec, 2004
i never said i painted my cache from another thread.
i cooperate with the host, which can manage exactly what i do, how often, whether it's done at all and so on.
i cooperate with the host, which can manage exactly what i do, how often, whether it's done at all and so on.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
-
tony tony chopper tony tony chopper https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=3103
- KVRAF
- 3561 posts since 20 Jun, 2002
so what are you doing in another thread?
...because the blits are dma to hardware, and they're cached, it's most efficient to draw and blit from a separate thread so you don't end up blocking window messages while you're fooling around drawing something
DOLPH WILL PWNZ0R J00r LAWZ!!!!
- KVRAF
- 12615 posts since 7 Dec, 2004
i never said i'm doing that, i only said it would be most efficient. in that case you'd probably need to double-buffer, and so unless you could blit to the hardware directly and allow it to buffer for you, avoiding this issue - then it wouldn't make sense.
it's all up to windows at that point. how does win7's blit work? does it send directly to the card where it keeps a double-buffer of your window so you can update in the middle of when it's refreshing? it probably does, i don't see how it couldn't since the double-buffer situation needs to happen between the memory you store, the blit, and the memory on the video card anyway. that's required for the hardware compositing to work, so it must work that way unless there is some better way i'm not thinking of.
(right? just to clarify, since it keeps your buffer on the video memory anyway, it won't call wm_paint during an update, so this situation could never happen. then you'd have double-buffered output that you could blit to from any thread without issues)
it's all up to windows at that point. how does win7's blit work? does it send directly to the card where it keeps a double-buffer of your window so you can update in the middle of when it's refreshing? it probably does, i don't see how it couldn't since the double-buffer situation needs to happen between the memory you store, the blit, and the memory on the video card anyway. that's required for the hardware compositing to work, so it must work that way unless there is some better way i'm not thinking of.
(right? just to clarify, since it keeps your buffer on the video memory anyway, it won't call wm_paint during an update, so this situation could never happen. then you'd have double-buffered output that you could blit to from any thread without issues)
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
-
tony tony chopper tony tony chopper https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=3103
- KVRAF
- 3561 posts since 20 Jun, 2002
so if you're not painting from another thread, I see zero benefit and only downsides in the way you're repainting your GUI
DOLPH WILL PWNZ0R J00r LAWZ!!!!
- KVRAF
- 12615 posts since 7 Dec, 2004
what downsides? any downside you've pointed out i've already explained doesn't actually occur.
here are the upsides:
1) the host can manage framerate between plugins individually. if one plugin uses a huge amount of time doing updates, it can be redraw less often to balance the load so other plugins don't lag because of the "naughty" plugin
2) the host can balance gui updates in general against window messages to ensure that keystrokes, mouse clicks and other events arrive on time, so the gui remains responsive even if someone decided to do software raytracing in realtime in their gui
3) it's possible to hide windows instead of closing them without modifying the code for the plugin to stop it from drawing into it's non-existing window by just not calling idle anymore
here is one true potential downside:
1) it uses some memory, probably a fifth of a percent per plugin for the average daw's memory, at most, assuming the plugin's gui is 1920x1600 resolution (that is: (1920*1600*4) / (1024*1024*1024*4), assuming 4gb of ram)
but you have to keep note that most plugins use huge backgrounds, knob strips, lights, fonts and so on and all these content is store uncompressed in the plugin's memory. for example if you use freetype to render text, all that data for glyphs is stored in multiple formats including vector and bitmap in several places in memory. if windows is used to render text, it also stores the bitmap in memory but at least it can be shared between processes, assuming they use exactly the same font, size, weight and so on.
also, most plugins use a lot more of memory just for the audio buffers they keep internally, or even event lists.
here you're talking to me - someone who is more concerned about memory use than anyone, someone who _has_ written lots of stuff on embedded 1kb systems - and you're telling me i'm wasting memory. i know exactly how much memory i'm using and why, and i can justify all of it. memory is less valuable here than cpu time, therefore when you can make a trade like 1mb for 1second, it's worth it by far. if this 1second period regularly happens more than once, it's suddenly so worth it you'd be insane not to use up the meg.
i do draw lots of stuff in software, but you still need to keep your own canvas to accomplish this. gdi's, gdi+'s, and most other available interfaces just don't supply the code needed to produce the kind of results i'm looking for. in some cases accomplishing things in software would take so much cpu time it doesn't make any sense at all to even attempt to do it. remember that code takes up space as well - would you throw a fit about your binary being 1mb more for including lots of stl objects when it could have added 200kb for a pre-rendered bitmap? an exaggerated case of course, but a case that could easily occur. it only seems an exaggeration because nobody would be crazy enough to actually do it.
here are the upsides:
1) the host can manage framerate between plugins individually. if one plugin uses a huge amount of time doing updates, it can be redraw less often to balance the load so other plugins don't lag because of the "naughty" plugin
2) the host can balance gui updates in general against window messages to ensure that keystrokes, mouse clicks and other events arrive on time, so the gui remains responsive even if someone decided to do software raytracing in realtime in their gui
3) it's possible to hide windows instead of closing them without modifying the code for the plugin to stop it from drawing into it's non-existing window by just not calling idle anymore
here is one true potential downside:
1) it uses some memory, probably a fifth of a percent per plugin for the average daw's memory, at most, assuming the plugin's gui is 1920x1600 resolution (that is: (1920*1600*4) / (1024*1024*1024*4), assuming 4gb of ram)
but you have to keep note that most plugins use huge backgrounds, knob strips, lights, fonts and so on and all these content is store uncompressed in the plugin's memory. for example if you use freetype to render text, all that data for glyphs is stored in multiple formats including vector and bitmap in several places in memory. if windows is used to render text, it also stores the bitmap in memory but at least it can be shared between processes, assuming they use exactly the same font, size, weight and so on.
also, most plugins use a lot more of memory just for the audio buffers they keep internally, or even event lists.
here you're talking to me - someone who is more concerned about memory use than anyone, someone who _has_ written lots of stuff on embedded 1kb systems - and you're telling me i'm wasting memory. i know exactly how much memory i'm using and why, and i can justify all of it. memory is less valuable here than cpu time, therefore when you can make a trade like 1mb for 1second, it's worth it by far. if this 1second period regularly happens more than once, it's suddenly so worth it you'd be insane not to use up the meg.
i do draw lots of stuff in software, but you still need to keep your own canvas to accomplish this. gdi's, gdi+'s, and most other available interfaces just don't supply the code needed to produce the kind of results i'm looking for. in some cases accomplishing things in software would take so much cpu time it doesn't make any sense at all to even attempt to do it. remember that code takes up space as well - would you throw a fit about your binary being 1mb more for including lots of stl objects when it could have added 200kb for a pre-rendered bitmap? an exaggerated case of course, but a case that could easily occur. it only seems an exaggeration because nobody would be crazy enough to actually do it.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
-
tony tony chopper tony tony chopper https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=3103
- KVRAF
- 3561 posts since 20 Jun, 2002
That doesn't make any sense, I won't even argue if a host could do what you describe, but no host ever will, even just for the reason that the host can't know if you're repainting directly from inside the idle (which no other existing plugin probably does).
DOLPH WILL PWNZ0R J00r LAWZ!!!!
- KVRAF
- 12615 posts since 7 Dec, 2004
yes but which downsides?
does your host call idle every message, or does it keep sending messages until the buffer is empty like
while (peekmessage)
{
translate;
dispatch;
}
...since if it does that, you actually technically already implement the feature. you just never thought of measuring the time with clock() or limiting it to 60fps, (only call once every x number of peekmessage loops) or if it starts to take too long, start to skip it more often. all easy to implement, all will improve your host. going as far as individually limiting each plugin would be a bit overkill, but in some cases improve user experience for sure.
all plugins must update animation from in idle, otherwise they'd need to have their own timer thread and double-buffering like we've discussed. so we can say for fairly certain that in fact a lot of plugins update from idle, a lot of hosts control idle frequency, and it's certainly a worth-while feature that stienberg just never mentioned. i'm pretty sure this was the idea for idle when it was implemented, but somebody forgot why.
does your host call idle every message, or does it keep sending messages until the buffer is empty like
while (peekmessage)
{
translate;
dispatch;
}
...since if it does that, you actually technically already implement the feature. you just never thought of measuring the time with clock() or limiting it to 60fps, (only call once every x number of peekmessage loops) or if it starts to take too long, start to skip it more often. all easy to implement, all will improve your host. going as far as individually limiting each plugin would be a bit overkill, but in some cases improve user experience for sure.
all plugins must update animation from in idle, otherwise they'd need to have their own timer thread and double-buffering like we've discussed. so we can say for fairly certain that in fact a lot of plugins update from idle, a lot of hosts control idle frequency, and it's certainly a worth-while feature that stienberg just never mentioned. i'm pretty sure this was the idea for idle when it was implemented, but somebody forgot why.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
-
tony tony chopper tony tony chopper https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=3103
- KVRAF
- 3561 posts since 20 Jun, 2002
idling is a timer function at a fixed frequency, according to the VST SDK, and we don't take any liberty with itdoes your host call idle every message, or does it keep sending messages until the buffer is empty like
DOLPH WILL PWNZ0R J00r LAWZ!!!!
