VSTGUI 3.6 Windows 7 GDI+ Sluggishness: A Workaround...

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

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?
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.

Post

you "hide" windows in your host?
when the user closes a window it doesn't stop existing
if the window is behind another one, the knobs aren't moving anyway
why not?
most hosts call open/close rather than just hiding the window, in which case i don't think you can get a dc.
& a lot of plugins take ages to create their editor or don't restore stuff properly
so the blit would never happen, but the updates still would apply to the cache.
if you keep a giant cache even for editors that aren't visible, it's worse than I thought
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?
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 plugin
are we talking about wastefully drawing a couple pixels along the edge that aren't animated and only redraw once anyway?
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?
DOLPH WILL PWNZ0R J00r LAWZ!!!!

Post

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.
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.

Post

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
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.

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.


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.
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?

Post

nollock wrote:
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.
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.
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).

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).

Post

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.
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: 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?
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.

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.

Post

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.
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.
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).
i'd think it isn't actually a problem in the first place. all graphical operations occur in the same thread.
you said you were painting in your cache from another thread
DOLPH WILL PWNZ0R J00r LAWZ!!!!

Post

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.
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.

Post

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!!!!

Post

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)
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.

Post

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!!!!

Post

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.
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.

Post

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!!!!

Post

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.
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.

Post

does your host call idle every message, or does it keep sending messages until the buffer is empty like
idling is a timer function at a fixed frequency, according to the VST SDK, and we don't take any liberty with it
DOLPH WILL PWNZ0R J00r LAWZ!!!!

Post Reply

Return to “DSP and Plugin Development”