1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQuick module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
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** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qsgdefaultinternalimagenode_p.h"
41#include <private/qsgdefaultrendercontext_p.h>
42#include <private/qsgmaterialshader_p.h>
43#include <private/qsgtexturematerial_p.h>
44#include <QtGui/qopenglfunctions.h>
45#include <QtCore/qmath.h>
46#include <QtGui/private/qrhi_p.h>
47
48QT_BEGIN_NAMESPACE
49
50class SmoothTextureMaterialShader : public QSGTextureMaterialShader
51{
52public:
53 SmoothTextureMaterialShader();
54
55 void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
56 char const *const *attributeNames() const override;
57
58protected:
59 void initialize() override;
60
61 int m_pixelSizeLoc;
62};
63
64class SmoothTextureMaterialRhiShader : public QSGTextureMaterialRhiShader
65{
66public:
67 SmoothTextureMaterialRhiShader();
68
69 bool updateUniformData(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
70};
71
72
73QSGSmoothTextureMaterial::QSGSmoothTextureMaterial()
74{
75 setFlag(SupportsRhiShader, true);
76 setFlag(RequiresFullMatrixExceptTranslate, true);
77 setFlag(Blending, true);
78}
79
80void QSGSmoothTextureMaterial::setTexture(QSGTexture *texture)
81{
82 m_texture = texture;
83}
84
85QSGMaterialType *QSGSmoothTextureMaterial::type() const
86{
87 static QSGMaterialType type;
88 return &type;
89}
90
91QSGMaterialShader *QSGSmoothTextureMaterial::createShader() const
92{
93 if (flags().testFlag(RhiShaderWanted))
94 return new SmoothTextureMaterialRhiShader;
95 else
96 return new SmoothTextureMaterialShader;
97}
98
99SmoothTextureMaterialShader::SmoothTextureMaterialShader()
100{
101 setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/smoothtexture.vert"));
102 setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/smoothtexture.frag"));
103}
104
105void SmoothTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
106{
107 if (oldEffect == nullptr) {
108 // The viewport is constant, so set the pixel size uniform only once.
109 QRect r = state.viewportRect();
110 program()->setUniformValue(m_pixelSizeLoc, 2.0f / r.width(), 2.0f / r.height());
111 }
112 QSGTextureMaterialShader::updateState(state, newEffect, oldEffect);
113}
114
115char const *const *SmoothTextureMaterialShader::attributeNames() const
116{
117 static char const *const attributes[] = {
118 "vertex",
119 "multiTexCoord",
120 "vertexOffset",
121 "texCoordOffset",
122 nullptr
123 };
124 return attributes;
125}
126
127void SmoothTextureMaterialShader::initialize()
128{
129 m_pixelSizeLoc = program()->uniformLocation("pixelSize");
130 QSGTextureMaterialShader::initialize();
131}
132
133SmoothTextureMaterialRhiShader::SmoothTextureMaterialRhiShader()
134{
135 setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/smoothtexture.vert.qsb"));
136 setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/smoothtexture.frag.qsb"));
137}
138
139bool SmoothTextureMaterialRhiShader::updateUniformData(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
140{
141 bool changed = false;
142 QByteArray *buf = state.uniformData();
143
144 if (!oldMaterial) {
145 // The viewport is constant, so set the pixel size uniform only once (per batches with the same material).
146 const QRect r = state.viewportRect();
147 const QVector2D v(2.0f / r.width(), 2.0f / r.height());
148 memcpy(buf->data() + 64 + 8, &v, 8);
149 changed = true;
150 }
151
152 changed |= QSGTextureMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial);
153
154 return changed;
155}
156
157
158QSGDefaultInternalImageNode::QSGDefaultInternalImageNode(QSGDefaultRenderContext *rc)
159 : m_rc(rc)
160{
161 setMaterial(&m_materialO);
162 setOpaqueMaterial(&m_material);
163}
164
165void QSGDefaultInternalImageNode::setFiltering(QSGTexture::Filtering filtering)
166{
167 if (m_material.filtering() == filtering)
168 return;
169
170 m_material.setFiltering(filtering);
171 m_materialO.setFiltering(filtering);
172 m_smoothMaterial.setFiltering(filtering);
173 markDirty(DirtyMaterial);
174}
175
176void QSGDefaultInternalImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
177{
178 if (m_material.mipmapFiltering() == filtering)
179 return;
180
181 m_material.setMipmapFiltering(filtering);
182 m_materialO.setMipmapFiltering(filtering);
183 m_smoothMaterial.setMipmapFiltering(filtering);
184 markDirty(DirtyMaterial);
185}
186
187void QSGDefaultInternalImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
188{
189 if (m_material.verticalWrapMode() == wrapMode)
190 return;
191
192 m_material.setVerticalWrapMode(wrapMode);
193 m_materialO.setVerticalWrapMode(wrapMode);
194 m_smoothMaterial.setVerticalWrapMode(wrapMode);
195 markDirty(DirtyMaterial);
196}
197
198void QSGDefaultInternalImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
199{
200 if (m_material.horizontalWrapMode() == wrapMode)
201 return;
202
203 m_material.setHorizontalWrapMode(wrapMode);
204 m_materialO.setHorizontalWrapMode(wrapMode);
205 m_smoothMaterial.setHorizontalWrapMode(wrapMode);
206 markDirty(DirtyMaterial);
207}
208
209void QSGDefaultInternalImageNode::updateMaterialAntialiasing()
210{
211 if (m_antialiasing) {
212 setMaterial(&m_smoothMaterial);
213 setOpaqueMaterial(nullptr);
214 } else {
215 setMaterial(&m_materialO);
216 setOpaqueMaterial(&m_material);
217 }
218}
219
220void QSGDefaultInternalImageNode::setMaterialTexture(QSGTexture *texture)
221{
222 m_material.setTexture(texture);
223 m_materialO.setTexture(texture);
224 m_smoothMaterial.setTexture(texture);
225}
226
227QSGTexture *QSGDefaultInternalImageNode::materialTexture() const
228{
229 return m_material.texture();
230}
231
232bool QSGDefaultInternalImageNode::updateMaterialBlending()
233{
234 const bool alpha = m_material.flags() & QSGMaterial::Blending;
235 if (materialTexture() && alpha != materialTexture()->hasAlphaChannel()) {
236 m_material.setFlag(QSGMaterial::Blending, !alpha);
237 return true;
238 }
239 return false;
240}
241
242inline static bool isPowerOfTwo(int x)
243{
244 // Assumption: x >= 1
245 return x == (x & -x);
246}
247
248bool QSGDefaultInternalImageNode::supportsWrap(const QSize &size) const
249{
250 bool wrapSupported = true;
251
252 if (m_rc->rhi()) {
253 wrapSupported = m_rc->rhi()->isFeatureSupported(QRhi::NPOTTextureRepeat)
254 || (isPowerOfTwo(size.width()) && isPowerOfTwo(size.height()));
255 } else {
256 QOpenGLContext *ctx = QOpenGLContext::currentContext();
257#ifndef QT_OPENGL_ES_2
258 if (ctx->isOpenGLES())
259#endif
260 {
261 bool npotSupported = ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat);
262 const bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
263 wrapSupported = npotSupported || !isNpot;
264 }
265 }
266
267 return wrapSupported;
268}
269
270QT_END_NAMESPACE
271