qt5base-lts/tests/manual/rhi/imguirenderer/imguirenderer.cpp
Laszlo Agocs fbb26c2b88 rhi manual tests: allow having some gui controls
Having a simple Dear ImGui bridge is not just useful for the manual
tests, which do not have any other means to displays GUIs, but is
in itself an important exercise for the QRhi machinery.

Have a new manual test that exercises the built-in ImGui demo window.
Then use it in the displacement test for real, to replace the myriads
of key presses with on-screen sliders and checkboxes (with less code).

Change-Id: I296bafae2a5cce6fc7a447d97e68e5bcec15f451
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
2023-03-23 16:39:19 +01:00

129 lines
4.2 KiB
C++

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#define EXAMPLEFW_IMGUI
#include "../shared/examplefw.h"
#include "../shared/cube.h"
struct {
QMatrix4x4 winProj;
QList<QRhiResource *> releasePool;
QRhiResourceUpdateBatch *initialUpdates = nullptr;
QRhiBuffer *vbuf = nullptr;
QRhiBuffer *ubuf = nullptr;
QRhiTexture *tex = nullptr;
QRhiSampler *sampler = nullptr;
QRhiShaderResourceBindings *srb = nullptr;
QRhiGraphicsPipeline *ps = nullptr;
bool showDemoWindow = true;
float rotation = 0.0f;
} d;
void Window::customInit()
{
d.initialUpdates = m_r->nextResourceUpdateBatch();
d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube));
d.vbuf->create();
d.releasePool << d.vbuf;
d.initialUpdates->uploadStaticBuffer(d.vbuf, cube);
d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68);
d.ubuf->create();
d.releasePool << d.ubuf;
float opacity = 1.0f;
d.initialUpdates->updateDynamicBuffer(d.ubuf, 64, 4, &opacity);
QImage image = QImage(QLatin1String(":/qt256.png")).convertToFormat(QImage::Format_RGBA8888).mirrored();
d.tex = m_r->newTexture(QRhiTexture::RGBA8, QSize(image.width(), image.height()), 1, {});
d.releasePool << d.tex;
d.tex->create();
d.initialUpdates->uploadTexture(d.tex, image);
d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
d.releasePool << d.sampler;
d.sampler->create();
d.srb = m_r->newShaderResourceBindings();
d.releasePool << d.srb;
d.srb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf),
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler)
});
d.srb->create();
d.ps = m_r->newGraphicsPipeline();
d.releasePool << d.ps;
d.ps->setCullMode(QRhiGraphicsPipeline::Back);
const QRhiShaderStage stages[] = {
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
};
d.ps->setShaderStages(stages, stages + 2);
QRhiVertexInputLayout inputLayout;
inputLayout.setBindings({
{ 3 * sizeof(float) },
{ 2 * sizeof(float) }
});
inputLayout.setAttributes({
{ 0, 0, QRhiVertexInputAttribute::Float3, 0 },
{ 1, 1, QRhiVertexInputAttribute::Float2, 0 }
});
d.ps->setVertexInputLayout(inputLayout);
d.ps->setShaderResourceBindings(d.srb);
d.ps->setRenderPassDescriptor(m_rp);
d.ps->create();
}
void Window::customRelease()
{
qDeleteAll(d.releasePool);
d.releasePool.clear();
}
void Window::customRender()
{
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch();
if (d.initialUpdates) {
u->merge(d.initialUpdates);
d.initialUpdates->release();
d.initialUpdates = nullptr;
}
QMatrix4x4 mvp = m_proj;
mvp.rotate(d.rotation, 0, 1, 0);
u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData());
const QSize outputSizeInPixels = m_sc->currentPixelSize();
cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u);
cb->setGraphicsPipeline(d.ps);
cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()));
cb->setShaderResources();
const QRhiCommandBuffer::VertexInput vbufBindings[] = {
{ d.vbuf, 0 },
{ d.vbuf, quint32(36 * 3 * sizeof(float)) }
};
cb->setVertexInput(0, 2, vbufBindings);
cb->draw(36);
m_imguiRenderer->render();
cb->endPass();
}
void Window::customGui()
{
ImGui::ShowDemoWindow(&d.showDemoWindow);
ImGui::SetNextWindowPos(ImVec2(50, 120), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(400, 100), ImGuiCond_FirstUseEver);
ImGui::Begin("Test");
ImGui::SliderFloat("Rotation", &d.rotation, 0.0f, 360.0f);
ImGui::End();
}