Jump to content
Rafal.B

Very poor responsiveness of components on the form in D13-FMX

Recommended Posts

Hello everyone,

I have a SCADA-style application (FMX).
It contains several threads, each of which communicates with a PLC, reads data from it, and enqueues it using TThread.Queue to synchronize with the main thread. Each queue entry represents a change in some value (appearance) of a visual component. A single read may involve 300–600 data points.
On the main form, I also have a TTimer that updates the current time in a TLabel every 1000ms. There are also a few buttons on the form.
In D12, everything works very well. The form's responsiveness is normal (very good).
Unfortunately, something has changed in D13. Visual components updated via TThread.Queue are refreshed correctly, but the time display from TTimer refreshes only every 3–15 seconds. Button response is also similarly delayed.
It looks as if the handling of TThread.Queue (on the main thread side) consumes 99.9% of the main thread's time.
It seems to be a problem with modifying a large number of components on the screen (at least that’s my impression), but...
Let me repeat — in D12 everything worked flawlessly.
I have no idea what they changed, but D13 is starting to feel like bad luck 😞
Any suggestions on where to start looking for a solution would be greatly appreciated.
I know this is a very general description, but I’m unable to share the source code.

Edited by Rafal.B

Share this post


Link to post

I realize this is a rather complex topic.
I've determined that the problem is 99% related to graphics display.
Running one of the animations (TFloatAnimation) that changes the X position of an element (TPatch)
causes the main thread to lock (screen unresponsive). But not always. It's difficult to diagnose.
First, I wanted to disable the Display Link Service, but unfortunately, there doesn't seem to be an option.
I'm looking for detailed information on the changes to FMX support introduced in D13.
Unfortunately, it's hard to find anything useful.

Share this post


Link to post

I don't use FMX but it sounds like a message flood; Something is causing messages to be posted to the queue and the handling of those messages causes more messages to be posted, etc. Likely at a faster rate than you can process them.

WM_TIMER and WM_PAINT are low priority, synthesized messages; They are generated by Windows when there are no other messages in the queue and either the internal timer or invalidate flag has been set.

 

Try to rate-limit your updates somehow. E.g. don't update more than once every 10 milliseconds. If that doesn't help, try lowering the rate (i.e. increase the delay). At some point your WM_TIMER messages should start to be handled at the normal rate.

You can also try to disable update of all your items and then enable them one after the other.

 

None of this will solve your problem, but maybe it can give you some data about where to focus.

Edited by Anders Melander

Share this post


Link to post

 

9 hours ago, Anders Melander said:

None of this will solve your problem, but maybe it can give you some data about where to focus.

 

4 hours ago, Pat Heuvel said:

Are your visual component updates wrapped in BeginUpdate/EndUpdate?

Still general, but with more detail:
The program (thread in background) receives 300–600 data items every 100ms.
They are sent to a queue (I replaced TThread.Queue with TThreadedQueue to gain more control).
On the main thread side, a TTimer (Interval = 50ms) retrieves data from the queue and performs preliminary filtering (unchanged data is discarded).
In practice, only 0–15(20) items remain that require component updates.
This mostly involves changing the Visible or Text properties,
less frequently triggering color (TColorAnimation) or position (TFloatAnimation) animations. And that’s all.
There’s not even a need to wrap this in BeginUpdate/EndUpdate.
Is that really a lot?
During testing, the program was stressed with up to 4000 data items every 100ms.
There were no issues with handling that load. Everything ran smoothly and responsively.
But that was done in Delphi 12. That’s why I chose to implement this project in that environment.
Unfortunately, Delphi 13 flipped the table.
From a quick glance, I see that they replaced the previous AniThread with a new "Display Link Service" for handling animations.
That’s where I believe the root of my problems lies.
I want to report this to QP, but there’s no room there for a sufficiently detailed problem description.
Can I include a link to this topic as the problem description?

Edited by Rafal.B

Share this post


Link to post
On 10/23/2025 at 8:47 PM, Rafal.B said:

Any suggestions on where to start looking for a solution would be greatly appreciated.

Have you tried to use a profiler to see where the bottleneck is?

Share this post


Link to post
24 minutes ago, Rafal.B said:

Can I include a link to this topic as the problem description?

Sure, but without a minimal reproducible example or a description of exactly where/what the bug is there's not much more to report than "I have a problem".

  • Like 1

Share this post


Link to post
26 minutes ago, Cristian Peța said:

Have you tried to use a profiler to see where the bottleneck is?

No, I haven't used it. Which one would you recommend?

 

17 minutes ago, Anders Melander said:

Sure, but without a minimal reproducible example or a description of exactly where/what the bug is there's not much more to report than "I have a problem".

That's why I haven't reported it yet 🙂

Share this post


Link to post
30 minutes ago, Rafal.B said:

No, I haven't used it. Which one would you recommend? 

I would use map2pdb with Intel VTune because I have more experience with.

Share this post


Link to post
5 minutes ago, Cristian Peța said:

I would use map2pdb with Intel VTune because I have more experience with.

Thanks. I'll try.

Share this post


Link to post
32 minutes ago, John van de Waeter said:

Just a guess... do you use the Application.OnIdle event?

No, I don't use it.

Share this post


Link to post
9 hours ago, Pat Heuvel said:

Are your visual component updates wrapped in BeginUpdate/EndUpdate? 

