[Development] How fast grab a QML item's content to image when it updates?
Denis Shienkov
denis.shienkov at gmail.com
Tue Dec 12 16:43:23 CET 2017
Now I tried to use the following code:
classBindableFbofinal:publicQSGBindable
{
public:
explicitBindableFbo(QOpenGLFramebufferObject*fbo)
:m_fbo(fbo)
{}
voidbind()constfinal{m_fbo->bind();}
private:
QOpenGLFramebufferObject*m_fbo=nullptr;
};
Grabber::Grabber(QQuickItem*parent)
:QQuickItem(parent)
{
setFlag(QQuickItem::ItemHasContents);
connect(this,&Grabber::windowChanged,
this,&Grabber::scheduleWindowChange);
}
voidGrabber::setSourceItem(QQuickItem*sourceItem)
{
if(sourceItem==m_sourceItem)
return;
m_sourceItem=sourceItem;
emitsourceItemChanged(m_sourceItem);
update();
}
QQuickItem*Grabber::sourceItem()const
{
returnm_sourceItem;
}
QSGNode*Grabber::updatePaintNode(QSGNode*oldNode,
UpdatePaintNodeData*updatePaintNodeData)
{
Q_UNUSED(updatePaintNodeData);
if(!m_sourceItem)
returnoldNode;
m_running=true;
constautoitemNode=QQuickItemPrivate::get(m_sourceItem)->itemNode();
constautoparentNode=itemNode->parent();
constautosiblingNode=itemNode->previousSibling();
if(parentNode)
parentNode->removeChildNode(itemNode);
constQScopedPointer<QSGRenderer>renderer(
QQuickItemPrivate::get(this)->
sceneGraphRenderContext()->createRenderer());
QSGRootNoderootNode;
rootNode.appendChildNode(itemNode);
renderer->setRootNode(&rootNode);
constQSizesize(m_sourceItem->width(),m_sourceItem->height());
renderer->setDeviceRect(size);
renderer->setViewportRect(size);
renderer->setProjectionMatrixToRect(QRectF(QPointF(),size));
renderer->setClearColor(Qt::transparent);
QOpenGLFramebufferObjectfbo(size);
renderer->renderScene(BindableFbo(&fbo));
fbo.release();
rootNode.removeChildNode(itemNode);
if(parentNode){
if(siblingNode){
parentNode->insertChildNodeAfter(itemNode,siblingNode);
}else{
parentNode->prependChildNode(itemNode);
}
}
QElapsedTimeret;
et.start();
constQImageimage=fbo.toImage();//TOOLONG!
staticintcount=0;
qDebug()<<"Elapsed:"<<et.elapsed()<<count;
++count;
//image.save(tr("test%1.png").arg(count++));
returnoldNode;
}
voidGrabber::scheduleWindowChange(QQuickWindow*window)
{
disconnect(m_updateConnection);
if(window){
m_updateConnection=connect(window,&QQuickWindow::afterRendering,
this,&Grabber::scheduleUpdate);
}
}
voidGrabber::scheduleUpdate()
{
if(!m_running)
update();
else
m_running=false;
}
Where for the 800x600 window, the elapsed time of fbo.toImage() is
around of ~8 msec
(with GPU rendering on Windows, as I assume). If try to expand a window
to full screen
(1920x1080 in my case), then this time increases up to ~30 msec.
I'm not sure, is this code correct? Is this values correct? Could
someone elaborate it?
12.12.2017 18:20, Shawn Rutledge пишет:
>> On 12 Dec 2017, at 14:53, Denis Shienkov <denis.shienkov at gmail.com> wrote:
>>
>>> Did you try QQuickItem::grabToImage?
>> Of course, it is veeery slowly.
> If the frame was rendered on the GPU, you have to download it from there, and that is slower than if you had rendered into CPU memory, as widgets do by default. Thus the note in the docs:
>
> Note: This function will render the item to an offscreen surface and copy
> that surface from the GPU's memory into the CPU's memory, which can be
> quite costly. For "live" preview, use layers or ShaderEffectSource.
>
> So, maybe try to get the GPU to do whatever comes next after you think you need to grab the frame? grabToImage is more for archival, not for real-time effects (although I did use it recently to record an animated GIF; I could only get 30FPS despite using a fairly powerful GPU, but that was good enough).
>
> _______________________________________________
> Development mailing list
> Development at qt-project.org
> http://lists.qt-project.org/mailman/listinfo/development
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20171212/b2af14c7/attachment.html>
More information about the Development
mailing list