examplewindow.cpp 8.26 KB
Newer Older
1
/****************************************************************************
Laszlo Agocs's avatar
Laszlo Agocs committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

#include "examplewindow.h"

void ExampleWindow::exposeEvent(QExposeEvent *)
{
    // You never know how Vulkan behaves today - at some point it started
    // requiring a swapchain recreate on unexpose-expose on Windows at least
    // (where unexpose comes when e.g. minimizing the window). Manage this.
    if (!isExposed() && m_running)
        m_notExposed = true;

    if (isExposed() && m_running && m_notExposed) {
        m_notExposed = false;
        m_newlyExposed = true;
        render();
    }

    if (isExposed() && !m_running) {
        m_running = true;
        init();
        recreateSwapChain();
        render();
    }
}

bool ExampleWindow::event(QEvent *e)
{
    switch (e->type()) {
    case QEvent::UpdateRequest:
        render();
        break;

    // With Vulkan the swapchain must be destroyed before the surface as per
    // spec. This is not ideal for us because the surface is managed by the
    // QPlatformWindow which may be gone already when the unexpose comes,
    // making the validation layer scream. The solution is to listen to the
    // PlatformSurface events.
    case QEvent::PlatformSurface:
        if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
            releaseSwapChain();
        break;

    default:
        break;
    }

    return QWindow::event(e);
}

void ExampleWindow::init()
{
101
    m_sc = m_r->newSwapChain();
102
103
104
    if (!m_sc)
        return;

Laszlo Agocs's avatar
Laszlo Agocs committed
105
    // allow depth-stencil, although we do not actually enable depth test/write for the triangle
106
107
108
109
    m_ds = m_r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
                                QSize(), // we don't know the size yet, this is fine
                                m_sampleCount,
                                QRhiRenderBuffer::ToBeUsedWithSwapChainOnly);
Laszlo Agocs's avatar
Laszlo Agocs committed
110
111
112
    m_sc->setWindow(this);
    m_sc->setDepthStencil(m_ds);
    m_sc->setSampleCount(m_sampleCount);
113
114
    m_scrp = m_sc->newCompatibleRenderPassDescriptor();
    m_sc->setRenderPassDescriptor(m_scrp);
Laszlo Agocs's avatar
Laszlo Agocs committed
115

116
117
    m_triRenderer.setRhi(m_r);
    m_triRenderer.setSampleCount(m_sampleCount);
Laszlo Agocs's avatar
Laszlo Agocs committed
118
    m_triRenderer.initResources(m_scrp);
119
120
121
122
123
124

    if (!m_triangleOnly) {
        m_triRenderer.setTranslation(QVector3D(0, 0.5f, 0));

        m_quadRenderer.setRhi(m_r);
        m_quadRenderer.setSampleCount(m_sampleCount);
Laszlo Agocs's avatar
Laszlo Agocs committed
125
126
        m_quadRenderer.setPipeline(m_triRenderer.pipeline());
        m_quadRenderer.initResources(m_scrp);
127
128
129
130
        m_quadRenderer.setTranslation(QVector3D(1.5f, -0.5f, 0));

        m_cubeRenderer.setRhi(m_r);
        m_cubeRenderer.setSampleCount(m_sampleCount);
Laszlo Agocs's avatar
Laszlo Agocs committed
131
        m_cubeRenderer.initResources(m_scrp);
132
133
134
135
136
137
        m_cubeRenderer.setTranslation(QVector3D(0, -0.5f, 0));
    }

    if (!m_onScreenOnly) {
        m_liveTexCubeRenderer.setRhi(m_r);
        m_liveTexCubeRenderer.setSampleCount(m_sampleCount);
Laszlo Agocs's avatar
Laszlo Agocs committed
138
        m_liveTexCubeRenderer.initResources(m_scrp);
139
140
141
142
143
144
145
146
147
148
149
150
151
        m_liveTexCubeRenderer.setTranslation(QVector3D(-2.0f, 0, 0));
    }
}

void ExampleWindow::releaseResources()
{
    m_triRenderer.releaseResources();

    if (!m_triangleOnly) {
        m_quadRenderer.releaseResources();
        m_cubeRenderer.releaseResources();
    }

Laszlo Agocs's avatar
Laszlo Agocs committed
152
    if (!m_onScreenOnly)
153
        m_liveTexCubeRenderer.releaseResources();
Laszlo Agocs's avatar
Laszlo Agocs committed
154
155
156
157
158
159
160
161
162

    if (m_scrp) {
        m_scrp->releaseAndDestroy();
        m_scrp = nullptr;
    }

    if (m_ds) {
        m_ds->releaseAndDestroy();
        m_ds = nullptr;
163
164
165
166
167
168
169
170
171
172
173
174
175
    }

    delete m_sc;
    m_sc = nullptr;

    delete m_r;
    m_r = nullptr;
}

void ExampleWindow::recreateSwapChain()
{
    const QSize outputSize = size() * devicePixelRatio();

Laszlo Agocs's avatar
Laszlo Agocs committed
176
177
    m_ds->setPixelSize(outputSize);
    m_ds->build(); // == m_ds->release(); m_ds->build();
178

Laszlo Agocs's avatar
Laszlo Agocs committed
179
180
    m_sc->setRequestedPixelSize(outputSize);
    m_hasSwapChain = m_sc->buildOrResize();
Laszlo Agocs's avatar
Laszlo Agocs committed
181
    m_resizedSwapChain = true;
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
}

void ExampleWindow::releaseSwapChain()
{
    if (m_hasSwapChain) {
        m_hasSwapChain = false;
        m_sc->release();
    }
}

void ExampleWindow::render()
{
    if (!m_hasSwapChain || m_notExposed)
        return;

Laszlo Agocs's avatar
Laszlo Agocs committed
197
    if (m_sc->requestedPixelSize() != size() * devicePixelRatio() || m_newlyExposed) {
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
        recreateSwapChain();
        if (!m_hasSwapChain)
            return;
        m_newlyExposed = false;
    }

    QRhi::FrameOpResult r = m_r->beginFrame(m_sc);
    if (r == QRhi::FrameOpSwapChainOutOfDate) {
        recreateSwapChain();
        if (!m_hasSwapChain)
            return;
        r = m_r->beginFrame(m_sc);
    }
    if (r != QRhi::FrameOpSuccess) {
        requestUpdate();
        return;
    }

Laszlo Agocs's avatar
Laszlo Agocs committed
216
217
218
    if (m_resizedSwapChain) {
        m_resizedSwapChain = false;
        m_triRenderer.resize(m_sc->effectiveSizeInPixels());
219
        if (!m_triangleOnly) {
Laszlo Agocs's avatar
Laszlo Agocs committed
220
221
            m_quadRenderer.resize(m_sc->effectiveSizeInPixels());
            m_cubeRenderer.resize(m_sc->effectiveSizeInPixels());
222
223
        }
        if (!m_onScreenOnly)
Laszlo Agocs's avatar
Laszlo Agocs committed
224
            m_liveTexCubeRenderer.resize(m_sc->effectiveSizeInPixels());
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
    }

    QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
    if (!m_onScreenOnly)
        m_liveTexCubeRenderer.queueOffscreenPass(cb);

    QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch();
    m_triRenderer.queueResourceUpdates(u);
    if (!m_triangleOnly) {
        m_quadRenderer.queueResourceUpdates(u);
        m_cubeRenderer.queueResourceUpdates(u);
    }
    if (!m_onScreenOnly)
        m_liveTexCubeRenderer.queueResourceUpdates(u);

    m_r->beginPass(m_sc->currentFrameRenderTarget(), cb, { 0.4f, 0.7f, 0.0f, 1.0f }, { 1.0f, 0 }, u);
    m_triRenderer.queueDraw(cb, m_sc->effectiveSizeInPixels());
    if (!m_triangleOnly) {
        m_quadRenderer.queueDraw(cb, m_sc->effectiveSizeInPixels());
        m_cubeRenderer.queueDraw(cb, m_sc->effectiveSizeInPixels());
    }
    if (!m_onScreenOnly)
        m_liveTexCubeRenderer.queueDraw(cb, m_sc->effectiveSizeInPixels());
    m_r->endPass(cb);

    m_r->endFrame(m_sc);

    requestUpdate(); // render continuously, throttled by the presentation rate
}