Add feature to dump GDShader API (`--dump-shader-api`)
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.
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).
Thank you for the thorough code review!! Apologies for the lack of a proposal, I will create asap! 👍