That would be my first guess too.
When using this on the Form or Frame level, those commands should be notified through all child components on that form as well:
https://docwiki.embarcadero.com/Libraries/Sydney/en/FMX.Forms.TCommonCustomForm.BeginUpdate

 

 

Edited by Rollo62
  • Like 1

Share this post


Link to post

In RAD Studio 13.0, animations attempt to link to the screen refresh rate, promoting a smoother animation (implemented in the new FMX.DisplayLink.*.pas units), instead to TTimer-based animations existing in RAD 12 or older. Although there is increased frame processing during animations to promote this fluidity, it is not expected to overload the application.
 

BeginUpdate and EndUpdate might solve this. If you are using the Skia render through GlobalUseSkia := True;, consider adding GlobalUseSkiaRasterWhenAvailable := False; to prioritize GPU rendering on Windows.


If none of this solves the problem, I suggest you try creating a simpler project simulating the problem for a bug report to QP.

Share this post


Link to post

Maybe I'm not being clearly understood.
I don't see any issue with computer overload. The same application running on D12 uses the same amount of CPU (~5%) and GPU (~30–40%) as when running on D13.
Animations that are already running continue to work smoothly. However, buttons and timers placed on the main form stop working. And yet, the running animations still perform smoothly 🙂 Clicking on the screen only causes a 'beep'. I'm not using Skia.
In my components, animations are configured via the object inspector, and in the code I only use ...Animation.Enable := True/False;
Where exactly should I place BeginUpdate/EndUpdate? I don't quite understand 🙂
I tried this:

BeginUpdate;
  ...Animation.Enable := True;
EndUpdate;

Unfortunately, it didn't help.
I guess I'll have to create something similar just to have something to send to QP.

 

Thanks  all for your interest in the topic.
 

Edited by Rafal.B

Share this post


Link to post
41 minutes ago, Rafal.B said:

Clicking on the screen only causes a 'beep'.

This is a clue.

Under various circumstances, DefWindowProc will emit a beep to indicate an error. I don't think it's really documented what the circumstances are.

Examples I know of are clicking on a form that has been disabled and calling DefWindowProc with an error code in one of the message params.

See also: https://www.google.com/search?q=DefWindowProc+beep

Share this post


Link to post

Interesting fact.
The program launched several times (4-5 times) in the IDE64 environment without any problems. Subsequent launches resulted in a known error. Nothing in the configuration had changed in the meantime.
It's like magic 🙂

Share this post


Link to post

No idea if it's related, but:

In my app, I have a thread that collects data from a server by TCP.

Before starting this thread, I enabled the TAniIndicator

When finished, the thread set a flag: new data available

In the main thread OnIdle event, I checked for this flag and if set, updated the UI, and at last disabled the AniIndicator

This worked okay until (I think) 12.3. 

 

In 12.3 it took quite a while (a few seconds) before the OnIdle event fired and my UI was updated.

I found that if I did NOT enable the AniIndicator, the OnIdle event fired immediately.

 

Somehow it looked like the AniIndicator 'eated' the OnIdle event.

I did not investigate the sourcecode

 

Well, FWIW :)

 

Share this post


Link to post
37 minutes ago, John van de Waeter said:

In 12.3 it took quite a while (a few seconds) before the OnIdle event fired and my UI was updated.

You can't expect the OnIdle event to be fired continuously. If it did, your application would consume 100% CPU regardless of it doing anything or not.

AFAIR, OnIdle is fired once when the message queue becomes empty.

 

Instead of using OnIdle, what you could have done was to post a message when the work was done, and then handle that message (update the UI, disable the animation, etc.) somewhere.

Share this post


Link to post
15 minutes ago, Anders Melander said:

You can't expect the OnIdle event to be fired continuously. If it did, your application would consume 100% CPU regardless of it doing anything or not.

AFAIR, OnIdle is fired once when the message queue becomes empty.

I know.

It's just that it used to work, and suddenly it didn't anymore. What the OP is about.

Share this post


Link to post

I'm trying to create a program that demonstrates the problem, but unfortunately, it's not working out.
This might be a serious issue.
I'm considering an alternative solution — using the old animation handling method in the new D13.
Is that possible?

Does this make sense?

Perhaps EMB could create a small Old/New Animation switch? 🙄🙂

Edited by Rafal.B

Share this post


Link to post

How much work / value updates is there in each item placed in the queue?  If it is only one update you could batch updates to some extent by putting a list of 1 or more value updates in a queue entry. That would reduce queue operations 

significantly. 

Share this post


Link to post

Unfortunately, I am unable to create a separate application that exhibits the same issues.
For the problems I previously described to occur, the original application must also operate in its natural environment (active TCP/IP connections with several PLCs). Any other attempt fails to produce the desired effect.
I am therefore forced to stick with these SCADA applications on Delphi 12, where everything works perfectly.
I know this has nothing to do directly with the computer's performance.
To simplify, the issue appears as if the message queue is no longer being handled by Application.ProcessMessages.
Perhaps a situation will arise that helps narrow down the search area.
In the meantime, thank you all for your interest and suggestions.
 

Share this post


Link to post
On 10/28/2025 at 9:13 AM, Rafal.B said:

I want to report this to QP, but there’s no room there for a sufficiently detailed problem description.

Plenty room. It expands. And, it takes attachments. Also, comments.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×