diff options
| author | Laszlo Agocs <laszlo.agocs@qt.io> | 2023-04-27 13:16:29 +0200 |
|---|---|---|
| committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2023-05-21 15:42:58 +0200 |
| commit | 1dd8b5ceec3a1cde987372a7f993c07f30e5af95 (patch) | |
| tree | 53e8b96c8a2bf104573a45958329255a5abcd4d9 /src/gui/doc/snippets/rhioffscreen/main.cpp | |
| parent | 30a8e79243084017d23f1c765d5f1cbb86564191 (diff) | |
rhi: Make it a QPA-style private but semi-public API
qrhi.h, qshader.h, qshaderdescription.h (and qshaderbaker.h from
shadertools; done separately) become "RHI APIs", following the concept
of QPA APIs.
Mirror completely what is done for QPA headers, but using the "rhi"
prefix for the headers. This involves updating syncqt to handle the
new category of headers. (a note on the regex: matching everything
starting with "qrhi" is not acceptable due to incorrectly matching
existing and future headers, hence specifying the four header names
explicitly)
There is going to be one difference to QPA: the documentation for
everything RHI is going to be public and part of the regular docs, not
hidden with \internal.
In addition to the header renaming and adding the comments and
documentation notes and warnings, there is one significant change
here: there is no longer a need to do API-specific includes, such as
qrhid3d11[_p].h, qrhivulkan[_p].h, etc. These are simply merged into a
single header that is then included from qrhi.h. This means that users
within Qt, and any future applications can just do #include
<rhi/qrhi.h> (or rhi/qshader.h if the QRhi stuff is not relevant), no
other headers are needed.
There are no changes to functionality in this patch. Only the
documentation is expanded, quite a lot, to eliminate all qdoc warnings
and make the generated API docs complete. An example, with a quite
extensive doc page is added as well.
Task-number: QTBUG-113331
Change-Id: I91c749826348f14320cb335b1c83e9d1ea2b1d8b
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'src/gui/doc/snippets/rhioffscreen/main.cpp')
| -rw-r--r-- | src/gui/doc/snippets/rhioffscreen/main.cpp | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/src/gui/doc/snippets/rhioffscreen/main.cpp b/src/gui/doc/snippets/rhioffscreen/main.cpp new file mode 100644 index 00000000000..b3fac4b5201 --- /dev/null +++ b/src/gui/doc/snippets/rhioffscreen/main.cpp @@ -0,0 +1,151 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +//! [0] +#include <QGuiApplication> +#include <QImage> +#include <QFile> +#include <rhi/qrhi.h> + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + std::unique_ptr<QRhi> rhi; +#if defined(Q_OS_WIN) + QRhiD3D12InitParams params; + rhi.reset(QRhi::create(QRhi::D3D12, ¶ms)); +#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS) + QRhiMetalInitParams params; + rhi.reset(QRhi::create(QRhi::Metal, ¶ms)); +#elif QT_CONFIG(vulkan) + QVulkanInstance inst; + inst.setExtensions(QRhiVulkanInitParams::preferredInstanceExtensions()); + if (inst.create()) { + QRhiVulkanInitParams params; + params.inst = &inst; + rhi.reset(QRhi::create(QRhi::Vulkan, ¶ms)); + } else { + qFatal("Failed to create Vulkan instance"); + } +#endif + if (rhi) + qDebug() << rhi->backendName() << rhi->driverInfo(); + else + qFatal("Failed to initialize RHI"); + + float rotation = 0.0f; + float opacity = 1.0f; + int opacityDir = 1; + + std::unique_ptr<QRhiTexture> tex(rhi->newTexture(QRhiTexture::RGBA8, + QSize(1280, 720), + 1, + QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource)); + tex->create(); + std::unique_ptr<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ tex.get() })); + std::unique_ptr<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor()); + rt->setRenderPassDescriptor(rp.get()); + rt->create(); + + QMatrix4x4 viewProjection = rhi->clipSpaceCorrMatrix(); + viewProjection.perspective(45.0f, 1280 / 720.f, 0.01f, 1000.0f); + viewProjection.translate(0, 0, -4); + + static float vertexData[] = { // Y up, CCW + 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, + }; + + std::unique_ptr<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, + QRhiBuffer::VertexBuffer, + sizeof(vertexData))); + vbuf->create(); + + std::unique_ptr<QRhiBuffer> ubuf(rhi->newBuffer(QRhiBuffer::Dynamic, + QRhiBuffer::UniformBuffer, + 64 + 4)); + ubuf->create(); + + std::unique_ptr<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings()); + srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, + QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, + ubuf.get()) + }); + srb->create(); + + std::unique_ptr<QRhiGraphicsPipeline> ps(rhi->newGraphicsPipeline()); + QRhiGraphicsPipeline::TargetBlend premulAlphaBlend; + premulAlphaBlend.enable = true; + ps->setTargetBlends({ premulAlphaBlend }); + static auto getShader = [](const QString &name) { + QFile f(name); + if (f.open(QIODevice::ReadOnly)) + return QShader::fromSerialized(f.readAll()); + return QShader(); + }; + ps->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String("color.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String("color.frag.qsb")) } + }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 5 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, + { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) } + }); + ps->setVertexInputLayout(inputLayout); + ps->setShaderResourceBindings(srb.get()); + ps->setRenderPassDescriptor(rp.get()); + ps->create(); + + QRhiCommandBuffer *cb; + for (int frame = 0; frame < 20; ++frame) { + rhi->beginOffscreenFrame(&cb); + + QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch(); + if (frame == 0) + u->uploadStaticBuffer(vbuf.get(), vertexData); + + QMatrix4x4 mvp = viewProjection; + mvp.rotate(rotation, 0, 1, 0); + u->updateDynamicBuffer(ubuf.get(), 0, 64, mvp.constData()); + rotation += 5.0f; + + u->updateDynamicBuffer(ubuf.get(), 64, 4, &opacity); + opacity += opacityDir * 0.2f; + if (opacity < 0.0f || opacity > 1.0f) { + opacityDir *= -1; + opacity = qBound(0.0f, opacity, 1.0f); + } + + cb->beginPass(rt.get(), Qt::green, { 1.0f, 0 }, u); + cb->setGraphicsPipeline(ps.get()); + cb->setViewport({ 0, 0, 1280, 720 }); + cb->setShaderResources(); + const QRhiCommandBuffer::VertexInput vbufBinding(vbuf.get(), 0); + cb->setVertexInput(0, 1, &vbufBinding); + cb->draw(3); + QRhiReadbackResult readbackResult; + u = rhi->nextResourceUpdateBatch(); + u->readBackTexture({ tex.get() }, &readbackResult); + cb->endPass(u); + + rhi->endOffscreenFrame(); + + QImage image(reinterpret_cast<const uchar *>(readbackResult.data.constData()), + readbackResult.pixelSize.width(), + readbackResult.pixelSize.height(), + QImage::Format_RGBA8888_Premultiplied); + if (rhi->isYUpInFramebuffer()) + image = image.mirrored(); + image.save(QString::asprintf("frame%d.png", frame)); + } + + return 0; +} +//! [0] |
