Update QRhiWidget API based on review comments

Spell out some API names in enum.

Some functions are now protected.

Remove property for autoRenderTarget.

textureFormat -> colorBufferFormat.

Used "fixed" instead of "explicit" and follow
the above naming, so that explicitSize becomes
fixedColorBufferSize.

Pick-to: 6.7
Change-Id: I2fd6ad46033313a3febbb8846146021d5dd11010
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Laszlo Agocs 2024-01-09 12:19:39 +01:00
parent 0e8086887a
commit acebb97b58
5 changed files with 111 additions and 103 deletions

View File

@ -24,8 +24,8 @@ int main(int argc, char **argv)
ExampleRhiWidget *rhiWidget = new ExampleRhiWidget;
QLabel *overlayLabel = new QLabel(rhiWidget);
overlayLabel->setText(QLatin1String("This is a\nsemi-transparent\n overlay widget\n"
"placed on top of\nthe QRhiWidget."));
overlayLabel->setText(QObject::tr("This is a\nsemi-transparent\n overlay widget\n"
"placed on top of\nthe QRhiWidget."));
overlayLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
overlayLabel->setAutoFillBackground(true);
QPalette semiTransparent(QColor(255, 0, 0, 64));
@ -44,9 +44,9 @@ int main(int argc, char **argv)
overlayLabel->setGeometry(rhiWidget->width() / 2 - w / 2, rhiWidget->height() / 2 - h / 2, w, h);
});
QTextEdit *edit = new QTextEdit(QLatin1String("QRhiWidget!<br><br>"
"The cube is textured with QPainter-generated content.<br><br>"
"Regular, non-native widgets on top work just fine."));
QTextEdit *edit = new QTextEdit(QObject::tr("QRhiWidget!<br><br>"
"The cube is textured with QPainter-generated content.<br><br>"
"Regular, non-native widgets on top work just fine."));
QObject::connect(edit, &QTextEdit::textChanged, edit, [edit, rhiWidget] {
rhiWidget->setCubeTextureText(edit->toPlainText());
});
@ -61,7 +61,7 @@ int main(int argc, char **argv)
});
QHBoxLayout *sliderLayout = new QHBoxLayout;
sliderLayout->addWidget(new QLabel(QLatin1String("Cube rotation")));
sliderLayout->addWidget(new QLabel(QObject::tr("Cube rotation")));
sliderLayout->addWidget(slider);
layout->addLayout(sliderLayout);
@ -70,25 +70,25 @@ int main(int argc, char **argv)
QLabel *apiLabel = new QLabel;
btnLayout->addWidget(apiLabel);
QObject::connect(rhiWidget, &ExampleRhiWidget::rhiChanged, rhiWidget, [apiLabel](const QString &apiName) {
apiLabel->setText(QLatin1String("Using QRhi on ") + apiName);
apiLabel->setText(QObject::tr("Using QRhi on ") + apiName);
});
QPushButton *btnMakeWindow = new QPushButton(QLatin1String("Make top-level window"));
QPushButton *btnMakeWindow = new QPushButton(QObject::tr("Make top-level window"));
QObject::connect(btnMakeWindow, &QPushButton::clicked, btnMakeWindow, [rhiWidget, btnMakeWindow, layout] {
if (rhiWidget->parentWidget()) {
rhiWidget->setParent(nullptr);
rhiWidget->setAttribute(Qt::WA_DeleteOnClose, true);
rhiWidget->show();
btnMakeWindow->setText(QLatin1String("Make child widget"));
btnMakeWindow->setText(QObject::tr("Make child widget"));
} else {
rhiWidget->setAttribute(Qt::WA_DeleteOnClose, false);
layout->addWidget(rhiWidget);
btnMakeWindow->setText(QLatin1String("Make top-level window"));
btnMakeWindow->setText(QObject::tr("Make top-level window"));
}
});
btnLayout->addWidget(btnMakeWindow);
QPushButton *btn = new QPushButton(QLatin1String("Grab to image"));
QPushButton *btn = new QPushButton(QObject::tr("Grab to image"));
QObject::connect(btn, &QPushButton::clicked, btn, [rhiWidget] {
QImage image = rhiWidget->grabFramebuffer();
qDebug() << "Got image" << image;
@ -103,7 +103,7 @@ int main(int argc, char **argv)
});
btnLayout->addWidget(btn);
QCheckBox *cbMsaa = new QCheckBox(QLatin1String("Use 4x MSAA"));
QCheckBox *cbMsaa = new QCheckBox(QObject::tr("Use 4x MSAA"));
QObject::connect(cbMsaa, &QCheckBox::stateChanged, cbMsaa, [cbMsaa, rhiWidget] {
if (cbMsaa->isChecked())
rhiWidget->setSampleCount(4);
@ -112,7 +112,7 @@ int main(int argc, char **argv)
});
btnLayout->addWidget(cbMsaa);
QCheckBox *cbOvberlay = new QCheckBox(QLatin1String("Show overlay widget"));
QCheckBox *cbOvberlay = new QCheckBox(QObject::tr("Show overlay widget"));
QObject::connect(cbOvberlay, &QCheckBox::stateChanged, cbOvberlay, [cbOvberlay, overlayLabel] {
if (cbOvberlay->isChecked())
overlayLabel->setVisible(true);
@ -121,28 +121,28 @@ int main(int argc, char **argv)
});
btnLayout->addWidget(cbOvberlay);
QCheckBox *cbFlip = new QCheckBox(QLatin1String("Flip"));
QCheckBox *cbFlip = new QCheckBox(QObject::tr("Flip"));
QObject::connect(cbFlip, &QCheckBox::stateChanged, cbOvberlay, [cbFlip, rhiWidget] {
rhiWidget->setMirrorVertically(cbFlip->isChecked());
});
btnLayout->addWidget(cbFlip);
QCheckBox *cbExplicitSize = new QCheckBox(QLatin1String("Use explicit size"));
btnLayout->addWidget(cbExplicitSize);
QSlider *explicitSizeSlider = new QSlider(Qt::Horizontal);
explicitSizeSlider->setMinimum(16);
explicitSizeSlider->setMaximum(512);
btnLayout->addWidget(explicitSizeSlider);
QCheckBox *cbFixedSize = new QCheckBox(QObject::tr("Use fixed color buffer size"));
btnLayout->addWidget(cbFixedSize);
QSlider *fixedSizeSlider = new QSlider(Qt::Horizontal);
fixedSizeSlider->setMinimum(16);
fixedSizeSlider->setMaximum(512);
btnLayout->addWidget(fixedSizeSlider);
QObject::connect(cbExplicitSize, &QCheckBox::stateChanged, cbExplicitSize, [cbExplicitSize, explicitSizeSlider, rhiWidget] {
if (cbExplicitSize->isChecked())
rhiWidget->setExplicitSize(QSize(explicitSizeSlider->value(), explicitSizeSlider->value()));
QObject::connect(cbFixedSize, &QCheckBox::stateChanged, cbFixedSize, [cbFixedSize, fixedSizeSlider, rhiWidget] {
if (cbFixedSize->isChecked())
rhiWidget->setFixedColorBufferSize(QSize(fixedSizeSlider->value(), fixedSizeSlider->value()));
else
rhiWidget->setExplicitSize(QSize());
rhiWidget->setFixedColorBufferSize(QSize());
});
QObject::connect(explicitSizeSlider, &QSlider::valueChanged, explicitSizeSlider, [explicitSizeSlider, cbExplicitSize, rhiWidget] {
if (cbExplicitSize->isChecked())
rhiWidget->setExplicitSize(QSize(explicitSizeSlider->value(), explicitSizeSlider->value()));
QObject::connect(fixedSizeSlider, &QSlider::valueChanged, fixedSizeSlider, [fixedSizeSlider, cbFixedSize, rhiWidget] {
if (cbFixedSize->isChecked())
rhiWidget->setFixedColorBufferSize(QSize(fixedSizeSlider->value(), fixedSizeSlider->value()));
});
// Exit when the detached window is closed; there is not much we can do

View File

@ -32,8 +32,8 @@ QT_BEGIN_NAMESPACE
reimplement the virtual functions initialize() and render().
The size of the texture will by default adapt to the size of the widget. If
a fixed size is preferred, set an explicit size specified in pixels by
calling setExplicitSize().
a fixed size is preferred, set a fixed size specified in pixels by calling
setFixedColorBufferSize().
In addition to the texture serving as the color buffer, a depth/stencil
buffer and a render target binding these together is maintained implicitly
@ -148,8 +148,8 @@ QT_BEGIN_NAMESPACE
\value OpenGL
\value Metal
\value Vulkan
\value D3D11
\value D3D12
\value Direct3D11
\value Direct3D12
\value Null
\sa QRhi
@ -528,7 +528,7 @@ void QRhiWidgetPrivate::ensureTexture(bool *changed)
{
Q_Q(QRhiWidget);
QSize newSize = explicitSize;
QSize newSize = fixedSize;
if (newSize.isEmpty())
newSize = q->size() * q->devicePixelRatio();
@ -702,12 +702,13 @@ QRhiWidget::Api QRhiWidget::api() const
case QPlatformBackingStoreRhiConfig::Vulkan:
return Api::Vulkan;
case QPlatformBackingStoreRhiConfig::D3D11:
return Api::D3D11;
return Api::Direct3D11;
case QPlatformBackingStoreRhiConfig::D3D12:
return Api::D3D12;
default:
return Api::Direct3D12;
case QPlatformBackingStoreRhiConfig::Null:
return Api::Null;
}
Q_UNREACHABLE_RETURN(Api::Null);
}
/*!
@ -726,7 +727,7 @@ QRhiWidget::Api QRhiWidget::api() const
backend to render. Attempting to set another value, or to add another
QRhiWidget with a different \a api will not function as expected.
\sa setTextureFormat(), setDebugLayer(), api()
\sa setColorBufferFormat(), setDebugLayer(), api()
*/
void QRhiWidget::setApi(Api api)
{
@ -741,10 +742,10 @@ void QRhiWidget::setApi(Api api)
case Api::Vulkan:
d->config.setApi(QPlatformBackingStoreRhiConfig::Vulkan);
break;
case Api::D3D11:
case Api::Direct3D11:
d->config.setApi(QPlatformBackingStoreRhiConfig::D3D11);
break;
case Api::D3D12:
case Api::Direct3D12:
d->config.setApi(QPlatformBackingStoreRhiConfig::D3D12);
break;
case Api::Null:
@ -787,13 +788,13 @@ void QRhiWidget::setDebugLayer(bool enable)
}
/*!
\property QRhiWidget::textureFormat
\property QRhiWidget::colorBufferFormat
This property controls the texture format for the texture used as the color
buffer. The default value is TextureFormat::RGBA8. QRhiWidget supports
rendering to a subset of the formats supported by \l QRhiTexture. Only
formats that are reported as supported from
\l QRhi::isTextureFormatSupported() should be specified, rendering will not be
This property controls the texture format of the texture (or renderbuffer)
used as the color buffer. The default value is TextureFormat::RGBA8.
QRhiWidget supports rendering to a subset of the formats supported by \l
QRhiTexture. Only formats that are reported as supported from \l
QRhi::isTextureFormatSupported() should be specified, rendering will not be
functional otherwise.
\note Setting a new format when the widget is already initialized and has
@ -805,13 +806,13 @@ void QRhiWidget::setDebugLayer(bool enable)
creating new ones.
*/
QRhiWidget::TextureFormat QRhiWidget::textureFormat() const
QRhiWidget::TextureFormat QRhiWidget::colorBufferFormat() const
{
Q_D(const QRhiWidget);
return d->widgetTextureFormat;
}
void QRhiWidget::setTextureFormat(TextureFormat format)
void QRhiWidget::setColorBufferFormat(TextureFormat format)
{
Q_D(QRhiWidget);
if (d->widgetTextureFormat != format) {
@ -830,7 +831,7 @@ void QRhiWidget::setTextureFormat(TextureFormat format)
d->rhiTextureFormat = QRhiTexture::RGB10A2;
break;
}
emit textureFormatChanged(format);
emit colorBufferFormatChanged(format);
update();
}
}
@ -884,7 +885,7 @@ void QRhiWidget::setSampleCount(int samples)
}
/*!
\property QRhiWidget::explicitSize
\property QRhiWidget::fixedColorBufferSize
The fixed size, in pixels, of the QRhiWidget's associated texture. Relevant
when a fixed texture size is desired that does not depend on the widget's
@ -902,18 +903,18 @@ void QRhiWidget::setSampleCount(int samples)
size} * \c{device pixel ratio}).
*/
QSize QRhiWidget::explicitSize() const
QSize QRhiWidget::fixedColorBufferSize() const
{
Q_D(const QRhiWidget);
return d->explicitSize;
return d->fixedSize;
}
void QRhiWidget::setExplicitSize(const QSize &pixelSize)
void QRhiWidget::setFixedColorBufferSize(QSize pixelSize)
{
Q_D(QRhiWidget);
if (d->explicitSize != pixelSize) {
d->explicitSize = pixelSize;
emit explicitSizeChanged(pixelSize);
if (d->fixedSize != pixelSize) {
d->fixedSize = pixelSize;
emit fixedColorBufferSizeChanged(pixelSize);
update();
}
}
@ -945,31 +946,38 @@ void QRhiWidget::setMirrorVertically(bool enabled)
}
/*!
\property QRhiWidget::autoRenderTarget
\return the current setting for automatic depth-stencil buffer and render
target maintenance.
This property controls if a depth-stencil QRhiRenderBuffer and a
QRhiTextureRenderTarget is created and maintained automatically by the
widget. The default value is \c true.
By default the value is \c true.
In automatic mode, the size and sample count of the depth-stencil buffer
follows the color buffer texture's settings. In non-automatic mode,
renderTarget() and depthStencilBuffer() always return \nullptr and it is
then up to the application's implementation of initialize() to take care of
setting up and managing these objects.
\sa setAutoRenderTarget()
*/
bool QRhiWidget::isAutoRenderTargetEnabled() const
{
Q_D(const QRhiWidget);
return d->autoRenderTarget;
}
/*!
Controls if a depth-stencil QRhiRenderBuffer and a QRhiTextureRenderTarget
is created and maintained automatically by the widget. The default value is
\c true.
In automatic mode, the size and sample count of the depth-stencil buffer
follows the color buffer texture's settings. In non-automatic mode,
renderTarget() and depthStencilBuffer() always return \nullptr and it is
then up to the application's implementation of initialize() to take care of
setting up and managing these objects.
Call this function with \a enabled set to \c false early on, for example in
the derived class' constructor, to disable the automatic mode.
*/
void QRhiWidget::setAutoRenderTarget(bool enabled)
{
Q_D(QRhiWidget);
if (d->autoRenderTarget != enabled) {
d->autoRenderTarget = enabled;
emit autoRenderTargetChanged(enabled);
update();
}
}
@ -982,7 +990,7 @@ void QRhiWidget::setAutoRenderTarget(bool enabled)
The returned QImage will have a format of QImage::Format_RGBA8888,
QImage::Format_RGBA16FPx4, QImage::Format_RGBA32FPx4, or
QImage::Format_BGR30 depending on textureFormat().
QImage::Format_BGR30, depending on colorBufferFormat().
QRhiWidget does not know the renderer's approach to blending and
composition, and therefore cannot know if the output has alpha
@ -1004,7 +1012,7 @@ void QRhiWidget::setAutoRenderTarget(bool enabled)
go through the rest of QWidget infrastructure but can right away trigger
rendering a new frame and then do the readback.
\sa setTextureFormat()
\sa setColorBufferFormat()
*/
QImage QRhiWidget::grabFramebuffer() const
{

View File

@ -20,9 +20,8 @@ class Q_WIDGETS_EXPORT QRhiWidget : public QWidget
Q_OBJECT
Q_DECLARE_PRIVATE(QRhiWidget)
Q_PROPERTY(int sampleCount READ sampleCount WRITE setSampleCount NOTIFY sampleCountChanged)
Q_PROPERTY(TextureFormat textureFormat READ textureFormat WRITE setTextureFormat NOTIFY textureFormatChanged)
Q_PROPERTY(bool autoRenderTarget READ isAutoRenderTargetEnabled WRITE setAutoRenderTarget NOTIFY autoRenderTargetChanged)
Q_PROPERTY(QSize explicitSize READ explicitSize WRITE setExplicitSize NOTIFY explicitSizeChanged)
Q_PROPERTY(TextureFormat colorBufferFormat READ colorBufferFormat WRITE setColorBufferFormat NOTIFY colorBufferFormatChanged)
Q_PROPERTY(QSize fixedColorBufferSize READ fixedColorBufferSize WRITE setFixedColorBufferSize NOTIFY fixedColorBufferSizeChanged)
Q_PROPERTY(bool mirrorVertically READ isMirrorVerticallyEnabled WRITE setMirrorVertically NOTIFY mirrorVerticallyChanged)
public:
@ -33,8 +32,8 @@ public:
OpenGL,
Metal,
Vulkan,
D3D11,
D3D12,
Direct3D11,
Direct3D12,
Null
};
Q_ENUM(Api)
@ -56,21 +55,22 @@ public:
int sampleCount() const;
void setSampleCount(int samples);
TextureFormat textureFormat() const;
void setTextureFormat(TextureFormat format);
TextureFormat colorBufferFormat() const;
void setColorBufferFormat(TextureFormat format);
QSize explicitSize() const;
void setExplicitSize(const QSize &pixelSize);
void setExplicitSize(int w, int h) { setExplicitSize(QSize(w, h)); }
bool isAutoRenderTargetEnabled() const;
void setAutoRenderTarget(bool enabled);
QSize fixedColorBufferSize() const;
void setFixedColorBufferSize(QSize pixelSize);
void setFixedColorBufferSize(int w, int h) { setFixedColorBufferSize(QSize(w, h)); }
bool isMirrorVerticallyEnabled() const;
void setMirrorVertically(bool enabled);
QImage grabFramebuffer() const;
protected:
bool isAutoRenderTargetEnabled() const;
void setAutoRenderTarget(bool enabled);
virtual void initialize(QRhiCommandBuffer *cb);
virtual void render(QRhiCommandBuffer *cb);
virtual void releaseResources();
@ -82,19 +82,17 @@ public:
QRhiRenderBuffer *depthStencilBuffer() const;
QRhiRenderTarget *renderTarget() const;
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
bool event(QEvent *e) override;
Q_SIGNALS:
void frameSubmitted();
void renderFailed();
void sampleCountChanged(int samples);
void textureFormatChanged(TextureFormat format);
void autoRenderTargetChanged(bool enabled);
void explicitSizeChanged(const QSize &pixelSize);
void colorBufferFormatChanged(TextureFormat format);
void fixedColorBufferSizeChanged(const QSize &pixelSize);
void mirrorVerticallyChanged(bool enabled);
protected:
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
bool event(QEvent *e) override;
};
QT_END_NAMESPACE

