Setting a waveform sample position in a timerCallback causes flickering

I was just asking you to try it so perhaps may be able to see it for yourself.

BTW a simple fix for this kind of ordering issue is just to repaint slightly more area than you need. For example you could create a cursor which is twice as wide as it needs to be, with the line in its centre.

And TBH that’s a better design for something like this anyway, as it means the line can use sub-pixel positioning, which you can’t do with just a component, which has integer coordinates. And if you ever want it to be draggable with the mouse, you’ll want a wider component anyway.

Thanks, but I don’t need to see it! Already understand what must be happening. But it’s not something that’s a “bug” we can fix, it’s just an unfortunate emergent behaviour of the event queue timings you get when you run this particular bit of GUI on a machine of a certain spec.

Adding other timers, threads, or other repainting will probably change the behaviour, but don’t obsess over this - try my suggestion above of just using a wider component.

I’ve made the needle 20 pixels wide. Just drawing the centre line still gives the flicker.
I can send a repaint of the wider area on the parent of the needle and it’s then OK until the needle moves at larger speeds - then I suppose I’ll have to calculate the entire movement area and redraw that, which will be slow to render, and all this is supposed to be handled for me.

I guess I’ll just have to wait for my first customer to complain about it, hopefully not.
It’s kinda disappointing - any chance of a DirectX renderer?
Dave

1 Like

Well yes - that’s exactly what I was suggesting! Obviously if you don’t do that, and still just paint the same pixels as before then it will do the same thing as before (!)

I’m sorry if you didn’t understand my attempts to explain what’s going on, but I did my best…

TL;DR: The renderer won’t make the slightest bit of difference!

You could find a way to get this same effect with ANY rendering engine, on ANY platform, if you manage get the order of the repaint/timer events just perfectly out-of-sync with each other somehow.

The fact that I’ve never seen it in any of my apps and nobody else has ever mentioned it on here shows just how rare it is to get a situation where anyone would notice.

I’m sorry that you seem to have hit the perfect-storm conditions for it, but it’s not a bug, nor is it specific to JUCE or anything else we could “fix”.

Juce is currently really slow at redrawing stuff in Windows, and yes I understand my 8 core processor is the ‘perfect storm’, but it’s funny how my 8 year old iMac can handle everything just fine.

Sigh… Like I said about 5 times now, what you’re seeing is a side-effect of the order in which the paint and timer callbacks happen. How fast a machine does the drawing is irrelevant.

DirectX can render millions of polygons in a single frame, and I can’t draw a little red line at 25 frames a second. LOL.

1 Like

The time used to argue should be used to find the real reason for the behavior.

if in Component::setBounds, which invalids the repaint rects (via repaintParent), the old and new-position rect will be consolidated first to one rect, could this be a solution?

It does consolidate!

I just discovered I can now get the problem when I change resolution from 3840x2160 to 1920x1080.
WTF!
Could it be that no-one has drawn a 2 pixel wide moving line before? Your dsp example repaints the whole waveform every time, like I mentioned.

Does the same thing happen with the JUCE demo “Audio: File Playback” page on your system?

Dave96 Yes, ‘Audio: File Playback’ pointer flickers as though it’s off half of the time, so it kind of blinks across the screen - this is after I change resolution or go into sleep mode. It’s fine if I’ve just done a restart. (Using latest ‘master’ from Github)

NO IT DOESNT

DBG("Begin");

needle.setBounds(posX, 0, 2, area.getHeight());

DBG("End");

in win32 Windowing

  void repaint (const Rectangle<int>& area) override
    {  
		DBG(area.toString());
        const RECT r = { area.getX(), area.getY(), area.getRight(), area.getBottom() };
        InvalidateRect (hwnd, &r, FALSE);
	
    }

Result

Begin
721 4 2 192
724 4 2 192
End

Yes, Windows MIGHT consolidate but OBVIOUSLY it doesn’t do it always, because OTHERWISE than we wouldn’t have this issue with the disappearing bar

PS: did you actually look 5 seconds in the sample-code, its actually only moving a component a few pixels, not a rare edge-case

PS: with consolidation i mean, find the biggest rectangle for the old and the new position, even if uninvolved pixels are repainted, which might be not an ideal solution far all kind of repaint (i also not like that behaviour) , but possibly this is okay, for setting new component-bounds .

So I’ve just tested this out on Windows 10 using your example code and I can reproduce it with faster timer intervals (around 60Hz). However this definitely looks like a fault with how win32 handles the invalidated RECTs when repainting - it seems the order in which the paint and timer callbacks are happening is wrong. You can verify this by using the OpenGL renderer as this results in smooth repainting of the needle position, similarly the macOS renderer handles this code just fine. A quick google of “InvalidateRect flicker” also shows a lot of other people experiencing a similar sort of problem.

Unfortunately that means that there’s not much we can do to improve the situation on our side, so I’d recommend just using the OpenGL renderer in your app.

Thanks for actually looking at the code, guys.
Why are you using win32 stuff? I don’t quite understand.

Can anyone show me where your double buffering code is?

I”ve used OpenGL in my plugins before, although it’s fast the install base is not that good on Windows, plus customers can get a little uptight when they can’t run things, so the admin goes up. Although it’s a little better now in the post Minecraft days. Shame about DirectX though.

1 Like

Would Direct2D version of the renderer avoid stuff like that ?

No. It would not.

Like Ed explained, this is an artefact of the way in which the win32 invalidation system sends WM_PAINT events. The rendering engine is irrelevant to the issue. It’s an event-loop and rectangle consolidation problem.

(And just to clarify, since for some reason this thread just seems to be full of people failing to understand things: the reason GL works better has nothing to do with it being GL, it’s just because for that renderer, we replace the win32 invalidation system with our own version which doesn’t have this particular behaviour)

Can someone tell me where the back buffer is splatted to the screen?

Please tell me you’re not asking that because you still think it has any relevance to the original problem…?