/**************************************************************************** ** ** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of Qt 3D Studio. ** ** $QT_BEGIN_LICENSE:GPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 or (at your option) any later version ** approved by the KDE Free Qt Foundation. The licenses are as published by ** the Free Software Foundation and appearing in the file LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "dragonglshader_p.h" #include #include #include QT_BEGIN_NAMESPACE namespace Qt3DRender { namespace Dragon { 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(); } } StandardUniformsNameToTypeHash initializeSetters() { StandardUniformsNameToTypeHash setters; setters.insert(DragonStringToInt::lookupId(QLatin1String("modelMatrix")), ModelMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("viewMatrix")), ViewMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("projectionMatrix")), ProjectionMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("modelView")), ModelViewMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("viewProjectionMatrix")), ViewProjectionMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("modelViewProjection")), ModelViewProjectionMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("mvp")), ModelViewProjectionMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("inverseModelMatrix")), InverseModelMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("inverseViewMatrix")), InverseViewMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("inverseProjectionMatrix")), InverseProjectionMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("inverseModelView")), InverseModelViewMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("inverseViewProjectionMatrix")), InverseViewProjectionMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("inverseModelViewProjection")), InverseModelViewProjectionMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("modelNormalMatrix")), ModelNormalMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("modelViewNormal")), ModelViewNormalMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("viewportMatrix")), ViewportMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("inverseViewportMatrix")), InverseViewportMatrix); setters.insert(DragonStringToInt::lookupId(QLatin1String("aspectRatio")), AspectRatio); setters.insert(DragonStringToInt::lookupId(QLatin1String("exposure")), Exposure); setters.insert(DragonStringToInt::lookupId(QLatin1String("gamma")), Gamma); setters.insert(DragonStringToInt::lookupId(QLatin1String("time")), Time); setters.insert(DragonStringToInt::lookupId(QLatin1String("eyePosition")), EyePosition); setters.insert(DragonStringToInt::lookupId(QLatin1String("skinningPalette[0]")), SkinningPalette); return setters; } static StandardUniformsNameToTypeHash s_standardUniformSetters = initializeSetters(); // TODO once we have C++14, this could go inside the function as a generic lambda template Container nameToNameId(Container container) { for (auto &value : container) { value.m_nameId = DragonStringToInt::lookupId(value.m_name); } return container; } } // namespace GLShader::GLShader(const ActivatedSurface &gl, const Immutable &shader) { GLShader &result = *this; result.dna = shader->dna(); // TODO remember to delete result.shaderProgram.reset(new QOpenGLShaderProgram); auto *shaderProgram = result.shaderProgram.data(); // convenience // Compile shaders const auto shaderCode = shader->shaderCode(); QString logs; for (int i = QShaderProgram::Vertex; i <= QShaderProgram::Compute; ++i) { QShaderProgram::ShaderType type = static_cast(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 // TODO add back support for frag outputs // bindFragOutputs(shaderProgram->programId(), shaderNode->fragOutputs()); const bool linkSucceeded = shaderProgram->link(); logs += shaderProgram->log(); // TODO add back support for logs // shader->setLog(logs); // shader->setStatus(linkSucceeded ? QShaderProgram::Ready : QShaderProgram::Error); if (!linkSucceeded) { qWarning() << "WARNING: Shader linking failed"; return; } // Ensure the Shader node knows about the program interface // Find an already loaded shader that shares the same QOpenGLShaderProgram // Introspect and set up interface description on Shader backend node // TODO should not have access to glHelper here, should use ActivatedSurface helper functions // or this entire function could go inside ActivatedSurface auto *glHelper = gl.glHelper(); auto uniforms = glHelper->programUniformsAndLocations(shaderProgram->programId()); uniforms = nameToNameId(uniforms); const auto &setters = s_standardUniformSetters; for (const auto &uniform : uniforms) { const auto &nameId = uniform.m_nameId; const auto &setter = setters[nameId]; if (setter == StandardUniform::UserUniform) { result.uniforms.append(uniform); continue; } StandardShaderUniform standardShaderUniform; standardShaderUniform.standardUniform = setter; standardShaderUniform.shaderUniform = uniform; result.standardUniforms.append(standardShaderUniform); } result.attributes = glHelper->programAttributesAndLocations(shaderProgram->programId()); result.attributes = nameToNameId(result.attributes); if (glHelper->supportsFeature(Dragon::GraphicsHelperInterface::UniformBufferObject)) { result.uniformBlocks = glHelper->programUniformBlocks(shaderProgram->programId()); result.uniformBlocks = nameToNameId(result.uniformBlocks); } if (glHelper->supportsFeature(Dragon::GraphicsHelperInterface::ShaderStorageObject)) { result.storageBlocks = glHelper->programShaderStorageBlocks(shaderProgram->programId()); result.storageBlocks = nameToNameId(result.storageBlocks); } } } } QT_END_NAMESPACE