55 serialization::EnumAsIntegerTag<OSVR_ImagingValueType,
74 void allocateBuffer(T &,
size_t bytes, std::true_type
const &) {
75 m_imgBuf = util::makeAlignedImageBuffer(bytes);
79 void allocateBuffer(T &,
size_t, std::false_type
const &) {
85 auto bytes = getBufferSize(m_meta);
89 allocateBuffer(p, bytes, p.isDeserialize());
95 ret.sensor = m_sensor;
96 ret.metadata = m_meta;
97 ret.buffer = m_imgBuf;
103 ImageBufferPtr m_imgBuf;
106 const char *ImageRegion::identifier() {
107 return "com.osvr.imaging.imageregion";
110 #ifdef OSVR_COMMON_IN_PROCESS_IMAGING
112 struct InProcessMemoryMessage {
117 template <
typename T>
118 void process(InProcessMemoryMessage &ipmmMsg, T &p) {
119 process(ipmmMsg.metadata, p);
125 const char *ImagePlacedInProcessMemory::identifier() {
126 return "com.osvr.imaging.imageplacedinprocessmemory";
129 class ImagePlacedInProcessMemory::MessageSerialization {
131 MessageSerialization() {}
132 explicit MessageSerialization(InProcessMemoryMessage &&msg)
133 : m_msgData(
std::move(msg)) {}
135 #if defined(_MSC_VER) && defined(_PREFAST_)
137 explicit MessageSerialization(InProcessMemoryMessage
const &msg)
140 template <
typename T>
void processMessage(T &p) {
141 process(m_msgData, p);
144 InProcessMemoryMessage
const &getMessage() {
return m_msgData; }
147 InProcessMemoryMessage m_msgData;
152 struct SharedMemoryMessage {
156 IPCRingBuffer::abi_level_type abiLevel;
157 IPCRingBuffer::BackendType backend;
160 template <
typename T>
161 void process(SharedMemoryMessage &shmMsg, T &p) {
162 process(shmMsg.metadata, p);
175 : m_msgData(std::move(msg)) {}
177 #if defined(_MSC_VER) && defined(_PREFAST_)
183 template <
typename T>
void processMessage(T &p) {
184 process(m_msgData, p);
187 SharedMemoryMessage
const &getMessage() {
return m_msgData; }
190 SharedMemoryMessage m_msgData;
193 const char *ImagePlacedInSharedMemory::identifier() {
194 return "com.osvr.imaging.imageplacedinsharedmemory";
198 shared_ptr<ImagingComponent>
204 : m_numSensor(numChan) {}
213 #ifdef OSVR_COMMON_IN_PROCESS_IMAGING
214 dataSent += m_sendImageDataViaInProcessMemory(metadata, imageData,
217 dataSent += m_sendImageDataViaSharedMemory(metadata, imageData, sensor,
221 m_sendImageDataOnTheWire(metadata, imageData, sensor, timestamp);
223 m_checkFirst(metadata);
227 #ifdef OSVR_COMMON_IN_PROCESS_IMAGING
228 bool ImagingComponent::m_sendImageDataViaInProcessMemory(
232 auto imageBufferSize = getBufferSize(metadata);
233 auto imageBufferCopy = util::makeAlignedImageBuffer(imageBufferSize);
234 memcpy(imageBufferCopy.get(), imageData, imageBufferSize);
237 messages::ImagePlacedInProcessMemory::MessageSerialization
238 serialization(messages::InProcessMemoryMessage{
240 reinterpret_cast<intptr_t
>(imageBufferCopy.release())});
244 buf, imagePlacedInProcessMemory.getMessageType(), timestamp);
250 bool ImagingComponent::m_sendImageDataViaSharedMemory(
254 m_growShmVecIfRequired(sensor);
255 uint32_t imageBufferSize = getBufferSize(metadata);
256 if (!m_shmBuf[sensor] ||
257 m_shmBuf[sensor]->getEntrySize() != imageBufferSize) {
260 std::string
const &devName) {
261 std::ostringstream os;
262 os <<
"com.osvr.imaging/" << devName <<
"/" << int(sensor);
266 IPCRingBuffer::Options(
268 .setEntrySize(imageBufferSize));
270 if (!m_shmBuf[sensor]) {
272 "Some issue creating shared memory for imaging, skipping out.");
275 auto &shm = *(m_shmBuf[sensor]);
276 auto seq = shm.put(imageData, imageBufferSize);
279 messages::ImagePlacedInSharedMemory::MessageSerialization serialization(
280 messages::SharedMemoryMessage{metadata, seq, sensor,
282 shm.getBackend(), shm.getName()});
290 bool ImagingComponent::m_sendImageDataOnTheWire(
294 if (metadata.
depth != 1) {
298 messages::ImageRegion::MessageSerialization msg(metadata, imageData,
301 if (buf.size() > vrpn_CONNECTION_TCP_BUFLEN) {
303 OSVR_DEV_VERBOSE(
"Skipping imaging message: size is "
304 << buf.size() <<
" vs the maximum of "
305 << vrpn_CONNECTION_TCP_BUFLEN);
315 ImagingComponent::m_handleImageRegion(
void *userdata, vrpn_HANDLERPARAM p) {
316 auto self =
static_cast<ImagingComponent *
>(userdata);
319 messages::ImageRegion::MessageSerialization msg;
321 auto data = msg.getData();
324 self->m_checkFirst(data.metadata);
325 for (
auto const &cb : self->m_cb) {
331 #ifdef OSVR_COMMON_IN_PROCESS_IMAGING
332 int VRPN_CALLBACK ImagingComponent::m_handleImagePlacedInProcessMemory(
333 void *userdata, vrpn_HANDLERPARAM p) {
334 auto self =
static_cast<ImagingComponent *
>(userdata);
337 messages::ImagePlacedInProcessMemory::MessageSerialization msgSerialize;
339 auto msg = msgSerialize.getMessage();
341 data.sensor = msg.sensor;
342 data.metadata = msg.metadata;
344 reinterpret_cast<OSVR_ImageBufferElement *>(msg.buffer),
348 self->m_checkFirst(msg.metadata);
349 for (
auto const &cb : self->m_cb) {
356 int VRPN_CALLBACK ImagingComponent::m_handleImagePlacedInSharedMemory(
357 void *userdata, vrpn_HANDLERPARAM p) {
358 auto self =
static_cast<ImagingComponent *
>(userdata);
361 messages::ImagePlacedInSharedMemory::MessageSerialization msgSerialize;
363 auto &msg = msgSerialize.getMessage();
368 OSVR_DEV_VERBOSE(
"Can't handle SHM ABI level " << msg.abiLevel);
371 self->m_growShmVecIfRequired(msg.sensor);
372 auto checkSameRingBuf = [](messages::SharedMemoryMessage
const &msg,
374 return (msg.backend == ringbuf->getBackend()) &&
375 (ringbuf->getEntrySize() == getBufferSize(msg.metadata)) &&
376 (ringbuf->getName() == msg.shmName);
378 if (!self->m_shmBuf[msg.sensor] ||
379 !checkSameRingBuf(msg, self->m_shmBuf[msg.sensor])) {
381 IPCRingBuffer::Options(msg.shmName, msg.backend));
383 if (!self->m_shmBuf[msg.sensor]) {
386 OSVR_DEV_VERBOSE(
"Can't find desired IPC ring buffer "
391 auto &shm =
self->m_shmBuf[msg.sensor];
392 auto getResult = shm->get(msg.seqNum);
394 auto bufptr = getResult.getBufferSmartPointer();
395 self->m_checkFirst(msg.metadata);
396 auto data = ImageData{msg.sensor, msg.metadata, bufptr};
398 for (
auto const &cb : self->m_cb) {
405 void ImagingComponent::registerImageHandler(ImageHandler handler) {
411 &ImagingComponent::m_handleImagePlacedInSharedMemory,
this,
414 #ifdef OSVR_COMMON_IN_PROCESS_IMAGING
416 &ImagingComponent::m_handleImagePlacedInProcessMemory,
this,
417 imagePlacedInProcessMemory.getMessageType());
420 m_cb.push_back(handler);
422 void ImagingComponent::m_parentSet() {
425 #ifdef OSVR_COMMON_IN_PROCESS_IMAGING
436 OSVR_DEV_VERBOSE(
"Sending/receiving first frame: width="
437 << metadata.
width <<
" height=" << metadata.
height);
440 if (m_shmBuf.size() <= sensor) {
441 m_shmBuf.resize(sensor + 1);
uint32_t OSVR_ChannelCount
The integer type specifying a number of channels/sensors or a channel/sensor index.
A tag for use for raw data (bytestream), optionally aligned.
void deserialize(BufferReaderType &reader, MessageClass &msg)
Deserializes a message from a buffer, using a MessageClass
void serialize(BufferType &buf, MessageClass &msg)
Serializes a message into a buffer, using a MessageClass
shared_ptr< IPCRingBuffer > IPCRingBufferPtr
Pointer type for holding a shared memory ring buffer.
static IPCRingBufferPtr find(Options const &opts)
Named constructor, for use by client processes: accesses an IPC ring buffer using the options structu...
static shared_ptr< ImagingComponent > create(OSVR_ChannelCount numSensor=0)
Factory method.
void m_registerHandler(vrpn_MESSAGEHANDLER handler, void *userdata, RawMessageType const &msgType)
Registers a handler whose lifetime is tied to the lifetime of the component.
void processMessage(T &p)
void fromStructTimeval(TimeValue &dest, struct timeval const &src)
Convert a struct timeval to a TimeValue.
static abi_level_type getABILevel()
Gets an integer representing a unique arrangement of the internal shared memory layout, such that if two processes try to communicate with different ABI levels, they will (likely) not succeed and thus should not try.
uint32_t sequence_type
The sequence number is automatically incremented with each "put" into the buffer. Note that...
void sendPending()
Called from a component to send pending messages instead of waiting for next time.
Parent & m_getParent()
Gets the parent - only call if m_hasParent() is true.
messages::ImageRegion imageRegion
Message from server to client, containing some image data.
Internal, configured header file for verbosity macros.
messages::ImagePlacedInSharedMemory imagePlacedInSharedMemory
Message from server to client, notifying of image data in the shared memory ring buffer.
Standardized, portable parallel to struct timeval for representing both absolute times and time inter...
Header defining buffer types, with optional alignment dependent on Boost version. ...
unsigned char OSVR_ImageBufferElement
Type for raw buffer access to image data.
BufferReader< ExternalBufferReadingWrapper< CharType > > readExternalBuffer(const CharType *buf, size_t len)
Constructs and returns a buffer reader for an externally-allocated buffer: it's on you to supply a va...
void registerMessageType(MessageRegistration< T > &messageReg)
Call with a MessageRegistration object, and the message type will be registered and stored in the typ...
void alignedFree(void *p)
Aligned deallocation function, uses the pointer to the original memory block to deallocate it...
A class that lightly wraps a bool, in order to provide easier maintenance of a "dirty" flag...
static IPCRingBufferPtr create(Options const &opts)
Named constructor, for use by server processes: creates a shared memory ring buffer given the options...