Skip to content

Inner Workings

MaximV88 edited this page Apr 14, 2020 · 1 revision

Parsing

Aluminum uses a Parser object to iterate through provided type tree until it reaches the leafs.
The iterated objects are wrapped in an associated enum that provides easy access to children:

enum MetalType: Hashable {
    case argument(MTLArgument)
    case array(MTLArrayType)
    case `struct`(MTLStructType)
    case pointer(MTLPointerType)
    case structMember(MTLStructMember)
}

where each case is a different Metal reflection object.

Convert to DataType

Once parser reaches the leafs the entire path is iterated with a DataTypeIterator.
This is an iterator that internally uses an array of DataTypeRecognizer in order to identify different types of Metal structures to allow correct binding. The DataType is much easier to work with since each case is a single item (composed of several MetalType).

Currently the known DataTypes are:

enum DataType: Equatable {
    case argument(MTLArgument)
    case argumentContainingArgumentBuffer(MTLArgument, MTLPointerType)
    case textureArgument(MTLArgument)
    case samplerArgument(MTLArgument)
    case encodableArgument(MTLArgument)
    case argumentBuffer(MTLPointerType)
    case structMember(MTLStructMember)
    case array(MTLArrayType)
    case buffer(MTLPointerType)
    case encodableBuffer(MTLPointerType)
    case metalArray(MTLArrayType, MTLStructMember)
    case atomicVariable(MTLStructMember)
}

DataType are parsed from a MetalType array, which results in DataType arrays. Internally the arrays are called paths (since a DataType array is like a path to a bindable target). The paths are referenced using a naming system.

Naming System

Very short:

  • .named: any non metal structure that has a name.
  • .indexed: arrays, and arguments that have arrays (more than 1 element).

Encoder internal paths

Once an encoder requests to encode something, the constructed named path references a DataType array which is used to understand what is the type at the last item, and how to access it (how to calculate offset or index).

For example: RootEncoder starts with a hidden root path that is composed of it's argument name (i.e. .named("argument")).
When we wish to encode something the encoder uses the request to construct a path.

Here the used 'visual' path (which is parsed by regex to internally transform into [.index(0)]) is used to call:

let childEncoder = encoder.childEncoder(for: "[0]")

which will return a wrapped argument encoder (ArgumentBufferEncoder) for index 0 in it's array.
Internally the child encoder will store the path [.named("argument"), .index(0)] and will use it as it's root path.

Clone this wiki locally