1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). |
4 | ** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). |
5 | ** Contact: https://www.qt.io/licensing/ |
6 | ** |
7 | ** This file is part of the Qt3D module of the Qt Toolkit. |
8 | ** |
9 | ** $QT_BEGIN_LICENSE:LGPL$ |
10 | ** Commercial License Usage |
11 | ** Licensees holding valid commercial Qt licenses may use this file in |
12 | ** accordance with the commercial license agreement provided with the |
13 | ** Software or, alternatively, in accordance with the terms contained in |
14 | ** a written agreement between you and The Qt Company. For licensing terms |
15 | ** and conditions see https://www.qt.io/terms-conditions. For further |
16 | ** information use the contact form at https://www.qt.io/contact-us. |
17 | ** |
18 | ** GNU Lesser General Public License Usage |
19 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
20 | ** General Public License version 3 as published by the Free Software |
21 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
22 | ** packaging of this file. Please review the following information to |
23 | ** ensure the GNU Lesser General Public License version 3 requirements |
24 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
25 | ** |
26 | ** GNU General Public License Usage |
27 | ** Alternatively, this file may be used under the terms of the GNU |
28 | ** General Public License version 2.0 or (at your option) the GNU General |
29 | ** Public license version 3 or any later version approved by the KDE Free |
30 | ** Qt Foundation. The licenses are as published by the Free Software |
31 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
32 | ** included in the packaging of this file. Please review the following |
33 | ** information to ensure the GNU General Public License requirements will |
34 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
35 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
36 | ** |
37 | ** $QT_END_LICENSE$ |
38 | ** |
39 | ****************************************************************************/ |
40 | |
41 | #include "graphicscontext_p.h" |
42 | |
43 | #include <Qt3DRender/qgraphicsapifilter.h> |
44 | #include <Qt3DRender/qparameter.h> |
45 | #include <Qt3DRender/private/renderlogging_p.h> |
46 | #include <Qt3DRender/private/shader_p.h> |
47 | #include <Qt3DRender/private/material_p.h> |
48 | #include <Qt3DRender/private/buffer_p.h> |
49 | #include <Qt3DRender/private/attribute_p.h> |
50 | #include <Qt3DRender/private/rendertarget_p.h> |
51 | #include <Qt3DRender/private/nodemanagers_p.h> |
52 | #include <Qt3DRender/private/buffermanager_p.h> |
53 | #include <Qt3DRender/private/managers_p.h> |
54 | #include <Qt3DRender/private/attachmentpack_p.h> |
55 | #include <Qt3DRender/private/qbuffer_p.h> |
56 | #include <Qt3DRender/private/attachmentpack_p.h> |
57 | #include <Qt3DRender/private/qbuffer_p.h> |
58 | #include <Qt3DRender/private/renderstateset_p.h> |
59 | #include <QOpenGLShaderProgram> |
60 | #include <glresourcemanagers_p.h> |
61 | #include <graphicshelperinterface_p.h> |
62 | #include <gltexture_p.h> |
63 | #include <rendercommand_p.h> |
64 | #include <renderer_p.h> |
65 | #include <renderbuffer_p.h> |
66 | #include <glshader_p.h> |
67 | |
68 | #if !defined(QT_OPENGL_ES_2) |
69 | #include <QOpenGLFunctions_2_0> |
70 | #include <QOpenGLFunctions_3_2_Core> |
71 | #include <QOpenGLFunctions_3_3_Core> |
72 | #include <QOpenGLFunctions_4_3_Core> |
73 | #include <graphicshelpergl2_p.h> |
74 | #include <graphicshelpergl3_2_p.h> |
75 | #include <graphicshelpergl3_3_p.h> |
76 | #include <graphicshelpergl4_p.h> |
77 | #endif |
78 | #include <graphicshelperes2_p.h> |
79 | #include <graphicshelperes3_p.h> |
80 | #include <graphicshelperes3_1_p.h> |
81 | #include <graphicshelperes3_2_p.h> |
82 | |
83 | #include <QSurface> |
84 | #include <QWindow> |
85 | #include <QOpenGLTexture> |
86 | #include <QOpenGLDebugLogger> |
87 | |
88 | QT_BEGIN_NAMESPACE |
89 | |
90 | #ifndef GL_READ_FRAMEBUFFER |
91 | #define GL_READ_FRAMEBUFFER 0x8CA8 |
92 | #endif |
93 | |
94 | #ifndef GL_DRAW_FRAMEBUFFER |
95 | #define GL_DRAW_FRAMEBUFFER 0x8CA9 |
96 | #endif |
97 | |
98 | #ifndef GL_MAX_IMAGE_UNITS |
99 | #define GL_MAX_IMAGE_UNITS 0x8F38 |
100 | #endif |
101 | |
102 | namespace { |
103 | |
104 | QOpenGLShader::ShaderType shaderType(Qt3DRender::QShaderProgram::ShaderType type) |
105 | { |
106 | switch (type) { |
107 | case Qt3DRender::QShaderProgram::Vertex: return QOpenGLShader::Vertex; |
108 | case Qt3DRender::QShaderProgram::TessellationControl: return QOpenGLShader::TessellationControl; |
109 | case Qt3DRender::QShaderProgram::TessellationEvaluation: return QOpenGLShader::TessellationEvaluation; |
110 | case Qt3DRender::QShaderProgram::Geometry: return QOpenGLShader::Geometry; |
111 | case Qt3DRender::QShaderProgram::Fragment: return QOpenGLShader::Fragment; |
112 | case Qt3DRender::QShaderProgram::Compute: return QOpenGLShader::Compute; |
113 | default: Q_UNREACHABLE(); |
114 | } |
115 | } |
116 | |
117 | } // anonymous namespace |
118 | |
119 | namespace Qt3DRender { |
120 | namespace Render { |
121 | namespace OpenGL { |
122 | |
123 | namespace { |
124 | |
125 | void logOpenGLDebugMessage(const QOpenGLDebugMessage &debugMessage) |
126 | { |
127 | qDebug() << "OpenGL debug message:" << debugMessage; |
128 | } |
129 | |
130 | } // anonymous |
131 | |
132 | GraphicsContext::GraphicsContext() |
133 | : m_initialized(false) |
134 | , m_supportsVAO(false) |
135 | , m_maxTextureUnits(0) |
136 | , m_maxImageUnits(0) |
137 | , m_defaultFBO(0) |
138 | , m_gl(nullptr) |
139 | , m_glHelper(nullptr) |
140 | , m_debugLogger(nullptr) |
141 | , m_currentVAO(nullptr) |
142 | { |
143 | } |
144 | |
145 | GraphicsContext::~GraphicsContext() |
146 | { |
147 | } |
148 | |
149 | void GraphicsContext::setOpenGLContext(QOpenGLContext* ctx) |
150 | { |
151 | Q_ASSERT(ctx); |
152 | m_gl = ctx; |
153 | } |
154 | |
155 | void GraphicsContext::initialize() |
156 | { |
157 | m_initialized = true; |
158 | |
159 | Q_ASSERT(m_gl); |
160 | |
161 | m_gl->functions()->glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, params: &m_maxTextureUnits); |
162 | qCDebug(Backend) << "context supports" << m_maxTextureUnits << "texture units" ; |
163 | m_gl->functions()->glGetIntegerv(GL_MAX_IMAGE_UNITS, params: &m_maxImageUnits); |
164 | qCDebug(Backend) << "context supports" << m_maxImageUnits << "image units" ; |
165 | |
166 | if (m_gl->format().majorVersion() >= 3) { |
167 | m_supportsVAO = true; |
168 | } else { |
169 | QSet<QByteArray> extensions = m_gl->extensions(); |
170 | m_supportsVAO = extensions.contains(QByteArrayLiteral("GL_OES_vertex_array_object" )) |
171 | || extensions.contains(QByteArrayLiteral("GL_ARB_vertex_array_object" )) |
172 | || extensions.contains(QByteArrayLiteral("GL_APPLE_vertex_array_object" )); |
173 | } |
174 | |
175 | m_defaultFBO = m_gl->defaultFramebufferObject(); |
176 | qCDebug(Backend) << "VAO support = " << m_supportsVAO; |
177 | } |
178 | |
179 | void GraphicsContext::clearBackBuffer(QClearBuffers::BufferTypeFlags buffers) |
180 | { |
181 | if (buffers != QClearBuffers::None) { |
182 | GLbitfield mask = 0; |
183 | |
184 | if (buffers & QClearBuffers::ColorBuffer) |
185 | mask |= GL_COLOR_BUFFER_BIT; |
186 | if (buffers & QClearBuffers::DepthBuffer) |
187 | mask |= GL_DEPTH_BUFFER_BIT; |
188 | if (buffers & QClearBuffers::StencilBuffer) |
189 | mask |= GL_STENCIL_BUFFER_BIT; |
190 | |
191 | m_gl->functions()->glClear(mask); |
192 | } |
193 | } |
194 | |
195 | bool GraphicsContext::hasValidGLHelper() const |
196 | { |
197 | return m_glHelper != nullptr; |
198 | } |
199 | |
200 | bool GraphicsContext::isInitialized() const |
201 | { |
202 | return m_initialized; |
203 | } |
204 | |
205 | bool GraphicsContext::makeCurrent(QSurface *surface) |
206 | { |
207 | Q_ASSERT(m_gl); |
208 | if (!m_gl->makeCurrent(surface)) { |
209 | qCWarning(Backend) << Q_FUNC_INFO << "makeCurrent failed" ; |
210 | return false; |
211 | } |
212 | |
213 | initializeHelpers(surface); |
214 | |
215 | return true; |
216 | } |
217 | |
218 | void GraphicsContext::initializeHelpers(QSurface *surface) |
219 | { |
220 | // Set the correct GL Helper depending on the surface |
221 | // If no helper exists, create one |
222 | m_glHelper = m_glHelpers.value(akey: surface); |
223 | if (!m_glHelper) { |
224 | m_glHelper = resolveHighestOpenGLFunctions(); |
225 | m_glHelpers.insert(akey: surface, avalue: m_glHelper); |
226 | } |
227 | } |
228 | |
229 | void GraphicsContext::doneCurrent() |
230 | { |
231 | Q_ASSERT(m_gl); |
232 | m_gl->doneCurrent(); |
233 | m_glHelper = nullptr; |
234 | } |
235 | |
236 | // Called by GraphicsContext::loadShader itself called by Renderer::updateGLResources |
237 | GraphicsContext::ShaderCreationInfo GraphicsContext::createShaderProgram(GLShader *shader) |
238 | { |
239 | QOpenGLShaderProgram *shaderProgram = shader->shaderProgram(); |
240 | |
241 | // Compile shaders |
242 | const auto shaderCode = shader->shaderCode(); |
243 | |
244 | QString logs; |
245 | for (int i = QShaderProgram::Vertex; i <= QShaderProgram::Compute; ++i) { |
246 | const QShaderProgram::ShaderType type = static_cast<QShaderProgram::ShaderType>(i); |
247 | if (!shaderCode.at(i).isEmpty()) { |
248 | // Note: logs only return the error but not all the shader code |
249 | // we could append it |
250 | if (!shaderProgram->addCacheableShaderFromSourceCode(type: shaderType(type), source: shaderCode.at(i))) |
251 | logs += shaderProgram->log(); |
252 | } |
253 | } |
254 | |
255 | // Call glBindFragDataLocation and link the program |
256 | // Since we are sharing shaders in the backend, we assume that if using custom |
257 | // fragOutputs, they should all be the same for a given shader |
258 | bindFragOutputs(shader: shaderProgram->programId(), outputs: shader->fragOutputs()); |
259 | |
260 | const bool linkSucceeded = shaderProgram->link(); |
261 | logs += shaderProgram->log(); |
262 | |
263 | // Perform shader introspection |
264 | introspectShaderInterface(shader); |
265 | |
266 | ShaderCreationInfo info; |
267 | info.linkSucceeded = linkSucceeded; |
268 | info.logs = logs; |
269 | |
270 | return info; |
271 | } |
272 | |
273 | // That assumes that the shaderProgram in Shader stays the same |
274 | void GraphicsContext::introspectShaderInterface(GLShader *shader) |
275 | { |
276 | QOpenGLShaderProgram *shaderProgram = shader->shaderProgram(); |
277 | GraphicsHelperInterface *glHelper = resolveHighestOpenGLFunctions(); |
278 | shader->initializeUniforms(uniformsDescription: glHelper->programUniformsAndLocations(programId: shaderProgram->programId())); |
279 | shader->initializeAttributes(attributesDescription: glHelper->programAttributesAndLocations(programId: shaderProgram->programId())); |
280 | if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::UniformBufferObject)) |
281 | shader->initializeUniformBlocks(uniformBlockDescription: m_glHelper->programUniformBlocks(programId: shaderProgram->programId())); |
282 | if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::ShaderStorageObject)) |
283 | shader->initializeShaderStorageBlocks(shaderStorageBlockDescription: m_glHelper->programShaderStorageBlocks(programId: shaderProgram->programId())); |
284 | } |
285 | |
286 | |
287 | // Called by Renderer::updateGLResources |
288 | void GraphicsContext::loadShader(Shader *shaderNode, |
289 | ShaderManager *shaderManager, |
290 | GLShaderManager *glShaderManager) |
291 | { |
292 | const Qt3DCore::QNodeId shaderId = shaderNode->peerId(); |
293 | GLShader *glShader = glShaderManager->lookupResource(shaderId); |
294 | |
295 | // We already have a shader associated with the node |
296 | if (glShader != nullptr) { |
297 | // We need to abandon it |
298 | glShaderManager->abandon(apiShader: glShader, shader: shaderNode); |
299 | } |
300 | |
301 | // We create or adopt an already created glShader |
302 | glShader = glShaderManager->createOrAdoptExisting(shader: shaderNode); |
303 | |
304 | const QVector<Qt3DCore::QNodeId> sharedShaderIds = glShaderManager->shaderIdsForProgram(glShader); |
305 | if (sharedShaderIds.size() == 1) { |
306 | // The Shader could already be loaded if we retrieved one |
307 | // that had been marked for destruction |
308 | if (!glShader->isLoaded()) { |
309 | glShader->setGraphicsContext(this); |
310 | glShader->setShaderCode(shaderNode->shaderCode()); |
311 | const ShaderCreationInfo loadResult = createShaderProgram(shader: glShader); |
312 | shaderNode->setStatus(loadResult.linkSucceeded ? QShaderProgram::Ready : QShaderProgram::Error); |
313 | shaderNode->setLog(loadResult.logs); |
314 | // Loaded in the sense we tried to load it (and maybe it failed) |
315 | glShader->setLoaded(true); |
316 | } |
317 | } else { |
318 | // Find an already loaded shader that shares the same QOpenGLShaderProgram |
319 | for (const Qt3DCore::QNodeId sharedShaderId : sharedShaderIds) { |
320 | if (sharedShaderId != shaderNode->peerId()) { |
321 | Shader *refShader = shaderManager->lookupResource(id: sharedShaderId); |
322 | // We only introspect once per actual OpenGL shader program |
323 | // rather than once per ShaderNode. |
324 | shaderNode->initializeFromReference(other: *refShader); |
325 | break; |
326 | } |
327 | } |
328 | } |
329 | shaderNode->unsetDirty(); |
330 | // Ensure we will rebuilt material caches |
331 | shaderNode->requestCacheRebuild(); |
332 | } |
333 | |
334 | void GraphicsContext::activateDrawBuffers(const AttachmentPack &attachments) |
335 | { |
336 | const QVector<int> activeDrawBuffers = attachments.getGlDrawBuffers(); |
337 | |
338 | if (m_glHelper->checkFrameBufferComplete()) { |
339 | if (activeDrawBuffers.size() > 1) {// We need MRT |
340 | if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::MRT)) { |
341 | // Set up MRT, glDrawBuffers... |
342 | m_glHelper->drawBuffers(n: activeDrawBuffers.size(), bufs: activeDrawBuffers.data()); |
343 | } |
344 | } |
345 | } else { |
346 | qWarning() << "FBO incomplete" ; |
347 | } |
348 | } |
349 | |
350 | void GraphicsContext::rasterMode(GLenum faceMode, GLenum rasterMode) |
351 | { |
352 | m_glHelper->rasterMode(faceMode, rasterMode); |
353 | } |
354 | |
355 | /*! |
356 | * \internal |
357 | * Finds the highest supported opengl version and internally use the most optimized |
358 | * helper for a given version. |
359 | */ |
360 | GraphicsHelperInterface *GraphicsContext::resolveHighestOpenGLFunctions() |
361 | { |
362 | Q_ASSERT(m_gl); |
363 | GraphicsHelperInterface *glHelper = nullptr; |
364 | |
365 | if (m_gl->isOpenGLES()) { |
366 | if (m_gl->format().majorVersion() >= 3) { |
367 | if (m_gl->format().minorVersion() >= 2) { |
368 | glHelper = new GraphicsHelperES3_2; |
369 | qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.2 Helper" ; |
370 | } else if (m_gl->format().minorVersion() >= 1) { |
371 | glHelper = new GraphicsHelperES3_1; |
372 | qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.1 Helper" ; |
373 | } else { |
374 | glHelper = new GraphicsHelperES3(); |
375 | qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.0 Helper" ; |
376 | } |
377 | } else { |
378 | glHelper = new GraphicsHelperES2(); |
379 | qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES2 Helper" ; |
380 | } |
381 | glHelper->initializeHelper(context: m_gl, functions: nullptr); |
382 | } |
383 | #ifndef QT_OPENGL_ES_2 |
384 | else { |
385 | QAbstractOpenGLFunctions *glFunctions = nullptr; |
386 | if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_4_3_Core>()) != nullptr) { |
387 | qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 4.3" ; |
388 | glHelper = new GraphicsHelperGL4(); |
389 | } else if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_3_3_Core>()) != nullptr) { |
390 | qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 3.3" ; |
391 | glHelper = new GraphicsHelperGL3_3(); |
392 | } else if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_3_2_Core>()) != nullptr) { |
393 | qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 3.2" ; |
394 | glHelper = new GraphicsHelperGL3_2(); |
395 | } else if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_2_0>()) != nullptr) { |
396 | qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 2 Helper" ; |
397 | glHelper = new GraphicsHelperGL2(); |
398 | } |
399 | Q_ASSERT_X(glHelper, "GraphicsContext::resolveHighestOpenGLFunctions" , "unable to create valid helper for available OpenGL version" ); |
400 | glHelper->initializeHelper(context: m_gl, functions: glFunctions); |
401 | } |
402 | #endif |
403 | |
404 | // Note: at this point we are certain the context (m_gl) is current with a surface |
405 | const QByteArray debugLoggingMode = qgetenv(varName: "QT3DRENDER_DEBUG_LOGGING" ); |
406 | const bool enableDebugLogging = !debugLoggingMode.isEmpty(); |
407 | |
408 | if (enableDebugLogging && !m_debugLogger) { |
409 | if (m_gl->hasExtension(extension: "GL_KHR_debug" )) { |
410 | qCDebug(Backend) << "Qt3D: Enabling OpenGL debug logging" ; |
411 | m_debugLogger.reset(other: new QOpenGLDebugLogger); |
412 | if (m_debugLogger->initialize()) { |
413 | QObject::connect(sender: m_debugLogger.data(), signal: &QOpenGLDebugLogger::messageLogged, slot: &logOpenGLDebugMessage); |
414 | const QString mode = QString::fromLocal8Bit(str: debugLoggingMode); |
415 | m_debugLogger->startLogging(loggingMode: mode.startsWith(s: QLatin1String("sync" ), cs: Qt::CaseInsensitive) |
416 | ? QOpenGLDebugLogger::SynchronousLogging |
417 | : QOpenGLDebugLogger::AsynchronousLogging); |
418 | |
419 | const auto msgs = m_debugLogger->loggedMessages(); |
420 | for (const QOpenGLDebugMessage &msg : msgs) |
421 | logOpenGLDebugMessage(debugMessage: msg); |
422 | } |
423 | } else { |
424 | qCDebug(Backend) << "Qt3D: OpenGL debug logging requested but GL_KHR_debug not supported" ; |
425 | } |
426 | } |
427 | |
428 | |
429 | // Set Vendor and Extensions of reference GraphicsApiFilter |
430 | // TO DO: would that vary like the glHelper ? |
431 | |
432 | QStringList extensions; |
433 | const auto exts = m_gl->extensions(); |
434 | for (const QByteArray &ext : exts) |
435 | extensions << QString::fromUtf8(str: ext); |
436 | m_contextInfo.m_major = m_gl->format().version().first; |
437 | m_contextInfo.m_minor = m_gl->format().version().second; |
438 | m_contextInfo.m_api = m_gl->isOpenGLES() ? QGraphicsApiFilter::OpenGLES : QGraphicsApiFilter::OpenGL; |
439 | m_contextInfo.m_profile = static_cast<QGraphicsApiFilter::OpenGLProfile>(m_gl->format().profile()); |
440 | m_contextInfo.m_extensions = extensions; |
441 | m_contextInfo.m_vendor = QString::fromUtf8(str: reinterpret_cast<const char *>(m_gl->functions()->glGetString(GL_VENDOR))); |
442 | |
443 | return glHelper; |
444 | } |
445 | |
446 | const GraphicsApiFilterData *GraphicsContext::contextInfo() const |
447 | { |
448 | return &m_contextInfo; |
449 | } |
450 | |
451 | bool GraphicsContext::supportsDrawBuffersBlend() const |
452 | { |
453 | return m_glHelper->supportsFeature(feature: GraphicsHelperInterface::DrawBuffersBlend); |
454 | } |
455 | |
456 | /*! |
457 | * \internal |
458 | * Wraps an OpenGL call to glDrawElementsInstanced. |
459 | * If the call is not supported by the system's OpenGL version, |
460 | * it is simulated with a loop. |
461 | */ |
462 | void GraphicsContext::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, |
463 | GLsizei primitiveCount, |
464 | GLint indexType, |
465 | void *indices, |
466 | GLsizei instances, |
467 | GLint baseVertex, |
468 | GLint baseInstance) |
469 | { |
470 | m_glHelper->drawElementsInstancedBaseVertexBaseInstance(primitiveType, |
471 | primitiveCount, |
472 | indexType, |
473 | indices, |
474 | instances, |
475 | baseVertex, |
476 | baseInstance); |
477 | } |
478 | |
479 | /*! |
480 | * \internal |
481 | * Wraps an OpenGL call to glDrawArraysInstanced. |
482 | */ |
483 | void GraphicsContext::drawArraysInstanced(GLenum primitiveType, |
484 | GLint first, |
485 | GLsizei count, |
486 | GLsizei instances) |
487 | { |
488 | m_glHelper->drawArraysInstanced(primitiveType, |
489 | first, |
490 | count, |
491 | instances); |
492 | } |
493 | |
494 | void GraphicsContext::drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseinstance) |
495 | { |
496 | m_glHelper->drawArraysInstancedBaseInstance(primitiveType, |
497 | first, |
498 | count, |
499 | instances, |
500 | baseinstance); |
501 | } |
502 | |
503 | /*! |
504 | * \internal |
505 | * Wraps an OpenGL call to glDrawElements. |
506 | */ |
507 | void GraphicsContext::drawElements(GLenum primitiveType, |
508 | GLsizei primitiveCount, |
509 | GLint indexType, |
510 | void *indices, |
511 | GLint baseVertex) |
512 | { |
513 | m_glHelper->drawElements(primitiveType, |
514 | primitiveCount, |
515 | indexType, |
516 | indices, |
517 | baseVertex); |
518 | } |
519 | |
520 | void GraphicsContext::drawElementsIndirect(GLenum mode, |
521 | GLenum type, |
522 | void *indirect) |
523 | { |
524 | m_glHelper->drawElementsIndirect(mode, type, indirect); |
525 | } |
526 | |
527 | /*! |
528 | * \internal |
529 | * Wraps an OpenGL call to glDrawArrays. |
530 | */ |
531 | void GraphicsContext::drawArrays(GLenum primitiveType, |
532 | GLint first, |
533 | GLsizei count) |
534 | { |
535 | m_glHelper->drawArrays(primitiveType, |
536 | first, |
537 | count); |
538 | } |
539 | |
540 | void GraphicsContext::drawArraysIndirect(GLenum mode, void *indirect) |
541 | { |
542 | m_glHelper->drawArraysIndirect(mode, indirect); |
543 | } |
544 | |
545 | void GraphicsContext::setVerticesPerPatch(GLint verticesPerPatch) |
546 | { |
547 | m_glHelper->setVerticesPerPatch(verticesPerPatch); |
548 | } |
549 | |
550 | void GraphicsContext::blendEquation(GLenum mode) |
551 | { |
552 | m_glHelper->blendEquation(mode); |
553 | } |
554 | |
555 | void GraphicsContext::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) |
556 | { |
557 | m_glHelper->blendFunci(buf, sfactor, dfactor); |
558 | } |
559 | |
560 | void GraphicsContext::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) |
561 | { |
562 | m_glHelper->blendFuncSeparatei(buf, sRGB, dRGB, sAlpha, dAlpha); |
563 | } |
564 | |
565 | void GraphicsContext::alphaTest(GLenum mode1, GLenum mode2) |
566 | { |
567 | m_glHelper->alphaTest(mode1, mode2); |
568 | } |
569 | |
570 | void GraphicsContext::bindFramebuffer(GLuint fbo, GraphicsHelperInterface::FBOBindMode mode) |
571 | { |
572 | m_glHelper->bindFrameBufferObject(frameBufferId: fbo, mode); |
573 | } |
574 | |
575 | void GraphicsContext::depthRange(GLdouble nearValue, GLdouble farValue) |
576 | { |
577 | m_glHelper->depthRange(nearValue, farValue); |
578 | } |
579 | |
580 | void GraphicsContext::depthTest(GLenum mode) |
581 | { |
582 | m_glHelper->depthTest(mode); |
583 | } |
584 | |
585 | void GraphicsContext::depthMask(GLenum mode) |
586 | { |
587 | m_glHelper->depthMask(mode); |
588 | } |
589 | |
590 | void GraphicsContext::frontFace(GLenum mode) |
591 | { |
592 | m_glHelper->frontFace(mode); |
593 | } |
594 | |
595 | void GraphicsContext::bindFragOutputs(GLuint shader, const QHash<QString, int> &outputs) |
596 | { |
597 | if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::MRT) && |
598 | m_glHelper->supportsFeature(feature: GraphicsHelperInterface::BindableFragmentOutputs)) |
599 | m_glHelper->bindFragDataLocation(shader, outputs); |
600 | } |
601 | |
602 | void GraphicsContext::bindImageTexture(GLuint imageUnit, GLuint texture, |
603 | GLint mipLevel, GLboolean layered, |
604 | GLint layer, GLenum access, GLenum format) |
605 | { |
606 | m_glHelper->bindImageTexture(imageUnit, |
607 | texture, |
608 | mipLevel, |
609 | layered, |
610 | layer, |
611 | access, |
612 | format); |
613 | } |
614 | |
615 | void GraphicsContext::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) |
616 | { |
617 | m_glHelper->bindUniformBlock(programId, uniformBlockIndex, uniformBlockBinding); |
618 | } |
619 | |
620 | void GraphicsContext::bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) |
621 | { |
622 | m_glHelper->bindShaderStorageBlock(programId, shaderStorageBlockIndex, shaderStorageBlockBinding); |
623 | } |
624 | |
625 | void GraphicsContext::bindBufferBase(GLenum target, GLuint bindingIndex, GLuint buffer) |
626 | { |
627 | m_glHelper->bindBufferBase(target, index: bindingIndex, buffer); |
628 | } |
629 | |
630 | void GraphicsContext::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) |
631 | { |
632 | m_glHelper->buildUniformBuffer(v, description, buffer); |
633 | } |
634 | |
635 | void GraphicsContext::setMSAAEnabled(bool enabled) |
636 | { |
637 | m_glHelper->setMSAAEnabled(enabled); |
638 | } |
639 | |
640 | void GraphicsContext::setAlphaCoverageEnabled(bool enabled) |
641 | { |
642 | m_glHelper->setAlphaCoverageEnabled(enabled); |
643 | } |
644 | |
645 | void GraphicsContext::clearBufferf(GLint drawbuffer, const QVector4D &values) |
646 | { |
647 | m_glHelper->clearBufferf(drawbuffer, values); |
648 | } |
649 | |
650 | GLuint GraphicsContext::boundFrameBufferObject() |
651 | { |
652 | return m_glHelper->boundFrameBufferObject(); |
653 | } |
654 | |
655 | void GraphicsContext::clearColor(const QColor &color) |
656 | { |
657 | m_gl->functions()->glClearColor(red: color.redF(), green: color.greenF(), blue: color.blueF(), alpha: color.alphaF()); |
658 | } |
659 | |
660 | void GraphicsContext::clearDepthValue(float depth) |
661 | { |
662 | m_gl->functions()->glClearDepthf(depth); |
663 | } |
664 | |
665 | void GraphicsContext::clearStencilValue(int stencil) |
666 | { |
667 | m_gl->functions()->glClearStencil(s: stencil); |
668 | } |
669 | |
670 | void GraphicsContext::enableClipPlane(int clipPlane) |
671 | { |
672 | m_glHelper->enableClipPlane(clipPlane); |
673 | } |
674 | |
675 | void GraphicsContext::disableClipPlane(int clipPlane) |
676 | { |
677 | m_glHelper->disableClipPlane(clipPlane); |
678 | } |
679 | |
680 | void GraphicsContext::setClipPlane(int clipPlane, const QVector3D &normal, float distance) |
681 | { |
682 | m_glHelper->setClipPlane(clipPlane, normal, distance); |
683 | } |
684 | |
685 | GLint GraphicsContext::maxClipPlaneCount() |
686 | { |
687 | return m_glHelper->maxClipPlaneCount(); |
688 | } |
689 | |
690 | GLint GraphicsContext::maxTextureUnitsCount() const |
691 | { |
692 | return m_maxTextureUnits; |
693 | } |
694 | |
695 | GLint GraphicsContext::maxImageUnitsCount() const |
696 | { |
697 | return m_maxImageUnits; |
698 | } |
699 | |
700 | |
701 | void GraphicsContext::enablePrimitiveRestart(int restartIndex) |
702 | { |
703 | if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::PrimitiveRestart)) |
704 | m_glHelper->enablePrimitiveRestart(primitiveRestartIndex: restartIndex); |
705 | } |
706 | |
707 | void GraphicsContext::disablePrimitiveRestart() |
708 | { |
709 | if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::PrimitiveRestart)) |
710 | m_glHelper->disablePrimitiveRestart(); |
711 | } |
712 | |
713 | void GraphicsContext::pointSize(bool programmable, GLfloat value) |
714 | { |
715 | m_glHelper->pointSize(programmable, value); |
716 | } |
717 | |
718 | void GraphicsContext::dispatchCompute(int x, int y, int z) |
719 | { |
720 | if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::Compute)) |
721 | m_glHelper->dispatchCompute(wx: x, wy: y, wz: z); |
722 | } |
723 | |
724 | GLboolean GraphicsContext::unmapBuffer(GLenum target) |
725 | { |
726 | return m_glHelper->unmapBuffer(target); |
727 | } |
728 | |
729 | char *GraphicsContext::mapBuffer(GLenum target, GLsizeiptr size) |
730 | { |
731 | return m_glHelper->mapBuffer(target, size); |
732 | } |
733 | |
734 | void GraphicsContext::enablei(GLenum cap, GLuint index) |
735 | { |
736 | m_glHelper->enablei(cap, index); |
737 | } |
738 | |
739 | void GraphicsContext::disablei(GLenum cap, GLuint index) |
740 | { |
741 | m_glHelper->disablei(cap, index); |
742 | } |
743 | |
744 | void GraphicsContext::setSeamlessCubemap(bool enable) |
745 | { |
746 | m_glHelper->setSeamlessCubemap(enable); |
747 | } |
748 | |
749 | void GraphicsContext::readBuffer(GLenum mode) |
750 | { |
751 | m_glHelper->readBuffer(mode); |
752 | } |
753 | |
754 | void GraphicsContext::drawBuffer(GLenum mode) |
755 | { |
756 | m_glHelper->drawBuffer(mode); |
757 | } |
758 | |
759 | void GraphicsContext::drawBuffers(GLsizei n, const int *bufs) |
760 | { |
761 | m_glHelper->drawBuffers(n, bufs); |
762 | } |
763 | |
764 | void GraphicsContext::applyUniform(const ShaderUniform &description, const UniformValue &v) |
765 | { |
766 | const UniformType type = m_glHelper->uniformTypeFromGLType(glType: description.m_type); |
767 | |
768 | switch (type) { |
769 | case UniformType::Float: |
770 | // See QTBUG-57510 and uniform_p.h |
771 | if (v.storedType() == Int) { |
772 | float value = float(*v.constData<int>()); |
773 | UniformValue floatV(value); |
774 | applyUniformHelper<UniformType::Float>(description, value: floatV); |
775 | } else { |
776 | applyUniformHelper<UniformType::Float>(description, value: v); |
777 | } |
778 | break; |
779 | case UniformType::Vec2: |
780 | applyUniformHelper<UniformType::Vec2>(description, value: v); |
781 | break; |
782 | case UniformType::Vec3: |
783 | applyUniformHelper<UniformType::Vec3>(description, value: v); |
784 | break; |
785 | case UniformType::Vec4: |
786 | applyUniformHelper<UniformType::Vec4>(description, value: v); |
787 | break; |
788 | |
789 | case UniformType::Double: |
790 | applyUniformHelper<UniformType::Double>(description, v); |
791 | break; |
792 | case UniformType::DVec2: |
793 | applyUniformHelper<UniformType::DVec2>(description, v); |
794 | break; |
795 | case UniformType::DVec3: |
796 | applyUniformHelper<UniformType::DVec3>(description, v); |
797 | break; |
798 | case UniformType::DVec4: |
799 | applyUniformHelper<UniformType::DVec4>(description, v); |
800 | break; |
801 | |
802 | case UniformType::Sampler: |
803 | case UniformType::Image: |
804 | case UniformType::Int: |
805 | applyUniformHelper<UniformType::Int>(description, value: v); |
806 | break; |
807 | case UniformType::IVec2: |
808 | applyUniformHelper<UniformType::IVec2>(description, value: v); |
809 | break; |
810 | case UniformType::IVec3: |
811 | applyUniformHelper<UniformType::IVec3>(description, value: v); |
812 | break; |
813 | case UniformType::IVec4: |
814 | applyUniformHelper<UniformType::IVec4>(description, value: v); |
815 | break; |
816 | |
817 | case UniformType::UInt: |
818 | applyUniformHelper<UniformType::UInt>(description, value: v); |
819 | break; |
820 | case UniformType::UIVec2: |
821 | applyUniformHelper<UniformType::UIVec2>(description, value: v); |
822 | break; |
823 | case UniformType::UIVec3: |
824 | applyUniformHelper<UniformType::UIVec3>(description, value: v); |
825 | break; |
826 | case UniformType::UIVec4: |
827 | applyUniformHelper<UniformType::UIVec4>(description, value: v); |
828 | break; |
829 | |
830 | case UniformType::Bool: |
831 | applyUniformHelper<UniformType::Bool>(description, value: v); |
832 | break; |
833 | case UniformType::BVec2: |
834 | applyUniformHelper<UniformType::BVec2>(description, value: v); |
835 | break; |
836 | case UniformType::BVec3: |
837 | applyUniformHelper<UniformType::BVec3>(description, value: v); |
838 | break; |
839 | case UniformType::BVec4: |
840 | applyUniformHelper<UniformType::BVec4>(description, value: v); |
841 | break; |
842 | |
843 | case UniformType::Mat2: |
844 | applyUniformHelper<UniformType::Mat2>(description, value: v); |
845 | break; |
846 | case UniformType::Mat3: |
847 | applyUniformHelper<UniformType::Mat3>(description, value: v); |
848 | break; |
849 | case UniformType::Mat4: |
850 | applyUniformHelper<UniformType::Mat4>(description, value: v); |
851 | break; |
852 | case UniformType::Mat2x3: |
853 | applyUniformHelper<UniformType::Mat2x3>(description, value: v); |
854 | break; |
855 | case UniformType::Mat3x2: |
856 | applyUniformHelper<UniformType::Mat3x2>(description, value: v); |
857 | break; |
858 | case UniformType::Mat2x4: |
859 | applyUniformHelper<UniformType::Mat2x4>(description, value: v); |
860 | break; |
861 | case UniformType::Mat4x2: |
862 | applyUniformHelper<UniformType::Mat4x2>(description, value: v); |
863 | break; |
864 | case UniformType::Mat3x4: |
865 | applyUniformHelper<UniformType::Mat3x4>(description, value: v); |
866 | break; |
867 | case UniformType::Mat4x3: |
868 | applyUniformHelper<UniformType::Mat4x3>(description, value: v); |
869 | break; |
870 | |
871 | default: |
872 | break; |
873 | } |
874 | } |
875 | |
876 | void GraphicsContext::memoryBarrier(QMemoryBarrier::Operations barriers) |
877 | { |
878 | m_glHelper->memoryBarrier(barriers); |
879 | } |
880 | |
881 | GLint GraphicsContext::elementType(GLint type) |
882 | { |
883 | switch (type) { |
884 | case GL_FLOAT: |
885 | case GL_FLOAT_VEC2: |
886 | case GL_FLOAT_VEC3: |
887 | case GL_FLOAT_VEC4: |
888 | return GL_FLOAT; |
889 | |
890 | #ifndef QT_OPENGL_ES_2 // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2 |
891 | case GL_DOUBLE: |
892 | #ifdef GL_DOUBLE_VEC3 // For compiling on pre GL 4.1 systems |
893 | case GL_DOUBLE_VEC2: |
894 | case GL_DOUBLE_VEC3: |
895 | case GL_DOUBLE_VEC4: |
896 | #endif |
897 | return GL_DOUBLE; |
898 | #endif |
899 | default: |
900 | qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, base: 16); |
901 | } |
902 | |
903 | return GL_INVALID_VALUE; |
904 | } |
905 | |
906 | GLint GraphicsContext::tupleSizeFromType(GLint type) |
907 | { |
908 | switch (type) { |
909 | case GL_FLOAT: |
910 | #ifndef QT_OPENGL_ES_2 // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2 |
911 | case GL_DOUBLE: |
912 | #endif |
913 | case GL_UNSIGNED_BYTE: |
914 | case GL_UNSIGNED_INT: |
915 | break; // fall through |
916 | |
917 | case GL_FLOAT_VEC2: |
918 | #ifdef GL_DOUBLE_VEC2 // For compiling on pre GL 4.1 systems. |
919 | case GL_DOUBLE_VEC2: |
920 | #endif |
921 | return 2; |
922 | |
923 | case GL_FLOAT_VEC3: |
924 | #ifdef GL_DOUBLE_VEC3 // For compiling on pre GL 4.1 systems. |
925 | case GL_DOUBLE_VEC3: |
926 | #endif |
927 | return 3; |
928 | |
929 | case GL_FLOAT_VEC4: |
930 | #ifdef GL_DOUBLE_VEC4 // For compiling on pre GL 4.1 systems. |
931 | case GL_DOUBLE_VEC4: |
932 | #endif |
933 | return 4; |
934 | |
935 | default: |
936 | qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, base: 16); |
937 | } |
938 | |
939 | return 1; |
940 | } |
941 | |
942 | GLuint GraphicsContext::byteSizeFromType(GLint type) |
943 | { |
944 | switch (type) { |
945 | case GL_FLOAT: return sizeof(float); |
946 | #ifndef QT_OPENGL_ES_2 // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2 |
947 | case GL_DOUBLE: return sizeof(double); |
948 | #endif |
949 | case GL_UNSIGNED_BYTE: return sizeof(unsigned char); |
950 | case GL_UNSIGNED_INT: return sizeof(GLuint); |
951 | |
952 | case GL_FLOAT_VEC2: return sizeof(float) * 2; |
953 | case GL_FLOAT_VEC3: return sizeof(float) * 3; |
954 | case GL_FLOAT_VEC4: return sizeof(float) * 4; |
955 | #ifdef GL_DOUBLE_VEC3 // Required to compile on pre GL 4.1 systems |
956 | case GL_DOUBLE_VEC2: return sizeof(double) * 2; |
957 | case GL_DOUBLE_VEC3: return sizeof(double) * 3; |
958 | case GL_DOUBLE_VEC4: return sizeof(double) * 4; |
959 | #endif |
960 | default: |
961 | qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, base: 16); |
962 | } |
963 | |
964 | return 0; |
965 | } |
966 | |
967 | GLint GraphicsContext::glDataTypeFromAttributeDataType(QAttribute::VertexBaseType dataType) |
968 | { |
969 | switch (dataType) { |
970 | case QAttribute::Byte: |
971 | return GL_BYTE; |
972 | case QAttribute::UnsignedByte: |
973 | return GL_UNSIGNED_BYTE; |
974 | case QAttribute::Short: |
975 | return GL_SHORT; |
976 | case QAttribute::UnsignedShort: |
977 | return GL_UNSIGNED_SHORT; |
978 | case QAttribute::Int: |
979 | return GL_INT; |
980 | case QAttribute::UnsignedInt: |
981 | return GL_UNSIGNED_INT; |
982 | case QAttribute::HalfFloat: |
983 | #ifdef GL_HALF_FLOAT |
984 | return GL_HALF_FLOAT; |
985 | #endif |
986 | #ifndef QT_OPENGL_ES_2 // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2 |
987 | case QAttribute::Double: |
988 | return GL_DOUBLE; |
989 | #endif |
990 | case QAttribute::Float: |
991 | break; |
992 | default: |
993 | qWarning() << Q_FUNC_INFO << "unsupported dataType:" << dataType; |
994 | } |
995 | return GL_FLOAT; |
996 | } |
997 | |
998 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Float, float, glUniform1fv) |
999 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec2, float, glUniform2fv) |
1000 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec3, float, glUniform3fv) |
1001 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec4, float, glUniform4fv) |
1002 | |
1003 | // OpenGL expects int* as values for booleans |
1004 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Bool, int, glUniform1iv) |
1005 | QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec2, int, glUniform2iv) |
1006 | QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec3, int, glUniform3iv) |
1007 | QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec4, int, glUniform4iv) |
1008 | |
1009 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Int, int, glUniform1iv) |
1010 | QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec2, int, glUniform2iv) |
1011 | QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec3, int, glUniform3iv) |
1012 | QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec4, int, glUniform4iv) |
1013 | |
1014 | QT3D_UNIFORM_TYPE_IMPL(UniformType::UInt, uint, glUniform1uiv) |
1015 | QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec2, uint, glUniform2uiv) |
1016 | QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec3, uint, glUniform3uiv) |
1017 | QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec4, uint, glUniform4uiv) |
1018 | |
1019 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2, float, glUniformMatrix2fv) |
1020 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3, float, glUniformMatrix3fv) |
1021 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4, float, glUniformMatrix4fv) |
1022 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2x3, float, glUniformMatrix2x3fv) |
1023 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3x2, float, glUniformMatrix3x2fv) |
1024 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2x4, float, glUniformMatrix2x4fv) |
1025 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4x2, float, glUniformMatrix4x2fv) |
1026 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3x4, float, glUniformMatrix3x4fv) |
1027 | QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4x3, float, glUniformMatrix4x3fv) |
1028 | |
1029 | } // namespace OpenGL |
1030 | } // namespace Render |
1031 | } // namespace Qt3DRender of namespace |
1032 | |
1033 | QT_END_NAMESPACE |
1034 | |