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 "imagesubmissioncontext_p.h"
41#include <Qt3DRender/private/shaderimage_p.h>
42#include <Qt3DRender/qshaderimage.h>
43#include <graphicscontext_p.h>
44#include <gltexture_p.h>
45#include <logging_p.h>
46
47QT_BEGIN_NAMESPACE
48
49// ES 3.1+ or GL 4.2+
50#ifndef GL_READ_ONLY
51#define GL_READ_ONLY 0x88B8
52#endif
53#ifndef GL_WRITE_ONLY
54#define GL_WRITE_ONLY 0x88B9
55#endif
56#ifndef GL_READ_WRITE
57#define GL_READ_WRITE 0x88BA
58#endif
59
60namespace Qt3DRender {
61namespace Render {
62namespace OpenGL {
63
64class GraphicsContext;
65class GLTexture;
66
67namespace {
68
69GLenum glAccessEnumForShaderImageAccess(QShaderImage::Access access)
70{
71 switch (access) {
72 case QShaderImage::ReadOnly:
73 return GL_READ_ONLY;
74 case QShaderImage::WriteOnly:
75 return GL_WRITE_ONLY;
76 case QShaderImage::ReadWrite:
77 default:
78 break;
79 }
80 return GL_READ_WRITE;
81}
82
83GLenum glImageFormatToGL(QShaderImage::ImageFormat format)
84{
85 // Right now we can abuse from the fact that the ImageFormat enum values
86 // have been assigned the same value as the GL enum
87 return GLenum(format);
88}
89
90GLenum glImageFormatForShaderImageFormat(QShaderImage::ImageFormat format,
91 QAbstractTexture::TextureFormat textureFormat)
92{
93 Q_ASSERT_X(format != QShaderImage::NoFormat, Q_FUNC_INFO, "Valid image format or Automatic expected");
94
95 if (format != QShaderImage::Automatic)
96 return glImageFormatToGL(format);
97
98 // Otherwise try to mind to best texture format
99 switch (textureFormat) {
100 case QAbstractTexture::R8_UNorm:
101 return glImageFormatToGL(format: QShaderImage::R8_UNorm);
102 case QAbstractTexture::RG8_UNorm:
103 return glImageFormatToGL(format: QShaderImage::RG8_UNorm);
104 case QAbstractTexture::RGBA8_UNorm:
105 return glImageFormatToGL(format: QShaderImage::RGBA8_UNorm);
106
107 case QAbstractTexture::R16_UNorm:
108 return glImageFormatToGL(format: QShaderImage::R16_UNorm);
109 case QAbstractTexture::RG16_UNorm:
110 return glImageFormatToGL(format: QShaderImage::RG16_UNorm);
111 case QAbstractTexture::RGBA16_UNorm:
112 return glImageFormatToGL(format: QShaderImage::RGBA16_UNorm);
113
114 case QAbstractTexture::R8_SNorm:
115 return glImageFormatToGL(format: QShaderImage::R8_SNorm);
116 case QAbstractTexture::RG8_SNorm:
117 return glImageFormatToGL(format: QShaderImage::RG8_SNorm);
118 case QAbstractTexture::RGBA8_SNorm:
119 return glImageFormatToGL(format: QShaderImage::RGBA8_SNorm);
120
121 case QAbstractTexture::R16_SNorm:
122 return glImageFormatToGL(format: QShaderImage::R16_SNorm);
123 case QAbstractTexture::RG16_SNorm:
124 return glImageFormatToGL(format: QShaderImage::RG16_SNorm);
125 case QAbstractTexture::RGBA16_SNorm:
126 return glImageFormatToGL(format: QShaderImage::RGBA16_SNorm);
127
128 case QAbstractTexture::R8U:
129 return glImageFormatToGL(format: QShaderImage::R8U);
130 case QAbstractTexture::RG8U:
131 return glImageFormatToGL(format: QShaderImage::RG8U);
132 case QAbstractTexture::RGBA8U:
133 return glImageFormatToGL(format: QShaderImage::RGBA8U);
134
135 case QAbstractTexture::R16U:
136 return glImageFormatToGL(format: QShaderImage::R16U);
137 case QAbstractTexture::RG16U:
138 return glImageFormatToGL(format: QShaderImage::RG16U);
139 case QAbstractTexture::RGBA16U:
140 return glImageFormatToGL(format: QShaderImage::RGBA16U);
141
142 case QAbstractTexture::R32U:
143 return glImageFormatToGL(format: QShaderImage::R32U);
144 case QAbstractTexture::RG32U:
145 return glImageFormatToGL(format: QShaderImage::RG32U);
146 case QAbstractTexture::RGBA32U:
147 return glImageFormatToGL(format: QShaderImage::RGBA32U);
148
149 case QAbstractTexture::R8I:
150 return glImageFormatToGL(format: QShaderImage::R8I);
151 case QAbstractTexture::RG8I:
152 return glImageFormatToGL(format: QShaderImage::RG8I);
153 case QAbstractTexture::RGBA8I:
154 return glImageFormatToGL(format: QShaderImage::RGBA8I);
155
156 case QAbstractTexture::R16I:
157 return glImageFormatToGL(format: QShaderImage::R16I);
158 case QAbstractTexture::RG16I:
159 return glImageFormatToGL(format: QShaderImage::RG16I);
160 case QAbstractTexture::RGBA16I:
161 return glImageFormatToGL(format: QShaderImage::RGBA16I);
162
163 case QAbstractTexture::R32I:
164 return glImageFormatToGL(format: QShaderImage::R32I);
165 case QAbstractTexture::RG32I:
166 return glImageFormatToGL(format: QShaderImage::RG32I);
167 case QAbstractTexture::RGBA32I:
168 return glImageFormatToGL(format: QShaderImage::RGBA32I);
169
170 case QAbstractTexture::R16F:
171 return glImageFormatToGL(format: QShaderImage::R16F);
172 case QAbstractTexture::RG16F:
173 return glImageFormatToGL(format: QShaderImage::RG16F);
174 case QAbstractTexture::RGBA16F:
175 return glImageFormatToGL(format: QShaderImage::RGBA16F);
176
177 case QAbstractTexture::R32F:
178 return glImageFormatToGL(format: QShaderImage::R32F);
179 case QAbstractTexture::RG32F:
180 return glImageFormatToGL(format: QShaderImage::RG32F);
181 case QAbstractTexture::RGBA32F:
182 return glImageFormatToGL(format: QShaderImage::RGBA32F);
183
184 case QAbstractTexture::RG11B10F:
185 return glImageFormatToGL(format: QShaderImage::RG11B10F);
186 case QAbstractTexture::RGB10A2:
187 return glImageFormatToGL(format: QShaderImage::RGB10A2);
188 case QAbstractTexture::RGB10A2U:
189 return glImageFormatToGL(format: QShaderImage::RGB10A2U);
190
191 default:
192 qWarning() << "Cannot map Texture format" << textureFormat << "to a valid Image Format";
193 Q_UNREACHABLE();
194 return GL_NONE;
195 }
196}
197
198} // anonymous
199
200ImageSubmissionContext::ImageSubmissionContext()
201 : m_ctx(nullptr)
202{
203}
204
205void ImageSubmissionContext::initialize(GraphicsContext *context)
206{
207 m_ctx = context;
208 m_activeImages.resize(asize: m_ctx->maxImageUnitsCount());
209}
210
211void ImageSubmissionContext::endDrawing()
212{
213 // Reduce score of all active Images
214 decayImageScores();
215}
216
217// Return Image Unit for Image
218// If Image was used previously and recently, it will return the last used unit
219// for that image. Otherwise it will try to return the image unit the least used.
220int ImageSubmissionContext::activateImage(ShaderImage *image, GLTexture *tex)
221{
222 const int onUnit = assignUnitForImage(shaderImageId: image->peerId());
223
224 if (onUnit < 0) {
225 qWarning() << "Unable to find available image unit";
226 return -1;
227 }
228
229 QOpenGLTexture *glTex = tex->getGLTexture();
230 if (glTex == nullptr) {
231 qWarning() << "Unable to retrieve valid texture for Image";
232 return -1;
233 }
234
235 // Bind Image against Texture and resolve Image Format
236 m_ctx->bindImageTexture(imageUnit: onUnit,
237 texture: glTex->textureId(),
238 mipLevel: image->mipLevel(),
239 layered: image->layered(),
240 layer: image->layer(),
241 access: glAccessEnumForShaderImageAccess(access: image->access()),
242 format: glImageFormatForShaderImageFormat(format: image->format(),
243 textureFormat: tex->properties().format));
244
245 // Store information about the Texture/Image on ActiveImage for given
246 // image unit
247 m_activeImages[onUnit].shaderImageId = image->peerId();
248 m_activeImages[onUnit].texture = tex;
249 m_activeImages[onUnit].score = 200;
250 m_activeImages[onUnit].pinned = true;
251
252 return onUnit;
253}
254
255// Unset pinned Active Image and reduce their score
256void ImageSubmissionContext::deactivateImages()
257{
258 for (int u = 0, m = m_activeImages.size(); u < m; ++u) {
259 if (m_activeImages[u].pinned) {
260 m_activeImages[u].pinned = false;
261 m_activeImages[u].score = qMax(a: m_activeImages[u].score - 1, b: 0);
262 return;
263 }
264 }
265}
266
267// Reduce score of all active images (pinned or not)
268void ImageSubmissionContext::decayImageScores()
269{
270 for (int u = 0, m = m_activeImages.size(); u < m; ++u)
271 m_activeImages[u].score = qMax(a: m_activeImages[u].score - 1, b: 0);
272}
273
274int ImageSubmissionContext::assignUnitForImage(Qt3DCore::QNodeId shaderImageId)
275{
276 int lowestScoredUnit = -1;
277 int lowestScore = 0xfffffff;
278
279 const int m = m_activeImages.size();
280 for (int u = 0; u < m; ++u) {
281 if (m_activeImages[u].shaderImageId == shaderImageId)
282 return u;
283 }
284
285 for (int u = 0; u < m; ++u) {
286 // No image is currently active on the image unit
287 // we save the image unit with the texture that has been on there
288 // the longest time while not being used
289 if (!m_activeImages[u].pinned) {
290 const int score = m_activeImages[u].score;
291 if (score < lowestScore) {
292 lowestScore = score;
293 lowestScoredUnit = u;
294 }
295 }
296 }
297
298 if (lowestScoredUnit == -1)
299 qCWarning(Backend) << Q_FUNC_INFO << "No free image units!";
300
301 return lowestScoredUnit;
302}
303
304} // namespace OpenGL
305} // namespace Render
306} // namespace Qt3DRender
307
308QT_END_NAMESPACE
309

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