Variable Types

Data Types

Variables in kernels can hold various data types depending on what is required.

int

This is an integer type for storing whole positive and negative numbers.

For example: -1, 0, 1, 2, 3 etc.

float

This is a floating point type for storing whole and/or partial positive and negative numbers.

For example: -1.0f, -0.5f, 0.0f, 0.5f, 1.0f etc. The f suffix indicates that these are floating point values.

bool

This is a boolean type for storing true or false.

Vector types

Vector types are a fixed-length sequence of the same scalar data type. In Blink, vectors can be either int or float types with 1-4 components int1, float3 etc. Individual elements of a vector can be accessed either by swizzling or subscripting operators.

See the Vectors Specification Kernel for an example of the following vector features used in a single kernel.

Creation

There are a few ways to construct and initialise a vector.

// C++ style constructor. Makes an int2 vector (5, 10).
int2 i2(5, 10);
// Initializer list construction. Makes a float3 vector (2.1f, 2.2f, 2.3f).
float3 f3{2.1f, 2.2f, 2.3f};
// Assignment constructor. Makes a float4 vector (1.0f, 2.0f, 3.0f, 4.0f).
float4 f4 = float4(1.0f, 2.0f, 3.0f, 4.0f);
// Singleton constructor. A constructor for a vector with multiple components
// can be constructed with a single argument to produce a vector with a single
// value for all elements. Makes an int4 vector (-10, -10, -10, -10).
int4 i4 = int4(-10);

Element Access

Individual elements of a vector can be accessed with a swizzle operator.

float4 vec4 = float4(1.1f, 1.2f, 1.3f, 1.4f);
// Reading from each component.
float comp0 = vec4.x;
float comp1 = vec4.y;
float comp2 = vec4.z;
float comp3 = vec4.w;
// Assigning to a specific component.
// New value of vec4 is now float4(1.1f, 1.2f, 23.0f, 1.4f)
vec4.z = 23.0f;

Individual elements of a vector can be accessed with a subscript operator.

float4 vec4 = float4(1.1f, 1.2f, 1.3f, 1.4f);
// Reading from each component.
float comp0 = vec4[0];
float comp1 = vec4[1];
float comp2 = vec4[2];
float comp3 = vec4[3];
// Assigning to a specific component.
// New value of vec4 is now float4(1.1f, 1.2f, 23.0f, 1.4f)
vec4[2] = 23.0f;

It is recommended to prefer the swizzle operator over the subscript operator when possible for performance.

The subscript operator has the additional functionality of being able to access components only known at runtime through the use of variables. A common pattern in Blink involves iterating through some of the components in a vector.

// Iterate through and set first 3 components of the vector.
for (int c = 0; c < 3; c++) {
  vec4[c] = 0.5f;
}

Vector Operators

Operators applied on vectors are applied element-wise unless specified otherwise.

// Vector addition: int2(4, 8) + int2(2, 4) -> int2(6, 12)
int2 addVar = int2(4, 8) + int2(2, 4);
// Vector subtraction: int2(4, 8) - int2(2, 4) -> int2(2, 4)
int2 subVar = int2(4, 8) - int2(2, 4);
// Vector multiplication: int2(4, 8) * int2(2, 4) -> int2(8, 32)
int2 mulVar = int2(4, 8) * int2(2, 4);
// Vector division: int2(4, 8) / int2(2, 4) -> int2(2, 2)
int2 divVar = int2(4, 8) / int2(2, 4);
// Unary minus: -int2(4, 8) -> int2(-4, -8);
int2 unaryMinVar = -int2(4, 8);

Arrays

Arrays are set length, zero-indexed lists of variables of the same type. They allow you to create multiple of a single data type that can be referenced via one variable name.

Creation

Arrays can be of any length and can be initialised with default values or with defined values. For example:

bool data[20]; // Array with 20 default boolean values
int definedData[4] = {4, 3, 2, 1}; // Array with four specified integer values

You can not dynamically change the length of an array after it is created. The length defined when an array is created is the length it always will be. For Example int data[3] will always have a length of 3 int types.

Element Access

You can access each element of an array with the subscript [] operator. For example:

bool data[3];
data[1] = true;
bool element = data[1];

This example creates a three element array of boolean values called data, sets the middle (second) boolean value to true and then copies the middle value to a new boolean variable called element.

Using Arrays with Functions

Arrays can be passed to user functions. Array arguments are passed by reference so that changes to the array made by the function will affect the array in the calling function. Functions cannot have an array as their return type.

kernel ArrayFunctionExample : ImageComputationKernel<eComponentWise>
{
  Image<eRead> src;
  Image<eWrite> dst;

  void fillArray( int arr[], int size ) {
    for (int i = 0; i < size; ++i) {
      arr[i] = i;
    }
  }

  void init() {
    int exampleArray[4];
    fillArray(exampleArray, 4);
  }

  void process() {
    dst() = src(); // passthrough
  }
};

This small example kernel in its init() function creates the default float array exampleArray with a length of 4. This array is then passed, along with the array size, to the fillArray function which proceeds to fill the array with integers.

