| IOLink 1.11.0

Loading...
Searching...
No Matches
View Extensions

# What are View Extensions ?

View extensions are a way to add new functionnalities for views without breaking the current ABI. If a view support a kind of extension, you can get it to access more information or services. You can get an extension this way:

std::shared_ptr<SomeExtension> extension = view->extension<SomeExtension>();
// we can now use the extension services
extension->someService();

This may seem a little complicated at first, but the nature of extensions make them this way. Usually shortcuts will be defined in the `View` class or its descendants, which will make them transparent for the user.

All classes that inherit from `Extension` must define a constant named `EXTENSION_ID` that is unique for each extension type, and is used when retrieving an extension from a view.

When choosing the identifier to use with your class, you must look at other defined identifiers to avoid collision. In addition, some ranges are reserved for specific usage:

- 0x0 to 0xFFFF: reserved for IOLink
- 0x10000 to 0xFFFFFFFF: reserved for external modules by the IOLink team
- Other values: user defined extensions

Currently defined extension identifiers are:

- `TilingInfoExtension`: 0x1
- `ParallelAccessExtension`: 0x2
- `ViewOriginExtension`: 0x3
- `ColumnUnitExtension`: 0x4

# Tiling Info

There is an extension for tiling-related informations called `TilingInfoExtension`. It defines multiple services to know the number of tiles, their location, and their topology. You can get this extension using this code:

std::shared_ptr<TilingInfoExtension> tilingInfo = view->extension<TilingInfoExtension>;
// we can now use the extension services
size_t count = tilingInfo->tileCount();

There is a shortcut in `ImageView` that does all the conversion work:

std::shared_ptr<TilingInfoExtension> tilingInfo = image->tilingInfo();
// we can now use the extension services
size_t count = tilingInfo->tileCount();

The extension provides the following services:

- maximum tile size: Return the maximum size of the tiles used for the tiling grid, as tiles can be cropped on the sides of the image, tiles can be smaller in usage.
- tile count: Simply the number of tiles in the image.
- tile region from a tile index: Get the region corresponding to a tile. The tile index goes from 0 to `tile count` - 1, all indices outside this range are undefined and will throw an exception if given as an argument to this method.
- tiling grid: return an array that shows how the tiles indices are distributed in the image. Each element of the returned array shows the tile index corresponding to the region.
- read tile from a tile index: Read data from a tile into a memory buffer buffer. The image must support the `READ` capability. Indexation rules are the same as `tile region`.
- write tile from a tile index: Write data of a memory buffer into a tile. The image must support the `WRITE` capability. Indexation rules are the same as `tile region`.

# Parallel Access

The `ParallelAccessExtension` extension provides information about parallelism capabilities of an ImageView. You can get this extension using this code:

std::shared_ptr<ParallelAccessExtension> parallelAccess = view->extension<ParallelAccessExtension>();
// we can now use the extension services
auto capabilities = parallelAccess->capabilities();

There is a shortcut in `ImageView` that does all the conversion work:

std::shared_ptr<ParallelAccessExtension> parallelAccess = image->parallelAccess();
// we can now use the extension services
auto capabilities = parallelAccess->capabilities();

In order to accelerate processing when handling an `ImageView`, you may have to use multi-threading to access your data. However, a given `ImageView` instance can have various support for parallel multithreaded operations, and may, or may not be performant when doing so.

In some cases, it can be more efficient to read multiple regions of the `ImageView` instance in parallel.

For all these cases, the `ParallelAccessExtension` extension provides a set of capabilities:

- THREAD_SAFE: ImageView is protected (thanks to its implementation or some locks) and can be used safely in a multi-threaded environment. No risk of race conditions, but as the order of operations in different thread can not be known, if different threads work on overlapping areas, the operations may yield undefined results.
- PARALLEL_READ: Non-overlapping regions can be read in parallel to gain performance benefits without any risk.
- PARALLEL_WRITE: Non-overlapping regions can be written in parallel to gain performance benefits without any risk.
- PARALLEL_TILE_READ: In case of tiled image (see TilingInfoExtension), distinct tiles can be simultaneously read to gain performance benefits.
- PARALLEL_TILE_WRITE: In case of tiled image (see TilingInfoExtension), distinct tiles can be simultaneously written to gain performance benefits.

