Object Model [¶]
Object Model & Memory Layout.
Blend2D object model is a foundation of all Blend2D objects. It was designed only for Blend2D and it's not supposed to be used as a foundation of other libraries. The object model provides runtime reflection, small size optimization (SSO), and good performance. In general, it focuses on optimizing memory footprint by taking advantage of SSO storage, however, this makes the implementation more complex compared to a traditional non-SSO model.
Blend2D object model used by BLObjectCore consists of 16 bytes that have the following layout:
Which allows to have either static or dynamic instances:
- Static instance stores payload in object detail,
impl
is not a valid pointer and cannot be accessed. - Dynamic instance has a valid
impl
pointer having a content, which type depends on BLObjectType.
The layout was designed to provide the following properties:
- Reflection - any Blend2D object can be casted to a generic BLObjectCore or BLVarCore and inspected at runtime.
- Small string, container, and value optimization saves memory allocations (BLString, BLArray, BLBitSet).
- No atomic reference counting operations for small containers and default constructed objects without data.
- It's possible to store a floating point RGBA color (BLRgba) as f32_data, which uses all 16 bytes. The last value of the color, which describes alpha channel, cannot have a sign bit set (cannot be negative and cannot be NaN with sign).
32-bit Floating Point is represented the following way (32 bits):
Where:
- 'S' - Sign bit
- 'e' - Exponent bits (all bits must be '1' to form NaN).
- 'Q' - Mantissa bit that can be used to describe quiet and signaling NaNs, the value is not standardized (X86 and ARM use '1' for quiet NaN and '0' for signaling NaN).
- '.' - Mantissa bits.
Blend2D uses a sign bit to determine whether the data is BLRgba or object compatible. This design has been chosen, because we don't allow alpha values to be negative. When the sign bit is set it means that it's a type inherited from BLObjectCore. When the sign bit is not set the whole payload represents 128-bit BLRgba color, where alpha is not a negative number. It's designed in a way that 31 bits out of 32 can be used as payload that represents object type, object info flags, and additional type-dependent payload.
Object info value looks like this (also compared with floating point):
Where:
- 'M' - Object marker, forms a valid BLObject signature when set to '1'.
- 'D' - Dynamic flag - when set the Impl pointer is valid. When 'D' == '0' it means the object is in SSO mode, when 'D' == '1' it means it's in Dynamic mode.
- 'R' - Ref counted flag - when set together with 'M' and 'D' it makes it guaranteed that teh Impl pointer is ref-counted. Otherwise if 'D' is not set, 'R' flag can be used by the SSO representation to store another bit.
- 't' - Object type bits - 'ttttttt' forms a 7-bit type having possible values from 0 to 127, see BLObjectType.
- 'a' - Object 'a' payload (6 bits).
- 'b' - Object 'b' payload (4 bits).
- 'c' - Object 'c' payload (4 bits).
- 'p' - Object 'p' payload (8 bits).
- 'q' - Object 'q' payload (8 bits aliased with 'bbbbcccc' fields).
Common meaning of payload fields:
- 'a' - If the object is a container (BLArray, BLString) 'a' field always represents its size in SSO mode. If the object is a BLBitSet, 'a' field is combined with other fields to store a start word index or to mark a BitSet, which contains an SSO range instead of dense words.
- 'b' - If the object is a container (BLArray) 'b' field always represents its capacity in SSO mode except BLString, which doesn't store capacity in 'b' field and uses it as an additional SSO content byte on little endian targets (SSO capacity is then either 14 on little endian targets or 11 on big endian targets). This is possible as BL_OBJECT_TYPE_STRING must be identifier that has 2 low bits zero, which then makes it possible to use 'ttIRaaaa' as null terminator when the string length is 14 characters.
- 'c' - Used freely.
- 'p' - Used freely.
- 'q' - Used freely.
If the 'D' flag is '1' the following payload fields are used by the allocator (and thus cannot be used by the object):
- 'a' - Allocation adjustment (4 bits) - At the moment the field describes how many bytes (shifted) to subtract from Impl to get the real pointer returned by Impl allocator. Object deallocation relies on this offset.
Not all object support all defined flags, here is a little overview: