diff options
Diffstat (limited to 'src/quick/scenegraph/coreapi/qsgmaterial.cpp')
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgmaterial.cpp | 200 |
1 files changed, 192 insertions, 8 deletions
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp index 9c7cbe4d8d..e2b240479e 100644 --- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp +++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp @@ -6,6 +6,8 @@ QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcQsgLeak) + #ifndef QT_NO_DEBUG bool qsg_material_failure = false; bool qsg_test_and_clear_material_failure() @@ -21,10 +23,6 @@ void qsg_set_material_failure() } #endif -#ifndef QT_NO_DEBUG -static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK"); -#endif - /*! \group qtquick-scenegraph-materials \title Qt Quick Scene Graph Material Classes @@ -39,7 +37,7 @@ static int qt_material_count = 0; static void qt_print_material_count() { - qDebug("Number of leaked materials: %i", qt_material_count); + qCDebug(lcQsgLeak, "Number of leaked materials: %i", qt_material_count); qt_material_count = -1; } #endif @@ -109,7 +107,7 @@ QSGMaterial::QSGMaterial() { Q_UNUSED(m_reserved); #ifndef QT_NO_DEBUG - if (qsg_leak_check) { + if (lcQsgLeak().isDebugEnabled()) { ++qt_material_count; static bool atexit_registered = false; if (!atexit_registered) { @@ -128,10 +126,10 @@ QSGMaterial::QSGMaterial() QSGMaterial::~QSGMaterial() { #ifndef QT_NO_DEBUG - if (qsg_leak_check) { + if (lcQsgLeak().isDebugEnabled()) { --qt_material_count; if (qt_material_count < 0) - qDebug("Material destroyed after qt_print_material_count() was called."); + qCDebug(lcQsgLeak, "Material destroyed after qt_print_material_count() was called."); } #endif } @@ -165,6 +163,10 @@ QSGMaterial::~QSGMaterial() \value CustomCompileStep In Qt 6 this flag is identical to NoBatching. Prefer using NoBatching instead. + + \omitvalue MultiView2 + \omitvalue MultiView3 + \omitvalue MultiView4 */ /*! @@ -249,4 +251,186 @@ int QSGMaterial::compare(const QSGMaterial *other) const RenderMode3D is in use. */ +/*! + \return The number of views in case of the material is used in multiview + rendering. + + \note The return value is valid only when called from createShader(), and + afterwards. The value is not necessarily up-to-date before createShader() + is invokved by the scene graph. + + Normally the return value is \c 1. A view count greater than 2 implies a + \e{multiview render pass}. Materials that support multiview are expected to + query viewCount() in createShader(), or in their QSGMaterialShader + constructor, and ensure the appropriate shaders are picked. The vertex + shader is then expected to use + \c{gl_ViewIndex} to index the modelview-projection matrix array as there + are multiple matrices in multiview mode. (one for each view) + + As an example, take the following simple vertex shader: + + \badcode + #version 440 + + layout(location = 0) in vec4 vertexCoord; + layout(location = 1) in vec4 vertexColor; + + layout(location = 0) out vec4 color; + + layout(std140, binding = 0) uniform buf { + mat4 matrix[2]; + float opacity; + }; + + void main() + { + gl_Position = matrix[gl_ViewIndex] * vertexCoord; + color = vertexColor * opacity; + } + \endcode + + This shader is prepared to handle 2 views, and 2 views only. It is not + compatible with other view counts. When conditioning the shader, the \c qsb + tool has to be invoked with \c{--view-count 2} or, if using the CMake + integration, + \c{VIEW_COUNT 2} must be specified in the \c{qt_add_shaders()} command. + + \note A line with \c{#extension GL_EXT_multiview : require} is injected + automatically by \c qsb whenever a view count of 2 or greater is set. + + Developers are encouraged to use the automatically injected preprocessor + variable \c{QSHADER_VIEW_COUNT} to simplify the handling of the different + number of views. For example, if there is a need to support both + non-multiview and multiview with a view count of 2 in the same source file, + the following could be done: + + \badcode + #version 440 + + layout(location = 0) in vec4 vertexCoord; + layout(location = 1) in vec4 vertexColor; + + layout(location = 0) out vec4 color; + + layout(std140, binding = 0) uniform buf { + #if QSHADER_VIEW_COUNT >= 2 + mat4 matrix[QSHADER_VIEW_COUNT]; + #else + mat4 matrix; + #endif + float opacity; + }; + + void main() + { + #if QSHADER_VIEW_COUNT >= 2 + gl_Position = matrix[gl_ViewIndex] * vertexCoord; + #else + gl_Position = matrix * vertexCoord; + #endif + color = vertexColor * opacity; + } + \endcode + + The same source file can now be run through \c qsb or \c{qt_add_shaders()} + twice, once without specify the view count, and once with the view count + set to 2. The material can then pick the appropriate .qsb file based on + viewCount() at run time. + + With CMake, this could looks similar to the following. With this example + the corresponding QSGMaterialShader is expected to choose between + \c{:/shaders/example.vert.qsb} and \c{:/shaders/multiview/example.vert.qsb} + based on the value of viewCount(). (same goes for the fragment shader) + + \badcode + qt_add_shaders(application "application_shaders" + PREFIX + / + FILES + shaders/example.vert + shaders/example.frag + ) + + qt_add_shaders(application "application_multiview_shaders" + GLSL + 330,300es + HLSL + 61 + MSL + 12 + VIEW_COUNT + 2 + PREFIX + / + FILES + shaders/example.vert + shaders/example.frag + OUTPUTS + shaders/multiview/example.vert + shaders/multiview/example.frag + ) + \endcode + + \note The fragment shader should be treated the same way the vertex shader + is, even though the fragment shader code cannot have any dependency on the + view count (\c{gl_ViewIndex}), for maximum portability. There are two + reasons for including fragment shaders too in the multiview set. One is that + mixing different shader versions within the same graphics pipeline can be + problematic, depending on the underlying graphics API: with D3D12 for + example, mixing HLSL shaders for shader model 5.0 and 6.1 would generate an + error. The other is that having \c QSHADER_VIEW_COUNT defined in fragment + shaders can be very useful, for example when sharing a uniform buffer layout + between the vertex and fragment stages. + + \note For OpenGL the minimum GLSL version for vertex shaders relying on + \c{gl_ViewIndex} is \c 330. Lower versions may be accepted at build time, + but may lead to an error at run time, depending on the OpenGL implementation. + + As a convenience, there is also a \c MULTIVIEW option for qt_add_shaders(). + This first runs the \c qsb tool normally, then overrides \c VIEW_COUNT to + \c 2, sets \c GLSL, \c HLSL, \c MSL to some suitable defaults, and runs \c + qsb again, this time outputting .qsb files with a suffix added. The material + implementation can then use the \l QSGMaterialShader::setShaderFileName() + overload taking a \c viewCount argument, that automatically picks the + correct .qsb file. + + The following is therefore mostly equivalent to the example call shown + above, except that no manually managed output files need to be specified. + Note that there can be cases when the automatically chosen shading language + versions are not sufficient, in which case applications should continue + specify everything explicitly. + + \badcode + qt_add_shaders(application "application_multiview_shaders" + MULTIVIEW + PREFIX + / + FILES + shaders/example.vert + shaders/example.frag + ) + \endcode + + See \l QRhi::MultiView, \l QRhiColorAttachment::setMultiViewCount(), and + \l QRhiGraphicsPipeline::setMultiViewCount() for further, lower-level details + on multiview support in Qt. The Qt Quick scene graph renderer is prepared to + recognize multiview render targets, when specified via \l + QQuickRenderTarget::fromRhiRenderTarget() or the 3D API specific functions, + such as \l{QQuickRenderTarget::}{fromVulkanImage()} with an \c arraySize + argument greater than 1. The renderer will then propagate the view count to + graphics pipelines and the materials. + + \since 6.8 + */ +int QSGMaterial::viewCount() const +{ + if (m_flags.testFlag(MultiView4)) + return 4; + if (m_flags.testFlag(MultiView3)) + return 3; + if (m_flags.testFlag(MultiView2)) + return 2; + return 1; +} + QT_END_NAMESPACE |