Commit b6f98270 authored by Laszlo Agocs's avatar Laszlo Agocs

Refactor renderpass handling

parent 728c8fa9
......@@ -132,7 +132,7 @@ public:
protected:
void init();
void releaseResources();
void recreateSwapChain();
void resizeSwapChain();
void releaseSwapChain();
void render();
......@@ -145,10 +145,9 @@ protected:
QRhi *m_r = nullptr;
bool m_hasSwapChain = false;
bool m_swapChainChanged = false;
QRhiSwapChain *m_sc = nullptr;
QRhiRenderBuffer *m_ds = nullptr;
QRhiRenderPass *m_rp = nullptr;
QRhiBuffer *m_vbuf = nullptr;
bool m_vbufReady = false;
QRhiBuffer *m_ubuf = nullptr;
......@@ -204,7 +203,7 @@ void Window::exposeEvent(QExposeEvent *)
if (isExposed() && !m_running) {
m_running = true;
init();
recreateSwapChain();
resizeSwapChain();
render();
}
......@@ -289,6 +288,15 @@ void Window::init()
// now onto the backend-independent init
m_sc = m_r->createSwapChain();
// allow depth-stencil, although we do not actually enable depth test/write for the triangle
m_ds = m_r->createRenderBuffer(QRhiRenderBuffer::DepthStencil,
QSize(), // we don't know the size yet, this is fine
1,
QRhiRenderBuffer::ToBeUsedWithSwapChainOnly);
m_sc->setWindow(this);
m_sc->setDepthStencil(m_ds);
m_rp = m_sc->buildCompatibleRenderPass();
m_sc->setRenderPass(m_rp);
m_vbuf = m_r->createBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData));
m_vbuf->build();
......@@ -302,10 +310,53 @@ void Window::init()
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, m_ubuf)
});
m_srb->build();
m_ps = m_r->createGraphicsPipeline();
QRhiGraphicsPipeline::TargetBlend premulAlphaBlend;
premulAlphaBlend.enable = true;
m_ps->setTargetBlends({ premulAlphaBlend });
const QBakedShader vs = getShader(QLatin1String(":/color.vert.qsb"));
if (!vs.isValid())
qFatal("Failed to load shader pack (vertex)");
const QBakedShader fs = getShader(QLatin1String(":/color.frag.qsb"));
if (!fs.isValid())
qFatal("Failed to load shader pack (fragment)");
m_ps->setShaderStages({
{ QRhiGraphicsShaderStage::Vertex, vs },
{ QRhiGraphicsShaderStage::Fragment, fs }
});
QRhiVertexInputLayout inputLayout;
inputLayout.bindings = {
{ 5 * sizeof(float) }
};
inputLayout.attributes = {
{ 0, 0, QRhiVertexInputLayout::Attribute::Float2, 0 },
{ 0, 1, QRhiVertexInputLayout::Attribute::Float3, 2 * sizeof(float) }
};
m_ps->setVertexInputLayout(inputLayout);
m_ps->setShaderResourceBindings(m_srb);
m_ps->setRenderPass(m_rp);
m_ps->build();
}
void Window::releaseResources()
{
if (m_ps) {
m_ps->releaseAndDestroy();
m_ps = nullptr;
}
if (m_rp) {
m_rp->releaseAndDestroy();
m_rp = nullptr;
}
if (m_srb) {
m_srb->releaseAndDestroy();
m_srb = nullptr;
......@@ -321,6 +372,11 @@ void Window::releaseResources()
m_vbuf = nullptr;
}
if (m_ds) {
m_ds->releaseAndDestroy();
m_ds = nullptr;
}
delete m_sc;
m_sc = nullptr;
......@@ -335,69 +391,19 @@ void Window::releaseResources()
#endif
}
void Window::recreateSwapChain()
void Window::resizeSwapChain()
{
if (!m_sc)
return;
const QSize outputSize = size() * devicePixelRatio();
// allow depth-stencil, although we do not actually enable depth test/write for the triangle
if (!m_ds) {
m_ds = m_r->createRenderBuffer(QRhiRenderBuffer::DepthStencil,
outputSize,
1,
QRhiRenderBuffer::ToBeUsedWithSwapChainOnly);
} else {
m_ds->release();
m_ds->setPixelSize(outputSize);
}
m_ds->build();
m_ds->setPixelSize(outputSize);
m_ds->build(); // == m_ds->release(); m_ds->build();
m_sc->setWindow(this);
m_sc->setRequestedPixelSize(outputSize);
m_sc->setDepthStencil(m_ds);
m_hasSwapChain = m_sc->buildOrResize();
m_swapChainChanged = true;
m_elapsedMs = 0;
m_elapsedCount = 0;
m_ps = m_r->createGraphicsPipeline();
QRhiGraphicsPipeline::TargetBlend premulAlphaBlend;
premulAlphaBlend.enable = true;
m_ps->setTargetBlends({ premulAlphaBlend });
const QBakedShader vs = getShader(QLatin1String(":/color.vert.qsb"));
if (!vs.isValid())
qFatal("Failed to load shader pack (vertex)");
const QBakedShader fs = getShader(QLatin1String(":/color.frag.qsb"));
if (!fs.isValid())
qFatal("Failed to load shader pack (fragment)");
m_ps->setShaderStages({
{ QRhiGraphicsShaderStage::Vertex, vs },
{ QRhiGraphicsShaderStage::Fragment, fs }
});
QRhiVertexInputLayout inputLayout;
inputLayout.bindings = {
{ 5 * sizeof(float) }
};
inputLayout.attributes = {
{ 0, 0, QRhiVertexInputLayout::Attribute::Float2, 0 },
{ 0, 1, QRhiVertexInputLayout::Attribute::Float3, 2 * sizeof(float) }
};
m_ps->setVertexInputLayout(inputLayout);
m_ps->setShaderResourceBindings(m_srb);
m_ps->setRenderPass(m_sc->defaultRenderPass());
m_ps->build();
const QSize outputSizeInPixels = m_sc->effectiveSizeInPixels();
m_proj = m_r->clipSpaceCorrMatrix();
m_proj.perspective(45.0f, outputSizeInPixels.width() / (float) outputSizeInPixels.height(), 0.01f, 100.0f);
......@@ -406,18 +412,10 @@ void Window::recreateSwapChain()
void Window::releaseSwapChain()
{
if (m_ps) {
m_ps->releaseAndDestroy();
m_ps = nullptr;
}
if (m_hasSwapChain) {
m_hasSwapChain = false;
m_sc->release();
}
if (m_ds) {
m_ds->releaseAndDestroy();
m_ds = nullptr;
}
}
void Window::render()
......@@ -425,11 +423,11 @@ void Window::render()
if (!m_hasSwapChain || m_notExposed)
return;
// If the window got resized or got newly exposed, recreate the swapchain.
// If the window got resized or got newly exposed, resize the swapchain.
// (the newly-exposed case is not actually required by some
// platforms/backends, but f.ex. Vulkan on Windows seems to need it)
if (m_sc->requestedPixelSize() != size() * devicePixelRatio() || m_newlyExposed) {
recreateSwapChain();
resizeSwapChain();
if (!m_hasSwapChain)
return;
m_newlyExposed = false;
......@@ -438,7 +436,7 @@ void Window::render()
// Start a new frame. This is where we block when too far ahead of GPU/present.
QRhi::FrameOpResult r = m_r->beginFrame(m_sc);
if (r == QRhi::FrameOpSwapChainOutOfDate) {
recreateSwapChain();
resizeSwapChain();
if (!m_hasSwapChain)
return;
r = m_r->beginFrame(m_sc);
......
......@@ -102,47 +102,64 @@ void ExampleWindow::init()
if (!m_sc)
return;
// allow depth-stencil, although we do not actually enable depth test/write for the triangle
m_ds = m_r->createRenderBuffer(QRhiRenderBuffer::DepthStencil,
QSize(), // we don't know the size yet, this is fine
m_sampleCount,
QRhiRenderBuffer::ToBeUsedWithSwapChainOnly);
m_sc->setWindow(this);
m_sc->setDepthStencil(m_ds);
m_sc->setSampleCount(m_sampleCount);
m_scrp = m_sc->buildCompatibleRenderPass();
m_sc->setRenderPass(m_scrp);
m_triRenderer.setRhi(m_r);
m_triRenderer.setSampleCount(m_sampleCount);
m_triRenderer.initResources();
m_triRenderer.initResources(m_scrp);
if (!m_triangleOnly) {
m_triRenderer.setTranslation(QVector3D(0, 0.5f, 0));
m_quadRenderer.setRhi(m_r);
m_quadRenderer.setSampleCount(m_sampleCount);
m_quadRenderer.initResources();
m_quadRenderer.setPipeline(m_triRenderer.pipeline());
m_quadRenderer.initResources(m_scrp);
m_quadRenderer.setTranslation(QVector3D(1.5f, -0.5f, 0));
m_cubeRenderer.setRhi(m_r);
m_cubeRenderer.setSampleCount(m_sampleCount);
m_cubeRenderer.initResources();
m_cubeRenderer.initResources(m_scrp);
m_cubeRenderer.setTranslation(QVector3D(0, -0.5f, 0));
}
if (!m_onScreenOnly) {
m_liveTexCubeRenderer.setRhi(m_r);
m_liveTexCubeRenderer.setSampleCount(m_sampleCount);
m_liveTexCubeRenderer.initResources();
m_liveTexCubeRenderer.initResources(m_scrp);
m_liveTexCubeRenderer.setTranslation(QVector3D(-2.0f, 0, 0));
}
}
void ExampleWindow::releaseResources()
{
m_triRenderer.releaseOutputDependentResources();
m_triRenderer.releaseResources();
if (!m_triangleOnly) {
m_quadRenderer.releaseResources();
m_cubeRenderer.releaseOutputDependentResources();
m_cubeRenderer.releaseResources();
}
if (!m_onScreenOnly) {
m_liveTexCubeRenderer.releaseOutputDependentResources();
if (!m_onScreenOnly)
m_liveTexCubeRenderer.releaseResources();
if (m_scrp) {
m_scrp->releaseAndDestroy();
m_scrp = nullptr;
}
if (m_ds) {
m_ds->releaseAndDestroy();
m_ds = nullptr;
}
delete m_sc;
......@@ -154,34 +171,14 @@ void ExampleWindow::releaseResources()
void ExampleWindow::recreateSwapChain()
{
if (!m_sc)
return;
const QSize outputSize = size() * devicePixelRatio();
if (!m_ds) {
m_ds = m_r->createRenderBuffer(QRhiRenderBuffer::DepthStencil,
outputSize,
m_triRenderer.sampleCount(),
QRhiRenderBuffer::ToBeUsedWithSwapChainOnly);
} else {
m_ds->release();
m_ds->setPixelSize(outputSize);
}
if (!m_ds)
return;
m_ds->build();
m_ds->setPixelSize(outputSize);
m_ds->build(); // == m_ds->release(); m_ds->build();
m_sc->setWindow(this);
m_sc->setRequestedPixelSize(outputSize);
m_sc->setDepthStencil(m_ds);
m_sc->setSampleCount(m_triRenderer.sampleCount());
m_hasSwapChain = m_sc->buildOrResize();
m_swapChainChanged = true;
m_resizedSwapChain = true;
}
void ExampleWindow::releaseSwapChain()
......@@ -190,10 +187,6 @@ void ExampleWindow::releaseSwapChain()
m_hasSwapChain = false;
m_sc->release();
}
if (m_ds) {
m_ds->releaseAndDestroy();
m_ds = nullptr;
}
}
void ExampleWindow::render()
......@@ -220,24 +213,15 @@ void ExampleWindow::render()
return;
}
if (m_swapChainChanged) {
m_swapChainChanged = false;
m_triRenderer.releaseOutputDependentResources();
if (!m_triangleOnly)
m_cubeRenderer.releaseOutputDependentResources();
if (!m_onScreenOnly)
m_liveTexCubeRenderer.releaseOutputDependentResources();
}
if (!m_triRenderer.isPipelineInitialized()) {
const QRhiRenderPass *rp = m_sc->defaultRenderPass();
m_triRenderer.initOutputDependentResources(rp, m_sc->effectiveSizeInPixels());
if (m_resizedSwapChain) {
m_resizedSwapChain = false;
m_triRenderer.resize(m_sc->effectiveSizeInPixels());
if (!m_triangleOnly) {
m_quadRenderer.setPipeline(m_triRenderer.pipeline(), m_sc->effectiveSizeInPixels());
m_cubeRenderer.initOutputDependentResources(rp, m_sc->effectiveSizeInPixels());
m_quadRenderer.resize(m_sc->effectiveSizeInPixels());
m_cubeRenderer.resize(m_sc->effectiveSizeInPixels());
}
if (!m_onScreenOnly)
m_liveTexCubeRenderer.initOutputDependentResources(rp, m_sc->effectiveSizeInPixels());
m_liveTexCubeRenderer.resize(m_sc->effectiveSizeInPixels());
}
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
......
......@@ -82,8 +82,9 @@ protected:
QRhi *m_r = nullptr;
bool m_hasSwapChain = false;
bool m_swapChainChanged = false;
bool m_resizedSwapChain = false;
QRhiSwapChain *m_sc = nullptr;
QRhiRenderPass *m_scrp = nullptr;
QRhiRenderBuffer *m_ds = nullptr;
TriangleRenderer m_triRenderer;
......
......@@ -70,7 +70,7 @@ static quint16 indexData[] =
0, 1, 2, 0, 2, 3
};
void QuadRenderer::initResources()
void QuadRenderer::initResources(QRhiRenderPass *)
{
m_vbuf = m_r->createBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData));
m_vbuf->build();
......@@ -89,10 +89,13 @@ void QuadRenderer::initResources()
m_srb->build();
}
void QuadRenderer::setPipeline(QRhiGraphicsPipeline *ps, const QSize &pixelSize)
void QuadRenderer::setPipeline(QRhiGraphicsPipeline *ps)
{
m_ps = ps;
}
void QuadRenderer::resize(const QSize &pixelSize)
{
m_proj = m_r->clipSpaceCorrMatrix();
m_proj.perspective(45.0f, pixelSize.width() / (float) pixelSize.height(), 0.01f, 100.0f);
m_proj.translate(0, 0, -4);
......
......@@ -60,9 +60,10 @@ public:
void setSampleCount(int samples) { m_sampleCount = samples; }
int sampleCount() const { return m_sampleCount; }
void setTranslation(const QVector3D &v) { m_translation = v; }
void initResources();
void initResources(QRhiRenderPass *rp);
void releaseResources();
void setPipeline(QRhiGraphicsPipeline *ps, const QSize &pixelSize);
void setPipeline(QRhiGraphicsPipeline *ps);
void resize(const QSize &pixelSize);
void queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates);
void queueDraw(QRhiCommandBuffer *cb, const QSize &outputSizeInPixels);
......
......@@ -65,7 +65,7 @@ static QBakedShader getShader(const QString &name)
return QBakedShader();
}
void TexturedCubeRenderer::initResources()
void TexturedCubeRenderer::initResources(QRhiRenderPass *rp)
{
m_vbuf = m_r->createBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube));
m_vbuf->build();
......@@ -91,10 +91,7 @@ void TexturedCubeRenderer::initResources()
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, m_tex, m_sampler)
});
m_srb->build();
}
void TexturedCubeRenderer::initOutputDependentResources(const QRhiRenderPass *rp, const QSize &pixelSize)
{
m_ps = m_r->createGraphicsPipeline();
m_ps->setDepthTest(true);
......@@ -130,7 +127,10 @@ void TexturedCubeRenderer::initOutputDependentResources(const QRhiRenderPass *rp
m_ps->setRenderPass(rp);
m_ps->build();
}
void TexturedCubeRenderer::resize(const QSize &pixelSize)
{
m_proj = m_r->clipSpaceCorrMatrix();
m_proj.perspective(45.0f, pixelSize.width() / (float) pixelSize.height(), 0.01f, 100.0f);
m_proj.translate(0, 0, -4);
......@@ -138,6 +138,11 @@ void TexturedCubeRenderer::initOutputDependentResources(const QRhiRenderPass *rp
void TexturedCubeRenderer::releaseResources()
{
if (m_ps) {
m_ps->releaseAndDestroy();
m_ps = nullptr;
}
if (m_srb) {
m_srb->releaseAndDestroy();
m_srb = nullptr;
......@@ -164,14 +169,6 @@ void TexturedCubeRenderer::releaseResources()
}
}
void TexturedCubeRenderer::releaseOutputDependentResources()
{
if (m_ps) {
m_ps->releaseAndDestroy();
m_ps = nullptr;
}
}
void TexturedCubeRenderer::queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates)
{
if (!m_vbufReady) {
......
......@@ -59,11 +59,9 @@ public:
void setRhi(QRhi *r) { m_r = r; }
void setSampleCount(int samples) { m_sampleCount = samples; }
void setTranslation(const QVector3D &v) { m_translation = v; }
bool isPipelineInitialized() const { return m_ps != nullptr; }
void initResources();
void initResources(QRhiRenderPass *rp);
void releaseResources();
void initOutputDependentResources(const QRhiRenderPass *rp, const QSize &pixelSize);
void releaseOutputDependentResources();
void resize(const QSize &pixelSize);
void queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates);
void queueDraw(QRhiCommandBuffer *cb, const QSize &outputSizeInPixels);
......
......@@ -72,7 +72,7 @@ static QBakedShader getShader(const QString &name)
static const QSize OFFSCREEN_SIZE(512, 512);
void TriangleOnCubeRenderer::initResources()
void TriangleOnCubeRenderer::initResources(QRhiRenderPass *rp)
{
m_vbuf = m_r->createBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube));
m_vbuf->build();
......@@ -105,37 +105,6 @@ void TriangleOnCubeRenderer::initResources()
});
m_srb->build();
if (DEPTH_TEXTURE) {
m_offscreenTriangle.setDepthWrite(true);
m_depthTex = m_r->createTexture(QRhiTexture::D32, OFFSCREEN_SIZE, QRhiTexture::RenderTarget);
m_depthTex->build();
}
QRhiTextureRenderTarget::Flags rtFlags = 0;
if (IMAGE_UNDER_OFFSCREEN_RENDERING)
rtFlags |= QRhiTextureRenderTarget::PreserveColorContents;
if (DEPTH_TEXTURE) {
m_rt = m_r->createTextureRenderTarget({ nullptr, m_depthTex }, rtFlags);
} else {
QRhiTextureRenderTargetDescription desc { m_tex };
if (MRT) {
m_offscreenTriangle.setColorAttCount(2);
desc.colorAttachments.append(m_tex2);
}
m_rt = m_r->createTextureRenderTarget(desc, rtFlags);
}
m_rt->build();
m_offscreenTriangle.setRhi(m_r);
m_offscreenTriangle.initResources();
m_offscreenTriangle.setScale(2);
// m_tex and the offscreen triangle are never multisample
}
void TriangleOnCubeRenderer::initOutputDependentResources(const QRhiRenderPass *rp, const QSize &pixelSize)
{
m_ps = m_r->createGraphicsPipeline();
m_ps->setDepthTest(true);
......@@ -172,17 +141,56 @@ void TriangleOnCubeRenderer::initOutputDependentResources(const QRhiRenderPass *
m_ps->build();
if (DEPTH_TEXTURE) {
m_offscreenTriangle.setDepthWrite(true);
m_depthTex = m_r->createTexture(QRhiTexture::D32, OFFSCREEN_SIZE, QRhiTexture::RenderTarget);
m_depthTex->build();
}
QRhiTextureRenderTarget::Flags rtFlags = 0;
if (IMAGE_UNDER_OFFSCREEN_RENDERING)
rtFlags |= QRhiTextureRenderTarget::PreserveColorContents;
if (DEPTH_TEXTURE) {
m_rt = m_r->createTextureRenderTarget({ nullptr, m_depthTex }, rtFlags);
} else {
QRhiTextureRenderTargetDescription desc { m_tex };
if (MRT) {
m_offscreenTriangle.setColorAttCount(2);
desc.colorAttachments.append(m_tex2);
}
m_rt = m_r->createTextureRenderTarget(desc, rtFlags);
}
m_rp = m_rt->buildCompatibleRenderPass();
m_rt->setRenderPass(m_rp);
m_rt->build();
m_offscreenTriangle.setRhi(m_r);
m_offscreenTriangle.initResources(m_rp);
m_offscreenTriangle.setScale(2);
// m_tex and the offscreen triangle are never multisample
}
void TriangleOnCubeRenderer::resize(const QSize &pixelSize)
{
m_proj = m_r->clipSpaceCorrMatrix();
m_proj.perspective(45.0f, pixelSize.width() / (float) pixelSize.height(), 0.01f, 100.0f);
m_proj.translate(0, 0, -4);
m_offscreenTriangle.initOutputDependentResources(m_rt->renderPass(), pixelSize);
m_offscreenTriangle.resize(pixelSize);
}
void TriangleOnCubeRenderer::releaseResources()
{
m_offscreenTriangle.releaseResources();
if (m_ps) {
m_ps->releaseAndDestroy();
m_ps = nullptr;
}
if (m_srb) {
m_srb->releaseAndDestroy();
m_srb = nullptr;
......@@ -193,6 +201,11 @@ void TriangleOnCubeRenderer::releaseResources()
m_rt = nullptr;
}
if (m_rp) {
m_rp->releaseAndDestroy();
m_rp = nullptr;
}
if (m_sampler) {
m_sampler->releaseAndDestroy();
m_sampler = nullptr;
......@@ -224,16 +237,6 @@ void TriangleOnCubeRenderer::releaseResources()
}
}
void TriangleOnCubeRenderer::releaseOutputDependentResources()
{
m_offscreenTriangle.releaseOutputDependentResources();
if (m_ps) {
m_ps->releaseAndDestroy();
m_ps = nullptr;
}
}
void TriangleOnCubeRenderer::queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates)
{
if (!m_vbufReady) {
......
......@@ -59,11 +59,9 @@ public:
void setRhi(QRhi *r) { m_r = r; }
void setSampleCount(int samples) { m_sampleCount = samples; }
void setTranslation(const QVector3D &v) { m_translation = v; }
bool isPipelineInitialized() const { return m_ps != nullptr; }
void initResources();
void initResources(QRhiRenderPass *rp);
void releaseResources();
void initOutputDependentResources(const QRhiRenderPass *rp, const QSize &pixelSize);
void releaseOutputDependentResources();
void resize(const QSize &pixelSize);
void queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates);
void queueOffscreenPass(QRhiCommandBuffer *cb);
void queueDraw(QRhiCommandBuffer *cb, const QSize &outputSizeInPixels);
......@@ -79,6 +77,7 @@ private:
QRhiTexture *m_depthTex = nullptr;
QRhiSampler *m_sampler = nullptr;
QRhiTextureRenderTarget *m_rt = nullptr;
QRhiRenderPass *m_rp = nullptr;
QRhiShaderResourceBindings *m_srb = nullptr;
QRhiGraphicsPipeline *m_ps = nullptr;
......
......@@ -69,7 +69,7 @@ static QBakedShader getShader(const QString &name)
return QBakedShader();
}
void TriangleRenderer::initResources()
void TriangleRenderer::initResources(QRhiRenderPass *rp)
{
#ifdef VBUF_IS_DYNAMIC
m_vbuf = m_r->createBuffer(QRhiBuffer::Dynamic, QRhiBuffer::VertexBuffer, sizeof(vertexData));
......@@ -87,13 +87,7 @@ void TriangleRenderer::initResources()
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, m_ubuf)
});
m_srb->build();
}
// ### the following limitation may be lifted later on, the ps won't need to be created here then
// the ps depends on the renderpass -> so it is tied to the swapchain.
// on the other hand, srb and buffers are referenced from the ps but can be reused.
void TriangleRenderer::initOutputDependentResources(const QRhiRenderPass *rp, const QSize &pixelSize)
{
m_ps = m_r->createGraphicsPipeline();
QRhiGraphicsPipeline::TargetBlend premulAlphaBlend; // convenient defaults...
......@@ -134,7 +128,10 @@ void TriangleRenderer::initOutputDependentResources(const QRhiRenderPass *rp, co
m_ps->setRenderPass(rp);
m_ps->build();
}
void TriangleRenderer::resize(const QSize &pixelSize)
{
m_proj = m_r->clipSpaceCorrMatrix();
m_proj.perspective(45.0f, pixelSize.width() / (float) pixelSize.height(), 0.01f, 100.0f);
m_proj.translate(0, 0, -4);
......@@ -142,6 +139,11 @@ void TriangleRenderer::initOutputDependentResources(const QRhiRenderPass *rp, co
void TriangleRenderer::releaseResources()
{
if (m_ps) {
m_ps->releaseAndDestroy();
m_ps = nullptr;
}