I am writing an application and there will potentially be tens of thousands of labels (a log-viewing application of a sort), most of them hidden with QWidget::hide(). I imagine a QLabel, when created, takes up some video memory. Now, does hide() free that video memory? Or will I have to QWidget::remove() most of those hidden labels to keep video memory usage at a reasonable level?
In general, most widgets do not store their pre-rendered images in memory. Instead, they are render themselves on demand after being invalidated. However, some do it if render is time-consuming. Took a look at QLabel source code (http://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/widgets/qlabel.cpp), it seems that QLabel caches its pixmap when scaledContents is enabled and scaling is necessary. Plain text-only labels are painted as-is without any caching.
Still, as #G.M mentioned, each widget consumes some system memory to store its own data, and processing time due to event handling, so producing 10k labels is a reasonable resource waste. In contrast, item views are single widgets that draws items on their surface. No event handling overhead, no unnecessary caches. Like QLabels, item view items are perfectly stylable, see http://doc.qt.io/archives/qt-5.8/stylesheet-examples.html#customizing-qlistview, http://doc.qt.io/archives/qt-5.8/stylesheet-examples.html#customizing-qtreeview for details. More complex looks like multi-line list items are achievable with QItemDelegate: Qt QListWidgetItem Multiple Lines
Related
I need to render lots (hundreds) of similar spheres and cylinders with different transforms. Currently this is achieved by creating hundreds of identical QEntity objects. The result is the app's constantly consuming 20..70% of CPU -- even when the scene is still.
Is there a default source of update events for the widget? If there is one, can I turn it off or reduce its frequency? There seems to be no other source of CPU load but the Qt3D widget.
Did you have a look at the enum of the QRenderSettings class? It seems like you can set the render policy to OnDemand which causes Qt to only render the scene when something changes.
Alternatively, if you don't need interaction with the scene you could have a look at my implementation of an offline renderer. The underlying QAspectEngine starts and stops whenever you set a root entity. You could set your root entity, capture the frame and unset the root entity, causing the graphics loop to stop which would result in less CPU load I would guess.
I have a QAbstractListModel with custom objects as items. Each object has a QImage that is loaded from a database. I use ListView in QML to visualize it but I do not see any mean to represent QImage in the delegate. Image primitive seems to accept only URLs.
Is the only way for me to show QImages is to create a QQuickImageProvider with some custom system of a URL per element (looks like a total overkill)?
I think QQuickImageProvider is the proper way.
Also, I think you can use the word 'overkill' if you know exactly how the Qt internals work. Otherwise it's just guessing.
AFAIK there is a complex caching system of images (and other data) underneath, so once an image pixmap is loaded (and doesn't change) data retrieval is immediate. So no overkill at all, since in any case at some point you need to load those QImage, but just once.
I believe a QQuickImageProvider provides pointers to the cached data, and not the whole rasterized data every time. Moreover blitting operations are nowadays performed with hardware accelerations, so it's a single operation taking a fraction of millisecond.
In other words you end up having:
give me image with url "image://xyz"
Qt looks up in the cache and returns the data pointer or performs a full load of the image if not found
the QML renderer passes the data array to OpenGL
one single blit operation (microseconds) and you have it on screen
A QML ShaderEffect will bind a QImage to a GLSL Sampler2D. See the list of "how properties are mapped to GLSL uniform variables" in the ShaderEffect docs. Needs a few lines of GLSL writing in the ShaderEffect to pass pixels through, (will update this post with an example sometime, when I have access to my code), but the result is a fast, QSG-friendly all-QML element which can render QImages.
I am trying to implemente a CoverFlow like effect using a QGLWidget, the problem is the texture loading process.
I have a worker (QThread) for loading images from disk, and the main thread checks for new loaded images, if it finds any then uses bindTexture for loading them into QGLContext. While the texture is being bound, the main thread is blocked, so I have a fps drop.
What is the right way to do this?
I have found that the default behaviour of bindTexture in Qt4 is extremelly slow:
bindTexture(image,target,format,LinearFilteringBindOption | InvertedYBindOption | MipmapBindOption)
using only the LinearFilteringBindOption in the binding options speeds up the things a lot, this is my current call:
bindTexture(image, GL_TEXTURE_2D,GL_RGBA,QGLContext::LinearFilteringBindOption);
more info here : load time for a 3800x2850 bmp file reduced from 2 seconds to 34 milliseconds
Of course, if you need mipmapping, this is not the solution. In this case, I think that the way to go is Pixel Buffer Objects.
Binding in the main thread (single QGLWidget solution):
decide on maximum texture size. You could decide it based on maximum possible widget size for example. Say you know that the widget can be at most (approximately) 800x600 pixels and the largest cover visible has 30 pixels margins up and down and 1:2 aspect ratio -> 600-2*30 = 540 -> maximum size of the cover is 270x540, e.g. stored in m_maxCoverSize.
scale the incoming images to that size in the loader thread. It doesn't make sense to bind larger textures and the larger it is, the longer it'll take to upload to the graphics card. Use QImage::scaled(m_maxCoverSize, Qt::KeepAspectRatio) to scale loaded image and pass it to the main thread.
limit the number of textures or better time spent binding them per frame. I.e. remember the time at which you started binding textures (e.g. QTime bindStartTime;) and after binding each texture do:
if (bindStartTime.elapsed() > BIND_TIME_LIMIT)
break;
BIND_TIME_LIMIT would depend on frame rate you want to keep. But of course if binding each one texture takes much longer than BIND_TIME_LIMIT you haven't solved anything.
You might still experience framerate drop while loading images though on slower machines / graphics cards. The rest of the code should be prepared to live with it (e.g. use actual time to drive animation).
Alternative solution is to bind in a separate thread (using a second invisible QGLWidget, see documentation):
2. Texture uploading in a thread.
Doing texture uploads in a thread may be very useful for applications handling large amounts of images that needs to be displayed, like for instance a photo gallery application. This is supported in Qt through the existing bindTexture() API. A simple way of doing this is to create two sharing QGLWidgets. One is made current in the main GUI thread, while the other is made current in the texture upload thread. The widget in the uploading thread is never shown, it is only used for sharing textures with the main thread. For each texture that is bound via bindTexture(), notify the main thread so that it can start using the texture.
I am working on a multi -segment download manager. I want to display the segmentation procedure. QGraphicsScene works fine but , unfortunately it slows the download. Is there any better option, other than using QProgressBars.
I am using QNetworkAccessManager to download files. If I connect the downloadProgress signal of QNetworkManager object to a slot of Main Gui Thread which draws on QGraphicsView, the download speed decreases even upto 10 times in some cases
// a custom progress bar
void Download::showGProgress(int num, float prgrss) //slot
{
prgrss=prgrss/100;
x_coord=(ui->graphicsView_2->width()-3)*prgrss;
for(float b=0;b<=x_coord;b=b+0.5)
{
progress.addRect(0,0,x_coord,y_coord);
}
}
QNetworkAccessManager is not threaded. It is asynchronous, using the current threads eventloop. It is the HTTP requests which it create that are the threaded aspect.
This would explain why anything you do in your main thread could theoretically slow down the operations of the download. Though not necessarily the underlying threaded download itself, but rather the signaling response time that would allow you to have fast feedback about it.
What you should probably do is create your own QThread subclass, and create the QNetworkAccessManager in the run() method. And then create a QEventLoop in the thread and call exec()
In a nutshell, you need to create your own Threaded QNetworkAccessManager.
create your own widget to do what you would like
this is easier than it sounds.
Make a class that subclasses from a QWidget. And in this widget make a Horizontal Sizer that contains 100 Qlabels (store the QLabels in a vector). Give it slots to 'update' the current progress by setting the background color of each QLabel to a different color. This should be fairly easy to do progressively, meaning you store the current 'percentage' as a member variable and then only adjust the fields that are necessary to get to the percentage that you're looking for (This will eliminate some flickering if you were to do it from scratch every time).
Add functions that will switch the sizer to a vertical one instead of a horizontal one to make it even more customizable.
This allows you to get creative in the what you can do for the progress bar as each element could be a different picture, or a different color, or whatever you would like.
Did you try QProgressBar? Maybe you can write a subclass of it to handle your own properties.
Is there a way to set the render target to a GDI bitmap in SlimDX so that as soon as the scene is rendered I can immediately BitBlt the render out of there for processing in another thread and continue rendering?
Is it necessary to render to a texture and then copy the contents out to the bitmap? I would like to be able to do this without any unnecessary copying. I'm going to need every speedup I can get.
Sorry, you do need to render to a RenderTarget then copy that resource into a Texture2D then you can map the data and get the pixels into your bitmap.
The memory for RenderTargets is marked for a special kind of use by the graphics card and cannot be read from directly
The memory for Textures can be marked so that it can be read but only through the API as it is still held on the graphics card (some exceptions but DirectX has to go with the lowest common denominator)
If you need the extra speed reuse the same bitmap or have an array of prepared bitmaps ready to fill and keep them on rotation.
And as ever, measure how much time these things are consuming with a profiler so that you can quantify bottlenecks.