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 | |
17 | QT_BEGIN_NAMESPACE |
18 | |
19 | using namespace Qt3DCore; |
20 | |
21 | namespace Qt3DRender { |
22 | namespace Render { |
23 | const int Shader::modelMatrixNameId = StringToInt::lookupId(str: QLatin1String("modelMatrix" )); |
24 | const int Shader::viewMatrixNameId = StringToInt::lookupId(str: QLatin1String("viewMatrix" )); |
25 | const int Shader::projectionMatrixNameId = StringToInt::lookupId(str: QLatin1String("projectionMatrix" )); |
26 | const int Shader::modelViewMatrixNameId = StringToInt::lookupId(str: QLatin1String("modelView" )); |
27 | const int Shader::viewProjectionMatrixNameId = StringToInt::lookupId(str: QLatin1String("viewProjectionMatrix" )); |
28 | const int Shader::modelViewProjectionNameId = StringToInt::lookupId(str: QLatin1String("modelViewProjection" )); |
29 | const int Shader::mvpNameId = StringToInt::lookupId(str: QLatin1String("mvp" )); |
30 | const int Shader::inverseModelMatrixNameId = StringToInt::lookupId(str: QLatin1String("inverseModelMatrix" )); |
31 | const int Shader::inverseViewMatrixNameId = StringToInt::lookupId(str: QLatin1String("inverseViewMatrix" )); |
32 | const int Shader::inverseProjectionMatrixNameId = StringToInt::lookupId(str: QLatin1String("inverseProjectionMatrix" )); |
33 | const int Shader::inverseModelViewNameId = StringToInt::lookupId(str: QLatin1String("inverseModelView" )); |
34 | const int Shader::inverseViewProjectionMatrixNameId = StringToInt::lookupId(str: QLatin1String("inverseViewProjectionMatrix" )); |
35 | const int Shader::inverseModelViewProjectionNameId = StringToInt::lookupId(str: QLatin1String("inverseModelViewProjection" )); |
36 | const int Shader::modelNormalMatrixNameId = StringToInt::lookupId(str: QLatin1String("modelNormalMatrix" )); |
37 | const int Shader::modelViewNormalNameId = StringToInt::lookupId(str: QLatin1String("modelViewNormal" )); |
38 | const int Shader::viewportMatrixNameId = StringToInt::lookupId(str: QLatin1String("viewportMatrix" )); |
39 | const int Shader::inverseViewportMatrixNameId = StringToInt::lookupId(str: QLatin1String("inverseViewportMatrix" )); |
40 | const int Shader::textureTransformMatrixNameId = StringToInt::lookupId(str: QLatin1String("textureTransformMatrix" )); |
41 | const int Shader::aspectRatioNameId = StringToInt::lookupId(str: QLatin1String("aspectRatio" )); |
42 | const int Shader::exposureNameId = StringToInt::lookupId(str: QLatin1String("exposure" )); |
43 | const int Shader::gammaNameId = StringToInt::lookupId(str: QLatin1String("gamma" )); |
44 | const int Shader::timeNameId = StringToInt::lookupId(str: QLatin1String("time" )); |
45 | const int Shader::eyePositionNameId = StringToInt::lookupId(str: QLatin1String("eyePosition" )); |
46 | const int Shader::skinningPaletteNameId = StringToInt::lookupId(str: QLatin1String("skinningPalette[0]" )); |
47 | const int Shader::yUpInFBOId = StringToInt::lookupId(str: QLatin1String("yUpInFBO" )); |
48 | const int Shader::yUpInNDCId = StringToInt::lookupId(str: QLatin1String("yUpInNDC" )); |
49 | |
50 | Shader::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 | |
60 | Shader::~Shader() |
61 | { |
62 | } |
63 | |
64 | void 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 | |
74 | void 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 | |
95 | void 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 | |
107 | void 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 | |
117 | const 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 | */ |
127 | void 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 |
137 | void Shader::requestCacheRebuild() |
138 | { |
139 | markDirty(changes: AbstractRenderer::MaterialDirty); |
140 | } |
141 | |
142 | void Shader::setLog(const QString &log) |
143 | { |
144 | m_log = log; |
145 | m_requiresFrontendSync = true; |
146 | } |
147 | |
148 | void Shader::setStatus(QShaderProgram::Status status) |
149 | { |
150 | m_status = status; |
151 | m_requiresFrontendSync = true; |
152 | } |
153 | |
154 | ShaderFunctor::ShaderFunctor(AbstractRenderer *renderer, ShaderManager *manager) |
155 | : m_renderer(renderer) |
156 | , m_shaderManager(manager) |
157 | { |
158 | } |
159 | |
160 | QBackendNode *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 | |
169 | QBackendNode *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 | |
178 | void 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 | |
190 | QT_END_NAMESPACE |
191 | |