1/*
2 * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7#include "shadermaterial.h"
8
9#include <QSGTexture>
10#include <QVariant>
11
12using namespace Qt::StringLiterals;
13
14ShaderMaterial::ShaderMaterial(const QString &name)
15 : m_name(name)
16{
17 m_type = typeForName(name);
18 setFlag(flags: QSGMaterial::Blending, on: true);
19}
20
21ShaderMaterial::ShaderMaterial(QSGMaterialType *type)
22 : m_type(type)
23{
24 m_name = nameForType(type);
25 setFlag(flags: QSGMaterial::Blending, on: true);
26}
27
28QString ShaderMaterial::name() const
29{
30 return m_name;
31}
32
33QSGMaterialShader *ShaderMaterial::createShader(QSGRendererInterface::RenderMode) const
34{
35 return new ShaderMaterialShader{m_name};
36}
37
38QSGMaterialType *ShaderMaterial::type() const
39{
40 return m_type;
41}
42
43int ShaderMaterial::compare(const QSGMaterial *other) const
44{
45 auto material = static_cast<const ShaderMaterial *>(other);
46 if (m_uniformData == material->m_uniformData && m_textures == material->m_textures) {
47 return 0;
48 }
49
50 return QSGMaterial::compare(other);
51}
52
53void ShaderMaterial::setUniformBufferSize(qsizetype size)
54{
55 if (size == m_uniformData.size()) {
56 return;
57 }
58
59 m_uniformData = QByteArray{size, '\0'};
60}
61
62std::span<char> ShaderMaterial::uniformData()
63{
64 return std::span(m_uniformData.data(), m_uniformData.size());
65}
66
67QSGTexture *ShaderMaterial::texture(int binding)
68{
69 return m_textures.value(key: binding, defaultValue: nullptr);
70}
71
72void ShaderMaterial::setTexture(int binding, QSGTexture *texture)
73{
74 m_textures[binding] = texture;
75}
76
77QSGTexture::Filtering ShaderMaterial::textureFiltering(int binding) const
78{
79 auto texture = m_textures.value(key: binding);
80 if (texture) {
81 return texture->filtering();
82 }
83
84 return QSGTexture::Linear;
85}
86
87void ShaderMaterial::setTextureFiltering(int binding, QSGTexture::Filtering filtering)
88{
89 auto texture = m_textures.value(key: binding);
90 if (texture) {
91 texture->setFiltering(filtering);
92 }
93}
94
95QString ShaderMaterial::nameForType(QSGMaterialType *type)
96{
97 for (auto &[key, value] : s_materialTypes) {
98 if (value.get() == type) {
99 return key;
100 }
101 }
102 return QString();
103}
104
105QSGMaterialType *ShaderMaterial::typeForName(const QString &name)
106{
107 if (!s_materialTypes.contains(x: name)) {
108 s_materialTypes[name] = std::make_unique<QSGMaterialType>();
109 }
110 return s_materialTypes[name].get();
111}
112
113ShaderMaterialShader::ShaderMaterialShader(const QString &shaderName)
114{
115 static const auto shaderRoot = QStringLiteral(":/qt/qml/org/kde/kirigami/primitives/shaders/");
116
117 setShaderFileName(stage: Stage::VertexStage, filename: shaderRoot + shaderName + u".vert.qsb");
118 setShaderFileName(stage: Stage::FragmentStage, filename: shaderRoot + shaderName + u".frag.qsb");
119}
120
121bool ShaderMaterialShader::updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
122{
123 bool changed = false;
124
125 auto data = state.uniformData()->data();
126 auto remainingSize = std::size_t(state.uniformData()->size());
127
128 if (state.isMatrixDirty()) {
129 auto matrix = state.combinedMatrix();
130 memcpy(dest: data, src: matrix.data(), n: sizeof(float) * 16);
131 changed = true;
132 }
133 data += sizeof(float) * 16;
134 remainingSize -= sizeof(float) * 16;
135
136 if (state.isOpacityDirty()) {
137 auto opacity = state.opacity();
138 memcpy(dest: data, src: &opacity, n: sizeof(float));
139 changed = true;
140 }
141
142 data += sizeof(float);
143 remainingSize -= sizeof(float);
144
145 if (!oldMaterial || newMaterial->compare(other: oldMaterial) != 0) {
146 const auto uniformData = static_cast<ShaderMaterial *>(newMaterial)->uniformData();
147 memcpy(dest: data, src: uniformData.data() + sizeof(float) * 17, n: remainingSize);
148 changed = true;
149 }
150
151 return changed;
152}
153
154void ShaderMaterialShader::updateSampledImage(QSGMaterialShader::RenderState &state,
155 int binding,
156 QSGTexture **texture,
157 QSGMaterial *newMaterial,
158 QSGMaterial *oldMaterial)
159{
160 Q_UNUSED(oldMaterial);
161
162 auto material = static_cast<ShaderMaterial *>(newMaterial);
163 auto source = material->texture(binding);
164 if (source) {
165 source->commitTextureOperations(rhi: state.rhi(), resourceUpdates: state.resourceUpdateBatch());
166 *texture = source;
167 } else {
168 *texture = nullptr;
169 }
170}
171

source code of kirigami/src/primitives/scenegraph/shadermaterial.cpp