1/****************************************************************************
2**
3** Copyright (C) 2019 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 "texturesubmissioncontext_p.h"
41
42#include <graphicscontext_p.h>
43#include <gltexture_p.h>
44#include <logging_p.h>
45
46QT_BEGIN_NAMESPACE
47
48namespace Qt3DRender {
49namespace Render {
50namespace OpenGL {
51
52class TextureExtRendererLocker
53{
54public:
55 static void lock(GLTexture *tex)
56 {
57 if (!tex->isExternalRenderingEnabled())
58 return;
59 if (s_lockHash.keys().contains(t: tex)) {
60 ++s_lockHash[tex];
61 } else {
62 tex->externalRenderingLock()->lock();
63 s_lockHash[tex] = 1;
64 }
65 }
66 static void unlock(GLTexture *tex)
67 {
68 if (!tex->isExternalRenderingEnabled())
69 return;
70 if (!s_lockHash.keys().contains(t: tex))
71 return;
72
73 --s_lockHash[tex];
74 if (s_lockHash[tex] == 0) {
75 s_lockHash.remove(akey: tex);
76 tex->externalRenderingLock()->unlock();
77 }
78 }
79private:
80 static QHash<GLTexture*, int> s_lockHash;
81};
82
83QHash<GLTexture*, int> TextureExtRendererLocker::s_lockHash = QHash<GLTexture*, int>();
84
85
86TextureSubmissionContext::TextureSubmissionContext()
87{
88
89}
90
91TextureSubmissionContext::~TextureSubmissionContext()
92{
93
94}
95
96void TextureSubmissionContext::initialize(GraphicsContext *context)
97{
98 m_activeTextures.resize(asize: context->maxTextureUnitsCount());
99}
100
101void TextureSubmissionContext::endDrawing()
102{
103 decayTextureScores();
104 for (int i = 0; i < m_activeTextures.size(); ++i)
105 if (m_activeTextures[i].texture)
106 TextureExtRendererLocker::unlock(tex: m_activeTextures[i].texture);
107}
108
109int TextureSubmissionContext::activateTexture(TextureSubmissionContext::TextureScope scope,
110 QOpenGLContext *m_gl,
111 GLTexture *tex)
112{
113 // Returns the texture unit to use for the texture
114 // This always return a valid unit, unless there are more textures than
115 // texture unit available for the current material
116 const int onUnit = assignUnitForTexture(tex);
117
118 // check we didn't overflow the available units
119 if (onUnit == -1)
120 return -1;
121
122 const int sharedTextureId = tex->sharedTextureId();
123 // We have a valid texture id provided by a shared context
124 if (sharedTextureId > 0) {
125 m_gl->functions()->glActiveTexture(GL_TEXTURE0 + onUnit);
126 const QAbstractTexture::Target target = tex->properties().target;
127 // For now we know that target values correspond to the GL values
128 m_gl->functions()->glBindTexture(target, texture: tex->sharedTextureId());
129 } else {
130 // Texture must have been created and updated at this point
131 QOpenGLTexture *glTex = tex->getGLTexture();
132 if (glTex == nullptr)
133 return -1;
134 glTex->bind(unit: uint(onUnit));
135 }
136 if (m_activeTextures[onUnit].texture != tex) {
137 if (m_activeTextures[onUnit].texture)
138 TextureExtRendererLocker::unlock(tex: m_activeTextures[onUnit].texture);
139 m_activeTextures[onUnit].texture = tex;
140 TextureExtRendererLocker::lock(tex);
141 }
142
143#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG)
144 int err = m_gl->functions()->glGetError();
145 if (err)
146 qCWarning(Backend) << "GL error after activating texture" << QString::number(err, 16)
147 << tex->getGLTexture()->textureId() << "on unit" << onUnit;
148#endif
149
150 m_activeTextures[onUnit].score = 200;
151 m_activeTextures[onUnit].pinned = true;
152 m_activeTextures[onUnit].scope = scope;
153
154 return onUnit;
155}
156
157void TextureSubmissionContext::deactivateTexturesWithScope(TextureSubmissionContext::TextureScope ts)
158{
159 for (int u=0; u<m_activeTextures.size(); ++u) {
160 if (!m_activeTextures[u].pinned)
161 continue; // inactive, ignore
162
163 if (m_activeTextures[u].scope == ts) {
164 m_activeTextures[u].pinned = false;
165 m_activeTextures[u].score = qMax(a: m_activeTextures[u].score, b: 1) - 1;
166 }
167 } // of units iteration
168}
169
170void TextureSubmissionContext::deactivateTexture(GLTexture* tex)
171{
172 for (int u=0; u<m_activeTextures.size(); ++u) {
173 if (m_activeTextures[u].texture == tex) {
174 Q_ASSERT(m_activeTextures[u].pinned);
175 m_activeTextures[u].pinned = false;
176 return;
177 }
178 } // of units iteration
179
180 qCWarning(Backend) << Q_FUNC_INFO << "texture not active:" << tex;
181}
182
183/*!
184 \internal
185 Returns a texture unit for a texture, -1 if all texture units are assigned.
186 Tries to use the texture unit with the texture that hasn't been used for the longest time
187 if the texture happens not to be already pinned on a texture unit.
188 */
189int TextureSubmissionContext::assignUnitForTexture(GLTexture *tex)
190{
191 int lowestScoredUnit = -1;
192 int lowestScore = 0xfffffff;
193
194 for (int u=0; u<m_activeTextures.size(); ++u) {
195 if (m_activeTextures[u].texture == tex)
196 return u;
197 }
198
199 for (int u=0; u<m_activeTextures.size(); ++u) {
200 // No texture is currently active on the texture unit
201 // we save the texture unit with the texture that has been on there
202 // the longest time while not being used
203 if (!m_activeTextures[u].pinned) {
204 int score = m_activeTextures[u].score;
205 if (score < lowestScore) {
206 lowestScore = score;
207 lowestScoredUnit = u;
208 }
209 }
210 } // of units iteration
211
212 if (lowestScoredUnit == -1)
213 qCWarning(Backend) << Q_FUNC_INFO << "No free texture units!";
214
215 return lowestScoredUnit;
216}
217
218void TextureSubmissionContext::decayTextureScores()
219{
220 for (int u = 0; u < m_activeTextures.size(); u++)
221 m_activeTextures[u].score = qMax(a: m_activeTextures[u].score - 1, b: 0);
222}
223
224} // namespace OpenGL
225} // namespace Render
226} // namespace Qt3DRender of namespace
227
228QT_END_NAMESPACE
229

source code of qt3d/src/plugins/renderers/opengl/graphicshelpers/texturesubmissioncontext.cpp