summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2019-06-04 14:37:29 +0200
committerPaul Lemire <paul.lemire@kdab.com>2019-06-05 16:05:13 +0200
commitc7167bac4efa50dcc21ed6ef48cc7a40d0bb5e82 (patch)
treef084b0e83914e02a21acbb4589717d4d55b29d8b
parent7f72710d73510b9d58e822ffa5b39dbd3fbbc11a (diff)
Renderer: Image support added
Change-Id: I5b2764f0ae5184c2097d6da5e7a6e24b5c6a5d1b Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r--src/render/backend/commandexecuter.cpp2
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp15
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicscontext_p.h4
-rw-r--r--src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri2
-rw-r--r--src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext.cpp304
-rw-r--r--src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext_p.h95
-rw-r--r--src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp43
-rw-r--r--src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h2
-rw-r--r--src/render/renderers/opengl/renderer/renderview.cpp40
-rw-r--r--src/render/renderers/opengl/renderer/shaderparameterpack.cpp17
-rw-r--r--src/render/renderers/opengl/renderer/shaderparameterpack_p.h38
11 files changed, 527 insertions, 35 deletions
diff --git a/src/render/backend/commandexecuter.cpp b/src/render/backend/commandexecuter.cpp
index 182ba89d1..54c3548ba 100644
--- a/src/render/backend/commandexecuter.cpp
+++ b/src/render/backend/commandexecuter.cpp
@@ -261,7 +261,7 @@ QJsonObject parameterPackToJson(const Render::ShaderParameterPack &pack)
obj.insert(QLatin1String("uniforms"), uniformsArray);
QJsonArray texturesArray;
- const QVector<Render::ShaderParameterPack::NamedTexture> &textures = pack.textures();
+ const QVector<Render::ShaderParameterPack::NamedResource> &textures = pack.textures();
for (const auto & texture : textures) {
QJsonObject textureObj;
textureObj.insert(QLatin1String("name"), Render::StringToInt::lookupString(texture.glslNameId));
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp b/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp
index 76320cfe5..c9b04fa8f 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp
@@ -92,6 +92,10 @@ QT_BEGIN_NAMESPACE
#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)
@@ -125,6 +129,7 @@ GraphicsContext::GraphicsContext()
: m_initialized(false)
, m_supportsVAO(false)
, m_maxTextureUnits(0)
+ , m_maxImageUnits(0)
, m_defaultFBO(0)
, m_gl(nullptr)
, m_glHelper(nullptr)
@@ -152,6 +157,8 @@ void GraphicsContext::initialize()
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;
@@ -675,11 +682,17 @@ GLint GraphicsContext::maxClipPlaneCount()
return m_glHelper->maxClipPlaneCount();
}
-GLint GraphicsContext::maxTextureUnitsCount()
+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))
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicscontext_p.h b/src/render/renderers/opengl/graphicshelpers/graphicscontext_p.h
index a6cce47cd..2f4df2e22 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicscontext_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/graphicscontext_p.h
@@ -156,7 +156,8 @@ public:
void enablePrimitiveRestart(int restartIndex);
void frontFace(GLenum mode);
GLint maxClipPlaneCount();
- GLint maxTextureUnitsCount();
+ GLint maxTextureUnitsCount() const;
+ GLint maxImageUnitsCount() const;
void pointSize(bool programmable, GLfloat value);
void readBuffer(GLenum mode);
void drawBuffer(GLenum mode);
@@ -186,6 +187,7 @@ public:
bool m_initialized;
bool m_supportsVAO;
GLint m_maxTextureUnits;
+ GLint m_maxImageUnits;
GLuint m_defaultFBO;
QOpenGLContext *m_gl;
GraphicsHelperInterface *m_glHelper;
diff --git a/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri b/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri
index ad08038c9..f2f7274d7 100644
--- a/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri
+++ b/src/render/renderers/opengl/graphicshelpers/graphicshelpers.pri
@@ -14,6 +14,7 @@ HEADERS += \
$$PWD/graphicshelpergl3_3_p.h \
$$PWD/graphicshelpergl4_p.h \
$$PWD/graphicshelpergl3_2_p.h \
+ $$PWD/imagesubmissioncontext_p.h \
$$PWD/submissioncontext_p.h \
$$PWD/texturesubmissioncontext_p.h
@@ -27,5 +28,6 @@ SOURCES += \
$$PWD/graphicshelpergl3_3.cpp \
$$PWD/graphicshelpergl4.cpp \
$$PWD/graphicshelpergl3_2.cpp \
+ $$PWD/imagesubmissioncontext.cpp \
$$PWD/submissioncontext.cpp \
$$PWD/texturesubmissioncontext.cpp
diff --git a/src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext.cpp b/src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext.cpp
new file mode 100644
index 000000000..a5633c306
--- /dev/null
+++ b/src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext.cpp
@@ -0,0 +1,304 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or 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.GPL2 and 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "imagesubmissioncontext_p.h"
+#include <Qt3DRender/private/graphicscontext_p.h>
+#include <Qt3DRender/private/gltexture_p.h>
+#include <Qt3DRender/private/shaderimage_p.h>
+#include <Qt3DRender/qshaderimage.h>
+
+QT_BEGIN_NAMESPACE
+
+// ES 3.1+ or GL 4.2+
+#ifndef GL_READ_ONLY
+#define GL_READ_ONLY 0x88B8
+#endif
+#ifndef GL_WRITE_ONLY
+#define GL_WRITE_ONLY 0x88B9
+#endif
+#ifndef GL_READ_WRITE
+#define GL_READ_WRITE 0x88BA
+#endif
+
+namespace Qt3DRender {
+namespace Render {
+
+class GraphicsContext;
+class GLTexture;
+
+namespace {
+
+GLenum glAccessEnumForShaderImageAccess(QShaderImage::Access access)
+{
+ switch (access) {
+ case QShaderImage::ReadOnly:
+ return GL_READ_ONLY;
+ case QShaderImage::WriteOnly:
+ return GL_WRITE_ONLY;
+ case QShaderImage::ReadWrite:
+ return GL_READ_WRITE;
+ }
+}
+
+GLenum glImageFormatToGL(QShaderImage::ImageFormat format)
+{
+ // Right now we can abuse from the fact that the ImageFormat enum values
+ // have been assigned the same value as the GL enum
+ return GLenum(format);
+}
+
+GLenum glImageFormatForShaderImageFormat(QShaderImage::ImageFormat format,
+ QAbstractTexture::TextureFormat textureFormat)
+{
+ Q_ASSERT_X(format != QShaderImage::NoFormat, Q_FUNC_INFO, "Valid image format or Automatic expected");
+
+ if (format != QShaderImage::Automatic)
+ return glImageFormatToGL(format);
+
+ // Otherwise try to mind to best texture format
+ switch (textureFormat) {
+ case QAbstractTexture::R8_UNorm:
+ return glImageFormatToGL(QShaderImage::R8_UNorm);
+ case QAbstractTexture::RG8_UNorm:
+ return glImageFormatToGL(QShaderImage::RG8_UNorm);
+ case QAbstractTexture::RGBA8_UNorm:
+ return glImageFormatToGL(QShaderImage::RGBA8_UNorm);
+
+ case QAbstractTexture::R16_UNorm:
+ return glImageFormatToGL(QShaderImage::R16_UNorm);
+ case QAbstractTexture::RG16_UNorm:
+ return glImageFormatToGL(QShaderImage::RG16_UNorm);
+ case QAbstractTexture::RGBA16_UNorm:
+ return glImageFormatToGL(QShaderImage::RGBA16_UNorm);
+
+ case QAbstractTexture::R8_SNorm:
+ return glImageFormatToGL(QShaderImage::R8_SNorm);
+ case QAbstractTexture::RG8_SNorm:
+ return glImageFormatToGL(QShaderImage::RG8_SNorm);
+ case QAbstractTexture::RGBA8_SNorm:
+ return glImageFormatToGL(QShaderImage::RGBA8_SNorm);
+
+ case QAbstractTexture::R16_SNorm:
+ return glImageFormatToGL(QShaderImage::R16_SNorm);
+ case QAbstractTexture::RG16_SNorm:
+ return glImageFormatToGL(QShaderImage::RG16_SNorm);
+ case QAbstractTexture::RGBA16_SNorm:
+ return glImageFormatToGL(QShaderImage::RGBA16_SNorm);
+
+ case QAbstractTexture::R8U:
+ return glImageFormatToGL(QShaderImage::R8U);
+ case QAbstractTexture::RG8U:
+ return glImageFormatToGL(QShaderImage::RG8U);
+ case QAbstractTexture::RGBA8U:
+ return glImageFormatToGL(QShaderImage::RGBA8U);
+
+ case QAbstractTexture::R16U:
+ return glImageFormatToGL(QShaderImage::R16U);
+ case QAbstractTexture::RG16U:
+ return glImageFormatToGL(QShaderImage::RG16U);
+ case QAbstractTexture::RGBA16U:
+ return glImageFormatToGL(QShaderImage::RGBA16U);
+
+ case QAbstractTexture::R32U:
+ return glImageFormatToGL(QShaderImage::R32U);
+ case QAbstractTexture::RG32U:
+ return glImageFormatToGL(QShaderImage::RG32U);
+ case QAbstractTexture::RGBA32U:
+ return glImageFormatToGL(QShaderImage::RGBA32U);
+
+ case QAbstractTexture::R8I:
+ return glImageFormatToGL(QShaderImage::R8I);
+ case QAbstractTexture::RG8I:
+ return glImageFormatToGL(QShaderImage::RG8I);
+ case QAbstractTexture::RGBA8I:
+ return glImageFormatToGL(QShaderImage::RGBA8I);
+
+ case QAbstractTexture::R16I:
+ return glImageFormatToGL(QShaderImage::R16I);
+ case QAbstractTexture::RG16I:
+ return glImageFormatToGL(QShaderImage::RG16I);
+ case QAbstractTexture::RGBA16I:
+ return glImageFormatToGL(QShaderImage::RGBA16I);
+
+ case QAbstractTexture::R32I:
+ return glImageFormatToGL(QShaderImage::R32I);
+ case QAbstractTexture::RG32I:
+ return glImageFormatToGL(QShaderImage::RG32I);
+ case QAbstractTexture::RGBA32I:
+ return glImageFormatToGL(QShaderImage::RGBA32I);
+
+ case QAbstractTexture::R16F:
+ return glImageFormatToGL(QShaderImage::R16F);
+ case QAbstractTexture::RG16F:
+ return glImageFormatToGL(QShaderImage::RG16F);
+ case QAbstractTexture::RGBA16F:
+ return glImageFormatToGL(QShaderImage::RGBA16F);
+
+ case QAbstractTexture::R32F:
+ return glImageFormatToGL(QShaderImage::R32F);
+ case QAbstractTexture::RG32F:
+ return glImageFormatToGL(QShaderImage::RG32F);
+ case QAbstractTexture::RGBA32F:
+ return glImageFormatToGL(QShaderImage::RGBA32F);
+
+ case QAbstractTexture::RG11B10F:
+ return glImageFormatToGL(QShaderImage::RG11B10F);
+ case QAbstractTexture::RGB10A2:
+ return glImageFormatToGL(QShaderImage::RGB10A2);
+ case QAbstractTexture::RGB10A2U:
+ return glImageFormatToGL(QShaderImage::RGB10A2U);
+
+ default:
+ qWarning() << "Cannot map Texture format" << textureFormat << "to a valid Image Format";
+ Q_UNREACHABLE();
+ return GL_NONE;
+ }
+}
+
+} // anonymous
+
+ImageSubmissionContext::ImageSubmissionContext()
+ : m_ctx(nullptr)
+{
+}
+
+void ImageSubmissionContext::initialize(GraphicsContext *context)
+{
+ m_ctx = context;
+ m_activeImages.resize(m_ctx->maxImageUnitsCount());
+}
+
+void ImageSubmissionContext::endDrawing()
+{
+ // Reduce score of all active Images
+ decayImageScores();
+}
+
+// Return Image Unit for Image
+// If Image was used previously and recently, it will return the last used unit
+// for that image. Otherwise it will try to return the image unit the least used.
+int ImageSubmissionContext::activateImage(ShaderImage *image, GLTexture *tex)
+{
+ const int onUnit = assignUnitForImage(image->peerId());
+
+ if (onUnit < 0) {
+ qWarning() << "Unable to find available image unit";
+ return -1;
+ }
+
+ QOpenGLTexture *glTex = tex->getGLTexture();
+ if (glTex == nullptr) {
+ qWarning() << "Unable to retrieve valid texture for Image";
+ return -1;
+ }
+
+ // Bind Image against Texture and resolve Image Format
+ m_ctx->bindImageTexture(onUnit,
+ glTex->textureId(),
+ image->mipLevel(),
+ image->layered(),
+ image->layer(),
+ glAccessEnumForShaderImageAccess(image->access()),
+ glImageFormatForShaderImageFormat(image->format(),
+ tex->properties().format));
+
+ // Store information about the Texture/Image on ActiveImage for given
+ // image unit
+ m_activeImages[onUnit].shaderImageId = image->peerId();
+ m_activeImages[onUnit].texture = tex;
+ m_activeImages[onUnit].score = 200;
+ m_activeImages[onUnit].pinned = true;
+
+ return onUnit;
+}
+
+// Unset pinned Active Image and reduce their score
+void ImageSubmissionContext::deactivateImages()
+{
+ for (int u = 0, m = m_activeImages.size(); u < m; ++u) {
+ if (m_activeImages[u].pinned) {
+ m_activeImages[u].pinned = false;
+ m_activeImages[u].score = qMax(m_activeImages[u].score - 1, 0);
+ return;
+ }
+ }
+}
+
+// Reduce score of all active images (pinned or not)
+void ImageSubmissionContext::decayImageScores()
+{
+ for (int u = 0, m = m_activeImages.size(); u < m; ++u)
+ m_activeImages[u].score = qMax(m_activeImages[u].score - 1, 0);
+}
+
+int ImageSubmissionContext::assignUnitForImage(Qt3DCore::QNodeId shaderImageId)
+{
+ int lowestScoredUnit = -1;
+ int lowestScore = 0xfffffff;
+
+ const int m = m_activeImages.size();
+ for (int u = 0; u < m; ++u) {
+ if (m_activeImages[u].shaderImageId == shaderImageId)
+ return u;
+ }
+
+ for (int u = 0; u < m; ++u) {
+ // No image is currently active on the image unit
+ // we save the image unit with the texture that has been on there
+ // the longest time while not being used
+ if (!m_activeImages[u].pinned) {
+ const int score = m_activeImages[u].score;
+ if (score < lowestScore) {
+ lowestScore = score;
+ lowestScoredUnit = u;
+ }
+ }
+ }
+
+ if (lowestScoredUnit == -1)
+ qCWarning(Backend) << Q_FUNC_INFO << "No free image units!";
+
+ return lowestScoredUnit;
+}
+
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext_p.h b/src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext_p.h
new file mode 100644
index 000000000..6d39f469b
--- /dev/null
+++ b/src/render/renderers/opengl/graphicshelpers/imagesubmissioncontext_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or 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.GPL2 and 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_IMAGESUBMISSIONCONTEXT_P_H
+#define QT3DRENDER_RENDER_IMAGESUBMISSIONCONTEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/QNodeId>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class GraphicsContext;
+class GLTexture;
+class ShaderImage;
+
+class Q_AUTOTEST_EXPORT ImageSubmissionContext
+{
+public:
+ ImageSubmissionContext();
+
+ void initialize(GraphicsContext *context);
+ void endDrawing();
+ int activateImage(ShaderImage *image, GLTexture *tex);
+ void deactivateImages();
+
+private:
+ void decayImageScores();
+ int assignUnitForImage(Qt3DCore::QNodeId shaderImageId);
+
+ struct ActiveImage
+ {
+ Qt3DCore::QNodeId shaderImageId;
+ GLTexture *texture = nullptr;
+ int score = 0;
+ bool pinned = false;
+ };
+ QVector<ActiveImage> m_activeImages;
+ GraphicsContext *m_ctx;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_IMAGESUBMISSIONCONTEXT_P_H
diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp
index d3bc46c12..028fd607a 100644
--- a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp
+++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp
@@ -389,6 +389,7 @@ void SubmissionContext::initialize()
{
GraphicsContext::initialize();
m_textureContext.initialize(this);
+ m_imageContext.initialize(this);
}
void SubmissionContext::resolveRenderTargetFormat()
@@ -479,6 +480,7 @@ void SubmissionContext::endDrawing(bool swapBuffers)
if (m_ownCurrent)
m_gl->doneCurrent();
m_textureContext.endDrawing();
+ m_imageContext.endDrawing();
}
void SubmissionContext::activateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments, GLuint defaultFboId)
@@ -864,6 +866,7 @@ void SubmissionContext::setActiveMaterial(Material *rmat)
return;
m_textureContext.deactivateTexturesWithScope(TextureSubmissionContext::TextureScopeMaterial);
+ m_imageContext.deactivateImages();
m_material = rmat;
}
@@ -1160,11 +1163,13 @@ bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack)
// Update the uniforms with the correct texture unit id's
PackUniformHash &uniformValues = parameterPack.uniforms();
+ // Fill Texture Uniform Value with proper texture units
+ // so that they can be applied as regular uniforms in a second step
for (int i = 0; i < parameterPack.textures().size(); ++i) {
- const ShaderParameterPack::NamedTexture &namedTex = parameterPack.textures().at(i);
+ const ShaderParameterPack::NamedResource &namedTex = parameterPack.textures().at(i);
// Given a Texture QNodeId, we retrieve the associated shared GLTexture
if (uniformValues.contains(namedTex.glslNameId)) {
- GLTexture *t = manager->glTextureManager()->lookupResource(namedTex.texId);
+ GLTexture *t = manager->glTextureManager()->lookupResource(namedTex.nodeId);
if (t != nullptr) {
UniformValue &texUniform = uniformValues[namedTex.glslNameId];
if (texUniform.valueType() == UniformValue::TextureValue) {
@@ -1174,6 +1179,34 @@ bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack)
if (namedTex.glslNameId != irradianceId &&
namedTex.glslNameId != specularId) {
// Only return false if we are not dealing with env light textures
+ qWarning() << "Unable to find suitable Texture Unit";
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Fill Image Uniform Value with proper image units
+ // so that they can be applied as regular uniforms in a second step
+ for (int i = 0; i < parameterPack.images().size(); ++i) {
+ const ShaderParameterPack::NamedResource &namedTex = parameterPack.images().at(i);
+ // Given a Texture QNodeId, we retrieve the associated shared GLTexture
+ if (uniformValues.contains(namedTex.glslNameId)) {
+ ShaderImage *img = manager->shaderImageManager()->lookupResource(namedTex.nodeId);
+ if (img != nullptr) {
+ GLTexture *t = manager->glTextureManager()->lookupResource(img->textureId());
+ if (t == nullptr) {
+ qWarning() << "Shader Image referencing invalid texture";
+ continue;
+ } else {
+ UniformValue &imgUniform = uniformValues[namedTex.glslNameId];
+ if (imgUniform.valueType() == UniformValue::ShaderImageValue) {
+ const int imgUnit = m_imageContext.activateImage(img, t);
+ imgUniform.data<int>()[namedTex.uniformArrayIndex] = imgUnit;
+ if (imgUnit == -1) {
+ qWarning() << "Unable to bind Image to Texture";
return false;
}
}
@@ -1229,8 +1262,10 @@ bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack)
// be un activeUniforms if there wasn't a matching value
const UniformValue &v = values[uniform.m_nameId];
- // skip invalid textures
- if (v.valueType() == UniformValue::TextureValue && *v.constData<int>() == -1)
+ // skip invalid textures/images
+ if ((v.valueType() == UniformValue::TextureValue ||
+ v.valueType() == UniformValue::ShaderImageValue) &&
+ *v.constData<int>() == -1)
continue;
applyUniform(uniform, v);
diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h b/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h
index 844e62f15..a8700dd3a 100644
--- a/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h
+++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext_p.h
@@ -55,6 +55,7 @@
#include <Qt3DRender/private/graphicscontext_p.h>
#include <Qt3DRender/private/texturesubmissioncontext_p.h>
+#include <Qt3DRender/private/imagesubmissioncontext_p.h>
#include <Qt3DRender/qclearbuffers.h>
#include <Qt3DRender/private/glbuffer_p.h>
#include <Qt3DRender/qattribute.h>
@@ -204,6 +205,7 @@ private:
QByteArray m_uboTempArray;
TextureSubmissionContext m_textureContext;
+ ImageSubmissionContext m_imageContext;
// Attributes
friend class OpenGLVertexArrayObject;
diff --git a/src/render/renderers/opengl/renderer/renderview.cpp b/src/render/renderers/opengl/renderer/renderview.cpp
index cf4a930bc..ebb1ee7ab 100644
--- a/src/render/renderers/opengl/renderer/renderview.cpp
+++ b/src/render/renderers/opengl/renderer/renderview.cpp
@@ -328,14 +328,14 @@ struct AdjacentSubRangeFinder<QSortPolicy::Texture>
static bool adjacentSubRange(RenderCommand *a, RenderCommand *b)
{
// Two renderCommands are adjacent if one contains all the other command's textures
- QVector<ShaderParameterPack::NamedTexture> texturesA = a->m_parameterPack.textures();
- QVector<ShaderParameterPack::NamedTexture> texturesB = b->m_parameterPack.textures();
+ QVector<ShaderParameterPack::NamedResource> texturesA = a->m_parameterPack.textures();
+ QVector<ShaderParameterPack::NamedResource> texturesB = b->m_parameterPack.textures();
if (texturesB.size() > texturesA.size())
qSwap(texturesA, texturesB);
// textureB.size() is always <= textureA.size()
- for (const ShaderParameterPack::NamedTexture &texB : qAsConst(texturesB)) {
+ for (const ShaderParameterPack::NamedResource &texB : qAsConst(texturesB)) {
if (!texturesA.contains(texB))
return false;
}
@@ -421,8 +421,8 @@ struct SubRangeSorter<QSortPolicy::Texture>
static void sortSubRange(CommandIt begin, const CommandIt end)
{
std::stable_sort(begin, end, [] (RenderCommand *a, RenderCommand *b) {
- QVector<ShaderParameterPack::NamedTexture> texturesA = a->m_parameterPack.textures();
- QVector<ShaderParameterPack::NamedTexture> texturesB = b->m_parameterPack.textures();
+ QVector<ShaderParameterPack::NamedResource> texturesA = a->m_parameterPack.textures();
+ QVector<ShaderParameterPack::NamedResource> texturesB = b->m_parameterPack.textures();
const int originalTextureASize = texturesA.size();
const bool isSuperior = originalTextureASize > texturesB.size();
@@ -432,7 +432,7 @@ struct SubRangeSorter<QSortPolicy::Texture>
int identicalTextureCount = 0;
- for (const ShaderParameterPack::NamedTexture &texB : qAsConst(texturesB)) {
+ for (const ShaderParameterPack::NamedResource &texB : qAsConst(texturesB)) {
if (texturesA.contains(texB))
++identicalTextureCount;
}
@@ -829,23 +829,35 @@ void RenderView::updateMatrices()
void RenderView::setUniformValue(ShaderParameterPack &uniformPack, int nameId, const UniformValue &value) const
{
// At this point a uniform value can only be a scalar type
- // or a Qt3DCore::QNodeId corresponding to a Texture
+ // or a Qt3DCore::QNodeId corresponding to a Texture or Image
// ShaderData/Buffers would be handled as UBO/SSBO and would therefore
// not be in the default uniform block
if (value.valueType() == UniformValue::NodeId) {
const Qt3DCore::QNodeId *nodeIds = value.constData<Qt3DCore::QNodeId>();
const int uniformArraySize = value.byteSize() / sizeof(Qt3DCore::QNodeId);
+ UniformValue::ValueType resourceType = UniformValue::TextureValue;
+
for (int i = 0; i < uniformArraySize; ++i) {
- const Qt3DCore::QNodeId texId = nodeIds[i];
- const Texture *tex = m_manager->textureManager()->lookupResource(texId);
- if (tex != nullptr)
- uniformPack.setTexture(nameId, i, texId);
+ const Qt3DCore::QNodeId resourceId = nodeIds[i];
+
+ const Texture *tex = m_manager->textureManager()->lookupResource(resourceId);
+ if (tex != nullptr) {
+ uniformPack.setTexture(nameId, i, resourceId);
+ } else {
+ const ShaderImage *img = m_manager->shaderImageManager()->lookupResource(resourceId);
+ if (img != nullptr) {
+ resourceType = UniformValue::ShaderImageValue;
+ uniformPack.setImage(nameId, i, resourceId);
+ }
+ }
}
- UniformValue textureValue(uniformArraySize * sizeof(int), UniformValue::TextureValue);
- std::fill(textureValue.data<int>(), textureValue.data<int>() + uniformArraySize, -1);
- uniformPack.setUniform(nameId, textureValue);
+ // This uniform will be overridden in SubmissionContext::setParameters
+ // and -1 values will be replaced by valid Texture or Image units
+ UniformValue uniformValue(uniformArraySize * sizeof(int), resourceType);
+ std::fill(uniformValue.data<int>(), uniformValue.data<int>() + uniformArraySize, -1);
+ uniformPack.setUniform(nameId, uniformValue);
} else {
uniformPack.setUniform(nameId, value);
}
diff --git a/src/render/renderers/opengl/renderer/shaderparameterpack.cpp b/src/render/renderers/opengl/renderer/shaderparameterpack.cpp
index f78e45a5e..13d05cac1 100644
--- a/src/render/renderers/opengl/renderer/shaderparameterpack.cpp
+++ b/src/render/renderers/opengl/renderer/shaderparameterpack.cpp
@@ -71,11 +71,24 @@ void ShaderParameterPack::setTexture(const int glslNameId, int uniformArrayIndex
if (m_textures[t].glslNameId != glslNameId || m_textures[t].uniformArrayIndex != uniformArrayIndex)
continue;
- m_textures[t].texId = texId;
+ m_textures[t].nodeId = texId;
return;
}
- m_textures.append(NamedTexture(glslNameId, texId, uniformArrayIndex));
+ m_textures.append(NamedResource(glslNameId, texId, uniformArrayIndex, NamedResource::Texture));
+}
+
+void ShaderParameterPack::setImage(const int glslNameId, int uniformArrayIndex, Qt3DCore::QNodeId id)
+{
+ for (int i=0, m = m_images.size(); i < m; ++i) {
+ if (m_images[i].glslNameId != glslNameId || m_images[i].uniformArrayIndex != uniformArrayIndex)
+ continue;
+
+ m_images[i].nodeId = id;
+ return;
+ }
+
+ m_images.append(NamedResource(glslNameId, id, uniformArrayIndex, NamedResource::Image));
}
// Contains Uniform Block Index and QNodeId of the ShaderData (UBO)
diff --git a/src/render/renderers/opengl/renderer/shaderparameterpack_p.h b/src/render/renderers/opengl/renderer/shaderparameterpack_p.h
index d1fbe936f..a5aee6ac4 100644
--- a/src/render/renderers/opengl/renderer/shaderparameterpack_p.h
+++ b/src/render/renderers/opengl/renderer/shaderparameterpack_p.h
@@ -98,6 +98,8 @@ public:
void setUniform(const int glslNameId, const UniformValue &val);
void setTexture(const int glslNameId, int uniformArrayIndex, Qt3DCore::QNodeId id);
+ void setImage(const int glslNameId, int uniformArrayIndex, Qt3DCore::QNodeId id);
+
void setUniformBuffer(BlockToUBO blockToUBO);
void setShaderStorageBuffer(BlockToSSBO blockToSSBO);
void setSubmissionUniform(const ShaderUniform &uniform);
@@ -106,47 +108,59 @@ public:
inline const PackUniformHash &uniforms() const { return m_uniforms; }
UniformValue uniform(const int glslNameId) const { return m_uniforms.value(glslNameId); }
- struct NamedTexture
+
+ struct NamedResource
{
- NamedTexture() {}
- NamedTexture(const int glslNameId, Qt3DCore::QNodeId texId, int uniformArrayIndex)
+ enum Type {
+ Texture = 0,
+ Image
+ };
+
+ NamedResource() {}
+ NamedResource(const int glslNameId, Qt3DCore::QNodeId texId,
+ int uniformArrayIndex, Type type)
: glslNameId(glslNameId)
- , texId(texId)
+ , nodeId(texId)
, uniformArrayIndex(uniformArrayIndex)
+ , type(type)
{ }
int glslNameId;
- Qt3DCore::QNodeId texId;
+ Qt3DCore::QNodeId nodeId;
int uniformArrayIndex;
+ Type type;
- bool operator==(const NamedTexture &other) const
+ bool operator==(const NamedResource &other) const
{
return glslNameId == other.glslNameId &&
- texId == other.texId &&
- uniformArrayIndex == other.uniformArrayIndex;
+ nodeId == other.nodeId &&
+ uniformArrayIndex == other.uniformArrayIndex &&
+ type == other.type;
}
- bool operator!=(const NamedTexture &other) const
+ bool operator!=(const NamedResource &other) const
{
return !(*this == other);
}
};
- inline QVector<NamedTexture> textures() const { return m_textures; }
+ inline QVector<NamedResource> textures() const { return m_textures; }
+ inline QVector<NamedResource> images() const { return m_images; }
inline QVector<BlockToUBO> uniformBuffers() const { return m_uniformBuffers; }
inline QVector<BlockToSSBO> shaderStorageBuffers() const { return m_shaderStorageBuffers; }
inline QVector<ShaderUniform> submissionUniforms() const { return m_submissionUniforms; }
private:
PackUniformHash m_uniforms;
- QVector<NamedTexture> m_textures;
+ QVector<NamedResource> m_textures;
+ QVector<NamedResource> m_images;
QVector<BlockToUBO> m_uniformBuffers;
QVector<BlockToSSBO> m_shaderStorageBuffers;
QVector<ShaderUniform> m_submissionUniforms;
friend class RenderView;
};
-QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, ShaderParameterPack::NamedTexture, Q_PRIMITIVE_TYPE)
+QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, ShaderParameterPack::NamedResource, Q_PRIMITIVE_TYPE)
} // namespace Render
} // namespace Qt3DRender