QQuickWindow::renderTargetId() is removed in Qt 6.0, because underlying graphics API now may be different from OpenGL.
There is now QQuickRenderTarget which is abstract from graphics API, but I can't obtain FBO ID from it when I use OpenGL (I call QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL) in main()).
So I render my scene in my offscreen FBO, but when I want to render a result into the FBO, created by a QQuickWindow, which is not the default FBO with ID = 0 (QQuickWindow creates an FBO with ID = 1 right now), because my QQuickWindow is used by a QQuickWidget embedded into a QMainWindow (so I put Qt Quick and QML into a QWidget-based UI).
I may query the current set FBO ID via OpenGL API, of course, before I call glBindFramebuffer() to render into my own FBO, but I would like to read QQuickWindow's FBO ID using it's API, is there any way?
Related
I'm trying to incorporate external Vulkan render commands inside the Qt Quick scenegraph following the example here. I would like to get access to current swap chain image and issue draw commands on it. QVulkanWindow has QVulkanWindow::currentSwapChainImageIndex() and QVulkanWindow::swapChainImage(int index), however I don't know how to get these from a QQuickWindow. QQuickWindow has an associated QSGRendererInterface that can be used as follows:
// m_window is a QQuickWindow*
auto instance = m_window->vulkanInstance();
QSGRendererInterface *rif = m_window->rendererInterface();
auto physicalDevice = *reinterpret_cast<VkPhysicalDevice*>(rif->getResource(m_window, QSGRendererInterface::PhysicalDeviceResource));
Is there a way to query the current swap chain image for a QQuickWindow?
I'm developping a Qt application in which the user can add QML objects inside a QGraphicsScene. The available QML objects are listed and the user can add as many as he wants.
Until now, I used QQuickWidgets. The QGraphicsScene contains a top-level widget which is the parent of all the QQuickWidgets I create. It works fine, but I have a performance problem. With a high number of objects, the application starts to slow down, and takes too much space in RAM (more than 1.5 GB with the first example I created, containing 400 objects).
I thought it comes from the way QQuickWidgets are handled by Qt, and wanted to try another way, with QQuickViews. To do so I created a root view, converted in a QWidget so I can embed it in my view, which is a QWidget. Then I add a new QQuickView in the root view for each created object.
The creation of the root view, its container and the engine:
_rootView = new QQuickWindow();
_rootView->resize(1024, 720);
_rootView->show();
QWidget *container = QWidget::createWindowContainer(_rootView, this);
container->resize(_rootView->size());
container->setObjectName("TopLevelQmlViewWidget");
_layout->addWidget(container);
_engine = new QQmlEngine(_rootView);
The creation of the QQuickViews representing the objects:
QQuickView *view = new QQuickView(_engine, _rootView);
view->setSource(url);
view->setResizeMode(QQuickView::SizeViewToRootObject);
view->show();
It works, but the problem is that each QQuickView creates its own thread, which doesn't change the way I handle it but takes place in memory. I don't understand why, because I reparent them to the root view.
So my questions are the following :
1 - Is there a way to prevent the QQuickViews to create their own threads ?
2 - Is using QQuickViews, indeed, less memory-consuming than using QQuickWidgets ?
3 - If no, how can I handle adding a big number of QML objects in a QWidget view without consuming too much memory ?
I think using multiple QQuickViews is a bad idea. An application usually only needs one. I would take a look at QQmlComponent instead. Here is an example:
QQmlComponent component(_engine, QUrl::fromLocalFile("MyItem.qml"));
QQuickItem *childItem = qobject_cast<QQuickItem*>(component.create());
childItem->setParentItem(_rootView);
I'm by no means a QML expert. However, here are some pointers I can think of
Avoid mixing and matching QQuick: widget/View.
Consider creating objects dynamically
You can also make use of Loaders, but they have a small amount of extra overhead.
Consider using something like a stack/swipe view to minimize amount of loaded objects.
For best ROI, I'd first try implementing something like stack view and see how much it may help with the RAM. Then go on to create other objects dynamically as needed.
Finally I think QT has a tool that lets you see during runtime the amount of memory of the QML tree. You can look at that and see where your biggest memory hogs are.
When using QQuickFramebufferObject, the QQuickFramebufferObject::Renderer is asked to create a FBO and also to output in this FBO (the content of the FBO being merged with the overall GUI by QtQuick behind the hood).
Now the Renderer is only asked to create the FBO (QOpenGLFramebufferObject), not the buffers themselves (Textures or RenderBuffers).
Where are these buffers attached to the FBO?
My custom QQuickItem currently does the following
Create a QSGNode that subclasses QSGSimpleTextureNode
In the nodes preprocess function, create a QOpenGLFramebufferObject to draw to
Draw on the QOpenGLFramebufferObject using a QPainter
Display the contents of the QOpenGLFramebufferObject as the node contents
The process I have for converting the FBO to a QSGTexture that I can set on the QSGSimpleTextureNode is the following.
QImage img = m_fbo->toImage();
QSGTexture* tex = m_window->createTextureFromImage(img, QQuickWindow::TextureCanUseAtlas);
setTexture(tex);
This seems very inefficient, and the app starts to get real framey even with relatively reasonable sized FBOs.
My questions are the following.
Is there a simpler way of getting an FBO into a QSGTexture?
Is there a better QPaintDevice compatible item that I should be using rather than a QOpenGLFramebufferObject?
Is there a better subclass I should be extending than QSGSimpleTextureNode to do what I am wanting to do?
Thanks!
1) For non multisample framebuffer objects a texture with the specified texture target is created. You can get the texture id for the texture attached to framebuffer object, using QOpenGLFramebufferObject::takeTexture(). And then
create a new QSGTexture object from an existing GL texture id:
QSize textureSize = m_fbo.size();
GLuint textureId = m_fbo.takeTexture();
QSGTexture* texture = window()->createTextureFromId(textureId, textureSize);
2, 3) The QQuickPaintedItem class provides a way to use the QPainter API in the QML Scene Graph.
The QQuickFramebufferObject class is a convenience class for integrating rendering using a framebuffer object (FBO) with Qt Quick.
I was just wondering if it is possible to use my existing MFC created DC to associate with a QPrinter so that it directly uses the existing DC rather creates its own with QPrintDialog?
Does QPrinter make use of Qt's backingstore as QWidget does, i.e., does it create an off-screen image before printing?
First thing:
QPrintDialog has nothing to do with your question.
You can set-up a QPrinter without using QPrintDialog.
Anyway: You paint into a QPainter where QPrinter is "only" the printing device. Printing only starts when you end the QPainter. So there is a backing store when using QPrinter.
You can't convert a DC to a QPainter so QPrinter can't do anything with a DC. The closest thing would be to get a Bitmap from the DC and print it to a fresh QPainter.