Repository: shader-slang/slang
File: source/slang/slang-check-shader.cpp (C++)

Code before:
                        &visitor,
                        sink,
                        param,
                        stage,
                        SemanticDirection::Input,
                        scope);
                }
            }

            // Validate the return type semantic
            validateSystemValueSemantic(
                &visitor,
                sink,
                entryPointFuncDecl,
                stage,
                SemanticDirection::Output,
                scope);
        }
    }

    // For compute entry points using GLSL syntax, the thread group size is
    // specified via layout(local_size_x = N) on a sibling EmptyDecl rather than
    // via [numthreads] on the entry point itself. GLSL allows each axis to be
    // specified in a separate declaration, so we merge all
    // GLSLLayoutLocalSizeAttribute values into a single NumThreadsAttribute.
    if (stage == Stage::Compute && !entryPointFuncDecl->findModifier<NumThreadsAttribute>())
    {
        auto parentDecl = entryPointFuncDecl->parentDecl;
        if (parentDecl)
        {
            NumThreadsAttribute* numThreads = nullptr;
            for (auto emptyDecl : parentDecl->getMembersOfType<EmptyDecl>())
            {
                auto glslAttr = emptyDecl->findModifier<GLSLLayoutLocalSizeAttribute>();
                if (!glslAttr)
                    continue;

                if (!numThreads)
                {
                    numThreads = getCurrentASTBuilder()->create<NumThreadsAttribute>();
                    for (int i = 0; i < 3; ++i)
                    {
                        numThreads->extents[i] = glslAttr->extents[i];
                        numThreads->specConstExtents[i] = glslAttr->specConstExtents[i];
                    }
                }
                else
                {
                    // Merge: for each axis, take the non-default value.
                    // GLSL defaults unspecified axes to 1.
                    for (int i = 0; i < 3; ++i)

Review comment (suggestion):
Note: Mesh and amplification (task) shaders are compute-like shaders, i.e., they require the numthreads specification.  I think we should include those stages here as well.

Code after:
                        &visitor,
                        sink,
                        param,
                        stage,
                        SemanticDirection::Input,
                        scope);
                }
            }

            // Validate the return type semantic
            validateSystemValueSemantic(
                &visitor,
                sink,
                entryPointFuncDecl,
                stage,
                SemanticDirection::Output,
                scope);
        }
    }

    // For compute, mesh, and amplification (task) entry points using GLSL
    // syntax, the thread group size is specified via layout(local_size_x = N)
    // on a sibling EmptyDecl rather than via [numthreads] on the entry point
    // itself. GLSL allows each axis to be specified in a separate declaration,
    // so we merge all GLSLLayoutLocalSizeAttribute values into a single
    // NumThreadsAttribute.
    if ((stage == Stage::Compute || stage == Stage::Mesh || stage == Stage::Amplification) &&
        !entryPointFuncDecl->findModifier<NumThreadsAttribute>())
    {
        auto parentDecl = entryPointFuncDecl->parentDecl;
        if (parentDecl)
        {
            NumThreadsAttribute* numThreads = nullptr;
            for (auto emptyDecl : parentDecl->getMembersOfType<EmptyDecl>())
            {
                auto glslAttr = emptyDecl->findModifier<GLSLLayoutLocalSizeAttribute>();
                if (!glslAttr)
                    continue;

                if (!numThreads)
                {
                    numThreads = getCurrentASTBuilder()->create<NumThreadsAttribute>();
                    for (int i = 0; i < 3; ++i)
                    {
                        numThreads->extents[i] = glslAttr->extents[i];
                        numThreads->specConstExtents[i] = glslAttr->specConstExtents[i];
                    }
                }
                else
                {
                    // Merge: for each axis, take the non-default value.