// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause //! [0] #include #include #include #include int main(int argc, char **argv) { QGuiApplication app(argc, argv); #if QT_CONFIG(vulkan) QVulkanInstance inst; #endif std::unique_ptr rhi; #if defined(Q_OS_WIN) QRhiD3D12InitParams params; rhi.reset(QRhi::create(QRhi::D3D12, ¶ms)); #elif QT_CONFIG(metal) QRhiMetalInitParams params; rhi.reset(QRhi::create(QRhi::Metal, ¶ms)); #elif QT_CONFIG(vulkan) 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 tex(rhi->newTexture(QRhiTexture::RGBA8, QSize(1280, 720), 1, QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource)); tex->create(); std::unique_ptr rt(rhi->newTextureRenderTarget({ tex.get() })); std::unique_ptr 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 vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData))); vbuf->create(); std::unique_ptr ubuf(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 + 4)); ubuf->create(); std::unique_ptr srb(rhi->newShaderResourceBindings()); srb->setBindings({ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, ubuf.get()) }); srb->create(); std::unique_ptr ps(rhi->newGraphicsPipeline()); QRhiGraphicsPipeline::TargetBlend premulAlphaBlend; premulAlphaBlend.enable = true; ps->setTargetBlends({ premulAlphaBlend }); static auto getShader = [](const QString &name) { QFile f(name); return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : 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(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]