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

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