1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsgtexturematerial_p.h"
5#include <private/qsgtexture_p.h>
6#include <rhi/qrhi.h>
7
8QT_BEGIN_NAMESPACE
9
10inline static bool isPowerOfTwo(int x)
11{
12 // Assumption: x >= 1
13 return x == (x & -x);
14}
15
16QSGOpaqueTextureMaterialRhiShader::QSGOpaqueTextureMaterialRhiShader()
17{
18 setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/opaquetexture.vert.qsb"));
19 setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/opaquetexture.frag.qsb"));
20}
21
22bool QSGOpaqueTextureMaterialRhiShader::updateUniformData(RenderState &state, QSGMaterial *, QSGMaterial *)
23{
24 bool changed = false;
25 QByteArray *buf = state.uniformData();
26
27 if (state.isMatrixDirty()) {
28 const QMatrix4x4 m = state.combinedMatrix();
29 memcpy(dest: buf->data(), src: m.constData(), n: 64);
30 changed = true;
31 }
32
33 return changed;
34}
35
36void QSGOpaqueTextureMaterialRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
37 QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
38{
39 if (binding != 1)
40 return;
41
42#ifdef QT_NO_DEBUG
43 Q_UNUSED(oldMaterial);
44#endif
45 Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
46 QSGOpaqueTextureMaterial *tx = static_cast<QSGOpaqueTextureMaterial *>(newMaterial);
47 QSGTexture *t = tx->texture();
48 if (!t) {
49 *texture = nullptr;
50 return;
51 }
52
53 t->setFiltering(tx->filtering());
54 t->setMipmapFiltering(tx->mipmapFiltering());
55 t->setAnisotropyLevel(tx->anisotropyLevel());
56
57 t->setHorizontalWrapMode(tx->horizontalWrapMode());
58 t->setVerticalWrapMode(tx->verticalWrapMode());
59 if (!state.rhi()->isFeatureSupported(feature: QRhi::NPOTTextureRepeat)) {
60 QSize size = t->textureSize();
61 const bool isNpot = !isPowerOfTwo(x: size.width()) || !isPowerOfTwo(x: size.height());
62 if (isNpot) {
63 t->setHorizontalWrapMode(QSGTexture::ClampToEdge);
64 t->setVerticalWrapMode(QSGTexture::ClampToEdge);
65 t->setMipmapFiltering(QSGTexture::None);
66 }
67 }
68
69 t->commitTextureOperations(rhi: state.rhi(), resourceUpdates: state.resourceUpdateBatch());
70 *texture = t;
71}
72
73
74/*!
75 \class QSGOpaqueTextureMaterial
76 \brief The QSGOpaqueTextureMaterial class provides a convenient way of
77 rendering textured geometry in the scene graph.
78 \inmodule QtQuick
79 \ingroup qtquick-scenegraph-materials
80
81 \warning This utility class is only functional when running with the
82 default backend of the Qt Quick scenegraph.
83
84 The opaque textured material will fill every pixel in a geometry with
85 the supplied texture. The material does not respect the opacity of the
86 QSGMaterialShader::RenderState, so opacity nodes in the parent chain
87 of nodes using this material, have no effect.
88
89 The geometry to be rendered with an opaque texture material requires
90 vertices in attribute location 0 and texture coordinates in attribute
91 location 1. The texture coordinate is a 2-dimensional floating-point
92 tuple. The QSGGeometry::defaultAttributes_TexturedPoint2D returns an
93 attribute set compatible with this material.
94
95 The texture to be rendered can be set using setTexture(). How the
96 texture should be rendered can be specified using setMipmapFiltering(),
97 setFiltering(), setHorizontalWrapMode() and setVerticalWrapMode().
98 The rendering state is set on the texture instance just before it
99 is bound.
100
101 The opaque textured material respects the current matrix and the alpha
102 channel of the texture. It will disregard the accumulated opacity in
103 the scenegraph.
104
105 A texture material must have a texture set before it is used as
106 a material in the scene graph.
107 */
108
109
110
111/*!
112 Creates a new QSGOpaqueTextureMaterial.
113
114 The default mipmap filtering and filtering mode is set to
115 QSGTexture::Nearest. The default wrap modes is set to
116 \c QSGTexture::ClampToEdge.
117
118 */
119QSGOpaqueTextureMaterial::QSGOpaqueTextureMaterial()
120 : m_texture(nullptr)
121 , m_filtering(QSGTexture::Nearest)
122 , m_mipmap_filtering(QSGTexture::None)
123 , m_horizontal_wrap(QSGTexture::ClampToEdge)
124 , m_vertical_wrap(QSGTexture::ClampToEdge)
125 , m_anisotropy_level(QSGTexture::AnisotropyNone)
126{
127}
128
129
130/*!
131 \internal
132 */
133QSGMaterialType *QSGOpaqueTextureMaterial::type() const
134{
135 static QSGMaterialType type;
136 return &type;
137}
138
139/*!
140 \internal
141 */
142QSGMaterialShader *QSGOpaqueTextureMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
143{
144 Q_UNUSED(renderMode);
145 return new QSGOpaqueTextureMaterialRhiShader;
146}
147
148
149/*!
150 \fn QSGTexture *QSGOpaqueTextureMaterial::texture() const
151
152 Returns this texture material's texture.
153 */
154
155
156
157/*!
158 Sets the texture of this material to \a texture.
159
160 The material does not take ownership of the texture.
161 */
162
163void QSGOpaqueTextureMaterial::setTexture(QSGTexture *texture)
164{
165 m_texture = texture;
166 setFlag(flags: Blending, on: m_texture ? m_texture->hasAlphaChannel() : false);
167}
168
169
170
171/*!
172 \fn void QSGOpaqueTextureMaterial::setMipmapFiltering(QSGTexture::Filtering filtering)
173
174 Sets the mipmap mode to \a filtering.
175
176 The mipmap filtering mode is set on the texture instance just before the
177 texture is bound for rendering.
178
179 If the texture does not have mipmapping support, enabling mipmapping has no
180 effect.
181 */
182
183
184
185/*!
186 \fn QSGTexture::Filtering QSGOpaqueTextureMaterial::mipmapFiltering() const
187
188 Returns this material's mipmap filtering mode.
189
190 The default mipmap mode is \c QSGTexture::Nearest.
191 */
192
193
194
195/*!
196 \fn void QSGOpaqueTextureMaterial::setFiltering(QSGTexture::Filtering filtering)
197
198 Sets the filtering to \a filtering.
199
200 The filtering mode is set on the texture instance just before the texture
201 is bound for rendering.
202 */
203
204
205
206/*!
207 \fn QSGTexture::Filtering QSGOpaqueTextureMaterial::filtering() const
208
209 Returns this material's filtering mode.
210
211 The default filtering is \c QSGTexture::Nearest.
212 */
213
214
215
216/*!
217 \fn void QSGOpaqueTextureMaterial::setHorizontalWrapMode(QSGTexture::WrapMode mode)
218
219 Sets the horizontal wrap mode to \a mode.
220
221 The horizontal wrap mode is set on the texture instance just before the texture
222 is bound for rendering.
223 */
224
225
226
227 /*!
228 \fn QSGTexture::WrapMode QSGOpaqueTextureMaterial::horizontalWrapMode() const
229
230 Returns this material's horizontal wrap mode.
231
232 The default horizontal wrap mode is \c QSGTexture::ClampToEdge.
233 */
234
235
236
237/*!
238 \fn void QSGOpaqueTextureMaterial::setVerticalWrapMode(QSGTexture::WrapMode mode)
239
240 Sets the vertical wrap mode to \a mode.
241
242 The vertical wrap mode is set on the texture instance just before the texture
243 is bound for rendering.
244 */
245
246
247
248 /*!
249 \fn QSGTexture::WrapMode QSGOpaqueTextureMaterial::verticalWrapMode() const
250
251 Returns this material's vertical wrap mode.
252
253 The default vertical wrap mode is \c QSGTexture::ClampToEdge.
254 */
255
256/*!
257 \fn void QSGOpaqueTextureMaterial::setAnisotropyLevel(QSGTexture::AnisotropyLevel level)
258
259 Sets this material's anistropy level to \a level.
260*/
261
262/*!
263 \fn QSGTexture::AnisotropyLevel QSGOpaqueTextureMaterial::anisotropyLevel() const
264
265 Returns this material's anistropy level.
266*/
267
268/*!
269 \internal
270 */
271
272int QSGOpaqueTextureMaterial::compare(const QSGMaterial *o) const
273{
274 Q_ASSERT(o && type() == o->type());
275 const QSGOpaqueTextureMaterial *other = static_cast<const QSGOpaqueTextureMaterial *>(o);
276 Q_ASSERT(m_texture);
277 Q_ASSERT(other->texture());
278 const qint64 diff = m_texture->comparisonKey() - other->texture()->comparisonKey();
279 if (diff != 0)
280 return diff < 0 ? -1 : 1;
281 return int(m_filtering) - int(other->m_filtering);
282}
283
284
285
286/*!
287 \class QSGTextureMaterial
288 \brief The QSGTextureMaterial class provides a convenient way of
289 rendering textured geometry in the scene graph.
290 \inmodule QtQuick
291 \ingroup qtquick-scenegraph-materials
292
293 \warning This utility class is only functional when running with the
294 default backend of the Qt Quick scenegraph.
295
296 The textured material will fill every pixel in a geometry with
297 the supplied texture.
298
299 The geometry to be rendered with a texture material requires
300 vertices in attribute location 0 and texture coordinates in attribute
301 location 1. The texture coordinate is a 2-dimensional floating-point
302 tuple. The QSGGeometry::defaultAttributes_TexturedPoint2D returns an
303 attribute set compatible with this material.
304
305 The texture to be rendered can be set using setTexture(). How the
306 texture should be rendered can be specified using setMipmapFiltering(),
307 setFiltering(), setHorizontalWrapMode() and setVerticalWrapMode().
308 The rendering state is set on the texture instance just before it
309 is bound.
310
311 The textured material respects the current matrix and the alpha
312 channel of the texture. It will also respect the accumulated opacity
313 in the scenegraph.
314
315 A texture material must have a texture set before it is used as
316 a material in the scene graph.
317 */
318
319/*!
320 \internal
321 */
322
323QSGMaterialType *QSGTextureMaterial::type() const
324{
325 static QSGMaterialType type;
326 return &type;
327}
328
329/*!
330 \internal
331 */
332
333QSGMaterialShader *QSGTextureMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
334{
335 Q_UNUSED(renderMode);
336 return new QSGTextureMaterialRhiShader;
337}
338
339
340QSGTextureMaterialRhiShader::QSGTextureMaterialRhiShader()
341{
342 setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/texture.vert.qsb"));
343 setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/texture.frag.qsb"));
344}
345
346bool QSGTextureMaterialRhiShader::updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
347{
348 bool changed = false;
349 QByteArray *buf = state.uniformData();
350
351 if (state.isOpacityDirty()) {
352 const float opacity = state.opacity();
353 memcpy(dest: buf->data() + 64, src: &opacity, n: 4);
354 changed = true;
355 }
356
357 changed |= QSGOpaqueTextureMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial);
358
359 return changed;
360}
361
362QT_END_NAMESPACE
363

source code of qtdeclarative/src/quick/scenegraph/util/qsgtexturematerial.cpp