View File

@ -45,7 +45,7 @@ public:
QRhiWidget::TextureFormat widgetTextureFormat = QRhiWidget::TextureFormat::RGBA8;
QRhiTexture::Format rhiTextureFormat = QRhiTexture::RGBA8;
int samples = 1;
QSize explicitSize;
QSize fixedSize;
bool autoRenderTarget = true;
bool mirrorVertically = false;
QBackingStoreRhiSupport offscreenRenderer;

View File

@ -31,8 +31,8 @@ private slots:
void simple();
void msaa_data();
void msaa();
void explicitSize_data();
void explicitSize();
void fixedSize_data();
void fixedSize();
void autoRt_data();
void autoRt();
void reparent_data();
@ -91,12 +91,12 @@ void tst_QRhiWidget::testData()
#endif
#ifdef Q_OS_WIN
QTest::newRow("D3D11") << QRhiWidget::Api::D3D11;
QTest::newRow("D3D11") << QRhiWidget::Api::Direct3D11;
// D3D12 needs to be probed too due to being disabled if the SDK headers
// are too old (clang, mingw).
QRhiD3D12InitParams d3d12InitParams;
if (QRhi::probe(QRhi::D3D12, &d3d12InitParams))
QTest::newRow("D3D12") << QRhiWidget::Api::D3D12;
QTest::newRow("D3D12") << QRhiWidget::Api::Direct3D12;
#endif
}
@ -225,6 +225,8 @@ public:
std::unique_ptr<QRhiGraphicsPipeline> m_pipeline;
QRhiTextureRenderTarget *m_rt = nullptr; // used when autoRenderTarget is off
QRhiRenderPassDescriptor *m_rp = nullptr; // used when autoRenderTarget is off
friend class tst_QRhiWidget;
};
void SimpleRhiWidget::initialize(QRhiCommandBuffer *cb)
@ -347,7 +349,7 @@ void tst_QRhiWidget::simple()
QCOMPARE(errorSpy.count(), 0);
QCOMPARE(rhiWidget->sampleCount(), 1);
QCOMPARE(rhiWidget->textureFormat(), QRhiWidget::TextureFormat::RGBA8);
QCOMPARE(rhiWidget->colorBufferFormat(), QRhiWidget::TextureFormat::RGBA8);
QVERIFY(rhiWidget->isAutoRenderTargetEnabled());
// Pull out the QRhiTexture (we know colorTexture() and rhi() and friends
@ -372,10 +374,10 @@ void tst_QRhiWidget::simple()
case QRhiWidget::Api::Vulkan:
QCOMPARE(rhi->backend(), QRhi::Vulkan);
break;
case QRhiWidget::Api::D3D11:
case QRhiWidget::Api::Direct3D11:
QCOMPARE(rhi->backend(), QRhi::D3D11);
break;
case QRhiWidget::Api::D3D12:
case QRhiWidget::Api::Direct3D12:
QCOMPARE(rhi->backend(), QRhi::D3D12);
break;
case QRhiWidget::Api::Null:
@ -462,7 +464,7 @@ void tst_QRhiWidget::msaa()
QCOMPARE(errorSpy.count(), 0);
QCOMPARE(rhiWidget->sampleCount(), 4);
QCOMPARE(rhiWidget->textureFormat(), QRhiWidget::TextureFormat::RGBA8);
QCOMPARE(rhiWidget->colorBufferFormat(), QRhiWidget::TextureFormat::RGBA8);
QVERIFY(!rhiWidget->colorTexture());
QVERIFY(rhiWidget->msaaColorBuffer());
QVERIFY(rhiWidget->depthStencilBuffer());
@ -515,12 +517,12 @@ void tst_QRhiWidget::msaa()
QVERIFY(rhiWidget->msaaColorBuffer());
}
void tst_QRhiWidget::explicitSize_data()
void tst_QRhiWidget::fixedSize_data()
{
testData();
}
void tst_QRhiWidget::explicitSize()
void tst_QRhiWidget::fixedSize()
{
QFETCH(QRhiWidget::Api, api);
@ -532,7 +534,7 @@ void tst_QRhiWidget::explicitSize()
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(rhiWidget);
rhiWidget->setExplicitSize(QSize(320, 200));
rhiWidget->setFixedColorBufferSize(QSize(320, 200));
QWidget w;
w.setLayout(layout);
@ -552,7 +554,7 @@ void tst_QRhiWidget::explicitSize()
QVERIFY(!rhiWidget->resolveTexture());
frameSpy.clear();
rhiWidget->setExplicitSize(640, 480); // should also trigger update()
rhiWidget->setFixedColorBufferSize(640, 480); // should also trigger update()
QTRY_VERIFY(frameSpy.count() > 0);
QVERIFY(rhiWidget->colorTexture());
@ -561,7 +563,7 @@ void tst_QRhiWidget::explicitSize()
QCOMPARE(rhiWidget->depthStencilBuffer()->pixelSize(), QSize(640, 480));
frameSpy.clear();
rhiWidget->setExplicitSize(QSize());
rhiWidget->setFixedColorBufferSize(QSize());
QTRY_VERIFY(frameSpy.count() > 0);
QVERIFY(rhiWidget->colorTexture());
@ -611,7 +613,7 @@ void tst_QRhiWidget::autoRt()
frameSpy.clear();
// do something that triggers creating a new backing texture
rhiWidget->setExplicitSize(QSize(320, 200));
rhiWidget->setFixedColorBufferSize(QSize(320, 200));
QTRY_VERIFY(frameSpy.count() > 0);
QVERIFY(rhiWidget->colorTexture());