Skip to content

Allow shader defines to be created with an optional value #1534

@rms7326

Description

@rms7326

Is your feature request related to a problem? Please describe.
Using shader specialization constants to size global arrays doesn't work on the Mac.

We have a need in our vertex shader to size both a vertex attribute array and an array of gl_clipDistance by a defined value at shader compile time. We were using shader specialization constants to achieve this and on Linux and Windows with NVidia and AMD we seemed to have success even though the "Arrays inside a block" discussion in section "4.4.x Specialization-Constant Qualifier" of ARB_gl_spirv.txt made it sound like using specialization constants to size these array members in the shader is not supported. When we tried out the same code on the Mac we had very unreliable results and were not able to get clipping to work correctly if the vertex array or the gl_ClipDistance array was sized by a specialization constant.

Describe the solution you'd like
We would like to expand the definition of a shader compiler define in VSG to allow for an optional value to be associated with the define name. Here are several proposed solutions:

  1. Continue with the existing std::string and std::set<std::string> interfaces for managing defines which allow client code to add valueless defines with a simple upper case string such as, "VERTEX_NORMALS". In addition to valueless defines that are currently supported, allow a define to have a "NAME=VALUE" syntax. This would allows a defined to be constructed as, "NUM_PRIMITIVE_CLIPS=3". There are several places in ShaderCompiler.cpp where the name portion of the define would need to be extracted when comparing with the list of #pragma import_defines, and when the define is expanded to the header stream. If an equal sign is found in a define it would be replaced with a space and then added to the headerstream just like it is today.
  2. Add a new type, vsg::CompileDefine, that is used in place of the std::string interface and maintain a set of defines with std::set<vsg::CompilerDefine>. The constructor for vsg::CompileDefine would allow for valueless or name/value construction. The changes required to VSG would be much more intrusive and we might need special handling for VSG serialization. This makes option 2 less attractive than option 1.

Describe alternatives you've considered
We attempted to use shader specialization constants but it wasn't super clear if they are even allowed to be used to size global arrays and we had inconsistent behavior on the Mac. Additionally, even on Linux and Windows with NVidia and AMD we had to make a default value for the shader constant that was the maximum array size. In the end we determined that using specialization constants for this purpose was not correct.

Additional context
We are happy to provide a pull request for review.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions