godot icon indicating copy to clipboard operation
godot copied to clipboard

Add feature to dump GDShader API (`--dump-shader-api`)

Open SomeRanDev opened this issue 2 weeks ago • 2 comments

Implements https://github.com/godotengine/godot-proposals/issues/13808!

Adds the --dump-shader-api command line argument that generates a shader_api.json containing the entirety of the GDShader API (basically a shader equivalent of --dump-extension-api).

Example

Here is the shader_api.json file that is generated on this build if you'd like to take a quick look: shader_api.json

Data Type Example

Every built-in data type is documented. mat3 looks like this:

{
	"name": "mat3",
	"indexing_return_type": "vec3",
	"size": 48,
	"component_count": 9,
	"indexing_size": 3,
	"swizzle_field_count": 0,
	"is_scalar": false,
	"is_float": true,
	"is_sampler": false,
	"operators": [
		{
			"name": "==",
			"return_type": "bool",
			"right_type": "mat3"
		},
		{
			"name": "!=",
			"return_type": "bool",
			"right_type": "mat3"
		},
		...
	]
}

Mode Example

Since constants/inputs are unique to certain modes (spatial, canvas_item, etc.) and even specific phases within those modes, each mode is documented. For example, the particles mode looks like this:

{
	"name": "particles",
	"stages": [
		{
			"name": "start",
			"can_discard": false,
			"main_function": true,
			"built_ins": [
				{
					"name": "COLOR",
					"type": "vec4",
					"constant": false
				},
				{
					"name": "VELOCITY",
					"type": "vec3",
					"constant": false
				},
				{
					"name": "MASS",
					"type": "float",
					"constant": false
				},
				...
			],
			"stage_functions": [
				{
					"name": "emit_subparticle",
					"return_type": "bool",
					"skip_function": "",
					"arguments": [
						{
							"name": "xform",
							"type": "mat4"
						},
						{
							"name": "velocity",
							"type": "vec3"
						},
						...
					]
				}
			]
		},
		...
	]
}

Function Example

Finally, functions that can be used anywhere are generated together. Each of its overloads are provided, listing precisely which argument combinations are valid and their return types. sin looks like this:

{
	"name": "sin",
	"is_frag_only": false,
	"overloads": [
		{
			"arguments": [
				{
					"name": "angle",
					"type": "float",
					"is_out": false,
					"is_const": false
				}
			],
			"return_type": "float",
			"is_high_end": false
		},
		{
			"arguments": [
				{
					"name": "angle",
					"type": "vec2",
					"is_out": false,
					"is_const": false
				}
			],
			"return_type": "vec2",
			"is_high_end": false
		},
		...
	]
}

JSON Structure

The shader_api.json structure currently looks like this. I've tried to use consistent naming with extension_api.json where possible.

{
    datatypes: Array<{
        name: string,
        indexing_return_type: string,
        size: number, // size of the type in memory
        component_count: number, // the number of scalars the type represents (ShaderLanguage::get_datatype_component_count)
        indexing_size: number, // the type can only be indexed within the rage of [0...indexing_size)
        swizzle_field_count: number, // the number of axes that can be swizzled; 0 if the type cannot swizzle
        is_scalar: boolean, // is bool, int, uint, or float
        is_float: boolean,
        is_sampler: boolean,
        operators: Array<{
            name: string,
            return_type: string,
            right_type?: string, // only defined if a binary operator
        }>,
    }>,
    modes: Array<{ // the different shader modes, i.e. spatial, canvas_item, sky, etc.
        name: string,
        render_modes: Array<{
            name: string,
            options?: Array<string>
        }>,
        stencil_modes: Array<{
            name: string,
            options?: Array<string>
        }>,
        stages: Array<{ // the mode's stages, i.e. vertex/fragment/light in spatial, or start/process in particles
            name: string,
            can_discard: boolean,
            main_function: boolean,
            built_ins: Array<{ // all the available built in input values, i.e. IN_SHADOW_PASS, VERTEX, etc.
                name: string,
                type: string,
                constant: boolean,
                values?: Array<boolean | number>,
            }>,
            stage_functions: Array<{ // functions unique to this specific mode and stage
                name: string,
                arguments: Array<{
                    name: string,
                    type: string,
                }>,
                return_type: string,
                skip_function: string,
            }>,
        }>,
    }>,
    functions: Array<{
        name: string,
        is_frag_only: boolean, // true if this function is a fragment-only function (in ShaderLanguage::frag_only_func_defs)
        overloads: Array<{
            return_type: string,
            is_high_end: boolean, // if true, this function isn't allowed in Compatibility (I think?); name based on ShaderLanguage::BuiltinFuncDef::high_end
            arguments: Array<{
                name: string,
                type: string,
                is_out: boolean, // true if argument is an "out" argument (in ShaderLanguage::builtin_func_out_args)
                is_const: boolean, // true if argument must be an int constant (in ShaderLanguage::builtin_func_const_args)
                min?: number, // only defined if is_const is true
                max?: number, // only defined if is_const is true
            }>,
        }>,
    }>,
}

Changes to Existing Code

This PR mainly just adds the shader_api_dump.cpp/h files, but code in shader_language.cpp/h needed to be modified to provide access to information. The most drastic change was extracting the operator validation out of _validate_operator to create a more generic get_datatype_operator_result that validates an operation given one or two DataTypes and an Operator.

SomeRanDev avatar Dec 07 '25 02:12 SomeRanDev

Thanks for opening a pull request!

Feature pull requests should be associated to a feature proposal to justify the need for implementing the feature in Godot core. Please open a proposal on the Godot proposals repository (and link to the proposal in this pull request's body).

AThousandShips avatar Dec 08 '25 09:12 AThousandShips

Thank you for the thorough code review!! Apologies for the lack of a proposal, I will create asap! 👍

SomeRanDev avatar Dec 08 '25 12:12 SomeRanDev