Matrices

There are two square row-major matrix types available in Blink kernels: float3x3 and float4x4. See the Matrices Specification Kernel for an example of the following matrix features used in a single kernel.

Matrix Constructors

Matrices can be constructed with their elements set either by using an initialising list or regular constructor. Matrices can also be left uninitialised and set later.

float3x3 m3x3 = {1.0f, 2.0f, 3.0f,
                 4.0f, 5.0f, 6.0f,
                 7.0f, 8.0f, 9.0f};

float4x4 m4x4 (1.0f, 2.0f, 3.0f, 4.0f,
               5.0f, 6.0f, 7.0f, 8.0f,
               9.0f, 10.0f, 11.0f, 12.0f,
               13.0f, 14.0f, 15.0f, 16.0f);

Access and Initialisation

Matrices defined in the process method can have their elements updated in a number of useful ways.

Operator [][]

Values from a matrix can be accessed directly with the double subscript operator [row][column]. Individual values can be updated separately with the double subscript operator.

float c01 = m3x3[0][1];
m3x3[1][1] = 3.4f;
setElements(float...)

Updates the entire matrix.

m3x3.setElements(2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f);
setArray(float[N*N])

Use an array to update the matrix values. Ensure that the array is the same size as the matrix.

float a[3*3] = {2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f};
m3x3.setArray(a);

Matrix Transformation, Rotation and Translation Initialisation Methods

Common matrix patterns have special methods to set them to reduce the overhead of manual matrix construction.

setIdentity()

Creates the NxN identity matrix.

m3x3.setIdentity();
setTranslate(floatN translationVector)

Creates an identity matrix with a translation vector on the rightmost column.

m3x3.setTranslate(float3(1.0f, 1.0f, 1.0f));
setScale(floatN scaleVector)

Sets the matrix as a scale matrix. Creates a diagonal matrix with the values of the vector.

m3x3.setScale(float3(2.0f, 2.0f, 2.0f));
setRotate(float angle)

Creates a 3x3 rotation matrix for the input angle in radians for the 2D coordinate system (3x3 matrices only).

m3x3.setRotate(PI/4);
setRotateX(float angle)

Creates a 4x4 rotation matrix about the X axis for the input angle in radians for the 3D coordinate system (4x4 matrices only).

m4x4.setRotateX(PI/4);
setRotateY(float angle)

Creates a 4x4 rotation matrix about the Y axis for the input angle in radians for the 3D coordinate system (4x4 matrices only).

m4x4.setRotateY(PI/4);
setRotateZ(float angle)

Creates a 4x4 rotation matrix about the Z axis for the input angle in radians for the 3D coordinate system (4x4 matrices only).

m4x4.setRotateZ(PI/4);

Matrix Transformation, Rotation and Translation Methods

There are a number of methods the matrix object provides. Each of the following methods operates on the matrix in place as well as returning a reference for assigning other matrices. For example, mat1.transpose() will transpose the mat1 matrix and mat2 = mat1.transpose() will transpose the mat1 matrix and assign the result to mat2.

translate(floatN translationVector)

Creates a translation matrix from the translationVector argument and left multiplies the matrix in place.

m3x3.translate(float3(1.0f, 1.0f, 1.0f));
scale(floatN scaleVector)

Creates a scale matrix from the scaleVector argument and left multiplies the matrix in place.

m3x3.scale(float3(2.0f, 3.0f, 4.0f));
rotate(float angle)

Creates a rotation matrix from the angle argument and left multiplies the matrix in place (3x3 matrices only).

m3x3.rotate(PI/4);
rotateX(float angle)

Creates a rotation matrix from the angle argument about the X axis and left multiplies the matrix in place (4x4 matrices only).

m4x4.rotateX(PI/4);
rotateY(float angle)

Creates a rotation matrix from the angle argument about the Y axis and left multiplies the matrix in place (4x4 matrices only).

m4x4.rotateY(PI/4);
rotateZ(float angle)

Creates a rotation matrix from the angle argument about the Z axis left multiplies the matrix in place (4x4 matrices only).

m4x4.rotateZ(PI/4);
transpose()

Computes the transpose of the matrix in place.

m3x3.transpose();
invert()

Computes the inverse of the matrix in place. Ensure that it can be inverted before running this.

m3x3.invert();

Matrix Operators

Matrices support addition (+), subtraction (-) and multiplication (*) binary operators on matrices of the same size. Matrix-vector multiplication is supported for when a NxN matrix is right multiplied by a vector of length N.

/// Matrix operators.
float3x3 A = {1.0f, 5.0f, 1.0f, 1.0f, 1.0f, 3.0f, 1.0f, 1.0f, 1.0f};
float3x3 B = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f};
float3x3 C;
// Matrix addition.
C = A + B;
// Matrix subtraction.
C = A - B;
// Matrix * Matrix multiplication.
C = A * B;
// Matrix * Vector multiplication.
float3 AxV = A * float3(2.0f, 2.0f, 2.0f);