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

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