QtBase  v6.3.1
triangleoncuberenderer.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the examples of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** BSD License Usage
18 ** Alternatively, you may use this file under the terms of the BSD license
19 ** as follows:
20 **
21 ** "Redistribution and use in source and binary forms, with or without
22 ** modification, are permitted provided that the following conditions are
23 ** met:
24 ** * Redistributions of source code must retain the above copyright
25 ** notice, this list of conditions and the following disclaimer.
26 ** * Redistributions in binary form must reproduce the above copyright
27 ** notice, this list of conditions and the following disclaimer in
28 ** the documentation and/or other materials provided with the
29 ** distribution.
30 ** * Neither the name of The Qt Company Ltd nor the names of its
31 ** contributors may be used to endorse or promote products derived
32 ** from this software without specific prior written permission.
33 **
34 **
35 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46 **
47 ** $QT_END_LICENSE$
48 **
49 ****************************************************************************/
50 
51 #include "triangleoncuberenderer.h"
52 #include <QFile>
53 #include <QtGui/private/qshader_p.h>
54 
55 // toggle to test the preserved content (no clear) path
57 const bool UPLOAD_UNDERLAY_ON_EVERY_FRAME = false;
58 
59 const bool DS_ATT = false; // have a depth-stencil attachment for the offscreen pass
60 
61 const bool DEPTH_TEXTURE = false; // offscreen pass uses a depth texture (verify with renderdoc etc., ignore valid.layer about ps slot 0)
62 const bool MRT = false; // two textures, the second is just cleared as the shader does not write anything (valid.layer may warn but for testing that's ok)
63 
64 #include "../shared/cube.h"
65 
66 static QShader getShader(const QString &name)
67 {
68  QFile f(name);
69  if (f.open(QIODevice::ReadOnly))
70  return QShader::fromSerialized(f.readAll());
71 
72  return QShader();
73 }
74 
75 static const QSize OFFSCREEN_SIZE(512, 512);
76 
78 {
79  m_vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube));
80  m_vbuf->setName(QByteArrayLiteral("Cube vbuf (textured with offscreen)"));
81  m_vbuf->create();
82  m_vbufReady = false;
83 
85  m_ubuf->setName(QByteArrayLiteral("Cube ubuf (textured with offscreen)"));
86  m_ubuf->create();
87 
89  m_image = QImage(QLatin1String(":/qt256.png")).scaled(OFFSCREEN_SIZE).convertToFormat(QImage::Format_RGBA8888);
90  if (m_r->isYUpInFramebuffer())
91  m_image = m_image.mirrored(); // just cause we'll flip texcoord Y when y up so accommodate our static background image as well
92  }
93 
94  m_tex = m_r->newTexture(QRhiTexture::RGBA8, OFFSCREEN_SIZE, 1, QRhiTexture::RenderTarget);
95  m_tex->setName(QByteArrayLiteral("Texture for offscreen content"));
96  m_tex->create();
97 
98  if (MRT) {
99  m_tex2 = m_r->newTexture(QRhiTexture::RGBA8, OFFSCREEN_SIZE, 1, QRhiTexture::RenderTarget);
100  m_tex2->create();
101  }
102 
103  if (DS_ATT) {
104  m_offscreenTriangle.setDepthWrite(true);
106  m_ds->create();
107  }
108 
109  if (DEPTH_TEXTURE) {
110  m_offscreenTriangle.setDepthWrite(true);
111  m_depthTex = m_r->newTexture(QRhiTexture::D32F, OFFSCREEN_SIZE, 1, QRhiTexture::RenderTarget);
112  m_depthTex->create();
113  }
114 
116  m_sampler->create();
117 
118  m_srb = m_r->newShaderResourceBindings();
119  m_srb->setBindings({
122  });
123  m_srb->create();
124 
125  m_ps = m_r->newGraphicsPipeline();
126 
127  m_ps->setDepthTest(true);
128  m_ps->setDepthWrite(true);
130 
133 
134  m_ps->setSampleCount(m_sampleCount);
135 
136  QShader vs = getShader(QLatin1String(":/texture.vert.qsb"));
137  Q_ASSERT(vs.isValid());
138  QShader fs = getShader(QLatin1String(":/texture.frag.qsb"));
139  Q_ASSERT(fs.isValid());
140  m_ps->setShaderStages({
141  { QRhiShaderStage::Vertex, vs },
143  });
144 
145  QRhiVertexInputLayout inputLayout;
146  inputLayout.setBindings({
147  { 3 * sizeof(float) },
148  { 2 * sizeof(float) }
149  });
150  inputLayout.setAttributes({
153  });
154 
155  m_ps->setVertexInputLayout(inputLayout);
156  m_ps->setShaderResourceBindings(m_srb);
157  m_ps->setRenderPassDescriptor(rp);
158 
159  m_ps->create();
160 
164 
165  if (DEPTH_TEXTURE) {
167  desc.setDepthTexture(m_depthTex);
168  m_rt = m_r->newTextureRenderTarget(desc, rtFlags);
169  } else {
171  QRhiColorAttachment color0 { m_tex };
172  if (DS_ATT)
173  desc.setDepthStencilBuffer(m_ds);
174  if (MRT) {
175  m_offscreenTriangle.setColorAttCount(2);
176  QRhiColorAttachment color1 { m_tex2 };
177  desc.setColorAttachments({ color0, color1 });
178  } else {
179  desc.setColorAttachments({ color0 });
180  }
181  m_rt = m_r->newTextureRenderTarget(desc, rtFlags);
182  }
183 
184  m_rp = m_rt->newCompatibleRenderPassDescriptor();
185  m_rt->setRenderPassDescriptor(m_rp);
186 
187  m_rt->create();
188 
189  m_offscreenTriangle.setRhi(m_r);
190  m_offscreenTriangle.initResources(m_rp);
191  m_offscreenTriangle.setScale(2);
192  // m_tex and the offscreen triangle are never multisample
193 }
194 
195 void TriangleOnCubeRenderer::resize(const QSize &pixelSize)
196 {
197  m_proj = m_r->clipSpaceCorrMatrix();
198  m_proj.perspective(45.0f, pixelSize.width() / (float) pixelSize.height(), 0.01f, 100.0f);
199  m_proj.translate(0, 0, -4);
200 
201  m_offscreenTriangle.resize(pixelSize);
202 }
203 
205 {
206  m_offscreenTriangle.releaseResources();
207 
208  delete m_ps;
209  m_ps = nullptr;
210 
211  delete m_srb;
212  m_srb = nullptr;
213 
214  delete m_rt;
215  m_rt = nullptr;
216 
217  delete m_rp;
218  m_rp = nullptr;
219 
220  delete m_sampler;
221  m_sampler = nullptr;
222 
223  delete m_depthTex;
224  m_depthTex = nullptr;
225 
226  delete m_tex2;
227  m_tex2 = nullptr;
228 
229  delete m_tex;
230  m_tex = nullptr;
231 
232  delete m_ds;
233  m_ds = nullptr;
234 
235  delete m_ubuf;
236  m_ubuf = nullptr;
237 
238  delete m_vbuf;
239  m_vbuf = nullptr;
240 }
241 
243 {
244  if (!m_vbufReady) {
245  m_vbufReady = true;
246  resourceUpdates->uploadStaticBuffer(m_vbuf, cube);
247  qint32 flip = m_r->isYUpInFramebuffer() ? 1 : 0;
248  resourceUpdates->updateDynamicBuffer(m_ubuf, 64, 4, &flip);
249  }
250 
251  m_rotation += 1.0f;
252  QMatrix4x4 mvp = m_proj;
253  mvp.translate(m_translation);
254  mvp.scale(0.5f);
255  mvp.rotate(m_rotation, 1, 0, 0);
256  resourceUpdates->updateDynamicBuffer(m_ubuf, 0, 64, mvp.constData());
257 
258  // ###
259 // if (DEPTH_TEXTURE) {
260 // // m_tex is basically undefined here, be nice and transition the layout properly at least
261 // resourceUpdates->prepareTextureForUse(m_tex, QRhiResourceUpdateBatch::TextureRead);
262 // }
263 }
264 
266 {
268  m_offscreenTriangle.queueResourceUpdates(u);
269 
270  if (IMAGE_UNDER_OFFSCREEN_RENDERING && !m_image.isNull()) {
271  u->uploadTexture(m_tex, m_image);
273  m_image = QImage();
274  }
275 
276  cb->beginPass(m_rt, QColor::fromRgbF(0.0f, 0.4f, 0.7f, 1.0f), { 1.0f, 0 }, u);
277  m_offscreenTriangle.queueDraw(cb, OFFSCREEN_SIZE);
278  cb->endPass();
279 }
280 
282 {
283  cb->setGraphicsPipeline(m_ps);
284  cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()));
285  cb->setShaderResources();
286  const QRhiCommandBuffer::VertexInput vbufBindings[] = {
287  { m_vbuf, 0 },
288  { m_vbuf, quint32(36 * 3 * sizeof(float)) }
289  };
290  cb->setVertexInput(0, 2, vbufBindings);
291  cb->draw(36);
292 }
small capitals from c petite p scientific f u
Definition: afcover.h:88
static QColor fromRgbF(float r, float g, float b, float a=1.0)
Definition: qcolor.cpp:2424
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:94
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:73
bool isNull() const
Definition: qimage.cpp:1319
QImage scaled(int w, int h, Qt::AspectRatioMode aspectMode=Qt::IgnoreAspectRatio, Qt::TransformationMode mode=Qt::FastTransformation) const
Definition: qimage.h:244
@ Format_RGBA8888
Definition: qimage.h:95
QImage mirrored(bool horizontally=false, bool vertically=true) const &
Definition: qimage.h:254
QImage convertToFormat(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor) const &
Definition: qimage.h:160
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition: qmatrix4x4.h:61
void rotate(float angle, const QVector3D &vector)
void scale(const QVector3D &vector)
Definition: qmatrix4x4.cpp:803
void perspective(float verticalAngle, float aspectRatio, float nearPlane, float farPlane)
const float * constData() const
Definition: qmatrix4x4.h:183
void translate(const QVector3D &vector)
Definition: qmatrix4x4.cpp:965
@ Immutable
Definition: qrhi_p.h:717
@ Dynamic
Definition: qrhi_p.h:719
@ VertexBuffer
Definition: qrhi_p.h:723
@ UniformBuffer
Definition: qrhi_p.h:725
virtual bool create()=0
QPair< QRhiBuffer *, quint32 > VertexInput
Definition: qrhi_p.h:1426
void setCullMode(CullMode mode)
Definition: qrhi_p.h:1216
void setFrontFace(FrontFace f)
Definition: qrhi_p.h:1219
void setDepthWrite(bool enable)
Definition: qrhi_p.h:1235
void setShaderResourceBindings(QRhiShaderResourceBindings *srb)
Definition: qrhi_p.h:1281
void setDepthOp(CompareOp op)
Definition: qrhi_p.h:1238
void setVertexInputLayout(const QRhiVertexInputLayout &layout)
Definition: qrhi_p.h:1278
void setShaderStages(std::initializer_list< QRhiShaderStage > list)
Definition: qrhi_p.h:1267
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Definition: qrhi_p.h:1284
void setSampleCount(int s)
Definition: qrhi_p.h:1256
virtual bool create()=0
void setDepthTest(bool enable)
Definition: qrhi_p.h:1232
QMatrix4x4 clipSpaceCorrMatrix() const
Definition: qrhi.cpp:6299
bool isYUpInFramebuffer() const
Definition: qrhi.cpp:6238
QRhiShaderResourceBindings * newShaderResourceBindings()
Definition: qrhi.cpp:6543
QRhiRenderBuffer * newRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount=1, QRhiRenderBuffer::Flags flags={}, QRhiTexture::Format backingFormatHint=QRhiTexture::UnknownFormat)
Definition: qrhi.cpp:6589
QRhiBuffer * newBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, int size)
Definition: qrhi.cpp:6562
QRhiSampler * newSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter, QRhiSampler::Filter mipmapMode, QRhiSampler::AddressMode addressU, QRhiSampler::AddressMode addressV, QRhiSampler::AddressMode addressW=QRhiSampler::Repeat)
Definition: qrhi.cpp:6679
QRhiTextureRenderTarget * newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags={})
Definition: qrhi.cpp:6696
QRhiGraphicsPipeline * newGraphicsPipeline()
Definition: qrhi.cpp:6520
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
Definition: qrhi.cpp:6609
QRhiResourceUpdateBatch * nextResourceUpdateBatch()
Definition: qrhi.cpp:5568
virtual bool create()=0
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Definition: qrhi_p.h:1011
void setName(const QByteArray &name)
Definition: qrhi.cpp:2068
void uploadStaticBuffer(QRhiBuffer *buf, int offset, int size, const void *data)
Definition: qrhi.cpp:5346
void updateDynamicBuffer(QRhiBuffer *buf, int offset, int size, const void *data)
Definition: qrhi.cpp:5326
virtual bool create()=0
@ ClampToEdge
Definition: qrhi_p.h:884
static QRhiShaderResourceBinding sampledTexture(int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
Definition: qrhi.cpp:3374
static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf)
Definition: qrhi.cpp:3268
void setBindings(std::initializer_list< QRhiShaderResourceBinding > list)
Definition: qrhi_p.h:1052
virtual bool create()=0
@ RenderTarget
Definition: qrhi_p.h:766
virtual bool create()=0
QSize pixelSize() const
Definition: qrhi_p.h:840
virtual QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor()=0
virtual bool create()=0
void setBindings(std::initializer_list< QRhiVertexInputBinding > list)
Definition: qrhi_p.h:257
void setAttributes(std::initializer_list< QRhiVertexInputAttribute > list)
Definition: qrhi_p.h:268
static QShader fromSerialized(const QByteArray &data)
Definition: qshader.cpp:418
bool isValid() const
Definition: qshader.cpp:266
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:55
constexpr int height() const noexcept
Definition: qsize.h:160
constexpr int width() const noexcept
Definition: qsize.h:157
The QString class provides a Unicode character string.
Definition: qstring.h:388
void queueOffscreenPass(QRhiCommandBuffer *cb)
void queueDraw(QRhiCommandBuffer *cb, const QSize &outputSizeInPixels)
void queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates)
void resize(const QSize &pixelSize)
void initResources(QRhiRenderPassDescriptor *rp)
void setColorAttCount(int count)
void queueDraw(QRhiCommandBuffer *cb, const QSize &outputSizeInPixels)
void setDepthWrite(bool enable)
void setScale(float f)
void setRhi(QRhi *r)
void releaseResources() override
void queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates)
void initResources() override
void resize(const QSize &pixelSize)
QShader getShader(const QString &name)
Definition: examplefw.h:86
@ color1
Definition: qnamespace.h:60
@ color0
Definition: qnamespace.h:59
#define QByteArrayLiteral(str)
Definition: qbytearray.h:80
Flags
unsigned int quint32
Definition: qglobal.h:288
int qint32
Definition: qglobal.h:287
@ desc
GLfloat GLfloat f
GLuint name
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
const bool IMAGE_UNDER_OFFSCREEN_RENDERING
const bool MRT
const bool DEPTH_TEXTURE
const bool UPLOAD_UNDERLAY_ON_EVERY_FRAME
const bool DS_ATT