CIRCT 22.0.0git
Loading...
Searching...
No Matches
Ports.h
Go to the documentation of this file.
1//===- Ports.h - ESI communication channels ---------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// DO NOT EDIT!
10// This file is distributed as part of an ESI package. The source for this file
11// should always be modified within CIRCT.
12//
13//===----------------------------------------------------------------------===//
14
15// NOLINTNEXTLINE(llvm-header-guard)
16#ifndef ESI_PORTS_H
17#define ESI_PORTS_H
18
19#include "esi/Common.h"
20#include "esi/Types.h"
21#include "esi/Utils.h"
22
23#include <cassert>
24#include <future>
25
26namespace esi {
27
28class ChannelPort;
29using PortMap = std::map<std::string, ChannelPort &>;
30
31/// Unidirectional channels are the basic communication primitive between the
32/// host and accelerator. A 'ChannelPort' is the host side of a channel. It can
33/// be either read or write but not both. At this level, channels are untyped --
34/// just streams of bytes. They are not intended to be used directly by users
35/// but used by higher level APIs which add types.
37public:
38 ChannelPort(const Type *type);
39 virtual ~ChannelPort() {}
40
42 /// The buffer size is optional and should be considered merely a hint.
43 /// Individual implementations use it however they like. The unit is number
44 /// of messages of the port type.
45 std::optional<unsigned> bufferSize = std::nullopt;
46
47 /// If the type of this port is a window, translate the incoming/outgoing
48 /// data into its underlying ('into') type. For 'into' types without lists,
49 /// just re-arranges the data fields from the lowered type to the 'into'
50 /// type.
51 ///
52 /// If this option is false, no translation is done and the data is
53 /// passed through as-is. Same is true for non-windowed types.
54 ///
55 /// For messages with lists, only two types are supported:
56 /// 1) Parallel encoding includes any 'header' data with each frame. Said
57 /// header data is the same across all frames, so this encoding is
58 /// inefficient but is commonly used for on-chip streaming interfaces.
59 /// Each frame contains a 'last' field to indicate the end of the list.
60 /// In cases where 'numItems' is greater than 1, a field named
61 /// '<listField>_size' indicates the number of valid items in that
62 /// frame.
63 /// 2) Serial (bulk transfer) encoding, where a 'header' frame precedes
64 /// the list data frame. Said header frame contains a 'count' field
65 /// indicating the number of items in the list. Importantly, the
66 /// header frame is always re-transmitted after the specified number of
67 /// list items have been sent. If the 'count' field is zero, the end of
68 /// the list has been reached. If it is non-zero, the message has not
69 /// been completely transmitted and reading should continue until a
70 /// 'count' of zero is received.
71 ///
72 /// In both cases, the host-side MessageData contains the complete header
73 /// followed by the list data. In other words, header data is not duplicated
74 /// in the returned message. So for a windowed type with header fields and
75 /// a list of (x,y) coordinates, the host memory layout would be:
76 /// ```
77 /// struct ExampleList {
78 /// uint32_t headerField2; // SystemVerilog ordering
79 /// uint32_t headerField1;
80 /// size_t list_length; // Number list items
81 /// struct { uint16_t y, x; } list_data[];
82 /// }
83 /// ```
84 ///
85 /// In a parallel encoding, each frame's wire format (from hardware) is:
86 /// ```
87 /// struct ExampleListFrame {
88 /// uint8_t list_last; // Non-zero indicates last item in list
89 /// struct { uint16_t y, x; } list_data[numItems]; // SV field ordering
90 /// uint32_t headerField2; // SV struct ordering (reversed)
91 /// uint32_t headerField1;
92 /// }
93 /// ```
94 ///
95 /// Important note: for consistency, preserves SystemVerilog struct field
96 /// ordering! So it's the opposite of C struct ordering.
97 ///
98 /// Implementation status:
99 /// - Only parallel list encoding is supported.
100 /// - Fields must be byte-aligned.
101 ///
102 /// See the CIRCT documentation (or td files) for more details on windowed
103 /// messages.
104 bool translateMessage = true;
105
106 ConnectOptions(std::optional<unsigned> bufferSize = std::nullopt,
107 bool translateMessage = true)
109 };
110
111 /// Set up a connection to the accelerator.
112 virtual void connect(const ConnectOptions &options = ConnectOptions()) = 0;
113 virtual void disconnect() = 0;
114 virtual bool isConnected() const = 0;
115
116 /// Poll for incoming data. Returns true if data was read or written into a
117 /// buffer as a result of the poll. Calling the call back could (will) also
118 /// happen in that case. Some backends need this to be called periodically. In
119 /// the usual case, this will be called by a background thread, but the ESI
120 /// runtime does not want to assume that the host processes use standard
121 /// threads. If the user wants to provide their own threads, they need to call
122 /// this on each port occasionally. This is also called from the 'master' poll
123 /// method in the Accelerator class.
124 bool poll() {
125 if (isConnected())
126 return pollImpl();
127 return false;
128 }
129
130 const Type *getType() const { return type; }
131
132protected:
133 const Type *type;
134
135 /// Instructions for translating windowed types. Precomputes and optimizes a
136 /// list of copy operations.
139
140 /// Precompute and optimize the copy operations for translating frames.
141 void precomputeFrameInfo();
142
143 /// The window type being translated.
145
146 /// A copy operation for translating between frame data and the translation.
147 /// Run this during the translation.
148 struct CopyOp {
149 /// Offset in the incoming/outgoing frame data.
151 /// Offset in the translation buffer.
153 /// Number of bytes to copy.
154 size_t size;
155 };
156
157 /// Information about a list field within a frame (for parallel encoding).
158 /// Note: Currently only numItems == 1 is supported (one list element per
159 /// frame).
161 /// Name of the list field.
162 std::string fieldName;
163 /// Offset of the list data array in the frame.
165 /// Size of each list element in bytes.
167 /// Offset of the 'last' field in the frame.
169 /// Offset in the translation buffer where list length is stored.
171 /// Offset in the translation buffer where list data starts.
173 };
174
175 /// Information about each frame in the windowed type.
176 struct FrameInfo {
177 /// The total size of a frame in bytes.
179 /// Precomputed copy operations for translating this frame (non-list
180 /// fields).
181 std::vector<CopyOp> copyOps;
182 /// Information about list fields in this frame (parallel encoding).
183 /// Currently only one list field per frame is supported.
184 std::optional<ListFieldInfo> listField;
185 };
186 /// Precomputed information about each frame.
187 std::vector<FrameInfo> frames;
188 /// Size of the 'into' type in bytes (for fixed-size types).
189 /// For types with lists, this is the size of the fixed header portion.
190 size_t intoTypeBytes = 0;
191 /// True if the window contains a list field (variable-size message).
192 bool hasListField = false;
193 };
194 std::unique_ptr<TranslationInfo> translationInfo;
195
196 /// Method called by poll() to actually poll the channel if the channel is
197 /// connected.
198 virtual bool pollImpl() { return false; }
199
200 /// Called by all connect methods to let backends initiate the underlying
201 /// connections.
202 virtual void connectImpl(const ConnectOptions &options) {}
203};
204
205/// A ChannelPort which sends data to the accelerator.
207public:
209
210 virtual void connect(const ConnectOptions &options = {}) override {
211 translateMessages = options.translateMessage && translationInfo;
213 translationInfo->precomputeFrameInfo();
214 connectImpl(options);
215 connected = true;
216 }
217 virtual void disconnect() override { connected = false; }
218 virtual bool isConnected() const override { return connected; }
219
220 /// A very basic blocking write API. Will likely change for performance
221 /// reasons.
222 void write(const MessageData &data) {
223 if (translateMessages) {
224 assert(translationBuffer.empty() &&
225 "Cannot call write() with pending translated messages");
226 translateOutgoing(data);
227 for (auto &msg : translationBuffer)
228 writeImpl(msg);
229 translationBuffer.clear();
230 } else {
231 writeImpl(data);
232 }
233 }
234
235 /// A basic non-blocking write API. Returns true if any of the data was queued
236 /// and/or sent. If the data type is a window a 'true' return does not
237 /// indicate that the message has been completely written. The 'flush' method
238 /// can be used to check that the entire buffer has been written. It is
239 /// invalid for backends to always return false (i.e. backends must eventually
240 /// ensure that writes may succeed).
241 bool tryWrite(const MessageData &data) {
242 if (translateMessages) {
243 // Do not accept a new message if there are pending messages to flush.
244 if (!flush())
245 return false;
246 assert(translationBuffer.empty() &&
247 "Translation buffer should be empty after successful flush");
248 translateOutgoing(data);
249 flush();
250 return true;
251 } else {
252 return tryWriteImpl(data);
253 }
254 }
255 /// Flush any buffered data. Returns true if all data was flushed.
256 ///
257 /// If `translateMessages` is false, calling `flush()` will immediately return
258 /// true and perform no action, as there is no buffered data to flush.
259 bool flush() {
260 while (translationBufferIdx < translationBuffer.size()) {
262 return false;
264 }
265 translationBuffer.clear();
267 return true;
268 }
269
270protected:
271 /// Implementation for write(). Subclasses must implement this.
272 virtual void writeImpl(const MessageData &) = 0;
273
274 /// Implementation for tryWrite(). Subclasses must implement this.
275 virtual bool tryWriteImpl(const MessageData &data) = 0;
276
277 /// Whether to translate outgoing data if the port type is a window type. Set
278 /// by the connect() method.
279 bool translateMessages = false;
280 /// If tryWrite cannot write all the messages of a windowed type at once, it
281 /// stores them here and writes them out one by one on subsequent calls.
282 std::vector<MessageData> translationBuffer;
283 /// Index of the next message to write in translationBuffer.
285 /// Translate outgoing data if the port type is a window type. Append the new
286 /// message 'chunks' to translationBuffer.
287 void translateOutgoing(const MessageData &data);
288
289private:
290 volatile bool connected = false;
291};
292
293/// Instantiated when a backend does not know how to create a write channel.
295public:
298
299 void connect(const ConnectOptions &options = {}) override {
300 throw std::runtime_error(errmsg);
301 }
302
303protected:
304 void writeImpl(const MessageData &) override {
305 throw std::runtime_error(errmsg);
306 }
307 bool tryWriteImpl(const MessageData &) override {
308 throw std::runtime_error(errmsg);
309 }
310
311 std::string errmsg;
312};
313
314/// A ChannelPort which reads data from the accelerator. It has two modes:
315/// Callback and Polling which cannot be used at the same time. The mode is set
316/// at connect() time. To change the mode, disconnect() and then connect()
317/// again.
319
320public:
323 virtual void disconnect() override { mode = Mode::Disconnected; }
324 virtual bool isConnected() const override {
325 return mode != Mode::Disconnected;
326 }
327
328 //===--------------------------------------------------------------------===//
329 // Callback mode: To use a callback, connect with a callback function which
330 // will get called with incoming data. This function can be called from any
331 // thread. It shall return true to indicate that the data was consumed. False
332 // if it could not accept the data and should be tried again at some point in
333 // the future. Callback is not allowed to block and needs to execute quickly.
334 //
335 // TODO: Have the callback return something upon which the caller can check,
336 // wait, and be notified.
337 //===--------------------------------------------------------------------===//
338
339 virtual void connect(std::function<bool(MessageData)> callback,
340 const ConnectOptions &options = {});
341
342 //===--------------------------------------------------------------------===//
343 // Polling mode methods: To use futures or blocking reads, connect without any
344 // arguments. You will then be able to use readAsync() or read().
345 //===--------------------------------------------------------------------===//
346
347 /// Default max data queue size set at connect time.
348 static constexpr uint64_t DefaultMaxDataQueueMsgs = 32;
349
350 /// Connect to the channel in polling mode.
351 virtual void connect(const ConnectOptions &options = {}) override;
352
353 /// Asynchronous read.
354 virtual std::future<MessageData> readAsync();
355
356 /// Specify a buffer to read into. Blocking. Basic API, will likely change
357 /// for performance and functionality reasons.
358 virtual void read(MessageData &outData) {
359 std::future<MessageData> f = readAsync();
360 f.wait();
361 outData = std::move(f.get());
362 }
363
364 /// Set maximum number of messages to store in the dataQueue. 0 means no
365 /// limit. This is only used in polling mode and is set to default of 32 upon
366 /// connect. While it may seem redundant to have this and bufferSize, there
367 /// may be (and are) backends which have a very small amount of memory which
368 /// are accelerator accessible and want to move messages out as quickly as
369 /// possible.
370 void setMaxDataQueueMsgs(uint64_t maxMsgs) { maxDataQueueMsgs = maxMsgs; }
371
372protected:
373 /// Indicates the current mode of the channel.
375 volatile Mode mode;
376
377 /// Backends call this callback when new data is available.
378 std::function<bool(MessageData)> callback;
379
380 /// Window translation support.
381 std::vector<uint8_t> translationBuffer;
382 /// Index of the next expected frame (for multi-frame windows).
383 size_t nextFrameIndex = 0;
384 /// For list fields: accumulated list data across frames.
385 std::vector<uint8_t> listDataBuffer;
386 /// Flag to track whether we're in the middle of accumulating list data.
388 /// Reset translation state buffers and indices.
390 /// Translate incoming data if the port type is a window type. Returns true if
391 /// the message has been completely received.
392 bool translateIncoming(MessageData &data);
393
394 //===--------------------------------------------------------------------===//
395 // Polling mode members.
396 //===--------------------------------------------------------------------===//
397
398 /// Mutex to protect the two queues used for polling.
399 std::mutex pollingM;
400 /// Store incoming data here if there are no outstanding promises to be
401 /// fulfilled.
402 std::queue<MessageData> dataQueue;
403 /// Maximum number of messages to store in dataQueue. 0 means no limit.
405 /// Promises to be fulfilled when data is available.
406 std::queue<std::promise<MessageData>> promiseQueue;
407};
408
409/// Instantiated when a backend does not know how to create a read channel.
411public:
414
415 void connect(std::function<bool(MessageData)> callback,
416 const ConnectOptions &options = ConnectOptions()) override {
417 throw std::runtime_error(errmsg);
418 }
419 void connect(const ConnectOptions &options = ConnectOptions()) override {
420 throw std::runtime_error(errmsg);
421 }
422 std::future<MessageData> readAsync() override {
423 throw std::runtime_error(errmsg);
424 }
425
426protected:
427 std::string errmsg;
428};
429
430/// Services provide connections to 'bundles' -- collections of named,
431/// unidirectional communication channels. This class provides access to those
432/// ChannelPorts.
434public:
435 /// Compute the direction of a channel given the bundle direction and the
436 /// bundle port's direction.
437 static bool isWrite(BundleType::Direction bundleDir) {
438 return bundleDir == BundleType::Direction::To;
439 }
440
441 /// Construct a port.
443 virtual ~BundlePort() = default;
444
445 /// Get the ID of the port.
446 AppID getID() const { return id; }
447
448 /// Get access to the raw byte streams of a channel. Intended for internal
449 /// usage and binding to other languages (e.g. Python) which have their own
450 /// message serialization code. Exposed publicly as an escape hatch, but
451 /// ordinary users should not use. You have been warned.
452 WriteChannelPort &getRawWrite(const std::string &name) const;
453 ReadChannelPort &getRawRead(const std::string &name) const;
454 const PortMap &getChannels() const { return channels; }
455
456 /// Cast this Bundle port to a subclass which is actually useful. Returns
457 /// nullptr if the cast fails.
458 // TODO: this probably shouldn't be 'const', but bundle ports' user access are
459 // const. Change that.
460 template <typename T>
461 T *getAs() const {
462 return const_cast<T *>(dynamic_cast<const T *>(this));
463 }
464
465 /// Calls `poll` on all channels in the bundle and returns true if any of them
466 /// returned true.
467 bool poll() {
468 bool result = false;
469 for (auto &channel : channels)
470 result |= channel.second.poll();
471 return result;
472 }
473
474protected:
478};
479
480} // namespace esi
481
482#endif // ESI_PORTS_H
assert(baseType &&"element must be base type")
Services provide connections to 'bundles' – collections of named, unidirectional communication channe...
Definition Ports.h:433
virtual ~BundlePort()=default
T * getAs() const
Cast this Bundle port to a subclass which is actually useful.
Definition Ports.h:461
PortMap channels
Definition Ports.h:477
ReadChannelPort & getRawRead(const std::string &name) const
Definition Ports.cpp:52
WriteChannelPort & getRawWrite(const std::string &name) const
Get access to the raw byte streams of a channel.
Definition Ports.cpp:42
const PortMap & getChannels() const
Definition Ports.h:454
bool poll()
Calls poll on all channels in the bundle and returns true if any of them returned true.
Definition Ports.h:467
const BundleType * type
Definition Ports.h:476
static bool isWrite(BundleType::Direction bundleDir)
Compute the direction of a channel given the bundle direction and the bundle port's direction.
Definition Ports.h:437
AppID getID() const
Get the ID of the port.
Definition Ports.h:446
Bundles represent a collection of channels.
Definition Types.h:97
Unidirectional channels are the basic communication primitive between the host and accelerator.
Definition Ports.h:36
const Type * getType() const
Definition Ports.h:130
virtual void connect(const ConnectOptions &options=ConnectOptions())=0
Set up a connection to the accelerator.
virtual void disconnect()=0
virtual bool pollImpl()
Method called by poll() to actually poll the channel if the channel is connected.
Definition Ports.h:198
const Type * type
Definition Ports.h:133
virtual void connectImpl(const ConnectOptions &options)
Called by all connect methods to let backends initiate the underlying connections.
Definition Ports.h:202
ChannelPort(const Type *type)
Definition Ports.cpp:26
virtual ~ChannelPort()
Definition Ports.h:39
std::unique_ptr< TranslationInfo > translationInfo
Definition Ports.h:194
bool poll()
Poll for incoming data.
Definition Ports.h:124
virtual bool isConnected() const =0
A logical chunk of data representing serialized data.
Definition Common.h:113
A ChannelPort which reads data from the accelerator.
Definition Ports.h:318
volatile Mode mode
Definition Ports.h:375
virtual std::future< MessageData > readAsync()
Asynchronous read.
Definition Ports.cpp:126
size_t nextFrameIndex
Index of the next expected frame (for multi-frame windows).
Definition Ports.h:383
virtual bool isConnected() const override
Definition Ports.h:324
virtual void connect(std::function< bool(MessageData)> callback, const ConnectOptions &options={})
Definition Ports.cpp:69
std::vector< uint8_t > translationBuffer
Window translation support.
Definition Ports.h:381
std::mutex pollingM
Mutex to protect the two queues used for polling.
Definition Ports.h:399
bool accumulatingListData
Flag to track whether we're in the middle of accumulating list data.
Definition Ports.h:387
void resetTranslationState()
Reset translation state buffers and indices.
Definition Ports.cpp:62
std::function< bool(MessageData)> callback
Backends call this callback when new data is available.
Definition Ports.h:378
Mode
Indicates the current mode of the channel.
Definition Ports.h:374
std::queue< MessageData > dataQueue
Store incoming data here if there are no outstanding promises to be fulfilled.
Definition Ports.h:402
static constexpr uint64_t DefaultMaxDataQueueMsgs
Default max data queue size set at connect time.
Definition Ports.h:348
bool translateIncoming(MessageData &data)
Translate incoming data if the port type is a window type.
Definition Ports.cpp:364
std::queue< std::promise< MessageData > > promiseQueue
Promises to be fulfilled when data is available.
Definition Ports.h:406
void setMaxDataQueueMsgs(uint64_t maxMsgs)
Set maximum number of messages to store in the dataQueue.
Definition Ports.h:370
uint64_t maxDataQueueMsgs
Maximum number of messages to store in dataQueue. 0 means no limit.
Definition Ports.h:404
virtual void disconnect() override
Definition Ports.h:323
std::vector< uint8_t > listDataBuffer
For list fields: accumulated list data across frames.
Definition Ports.h:385
virtual void read(MessageData &outData)
Specify a buffer to read into.
Definition Ports.h:358
ReadChannelPort(const Type *type)
Definition Ports.h:321
Root class of the ESI type system.
Definition Types.h:34
Instantiated when a backend does not know how to create a read channel.
Definition Ports.h:410
void connect(std::function< bool(MessageData)> callback, const ConnectOptions &options=ConnectOptions()) override
Definition Ports.h:415
void connect(const ConnectOptions &options=ConnectOptions()) override
Connect to the channel in polling mode.
Definition Ports.h:419
std::future< MessageData > readAsync() override
Asynchronous read.
Definition Ports.h:422
UnknownReadChannelPort(const Type *type, std::string errmsg)
Definition Ports.h:412
Instantiated when a backend does not know how to create a write channel.
Definition Ports.h:294
void connect(const ConnectOptions &options={}) override
Set up a connection to the accelerator.
Definition Ports.h:299
void writeImpl(const MessageData &) override
Implementation for write(). Subclasses must implement this.
Definition Ports.h:304
UnknownWriteChannelPort(const Type *type, std::string errmsg)
Definition Ports.h:296
bool tryWriteImpl(const MessageData &) override
Implementation for tryWrite(). Subclasses must implement this.
Definition Ports.h:307
Windows represent a fixed-size sliding window over a stream of data.
Definition Types.h:280
A ChannelPort which sends data to the accelerator.
Definition Ports.h:206
virtual bool isConnected() const override
Definition Ports.h:218
virtual void disconnect() override
Definition Ports.h:217
size_t translationBufferIdx
Index of the next message to write in translationBuffer.
Definition Ports.h:284
virtual bool tryWriteImpl(const MessageData &data)=0
Implementation for tryWrite(). Subclasses must implement this.
volatile bool connected
Definition Ports.h:290
bool translateMessages
Whether to translate outgoing data if the port type is a window type.
Definition Ports.h:279
void write(const MessageData &data)
A very basic blocking write API.
Definition Ports.h:222
bool flush()
Flush any buffered data.
Definition Ports.h:259
bool tryWrite(const MessageData &data)
A basic non-blocking write API.
Definition Ports.h:241
virtual void connect(const ConnectOptions &options={}) override
Set up a connection to the accelerator.
Definition Ports.h:210
void translateOutgoing(const MessageData &data)
Translate outgoing data if the port type is a window type.
Definition Ports.cpp:461
std::vector< MessageData > translationBuffer
If tryWrite cannot write all the messages of a windowed type at once, it stores them here and writes ...
Definition Ports.h:282
virtual void writeImpl(const MessageData &)=0
Implementation for write(). Subclasses must implement this.
Definition esi.py:1
std::map< std::string, ChannelPort & > PortMap
Definition Ports.h:29
ConnectOptions(std::optional< unsigned > bufferSize=std::nullopt, bool translateMessage=true)
Definition Ports.h:106
std::optional< unsigned > bufferSize
The buffer size is optional and should be considered merely a hint.
Definition Ports.h:45
bool translateMessage
If the type of this port is a window, translate the incoming/outgoing data into its underlying ('into...
Definition Ports.h:104
A copy operation for translating between frame data and the translation.
Definition Ports.h:148
size_t bufferOffset
Offset in the translation buffer.
Definition Ports.h:152
size_t frameOffset
Offset in the incoming/outgoing frame data.
Definition Ports.h:150
size_t size
Number of bytes to copy.
Definition Ports.h:154
Information about each frame in the windowed type.
Definition Ports.h:176
std::vector< CopyOp > copyOps
Precomputed copy operations for translating this frame (non-list fields).
Definition Ports.h:181
std::optional< ListFieldInfo > listField
Information about list fields in this frame (parallel encoding).
Definition Ports.h:184
size_t expectedSize
The total size of a frame in bytes.
Definition Ports.h:178
Information about a list field within a frame (for parallel encoding).
Definition Ports.h:160
size_t listLengthBufferOffset
Offset in the translation buffer where list length is stored.
Definition Ports.h:170
size_t dataOffset
Offset of the list data array in the frame.
Definition Ports.h:164
std::string fieldName
Name of the list field.
Definition Ports.h:162
size_t lastFieldOffset
Offset of the 'last' field in the frame.
Definition Ports.h:168
size_t elementSize
Size of each list element in bytes.
Definition Ports.h:166
size_t listDataBufferOffset
Offset in the translation buffer where list data starts.
Definition Ports.h:172
Instructions for translating windowed types.
Definition Ports.h:137
void precomputeFrameInfo()
Precompute and optimize the copy operations for translating frames.
Definition Ports.cpp:154
TranslationInfo(const WindowType *windowType)
Definition Ports.h:138
bool hasListField
True if the window contains a list field (variable-size message).
Definition Ports.h:192
const WindowType * windowType
The window type being translated.
Definition Ports.h:144
size_t intoTypeBytes
Size of the 'into' type in bytes (for fixed-size types).
Definition Ports.h:190
std::vector< FrameInfo > frames
Precomputed information about each frame.
Definition Ports.h:187