Revision control

Copy as Markdown

// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
// Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "graphicscontext_p.h"
#include <Qt3DRender/qgraphicsapifilter.h>
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/private/renderlogging_p.h>
#include <Qt3DRender/private/shader_p.h>
#include <Qt3DRender/private/material_p.h>
#include <Qt3DRender/private/buffer_p.h>
#include <Qt3DRender/private/attribute_p.h>
#include <Qt3DRender/private/rendertarget_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/buffermanager_p.h>
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/attachmentpack_p.h>
#include <Qt3DRender/private/attachmentpack_p.h>
#include <Qt3DRender/private/renderstateset_p.h>
#include <QOpenGLShaderProgram>
#include <glresourcemanagers_p.h>
#include <graphicshelperinterface_p.h>
#include <gltexture_p.h>
#include <rendercommand_p.h>
#include <renderer_p.h>
#include <renderbuffer_p.h>
#include <glshader_p.h>
#if !QT_CONFIG(opengles2)
#include <QtOpenGL/QOpenGLVersionFunctionsFactory>
#include <QOpenGLFunctions_2_0>
#include <QOpenGLFunctions_3_2_Core>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLFunctions_4_3_Core>
#include <graphicshelpergl2_p.h>
#include <graphicshelpergl3_2_p.h>
#include <graphicshelpergl3_3_p.h>
#include <graphicshelpergl4_p.h>
#endif
#include <graphicshelperes2_p.h>
#include <graphicshelperes3_p.h>
#include <graphicshelperes3_1_p.h>
#include <graphicshelperes3_2_p.h>
#include <QSurface>
#include <QWindow>
#include <QOpenGLTexture>
#ifdef QT_OPENGL_LIB
#include <QtOpenGL/QOpenGLDebugLogger>
#endif
QT_BEGIN_NAMESPACE
#ifndef GL_READ_FRAMEBUFFER
#define GL_READ_FRAMEBUFFER 0x8CA8
#endif
#ifndef GL_DRAW_FRAMEBUFFER
#define GL_DRAW_FRAMEBUFFER 0x8CA9
#endif
#ifndef GL_MAX_IMAGE_UNITS
#define GL_MAX_IMAGE_UNITS 0x8F38
#endif
namespace {
QOpenGLShader::ShaderType shaderType(Qt3DRender::QShaderProgram::ShaderType type)
{
switch (type) {
case Qt3DRender::QShaderProgram::Vertex: return QOpenGLShader::Vertex;
case Qt3DRender::QShaderProgram::TessellationControl: return QOpenGLShader::TessellationControl;
case Qt3DRender::QShaderProgram::TessellationEvaluation: return QOpenGLShader::TessellationEvaluation;
case Qt3DRender::QShaderProgram::Geometry: return QOpenGLShader::Geometry;
case Qt3DRender::QShaderProgram::Fragment: return QOpenGLShader::Fragment;
case Qt3DRender::QShaderProgram::Compute: return QOpenGLShader::Compute;
default: Q_UNREACHABLE();
}
}
} // anonymous namespace
namespace Qt3DRender {
namespace Render {
namespace OpenGL {
namespace {
#ifdef QT_OPENGL_LIB
void logOpenGLDebugMessage(const QOpenGLDebugMessage &debugMessage)
{
qDebug() << "OpenGL debug message:" << debugMessage;
}
#endif
} // anonymous
GraphicsContext::GraphicsContext()
: m_initialized(false)
, m_supportsVAO(false)
, m_maxTextureUnits(0)
, m_maxImageUnits(0)
, m_defaultFBO(0)
, m_gl(nullptr)
, m_glHelper(nullptr)
#ifdef QT_OPENGL_LIB
, m_debugLogger(nullptr)
#endif
, m_currentVAO(nullptr)
{
}
GraphicsContext::~GraphicsContext()
{
}
void GraphicsContext::setOpenGLContext(QOpenGLContext* ctx)
{
Q_ASSERT(ctx);
m_gl = ctx;
}
void GraphicsContext::initialize()
{
m_initialized = true;
Q_ASSERT(m_gl);
m_gl->functions()->glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &m_maxTextureUnits);
qCDebug(Backend) << "context supports" << m_maxTextureUnits << "texture units";
m_gl->functions()->glGetIntegerv(GL_MAX_IMAGE_UNITS, &m_maxImageUnits);
qCDebug(Backend) << "context supports" << m_maxImageUnits << "image units";
if (m_gl->format().majorVersion() >= 3) {
m_supportsVAO = true;
} else {
QSet<QByteArray> extensions = m_gl->extensions();
m_supportsVAO = extensions.contains(QByteArrayLiteral("GL_OES_vertex_array_object"))
|| extensions.contains(QByteArrayLiteral("GL_ARB_vertex_array_object"))
|| extensions.contains(QByteArrayLiteral("GL_APPLE_vertex_array_object"));
}
m_defaultFBO = m_gl->defaultFramebufferObject();
qCDebug(Backend) << "VAO support = " << m_supportsVAO;
}
void GraphicsContext::clearBackBuffer(QClearBuffers::BufferTypeFlags buffers)
{
if (buffers != QClearBuffers::None) {
GLbitfield mask = 0;
if (buffers & QClearBuffers::ColorBuffer)
mask |= GL_COLOR_BUFFER_BIT;
if (buffers & QClearBuffers::DepthBuffer)
mask |= GL_DEPTH_BUFFER_BIT;
if (buffers & QClearBuffers::StencilBuffer)
mask |= GL_STENCIL_BUFFER_BIT;
m_gl->functions()->glClear(mask);
}
}
bool GraphicsContext::hasValidGLHelper() const
{
return m_glHelper != nullptr;
}
bool GraphicsContext::isInitialized() const
{
return m_initialized;
}
bool GraphicsContext::makeCurrent(QSurface *surface)
{
Q_ASSERT(m_gl);
if (!m_gl->makeCurrent(surface)) {
qCWarning(Backend) << Q_FUNC_INFO << "makeCurrent failed";
return false;
}
initializeHelpers(surface);
return true;
}
void GraphicsContext::initializeHelpers(QSurface *surface)
{
// Set the correct GL Helper depending on the surface
// If no helper exists, create one
auto it = m_glHelpers.find(surface);
if (it == m_glHelpers.end())
std::tie(it, std::ignore) = m_glHelpers.emplace(surface, resolveHighestOpenGLFunctions());
m_glHelper = it->second.get();
}
void GraphicsContext::doneCurrent()
{
Q_ASSERT(m_gl);
m_gl->doneCurrent();
m_glHelper = nullptr;
}
// Called by GraphicsContext::loadShader itself called by Renderer::updateGLResources
GraphicsContext::ShaderCreationInfo GraphicsContext::createShaderProgram(GLShader *shader)
{
QOpenGLShaderProgram *shaderProgram = shader->shaderProgram();
// Compile shaders
const auto shaderCode = shader->shaderCode();
QString logs;
for (int i = QShaderProgram::Vertex; i <= QShaderProgram::Compute; ++i) {
const QShaderProgram::ShaderType type = static_cast<QShaderProgram::ShaderType>(i);
if (!shaderCode.at(i).isEmpty()) {
// Note: logs only return the error but not all the shader code
// we could append it
if (!shaderProgram->addCacheableShaderFromSourceCode(shaderType(type), shaderCode.at(i)))
logs += shaderProgram->log();
}
}
// Call glBindFragDataLocation and link the program
// Since we are sharing shaders in the backend, we assume that if using custom
// fragOutputs, they should all be the same for a given shader
bindFragOutputs(shaderProgram->programId(), shader->fragOutputs());
const bool linkSucceeded = shaderProgram->link();
logs += shaderProgram->log();
// Perform shader introspection
introspectShaderInterface(shader);
ShaderCreationInfo info;
info.linkSucceeded = linkSucceeded;
info.logs = logs;
return info;
}
// That assumes that the shaderProgram in Shader stays the same
void GraphicsContext::introspectShaderInterface(GLShader *shader)
{
QOpenGLShaderProgram *shaderProgram = shader->shaderProgram();
shader->initializeUniforms(m_glHelper->programUniformsAndLocations(shaderProgram->programId()));
shader->initializeAttributes(m_glHelper->programAttributesAndLocations(shaderProgram->programId()));
if (m_glHelper->supportsFeature(GraphicsHelperInterface::UniformBufferObject))
shader->initializeUniformBlocks(m_glHelper->programUniformBlocks(shaderProgram->programId()));
if (m_glHelper->supportsFeature(GraphicsHelperInterface::ShaderStorageObject))
shader->initializeShaderStorageBlocks(m_glHelper->programShaderStorageBlocks(shaderProgram->programId()));
}
// Called by Renderer::updateGLResources
void GraphicsContext::loadShader(Shader *shaderNode,
ShaderManager *shaderManager,
GLShaderManager *glShaderManager)
{
const Qt3DCore::QNodeId shaderId = shaderNode->peerId();
GLShader *glShader = glShaderManager->lookupResource(shaderId);
// We already have a shader associated with the node
if (glShader != nullptr) {
// We need to abandon it
glShaderManager->abandon(glShader, shaderNode);
}
// We create or adopt an already created glShader
glShader = glShaderManager->createOrAdoptExisting(shaderNode);
const std::vector<Qt3DCore::QNodeId> sharedShaderIds = glShaderManager->shaderIdsForProgram(glShader);
if (sharedShaderIds.size() == 1) {
// The Shader could already be loaded if we retrieved one
// that had been marked for destruction
if (!glShader->isLoaded()) {
glShader->setGraphicsContext(this);
glShader->setShaderCode(shaderNode->shaderCode());
const ShaderCreationInfo loadResult = createShaderProgram(glShader);
shaderNode->setStatus(loadResult.linkSucceeded ? QShaderProgram::Ready : QShaderProgram::Error);
shaderNode->setLog(loadResult.logs);
// Loaded in the sense we tried to load it (and maybe it failed)
glShader->setLoaded(true);
}
} else {
// Find an already loaded shader that shares the same QOpenGLShaderProgram
for (const Qt3DCore::QNodeId &sharedShaderId : sharedShaderIds) {
if (sharedShaderId != shaderNode->peerId()) {
Shader *refShader = shaderManager->lookupResource(sharedShaderId);
// We only introspect once per actual OpenGL shader program
// rather than once per ShaderNode.
shaderNode->initializeFromReference(*refShader);
break;
}
}
}
shaderNode->unsetDirty();
// Ensure we will rebuilt material caches
shaderNode->requestCacheRebuild();
}
void GraphicsContext::rasterMode(GLenum faceMode, GLenum rasterMode)
{
m_glHelper->rasterMode(faceMode, rasterMode);
}
/*!
* \internal
* Finds the highest supported opengl version and internally use the most optimized
* helper for a given version.
*/
GraphicsHelperInterface *GraphicsContext::resolveHighestOpenGLFunctions()
{
Q_ASSERT(m_gl);
GraphicsHelperInterface *glHelper = nullptr;
if (m_gl->isOpenGLES()) {
if (m_gl->format().majorVersion() >= 3) {
if (m_gl->format().minorVersion() >= 2) {
glHelper = new GraphicsHelperES3_2;
qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.2 Helper";
} else if (m_gl->format().minorVersion() >= 1) {
glHelper = new GraphicsHelperES3_1;
qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.1 Helper";
} else {
glHelper = new GraphicsHelperES3();
qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.0 Helper";
}
} else {
glHelper = new GraphicsHelperES2();
qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES2 Helper";
}
glHelper->initializeHelper(m_gl, nullptr);
}
#if !QT_CONFIG(opengles2)
else {
QAbstractOpenGLFunctions *glFunctions = nullptr;
if ((glFunctions = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_4_3_Core>()) != nullptr) {
qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 4.3";
glHelper = new GraphicsHelperGL4();
} else if ((glFunctions = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_3_3_Core>()) != nullptr) {
qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 3.3";
glHelper = new GraphicsHelperGL3_3();
} else if ((glFunctions = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_3_2_Core>()) != nullptr) {
qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 3.2";
glHelper = new GraphicsHelperGL3_2();
} else if ((glFunctions = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_2_0>()) != nullptr) {
qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 2 Helper";
glHelper = new GraphicsHelperGL2();
}
Q_ASSERT_X(glHelper, "GraphicsContext::resolveHighestOpenGLFunctions", "unable to create valid helper for available OpenGL version");
glHelper->initializeHelper(m_gl, glFunctions);
}
#endif
// Note: at this point we are certain the context (m_gl) is current with a surface
const QByteArray debugLoggingMode = qgetenv("QT3DRENDER_DEBUG_LOGGING");
const bool enableDebugLogging = !debugLoggingMode.isEmpty();
#ifdef QT_OPENGL_LIB
if (enableDebugLogging && !m_debugLogger) {
if (m_gl->hasExtension("GL_KHR_debug")) {
qCDebug(Backend) << "Qt3D: Enabling OpenGL debug logging";
m_debugLogger.reset(new QOpenGLDebugLogger);
if (m_debugLogger->initialize()) {
QObject::connect(m_debugLogger.data(), &QOpenGLDebugLogger::messageLogged, m_debugLogger.data(), &logOpenGLDebugMessage);
const QString mode = QString::fromLocal8Bit(debugLoggingMode);
m_debugLogger->startLogging(mode.startsWith(QLatin1String("sync"), Qt::CaseInsensitive)
? QOpenGLDebugLogger::SynchronousLogging
: QOpenGLDebugLogger::AsynchronousLogging);
const auto msgs = m_debugLogger->loggedMessages();
for (const QOpenGLDebugMessage &msg : msgs)
logOpenGLDebugMessage(msg);
}
} else {
qCDebug(Backend) << "Qt3D: OpenGL debug logging requested but GL_KHR_debug not supported";
}
}
#endif
// Set Vendor and Extensions of reference GraphicsApiFilter
// TO DO: would that vary like the glHelper ?
QStringList extensions;
const auto exts = m_gl->extensions();
for (const QByteArray &ext : exts)
extensions << QString::fromUtf8(ext);
m_contextInfo.m_major = m_gl->format().version().first;
m_contextInfo.m_minor = m_gl->format().version().second;
m_contextInfo.m_api = m_gl->isOpenGLES() ? QGraphicsApiFilter::OpenGLES : QGraphicsApiFilter::OpenGL;
m_contextInfo.m_profile = static_cast<QGraphicsApiFilter::OpenGLProfile>(m_gl->format().profile());
m_contextInfo.m_extensions = extensions;
m_contextInfo.m_vendor = QString::fromUtf8(reinterpret_cast<const char *>(m_gl->functions()->glGetString(GL_VENDOR)));
return glHelper;
}
const GraphicsApiFilterData *GraphicsContext::contextInfo() const
{
return &m_contextInfo;
}
bool GraphicsContext::supportsDrawBuffersBlend() const
{
return m_glHelper->supportsFeature(GraphicsHelperInterface::DrawBuffersBlend);
}
/*!
* \internal
* Wraps an OpenGL call to glDrawElementsInstanced.
* If the call is not supported by the system's OpenGL version,
* it is simulated with a loop.
*/
void GraphicsContext::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType,
GLsizei primitiveCount,
GLint indexType,
void *indices,
GLsizei instances,
GLint baseVertex,
GLint baseInstance)
{
m_glHelper->drawElementsInstancedBaseVertexBaseInstance(primitiveType,
primitiveCount,
indexType,
indices,
instances,
baseVertex,
baseInstance);
}
/*!
* \internal
* Wraps an OpenGL call to glDrawArraysInstanced.
*/
void GraphicsContext::drawArraysInstanced(GLenum primitiveType,
GLint first,
GLsizei count,
GLsizei instances)
{
m_glHelper->drawArraysInstanced(primitiveType,
first,
count,
instances);
}
void GraphicsContext::drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseinstance)
{
m_glHelper->drawArraysInstancedBaseInstance(primitiveType,
first,
count,
instances,
baseinstance);
}
/*!
* \internal
* Wraps an OpenGL call to glDrawElements.
*/
void GraphicsContext::drawElements(GLenum primitiveType,
GLsizei primitiveCount,
GLint indexType,
void *indices,
GLint baseVertex)
{
m_glHelper->drawElements(primitiveType,
primitiveCount,
indexType,
indices,
baseVertex);
}
void GraphicsContext::drawElementsIndirect(GLenum mode,
GLenum type,
void *indirect)
{
m_glHelper->drawElementsIndirect(mode, type, indirect);
}
/*!
* \internal
* Wraps an OpenGL call to glDrawArrays.
*/
void GraphicsContext::drawArrays(GLenum primitiveType,
GLint first,
GLsizei count)
{
m_glHelper->drawArrays(primitiveType,
first,
count);
}
void GraphicsContext::drawArraysIndirect(GLenum mode, void *indirect)
{
m_glHelper->drawArraysIndirect(mode, indirect);
}
void GraphicsContext::setVerticesPerPatch(GLint verticesPerPatch)
{
m_glHelper->setVerticesPerPatch(verticesPerPatch);
}
void GraphicsContext::blendEquation(GLenum mode)
{
m_glHelper->blendEquation(mode);
}
void GraphicsContext::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
{
m_glHelper->blendFunci(buf, sfactor, dfactor);
}
void GraphicsContext::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha)
{
m_glHelper->blendFuncSeparatei(buf, sRGB, dRGB, sAlpha, dAlpha);
}
void GraphicsContext::alphaTest(GLenum mode1, GLenum mode2)
{
m_glHelper->alphaTest(mode1, mode2);
}
void GraphicsContext::bindFramebuffer(GLuint fbo, GraphicsHelperInterface::FBOBindMode mode)
{
m_glHelper->bindFrameBufferObject(fbo, mode);
}
void GraphicsContext::depthRange(GLdouble nearValue, GLdouble farValue)
{
m_glHelper->depthRange(nearValue, farValue);
}
void GraphicsContext::depthTest(GLenum mode)
{
m_glHelper->depthTest(mode);
}
void GraphicsContext::depthMask(GLenum mode)
{
m_glHelper->depthMask(mode);
}
void GraphicsContext::frontFace(GLenum mode)
{
m_glHelper->frontFace(mode);
}
void GraphicsContext::bindFragOutputs(GLuint shader, const QHash<QString, int> &outputs)
{
if (m_glHelper->supportsFeature(GraphicsHelperInterface::MRT) &&
m_glHelper->supportsFeature(GraphicsHelperInterface::BindableFragmentOutputs))
m_glHelper->bindFragDataLocation(shader, outputs);
}
void GraphicsContext::bindImageTexture(GLuint imageUnit, GLuint texture,
GLint mipLevel, GLboolean layered,
GLint layer, GLenum access, GLenum format)
{
m_glHelper->bindImageTexture(imageUnit,
texture,
mipLevel,
layered,
layer,
access,
format);
}
void GraphicsContext::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
{
m_glHelper->bindUniformBlock(programId, uniformBlockIndex, uniformBlockBinding);
}
void GraphicsContext::bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding)
{
m_glHelper->bindShaderStorageBlock(programId, shaderStorageBlockIndex, shaderStorageBlockBinding);
}
void GraphicsContext::bindBufferBase(GLenum target, GLuint bindingIndex, GLuint buffer)
{
m_glHelper->bindBufferBase(target, bindingIndex, buffer);
}
void GraphicsContext::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
{
m_glHelper->buildUniformBuffer(v, description, buffer);
}
void GraphicsContext::setMSAAEnabled(bool enabled)
{
m_glHelper->setMSAAEnabled(enabled);
}
void GraphicsContext::setAlphaCoverageEnabled(bool enabled)
{
m_glHelper->setAlphaCoverageEnabled(enabled);
}
void GraphicsContext::clearBufferf(GLint drawbuffer, const QVector4D &values)
{
m_glHelper->clearBufferf(drawbuffer, values);
}
GLuint GraphicsContext::boundFrameBufferObject()
{
return m_glHelper->boundFrameBufferObject();
}
void GraphicsContext::clearColor(const QColor &color)
{
m_gl->functions()->glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());
}
void GraphicsContext::clearDepthValue(float depth)
{
m_gl->functions()->glClearDepthf(depth);
}
void GraphicsContext::clearStencilValue(int stencil)
{
m_gl->functions()->glClearStencil(stencil);
}
void GraphicsContext::enableClipPlane(int clipPlane)
{
m_glHelper->enableClipPlane(clipPlane);
}
void GraphicsContext::disableClipPlane(int clipPlane)
{
m_glHelper->disableClipPlane(clipPlane);
}
void GraphicsContext::setClipPlane(int clipPlane, const QVector3D &normal, float distance)
{
m_glHelper->setClipPlane(clipPlane, normal, distance);
}
GLint GraphicsContext::maxClipPlaneCount()
{
return m_glHelper->maxClipPlaneCount();
}
GLint GraphicsContext::maxTextureUnitsCount() const
{
return m_maxTextureUnits;
}
GLint GraphicsContext::maxImageUnitsCount() const
{
return m_maxImageUnits;
}
void GraphicsContext::enablePrimitiveRestart(int restartIndex)
{
if (m_glHelper->supportsFeature(GraphicsHelperInterface::PrimitiveRestart))
m_glHelper->enablePrimitiveRestart(restartIndex);
}
void GraphicsContext::disablePrimitiveRestart()
{
if (m_glHelper->supportsFeature(GraphicsHelperInterface::PrimitiveRestart))
m_glHelper->disablePrimitiveRestart();
}
void GraphicsContext::pointSize(bool programmable, GLfloat value)
{
m_glHelper->pointSize(programmable, value);
}
void GraphicsContext::dispatchCompute(int x, int y, int z)
{
if (m_glHelper->supportsFeature(GraphicsHelperInterface::Compute))
m_glHelper->dispatchCompute(x, y, z);
}
GLboolean GraphicsContext::unmapBuffer(GLenum target)
{
return m_glHelper->unmapBuffer(target);
}
char *GraphicsContext::mapBuffer(GLenum target, GLsizeiptr size)
{
return m_glHelper->mapBuffer(target, size);
}
void GraphicsContext::enablei(GLenum cap, GLuint index)
{
m_glHelper->enablei(cap, index);
}
void GraphicsContext::disablei(GLenum cap, GLuint index)
{
m_glHelper->disablei(cap, index);
}
void GraphicsContext::setSeamlessCubemap(bool enable)
{
m_glHelper->setSeamlessCubemap(enable);
}
void GraphicsContext::readBuffer(GLenum mode)
{
m_glHelper->readBuffer(mode);
}
void GraphicsContext::drawBuffer(GLenum mode)
{
m_glHelper->drawBuffer(mode);
}
void GraphicsContext::drawBuffers(GLsizei n, const GLenum *bufs)
{
m_glHelper->drawBuffers(n, bufs);
}
void GraphicsContext::applyUniform(const ShaderUniform &description, const UniformValue &v)
{
const UniformType type = m_glHelper->uniformTypeFromGLType(description.m_type);
switch (type) {
case UniformType::Float:
// See QTBUG-57510 and uniform_p.h
if (v.storedType() == Int) {
float value = float(*v.constData<int>());
UniformValue floatV(value);
applyUniformHelper<UniformType::Float>(description, floatV);
} else {
applyUniformHelper<UniformType::Float>(description, v);
}
break;
case UniformType::Vec2:
applyUniformHelper<UniformType::Vec2>(description, v);
break;
case UniformType::Vec3:
applyUniformHelper<UniformType::Vec3>(description, v);
break;
case UniformType::Vec4:
applyUniformHelper<UniformType::Vec4>(description, v);
break;
case UniformType::Double:
applyUniformHelper<UniformType::Double>(description, v);
break;
case UniformType::DVec2:
applyUniformHelper<UniformType::DVec2>(description, v);
break;
case UniformType::DVec3:
applyUniformHelper<UniformType::DVec3>(description, v);
break;
case UniformType::DVec4:
applyUniformHelper<UniformType::DVec4>(description, v);
break;
case UniformType::Sampler:
case UniformType::Image:
case UniformType::Int:
applyUniformHelper<UniformType::Int>(description, v);
break;
case UniformType::IVec2:
applyUniformHelper<UniformType::IVec2>(description, v);
break;
case UniformType::IVec3:
applyUniformHelper<UniformType::IVec3>(description, v);
break;
case UniformType::IVec4:
applyUniformHelper<UniformType::IVec4>(description, v);
break;
case UniformType::UInt:
applyUniformHelper<UniformType::UInt>(description, v);
break;
case UniformType::UIVec2:
applyUniformHelper<UniformType::UIVec2>(description, v);
break;
case UniformType::UIVec3:
applyUniformHelper<UniformType::UIVec3>(description, v);
break;
case UniformType::UIVec4:
applyUniformHelper<UniformType::UIVec4>(description, v);
break;
case UniformType::Bool:
applyUniformHelper<UniformType::Bool>(description, v);
break;
case UniformType::BVec2:
applyUniformHelper<UniformType::BVec2>(description, v);
break;
case UniformType::BVec3:
applyUniformHelper<UniformType::BVec3>(description, v);
break;
case UniformType::BVec4:
applyUniformHelper<UniformType::BVec4>(description, v);
break;
case UniformType::Mat2:
applyUniformHelper<UniformType::Mat2>(description, v);
break;
case UniformType::Mat3:
applyUniformHelper<UniformType::Mat3>(description, v);
break;
case UniformType::Mat4:
applyUniformHelper<UniformType::Mat4>(description, v);
break;
case UniformType::Mat2x3:
applyUniformHelper<UniformType::Mat2x3>(description, v);
break;
case UniformType::Mat3x2:
applyUniformHelper<UniformType::Mat3x2>(description, v);
break;
case UniformType::Mat2x4:
applyUniformHelper<UniformType::Mat2x4>(description, v);
break;
case UniformType::Mat4x2:
applyUniformHelper<UniformType::Mat4x2>(description, v);
break;
case UniformType::Mat3x4:
applyUniformHelper<UniformType::Mat3x4>(description, v);
break;
case UniformType::Mat4x3:
applyUniformHelper<UniformType::Mat4x3>(description, v);
break;
default:
break;
}
}
void GraphicsContext::memoryBarrier(QMemoryBarrier::Operations barriers)
{
m_glHelper->memoryBarrier(barriers);
}
GLint GraphicsContext::elementType(GLint type)
{
switch (type) {
case GL_FLOAT:
case GL_FLOAT_VEC2:
case GL_FLOAT_VEC3:
case GL_FLOAT_VEC4:
return GL_FLOAT;
#if !QT_CONFIG(opengles2) // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
case GL_DOUBLE:
#ifdef GL_DOUBLE_VEC3 // For compiling on pre GL 4.1 systems
case GL_DOUBLE_VEC2:
case GL_DOUBLE_VEC3:
case GL_DOUBLE_VEC4:
#endif
return GL_DOUBLE;
#endif
default:
qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, 16);
}
return GL_INVALID_VALUE;
}
GLint GraphicsContext::tupleSizeFromType(GLint type)
{
switch (type) {
case GL_FLOAT:
#if !QT_CONFIG(opengles2) // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
case GL_DOUBLE:
#endif
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_INT:
break; // fall through
case GL_FLOAT_VEC2:
#ifdef GL_DOUBLE_VEC2 // For compiling on pre GL 4.1 systems.
case GL_DOUBLE_VEC2:
#endif
return 2;
case GL_FLOAT_VEC3:
#ifdef GL_DOUBLE_VEC3 // For compiling on pre GL 4.1 systems.
case GL_DOUBLE_VEC3:
#endif
return 3;
case GL_FLOAT_VEC4:
#ifdef GL_DOUBLE_VEC4 // For compiling on pre GL 4.1 systems.
case GL_DOUBLE_VEC4:
#endif
return 4;
default:
qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, 16);
}
return 1;
}
GLuint GraphicsContext::byteSizeFromType(GLint type)
{
switch (type) {
case GL_FLOAT: return sizeof(float);
#if !QT_CONFIG(opengles2) // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
case GL_DOUBLE: return sizeof(double);
#endif
case GL_UNSIGNED_BYTE: return sizeof(unsigned char);
case GL_UNSIGNED_INT: return sizeof(GLuint);
case GL_FLOAT_VEC2: return sizeof(float) * 2;
case GL_FLOAT_VEC3: return sizeof(float) * 3;
case GL_FLOAT_VEC4: return sizeof(float) * 4;
#ifdef GL_DOUBLE_VEC3 // Required to compile on pre GL 4.1 systems
case GL_DOUBLE_VEC2: return sizeof(double) * 2;
case GL_DOUBLE_VEC3: return sizeof(double) * 3;
case GL_DOUBLE_VEC4: return sizeof(double) * 4;
#endif
default:
qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, 16);
}
return 0;
}
GLint GraphicsContext::glDataTypeFromAttributeDataType(Qt3DCore::QAttribute::VertexBaseType dataType)
{
using namespace Qt3DCore;
switch (dataType) {
case QAttribute::Byte:
return GL_BYTE;
case QAttribute::UnsignedByte:
return GL_UNSIGNED_BYTE;
case QAttribute::Short:
return GL_SHORT;
case QAttribute::UnsignedShort:
return GL_UNSIGNED_SHORT;
case QAttribute::Int:
return GL_INT;
case QAttribute::UnsignedInt:
return GL_UNSIGNED_INT;
case QAttribute::HalfFloat:
#ifdef GL_HALF_FLOAT
return GL_HALF_FLOAT;
#endif
#if !QT_CONFIG(opengles2) // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
case QAttribute::Double:
return GL_DOUBLE;
#endif
case QAttribute::Float:
break;
default:
qWarning() << Q_FUNC_INFO << "unsupported dataType:" << dataType;
}
return GL_FLOAT;
}
QT3D_UNIFORM_TYPE_IMPL(UniformType::Float, float, glUniform1fv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec2, float, glUniform2fv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec3, float, glUniform3fv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec4, float, glUniform4fv)
// OpenGL expects int* as values for booleans
QT3D_UNIFORM_TYPE_IMPL(UniformType::Bool, int, glUniform1iv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec2, int, glUniform2iv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec3, int, glUniform3iv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec4, int, glUniform4iv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::Int, int, glUniform1iv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec2, int, glUniform2iv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec3, int, glUniform3iv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec4, int, glUniform4iv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::UInt, uint, glUniform1uiv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec2, uint, glUniform2uiv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec3, uint, glUniform3uiv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec4, uint, glUniform4uiv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2, float, glUniformMatrix2fv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3, float, glUniformMatrix3fv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4, float, glUniformMatrix4fv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2x3, float, glUniformMatrix2x3fv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3x2, float, glUniformMatrix3x2fv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2x4, float, glUniformMatrix2x4fv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4x2, float, glUniformMatrix4x2fv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3x4, float, glUniformMatrix3x4fv)
QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4x3, float, glUniformMatrix4x3fv)
} // namespace OpenGL
} // namespace Render
} // namespace Qt3DRender of namespace
QT_END_NAMESPACE