summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2019-06-03 10:53:54 +0200
committerPaul Lemire <paul.lemire@kdab.com>2019-06-05 10:30:06 +0200
commit361dfd809c3984e0b561b1a60a75beb188d42165 (patch)
tree6796f611cd42d030d3bc8487f66e6bf6803b8b35
parent6eca6eb123588fab5db7a74718f81575f6b2220b (diff)
Add QShaderImage frontend class
Will allow to use GL Image with shaders for read/write operations Change-Id: Ib08068d982a523bb84d9897c32ece237452f8d2c Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r--src/render/materialsystem/materialsystem.pri3
-rw-r--r--src/render/materialsystem/qshaderimage.cpp984
-rw-r--r--src/render/materialsystem/qshaderimage.h170
-rw-r--r--src/render/materialsystem/qshaderimage_p.h82
-rw-r--r--tests/auto/render/qshaderimage/qshaderimage.pro12
-rw-r--r--tests/auto/render/qshaderimage/tst_qshaderimage.cpp495
-rw-r--r--tests/auto/render/render.pro3
7 files changed, 1748 insertions, 1 deletions
diff --git a/src/render/materialsystem/materialsystem.pri b/src/render/materialsystem/materialsystem.pri
index c464d6b99..5aa36d615 100644
--- a/src/render/materialsystem/materialsystem.pri
+++ b/src/render/materialsystem/materialsystem.pri
@@ -17,6 +17,8 @@ HEADERS += \
$$PWD/qrenderpass.h \
$$PWD/qshaderdata.h \
$$PWD/qshaderdata_p.h \
+ $$PWD/qshaderimage.h \
+ $$PWD/qshaderimage_p.h \
$$PWD/qshaderprogram.h \
$$PWD/qshaderprogram_p.h \
$$PWD/qshaderprogrambuilder.h \
@@ -44,6 +46,7 @@ SOURCES += \
$$PWD/qparameter.cpp \
$$PWD/qrenderpass.cpp \
$$PWD/qshaderdata.cpp \
+ $$PWD/qshaderimage.cpp \
$$PWD/qshaderprogram.cpp \
$$PWD/qshaderprogrambuilder.cpp \
$$PWD/qtechnique.cpp \
diff --git a/src/render/materialsystem/qshaderimage.cpp b/src/render/materialsystem/qshaderimage.cpp
new file mode 100644
index 000000000..868780789
--- /dev/null
+++ b/src/render/materialsystem/qshaderimage.cpp
@@ -0,0 +1,984 @@
+/****************************************************************************
+**
+** 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 "qshaderimage.h"
+#include "qshaderimage_p.h"
+#include <Qt3DRender/qabstracttexture.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+QShaderImagePrivate::QShaderImagePrivate()
+ : Qt3DCore::QNodePrivate()
+ , m_texture(nullptr)
+ , m_mipLevel(0)
+ , m_layer(0)
+ , m_access(QShaderImage::ReadWrite)
+ , m_format(QShaderImage::Automatic)
+ , m_layered(false)
+{
+}
+
+QShaderImagePrivate::~QShaderImagePrivate()
+{
+}
+
+/*!
+ \qmltype ShaderImage
+ \instantiates Qt3DRender::QShaderImage
+ \inqmlmodule Qt3D.Render
+ \since 5.14
+ \brief Provides Image access to shader programs
+
+ To make the content of textures available for read and write operations in
+ a shader, they need to exposed as ShaderImage. Textures can be composed of
+ several mip levels, layers and faces. Additionally declaring a ShaderImage
+ allows specifying which level, layer or face of the texture content we want
+ to access.
+
+ ShaderImage has to be assigned as a Parameter's value and reference a valid
+ Qt3D.Render.AbstractTexture to work properly.
+
+ If the referenced texture is a one-dimensional array, two-dimensional array,
+ three-dimensional, cube map, cube map array, or two-dimensional multisample
+ array texture, it is possible to bind either the entire texture level or a
+ single layer or face of the texture level. This can be controlled with the
+ \l layered property.
+
+ Support for ShaderImage is only supported with OpenGL 4 and partially with
+ OpenGL ES 3.1 and 3.2.
+
+ OpenGL 4 supports the following image types:
+ \table
+ \header
+ \li GLSL Type
+ \li OpenGL Type Enum
+ \li Texture Type
+ \row
+ \li image1D
+ \li GL_IMAGE_1D
+ \li Texture1D
+ \row
+ \li image2D
+ \li GL_IMAGE_2D
+ \li Texture2D
+ \row
+ \li image3D
+ \li GL_IMAGE_3D
+ \li Texture3D
+ \row
+ \li image2DRect
+ \li GL_IMAGE_2D_RECT
+ \li TextureRectangle
+ \row
+ \li imageCube
+ \li GL_IMAGE_CUBE
+ \li TextureCubeMap
+ \row
+ \li imageBuffer
+ \li GL_IMAGE_BUFFER
+ \li TextureBuffer
+ \row
+ \li image1DArray
+ \li GL_IMAGE_1D_ARRAY
+ \li Texture1DArray
+ \row
+ \li image2DArray
+ \li GL_IMAGE_2D_ARRAY
+ \li Texture2DArray
+ \row
+ \li imageCubeArray
+ \li GL_IMAGE_CUBE_MAP_ARRAY
+ \li TextureCubeMapArray
+ \row
+ \li image2DMS
+ \li GL_IMAGE_2D_MULTISAMPLE
+ \li Texture2DMultisample
+ \row
+ \li image2DMSArray
+ \li GL_IMAGE_2D_MULTISAMPLE_ARRAY
+ \li Texture2DMultisampleArray
+ \row
+ \li iimage1D
+ \li GL_INT_IMAGE_1D
+ \li Texture1D
+ \row
+ \li iimage2D
+ \li GL_INT_IMAGE_2D
+ \li Texture2D
+ \row
+ \li iimage3D
+ \li GL_INT_IMAGE_3D
+ \li Texture3D
+ \row
+ \li iimage2DRect
+ \li GL_INT_IMAGE_2D_RECT
+ \li TextureRectangle
+ \row
+ \li iimageCube
+ \li GL_INT_IMAGE_CUBE
+ \li TextureCubeMap
+ \row
+ \li iimageBuffer
+ \li GL_INT_IMAGE_BUFFER
+ \li TextureBuffer
+ \row
+ \li iimage1DArray
+ \li GL_INT_IMAGE_1D_ARRAY
+ \li Texture1DArray
+ \row
+ \li iimage2DArray
+ \li GL_INT_IMAGE_2D_ARRAY
+ \li Texture2DArray
+ \row
+ \li iimageCubeArray
+ \li GL_INT_IMAGE_CUBE_MAP_ARRAY
+ \li TextureCubeMapArray
+ \row
+ \li iimage2DMS
+ \li GL_INT_IMAGE_2D_MULTISAMPLE
+ \li Texture2DMultisample
+ \row
+ \li iimage2DMSArray
+ \li GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY
+ \li Texture2DMultisampleArray
+ \row
+ \li uimage1D
+ \li GL_UNSIGNED_INT_IMAGE_1D
+ \li Texture1D
+ \row
+ \li uimage2D
+ \li GL_UNSIGNED_INT_IMAGE_2D
+ \li Texture2D
+ \row
+ \li uimage3D
+ \li GL_UNSIGNED_INT_IMAGE_3D
+ \li Texture3D
+ \row
+ \li uimage2DRect
+ \li GL_UNSIGNED_INT_IMAGE_2D_RECT
+ \li TextureRectangle
+ \row
+ \li uimageCube
+ \li GL_UNSIGNED_INT_IMAGE_CUBE
+ \li TextureCubeMap
+ \row
+ \li uimageBuffer
+ \li GL_UNSIGNED_INT_IMAGE_BUFFER
+ \li TextureBuffer
+ \row
+ \li uimage1DArray
+ \li GL_UNSIGNED_INT_IMAGE_1D_ARRAY
+ \li Texture1DArray
+ \row
+ \li uimage2DArray
+ \li GL_UNSIGNED_INT_IMAGE_2D_ARRAY
+ \li Texture2DArray
+ \row
+ \li uimageCubeArray
+ \li GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY
+ \li TextureCubeMapArray
+ \row
+ \li uimage2DMS
+ \li GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE
+ \li Texture2DMultisample
+ \row
+ \li uimage2DMSArray
+ \li GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY
+ \li Texture2DMultisampleArray
+ \endtable
+
+ OpenGL ES 3.1 supports the following image types:
+ \table
+ \header
+ \li GLSL Type
+ \li OpenGL Type Enum
+ \li Texture Type
+ \row
+ \li image2D
+ \li GL_IMAGE_2D
+ \li Texture2D
+ \row
+ \li image3D
+ \li GL_IMAGE_3D
+ \li Texture3D
+ \row
+ \li imageCube
+ \li GL_IMAGE_CUBE
+ \li TextureCubeMap
+ \row
+ \li image2DArray
+ \li GL_IMAGE_2D_ARRAY
+ \li Texture2DArray
+ \row
+ \li iimage2D
+ \li GL_INT_IMAGE_2D
+ \li Texture2D
+ \row
+ \li iimage3D
+ \li GL_INT_IMAGE_3D
+ \li Texture3D
+ \row
+ \li iimageCube
+ \li GL_INT_IMAGE_CUBE
+ \li TextureCubeMap
+ \row
+ \li iimage2DArray
+ \li GL_INT_IMAGE_2D_ARRAY
+ \li Texture2DArray
+ \row
+ \li uimage2D
+ \li GL_UNSIGNED_INT_IMAGE_2D
+ \li Texture2D
+ \row
+ \li uimage3D
+ \li GL_UNSIGNED_INT_IMAGE_3D
+ \li Texture3D
+ \row
+ \li uimageCube
+ \li GL_UNSIGNED_INT_IMAGE_CUBE
+ \li TextureCubeMap
+ \row
+ \li uimage2DArray
+ \li GL_UNSIGNED_INT_IMAGE_2D_ARRAY
+ \li Texture2DArray
+ \endtable
+
+ OpenGL ES 3.2 supports all of the OpenGL ES 3.1 image types as well as the
+ following:
+ \table
+ \header
+ \li GLSL Type
+ \li OpenGL Type Enum
+ \li Texture Type
+ \row
+ \li imageBuffer
+ \li GL_IMAGE_BUFFER
+ \li TextureBuffer
+ \row
+ \li imageCubeArray
+ \li GL_IMAGE_CUBE_MAP_ARRAY
+ \li TextureCubeMapArray
+ \row
+ \li iimageBuffer
+ \li GL_IMAGE_BUFFER
+ \li TextureBuffer
+ \row
+ \li iimageCubeArray
+ \li GL_INT_IMAGE_CUBE_MAP_ARRAY
+ \li TextureCubeMapArray
+ \row
+ \li uimageBuffer
+ \li GL_UNSIGNED_INT_IMAGE_BUFFER
+ \li TextureBuffer
+ \row
+ \li uimageCubeArray
+ \li GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY
+ \li TextureCubeMapArray
+ \endlist
+
+ Expected use would look like:
+
+ \badcode
+
+ import Qt3D.Render 2.14
+
+ Entity {
+ ...
+ Texture2D {
+ id: tex2D
+ ...
+ }
+
+ Material {
+ parameters: Parameter {
+ name: "imageUniformName"
+ value: ShaderImage {
+ texture: tex2D
+ }
+ }
+ ...
+ }
+ ...
+ }
+ \endcode
+ */
+
+/*!
+ \qmlproperty Qt3DRender::QShaderImage::mipLevel
+
+ Holds which mipLevel out of the referenced texture should be used for the
+ ShaderImage.
+
+ \default 0
+ */
+
+/*!
+ \qmlproperty Qt3DRender::QShaderImage::layer
+
+ Holds which layer out of the referenced texture should be used for the
+ ShaderImage. This property does nothing if \a layered is set to true or if
+ the reference texture's type isn't compatible with layers.
+
+ \note When the referenced texture is of type cube map or cube map array and
+ \a ĺayered is set to false, the face and layer are retrieved in the
+ following manner:
+ \badcode
+ cubeMapLayer = layer / 6
+ cubeMapFace = layer - (cubeMapLayer * 6)
+ \endcode
+
+ \default 0
+ */
+
+/*!
+ * \qmlproperty Qt3DRender::QShaderImage::layered
+
+ If set to true, if the referenced texture is a one-dimensional array,
+ two-dimensional array, three-dimensional, cube map, cube map array, or
+ two-dimensional multisample array texture, the entire level will be bound
+ for all layers. If set to false, only the single layer specified by the \a
+ layer property will be bound.
+
+ \default false
+ */
+
+/*!
+ \qmlproperty Qt3DRender::QShaderImage::access
+
+ Specifies the type of access we want to allow from our shader instances to
+ the image. If a shader tries to write or read from an image that has
+ incompatible access, the behavior is undefined.
+
+ \default ShaderImage.ReadWrite
+ */
+
+/*!
+ \qmlproperty Qt3DRender::QShaderImage::format
+
+ Specifies the image format, which is essentially important when storing values
+ in the ShaderImage from a shader.
+
+ The format doesn't have to be the same as the referenced texture's format.
+ It however has to be compatible (matching in size but not necessarily by
+ class type). For instance a texture of format R32F (size 32bits, class
+ 1x32) could be used with an image of format RGBA8I (size 32bits, class
+ 4x8). Table 8.27 of the \l {OpenG specifications}
+ {https://www.khronos.org/registry/OpenGL/specs/gl/glspec45.core.pdf}
+ shows the size and class for all supported image formats.
+
+ By default Qt3D will try to set the image format to match that of the
+ referenced texture.
+
+ \default ShaderImage.Automatic
+ */
+
+/*!
+ \class Qt3DRender::QShaderImage
+ \inmodule Qt3DRender
+ \since 5.14
+ \brief Provides Image access to shader programs
+
+ To make the content of textures available for read and write operations in
+ a shader, they need to exposed as QShaderImage. Textures can be composed of
+ several mip levels, layers and faces. Additionally declaring a QShaderImage
+ allows specifying which level, layer or face of the texture content we want
+ to access.
+
+ QShaderImage has to be assigned as a QParameter's value and reference a valid
+ Qt3DRender::QAbstractTexture to work properly.
+
+ If the referenced texture is a one-dimensional array, two-dimensional array,
+ three-dimensional, cube map, cube map array, or two-dimensional multisample
+ array texture, it is possible to bind either the entire texture level or a
+ single layer or face of the texture level. This can be controlled with the
+ \l layered property.
+
+ Support for QShaderImage is only supported with OpenGL 4 and partially with
+ OpenGL ES 3.1 and 3.2.
+
+ OpenGL 4 supports the following image types:
+ \table
+ \header
+ \li GLSL Type
+ \li OpenGL Type Enum
+ \li Texture Type
+ \row
+ \li image1D
+ \li GL_IMAGE_1D
+ \li QTexture1D
+ \row
+ \li image2D
+ \li GL_IMAGE_2D
+ \li QTexture2D
+ \row
+ \li image3D
+ \li GL_IMAGE_3D
+ \li QTexture3D
+ \row
+ \li image2DRect
+ \li GL_IMAGE_2D_RECT
+ \li QTextureRectangle
+ \row
+ \li imageCube
+ \li GL_IMAGE_CUBE
+ \li QTextureCubeMap
+ \row
+ \li imageBuffer
+ \li GL_IMAGE_BUFFER
+ \li QTextureBuffer
+ \row
+ \li image1DArray
+ \li GL_IMAGE_1D_ARRAY
+ \li QTexture1DArray
+ \row
+ \li image2DArray
+ \li GL_IMAGE_2D_ARRAY
+ \li QTexture2DArray
+ \row
+ \li imageCubeArray
+ \li GL_IMAGE_CUBE_MAP_ARRAY
+ \li QTextureCubeMapArray
+ \row
+ \li image2DMS
+ \li GL_IMAGE_2D_MULTISAMPLE
+ \li QTexture2DMultisample
+ \row
+ \li image2DMSArray
+ \li GL_IMAGE_2D_MULTISAMPLE_ARRAY
+ \li QTexture2DMultisampleArray
+ \row
+ \li iimage1D
+ \li GL_INT_IMAGE_1D
+ \li QTexture1D
+ \row
+ \li iimage2D
+ \li GL_INT_IMAGE_2D
+ \li QTexture2D
+ \row
+ \li iimage3D
+ \li GL_INT_IMAGE_3D
+ \li QTexture3D
+ \row
+ \li iimage2DRect
+ \li GL_INT_IMAGE_2D_RECT
+ \li QTextureRectangle
+ \row
+ \li iimageCube
+ \li GL_INT_IMAGE_CUBE
+ \li QTextureCubeMap
+ \row
+ \li iimageBuffer
+ \li GL_INT_IMAGE_BUFFER
+ \li QTextureBuffer
+ \row
+ \li iimage1DArray
+ \li GL_INT_IMAGE_1D_ARRAY
+ \li QTexture1DArray
+ \row
+ \li iimage2DArray
+ \li GL_INT_IMAGE_2D_ARRAY
+ \li QTexture2DArray
+ \row
+ \li iimageCubeArray
+ \li GL_INT_IMAGE_CUBE_MAP_ARRAY
+ \li QTextureCubeMapArray
+ \row
+ \li iimage2DMS
+ \li GL_INT_IMAGE_2D_MULTISAMPLE
+ \li QTexture2DMultisample
+ \row
+ \li iimage2DMSArray
+ \li GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY
+ \li QTexture2DMultisampleArray
+ \row
+ \li uimage1D
+ \li GL_UNSIGNED_INT_IMAGE_1D
+ \li QTexture1D
+ \row
+ \li uimage2D
+ \li GL_UNSIGNED_INT_IMAGE_2D
+ \li QTexture2D
+ \row
+ \li uimage3D
+ \li GL_UNSIGNED_INT_IMAGE_3D
+ \li QTexture3D
+ \row
+ \li uimage2DRect
+ \li GL_UNSIGNED_INT_IMAGE_2D_RECT
+ \li QTextureRectangle
+ \row
+ \li uimageCube
+ \li GL_UNSIGNED_INT_IMAGE_CUBE
+ \li QTextureCubeMap
+ \row
+ \li uimageBuffer
+ \li GL_UNSIGNED_INT_IMAGE_BUFFER
+ \li QTextureBuffer
+ \row
+ \li uimage1DArray
+ \li GL_UNSIGNED_INT_IMAGE_1D_ARRAY
+ \li QTexture1DArray
+ \row
+ \li uimage2DArray
+ \li GL_UNSIGNED_INT_IMAGE_2D_ARRAY
+ \li QTexture2DArray
+ \row
+ \li uimageCubeArray
+ \li GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY
+ \li QTextureCubeMapArray
+ \row
+ \li uimage2DMS
+ \li GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE
+ \li QTexture2DMultisample
+ \row
+ \li uimage2DMSArray
+ \li GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY
+ \li QTexture2DMultisampleArray
+ \endtable
+
+ OpenGL ES 3.1 supports the following image types:
+ \table
+ \header
+ \li GLSL Type
+ \li OpenGL Type Enum
+ \li Texture Type
+ \row
+ \li image2D
+ \li GL_IMAGE_2D
+ \li QTexture2D
+ \row
+ \li image3D
+ \li GL_IMAGE_3D
+ \li QTexture3D
+ \row
+ \li imageCube
+ \li GL_IMAGE_CUBE
+ \li QTextureCubeMap
+ \row
+ \li image2DArray
+ \li GL_IMAGE_2D_ARRAY
+ \li QTexture2DArray
+ \row
+ \li iimage2D
+ \li GL_INT_IMAGE_2D
+ \li QTexture2D
+ \row
+ \li iimage3D
+ \li GL_INT_IMAGE_3D
+ \li QTexture3D
+ \row
+ \li iimageCube
+ \li GL_INT_IMAGE_CUBE
+ \li QTextureCubeMap
+ \row
+ \li iimage2DArray
+ \li GL_INT_IMAGE_2D_ARRAY
+ \li QTexture2DArray
+ \row
+ \li uimage2D
+ \li GL_UNSIGNED_INT_IMAGE_2D
+ \li QTexture2D
+ \row
+ \li uimage3D
+ \li GL_UNSIGNED_INT_IMAGE_3D
+ \li QTexture3D
+ \row
+ \li uimageCube
+ \li GL_UNSIGNED_INT_IMAGE_CUBE
+ \li QTextureCubeMap
+ \row
+ \li uimage2DArray
+ \li GL_UNSIGNED_INT_IMAGE_2D_ARRAY
+ \li QTexture2DArray
+ \endtable
+
+ OpenGL ES 3.2 supports all of the OpenGL ES 3.1 image types as well as the
+ following:
+ \table
+ \header
+ \li GLSL Type
+ \li OpenGL Type Enum
+ \li Texture Type
+ \row
+ \li imageBuffer
+ \li GL_IMAGE_BUFFER
+ \li QTextureBuffer
+ \row
+ \li imageCubeArray
+ \li GL_IMAGE_CUBE_MAP_ARRAY
+ \li QTextureCubeMapArray
+ \row
+ \li iimageBuffer
+ \li GL_IMAGE_BUFFER
+ \li QTextureBuffer
+ \row
+ \li iimageCubeArray
+ \li GL_INT_IMAGE_CUBE_MAP_ARRAY
+ \li QTextureCubeMapArray
+ \row
+ \li uimageBuffer
+ \li GL_UNSIGNED_INT_IMAGE_BUFFER
+ \li QTextureBuffer
+ \row
+ \li uimageCubeArray
+ \li GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY
+ \li QTextureCubeMapArray
+ \endlist
+
+ Expected use would look like:
+
+ \badcode
+ Qt3DRender::QTexture2D *tex2D = new Qt3DRender::QTexture2D();
+ ...
+ Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial();
+ ...
+ Qt3DRender::QParameter *imageParameter = new Qt3DRender::QParameter();
+ Qt3DRender::QShaderImage *shaderImage = new Qt3DRender::QShaderImage();
+
+ shaderImage->setTexture(tex2D);
+
+ imageParameter->setName("imageUniformName");
+ imageParameter->setValue(QVariant::fromValue(shaderImage));
+
+ material->addParameter(imageParamenter);
+ \endcode
+ */
+
+/*!
+ \property Qt3DRender::QShaderImage::mipLevel
+
+ Holds which mipLevel out of the referenced texture should be used for the
+ QShaderImage.
+
+ \default 0
+ */
+
+/*!
+ \property Qt3DRender::QShaderImage::layer
+
+ Holds which layer out of the referenced texture should be used for the
+ QShaderImage. This property does nothing if \a layered is set to true or if the
+ reference texture's type isn't compatible with layers.
+
+ \note When the referenced texture is of type cube map or cube map array and
+ \a ĺayered is set to false, the face and layer are retrieved in the
+ following manner:
+ \badcode
+ cubeMapLayer = layer / 6
+ cubeMapFace = layer - (cubeMapLayer * 6)
+ \endcode
+
+ \default 0
+ */
+
+/*!
+ * \property Qt3DRender::QShaderImage::layered
+
+ If set to true, if the referenced texture is a one-dimensional array,
+ two-dimensional array, three-dimensional, cube map, cube map array, or
+ two-dimensional multisample array texture, the entire level will be bound
+ for all layers. If set to false, only the single layer specified by the \a
+ layer property will be bound.
+
+ \default false
+ */
+
+/*!
+ \property Qt3DRender::QShaderImage::access
+
+ Specifies the type of access we want to allow from our shader instances to
+ the image. If a shader tries to write or read from an image that has
+ incompatible access, the behavior is undefined.
+
+ \defaut QShaderImage::ReadWrite
+ */
+
+/*!
+ \property Qt3DRender::QShaderImage::format
+
+ Specifies the image format, which is essentially important when storing values
+ in the Image from a shader.
+
+ The format doesn't have to be the same as the referenced texture's format.
+ It however has to be compatible (matching in size but not necessarily by
+ class type). For instance a texture of format R32F (size 32bits, class
+ 1x32) could be used with an image of format RGBA8I (size 32bits, class
+ 4x8). Table 8.27 of the \l {OpenG specifications}
+ {https://www.khronos.org/registry/OpenGL/specs/gl/glspec45.core.pdf}
+ shows the size and class for all supported Image formats.
+
+ By default Qt3D will try to set the image format to match that of the
+ referenced texture.
+
+ \default QShaderImage::Automatic
+ */
+
+/*!
+ \enum Qt3DRender::QShaderImage::Access
+
+ \value ReadOnly
+ Image will only be read from in shaders
+ \value WriteOnly
+ Image will only be written into from shaders
+ \value ReadWrite
+ Image will only be read and written into from shaders
+*/
+
+/*!
+ \enum Qt3DRender::QShaderImage::ImageFormat
+
+ This list describes all possible image formats
+
+ \value NoFormat
+ GL_NONE
+ \value Automatic
+ Qt 3D will try to determine the format automatically based on
+ the referenced texture.
+ \value R8_UNorm
+ GL_R8 (GLSL type r8, supported by OpenGL 4.2+)
+ \value RG8_UNorm
+ GL_RG8 (GLSL type rg8, supported by OpenGL 4.2+)
+ \value RGBA8_UNorm
+ GL_RGBA8 (GLSL type rgba8, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R16_UNorm
+ GL_R16 (GLSL type r16, supported by OpenGL 4.2+)
+ \value RG16_UNorm
+ GL_RG16 (GLSL type rg16, supported by OpenGL 4.2+)
+ \value RGBA16_UNorm
+ GL_RGBA16 (GLSL type rgba16, supported by OpenGL 4.2+)
+ \value R8_SNorm
+ GL_R8_SNORM (GLSL type r8_snorm, supported by OpenGL 4.2+)
+ \value RG8_SNorm
+ GL_RG8_SNORM (GLSL type rg8_snorm, supported by OpenGL 4.2+)
+ \value RGBA8_SNorm
+ GL_RGBA8_SNORM (GLSL type rgba8_snorm, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R16_SNorm
+ GL_R16_SNORM (GLSL type r16_snorm, supported by OpenGL 4.2+)
+ \value RG16_SNorm
+ GL_RG16_SNORM (GLSL type rg16_snorm, supported by OpenGL 4.2+)
+ \value RGBA16_SNorm
+ GL_RGBA16_SNORM (GLSL type rgba16_snorm, supported by OpenGL 4.2+)
+ \value R8U
+ GL_R8UI (GLSL type r8ui, supported by OpenGL 4.2+)
+ \value RG8U
+ GL_RG8UI (GLSL type rg8ui, supported by OpenGL 4.2+)
+ \value RGBA8U
+ GL_RGBA8UI (GLSL type rgba8ui, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R16U
+ GL_R16UI (GLSL type r16ui, supported by OpenGL 4.2+)
+ \value RG16U
+ GL_RG16UI (GLSL type rg16ui, supported by OpenGL 4.2+)
+ \value RGBA16U
+ GL_RGBA16UI (GLSL type rgba16ui, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R32U
+ GL_R32UI (GLSL type r32ui, supported by OpenGL 4.2+, OpenGL ES 3.1)
+ \value RG32U
+ GL_RG32UI (GLSL type rg32ui, supported by OpenGL 4.2+)
+ \value RGBA32U
+ GL_RGBA32UI (GLSL type rgba32ui, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R8I
+ GL_R8I (GLSL type r8i, supported by OpenGL 4.2+)
+ \value RG8I
+ GL_RG8I (GLSL type rg8i, supported by OpenGL 4.2+)
+ \value RGBA8I
+ GL_RGBA8I (GLSL type rgba8i, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R16I
+ GL_R16I (GLSL type r16i, supported by OpenGL 4.2+)
+ \value RG16I
+ GL_RG16I (GLSL type rg16i, supported by OpenGL 4.2+)
+ \value RGBA16I
+ GL_RGBA16I (GLSL type rgba16i, supported by OpenGL 4.2+, OpenGL ES 3.1)
+ \value R32I
+ GL_R32I (GLSL type r32i, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value RG32I
+ GL_RG32I (GLSL type rg32i, supported by OpenGL 4.2+)
+ \value RGBA32I
+ GL_RGBA32I (GLSL type rgba32i, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R16F
+ GL_R16F (GLSL type r16f, supported by OpenGL 4.2+)
+ \value RG16F
+ GL_RG16F (GLSL type rg16f, supported by OpenGL 4.2+)
+ \value RGBA16F
+ GL_RGBA16F (GLSL type rgba16f, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value R32F
+ GL_R32F (GLSL type r32f, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value RG32F
+ GL_RG32F (GLSL type rg32f, supported by OpenGL 4.2+)
+ \value RGBA32F
+ GL_RGBA32F (GLSL type rgba32f, supported by OpenGL 4.2+, OpenGL ES 3.1+)
+ \value RG11B10F
+ GL_R11F_G11F_B10F (GLSL type r11f_g11f_b10f, supported by OpenGL 4.2+)
+ \value RGB10A2
+ GL_RGB10_A2 (GLSL type rgb10_a2, supported by OpenGL 4.2+)
+ \value RGB10A2U
+ GL_RGB10_A2UI (GLSL type rgb10_a2ui, supported by OpenGL 4.2+)
+*/
+
+
+QShaderImage::QShaderImage(Qt3DCore::QNode *parent)
+ : Qt3DCore::QNode(*new QShaderImagePrivate, parent)
+{
+}
+
+QShaderImage::~QShaderImage()
+{
+
+}
+
+QAbstractTexture *QShaderImage::texture() const
+{
+ Q_D(const QShaderImage);
+ return d->m_texture;
+}
+
+bool QShaderImage::layered() const
+{
+ Q_D(const QShaderImage);
+ return d->m_layered;
+}
+
+int QShaderImage::mipLevel() const
+{
+ Q_D(const QShaderImage);
+ return d->m_mipLevel;
+}
+
+int QShaderImage::layer() const
+{
+ Q_D(const QShaderImage);
+ return d->m_layer;
+}
+
+QShaderImage::Access QShaderImage::access() const
+{
+ Q_D(const QShaderImage);
+ return d->m_access;
+}
+
+QShaderImage::ImageFormat QShaderImage::format() const
+{
+ Q_D(const QShaderImage);
+ return d->m_format;
+}
+
+void QShaderImage::setTexture(QAbstractTexture *texture)
+{
+ Q_D(QShaderImage);
+ if (texture == d->m_texture)
+ return;
+
+ if (d->m_texture)
+ d->unregisterDestructionHelper(d->m_texture);
+
+ if (texture && !texture->parent())
+ texture->setParent(this);
+
+ d->m_texture = texture;
+
+ if (d->m_texture)
+ d->registerDestructionHelper(d->m_texture, &QShaderImage::setTexture, d->m_texture);
+
+ Q_EMIT textureChanged(texture);
+}
+
+void QShaderImage::setLayered(bool layered)
+{
+ Q_D(QShaderImage);
+ if (layered == d->m_layered)
+ return;
+ d->m_layered = layered;
+ Q_EMIT layeredChanged(layered);
+}
+
+void QShaderImage::setMipLevel(int mipLevel)
+{
+ Q_D(QShaderImage);
+ if (mipLevel == d->m_mipLevel)
+ return;
+ d->m_mipLevel = mipLevel;
+ Q_EMIT mipLevelChanged(mipLevel);
+}
+
+void QShaderImage::setLayer(int layer)
+{
+ Q_D(QShaderImage);
+ if (layer == d->m_layer)
+ return;
+ d->m_layer = layer;
+ Q_EMIT layerChanged(layer);
+}
+
+void QShaderImage::setAccess(QShaderImage::Access access)
+{
+ Q_D(QShaderImage);
+ if (access == d->m_access)
+ return;
+ d->m_access = access;
+ Q_EMIT accessChanged(access);
+}
+
+void QShaderImage::setFormat(QShaderImage::ImageFormat format)
+{
+ Q_D(QShaderImage);
+ if (format == d->m_format)
+ return;
+ d->m_format = format;
+ Q_EMIT formatChanged(format);
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr Qt3DRender::QShaderImage::createNodeCreationChange() const
+{
+ auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QShaderImageData>::create(this);
+ QShaderImageData &data = creationChange->data;
+ Q_D(const QShaderImage);
+ data.textureId = Qt3DCore::qIdForNode(d->m_texture);
+ data.layer = d->m_layer;
+ data.mipLevel = d->m_mipLevel;
+ data.access = d->m_access;
+ data.format = d->m_format;
+ data.layered = d->m_layered;
+ return creationChange;
+
+}
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/materialsystem/qshaderimage.h b/src/render/materialsystem/qshaderimage.h
new file mode 100644
index 000000000..e1f5459d2
--- /dev/null
+++ b/src/render/materialsystem/qshaderimage.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** 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_QSHADERIMAGE_H
+#define QT3DRENDER_QSHADERIMAGE_H
+
+#include <Qt3DCore/qnode.h>
+#include <Qt3DRender/qt3drender_global.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QAbstractTexture;
+class QShaderImagePrivate;
+
+class Q_3DRENDERSHARED_EXPORT QShaderImage : public Qt3DCore::QNode
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DRender::QAbstractTexture *texture READ texture WRITE setTexture NOTIFY textureChanged)
+ Q_PROPERTY(bool layered READ layered WRITE setLayered NOTIFY layeredChanged)
+ Q_PROPERTY(int mipLevel READ mipLevel WRITE setMipLevel NOTIFY mipLevelChanged)
+ Q_PROPERTY(int layer READ layer WRITE setLayer NOTIFY layerChanged)
+ Q_PROPERTY(Access access READ access WRITE setAccess NOTIFY accessChanged)
+ Q_PROPERTY(ImageFormat format READ format WRITE setFormat NOTIFY formatChanged)
+
+public:
+ enum Access {
+ ReadOnly = 0,
+ WriteOnly,
+ ReadWrite
+ };
+ Q_ENUM(Access)
+
+ enum ImageFormat {
+ NoFormat = 0, // GL_NONE
+ Automatic = 1, // The Qt3D engine automatically determines the best format
+
+ // Unsigned normalized formats
+ R8_UNorm = 0x8229, // GL_R8
+ RG8_UNorm = 0x822B, // GL_RG8
+ RGBA8_UNorm = 0x8058, // GL_RGBA8
+
+ R16_UNorm = 0x822A, // GL_R16
+ RG16_UNorm = 0x822C, // GL_RG16
+ RGBA16_UNorm = 0x805B, // GL_RGBA16
+
+ // Signed normalized formats
+ R8_SNorm = 0x8F94, // GL_R8_SNORM
+ RG8_SNorm = 0x8F95, // GL_RG8_SNORM
+ RGBA8_SNorm = 0x8F97, // GL_RGBA8_SNORM
+
+ R16_SNorm = 0x8F98, // GL_R16_SNORM
+ RG16_SNorm = 0x8F99, // GL_RG16_SNORM
+ RGBA16_SNorm = 0x8F9B, // GL_RGBA16_SNORM
+
+ // Unsigned integer formats
+ R8U = 0x8232, // GL_R8UI
+ RG8U = 0x8238, // GL_RG8UI
+ RGBA8U = 0x8D7C, // GL_RGBA8UI
+
+ R16U = 0x8234, // GL_R16UI
+ RG16U = 0x823A, // GL_RG16UI
+ RGBA16U = 0x8D76, // GL_RGBA16UI
+
+ R32U = 0x8236, // GL_R32UI
+ RG32U = 0x823C, // GL_RG32UI
+ RGBA32U = 0x8D70, // GL_RGBA32UI
+
+ // Signed integer formats
+ R8I = 0x8231, // GL_R8I
+ RG8I = 0x8237, // GL_RG8I
+ RGBA8I = 0x8D8E, // GL_RGBA8I
+
+ R16I = 0x8233, // GL_R16I
+ RG16I = 0x8239, // GL_RG16I
+ RGBA16I = 0x8D88, // GL_RGBA16I
+
+ R32I = 0x8235, // GL_R32I
+ RG32I = 0x823B, // GL_RG32I
+ RGBA32I = 0x8D82, // GL_RGBA32I
+
+ // Floating point formats
+ R16F = 0x822D, // GL_R16F
+ RG16F = 0x822F, // GL_RG16F
+ RGBA16F = 0x881A, // GL_RGBA16F
+
+ R32F = 0x822E, // GL_R32F
+ RG32F = 0x8230, // GL_RG32F
+ RGBA32F = 0x8814, // GL_RGBA32F
+
+ // Packed formats
+ RG11B10F = 0x8C3A, // GL_R11F_G11F_B10F
+ RGB10A2 = 0x8059, // GL_RGB10_A2
+ RGB10A2U = 0x906F, // GL_RGB10_A2_UI
+ };
+ Q_ENUM(ImageFormat)
+
+ explicit QShaderImage(Qt3DCore::QNode *parent = nullptr);
+ ~QShaderImage();
+
+ Qt3DRender::QAbstractTexture *texture() const;
+ bool layered() const;
+ int mipLevel() const;
+ int layer() const;
+ Access access() const;
+ ImageFormat format() const;
+
+public Q_SLOTS:
+ void setTexture(Qt3DRender::QAbstractTexture *texture);
+ void setLayered(bool layered);
+ void setMipLevel(int mipLevel);
+ void setLayer(int layer);
+ void setAccess(Access access);
+ void setFormat(ImageFormat format);
+
+Q_SIGNALS:
+ void textureChanged(Qt3DRender::QAbstractTexture *texture);
+ void layeredChanged(bool layered);
+ void mipLevelChanged(int mipLevel);
+ void layerChanged(int layer);
+ void accessChanged(Access access);
+ void formatChanged(ImageFormat format);
+
+private:
+ Q_DECLARE_PRIVATE(QShaderImage)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const override;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QSHADERIMAGE_H
diff --git a/src/render/materialsystem/qshaderimage_p.h b/src/render/materialsystem/qshaderimage_p.h
new file mode 100644
index 000000000..93eb8635d
--- /dev/null
+++ b/src/render/materialsystem/qshaderimage_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** 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_QSHADERIMAGE_P_H
+#define QT3DRENDER_QSHADERIMAGE_P_H
+
+#include <Qt3DCore/private/qnode_p.h>
+#include <Qt3DRender/qshaderimage.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QAbstractTexture;
+
+class QShaderImagePrivate : public Qt3DCore::QNodePrivate
+{
+public:
+ QShaderImagePrivate();
+ ~QShaderImagePrivate();
+
+ Q_DECLARE_PUBLIC(QShaderImage)
+
+ Qt3DRender::QAbstractTexture *m_texture;
+ int m_mipLevel;
+ int m_layer;
+ QShaderImage::Access m_access;
+ QShaderImage::ImageFormat m_format;
+ bool m_layered;
+};
+
+struct QShaderImageData
+{
+ Qt3DCore::QNodeId textureId;
+ int mipLevel;
+ int layer;
+ QShaderImage::Access access;
+ QShaderImage::ImageFormat format;
+ bool layered;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QSHADERIMAGE_P_H
diff --git a/tests/auto/render/qshaderimage/qshaderimage.pro b/tests/auto/render/qshaderimage/qshaderimage.pro
new file mode 100644
index 000000000..1990b9732
--- /dev/null
+++ b/tests/auto/render/qshaderimage/qshaderimage.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qshaderimage
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qshaderimage.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qshaderimage/tst_qshaderimage.cpp b/tests/auto/render/qshaderimage/tst_qshaderimage.cpp
new file mode 100644
index 000000000..0a12e806f
--- /dev/null
+++ b/tests/auto/render/qshaderimage/tst_qshaderimage.cpp
@@ -0,0 +1,495 @@
+/****************************************************************************
+**
+** 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 <QtTest/QTest>
+#include <Qt3DRender/qshaderimage.h>
+#include <Qt3DRender/qtexture.h>
+#include <Qt3DRender/private/qshaderimage_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
+
+class tst_QShaderImage : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void initTestCase()
+ {
+ qRegisterMetaType<Qt3DRender::QAbstractTexture*>("Qt3DRender::QAbstractTexture*");
+
+ }
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QShaderImage shaderImage;
+
+ // THEN
+ QVERIFY(shaderImage.texture() == nullptr);
+ QCOMPARE(shaderImage.layered(), false);
+ QCOMPARE(shaderImage.mipLevel(), 0);
+ QCOMPARE(shaderImage.layer(), 0);
+ QCOMPARE(shaderImage.access(), Qt3DRender::QShaderImage::ReadWrite);
+ QCOMPARE(shaderImage.format(), Qt3DRender::QShaderImage::Automatic);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QShaderImage shaderImage;
+
+ {
+ // WHEN
+ QSignalSpy spy(&shaderImage, SIGNAL(textureChanged(Qt3DRender::QAbstractTexture *)));
+ Qt3DRender::QTexture2D newValue;
+ shaderImage.setTexture(&newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(shaderImage.texture(), &newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ shaderImage.setTexture(&newValue);
+
+ // THEN
+ QCOMPARE(shaderImage.texture(), &newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&shaderImage, SIGNAL(layeredChanged(bool)));
+ const bool newValue = true;
+ shaderImage.setLayered(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(shaderImage.layered(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ shaderImage.setLayered(newValue);
+
+ // THEN
+ QCOMPARE(shaderImage.layered(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&shaderImage, SIGNAL(mipLevelChanged(int)));
+ const int newValue = 12;
+ shaderImage.setMipLevel(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(shaderImage.mipLevel(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ shaderImage.setMipLevel(newValue);
+
+ // THEN
+ QCOMPARE(shaderImage.mipLevel(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&shaderImage, SIGNAL(layerChanged(int)));
+ const int newValue = 2;
+ shaderImage.setLayer(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(shaderImage.layer(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ shaderImage.setLayer(newValue);
+
+ // THEN
+ QCOMPARE(shaderImage.layer(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&shaderImage, SIGNAL(accessChanged(Access)));
+ const Qt3DRender::QShaderImage::Access newValue = Qt3DRender::QShaderImage::ReadOnly;
+ shaderImage.setAccess(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(shaderImage.access(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ shaderImage.setAccess(newValue);
+
+ // THEN
+ QCOMPARE(shaderImage.access(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&shaderImage, SIGNAL(formatChanged(ImageFormat)));
+ const Qt3DRender::QShaderImage::ImageFormat newValue = Qt3DRender::QShaderImage::RG8U;
+ shaderImage.setFormat(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(shaderImage.format(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ shaderImage.setFormat(newValue);
+
+ // THEN
+ QCOMPARE(shaderImage.format(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QShaderImage shaderImage;
+ Qt3DRender::QTexture2D t;
+
+ shaderImage.setTexture(&t);
+ shaderImage.setLayered(true);
+ shaderImage.setMipLevel(883);
+ shaderImage.setLayer(1584);
+ shaderImage.setAccess(Qt3DRender::QShaderImage::WriteOnly);
+ shaderImage.setFormat(Qt3DRender::QShaderImage::R32F);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&shaderImage);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ // ShaderImage + Texture creation
+ QCOMPARE(creationChanges.size(), 2);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QShaderImageData>>(creationChanges.first());
+ const Qt3DRender::QShaderImageData cloneData = creationChangeData->data;
+
+ QCOMPARE(shaderImage.texture()->id(), cloneData.textureId);
+ QCOMPARE(shaderImage.layered(), cloneData.layered);
+ QCOMPARE(shaderImage.mipLevel(), cloneData.mipLevel);
+ QCOMPARE(shaderImage.layer(), cloneData.layer);
+ QCOMPARE(shaderImage.access(), cloneData.access);
+ QCOMPARE(shaderImage.format(), cloneData.format);
+ QCOMPARE(shaderImage.id(), creationChangeData->subjectId());
+ QCOMPARE(shaderImage.isEnabled(), true);
+ QCOMPARE(shaderImage.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(shaderImage.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ shaderImage.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&shaderImage);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ // ShaderImage + Texture creation
+ QCOMPARE(creationChanges.size(), 2);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QShaderImageData>>(creationChanges.first());
+ const Qt3DRender::QShaderImageData cloneData = creationChangeData->data;
+
+ QCOMPARE(shaderImage.texture()->id(), cloneData.textureId);
+ QCOMPARE(shaderImage.layered(), cloneData.layered);
+ QCOMPARE(shaderImage.mipLevel(), cloneData.mipLevel);
+ QCOMPARE(shaderImage.layer(), cloneData.layer);
+ QCOMPARE(shaderImage.access(), cloneData.access);
+ QCOMPARE(shaderImage.format(), cloneData.format);
+ QCOMPARE(shaderImage.id(), creationChangeData->subjectId());
+ QCOMPARE(shaderImage.isEnabled(), false);
+ QCOMPARE(shaderImage.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(shaderImage.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkTextureUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QShaderImage shaderImage;
+ arbiter.setArbiterOnNode(&shaderImage);
+ Qt3DRender::QTexture2D t;
+
+ {
+ // WHEN
+ shaderImage.setTexture(&t);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "texture");
+ QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), shaderImage.texture()->id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ shaderImage.setTexture(&t);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkLayeredUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QShaderImage shaderImage;
+ arbiter.setArbiterOnNode(&shaderImage);
+
+ {
+ // WHEN
+ shaderImage.setLayered(true);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "layered");
+ QCOMPARE(change->value().value<bool>(), shaderImage.layered());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ shaderImage.setLayered(true);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkMipLevelUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QShaderImage shaderImage;
+ arbiter.setArbiterOnNode(&shaderImage);
+
+ {
+ // WHEN
+ shaderImage.setMipLevel(5);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "mipLevel");
+ QCOMPARE(change->value().value<int>(), shaderImage.mipLevel());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ shaderImage.setMipLevel(5);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkLayerUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QShaderImage shaderImage;
+ arbiter.setArbiterOnNode(&shaderImage);
+
+ {
+ // WHEN
+ shaderImage.setLayer(8);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "layer");
+ QCOMPARE(change->value().value<int>(), shaderImage.layer());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ shaderImage.setLayer(8);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkAccessUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QShaderImage shaderImage;
+ arbiter.setArbiterOnNode(&shaderImage);
+
+ {
+ // WHEN
+ shaderImage.setAccess(Qt3DRender::QShaderImage::WriteOnly);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "access");
+ QCOMPARE(change->value().value<Qt3DRender::QShaderImage::Access>(), shaderImage.access());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ shaderImage.setAccess(Qt3DRender::QShaderImage::WriteOnly);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkFormatUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QShaderImage shaderImage;
+ arbiter.setArbiterOnNode(&shaderImage);
+
+ {
+ // WHEN
+ shaderImage.setFormat(Qt3DRender::QShaderImage::RG16F);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "format");
+ QCOMPARE(change->value().value<Qt3DRender::QShaderImage::ImageFormat>(), shaderImage.format());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ shaderImage.setFormat(Qt3DRender::QShaderImage::RG16F);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkTextureBookeeping()
+ {
+ // GIVEN
+ Qt3DRender::QShaderImage shaderImage;
+ QSignalSpy spy(&shaderImage, SIGNAL(textureChanged(Qt3DRender::QAbstractTexture *)));
+
+ {
+ // WHEN
+ Qt3DRender::QTexture2D tex;
+ shaderImage.setTexture(&tex);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(shaderImage.texture(), &tex);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ }
+ // THEN
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(shaderImage.texture() == nullptr);
+ }
+
+};
+
+QTEST_MAIN(tst_QShaderImage)
+
+#include "tst_qshaderimage.moc"
diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro
index ac1ef50dd..8c5c43483 100644
--- a/tests/auto/render/render.pro
+++ b/tests/auto/render/render.pro
@@ -103,7 +103,8 @@ qtConfig(private_tests) {
qwaitfence \
setfence \
waitfence \
- qtexturedataupdate
+ qtexturedataupdate \
+ qshaderimage
QT_FOR_CONFIG = 3dcore-private
# TO DO: These could be restored to be executed in all cases