Revision control
Copy as Markdown
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "rhirendernode.h"
#include <QQuickWindow>
#include <rhi/qrhi.h>
RhiItem::RhiItem(QQuickItem *parent)
: QQuickItem(parent)
{
setFlag(ItemHasContents, true);
}
void RhiItem::setCircleRadius(float r)
{
if (m_circleRadius == r)
return;
m_circleRadius = r;
emit circleRadiusChanged();
update();
}
void RhiItem::setUseClipRect(bool use)
{
if (m_useClipRect == use)
return;
m_useClipRect = use;
emit useClipRectChanged();
update();
}
QSGNode *RhiItem::updatePaintNode(QSGNode *old, UpdatePaintNodeData *)
{
RhiRenderNode *node = static_cast<RhiRenderNode *>(old);
if (!node) {
node = new RhiRenderNode(window());
window()->setColor(QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f));
node->m_width = width();
node->m_height = height();
}
node->m_circleRadius = m_circleRadius;
node->m_useClipRect = m_useClipRect;
return node;
}
RhiRenderNode::RhiRenderNode(QQuickWindow *window)
: m_window(window)
{
QRhi *rhi = m_window->rhi();
// One catch currently: using a shared painter works for a single rendernode,
// but breaks down for multiple ones, because that leads to
// prepare, prepare, ..., render, render, ...
// on the rendernodes, and that cannot be made working with the paintdriver atm.
// (because it would mean beginPaint-endPaint, beginPaint-endPaint, ...,
// renderPaint, renderPaint, ... all using the same painter+engine+renderer,
// which breaks)
//m_fac = QCanvasPainterFactory::sharedInstance(rhi);
m_fac = new QCanvasPainterFactory;
m_fac->create(rhi);
m_pd = m_fac->paintDriver();
m_p = m_fac->painter();
}
RhiRenderNode::~RhiRenderNode()
{
delete m_fac;
}
void RhiRenderNode::releaseResources()
{
}
QSGRenderNode::RenderingFlags RhiRenderNode::flags() const
{
// DepthAware is actually important (for rendering performance)
return QSGRenderNode::DepthAwareRendering | QSGRenderNode::NoExternalRendering;
}
QSGRenderNode::StateFlags RhiRenderNode::changedStates() const
{
// which ones matter, not sure, perhaps none
return QSGRenderNode::StateFlag::ViewportState | QSGRenderNode::StateFlag::CullState;
}
void RhiRenderNode::prepare()
{
m_pd->resetForNewFrame();
QRhiCommandBuffer *cb = commandBuffer();
QRhiRenderTarget *rt = renderTarget();
const QMatrix4x4 mvp = *projectionMatrix() * *matrix();
m_pd->beginPaint(cb, rt, mvp, QCanvasRhiPaintDriver::BeginPaintFlag::DepthTest);
const QSize itemSize(m_width, m_height);
QCanvasPainter *painter = m_p;
painter->resetClipping();
const QSGClipNode *clip = clipList();
// only the first, ignore matrix, etc.
while (clip) {
painter->setClipRect(clip->clipRect());
break;
//clip = clip->clipList();
}
painter->save();
painter->beginPath();
const QPointF center(itemSize.width() / 2, itemSize.height() / 2);
painter->circle(center, m_circleRadius); // we are not restricted to the item bounds
//painter->setFillStyle(QColor::fromRgbF(1.0, 0.0, 0.0, 0.5));
painter->setFillStyle(Qt::red);
painter->fill();
painter->setTextAlign(QCanvasPainter::TextAlign::Center);
painter->setTextBaseline(QCanvasPainter::TextBaseline::Middle);
QFont font1;
font1.setWeight(QFont::Weight::Bold);
font1.setItalic(true);
font1.setPixelSize(24);
painter->setFont(font1);
painter->setFillStyle(Qt::green);
painter->fillText("QCanvasPainter", center.x(), center.y() - 30);
painter->fillText("all inline", center.x(), center.y() + 0);
painter->fillText("(render node)", center.x(), center.y() + 30);
painter->restore();
if (m_useClipRect) {
QRectF viewArea(20, 20, 160, 160);
painter->setClipRect(viewArea);
painter->beginPath();
painter->circle(40, 40, 110);
painter->setFillStyle(Qt::green);
painter->fill();
painter->setFillStyle(Qt::black);
painter->fillText("Clip me...", 40, 100);
painter->setLineWidth(2);
painter->strokeRect(viewArea);
}
m_pd->endPaint(QCanvasRhiPaintDriver::EndPaintFlag::DoNotRecordRenderPass);
}
void RhiRenderNode::render(const RenderState *)
{
m_pd->renderPaint();
}