// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only

/*!
    \title Qt Shader Tools Build System Integration
    \page qtshadertools-build.html

    \section1 Introduction

    The \l{Qt Shader Tools} module provides a CMake macro file that provides
    useful functions applications can take into use in their \c{CMakeLists.txt}.

    When using the \c{qt6_add_shaders} function, the \l{QSB Manual}{qsb} tool
    will get invoked automatically by the build system, and the resulting
    \c{.qsb} files get added to the resource system implicitly.

    \section1 First Example

    Let's look at a simple example. Assume that we have a Qt Quick application
    that wants to provides its own wobble effect via \l ShaderEffect. The
    fragment shader is implemented in \c{wobble.frag}. The ShaderEffect item's
    fragmentShader property refers to \c{wobble.frag.qsb}. How do we ensure this
    .qsb file gets generated at build time?

    \badcode
...
project(exampleapp LANGUAGES CXX)
...
find_package(Qt6 COMPONENTS ShaderTools)
...
qt6_add_executable(exampleapp
    main.cpp
)
...
qt6_add_resources(exampleapp "exampleapp"
    PREFIX
        "/"
    FILES
        "main.qml"
)

qt6_add_shaders(exampleapp "exampleapp_shaders"
    PREFIX
        "/"
    FILES
        "wobble.frag"
)
\endcode

    The above is sufficient to enable the application to access
    \c{:/wobble.frag.qsb} at run time. The original Vulkan-style GLSL source
    code (wobble.frag) is not included in the application's executable and does
    not need to be shipped. If there are errors in the shader code, the \c
    glslang compiler messages are printed at build time and the build
    fails. When changing the shader source file, the changes are picked up
    automatically in the next build, like they would for C++ and other source
    files.

    The key is the \c qt6_add_shaders function, which shares similarity with \c
    qt6_add_resources. Without specifying further parameters, the function will
    lead to running qsb with a reasonable set of default arguments that are
    suitable for fragment shaders when targeting Vulkan, Metal, Direct 3D, and
    OpenGL or OpenGL ES.

    \note Watch out for the \c find_package line. It is important to include the
    \c find_package for \c ShaderTools, otherwise \c qt6_add_shaders will not be
    available.

    \note Multiple \c qt6_add_shaders calls are supported. In complex
    applications it is not unlikely that different sets of shaders need
    different settings. The name after the project (\c{"exampleapp_shaders"} in
    the above example) has to be unique for each call.

    \section1 Configuration

    By default \c qt6_add_shaders invokes \l{QSB Manual}{qsb} as follows:
    \badcode
    qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -o <output>.qsb <input>
    \endcode

    This means that the resulting package will contain SPIR-V (for Vulkan 1.0),
    GLSL ES 100 (for OpenGL ES 2.0 and newer), GLSL 120 (for non-core profile
    OpenGL contexts), GLSL 150 (for core profile OpenGL contexts), HLSL source
    for Shader Model 5.0 (for Direct3D 11.1), and Metal Shading Language 1.2
    source (for Metal).

    This is a good set of defaults for Qt Quick, and creates applications that
    are highly portable to a wide variety of systems. These defaults are not
    always suitable however.  If the shader uses functions or constructs that do
    not have an equivalent in these targets, the process, and so the build, will
    fail. If that is the case, the targets will need to be adjusted, and this
    also means that the application's minimum system requirements get adjusted
    implicitly. As an example, take the \c textureLod GLSL function that is only
    available with OpenGL ES 3.0 and up (meaning GLSL ES 300 or higher). When
    requesting GLSL \c{300 es} instead of \c{100 es}, the build will succeed, but
    the resulting application will now require OpenGL ES 3.0 or higher and will
    not be compatible with OpenGL ES 2.0 based systems.

    \section2 Shader type

    The type of shader is deduced from the file extension. Thus, the extension
    must be one of the following:

    \list
    \li \c .vert - for vertex shaders
    \li \c .frag - for fragment (pixel) shaders
    \li \c .comp - for compute shaders
    \endlist

    \section2 Targets

    The following keywords are available:

    \list

    \li \c GLSL - Requests generating source code for the given list of GLSL
    versions. Watch out that the list follows the comma-separated \c qsb
    syntax. For example, a compute shader will want to specify \c{"310 es,430"}
    here as the defaults are not suitable for it.

    \li \c NOGLSL - This argument-less keyword disables generating GLSL
    source. Suitable for applications that do not wish to function with OpenGL
    at all.

    \li \c HLSL - Requests generating source code for the given list of HLSL
    (shader model) versions. The \c qsb tool follows GLSL-style version numbers
    and therefore \c 50 corresponds to Shader Model 5.0, \c 51 is 5.1.

    \li \c NOHLSL - This argument-less keyword disables generating HLSL
    source. Suitable for applications that do not wish to function with Direct 3D
    at all.

    \li \c MSL - Requests generating source code for the given version of the
    Metal Shading Language. \c 12 corresponds to 1.2, \c 20 to 2.0.

    \li \c NOMSL - This argument-less keyword disables generating MSL
    source. Suitable for applications that do not wish to function with Metal at
    all.

    \endlist

    The most commonly overridden setting is \c GLSL. For example, if the
    application's shaders use OpenGL 3.x features, it will likely want to
    specify something higher than \c{100 es} or \c{120}:

    \badcode
    qt_add_shaders(exampleapp "res_gl3shaders"
        GLSL "300es,330"
        PREFIX
            "/shaders"
        FILES
           shaders/ssao.vert
           shaders/ssao.frag
           shaders/skybox.vert
           shaders/skybox.frag
    )
    \endcode

    \note The space before the \c es suffix is optional.

    \section2 Qt Quick specifics

    \list

    \li \c BATCHABLE - Specifying this single, argument-less keyword is
    essential for vertex shaders that are used with Qt Quick, either in a \l
    ShaderEffect or in a \l QSGMaterialShader. It has no effect for fragment or
    compute shaders, and different types can safely be included in the same list
    since the keyword is taken into account only for the \c{.vert}
    files. Equivalent to the \c{-b} argument of \l{QSB Manual}{qsb}.

    \endlist

    \section2 Invoking external tools

    \list

    \li \c PRECOMPILE - Equivalent to the \c{-c} or \c{-t} options of \l{QSB
    Manual}{qsb}, depending on the platform. When building on Windows, this
    leads to invoking \c fxc from the Windows SDK to do the first phase of
    compilation (HLSL source to DXBC bytecode) at build time instead of at run
    time. On macOS it uses invokves the Metal tools to generate a Metal library.
    In either case the resulting \c{.qsb} file will only include the compilation
    results, not the HLSL or MSL source.

    \li \c OPTIMIZED - Invokes \c spirv-opt (which must be available from the
    Vulkan SDK or elsewhere) to perform optimizations on the SPIR-V
    bytecode. Equivalent to the \c{-O} argument of \l{QSB Manual}{qsb}.

    \endlist

    \section2 Other settings

    \list

    \li \c DEFINES - Defines macros that are active during shader
    compilation. Equivalent to the \c{-D} argument of \l{QSB Manual}{qsb}. The
    list has the form of \c{"name1=value1;name2=value2"}. Alternatively, just
    like \c FILES, the list can be separated by newlines.

    \li \c OUTPUTS - When the name of the generated .qsb file needs to be
    different from the source, for example because one shader file serves as the
    source for multiple .qsb files due to differentiating via \c DEFINES, this
    list can contain an entry for each item in \c FILES, specifying a file name
    typically ending in \c{.qsb}. The specified name is then passed in the
    \c{-o} argument to qsb instead of just appending \c{.qsb} to the source file
    name.

    \li \c DEBUGINFO - Enables generating full debug information for SPIR-V,
    thus enabling tools like \l{https://renderdoc.org/}{RenderDoc} to display
    the full source when inspecting a pipeline or when performing vertex or
    fragment debugging. Equivalent to the \c{-g} argument of \l{QSB
    Manual}{qsb}. Also has an effect for Direct 3D in case the \c PRECOMPILE
    keyword has been specified, as \c fxc is then instructed to include debug
    information in the generated intermediate bytecode.

    \li \c QUIET - Suppresses debug and warning output from qsb. Only fatal
    errors are printed.

    \li \c OUTPUT_TARGETS - When using qt_add_shaders with static libraries,
    one or more special targets will be generated. Should you wish to perform
    additional processing on these targets pass a value to the OUTPUT_TARGETS
    parameter.

    \endlist

    \section1 Substituting Hand-Crafted Shaders

    The CMake integration also supports specifying replacements for
    given versions of the shader in the resulting .qsb file. This in
    effect is equivalent to running \l{QSB Manual}{qsb} with the
    \c{-r} command-line option.

    This is enabled by the following special syntax in the FILES list:

    \badcode
    FILES
        "shaders/externalsampler.frag@glsl,100es,shaders/externalsampler_gles.frag"
    \endcode

    The filename can be followed by any number of @-separated
    replacement specifications. Each of these specifies the shading
    language, the version, and the file from which the data is to be
    read separated by commas. See the \l{QSB Manual} for details.
*/
