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 "qsgdefaultinternalimagenode_p.h" |
5 | #include <private/qsgdefaultrendercontext_p.h> |
6 | #include <private/qsgmaterialshader_p.h> |
7 | #include <private/qsgtexturematerial_p.h> |
8 | #include <qopenglfunctions.h> |
9 | #include <QtCore/qmath.h> |
10 | #include <rhi/qrhi.h> |
11 | |
12 | QT_BEGIN_NAMESPACE |
13 | |
14 | class SmoothTextureMaterialRhiShader : public QSGTextureMaterialRhiShader |
15 | { |
16 | public: |
17 | SmoothTextureMaterialRhiShader(); |
18 | |
19 | bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; |
20 | }; |
21 | |
22 | |
23 | QSGSmoothTextureMaterial::QSGSmoothTextureMaterial() |
24 | { |
25 | setFlag(flags: RequiresFullMatrixExceptTranslate, on: true); |
26 | setFlag(flags: Blending, on: true); |
27 | } |
28 | |
29 | void QSGSmoothTextureMaterial::setTexture(QSGTexture *texture) |
30 | { |
31 | m_texture = texture; |
32 | } |
33 | |
34 | QSGMaterialType *QSGSmoothTextureMaterial::type() const |
35 | { |
36 | static QSGMaterialType type; |
37 | return &type; |
38 | } |
39 | |
40 | QSGMaterialShader *QSGSmoothTextureMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const |
41 | { |
42 | Q_UNUSED(renderMode); |
43 | return new SmoothTextureMaterialRhiShader; |
44 | } |
45 | |
46 | SmoothTextureMaterialRhiShader::SmoothTextureMaterialRhiShader() |
47 | { |
48 | setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/smoothtexture.vert.qsb" )); |
49 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/smoothtexture.frag.qsb" )); |
50 | } |
51 | |
52 | bool SmoothTextureMaterialRhiShader::updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) |
53 | { |
54 | bool changed = false; |
55 | QByteArray *buf = state.uniformData(); |
56 | |
57 | if (!oldMaterial) { |
58 | // The viewport is constant, so set the pixel size uniform only once (per batches with the same material). |
59 | const QRect r = state.viewportRect(); |
60 | const QVector2D v(2.0f / r.width(), 2.0f / r.height()); |
61 | memcpy(dest: buf->data() + 64 + 8, src: &v, n: 8); |
62 | changed = true; |
63 | } |
64 | |
65 | changed |= QSGTextureMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial); |
66 | |
67 | return changed; |
68 | } |
69 | |
70 | |
71 | QSGDefaultInternalImageNode::QSGDefaultInternalImageNode(QSGDefaultRenderContext *rc) |
72 | : m_rc(rc) |
73 | { |
74 | setMaterial(&m_materialO); |
75 | setOpaqueMaterial(&m_material); |
76 | } |
77 | |
78 | void QSGDefaultInternalImageNode::setFiltering(QSGTexture::Filtering filtering) |
79 | { |
80 | if (m_material.filtering() == filtering) |
81 | return; |
82 | |
83 | m_material.setFiltering(filtering); |
84 | m_materialO.setFiltering(filtering); |
85 | m_smoothMaterial.setFiltering(filtering); |
86 | markDirty(bits: DirtyMaterial); |
87 | } |
88 | |
89 | void QSGDefaultInternalImageNode::setMipmapFiltering(QSGTexture::Filtering filtering) |
90 | { |
91 | if (m_material.mipmapFiltering() == filtering) |
92 | return; |
93 | |
94 | m_material.setMipmapFiltering(filtering); |
95 | m_materialO.setMipmapFiltering(filtering); |
96 | m_smoothMaterial.setMipmapFiltering(filtering); |
97 | markDirty(bits: DirtyMaterial); |
98 | } |
99 | |
100 | void QSGDefaultInternalImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode) |
101 | { |
102 | if (m_material.verticalWrapMode() == wrapMode) |
103 | return; |
104 | |
105 | m_material.setVerticalWrapMode(wrapMode); |
106 | m_materialO.setVerticalWrapMode(wrapMode); |
107 | m_smoothMaterial.setVerticalWrapMode(wrapMode); |
108 | markDirty(bits: DirtyMaterial); |
109 | } |
110 | |
111 | void QSGDefaultInternalImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) |
112 | { |
113 | if (m_material.horizontalWrapMode() == wrapMode) |
114 | return; |
115 | |
116 | m_material.setHorizontalWrapMode(wrapMode); |
117 | m_materialO.setHorizontalWrapMode(wrapMode); |
118 | m_smoothMaterial.setHorizontalWrapMode(wrapMode); |
119 | markDirty(bits: DirtyMaterial); |
120 | } |
121 | |
122 | void QSGDefaultInternalImageNode::updateMaterialAntialiasing() |
123 | { |
124 | if (m_antialiasing) { |
125 | setMaterial(&m_smoothMaterial); |
126 | setOpaqueMaterial(nullptr); |
127 | } else { |
128 | setMaterial(&m_materialO); |
129 | setOpaqueMaterial(&m_material); |
130 | } |
131 | } |
132 | |
133 | void QSGDefaultInternalImageNode::setMaterialTexture(QSGTexture *texture) |
134 | { |
135 | m_material.setTexture(texture); |
136 | m_materialO.setTexture(texture); |
137 | m_smoothMaterial.setTexture(texture); |
138 | } |
139 | |
140 | QSGTexture *QSGDefaultInternalImageNode::materialTexture() const |
141 | { |
142 | return m_material.texture(); |
143 | } |
144 | |
145 | bool QSGDefaultInternalImageNode::updateMaterialBlending() |
146 | { |
147 | const bool alpha = m_material.flags() & QSGMaterial::Blending; |
148 | if (materialTexture() && alpha != materialTexture()->hasAlphaChannel()) { |
149 | m_material.setFlag(flags: QSGMaterial::Blending, on: !alpha); |
150 | return true; |
151 | } |
152 | return false; |
153 | } |
154 | |
155 | inline static bool isPowerOfTwo(int x) |
156 | { |
157 | // Assumption: x >= 1 |
158 | return x == (x & -x); |
159 | } |
160 | |
161 | bool QSGDefaultInternalImageNode::supportsWrap(const QSize &size) const |
162 | { |
163 | bool npotSupported = m_rc->rhi() && m_rc->rhi()->isFeatureSupported(feature: QRhi::NPOTTextureRepeat); |
164 | return npotSupported || (isPowerOfTwo(x: size.width()) && isPowerOfTwo(x: size.height())); |
165 | } |
166 | |
167 | QT_END_NAMESPACE |
168 | |