Apple's documentation has that:
Core Image Kernel Language Reference: Core Image Kernel Language.
Needless to say, Apple also has
Core Image Programming Guide: Introduction to Core Image Programming Guide and
Core Image Programming Guide: Creating Custom Filters.
You can test your kernel code in Quartz Composer using the filter Core Image Filter. Do cmd-I on it, go the the second item in the top popup menu, and you'll get a place to enter your filter source code.
I've actually written a custom-filter kernel, one that makes rosette-group or kaleidoscope patterns:
Code:
const float PI = 3.14159265358979323846;
const float TWO_PI = 2.0*PI;
kernel vec4 Rosette(sampler Image, vec2 Center, float Angle, float Number, float Reflect)
{
float TrueAngle = TWO_PI*Angle;
float ReptAngle = TWO_PI/Number;
float InvReptAngle = Number/TWO_PI;
vec2 Pos = samplerCoord(Image) - Center;
float PosLength = length(Pos);
float PosAngle = atan(Pos.y, Pos.x) - TrueAngle;
float RedPosAngle = mod(PosAngle* InvReptAngle,1.0);
RedPosAngle = compare(-Reflect, compare(0.5-RedPosAngle, 1.0-RedPosAngle, RedPosAngle), RedPosAngle);
PosAngle = RedPosAngle*ReptAngle;
Pos = PosLength*cossin(PosAngle + TrueAngle) + Center;
return sample(Image, Pos);
}
I've been meaning to do more, but I'd have to complete writing a self-contained version of that filter (kernel + info files). I'd have to see what sort of ROI setup it would need, for instance.
My experience so far:
The CI kernel has a float data type, but no others primitive ones. No booleans, characters, integers, or doubles. It's picky about numerical constants -- you have to write them as floats, even if they are integers: 1. or 1.0 instead of 1
But it does have some ways of grouping data: fixed-size arrays, structs, and vec2, vec3, and vec4 of floats.
I used not only some GLSL functions: length, atan, mod, etc., but also some CI ones: cossin, etc. One can also define one's own functions in it, and forward-declare them with prototype statements in ANSI-C/C++ fashion. However, I've had to define pi explicitly.
One can use a few C++ constructions, like const for constant values, and one can use both /* */ and // for comments.
Flow of control is very limited. One can only use if, for, do, and while statements if their control-statement outcomes can be determined at compile time, not at run time.
That may be why the CI kernel functions include compare(), defined as
compare(x,y,z) = x < 0 ? y : z
One can nest these functions; it seems that it calculates all the arg values, then does a conditional assignment.