401c844fcc
Big waves. This function wraps the operation of getting a stimframe from the SpMcRingBuffer, and then eventually assigning it a SimultaneityStamp. For now we just always pass in the first stim frame and we don't get any simulstamps. Its callOriginalCallback() automatically calls allowNextStimulusFrame() to ensure that it doesn't deadlock future timeslices.
191 lines
5.3 KiB
C++
191 lines
5.3 KiB
C++
#include <config.h>
|
|
#include <opts.h>
|
|
#include <algorithm>
|
|
#include <unistd.h>
|
|
#include <iomanip>
|
|
#include <user/spMcRingBuffer.h>
|
|
#include <componentThread.h>
|
|
#include <asynchronousLoop.h>
|
|
#include <user/stimulusFrame.h>
|
|
#include "pcloudStimulusBuffer.h"
|
|
#include "frameAssemblyDesc.h"
|
|
|
|
namespace smo {
|
|
namespace stim_buff {
|
|
|
|
extern const SmoCallbacks* smoHooksPtr;
|
|
|
|
// OpenCL kernels are used to collate and produce our StimFrames.
|
|
static SpMcRingBuffer::InputEngineConstraints openClInputConstraints(
|
|
static_cast<size_t>(sysconf(_SC_PAGE_SIZE)), sizeof(void *));
|
|
|
|
PcloudStimulusBuffer::PcloudStimulusBuffer(
|
|
const std::shared_ptr<device::DeviceAttachmentSpec> &deviceAttachmentSpec,
|
|
std::shared_ptr<livoxProto1::Device> &device,
|
|
const PcloudFormatDesc& formatDesc,
|
|
int histbuffMs,
|
|
size_t nDgramsPerStagingBufferFrame)
|
|
: StimulusBuffer(
|
|
deviceAttachmentSpec,
|
|
static_cast<size_t>(histbuffMs / CONFIG_STIMBUFF_FRAME_PERIOD_MS),
|
|
openClInputConstraints,
|
|
device->componentThread->getIoService()),
|
|
device(device),
|
|
formatDesc(formatDesc),
|
|
openClCollatingAndMeshingEngine(*this),
|
|
assemblyBuffer(
|
|
StagingBuffer::IOEngineConstraints::ioUringConstraints,
|
|
StagingBuffer::IOEngineConstraints::openClInputConstraints,
|
|
nDgramsPerStagingBufferFrame),
|
|
ioUringAssemblyEngine(*this, nDgramsPerStagingBufferFrame),
|
|
collationBuffer(
|
|
StagingBuffer::IOEngineConstraints::openClInputConstraints,
|
|
StagingBuffer::IOEngineConstraints::openClInputConstraints,
|
|
nDgramsPerStagingBufferFrame)
|
|
{
|
|
if (smoHooksPtr->OptionParser_getOptions().verbose)
|
|
{
|
|
std::cout << __func__ << ": assembly buffer : "
|
|
<< assemblyBuffer.stringify()
|
|
<< "\n\tcollation buffer : " << collationBuffer.stringify()
|
|
<< "\n";
|
|
}
|
|
|
|
std::cout << __func__ << ": Device's component thread is "
|
|
<< device->componentThread->name << std::endl;
|
|
|
|
#ifndef CONFIG_WORLD_USE_BODY_THREAD
|
|
if (smoHooksPtr->ComponentThread_getSelf()->id != ComponentThread::WORLD)
|
|
#else
|
|
if (smoHooksPtr->ComponentThread_getSelf()->id != ComponentThread::BODY)
|
|
#endif
|
|
{
|
|
std::string errMsg = std::string(__func__) +
|
|
": PcloudStimulusBuffer constructor called on non-world/body thread " +
|
|
smoHooksPtr->ComponentThread_getSelf()->name;
|
|
|
|
std::cout << errMsg << std::endl;
|
|
// throw std::runtime_error(errMsg);
|
|
}
|
|
}
|
|
|
|
void PcloudStimulusBuffer::start()
|
|
{
|
|
// Call ioUringAssemblyEngine setup() as the final step
|
|
ioUringAssemblyEngine.setup();
|
|
openClCollatingAndMeshingEngine.setup();
|
|
// Call base class start() as the final step
|
|
StimulusBuffer::start();
|
|
}
|
|
|
|
void PcloudStimulusBuffer::stop()
|
|
{
|
|
// Call base class stop() as the first step
|
|
StimulusBuffer::stop();
|
|
// Call ioUringAssemblyEngine stop() as the final step
|
|
openClCollatingAndMeshingEngine.finalize();
|
|
ioUringAssemblyEngine.finalize();
|
|
}
|
|
|
|
void produceStimFrameAck(void)
|
|
{
|
|
}
|
|
|
|
void PcloudStimulusBuffer::stimFrameProductionTimesliceInd()
|
|
{
|
|
produceFrameReq({nullptr, nullptr});
|
|
}
|
|
|
|
class PcloudStimulusBuffer::ProduceFrameReq
|
|
: public PostedAsynchronousContinuation<produceFrameReqCbFn>
|
|
{
|
|
private:
|
|
PcloudStimulusBuffer& stimBuff;
|
|
AsynchronousLoop frameAssemblyResult;
|
|
StimulusFrame& stimulusFrame;
|
|
|
|
public:
|
|
ProduceFrameReq(
|
|
PcloudStimulusBuffer& buffer,
|
|
const std::shared_ptr<ComponentThread>& caller,
|
|
Callback<produceFrameReqCbFn> cb)
|
|
: PostedAsynchronousContinuation<produceFrameReqCbFn>(caller, cb),
|
|
stimBuff(buffer),
|
|
frameAssemblyResult(0),
|
|
stimulusFrame(buffer.frames_[0])
|
|
{}
|
|
|
|
public:
|
|
void callOriginalCallback()
|
|
{
|
|
stimBuff.allowNextStimulusFrame();
|
|
callOriginalCb();
|
|
}
|
|
|
|
public:
|
|
void produceFrameReq1_doAssemble_posted(
|
|
std::shared_ptr<ProduceFrameReq> context)
|
|
{
|
|
stimBuff.ioUringAssemblyEngine.assembleFrameReq(
|
|
{context, std::bind(
|
|
&ProduceFrameReq::produceFrameReq2_assembleDone,
|
|
context.get(), context,
|
|
std::placeholders::_1, std::placeholders::_2)});
|
|
}
|
|
|
|
void produceFrameReq2_assembleDone(
|
|
std::shared_ptr<ProduceFrameReq> context,
|
|
bool success, AsynchronousLoop loop)
|
|
{
|
|
if (!success)
|
|
{
|
|
std::cerr << __func__ << ": Failed to assemble frame" << std::endl;
|
|
callOriginalCallback();
|
|
return;
|
|
}
|
|
|
|
std::cout << __func__ << ": Successfully assembled frame "
|
|
<< loop.nSucceeded.load() << " slots succeeded "
|
|
<< "out of " << loop.nTotal << " total slots" << std::endl;
|
|
|
|
context->frameAssemblyResult = loop;
|
|
|
|
stimBuff.openClCollatingAndMeshingEngine.compactCollateAndMeshFrameReq(
|
|
loop, stimulusFrame,
|
|
{context, std::bind(
|
|
&ProduceFrameReq::produceFrameReq3_compactCollateDone,
|
|
context.get(), context,
|
|
std::placeholders::_1, std::placeholders::_2)});
|
|
}
|
|
|
|
void produceFrameReq3_compactCollateDone(
|
|
[[maybe_unused]] std::shared_ptr<ProduceFrameReq> context,
|
|
bool success, StimulusFrame& /*stimulusFrame*/)
|
|
{
|
|
if (!success) {
|
|
std::cerr << __func__ << ": Failed to compact and collate frame" << std::endl;
|
|
} else {
|
|
std::cout << __func__ << ": Successfully compacted and collated frame" << std::endl;
|
|
}
|
|
|
|
callOriginalCallback();
|
|
}
|
|
};
|
|
|
|
void PcloudStimulusBuffer::produceFrameReq(
|
|
smo::Callback<produceFrameReqCbFn> callback)
|
|
{
|
|
auto caller = smoHooksPtr->ComponentThread_getSelf();
|
|
auto request = std::make_shared<ProduceFrameReq>(
|
|
*this, caller, std::move(callback));
|
|
|
|
// Post the doAssemble method to the component thread
|
|
device->componentThread->getIoService().post(
|
|
STC(std::bind(
|
|
&ProduceFrameReq::produceFrameReq1_doAssemble_posted,
|
|
request.get(), request)));
|
|
}
|
|
|
|
} // namespace stim_buff
|
|
} // namespace smo
|