Efficiently getting from a QPaintDevice to a QSGTexture in QQuickItem - qt

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.

Related

QQuickWindow:renderTargetId() replacement in Qt 6.0?

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?

Can I attach a texture, which I created, to a QOpenGLFramebufferObject?

QOpenGLFramebufferObject provides methods that internally create a texture and attach it to the FBO. But what if I have an existing texture ID (taken from a QSGTexture btw) and I want to attach it to the FBO?

How to work with QGraphicsScene::addPixmap when it only accepts const QPixmap?

I'd like to display some QImage through QGraphicsScene, my code's very straightforward:
mainwindow.h
QImage *sourceImage;
QGraphicsView *imageView;
QGraphicsScene *imageScene;
mainwindow.cpp
imageScene = new QGraphicsScene;
imageView = new QGraphicsView;
imageView->setScene(imageScene);
sourceImage = new QImage;
sourceImage.load(":/targetimage.png");
imageScene.addPixmap(QPixmap::fromImage(sourceImage));
And then the complier points out exactly what I did wrong: QGraphicsScene::addPixmap accepts only const QPixmap as argument, and I was trying to convert QImage to const QPixmap, which is not allowed because QPixmap::fromImage within only accept const QImage, like a const hell.
The official documentation on this method doesn't make much sense to me either, if I'd like to make for example, an image viewer, and during runtime I'd sure load different images into QImage sourceImage, and how can I accomplish that using a const QImage?
This problem has been agonizing, thanks for any advice. Moreover could you light me a bit if there's any vision on the philosophical reason why guys in Qt make these methods const?
Try
imageScene.addPixmap(QPixmap::fromImage(*sourceImage));
Some advice:
there is no need to allocate the QImage on the heap (using new).
Use:
QImage sourceImage;
Then you do not need to dereference the pointer when calling QPixmap::fromImage
Just to clarify: the constness has nothing to do with the error.

Is there any easy way to copy QPainter state?

I want to implment push_group/pop_group of cairo with QPainter, but QPainter resets all its state while begin() with a new painterDevice, so I have to save/revert all state manually.
Yes, just check out QPainter::save() and QPainter::restore().
If you want to save/restore between the lifespan of multiple QPainters, you have to do it manually. You could just create a class PainterState that encapsulates the painter state (pen, brush, transform, etc.), and then store a QStack<PainterState>.
There is a QPainterState class, but it is for internal use only, and I think it's only for use with a single QPainter. See the source ("qpainter_p.h") if you're interested in the QPainterState members (too many to copy here).
When constructing the QPainter object, you can draw it to a QPicture. Then it can be reloaded when needed and painted out to the real QPaintDevice.
QPicture picture;
QPainter painterQueued;
painterQueued.begin(&picture); // paint in picture
painterQueued.drawEllipse(10,20, 80,70); // draw an ellipse
painterQueued.end(); // painting done
QImage myImage;
QPainter painterTarget;
painterTarget.begin(&myImage); // paint in myImage
painterTarget.drawPicture(0, 0, picture); // draw the picture at (0,0)
painterTarget.end(); // painting done
You could queue up many QPicture objects in a list, stack, etc, and replay them when needed.

How to associate a MFC DC with QPrinter?

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.

Resources