X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fglsl%2Fspirv.cpp;h=c6f15614f5c8a56a36c7e7236a1c785f081e0a19;hp=35d46ab7f9333b503897585de8bbebded43b62f7;hb=HEAD;hpb=513dd710045f66c4e79e1db56cdad87e9ad143a0 diff --git a/source/glsl/spirv.cpp b/source/glsl/spirv.cpp index 35d46ab7..4dceb971 100644 --- a/source/glsl/spirv.cpp +++ b/source/glsl/spirv.cpp @@ -1,3 +1,4 @@ +#include #include #include #include "reflect.h" @@ -11,149 +12,144 @@ namespace SL { const SpirVGenerator::BuiltinFunctionInfo SpirVGenerator::builtin_functions[] = { - { "radians", "f", "GLSL.std.450", GLSL450_RADIANS, { 1 }, 0 }, - { "degrees", "f", "GLSL.std.450", GLSL450_DEGREES, { 1 }, 0 }, - { "sin", "f", "GLSL.std.450", GLSL450_SIN, { 1 }, 0 }, - { "cos", "f", "GLSL.std.450", GLSL450_COS, { 1 }, 0 }, - { "tan", "f", "GLSL.std.450", GLSL450_TAN, { 1 }, 0 }, - { "asin", "f", "GLSL.std.450", GLSL450_ASIN, { 1 }, 0 }, - { "acos", "f", "GLSL.std.450", GLSL450_ACOS, { 1 }, 0 }, - { "atan", "f", "GLSL.std.450", GLSL450_ATAN, { 1 }, 0 }, - { "atan", "ff", "GLSL.std.450", GLSL450_ATAN2, { 1, 2 }, 0 }, - { "sinh", "f", "GLSL.std.450", GLSL450_SINH, { 1 }, 0 }, - { "cosh", "f", "GLSL.std.450", GLSL450_COSH, { 1 }, 0 }, - { "tanh", "f", "GLSL.std.450", GLSL450_TANH, { 1 }, 0 }, - { "asinh", "f", "GLSL.std.450", GLSL450_ASINH, { 1 }, 0 }, - { "acosh", "f", "GLSL.std.450", GLSL450_ACOSH, { 1 }, 0 }, - { "atanh", "f", "GLSL.std.450", GLSL450_ATANH, { 1 }, 0 }, - { "pow", "ff", "GLSL.std.450", GLSL450_POW, { 1, 2 }, 0 }, - { "exp", "f", "GLSL.std.450", GLSL450_EXP, { 1 }, 0 }, - { "log", "f", "GLSL.std.450", GLSL450_LOG, { 1 }, 0 }, - { "exp2", "f", "GLSL.std.450", GLSL450_EXP2, { 1 }, 0 }, - { "log2", "f", "GLSL.std.450", GLSL450_LOG2, { 1 }, 0 }, - { "sqrt", "f", "GLSL.std.450", GLSL450_SQRT, { 1 }, 0 }, - { "inversesqrt", "f", "GLSL.std.450", GLSL450_INVERSE_SQRT, { 1 }, 0 }, - { "abs", "f", "GLSL.std.450", GLSL450_F_ABS, { 1 }, 0 }, - { "abs", "i", "GLSL.std.450", GLSL450_S_ABS, { 1 }, 0 }, - { "sign", "f", "GLSL.std.450", GLSL450_F_SIGN, { 1 }, 0 }, - { "sign", "i", "GLSL.std.450", GLSL450_S_SIGN, { 1 }, 0 }, - { "floor", "f", "GLSL.std.450", GLSL450_FLOOR, { 1 }, 0 }, - { "trunc", "f", "GLSL.std.450", GLSL450_TRUNC, { 1 }, 0 }, - { "round", "f", "GLSL.std.450", GLSL450_ROUND, { 1 }, 0 }, - { "roundEven", "f", "GLSL.std.450", GLSL450_ROUND_EVEN, { 1 }, 0 }, - { "ceil", "f", "GLSL.std.450", GLSL450_CEIL, { 1 }, 0 }, - { "fract", "f", "GLSL.std.450", GLSL450_FRACT, { 1 }, 0 }, - { "mod", "f", "", OP_F_MOD, { 1, 2 }, 0 }, - { "min", "ff", "GLSL.std.450", GLSL450_F_MIN, { 1, 2 }, 0 }, - { "min", "ii", "GLSL.std.450", GLSL450_S_MIN, { 1, 2 }, 0 }, - { "min", "uu", "GLSL.std.450", GLSL450_U_MIN, { 1, 2 }, 0 }, - { "max", "ff", "GLSL.std.450", GLSL450_F_MAX, { 1, 2 }, 0 }, - { "max", "ii", "GLSL.std.450", GLSL450_S_MAX, { 1, 2 }, 0 }, - { "max", "uu", "GLSL.std.450", GLSL450_U_MAX, { 1, 2 }, 0 }, - { "clamp", "fff", "GLSL.std.450", GLSL450_F_CLAMP, { 1, 2, 3 }, 0 }, - { "clamp", "iii", "GLSL.std.450", GLSL450_S_CLAMP, { 1, 2, 3 }, 0 }, - { "clamp", "uuu", "GLSL.std.450", GLSL450_U_CLAMP, { 1, 2, 3 }, 0 }, - { "mix", "fff", "GLSL.std.450", GLSL450_F_MIX, { 1, 2, 3 }, 0 }, - { "mix", "ffb", "", OP_SELECT, { 3, 2, 1 }, 0 }, - { "mix", "iib", "", OP_SELECT, { 3, 2, 1 }, 0 }, - { "mix", "uub", "", OP_SELECT, { 3, 2, 1 }, 0 }, - { "step", "ff", "GLSL.std.450", GLSL450_F_STEP, { 1, 2 }, 0 }, - { "smoothstep", "fff", "GLSL.std.450", GLSL450_F_SMOOTH_STEP, { 1, 2, 3 }, 0 }, - { "isnan", "f", "", OP_IS_NAN, { 1 }, 0 }, - { "isinf", "f", "", OP_IS_INF, { 1 }, 0 }, - { "fma", "fff", "GLSL.std.450", GLSL450_F_FMA, { 1, 2, 3 }, 0 }, - { "length", "f", "GLSL.std.450", GLSL450_LENGTH, { 1 }, 0 }, - { "distance", "ff", "GLSL.std.450", GLSL450_DISTANCE, { 1, 2 }, 0 }, - { "dot", "ff", "", OP_DOT, { 1, 2 }, 0 }, - { "cross", "ff", "GLSL.std.450", GLSL450_CROSS, { 1, 2 }, 0 }, - { "normalize", "f", "GLSL.std.450", GLSL450_NORMALIZE, { 1 }, 0 }, - { "faceforward", "fff", "GLSL.std.450", GLSL450_FACE_FORWARD, { 1, 2, 3 }, 0 }, - { "reflect", "ff", "GLSL.std.450", GLSL450_REFLECT, { 1, 2 }, 0 }, - { "refract", "fff", "GLSL.std.450", GLSL450_REFRACT, { 1, 2, 3 }, 0 }, - { "matrixCompMult", "ff", "", 0, { 0 }, &SpirVGenerator::visit_builtin_matrix_comp_mult }, - { "outerProduct", "ff", "", OP_OUTER_PRODUCT, { 1, 2 }, 0 }, - { "transpose", "f", "", OP_TRANSPOSE, { 1 }, 0 }, - { "determinant", "f", "GLSL.std.450", GLSL450_DETERMINANT, { 1 }, 0 }, - { "inverse", "f", "GLSL.std.450", GLSL450_MATRIX_INVERSE, { 1 }, 0 }, - { "lessThan", "ff", "", OP_F_ORD_LESS_THAN, { 1, 2 }, 0 }, - { "lessThan", "ii", "", OP_S_LESS_THAN, { 1, 2 }, 0 }, - { "lessThan", "uu", "", OP_U_LESS_THAN, { 1, 2 }, 0 }, - { "lessThanEqual", "ff", "", OP_F_ORD_LESS_THAN_EQUAL, { 1, 2 }, 0 }, - { "lessThanEqual", "ii", "", OP_S_LESS_THAN_EQUAL, { 1, 2 }, 0 }, - { "lessThanEqual", "uu", "", OP_U_LESS_THAN_EQUAL, { 1, 2 }, 0 }, - { "greaterThan", "ff", "", OP_F_ORD_GREATER_THAN, { 1, 2 }, 0 }, - { "greaterThan", "ii", "", OP_S_GREATER_THAN, { 1, 2 }, 0 }, - { "greaterThan", "uu", "", OP_U_GREATER_THAN, { 1, 2 }, 0 }, - { "greaterThanEqual", "ff", "", OP_F_ORD_GREATER_THAN_EQUAL, { 1, 2 }, 0 }, - { "greaterThanEqual", "ii", "", OP_S_GREATER_THAN_EQUAL, { 1, 2 }, 0 }, - { "greaterThanEqual", "uu", "", OP_U_GREATER_THAN_EQUAL, { 1, 2 }, 0 }, - { "equal", "ff", "", OP_F_ORD_EQUAL, { 1, 2 }, 0 }, - { "equal", "ii", "", OP_I_EQUAL, { 1, 2 }, 0 }, - { "equal", "uu", "", OP_I_EQUAL, { 1, 2 }, 0 }, - { "notEqual", "ff", "", OP_F_ORD_NOT_EQUAL, { 1, 2 }, 0 }, - { "notEqual", "ii", "", OP_I_NOT_EQUAL, { 1, 2 }, 0 }, - { "notEqual", "uu", "", OP_I_NOT_EQUAL, { 1, 2 }, 0 }, - { "any", "b", "", OP_ANY, { 1 }, 0 }, - { "all", "b", "", OP_ALL, { 1 }, 0 }, - { "not", "b", "", OP_LOGICAL_NOT, { 1 }, 0 }, - { "bitfieldExtract", "iii", "", OP_BIT_FIELD_S_EXTRACT, { 1, 2, 3 }, 0 }, - { "bitfieldExtract", "uii", "", OP_BIT_FIELD_U_EXTRACT, { 1, 2, 3 }, 0 }, - { "bitfieldInsert", "iiii", "", OP_BIT_FIELD_INSERT, { 1, 2, 3, 4 }, 0 }, - { "bitfieldInsert", "uuii", "", OP_BIT_FIELD_INSERT, { 1, 2, 3, 4 }, 0 }, - { "bitfieldReverse", "i", "", OP_BIT_REVERSE, { 1 }, 0 }, - { "bitfieldReverse", "u", "", OP_BIT_REVERSE, { 1 }, 0 }, - { "bitCount", "i", "", OP_BIT_COUNT, { 1 }, 0 }, - { "findLSB", "i", "GLSL.std.450", GLSL450_FIND_I_LSB, { 1 }, 0 }, - { "findLSB", "u", "GLSL.std.450", GLSL450_FIND_I_LSB, { 1 }, 0 }, - { "findMSB", "i", "GLSL.std.450", GLSL450_FIND_S_MSB, { 1 }, 0 }, - { "findMSB", "u", "GLSL.std.450", GLSL450_FIND_U_MSB, { 1 }, 0 }, - { "textureSize", "", "", OP_IMAGE_QUERY_SIZE_LOD, { 1, 2 }, 0 }, - { "texture", "", "", 0, { }, &SpirVGenerator::visit_builtin_texture }, - { "textureLod", "", "", 0, { }, &SpirVGenerator::visit_builtin_texture }, - { "texelFetch", "", "", 0, { }, &SpirVGenerator::visit_builtin_texel_fetch }, - { "EmitVertex", "", "", OP_EMIT_VERTEX, { }, 0 }, - { "EndPrimitive", "", "", OP_END_PRIMITIVE, { }, 0 }, - { "dFdx", "f", "", OP_DP_DX, { 1 }, 0 }, - { "dFdy", "f", "", OP_DP_DY, { 1 }, 0 }, - { "dFdxFine", "f", "", OP_DP_DX_FINE, { 1 }, 0 }, - { "dFdyFine", "f", "", OP_DP_DY_FINE, { 1 }, 0 }, - { "dFdxCoarse", "f", "", OP_DP_DX_COARSE, { 1 }, 0 }, - { "dFdyCoarse", "f", "", OP_DP_DY_COARSE, { 1 }, 0 }, - { "fwidth", "f", "", OP_FWIDTH, { 1 }, 0 }, - { "fwidthFine", "f", "", OP_FWIDTH_FINE, { 1 }, 0 }, - { "fwidthCoarse", "f", "", OP_FWIDTH_COARSE, { 1 }, 0 }, - { "interpolateAtCentroid", "", "", 0, { }, &SpirVGenerator::visit_builtin_interpolate }, - { "interpolateAtSample", "", "", 0, { }, &SpirVGenerator::visit_builtin_interpolate }, - { "interpolateAtOffset", "", "", 0, { }, &SpirVGenerator::visit_builtin_interpolate }, - { "", "", "", 0, { }, 0 } + { "radians", "f", "GLSL.std.450", GLSL450_RADIANS, { 1 }, 0, 0 }, + { "degrees", "f", "GLSL.std.450", GLSL450_DEGREES, { 1 }, 0, 0 }, + { "sin", "f", "GLSL.std.450", GLSL450_SIN, { 1 }, 0, 0 }, + { "cos", "f", "GLSL.std.450", GLSL450_COS, { 1 }, 0, 0 }, + { "tan", "f", "GLSL.std.450", GLSL450_TAN, { 1 }, 0, 0 }, + { "asin", "f", "GLSL.std.450", GLSL450_ASIN, { 1 }, 0, 0 }, + { "acos", "f", "GLSL.std.450", GLSL450_ACOS, { 1 }, 0, 0 }, + { "atan", "f", "GLSL.std.450", GLSL450_ATAN, { 1 }, 0, 0 }, + { "atan", "ff", "GLSL.std.450", GLSL450_ATAN2, { 1, 2 }, 0, 0 }, + { "sinh", "f", "GLSL.std.450", GLSL450_SINH, { 1 }, 0, 0 }, + { "cosh", "f", "GLSL.std.450", GLSL450_COSH, { 1 }, 0, 0 }, + { "tanh", "f", "GLSL.std.450", GLSL450_TANH, { 1 }, 0, 0 }, + { "asinh", "f", "GLSL.std.450", GLSL450_ASINH, { 1 }, 0, 0 }, + { "acosh", "f", "GLSL.std.450", GLSL450_ACOSH, { 1 }, 0, 0 }, + { "atanh", "f", "GLSL.std.450", GLSL450_ATANH, { 1 }, 0, 0 }, + { "pow", "ff", "GLSL.std.450", GLSL450_POW, { 1, 2 }, 0, 0 }, + { "exp", "f", "GLSL.std.450", GLSL450_EXP, { 1 }, 0, 0 }, + { "log", "f", "GLSL.std.450", GLSL450_LOG, { 1 }, 0, 0 }, + { "exp2", "f", "GLSL.std.450", GLSL450_EXP2, { 1 }, 0, 0 }, + { "log2", "f", "GLSL.std.450", GLSL450_LOG2, { 1 }, 0, 0 }, + { "sqrt", "f", "GLSL.std.450", GLSL450_SQRT, { 1 }, 0, 0 }, + { "inversesqrt", "f", "GLSL.std.450", GLSL450_INVERSE_SQRT, { 1 }, 0, 0 }, + { "abs", "f", "GLSL.std.450", GLSL450_F_ABS, { 1 }, 0, 0 }, + { "abs", "i", "GLSL.std.450", GLSL450_S_ABS, { 1 }, 0, 0 }, + { "sign", "f", "GLSL.std.450", GLSL450_F_SIGN, { 1 }, 0, 0 }, + { "sign", "i", "GLSL.std.450", GLSL450_S_SIGN, { 1 }, 0, 0 }, + { "floor", "f", "GLSL.std.450", GLSL450_FLOOR, { 1 }, 0, 0 }, + { "trunc", "f", "GLSL.std.450", GLSL450_TRUNC, { 1 }, 0, 0 }, + { "round", "f", "GLSL.std.450", GLSL450_ROUND, { 1 }, 0, 0 }, + { "roundEven", "f", "GLSL.std.450", GLSL450_ROUND_EVEN, { 1 }, 0, 0 }, + { "ceil", "f", "GLSL.std.450", GLSL450_CEIL, { 1 }, 0, 0 }, + { "fract", "f", "GLSL.std.450", GLSL450_FRACT, { 1 }, 0, 0 }, + { "mod", "f", "", OP_F_MOD, { 1, 2 }, 0, 0 }, + { "min", "ff", "GLSL.std.450", GLSL450_F_MIN, { 1, 2 }, 0, 0 }, + { "min", "ii", "GLSL.std.450", GLSL450_S_MIN, { 1, 2 }, 0, 0 }, + { "min", "uu", "GLSL.std.450", GLSL450_U_MIN, { 1, 2 }, 0, 0 }, + { "max", "ff", "GLSL.std.450", GLSL450_F_MAX, { 1, 2 }, 0, 0 }, + { "max", "ii", "GLSL.std.450", GLSL450_S_MAX, { 1, 2 }, 0, 0 }, + { "max", "uu", "GLSL.std.450", GLSL450_U_MAX, { 1, 2 }, 0, 0 }, + { "clamp", "fff", "GLSL.std.450", GLSL450_F_CLAMP, { 1, 2, 3 }, 0, 0 }, + { "clamp", "iii", "GLSL.std.450", GLSL450_S_CLAMP, { 1, 2, 3 }, 0, 0 }, + { "clamp", "uuu", "GLSL.std.450", GLSL450_U_CLAMP, { 1, 2, 3 }, 0, 0 }, + { "mix", "fff", "GLSL.std.450", GLSL450_F_MIX, { 1, 2, 3 }, 0, 0 }, + { "mix", "ffb", "", OP_SELECT, { 3, 2, 1 }, 0, 0 }, + { "mix", "iib", "", OP_SELECT, { 3, 2, 1 }, 0, 0 }, + { "mix", "uub", "", OP_SELECT, { 3, 2, 1 }, 0, 0 }, + { "step", "ff", "GLSL.std.450", GLSL450_F_STEP, { 1, 2 }, 0, 0 }, + { "smoothstep", "fff", "GLSL.std.450", GLSL450_F_SMOOTH_STEP, { 1, 2, 3 }, 0, 0 }, + { "isnan", "f", "", OP_IS_NAN, { 1 }, 0, 0 }, + { "isinf", "f", "", OP_IS_INF, { 1 }, 0, 0 }, + { "fma", "fff", "GLSL.std.450", GLSL450_F_FMA, { 1, 2, 3 }, 0, 0 }, + { "length", "f", "GLSL.std.450", GLSL450_LENGTH, { 1 }, 0, 0 }, + { "distance", "ff", "GLSL.std.450", GLSL450_DISTANCE, { 1, 2 }, 0, 0 }, + { "dot", "ff", "", OP_DOT, { 1, 2 }, 0, 0 }, + { "cross", "ff", "GLSL.std.450", GLSL450_CROSS, { 1, 2 }, 0, 0 }, + { "normalize", "f", "GLSL.std.450", GLSL450_NORMALIZE, { 1 }, 0, 0 }, + { "faceforward", "fff", "GLSL.std.450", GLSL450_FACE_FORWARD, { 1, 2, 3 }, 0, 0 }, + { "reflect", "ff", "GLSL.std.450", GLSL450_REFLECT, { 1, 2 }, 0, 0 }, + { "refract", "fff", "GLSL.std.450", GLSL450_REFRACT, { 1, 2, 3 }, 0, 0 }, + { "matrixCompMult", "ff", "", 0, { 0 }, 0, &SpirVGenerator::visit_builtin_matrix_comp_mult }, + { "outerProduct", "ff", "", OP_OUTER_PRODUCT, { 1, 2 }, 0, 0 }, + { "transpose", "f", "", OP_TRANSPOSE, { 1 }, 0, 0 }, + { "determinant", "f", "GLSL.std.450", GLSL450_DETERMINANT, { 1 }, 0, 0 }, + { "inverse", "f", "GLSL.std.450", GLSL450_MATRIX_INVERSE, { 1 }, 0, 0 }, + { "lessThan", "ff", "", OP_F_ORD_LESS_THAN, { 1, 2 }, 0, 0 }, + { "lessThan", "ii", "", OP_S_LESS_THAN, { 1, 2 }, 0, 0 }, + { "lessThan", "uu", "", OP_U_LESS_THAN, { 1, 2 }, 0, 0 }, + { "lessThanEqual", "ff", "", OP_F_ORD_LESS_THAN_EQUAL, { 1, 2 }, 0, 0 }, + { "lessThanEqual", "ii", "", OP_S_LESS_THAN_EQUAL, { 1, 2 }, 0, 0 }, + { "lessThanEqual", "uu", "", OP_U_LESS_THAN_EQUAL, { 1, 2 }, 0, 0 }, + { "greaterThan", "ff", "", OP_F_ORD_GREATER_THAN, { 1, 2 }, 0, 0 }, + { "greaterThan", "ii", "", OP_S_GREATER_THAN, { 1, 2 }, 0, 0 }, + { "greaterThan", "uu", "", OP_U_GREATER_THAN, { 1, 2 }, 0, 0 }, + { "greaterThanEqual", "ff", "", OP_F_ORD_GREATER_THAN_EQUAL, { 1, 2 }, 0, 0 }, + { "greaterThanEqual", "ii", "", OP_S_GREATER_THAN_EQUAL, { 1, 2 }, 0, 0 }, + { "greaterThanEqual", "uu", "", OP_U_GREATER_THAN_EQUAL, { 1, 2 }, 0, 0 }, + { "equal", "ff", "", OP_F_ORD_EQUAL, { 1, 2 }, 0, 0 }, + { "equal", "ii", "", OP_I_EQUAL, { 1, 2 }, 0, 0 }, + { "equal", "uu", "", OP_I_EQUAL, { 1, 2 }, 0, 0 }, + { "notEqual", "ff", "", OP_F_ORD_NOT_EQUAL, { 1, 2 }, 0, 0 }, + { "notEqual", "ii", "", OP_I_NOT_EQUAL, { 1, 2 }, 0, 0 }, + { "notEqual", "uu", "", OP_I_NOT_EQUAL, { 1, 2 }, 0, 0 }, + { "any", "b", "", OP_ANY, { 1 }, 0, 0 }, + { "all", "b", "", OP_ALL, { 1 }, 0, 0 }, + { "not", "b", "", OP_LOGICAL_NOT, { 1 }, 0, 0 }, + { "bitfieldExtract", "iii", "", OP_BIT_FIELD_S_EXTRACT, { 1, 2, 3 }, 0, 0 }, + { "bitfieldExtract", "uii", "", OP_BIT_FIELD_U_EXTRACT, { 1, 2, 3 }, 0, 0 }, + { "bitfieldInsert", "iiii", "", OP_BIT_FIELD_INSERT, { 1, 2, 3, 4 }, 0, 0 }, + { "bitfieldInsert", "uuii", "", OP_BIT_FIELD_INSERT, { 1, 2, 3, 4 }, 0, 0 }, + { "bitfieldReverse", "i", "", OP_BIT_REVERSE, { 1 }, 0, 0 }, + { "bitfieldReverse", "u", "", OP_BIT_REVERSE, { 1 }, 0, 0 }, + { "bitCount", "i", "", OP_BIT_COUNT, { 1 }, 0, 0 }, + { "findLSB", "i", "GLSL.std.450", GLSL450_FIND_I_LSB, { 1 }, 0, 0 }, + { "findLSB", "u", "GLSL.std.450", GLSL450_FIND_I_LSB, { 1 }, 0, 0 }, + { "findMSB", "i", "GLSL.std.450", GLSL450_FIND_S_MSB, { 1 }, 0, 0 }, + { "findMSB", "u", "GLSL.std.450", GLSL450_FIND_U_MSB, { 1 }, 0, 0 }, + { "textureSize", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, + { "textureQueryLod", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, + { "textureQueryLevels", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, + { "textureSamples", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, + { "texture", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture }, + { "textureLod", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture }, + { "texelFetch", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_fetch }, + { "imageSize", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, + { "imageSamples", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, + { "imageLoad", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_fetch }, + { "imageStore", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_store }, + { "EmitVertex", "", "", OP_EMIT_VERTEX, { }, 0, 0 }, + { "EndPrimitive", "", "", OP_END_PRIMITIVE, { }, 0, 0 }, + { "dFdx", "f", "", OP_DP_DX, { 1 }, 0, 0 }, + { "dFdy", "f", "", OP_DP_DY, { 1 }, 0, 0 }, + { "dFdxFine", "f", "", OP_DP_DX_FINE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 }, + { "dFdyFine", "f", "", OP_DP_DY_FINE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 }, + { "dFdxCoarse", "f", "", OP_DP_DX_COARSE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 }, + { "dFdyCoarse", "f", "", OP_DP_DY_COARSE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 }, + { "fwidth", "f", "", OP_FWIDTH, { 1 }, 0, 0 }, + { "fwidthFine", "f", "", OP_FWIDTH_FINE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 }, + { "fwidthCoarse", "f", "", OP_FWIDTH_COARSE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 }, + { "interpolateAtCentroid", "", "", 0, { }, CAP_INTERPOLATION_FUNCTION, &SpirVGenerator::visit_builtin_interpolate }, + { "interpolateAtSample", "", "", 0, { }, CAP_INTERPOLATION_FUNCTION, &SpirVGenerator::visit_builtin_interpolate }, + { "interpolateAtOffset", "", "", 0, { }, CAP_INTERPOLATION_FUNCTION, &SpirVGenerator::visit_builtin_interpolate }, + { "", "", "", 0, { }, 0, 0 } }; SpirVGenerator::SpirVGenerator(): - stage(0), - current_function(0), - writer(content), - next_id(1), - r_expression_result_id(0), - constant_expression(false), - spec_constant(false), - reachable(false), - composite_access(false), - r_composite_base_id(0), - r_composite_base(0), - assignment_source_id(0), - loop_merge_block_id(0), - loop_continue_target_id(0) + writer(content) { } -void SpirVGenerator::apply(Module &module) +void SpirVGenerator::apply(Module &module, const Features &f) { + features = f; use_capability(CAP_SHADER); - for(list::iterator i=module.stages.begin(); i!=module.stages.end(); ++i) + for(Stage &s: module.stages) { - stage = &*i; + stage = &s; interface_layouts.clear(); - i->content.visit(*this); + s.content.visit(*this); } writer.finalize(SPIRV_GENERATOR_MSP, next_id); @@ -191,6 +187,14 @@ SpirVGenerator::BuiltinSemantic SpirVGenerator::get_builtin_semantic(const strin return BUILTIN_INVOCATION_ID; else if(name=="gl_Layer") return BUILTIN_LAYER; + else if(name=="gl_TessLevelOuter") + return BUILTIN_TESS_LEVEL_OUTER; + else if(name=="gl_TessLevelInner") + return BUILTIN_TESS_LEVEL_INNER; + else if(name=="gl_TessCoord") + return BUILTIN_TESS_COORD; + else if(name=="gl_PatchVerticesIn") + return BUILTIN_PATCH_VERTICES; else if(name=="gl_FragCoord") return BUILTIN_FRAG_COORD; else if(name=="gl_PointCoord") @@ -203,10 +207,66 @@ SpirVGenerator::BuiltinSemantic SpirVGenerator::get_builtin_semantic(const strin return BUILTIN_SAMPLE_POSITION; else if(name=="gl_FragDepth") return BUILTIN_FRAG_DEPTH; + else if(name=="gl_NumWorkGroups") + return BUILTIN_NUM_WORKGROUPS; + else if(name=="gl_WorkGroupSize") + return BUILTIN_WORKGROUP_SIZE; + else if(name=="gl_WorkGroupID") + return BUILTIN_WORKGROUP_ID; + else if(name=="gl_LocalInvocationID") + return BUILTIN_LOCAL_INVOCATION_ID; + else if(name=="gl_GlobalInvocationID") + return BUILTIN_GLOBAL_INVOCATION_ID; + else if(name=="gl_LocalInvocationIndex") + return BUILTIN_LOCAL_INVOCATION_INDEX; else throw invalid_argument("SpirVGenerator::get_builtin_semantic"); } +SpirVFormat SpirVGenerator::get_format(const std::string &name) +{ + if(name.empty()) + return FORMAT_UNKNOWN; + else if(name=="rgba32f") + return FORMAT_RGBA32F; + else if(name=="rgba16f") + return FORMAT_RGBA16F; + else if(name=="r32f") + return FORMAT_R32F; + else if(name=="rgba8") + return FORMAT_RGBA8; + else if(name=="rgba8_snorm") + return FORMAT_RGBA8_SNORM; + else if(name=="rg32f") + return FORMAT_RG32F; + else if(name=="rg16f") + return FORMAT_RG16F; + else if(name=="r16f") + return FORMAT_R16F; + else if(name=="rgba16") + return FORMAT_RGBA16; + else if(name=="rg16") + return FORMAT_RG16; + else if(name=="rg8") + return FORMAT_RG8; + else if(name=="r16") + return FORMAT_RG16; + else if(name=="r8") + return FORMAT_RG8; + else if(name=="rgba16_snorm") + return FORMAT_RGBA16_SNORM; + else if(name=="rg16_snorm") + return FORMAT_RG16_SNORM; + else if(name=="rg8_snorm") + return FORMAT_RG8_SNORM; + else if(name=="r16_snorm") + return FORMAT_RG16_SNORM; + else if(name=="r8_snorm") + return FORMAT_RG8_SNORM; + else + throw invalid_argument("SpirVGenerator::get_format"); +} + void SpirVGenerator::use_capability(Capability cap) { if(used_capabilities.count(cap)) @@ -237,7 +297,7 @@ SpirVGenerator::Id SpirVGenerator::get_id(Node &node) const SpirVGenerator::Id SpirVGenerator::allocate_id(Node &node, Id type_id) { - map::iterator i = declared_ids.find(&node); + auto i = declared_ids.find(&node); if(i!=declared_ids.end()) { if(i->second.type_id) @@ -253,7 +313,7 @@ SpirVGenerator::Id SpirVGenerator::allocate_id(Node &node, Id type_id) SpirVGenerator::Id SpirVGenerator::allocate_forward_id(Node &node) { - map::iterator i = declared_ids.find(&node); + auto i = declared_ids.find(&node); if(i!=declared_ids.end()) return i->second.id; @@ -343,14 +403,14 @@ SpirVGenerator::Id SpirVGenerator::get_standard_type_id(BasicTypeDeclaration::Ki bool SpirVGenerator::is_scalar_type(Id type_id, BasicTypeDeclaration::Kind kind) const { - map::const_iterator i = standard_type_ids.find(TypeKey(kind, true)); + auto i = standard_type_ids.find(TypeKey(kind, true)); return (i!=standard_type_ids.end() && i->second==type_id); } -SpirVGenerator::Id SpirVGenerator::get_array_type_id(TypeDeclaration &base_type, Id size_id) +SpirVGenerator::Id SpirVGenerator::get_array_type_id(TypeDeclaration &base_type, Id size_id, bool extended_align) { Id base_type_id = get_id(base_type); - Id &array_type_id = array_type_ids[TypeKey(base_type_id, size_id)]; + Id &array_type_id = array_type_ids[TypeKey(base_type_id, extended_align*0x400000 | size_id)]; if(!array_type_id) { array_type_id = next_id++; @@ -360,6 +420,8 @@ SpirVGenerator::Id SpirVGenerator::get_array_type_id(TypeDeclaration &base_type, writer.write_op(content.globals, OP_TYPE_RUNTIME_ARRAY, array_type_id, base_type_id); unsigned stride = MemoryRequirementsCalculator().apply(base_type).stride; + if(extended_align) + stride = (stride+15)&~15U; writer.write_op_decorate(array_type_id, DECO_ARRAY_STRIDE, stride); } @@ -382,17 +444,13 @@ SpirVGenerator::Id SpirVGenerator::get_variable_type_id(const VariableDeclaratio if(const BasicTypeDeclaration *basic = dynamic_cast(var.type_declaration)) if(basic->kind==BasicTypeDeclaration::ARRAY) { - Id size_id = 0; - if(var.array_size) - { - SetFlag set_const(constant_expression); - r_expression_result_id = 0; - var.array_size->visit(*this); - size_id = r_expression_result_id; - } - else - size_id = get_constant_id(get_standard_type_id(BasicTypeDeclaration::INT, 1), 1); - return get_array_type_id(*basic->base_type, size_id); + if(!var.array_size) + throw logic_error("array without size"); + + SetFlag set_const(constant_expression); + r_expression_result_id = 0; + var.array_size->visit(*this); + return get_array_type_id(*basic->base_type, r_expression_result_id, basic->extended_alignment); } return get_id(*var.type_declaration); @@ -411,7 +469,7 @@ SpirVGenerator::Id SpirVGenerator::get_load_id(VariableDeclaration &var) void SpirVGenerator::prune_loads(Id min_id) { - for(map::iterator i=variable_load_ids.begin(); i!=variable_load_ids.end(); ) + for(auto i=variable_load_ids.begin(); i!=variable_load_ids.end(); ) { if(i->second>=min_id) variable_load_ids.erase(i++); @@ -497,8 +555,8 @@ SpirVGenerator::Id SpirVGenerator::write_construct(Id type_id, const Id *elem_id void SpirVGenerator::visit(Block &block) { - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) - (*i)->visit(*this); + for(const RefPtr &s: block.body) + s->visit(*this); } void SpirVGenerator::visit(Literal &literal) @@ -528,8 +586,17 @@ void SpirVGenerator::visit(VariableReference &var) r_constant_result = false; if(composite_access) { - r_composite_base = var.declaration; r_expression_result_id = 0; + if(assignment_source_id) + variable_load_ids.erase(var.declaration); + else + { + auto i = variable_load_ids.find(var.declaration); + if(i!=variable_load_ids.end()) + r_expression_result_id = i->second; + } + if(!r_expression_result_id) + r_composite_base = var.declaration; } else if(assignment_source_id) { @@ -541,16 +608,6 @@ void SpirVGenerator::visit(VariableReference &var) r_expression_result_id = get_load_id(*var.declaration); } -void SpirVGenerator::visit(InterfaceBlockReference &iface) -{ - if(!composite_access || !current_function) - throw internal_error("invalid interface block reference"); - - r_composite_base = iface.declaration; - r_expression_result_id = 0; - r_constant_result = false; -} - void SpirVGenerator::generate_composite_access(TypeDeclaration &result_type) { Opcode opcode; @@ -562,13 +619,13 @@ void SpirVGenerator::generate_composite_access(TypeDeclaration &result_type) throw internal_error("composite access through pointer in constant context"); Id int32_type_id = get_standard_type_id(BasicTypeDeclaration::INT, 1); - for(vector::iterator i=r_composite_chain.begin(); i!=r_composite_chain.end(); ++i) - *i = (*i<0x400000 ? get_constant_id(int32_type_id, static_cast(*i)) : *i&0x3FFFFF); + for(unsigned &i: r_composite_chain) + i = (i<0x400000 ? get_constant_id(int32_type_id, static_cast(i)) : i&0x3FFFFF); /* Find the storage class of the base and obtain appropriate pointer type for the result. */ const Declaration &base_decl = get_item(declared_ids, r_composite_base); - map::const_iterator i = pointer_type_ids.begin(); + auto i = pointer_type_ids.begin(); for(; (i!=pointer_type_ids.end() && i->second!=base_decl.type_id); ++i) ; if(i==pointer_type_ids.end()) throw internal_error("could not find storage class"); @@ -580,18 +637,18 @@ void SpirVGenerator::generate_composite_access(TypeDeclaration &result_type) throw internal_error("assignment to temporary composite"); else { - for(vector::iterator i=r_composite_chain.begin(); i!=r_composite_chain.end(); ++i) - for(map::iterator j=constant_ids.begin(); (*i>=0x400000 && j!=constant_ids.end()); ++j) - if(j->second==(*i&0x3FFFFF)) - *i = j->first.int_value; + for(unsigned &i: r_composite_chain) + for(auto j=constant_ids.begin(); (i>=0x400000 && j!=constant_ids.end()); ++j) + if(j->second==(i&0x3FFFFF)) + i = j->first.int_value; opcode = OP_COMPOSITE_EXTRACT; } Id access_id = begin_expression(opcode, access_type_id, 1+r_composite_chain.size()); writer.write(r_composite_base_id); - for(vector::const_iterator i=r_composite_chain.begin(); i!=r_composite_chain.end(); ++i) - writer.write(*i); + for(unsigned i: r_composite_chain) + writer.write(i); end_expression(opcode); r_constant_result = false; @@ -693,6 +750,9 @@ void SpirVGenerator::visit(Swizzle &swizzle) void SpirVGenerator::visit(UnaryExpression &unary) { + if(composite_access) + return visit_isolated(unary); + unary.expression->visit(*this); char oper = unary.oper->token[0]; @@ -777,6 +837,8 @@ void SpirVGenerator::visit(BinaryExpression &binary) visit_isolated(*binary.right); return visit_composite(*binary.left, 0x400000|r_expression_result_id, *binary.type); } + else if(composite_access) + return visit_isolated(binary); if(assignment_source_id) throw internal_error("invalid binary expression in assignment target"); @@ -855,9 +917,10 @@ void SpirVGenerator::visit(BinaryExpression &binary) compare_id = write_construct(bool_vec_type_id, column_ids, n_elems); } + else + throw internal_error("unsupported types for non-scalar equality comparison"); - if(compare_id) - r_expression_result_id = write_expression(combine_op, result_type_id, compare_id); + r_expression_result_id = write_expression(combine_op, result_type_id, compare_id); return; } } @@ -1001,6 +1064,8 @@ void SpirVGenerator::visit(Assignment &assign) void SpirVGenerator::visit(TernaryExpression &ternary) { + if(composite_access) + return visit_isolated(ternary); if(constant_expression) { ternary.condition->visit(*this); @@ -1028,16 +1093,22 @@ void SpirVGenerator::visit(TernaryExpression &ternary) writer.write_op(content.function_body, OP_SELECTION_MERGE, merge_block_id, 0); // Selection control (none) writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, condition_id, true_label_id, false_label_id); + std::map saved_load_ids = variable_load_ids; + writer.write_op_label(true_label_id); ternary.true_expr->visit(*this); Id true_result_id = r_expression_result_id; + true_label_id = writer.get_current_block(); writer.write_op(content.function_body, OP_BRANCH, merge_block_id); + swap(saved_load_ids, variable_load_ids); writer.write_op_label(false_label_id); ternary.false_expr->visit(*this); Id false_result_id = r_expression_result_id; + false_label_id = writer.get_current_block(); writer.write_op_label(merge_block_id); + prune_loads(true_label_id); r_expression_result_id = begin_expression(OP_PHI, get_id(*ternary.type), 4); writer.write(true_result_id); writer.write(true_label_id); @@ -1060,9 +1131,9 @@ void SpirVGenerator::visit(FunctionCall &call) vector argument_ids; argument_ids.reserve(call.arguments.size()); bool all_args_const = true; - for(NodeArray::const_iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) + for(const RefPtr &a: call.arguments) { - (*i)->visit(*this); + a->visit(*this); argument_ids.push_back(r_expression_result_id); all_args_const &= r_constant_result; } @@ -1078,8 +1149,8 @@ void SpirVGenerator::visit(FunctionCall &call) else if(call.declaration->source==BUILTIN_SOURCE) { string arg_types; - for(NodeArray::const_iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) - if(BasicTypeDeclaration *basic_arg = dynamic_cast((*i)->type)) + for(const RefPtr &a: call.arguments) + if(BasicTypeDeclaration *basic_arg = dynamic_cast(a->type)) { BasicTypeDeclaration &elem_arg = *get_element_type(*basic_arg); switch(elem_arg.kind) @@ -1096,6 +1167,9 @@ void SpirVGenerator::visit(FunctionCall &call) if(builtin_info->function==call.name && (!builtin_info->arg_types[0] || builtin_info->arg_types==arg_types)) break; + if(builtin_info->capability) + use_capability(static_cast(builtin_info->capability)); + if(builtin_info->opcode) { Opcode opcode; @@ -1132,14 +1206,14 @@ void SpirVGenerator::visit(FunctionCall &call) { r_expression_result_id = begin_expression(OP_FUNCTION_CALL, result_type_id, 1+call.arguments.size()); writer.write(get_id(*call.declaration->definition)); - for(vector::const_iterator i=argument_ids.begin(); i!=argument_ids.end(); ++i) - writer.write(*i); + for(Id i: argument_ids) + writer.write(i); end_expression(OP_FUNCTION_CALL); // Any global variables the called function uses might have changed value set dependencies = DependencyCollector().apply(*call.declaration->definition); - for(set::const_iterator i=dependencies.begin(); i!=dependencies.end(); ++i) - if(const VariableDeclaration *var = dynamic_cast(*i)) + for(Node *n: dependencies) + if(const VariableDeclaration *var = dynamic_cast(n)) variable_load_ids.erase(var); } } @@ -1177,7 +1251,7 @@ void SpirVGenerator::visit_constructor(FunctionCall &call, const vector &arg Id zero_id = get_constant_id(get_id(elem), 0.0f); for(unsigned i=0; i &argument_ids) +{ + if(argument_ids.size()<1) + throw internal_error("invalid texture query call"); + + Opcode opcode; + if(call.name=="textureSize") + opcode = OP_IMAGE_QUERY_SIZE_LOD; + else if(call.name=="imageSize") + opcode = OP_IMAGE_QUERY_SIZE; + else if(call.name=="textureQueryLod") + opcode = OP_IMAGE_QUERY_LOD; + else if(call.name=="textureQueryLevels") + opcode = OP_IMAGE_QUERY_LEVELS; + else if(call.name=="textureSamples" || call.name=="imageSamples") + opcode = OP_IMAGE_QUERY_SAMPLES; + else + throw internal_error("invalid texture query call"); + + ImageTypeDeclaration &image_arg0 = dynamic_cast(*call.arguments[0]->type); + + Id image_id; + if(image_arg0.sampled && opcode!=OP_IMAGE_QUERY_LOD) + { + Id image_type_id = get_item(image_type_ids, get_id(image_arg0)); + image_id = write_expression(OP_IMAGE, image_type_id, argument_ids[0]); + } + else + image_id = argument_ids[0]; + + Id result_type_id = get_id(*call.type); + r_expression_result_id = begin_expression(opcode, result_type_id, argument_ids.size()); + writer.write(image_id); + for(unsigned i=1; i &argument_ids) { if(argument_ids.size()<2) @@ -1330,17 +1442,63 @@ void SpirVGenerator::visit_builtin_texture(FunctionCall &call, const vector end_expression(opcode); } -void SpirVGenerator::visit_builtin_texel_fetch(FunctionCall &call, const vector &argument_ids) +void SpirVGenerator::visit_builtin_texture_fetch(FunctionCall &call, const vector &argument_ids) +{ + ImageTypeDeclaration &image = dynamic_cast(*call.arguments[0]->type); + + Opcode opcode; + if(call.name=="texelFetch") + opcode = OP_IMAGE_FETCH; + else if(call.name=="imageLoad") + opcode = OP_IMAGE_READ; + else + throw internal_error("invalid texture fetch call"); + + bool need_sample = image.multisample; + bool need_lod = (opcode==OP_IMAGE_FETCH && !need_sample); + + if(argument_ids.size()!=2U+need_sample+need_lod) + throw internal_error("invalid texture fetch call"); + + Id image_id; + if(image.sampled) + { + Id image_type_id = get_item(image_type_ids, get_id(image)); + image_id = write_expression(OP_IMAGE, image_type_id, argument_ids[0]); + } + else + image_id = argument_ids[0]; + + r_expression_result_id = begin_expression(opcode, get_id(*call.type), 2+(need_lod|need_sample)+need_lod+need_sample); + writer.write(image_id); + writer.write(argument_ids[1]); + if(need_lod || need_sample) + { + writer.write(need_lod*0x02 | need_sample*0x40); + writer.write(argument_ids.back()); + } + end_expression(opcode); +} + +void SpirVGenerator::visit_builtin_texture_store(FunctionCall &call, const vector &argument_ids) { if(argument_ids.size()!=3) - throw internal_error("invalid texelFetch call"); + throw internal_error("invalid texture store call"); + + const ImageTypeDeclaration &image = dynamic_cast(*call.arguments[0]->type); - r_expression_result_id = begin_expression(OP_IMAGE_FETCH, get_id(*call.type), 4); + begin_expression(OP_IMAGE_WRITE, get_id(*call.type), 3+image.multisample*2); for(unsigned i=0; i<2; ++i) writer.write(argument_ids[i]); - writer.write(2); // Lod writer.write(argument_ids.back()); - end_expression(OP_IMAGE_FETCH); + if(image.multisample) + { + writer.write(0x40); // Sample + writer.write(argument_ids[2]); + } + end_expression(OP_IMAGE_WRITE); + + r_expression_result_id = 0; } void SpirVGenerator::visit_builtin_interpolate(FunctionCall &call, const vector &argument_ids) @@ -1361,14 +1519,12 @@ void SpirVGenerator::visit_builtin_interpolate(FunctionCall &call, const vector< else throw internal_error("invalid interpolate call"); - use_capability(CAP_INTERPOLATION_FUNCTION); - Id ext_id = import_extension("GLSL.std.450"); r_expression_result_id = begin_expression(OP_EXT_INST, get_id(*call.type)); writer.write(ext_id); writer.write(opcode); writer.write(get_id(*var->declaration)); - for(vector::const_iterator i=argument_ids.begin(); ++i!=argument_ids.end(); ) + for(auto i=argument_ids.begin(); ++i!=argument_ids.end(); ) writer.write(*i); end_expression(OP_EXT_INST); } @@ -1385,11 +1541,11 @@ void SpirVGenerator::visit(InterfaceLayout &layout) bool SpirVGenerator::check_duplicate_type(TypeDeclaration &type) { - for(map::const_iterator i=declared_ids.begin(); i!=declared_ids.end(); ++i) - if(TypeDeclaration *type2 = dynamic_cast(i->first)) + for(const auto &kvp: declared_ids) + if(TypeDeclaration *type2 = dynamic_cast(kvp.first)) if(TypeComparer().apply(type, *type2)) { - insert_unique(declared_ids, &type, i->second); + insert_unique(declared_ids, &type, kvp.second); return true; } @@ -1450,6 +1606,7 @@ void SpirVGenerator::visit(ImageTypeDeclaration &image) return; Id type_id = allocate_id(image, 0); + SpirVFormat format = get_format(image.format); Id image_id = (image.sampled ? next_id++ : type_id); writer.begin_op(content.globals, OP_TYPE_IMAGE, 9); @@ -1458,21 +1615,28 @@ void SpirVGenerator::visit(ImageTypeDeclaration &image) writer.write(image.dimensions-1); writer.write(image.shadow); writer.write(image.array); - writer.write(false); // Multisample + writer.write(image.multisample); writer.write(image.sampled ? 1 : 2); - writer.write(0); // Format (unknown) + writer.write(format); writer.end_op(OP_TYPE_IMAGE); if(image.sampled) { writer.write_op_name(type_id, image.name); writer.write_op(content.globals, OP_TYPE_SAMPLED_IMAGE, type_id, image_id); + insert_unique(image_type_ids, type_id, image_id); } if(image.dimensions==ImageTypeDeclaration::ONE) use_capability(image.sampled ? CAP_SAMPLED_1D : CAP_IMAGE_1D); else if(image.dimensions==ImageTypeDeclaration::CUBE && image.array) use_capability(image.sampled ? CAP_SAMPLED_CUBE_ARRAY : CAP_IMAGE_CUBE_ARRAY); + + if(image.multisample && !image.sampled) + use_capability(CAP_STORAGE_IMAGE_MULTISAMPLE); + + if(format>=FORMAT_RG32F && format<=FORMAT_R8_SNORM) + use_capability(CAP_STORAGE_IMAGE_EXTENDED_FORMATS); } void SpirVGenerator::visit(StructDeclaration &strct) @@ -1481,17 +1645,17 @@ void SpirVGenerator::visit(StructDeclaration &strct) return; Id type_id = allocate_id(strct, 0); - writer.write_op_name(type_id, strct.name); + writer.write_op_name(type_id, (strct.block_name.empty() ? strct.name : strct.block_name)); - if(strct.interface_block) + if(!strct.block_name.empty()) writer.write_op_decorate(type_id, DECO_BLOCK); - bool builtin = (strct.interface_block && !strct.interface_block->block_name.compare(0, 3, "gl_")); + bool builtin = !strct.block_name.compare(0, 3, "gl_"); vector member_type_ids; member_type_ids.reserve(strct.members.body.size()); - for(NodeList::const_iterator i=strct.members.body.begin(); i!=strct.members.body.end(); ++i) + for(const RefPtr &s: strct.members.body) { - const VariableDeclaration *var = dynamic_cast(i->get()); + const VariableDeclaration *var = dynamic_cast(s.get()); if(!var) continue; @@ -1509,14 +1673,13 @@ void SpirVGenerator::visit(StructDeclaration &strct) { if(var->layout) { - const vector &qualifiers = var->layout->qualifiers; - for(vector::const_iterator j=qualifiers.begin(); j!=qualifiers.end(); ++j) + for(const Layout::Qualifier &q: var->layout->qualifiers) { - if(j->name=="offset") - writer.write_op_member_decorate(type_id, index, DECO_OFFSET, j->value); - else if(j->name=="column_major") + if(q.name=="offset") + writer.write_op_member_decorate(type_id, index, DECO_OFFSET, q.value); + else if(q.name=="column_major") writer.write_op_member_decorate(type_id, index, DECO_COL_MAJOR); - else if(j->name=="row_major") + else if(q.name=="row_major") writer.write_op_member_decorate(type_id, index, DECO_ROW_MAJOR); } } @@ -1534,23 +1697,13 @@ void SpirVGenerator::visit(StructDeclaration &strct) writer.begin_op(content.globals, OP_TYPE_STRUCT); writer.write(type_id); - for(vector::const_iterator i=member_type_ids.begin(); i!=member_type_ids.end(); ++i) - writer.write(*i); + for(Id i: member_type_ids) + writer.write(i); writer.end_op(OP_TYPE_STRUCT); } void SpirVGenerator::visit(VariableDeclaration &var) { - const vector *layout_ql = (var.layout ? &var.layout->qualifiers : 0); - - int spec_id = -1; - if(layout_ql) - { - for(vector::const_iterator i=layout_ql->begin(); (spec_id<0 && i!=layout_ql->end()); ++i) - if(i->name=="constant_id") - spec_id = i->value; - } - Id type_id = get_variable_type_id(var); Id var_id; @@ -1559,26 +1712,42 @@ void SpirVGenerator::visit(VariableDeclaration &var) if(!var.init_expression) throw internal_error("const variable without initializer"); + int spec_id = get_layout_value(var.layout.get(), "constant_id"); + Id *spec_var_id = (spec_id>=0 ? &declared_spec_ids[spec_id] : 0); + if(spec_id>=0 && *spec_var_id) + { + insert_unique(declared_ids, &var, Declaration(*spec_var_id, type_id)); + return; + } + SetFlag set_const(constant_expression); SetFlag set_spec(spec_constant, spec_id>=0); r_expression_result_id = 0; var.init_expression->visit(*this); var_id = r_expression_result_id; insert_unique(declared_ids, &var, Declaration(var_id, type_id)); - writer.write_op_decorate(var_id, DECO_SPEC_ID, spec_id); - - /* It's unclear what should be done if a specialization constant is - initialized with anything other than a literal. GLSL doesn't seem to - prohibit that but SPIR-V says OpSpecConstantOp can't be updated via - specialization. */ + if(spec_id>=0) + { + writer.write_op_decorate(var_id, DECO_SPEC_ID, spec_id); + *spec_var_id = var_id; + } } else { - StorageClass storage = (current_function ? STORAGE_FUNCTION : get_interface_storage(var.interface, false)); + bool push_const = has_layout_qualifier(var.layout.get(), "push_constant"); + + StorageClass storage; + if(current_function) + storage = STORAGE_FUNCTION; + else if(push_const) + storage = STORAGE_PUSH_CONSTANT; + else + storage = get_interface_storage(var.interface, var.block_declaration); + Id ptr_type_id = get_pointer_type_id(type_id, storage); if(var.interface=="uniform") { - Id &uni_id = declared_uniform_ids["v"+var.name]; + Id &uni_id = declared_uniform_ids[var.block_declaration ? "b"+var.block_declaration->block_name : "v"+var.name]; if(uni_id) { insert_unique(declared_ids, &var, Declaration(uni_id, ptr_type_id)); @@ -1609,61 +1778,39 @@ void SpirVGenerator::visit(VariableDeclaration &var) writer.write(init_id); writer.end_op(OP_VARIABLE); - if(layout_ql) + if(var.layout) { - for(vector::const_iterator i=layout_ql->begin(); i!=layout_ql->end(); ++i) + for(const Layout::Qualifier &q: var.layout->qualifiers) { - if(i->name=="location") - writer.write_op_decorate(var_id, DECO_LOCATION, i->value); - else if(i->name=="set") - writer.write_op_decorate(var_id, DECO_DESCRIPTOR_SET, i->value); - else if(i->name=="binding") - writer.write_op_decorate(var_id, DECO_BINDING, i->value); + if(q.name=="location") + writer.write_op_decorate(var_id, DECO_LOCATION, q.value); + else if(q.name=="set") + writer.write_op_decorate(var_id, DECO_DESCRIPTOR_SET, q.value); + else if(q.name=="binding") + writer.write_op_decorate(var_id, DECO_BINDING, q.value); } } + if(!var.block_declaration && !var.name.compare(0, 3, "gl_")) + { + BuiltinSemantic semantic = get_builtin_semantic(var.name); + writer.write_op_decorate(var_id, DECO_BUILTIN, semantic); + } + if(var.interpolation=="flat") + writer.write_op_decorate(var_id, DECO_FLAT); + if(var.sampling=="centroid") + writer.write_op_decorate(var_id, DECO_CENTROID); + if(var.sampling=="patch") + writer.write_op_decorate(var_id, DECO_PATCH); if(init_id && current_function) - writer.write_op(content.function_body, OP_STORE, var_id, init_id); - } - - writer.write_op_name(var_id, var.name); -} - -void SpirVGenerator::visit(InterfaceBlock &iface) -{ - StorageClass storage = get_interface_storage(iface.interface, true); - Id type_id; - if(iface.array) - type_id = get_array_type_id(*iface.struct_declaration, 0); - else - type_id = get_id(*iface.struct_declaration); - Id ptr_type_id = get_pointer_type_id(type_id, storage); - - Id block_id; - if(iface.interface=="uniform") - { - Id &uni_id = declared_uniform_ids["b"+iface.block_name]; - if(uni_id) { - insert_unique(declared_ids, &iface, Declaration(uni_id, ptr_type_id)); - return; + writer.write_op(content.function_body, OP_STORE, var_id, init_id); + variable_load_ids[&var] = init_id; } - - uni_id = block_id = allocate_id(iface, ptr_type_id); } - else - block_id = allocate_id(iface, ptr_type_id); - writer.write_op_name(block_id, iface.instance_name); - - writer.write_op(content.globals, OP_VARIABLE, ptr_type_id, block_id, storage); - if(iface.layout) - { - const vector &qualifiers = iface.layout->qualifiers; - for(vector::const_iterator i=qualifiers.begin(); i!=qualifiers.end(); ++i) - if(i->name=="binding") - writer.write_op_decorate(block_id, DECO_BINDING, i->value); - } + if(var.name.find(' ')==string::npos) + writer.write_op_name(var_id, var.name); } void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id) @@ -1672,56 +1819,94 @@ void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id) switch(stage->type) { case Stage::VERTEX: writer.write(0); break; + case Stage::TESS_CONTROL: writer.write(1); break; + case Stage::TESS_EVAL: writer.write(2); break; case Stage::GEOMETRY: writer.write(3); break; case Stage::FRAGMENT: writer.write(4); break; + case Stage::COMPUTE: writer.write(5); break; default: throw internal_error("unknown stage"); } writer.write(func_id); writer.write_string(func.name); set dependencies = DependencyCollector().apply(func); - for(set::const_iterator i=dependencies.begin(); i!=dependencies.end(); ++i) - { - if(const VariableDeclaration *var = dynamic_cast(*i)) - { + for(Node *n: dependencies) + if(const VariableDeclaration *var = dynamic_cast(n)) if(!var->interface.empty()) - writer.write(get_id(**i)); - } - else if(dynamic_cast(*i)) - writer.write(get_id(**i)); - } + writer.write(allocate_forward_id(*n)); writer.end_op(OP_ENTRY_POINT); if(stage->type==Stage::FRAGMENT) - writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_ORIGIN_LOWER_LEFT); + { + SpirVExecutionMode origin = (features.target_api==VULKAN ? EXEC_ORIGIN_UPPER_LEFT : EXEC_ORIGIN_LOWER_LEFT); + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, origin); + } else if(stage->type==Stage::GEOMETRY) + { use_capability(CAP_GEOMETRY); + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INVOCATIONS, 1); + } + else if(stage->type==Stage::TESS_CONTROL || stage->type==Stage::TESS_EVAL) + { + use_capability(CAP_TESSELLATION); + } - for(vector::const_iterator i=interface_layouts.begin(); i!=interface_layouts.end(); ++i) + unsigned local_size[3] = { 0, 1, 1 }; + + for(const InterfaceLayout *i: interface_layouts) { - const vector &qualifiers = (*i)->layout.qualifiers; - for(vector::const_iterator j=qualifiers.begin(); j!=qualifiers.end(); ++j) + for(const Layout::Qualifier &q: i->layout.qualifiers) { - if(j->name=="point") + if(q.name=="point") writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, - ((*i)->interface=="in" ? EXEC_INPUT_POINTS : EXEC_OUTPUT_POINTS)); - else if(j->name=="lines") + (i->interface=="in" ? EXEC_INPUT_POINTS : EXEC_OUTPUT_POINTS)); + else if(q.name=="lines") writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_LINES); - else if(j->name=="lines_adjacency") + else if(q.name=="lines_adjacency") writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_LINES_ADJACENCY); - else if(j->name=="triangles") + else if(q.name=="triangles") writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_TRIANGLES); - else if(j->name=="triangles_adjacency") + else if(q.name=="triangles_adjacency") writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_TRIANGLES_ADJACENCY); - else if(j->name=="line_strip") + else if(q.name=="quads") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_QUADS); + else if(q.name=="isolines") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_ISOLINES); + else if(q.name=="line_strip") writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_LINE_STRIP); - else if(j->name=="triangle_strip") + else if(q.name=="triangle_strip") writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_TRIANGLE_STRIP); - else if(j->name=="max_vertices") - writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_VERTICES, j->value); + else if(q.name=="max_vertices" || q.name=="vertices") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_VERTICES, q.value); + else if(q.name=="cw") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_VERTEX_ORDER_CW); + else if(q.name=="ccw") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_VERTEX_ORDER_CCW); + else if(q.name=="equal_spacing") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_SPACING_EQUAL); + else if(q.name=="fractional_even_spacing") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_SPACING_FRACTIONAL_EVEN); + else if(q.name=="fractional_odd_spacing") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_SPACING_FRACTIONAL_ODD); + else if(q.name=="local_size_x") + local_size[0] = q.value; + else if(q.name=="local_size_y") + local_size[1] = q.value; + else if(q.name=="local_size_z") + local_size[2] = q.value; } } + + if(stage->type==Stage::COMPUTE && local_size[0]) + { + writer.begin_op(content.exec_modes, OP_EXECUTION_MODE); + writer.write(func_id); + writer.write(EXEC_LOCAL_SIZE); + for(unsigned j=0; j<3; ++j) + writer.write(local_size[j]); + writer.end_op(OP_EXECUTION_MODE); + } } void SpirVGenerator::visit(FunctionDeclaration &func) @@ -1738,8 +1923,8 @@ void SpirVGenerator::visit(FunctionDeclaration &func) Id return_type_id = get_id(*func.return_type_declaration); vector param_type_ids; param_type_ids.reserve(func.parameters.size()); - for(NodeArray::const_iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) - param_type_ids.push_back(get_variable_type_id(**i)); + for(const RefPtr &p: func.parameters) + param_type_ids.push_back(get_variable_type_id(*p)); string sig_with_return = func.return_type+func.signature; Id &type_id = function_type_ids[sig_with_return]; @@ -1749,8 +1934,8 @@ void SpirVGenerator::visit(FunctionDeclaration &func) writer.begin_op(content.globals, OP_TYPE_FUNCTION); writer.write(type_id); writer.write(return_type_id); - for(vector::const_iterator i=param_type_ids.begin(); i!=param_type_ids.end(); ++i) - writer.write(*i); + for(unsigned i: param_type_ids) + writer.write(i); writer.end_op(OP_TYPE_FUNCTION); writer.write_op_name(type_id, sig_with_return); @@ -1773,15 +1958,17 @@ void SpirVGenerator::visit(FunctionDeclaration &func) { Id param_id = allocate_id(*func.parameters[i], param_type_ids[i]); writer.write_op(content.functions, OP_FUNCTION_PARAMETER, param_type_ids[i], param_id); + writer.write_op_name(param_id, func.parameters[i]->name); // TODO This is probably incorrect if the parameter is assigned to. variable_load_ids[func.parameters[i].get()] = param_id; } + reachable = true; writer.begin_function_body(next_id++); SetForScope set_func(current_function, &func); func.body.visit(*this); - if(writer.has_current_block()) + if(writer.get_current_block()) { if(!reachable) writer.write_op(content.function_body, OP_UNREACHABLE); @@ -1808,9 +1995,11 @@ void SpirVGenerator::visit(Conditional &cond) writer.write_op(content.function_body, OP_SELECTION_MERGE, merge_block_id, 0); // Selection control (none) writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, r_expression_result_id, true_label_id, false_label_id); + std::map saved_load_ids = variable_load_ids; + writer.write_op_label(true_label_id); cond.body.visit(*this); - if(writer.has_current_block()) + if(writer.get_current_block()) writer.write_op(content.function_body, OP_BRANCH, merge_block_id); bool reachable_if_true = reachable; @@ -1818,6 +2007,7 @@ void SpirVGenerator::visit(Conditional &cond) reachable = true; if(!cond.else_body.body.empty()) { + swap(saved_load_ids, variable_load_ids); writer.write_op_label(false_label_id); cond.else_body.visit(*this); reachable |= reachable_if_true; @@ -1832,7 +2022,9 @@ void SpirVGenerator::visit(Iteration &iter) if(iter.init_statement) iter.init_statement->visit(*this); - variable_load_ids.clear(); + for(Node *n: AssignmentCollector().apply(iter)) + if(VariableDeclaration *var = dynamic_cast(n)) + variable_load_ids.erase(var); Id header_id = next_id++; Id continue_id = next_id++; @@ -1861,6 +2053,7 @@ void SpirVGenerator::visit(Iteration &iter) writer.write_op(content.function_body, OP_BRANCH, header_id); writer.write_op_label(merge_block_id); + prune_loads(header_id); reachable = true; }