Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Qt Text Rendering is extremely slow... any way to speed up?
Forum Updated to NodeBB v4.3 + New Features

Qt Text Rendering is extremely slow... any way to speed up?

Scheduled Pinned Locked Moved Unsolved General and Desktop
16 Posts 5 Posters 7.0k Views 5 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    primem0ver
    wrote on last edited by
    #1

    I am converting a program from C# on the .NET platform (using the normal System.Drawing methods) to Qt. As soon as I added text to the drawing process for my control (widget), the time it took to render the control went up from a smooth scrolling, to taking several seconds to draw a single frame before the scroll continues. The amount of time the text is taking is insane.

    I have researched this issue on the internet and while I realize there may be some difference due to the exact way the text is drawn. the difference pointed out in this post of a test is still staggering: http://www.amigans.net/modules/xforum/viewtopic.php?forum=38&topic_id=5184&order=

    Is there any way to speed up the process? The only difference between the old and the new way of doing things (from my end) is that I am now using a callback to get the needed data rather than a large switch case statement. (The text that is actually drawn depends on the text "mode" because there are several points of data that need to be available).

    Here is my widget's paint method:

    void LabMapWidget::paintEvent(QPaintEvent* event)
    {
    	// final layer
    	QPainter widgetPainter(this);
    	QSize size = mFormat->mapSize(mMap->width(), mMap->height());
    	this->setMinimumSize(size);
    	this->resize(size);
    	
    	GlobalData::setPainter(&widgetPainter);
    	mMainMode->renderData();
    
    	// this line draws the text when appropriate
    	if ((GlobalData::scale() >= MIN_SPRITE_ZOOM) && mDataMode)
    		mDataMode->renderData();
    	GlobalData::clearPainter();
    }
    

    The "mDataMode" is a class derived from my data mode interface. Here is an example method that actually draws the text (since there are several text/data modes)

    #define SURFACE GlobalData::painter()
    ...
    void Coordinates::renderData()
    {
    	SURFACE->setFont(QFont("Microsoft Sans Serif", 7, QFont::Bold));
    	for (int x = 0; x < MAP()->width(); ++x)
    	{
    		for (int y = 0; y < MAP()->height(); ++y)
    		{
    			QString string = QString::number(x) + ",\n" + QString::number(y);
    			SURFACE->setPen(Black);
    			SURFACE->drawText(LabMapWidget::cellFormat()->getSpriteRect(x, y), Qt::AlignCenter, string);
    		}
    	}
    }
    
    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      Small details but do you really need to set the pen at each iteration ?

      Why not retrieve the with and height of MAP at the beginning of the function before the loop ?

      What size is that MAP object ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • P Offline
        P Offline
        primem0ver
        wrote on last edited by primem0ver
        #3
        1. Each cell is drawn as an individual unit as a square or hex (depending on the map type). Eventually the plan is to adapt the pen to the background as some map cells are dark colored and some are light colored... so yes.

        2. Sure, I can do that. But it isn't what is causing the delay here. The method for drawing the tiles themselves use the same set of changes for each cell... so that isn't what is causing the time here.

        3. The "size" is the map size in cells. The widget itself is a rendering of all these cells. Maps can be of any size but currently they do not go above somewhere around 200 x 120.

        kshegunovK 1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          I'm was looking to eliminate the unneeded time consuming stuff.

          How many maps can there be ?

          I'm also wondering why you resize the widget in the paint event. Sounds like you might be losing time there depending on the refresh speed.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0
          • P primem0ver
            1. Each cell is drawn as an individual unit as a square or hex (depending on the map type). Eventually the plan is to adapt the pen to the background as some map cells are dark colored and some are light colored... so yes.

            2. Sure, I can do that. But it isn't what is causing the delay here. The method for drawing the tiles themselves use the same set of changes for each cell... so that isn't what is causing the time here.

            3. The "size" is the map size in cells. The widget itself is a rendering of all these cells. Maps can be of any size but currently they do not go above somewhere around 200 x 120.

            kshegunovK Offline
            kshegunovK Offline
            kshegunov
            Moderators
            wrote on last edited by
            #5

            @primem0ver

            To add to @SGaist, resizing will cause implicit update() to be issued, so you'll get additional paint event(s). Also, to be absolutely frank, that code you've posted looks terrible. It's all coupled and tangled up, and that's leaving aside the macro(s) and the global(s) ...

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            0
            • P Offline
              P Offline
              primem0ver
              wrote on last edited by primem0ver
              #6

              All your points are non issues. They were all being done before the addition of the text. Without the text, the scrolling runs smoothly and it doesn't take much time to render. But to answer your questions anyway...

              1. There is only one map loaded at a time.

              2. Resizing the control is necessary because it is on a scrollable surface. If the current zoom is low enough that the map is entirely visible, no scrolling should take place. Otherwise, the control must be resized to fit the entire map so that the scroll bar is sized appropriately. EDIT: I suppose I could just disable scrolling if the maps size is too small... but I would prefer it not be there; and as I said earlier... resizing is not causing an issue.

              3. Please explain to me how it is "terrible." I really hope this isn't a comment on how the code looks... because 1) it is entirely irrelevant to the problem 2) that is your opinion, and to be frank... 3) I have been told that my coding is generally much easier to read that other peoples... so to each his own. If you mean that it looks like a bad algorithm, then please justify/explain your statement.

              kshegunovK 1 Reply Last reply
              0
              • E Offline
                E Offline
                euchkatzl
                wrote on last edited by
                #7

                On which os are you working ?

                On OS X you can start XCode Developer Tool called Instruments (Time Profiler).
                There you can exactly see whats is responsible for the slow execution time.

                On the first look i'm also @kshegunov opinion. Resizing the widget in the paint event should never be done !!

                As he mentioned it causes implicit an update of your widget which then results in another paint event.
                Did you get that ? In your case there are 3 times more paint events than normal (which of course makes the execution slower)

                So try it out...without the setMinimumSize and resize calls it will be faster !

                1 Reply Last reply
                0
                • P primem0ver

                  All your points are non issues. They were all being done before the addition of the text. Without the text, the scrolling runs smoothly and it doesn't take much time to render. But to answer your questions anyway...

                  1. There is only one map loaded at a time.

                  2. Resizing the control is necessary because it is on a scrollable surface. If the current zoom is low enough that the map is entirely visible, no scrolling should take place. Otherwise, the control must be resized to fit the entire map so that the scroll bar is sized appropriately. EDIT: I suppose I could just disable scrolling if the maps size is too small... but I would prefer it not be there; and as I said earlier... resizing is not causing an issue.

                  3. Please explain to me how it is "terrible." I really hope this isn't a comment on how the code looks... because 1) it is entirely irrelevant to the problem 2) that is your opinion, and to be frank... 3) I have been told that my coding is generally much easier to read that other peoples... so to each his own. If you mean that it looks like a bad algorithm, then please justify/explain your statement.

                  kshegunovK Offline
                  kshegunovK Offline
                  kshegunov
                  Moderators
                  wrote on last edited by kshegunov
                  #8

                  @primem0ver

                  Resizing the control is necessary because it is on a scrollable surface.

                  It may very well be necessary, but it shouldn't happen when drawing. Issue the resize from outside (i.e. the containing object) and in the paintEvent override only do the painting.

                  Please explain to me how it is "terrible".

                  Nothing to do with the looks. Your code style is good and clearly understandable, your design choice is what I was referring to. From the short snippet you provided it appears you've jumped through all kinds of hoops to couple you objects up. For one, they all use something called GlobalData which is suspicious by itself. What's the reason for it? Why are Coordinates painting, it doesn't make sense? Are Coordinates coordinates, or are they CoordinatesRenderer, or something else? And why Coordinates have any knowledge that there's such a thing as LabMapWidget?! Same reasoning for modes, a mode shouldn't care at all that there's such a thing as painting, much less do the painting ...

                  Read and abide by the Qt Code of Conduct

                  P 2 Replies Last reply
                  0
                  • kshegunovK kshegunov

                    @primem0ver

                    Resizing the control is necessary because it is on a scrollable surface.

                    It may very well be necessary, but it shouldn't happen when drawing. Issue the resize from outside (i.e. the containing object) and in the paintEvent override only do the painting.

                    Please explain to me how it is "terrible".

                    Nothing to do with the looks. Your code style is good and clearly understandable, your design choice is what I was referring to. From the short snippet you provided it appears you've jumped through all kinds of hoops to couple you objects up. For one, they all use something called GlobalData which is suspicious by itself. What's the reason for it? Why are Coordinates painting, it doesn't make sense? Are Coordinates coordinates, or are they CoordinatesRenderer, or something else? And why Coordinates have any knowledge that there's such a thing as LabMapWidget?! Same reasoning for modes, a mode shouldn't care at all that there's such a thing as painting, much less do the painting ...

                    P Offline
                    P Offline
                    primem0ver
                    wrote on last edited by primem0ver
                    #9

                    @kshegunov
                    LOL. Ok. Now I get it. The reason for your objection is because you don't understand the nature of the application. FYI... this is NOT the big application I am talking about in my post in the general lounge about the commercial cost. This is a second major application that I decided to convert to C++ because that is the target language anyway.

                    The purpose of this application is to come up with a very complex algorithm for creating realistic maps in a gaming environment. I am a "civfanatic" and a map "fetishist" (I have been obsessed with maps since I was bout 6-7 years old; I became the navigator for family trips are around 10.). I also was an Earth science teacher for 5 years. Here are the list of constraints I put on myself for this program after working with my first version in pure C#.

                    1. This version of application must be able to deal with more than one type of tile because of the up and coming release of Civ 6 (as well as Civ 5). Currently both squares and hexes are supported.. eventually I will hopefully introduce an ISEA (Isocohedral Equal Area) grid on a true spherical globe (made of a combination of hexes and pentagrams. A soccer ball is an example of a kind of ISEA grid. The "Cell Format" is the interface that deals with this particular aspect of the program.

                    2. "Modes" DO take care of the painting if that is the whole point of the "mode." Since much of what I am doing is based on intuition and trial and error in addition to research and my training, I need to be able to view a long list of points of data and be able to switch between them instantly; even superimpose them. (A few dozen already exist... think elevation, temperature, shore distance, precipitation, etc...). Superimposing the text itself is unlikely considering the time it would take... but I have already done it with color.

                    I decided to consolidate code by using a "data" class which is what I am referring to by mode. The "coordinates" data mode is the mod that is chosen when I need to see the plot coordinates on the screen. Before, adding new drawing/data modes was an annoyingly lengthy process that involved changing several sections of code (switch case statements etc...) I have simplified the process tremendously. All data points now inherit a template class interface that handles the retrieval of data (using a typed delegate/callback... hence the need for a template) and "rendering" it on the map. The class is fairly simple and only involves creating a constructor, a render method (that was originally stuck in at least one case in switch case statements), and adding a single line for creating the single class instance. "Main mode' refers to the primary data that is being colored. The "data mode" refers to the data being printed (or illustrated in the case of wind/current direction). Eventually I will add at least one more "secondary" mode that will be color blended with the primary mode.

                    1. Global Data is a class of static/global data that needs to be shared with all classes.

                    Let me show you PART of an image exported by the previous version of the application to give you an idea of the nature of the program. Here is a strip from a world map image exported by the original program. The current "data mode' is global wind direction (with the size of the arrow based on relative wind speed). The current "main mode" (coloration) is plot type (blue = ocean, light blue = coast, green = plains, yellow = hills, orange = mountains). No mixing here so there is no secondary mode selected. Perhaps I should use another word besides "mode"... but hopefully you get the idea.

                    Just in case you are curious about details regarding the project, there are several threads I started on Civfanatics that revolve around this engine. The main one is here.

                    1 Reply Last reply
                    0
                    • SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      Interesting background ! That shed some lights for other suggestions. You should then maybe avoid doing it with widgets and go for the Graphics View framework. It looks like it should be more suited for your needs.

                      On a side note, maybe the Marble project could be of interest.

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      1 Reply Last reply
                      1
                      • P Offline
                        P Offline
                        primem0ver
                        wrote on last edited by primem0ver
                        #11

                        @SGaist
                        I remember you mentioning this or something similar when I was asking questions about combining views (i.e. "layers"; now that you have an understanding of the goal, I can be specific... I was talking about combining the primary/main view with the secondary and possibly more views).

                        I will go ahead and give the framework a shot to see if text rendering is faster there.

                        A 1 Reply Last reply
                        0
                        • kshegunovK kshegunov

                          @primem0ver

                          Resizing the control is necessary because it is on a scrollable surface.

                          It may very well be necessary, but it shouldn't happen when drawing. Issue the resize from outside (i.e. the containing object) and in the paintEvent override only do the painting.

                          Please explain to me how it is "terrible".

                          Nothing to do with the looks. Your code style is good and clearly understandable, your design choice is what I was referring to. From the short snippet you provided it appears you've jumped through all kinds of hoops to couple you objects up. For one, they all use something called GlobalData which is suspicious by itself. What's the reason for it? Why are Coordinates painting, it doesn't make sense? Are Coordinates coordinates, or are they CoordinatesRenderer, or something else? And why Coordinates have any knowledge that there's such a thing as LabMapWidget?! Same reasoning for modes, a mode shouldn't care at all that there's such a thing as painting, much less do the painting ...

                          P Offline
                          P Offline
                          primem0ver
                          wrote on last edited by primem0ver
                          #12

                          @kshegunov and @euchkatzl
                          Yeah you're right about the resizing... bad idea. I am surprised it doesn't do a recursive call then. I don't think it will change the non-recursive number of times the paint method is called for a zoom in/out event but it was simply a bad move.

                          kshegunovK 1 Reply Last reply
                          0
                          • P primem0ver

                            @kshegunov and @euchkatzl
                            Yeah you're right about the resizing... bad idea. I am surprised it doesn't do a recursive call then. I don't think it will change the non-recursive number of times the paint method is called for a zoom in/out event but it was simply a bad move.

                            kshegunovK Offline
                            kshegunovK Offline
                            kshegunov
                            Moderators
                            wrote on last edited by kshegunov
                            #13

                            @primem0ver said:

                            I am surprised it doesn't do a recursive call then.

                            Qt tries to be, and in many cases succeeds in being, smart about events (input and window events especially) and their dispatching. The paint event is not issued immediately but is put in the event queue and is also sometimes subject to compression.

                            Read and abide by the Qt Code of Conduct

                            1 Reply Last reply
                            0
                            • P primem0ver

                              @SGaist
                              I remember you mentioning this or something similar when I was asking questions about combining views (i.e. "layers"; now that you have an understanding of the goal, I can be specific... I was talking about combining the primary/main view with the secondary and possibly more views).

                              I will go ahead and give the framework a shot to see if text rendering is faster there.

                              A Offline
                              A Offline
                              Asperamanca
                              wrote on last edited by
                              #14

                              @primem0ver said:

                              @SGaist
                              I remember you mentioning this or something similar when I was asking questions about combining views (i.e. "layers"; now that you have an understanding of the goal, I can be specific... I was talking about combining the primary/main view with the secondary and possibly more views).

                              I will go ahead and give the framework a shot to see if text rendering is faster there.

                              Don't be too disappointed, though. Rendering of glyphs is a complex task, and neither Widgets nor GraphicsView makes use of the GPU or even multiple threads.

                              However, GraphicsView makes it pretty easy to cache painted items: Unless you change the text or looks of an item, there's no need to re-render the glyphs every time.

                              P 1 Reply Last reply
                              0
                              • A Asperamanca

                                @primem0ver said:

                                @SGaist
                                I remember you mentioning this or something similar when I was asking questions about combining views (i.e. "layers"; now that you have an understanding of the goal, I can be specific... I was talking about combining the primary/main view with the secondary and possibly more views).

                                I will go ahead and give the framework a shot to see if text rendering is faster there.

                                Don't be too disappointed, though. Rendering of glyphs is a complex task, and neither Widgets nor GraphicsView makes use of the GPU or even multiple threads.

                                However, GraphicsView makes it pretty easy to cache painted items: Unless you change the text or looks of an item, there's no need to re-render the glyphs every time.

                                P Offline
                                P Offline
                                primem0ver
                                wrote on last edited by primem0ver
                                #15

                                @Asperamanca so basically you're saying it won't change the text rendering speed? That would be rather annoying after spending a day and a half of changing my code to work with the graphics view. (Close to being done)

                                Another question that I have about the QGraphicsView. I need to change the way it detects zoom events. If the mouse is scrolled normally I want to scroll the picture down. If the shift is held down while the mouse is scrolled, THEN I want it to zoom.

                                1 Reply Last reply
                                0
                                • P Offline
                                  P Offline
                                  primem0ver
                                  wrote on last edited by primem0ver
                                  #16

                                  @SGaist and everyone else interested...

                                  The QGraphicsView does speed up drawing text enough that the control is usable in that regard. However, there are three issues with it (in order of importance).

                                  1. Scrolling horizontally causes white lines to appear, Not sure why. They appear to be made of cached text from the "text" layer of objects that are being drawn on top of the picture. They clear when I scroll vertically but unless I do that it makes the view unusable.
                                  2. It takes a substantial amount of time to create the view.
                                  3. It takes a horrendous amount of time to destruct the view.

                                  I believe the time issue stems from the fact that there are so many objects to create and destroy (rather than simply drawing them manually).

                                  1 Reply Last reply
                                  0

                                  • Login

                                  • Login or register to search.
                                  • First post
                                    Last post
                                  0
                                  • Categories
                                  • Recent
                                  • Tags
                                  • Popular
                                  • Users
                                  • Groups
                                  • Search
                                  • Get Qt Extensions
                                  • Unsolved