1/****************************************************************************
2**
3** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D 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 "shader_p.h"
41#include "renderlogging_p.h"
42
43#include <QFile>
44#include <QOpenGLContext>
45#include <QOpenGLShaderProgram>
46#include <QMutexLocker>
47#include <qshaderprogram.h>
48#include <Qt3DRender/private/attachmentpack_p.h>
49#include <Qt3DRender/private/qshaderprogram_p.h>
50#include <Qt3DRender/private/stringtoint_p.h>
51#include <Qt3DCore/qpropertyupdatedchange.h>
52#include <Qt3DRender/private/managers_p.h>
53
54QT_BEGIN_NAMESPACE
55
56using namespace Qt3DCore;
57
58namespace Qt3DRender {
59namespace Render {
60const int Shader::modelMatrixNameId = StringToInt::lookupId(str: QLatin1String("modelMatrix"));
61const int Shader::viewMatrixNameId = StringToInt::lookupId(str: QLatin1String("viewMatrix"));
62const int Shader::projectionMatrixNameId = StringToInt::lookupId(str: QLatin1String("projectionMatrix"));
63const int Shader::modelViewMatrixNameId = StringToInt::lookupId(str: QLatin1String("modelView"));
64const int Shader::viewProjectionMatrixNameId = StringToInt::lookupId(str: QLatin1String("viewProjectionMatrix"));
65const int Shader::modelViewProjectionNameId = StringToInt::lookupId(str: QLatin1String("modelViewProjection"));
66const int Shader::mvpNameId = StringToInt::lookupId(str: QLatin1String("mvp"));
67const int Shader::inverseModelMatrixNameId = StringToInt::lookupId(str: QLatin1String("inverseModelMatrix"));
68const int Shader::inverseViewMatrixNameId = StringToInt::lookupId(str: QLatin1String("inverseViewMatrix"));
69const int Shader::inverseProjectionMatrixNameId = StringToInt::lookupId(str: QLatin1String("inverseProjectionMatrix"));
70const int Shader::inverseModelViewNameId = StringToInt::lookupId(str: QLatin1String("inverseModelView"));
71const int Shader::inverseViewProjectionMatrixNameId = StringToInt::lookupId(str: QLatin1String("inverseViewProjectionMatrix"));
72const int Shader::inverseModelViewProjectionNameId = StringToInt::lookupId(str: QLatin1String("inverseModelViewProjection"));
73const int Shader::modelNormalMatrixNameId = StringToInt::lookupId(str: QLatin1String("modelNormalMatrix"));
74const int Shader::modelViewNormalNameId = StringToInt::lookupId(str: QLatin1String("modelViewNormal"));
75const int Shader::viewportMatrixNameId = StringToInt::lookupId(str: QLatin1String("viewportMatrix"));
76const int Shader::inverseViewportMatrixNameId = StringToInt::lookupId(str: QLatin1String("inverseViewportMatrix"));
77const int Shader::textureTransformMatrixNameId = StringToInt::lookupId(str: QLatin1String("textureTransformMatrix"));
78const int Shader::aspectRatioNameId = StringToInt::lookupId(str: QLatin1String("aspectRatio"));
79const int Shader::exposureNameId = StringToInt::lookupId(str: QLatin1String("exposure"));
80const int Shader::gammaNameId = StringToInt::lookupId(str: QLatin1String("gamma"));
81const int Shader::timeNameId = StringToInt::lookupId(str: QLatin1String("time"));
82const int Shader::eyePositionNameId = StringToInt::lookupId(str: QLatin1String("eyePosition"));
83const int Shader::skinningPaletteNameId = StringToInt::lookupId(str: QLatin1String("skinningPalette[0]"));
84
85Shader::Shader()
86 : BackendNode(ReadWrite)
87 , m_requiresFrontendSync(false)
88 , m_status(QShaderProgram::NotReady)
89 , m_format(QShaderProgram::GLSL)
90 , m_dirty(false)
91{
92 m_shaderCode.resize(asize: static_cast<int>(QShaderProgram::Compute) + 1);
93}
94
95Shader::~Shader()
96{
97}
98
99void Shader::cleanup()
100{
101 QBackendNode::setEnabled(false);
102 m_status = QShaderProgram::NotReady;
103 m_format = QShaderProgram::GLSL;
104 m_log.clear();
105 m_requiresFrontendSync = false;
106 m_dirty = false;
107}
108
109void Shader::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
110{
111 const QShaderProgram *node = qobject_cast<const QShaderProgram *>(object: frontEnd);
112 if (!node)
113 return;
114
115 BackendNode::syncFromFrontEnd(frontEnd, firstTime);
116
117 if (firstTime)
118 for (int i = QShaderProgram::Vertex; i <= QShaderProgram::Compute; ++i)
119 m_shaderCode[i].clear();
120
121 for (int i = QShaderProgram::Vertex; i <= QShaderProgram::Compute; ++i) {
122 const QShaderProgram::ShaderType shaderType = static_cast<QShaderProgram::ShaderType>(i);
123 const QByteArray code = node->shaderCode(type: shaderType);
124 if (code != m_shaderCode.value(i: shaderType))
125 setShaderCode(type: shaderType, code);
126 }
127 setFormat(node->format());
128}
129
130void Shader::setShaderCode(QShaderProgram::ShaderType type, const QByteArray &code)
131{
132 if (code == m_shaderCode[type])
133 return;
134
135 m_shaderCode[type] = code;
136 m_requiresFrontendSync = true;
137 m_dirty = true;
138 setStatus(QShaderProgram::NotReady);
139 markDirty(changes: AbstractRenderer::ShadersDirty);
140}
141
142void Shader::setFormat(QShaderProgram::Format format)
143{
144 if (format == m_format)
145 return;
146 m_format = format;
147 m_dirty = true;
148 setStatus(QShaderProgram::NotReady);
149 markDirty(changes: AbstractRenderer::ShadersDirty);
150}
151
152QVector<QByteArray> Shader::shaderCode() const
153{
154 return m_shaderCode;
155}
156
157/*!
158 \internal
159 Initializes this Shader's state relating to attributes, global block uniforms and
160 and named uniform blocks by copying these details from \a other.
161*/
162void Shader::initializeFromReference(const Shader &other)
163{
164 m_status = other.m_status;
165 m_log = other.m_log;
166 m_requiresFrontendSync = true;
167 setStatus(other.status());
168 setLog(other.log());
169}
170
171// Called by renderer plugin when loading a GL Shader plugins
172void Shader::requestCacheRebuild()
173{
174 markDirty(changes: AbstractRenderer::MaterialDirty);
175}
176
177void Shader::setLog(const QString &log)
178{
179 m_log = log;
180 m_requiresFrontendSync = true;
181}
182
183void Shader::setStatus(QShaderProgram::Status status)
184{
185 m_status = status;
186 m_requiresFrontendSync = true;
187}
188
189ShaderFunctor::ShaderFunctor(AbstractRenderer *renderer, ShaderManager *manager)
190 : m_renderer(renderer)
191 , m_shaderManager(manager)
192{
193}
194
195QBackendNode *ShaderFunctor::create(const QNodeCreatedChangeBasePtr &change) const
196{
197 Shader *backend = m_shaderManager->getOrCreateResource(id: change->subjectId());
198 // Remove from the list of ids to destroy in case we were added to it
199 m_shaderManager->removeShaderIdFromIdsToCleanup(id: change->subjectId());
200 backend->setRenderer(m_renderer);
201 return backend;
202}
203
204QBackendNode *ShaderFunctor::get(QNodeId id) const
205{
206 // If we are marked for destruction, return nullptr so that
207 // if we were to be recreated, create would be called again
208 if (m_shaderManager->hasShaderIdToCleanup(id))
209 return nullptr;
210 return m_shaderManager->lookupResource(id);
211}
212
213void ShaderFunctor::destroy(QNodeId id) const
214{
215 m_shaderManager->addShaderIdToCleanup(id);
216 // We only add ourselves to the dirty list
217 // The actual removal needs to be performed after we have
218 // destroyed the associated APIShader in the RenderThread
219}
220
221} // namespace Render
222} // namespace Qt3DRender
223
224QT_END_NAMESPACE
225

source code of qt3d/src/render/materialsystem/shader.cpp