Warning: In any case a same region of an ImageView should be read and written at the same time, or even written by separated threads. In addition to the risk of race conditions, the result of such operation would be totally unpredictable.

THREAD_SAFE

If an ImageView has PARALLEL_READ capability, you can execute parallel reads on separated regions with a likely performance boost.

PARALLEL_READ

If an ImageView has PARALLEL_WRITE capability, you can execute parallel writes on separated regions with a likely performance boost.

PARALLEL_WRITE

If a tiled ImageView has PARALLEL_TILE_READ capability, you can execute parallel reads on separated tiles with a likely performance boost.

PARALLEL_TILE_READ

If a tiled ImageView has PARALLEL_TILE_WRITE capability, you can execute parallel writes on separated tiles with a likely performance boost.

PARALLEL_TILE_WRITE

# View Origin

The `ViewOriginExtension` extension provides information about the data origin of a view. You can get this extension using this code:

std::shared_ptr<ViewOriginExtension> viewOrigin = view->extension<ViewOriginExtension>();
// we can now use the extension services
ViewDataOrigin origin = viewOrigin->dataOrigin();

There is a shortcut in `View` that does all the conversion work:

std::shared_ptr<ViewOriginExtension> viewOrigin = view->viewOrigin();
// we can now use the extension services
auto origin = viewOrigin->dataOrigin();

Views allow to access data, but they don't give any information about where it comes from. For example, if a view A was "adapted" to create two distinct views B and C. And C is used with another view D to create E, it is not possible to know the connection between these 4 views from the actual interface.

> ‍B, and C are created from the same view A.

> A, B, C and E share the same data.

> D shares data with E only.

With this extension, from any view it is possible to navigate through parents (adapters, proxy...) til the original view(s).

> ‍A -> B

> A -> C -> E

> D -> E

Each view can give information about the origin of its data:

- In CPU memory
- In GPU memory
- On a Drive (Hard Disk, SSD, ...)
- On a Network
- Generated (no data is stored)

Data origin may also be `COMPOSITE` if the view is composed of data from multiple sources, or simply `UNKNOWN` when IOLink has no information about the source of the data.

The extension also provides an `uid` which allows to identify a view. Sometimes this UID has a value equal to `UidGenerator::UNDEFINED_UID`, meaning that the origin of the view is actually unknown and we cannot know if this view is actually related with any other view.

Thanks to this extension, when parsing the parents of different views, it is possible to determine if these views share the same data source. This can be decisive, for example, to allow parallel access on these views.

LIMITATION: As of now, view origin only takes into account 'view' instances as sources of data. Different views created from the same resource, i.e. a file, won't be identified as the same data source, and will have different UIDs

# Column Unit

The `ColumnUnitExtension` extension provides support of units per column in `DataFrameView`.

The unit is an UTF-8 encoded string that describes the unit of the column, in a format described as follows:

- A scalar unit is an string of alphabetical characters, describing the base unit. For example, "m" for meters, "s" for seconds, or "Å" for angstroms.
- Such scalar can have a dimensional suffix, starting with the `^` character, followed by an integer number. this number may be prefixed by a sign, `+` or `-`.
- Unsuffixed units of unsuffixed units may be combined using the `/` or `.` character, to form a compound unit. For example, "m/s" for meters per second.
- An empty unit, or "" is a valid unit, and is equivalent to a dimensionless unit.

Examples of such units:

- "m/s" or "m.s^-1" for meters per second.
- "µm^2" for square micrometers.
- "Ω.s^-1" for ohms per seconds, or more simply as siemens "S".

++
std::shared_ptr<ColumnUnitExtension> columnUnit = frame->extension<ColumnUnitExtension>();
columnUnit->setUnit(1, "m");
std::string unit = columnUnit->unit(1); // contains "m"