35eb466a60
We've now ported the OpenClCollMeshEngn and PcloudStimProd::produceFrameReq portions of the Livox pipeline to coros.
743 lines
22 KiB
C++
743 lines
22 KiB
C++
#include <config.h>
|
|
#include <opts.h>
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
#include <ctime>
|
|
#include <iostream>
|
|
#include <unistd.h>
|
|
#include <iomanip>
|
|
#include <cstddef>
|
|
#include <string>
|
|
#include <user/spMcRingBuffer.h>
|
|
#include <componentThread.h>
|
|
#include <spinscale/asynchronousLoop.h>
|
|
#include <spinscale/co/invokers.h>
|
|
#include <adapters/smo/assembleFrameAReq.h>
|
|
#include <user/stimulusFrame.h>
|
|
#include <user/frameAssemblyDesc.h>
|
|
#include <livoxProto1/device.h>
|
|
#include "livoxGen1.h"
|
|
#include "pcloudStimulusProducer.h"
|
|
|
|
#ifndef SMO_DEBUG_PCLOUD_AMBIENCE_INTRIN
|
|
#define SMO_DEBUG_PCLOUD_AMBIENCE_INTRIN 0
|
|
#endif
|
|
|
|
#ifndef SMO_PRINT_PCLOUD_STAGE_DURATIONS
|
|
#define SMO_PRINT_PCLOUD_STAGE_DURATIONS 1
|
|
#endif
|
|
|
|
namespace smo {
|
|
namespace stim_buff {
|
|
|
|
#if SMO_DEBUG_PCLOUD_AMBIENCE_INTRIN
|
|
namespace {
|
|
|
|
char ambienceComparatorOpChar(ParamComparatorOp op)
|
|
{
|
|
switch (op)
|
|
{
|
|
case OP_CMP_GT:
|
|
return '>';
|
|
case OP_CMP_LT:
|
|
return '<';
|
|
}
|
|
|
|
return '?';
|
|
}
|
|
|
|
} // namespace
|
|
#endif
|
|
|
|
extern const SmoCallbacks* smoHooksPtr;
|
|
|
|
// OpenCL kernels are used to collate and produce our StimFrames.
|
|
static StagingBuffer::IOEngineConstraints openClInputConstraints(
|
|
/** FIXME:
|
|
* This should eventually be aligned to 4B and padded to 12B.
|
|
*/
|
|
// slotStartAlignmentByteVal (page alignment)
|
|
sizeof(float),
|
|
// slotPadToNBytes (XYZ = 3 floats per point)
|
|
sizeof(float) * 3,
|
|
// frameStartAlignmentByteVal (page alignment)
|
|
static_cast<size_t>(sysconf(_SC_PAGE_SIZE)),
|
|
// framePadToNBytes (pointer size)
|
|
static_cast<size_t>(sysconf(_SC_PAGE_SIZE)));
|
|
|
|
// OpenCL kernels are used to collate and produce our StimFrames.
|
|
static StagingBuffer::IOEngineConstraints openClMeshInputConstraints(
|
|
// slotStartAlignmentByteVal (page alignment)
|
|
static_cast<size_t>(sysconf(_SC_PAGE_SIZE)),
|
|
// slotPadToNBytes: This is dynamically calculated based on the return mode.
|
|
sizeof(float) * 3,
|
|
// frameStartAlignmentByteVal (page alignment)
|
|
static_cast<size_t>(sysconf(_SC_PAGE_SIZE)),
|
|
// framePadToNBytes (pointer size)
|
|
static_cast<size_t>(sysconf(_SC_PAGE_SIZE)));
|
|
|
|
static StagingBuffer::IOEngineConstraints openClIntensityInputConstraints(
|
|
// slotStartAlignmentByteVal (page alignment)
|
|
static_cast<size_t>(sysconf(_SC_PAGE_SIZE)),
|
|
// slotPadToNBytes: This is dynamically calculated based on the return mode.
|
|
sizeof(float),
|
|
// frameStartAlignmentByteVal (page alignment)
|
|
static_cast<size_t>(sysconf(_SC_PAGE_SIZE)),
|
|
// framePadToNBytes (pointer size)
|
|
static_cast<size_t>(sysconf(_SC_PAGE_SIZE)));
|
|
|
|
/* IOEngineConstraints for Pcloud[Light|Dark]AmbienceStimulusBuffer's
|
|
* StagingBuffer, which backs SpMcRingBuffer (one StimulusFrame per ring
|
|
* slot — a single uint32 passband count). slotPadToNBytes is sized in
|
|
* ctor to sizeof(uint32_t).
|
|
*/
|
|
static StagingBuffer::IOEngineConstraints openClAmbienceInputConstraints(
|
|
sizeof(uint32_t),
|
|
sizeof(uint32_t),
|
|
// frameStartAlignmentByteVal (page alignment)
|
|
static_cast<size_t>(sysconf(_SC_PAGE_SIZE)),
|
|
// framePadToNBytes (page alignment)
|
|
static_cast<size_t>(sysconf(_SC_PAGE_SIZE)));
|
|
|
|
/* IOEngineConstraints for OClCollMeshEngn's per-slot averageIntensityBuffer
|
|
* staging area. Holds nDgramsPerStagingBufferFrame floats; attached ambience
|
|
* stimbuffs read from it to compute passband counts after collate.
|
|
*/
|
|
static StagingBuffer::IOEngineConstraints openClAverageIntensityConstraints(
|
|
sizeof(float),
|
|
sizeof(float),
|
|
static_cast<size_t>(sysconf(_SC_PAGE_SIZE)),
|
|
static_cast<size_t>(sysconf(_SC_PAGE_SIZE)));
|
|
|
|
PcloudStimulusProducer::PcloudStimulusProducer(
|
|
const std::shared_ptr<device::DeviceAttachmentSpec> &deviceAttachmentSpec,
|
|
std::shared_ptr<livoxProto1::Device> &device,
|
|
const PcloudFormatDesc& formatDesc,
|
|
size_t nDgramsPerStagingBufferFrame)
|
|
: StimulusProducer(
|
|
deviceAttachmentSpec,
|
|
device->componentThread->getIoContext()),
|
|
nDgramsPerStagingBufferFrame(nDgramsPerStagingBufferFrame),
|
|
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),
|
|
collationBufferMlockPinner(collationBuffer.makeMlockPinner()),
|
|
averageIntensityBuffer(
|
|
openClAverageIntensityConstraints,
|
|
openClAverageIntensityConstraints,
|
|
nDgramsPerStagingBufferFrame),
|
|
averageIntensityBufferMlockPinner(averageIntensityBuffer.makeMlockPinner()),
|
|
pcloudFrameDumper(deviceAttachmentSpec),
|
|
tempStimulusFrameMem(0),
|
|
tempStimulusFrame(
|
|
FrameAssemblyDesc::SlotDesc{
|
|
0,
|
|
reinterpret_cast<uint8_t*>(&tempStimulusFrameMem),
|
|
sizeof(tempStimulusFrameMem)},
|
|
*smoHooksPtr, 0, SIZE_MAX)
|
|
{
|
|
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 != SmoThreadId::WORLD)
|
|
#else
|
|
if (smoHooksPtr->ComponentThread_getSelf()->id != SmoThreadId::BODY)
|
|
#endif
|
|
{
|
|
std::string errMsg = std::string(__func__) +
|
|
": PcloudStimulusProducer constructor called on non-world/body thread " +
|
|
smoHooksPtr->ComponentThread_getSelf()->name;
|
|
|
|
std::cout << errMsg << std::endl;
|
|
// throw std::runtime_error(errMsg);
|
|
}
|
|
}
|
|
|
|
bool PcloudStimulusProducer::supportsQualeIfaceApi(
|
|
const std::string& qualeIfaceApi)
|
|
{
|
|
return qualeIfaceApi == "mesh" || qualeIfaceApi == "pcloudIntensity" ||
|
|
qualeIfaceApi == "pcloudLightAmbience" ||
|
|
qualeIfaceApi == "pcloudDarkAmbience";
|
|
}
|
|
|
|
bool PcloudStimulusProducer::exportsQualeIfaceApi(
|
|
const std::string& qualeIfaceApi) const
|
|
{
|
|
return supportsQualeIfaceApi(qualeIfaceApi);
|
|
}
|
|
|
|
void PcloudStimulusProducer::start()
|
|
{
|
|
std::cout << __func__ << ": Starting PcloudStimulusProducer for device "
|
|
<< device->discoveredDevice.deviceIdentifier << std::endl;
|
|
|
|
pcloudFrameDumper.prepareForRun();
|
|
|
|
// Call ioUringAssemblyEngine setup() as the first step
|
|
if (!ioUringAssemblyEngine.setup())
|
|
{
|
|
std::cout <<__func__ <<"Failed to setup() "
|
|
<<"IOUringAssemblyEngine.\n";
|
|
return;
|
|
}
|
|
|
|
if (!openClCollatingAndMeshingEngine.setup())
|
|
{
|
|
ioUringAssemblyEngine.finalize();
|
|
std::cout <<__func__ <<"Failed to setup() "
|
|
<<"OClCollMeshEngine.\n";
|
|
return;
|
|
}
|
|
|
|
// Call base class start() as the final step
|
|
StimulusProducer::start();
|
|
}
|
|
|
|
void PcloudStimulusProducer::stop()
|
|
{
|
|
std::cout << __func__ << ": Stopping PcloudStimulusProducer for device "
|
|
<< device->discoveredDevice.deviceIdentifier << std::endl;
|
|
|
|
// Call base class stop() as the first step
|
|
StimulusProducer::stop();
|
|
// Call ioUringAssemblyEngine stop() as the final step
|
|
openClCollatingAndMeshingEngine.finalize();
|
|
ioUringAssemblyEngine.finalize();
|
|
}
|
|
|
|
void produceStimFrameAck(void)
|
|
{
|
|
}
|
|
|
|
// Helper function to parse histbuffMs from device attachment spec
|
|
static int parseHistbuffMs(
|
|
const std::shared_ptr<device::DeviceAttachmentSpec>& spec)
|
|
{
|
|
const std::vector<std::string> histbuffParamNames = {
|
|
"history-buffer-duration-ms",
|
|
"hist-buff-duration-ms",
|
|
"histbuff-duration-ms",
|
|
"histbuff-ms"
|
|
};
|
|
|
|
return device::DeviceAttachmentSpec::parseOptionalParamAsIntWithSynonyms(
|
|
spec->qualeIfaceApiParams, histbuffParamNames, 30000);
|
|
}
|
|
|
|
std::shared_ptr<StimulusBuffer>
|
|
PcloudStimulusProducer::getAttachedStimulusBuffer(
|
|
const std::shared_ptr<device::DeviceAttachmentSpec>& spec) const
|
|
{
|
|
// Call base class implementation
|
|
auto buffer = StimulusProducer::getAttachedStimulusBuffer(spec);
|
|
if (!buffer)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
// Optionally validate/upcast the buffer type matches expected type
|
|
// based on qualeIfaceApi (for type safety)
|
|
const std::string& qualeIfaceApi = spec->qualeIfaceApi;
|
|
if (qualeIfaceApi == "mesh")
|
|
{
|
|
if (std::dynamic_pointer_cast<MeshStimulusBuffer>(buffer))
|
|
{ return buffer; }
|
|
}
|
|
else if (qualeIfaceApi == "pcloudIntensity")
|
|
{
|
|
if (std::dynamic_pointer_cast<PcloudIntensityStimulusBuffer>(buffer))
|
|
{ return buffer; }
|
|
}
|
|
else if (qualeIfaceApi == "pcloudLightAmbience")
|
|
{
|
|
if (std::dynamic_pointer_cast<PcloudLightAmbienceStimulusBuffer>(buffer))
|
|
{ return buffer; }
|
|
}
|
|
else if (qualeIfaceApi == "pcloudDarkAmbience")
|
|
{
|
|
if (std::dynamic_pointer_cast<PcloudDarkAmbienceStimulusBuffer>(buffer))
|
|
{ return buffer; }
|
|
}
|
|
|
|
// Type mismatch - return nullptr
|
|
return nullptr;
|
|
}
|
|
|
|
void PcloudStimulusProducer::destroyAttachedStimulusBuffer(
|
|
const std::shared_ptr<StimulusBuffer>& buffer)
|
|
{
|
|
if (!buffer) { return; }
|
|
|
|
this->stop();
|
|
|
|
// Clear specialized buffer pointers if they match
|
|
auto meshBuff = meshStimulusBuffer.load(std::memory_order_acquire);
|
|
if (meshBuff == buffer)
|
|
{
|
|
meshBuff.reset();
|
|
meshStimulusBuffer.store(nullptr, std::memory_order_release);
|
|
}
|
|
auto intensityBuff = intensityStimulusBuffer.load(std::memory_order_acquire);
|
|
if (intensityBuff == buffer)
|
|
{
|
|
intensityBuff.reset();
|
|
intensityStimulusBuffer.store(nullptr, std::memory_order_release);
|
|
}
|
|
auto lightAmbienceBuff = lightAmbienceStimulusBuffer.load(
|
|
std::memory_order_acquire);
|
|
if (lightAmbienceBuff == buffer)
|
|
{
|
|
lightAmbienceBuff.reset();
|
|
lightAmbienceStimulusBuffer.store(nullptr, std::memory_order_release);
|
|
}
|
|
auto darkAmbienceBuff = darkAmbienceStimulusBuffer.load(
|
|
std::memory_order_acquire);
|
|
if (darkAmbienceBuff == buffer)
|
|
{
|
|
darkAmbienceBuff.reset();
|
|
darkAmbienceStimulusBuffer.store(nullptr, std::memory_order_release);
|
|
}
|
|
|
|
// Call base class implementation to remove from attachedStimulusBuffers
|
|
StimulusProducer::destroyAttachedStimulusBuffer(buffer);
|
|
|
|
this->start();
|
|
}
|
|
|
|
std::shared_ptr<StimulusBuffer>
|
|
PcloudStimulusProducer::getOrCreateAttachedStimulusBuffer(
|
|
const std::shared_ptr<device::DeviceAttachmentSpec>& deviceAttachmentSpec
|
|
)
|
|
{
|
|
// Check if buffer already exists (idempotent)
|
|
auto existingBuffer = getAttachedStimulusBuffer(deviceAttachmentSpec);
|
|
if (existingBuffer)
|
|
{ return existingBuffer; }
|
|
|
|
// Parse histbuffMs from device attachment spec
|
|
int histbuffMs = parseHistbuffMs(deviceAttachmentSpec);
|
|
|
|
// Parse qualeIfaceApi to determine buffer type
|
|
const std::string& qualeIfaceApi = deviceAttachmentSpec->qualeIfaceApi;
|
|
|
|
if (qualeIfaceApi == "mesh")
|
|
{
|
|
size_t nPointsPerDgram = livoxProto1::Device::getNPointsPerDgram(
|
|
static_cast<int>(device->currentReturnMode));
|
|
/* Calculate slotStrideNBytes:
|
|
* nDgramsPerStagingBufferFrame * nPointsPerDgram * sizeof(float) * 3
|
|
*/
|
|
size_t slotStrideNBytes = this->nDgramsPerStagingBufferFrame
|
|
* nPointsPerDgram * sizeof(float) * 3;
|
|
// Reuse openClMeshInputConstraints, only modify slotPadToNBytes
|
|
openClMeshInputConstraints.slotPadToNBytes = slotStrideNBytes;
|
|
|
|
auto meshBuffer = std::make_shared<MeshStimulusBuffer>(
|
|
*this, deviceAttachmentSpec, histbuffMs,
|
|
openClMeshInputConstraints, openClMeshInputConstraints,
|
|
*smoHooksPtr, CL_MEM_READ_WRITE);
|
|
|
|
this->stop();
|
|
addAttachedStimulusBufferIfNotExists(meshBuffer);
|
|
meshStimulusBuffer.store(meshBuffer, std::memory_order_release);
|
|
this->start();
|
|
return meshBuffer;
|
|
}
|
|
else if (qualeIfaceApi == "pcloudIntensity")
|
|
{
|
|
size_t nPointsPerDgram = livoxProto1::Device::getNPointsPerDgram(
|
|
static_cast<int>(device->currentReturnMode));
|
|
/* Calculate slotStrideNBytes:
|
|
* nDgramsPerStagingBufferFrame * nPointsPerDgram * sizeof(float) * 1
|
|
*/
|
|
size_t slotStrideNBytes = this->nDgramsPerStagingBufferFrame
|
|
* nPointsPerDgram * sizeof(float) * 1;
|
|
// Reuse openClIntensityInputConstraints, only modify slotPadToNBytes
|
|
openClIntensityInputConstraints.slotPadToNBytes = slotStrideNBytes;
|
|
|
|
auto intensityBuffer = std::make_shared<PcloudIntensityStimulusBuffer>(
|
|
*this, deviceAttachmentSpec, histbuffMs,
|
|
openClIntensityInputConstraints, openClIntensityInputConstraints,
|
|
*smoHooksPtr, CL_MEM_READ_WRITE);
|
|
|
|
this->stop();
|
|
addAttachedStimulusBufferIfNotExists(intensityBuffer);
|
|
intensityStimulusBuffer.store(
|
|
intensityBuffer, std::memory_order_release);
|
|
this->start();
|
|
return intensityBuffer;
|
|
}
|
|
else if (qualeIfaceApi == "pcloudLightAmbience")
|
|
{
|
|
auto lightAmbienceStimBuff =
|
|
std::make_shared<PcloudLightAmbienceStimulusBuffer>(
|
|
*this, deviceAttachmentSpec, histbuffMs,
|
|
openClAmbienceInputConstraints, openClAmbienceInputConstraints,
|
|
*smoHooksPtr, CL_MEM_READ_WRITE,
|
|
this->nDgramsPerStagingBufferFrame);
|
|
|
|
this->stop();
|
|
addAttachedStimulusBufferIfNotExists(lightAmbienceStimBuff);
|
|
lightAmbienceStimulusBuffer.store(
|
|
lightAmbienceStimBuff, std::memory_order_release);
|
|
this->start();
|
|
return lightAmbienceStimBuff;
|
|
}
|
|
else if (qualeIfaceApi == "pcloudDarkAmbience")
|
|
{
|
|
auto darkAmbienceStimBuff =
|
|
std::make_shared<PcloudDarkAmbienceStimulusBuffer>(
|
|
*this, deviceAttachmentSpec, histbuffMs,
|
|
openClAmbienceInputConstraints, openClAmbienceInputConstraints,
|
|
*smoHooksPtr, CL_MEM_READ_WRITE,
|
|
this->nDgramsPerStagingBufferFrame);
|
|
|
|
this->stop();
|
|
addAttachedStimulusBufferIfNotExists(darkAmbienceStimBuff);
|
|
darkAmbienceStimulusBuffer.store(
|
|
darkAmbienceStimBuff, std::memory_order_release);
|
|
this->start();
|
|
return darkAmbienceStimBuff;
|
|
}
|
|
else
|
|
{
|
|
throw std::runtime_error(
|
|
"Unsupported qualeIfaceApi: '" + qualeIfaceApi + "' for "
|
|
"PcloudStimulusProducer. "
|
|
"Supported values: mesh, pcloudIntensity, "
|
|
"pcloudLightAmbience, pcloudDarkAmbience");
|
|
}
|
|
}
|
|
|
|
void PcloudStimulusProducer::stimFrameProductionTimesliceInd()
|
|
{
|
|
holdProduceFrameCReq();
|
|
}
|
|
|
|
struct AllowNextStimulusFrameGuard
|
|
{
|
|
PcloudStimulusProducer& producer;
|
|
|
|
explicit AllowNextStimulusFrameGuard(PcloudStimulusProducer& _producer)
|
|
: producer(_producer)
|
|
{}
|
|
|
|
~AllowNextStimulusFrameGuard()
|
|
{ producer.allowNextStimulusFrame(); }
|
|
};
|
|
|
|
void PcloudStimulusProducer::holdProduceFrameCReq()
|
|
{
|
|
/** EXPLANATION:
|
|
* We shouldn't acquire stimulusProducerCanceler.s.lock here because
|
|
* this function is called from
|
|
* StimulusProducer::stimFrameProductionTimesliceInd(), which is already
|
|
* holding the lock.
|
|
*/
|
|
activeProduceFrameInvoker.emplace(produceFrameCReq(
|
|
produceFrameExceptionPtr,
|
|
[this]() { activeProduceFrameInvoker.reset(); }));
|
|
}
|
|
|
|
sscl::co::NonViralNonPostingInvoker PcloudStimulusProducer::produceFrameCReq(
|
|
[[maybe_unused]] std::exception_ptr& exceptionPtr,
|
|
[[maybe_unused]] std::function<void()> completion)
|
|
{
|
|
AllowNextStimulusFrameGuard allowNextGuard(*this);
|
|
StimulusFrame& stimulusFrame = tempStimulusFrame;
|
|
sscl::AsynchronousLoop frameAssemblyResult(0);
|
|
std::optional<std::reference_wrapper<StimulusFrame>> intensityStimFrame;
|
|
std::optional<std::reference_wrapper<StimulusFrame>> lightAmbienceStimFrame;
|
|
std::optional<std::reference_wrapper<StimulusFrame>> darkAmbienceStimFrame;
|
|
|
|
auto& resumeIoContext = device->componentThread->getIoContext();
|
|
|
|
// produceFrameReq1_doAssemble_posted
|
|
/** EXPLANATION:
|
|
* stimFrameProductionTimesliceInd() is entered with
|
|
* stimulusProducerCanceler.s.lock held; do not re-acquire here.
|
|
*
|
|
* This function is called from
|
|
* StimulusProducer::stimFrameProductionTimesliceInd(), whose caller is
|
|
* already holding the lock.
|
|
*/
|
|
if (stimulusProducerCanceler.isCancellationRequestedUnlocked())
|
|
{ co_return; }
|
|
|
|
cpsBoundary::AssembleFrameResult assembleResult = co_await
|
|
cpsBoundary::getAssembleFrameReqAReqAwaiter(
|
|
resumeIoContext, ioUringAssemblyEngine);
|
|
|
|
// produceFrameReq2_assembleDone
|
|
std::optional<AmbienceProductionDesc> lightAmbienceProductionDescDesc;
|
|
std::optional<AmbienceProductionDesc> darkAmbienceProductionDescDesc;
|
|
{
|
|
sscl::SpinLock::Guard guard(stimulusProducerCanceler.s.lock);
|
|
if (stimulusProducerCanceler.isCancellationRequestedUnlocked())
|
|
{ co_return; }
|
|
|
|
if (!assembleResult.success)
|
|
{
|
|
if (attachedStimulusBuffers.size() > 0) {
|
|
std::cerr << __func__ << ": Failed to assemble frame.\n";
|
|
}
|
|
co_return;
|
|
}
|
|
|
|
frameAssemblyResult = assembleResult.loop;
|
|
|
|
// Check if intensity buffer is attached and acquire frame if so
|
|
if (auto intensityBuff = intensityStimulusBuffer.load(
|
|
std::memory_order_acquire))
|
|
{
|
|
size_t intensityRingbuffIndex = intensityBuff
|
|
->ringBuffer.getIndexToProduceInto();
|
|
|
|
StimulusFrame& intensityStimFrameRef = intensityBuff
|
|
->ringBuffer.getDataAtSlot(
|
|
intensityRingbuffIndex);
|
|
|
|
intensityStimFrameRef.lock.writeAcquire();
|
|
intensityStimFrame = std::make_optional(
|
|
std::ref(intensityStimFrameRef));
|
|
}
|
|
else {
|
|
intensityStimFrame = std::nullopt;
|
|
}
|
|
|
|
// Check if light ambience buffer is attached and acquire frame if so
|
|
if (auto lightAmbienceBuff =
|
|
lightAmbienceStimulusBuffer.load(
|
|
std::memory_order_acquire))
|
|
{
|
|
size_t lightAmbienceRingbuffIndex = lightAmbienceBuff
|
|
->ringBuffer.getIndexToProduceInto();
|
|
|
|
StimulusFrame& lightAmbienceStimFrameRef = lightAmbienceBuff
|
|
->ringBuffer.getDataAtSlot(lightAmbienceRingbuffIndex);
|
|
|
|
lightAmbienceStimFrameRef.lock.writeAcquire();
|
|
lightAmbienceStimFrame = std::make_optional(
|
|
std::ref(lightAmbienceStimFrameRef));
|
|
lightAmbienceProductionDescDesc = AmbienceProductionDesc{
|
|
std::ref(lightAmbienceStimFrameRef),
|
|
lightAmbienceBuff->passbandCountGtComparator};
|
|
}
|
|
else {
|
|
lightAmbienceStimFrame = std::nullopt;
|
|
}
|
|
|
|
// Check if dark ambience buffer is attached and acquire frame if so
|
|
if (auto darkAmbienceBuff =
|
|
darkAmbienceStimulusBuffer.load(
|
|
std::memory_order_acquire))
|
|
{
|
|
size_t darkAmbienceRingbuffIndex = darkAmbienceBuff
|
|
->ringBuffer.getIndexToProduceInto();
|
|
|
|
StimulusFrame& darkAmbienceStimFrameRef = darkAmbienceBuff
|
|
->ringBuffer.getDataAtSlot(darkAmbienceRingbuffIndex);
|
|
|
|
darkAmbienceStimFrameRef.lock.writeAcquire();
|
|
darkAmbienceStimFrame = std::make_optional(
|
|
std::ref(darkAmbienceStimFrameRef));
|
|
darkAmbienceProductionDescDesc = AmbienceProductionDesc{
|
|
std::ref(darkAmbienceStimFrameRef),
|
|
darkAmbienceBuff->passbandCountLtComparator};
|
|
}
|
|
else {
|
|
darkAmbienceStimFrame = std::nullopt;
|
|
}
|
|
}
|
|
|
|
bool compactCollateSuccess = co_await
|
|
openClCollatingAndMeshingEngine.compactCollateAndMeshFrameCReq(
|
|
frameAssemblyResult, stimulusFrame,
|
|
intensityStimFrame,
|
|
std::move(lightAmbienceProductionDescDesc),
|
|
std::move(darkAmbienceProductionDescDesc));
|
|
|
|
// produceFrameReq3_compactCollateDone
|
|
#if SMO_DEBUG_PCLOUD_AMBIENCE_INTRIN
|
|
uint32_t logLightPassbandCount = 0;
|
|
uint32_t logDarkPassbandCount = 0;
|
|
bool logLightAmbience = false;
|
|
bool logDarkAmbience = false;
|
|
if (compactCollateSuccess)
|
|
{
|
|
if (lightAmbienceStimFrame.has_value())
|
|
{
|
|
logLightPassbandCount = *reinterpret_cast<const uint32_t*>(
|
|
lightAmbienceStimFrame->get().slotDesc.vaddr);
|
|
logLightAmbience = true;
|
|
}
|
|
if (darkAmbienceStimFrame.has_value())
|
|
{
|
|
logDarkPassbandCount = *reinterpret_cast<const uint32_t*>(
|
|
darkAmbienceStimFrame->get().slotDesc.vaddr);
|
|
logDarkAmbience = true;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Release intensity frame if it was used
|
|
if (intensityStimFrame.has_value()) {
|
|
intensityStimFrame->get().lock.writeRelease();
|
|
}
|
|
// Release ambience frames if they were used
|
|
if (lightAmbienceStimFrame.has_value()) {
|
|
lightAmbienceStimFrame->get().lock.writeRelease();
|
|
}
|
|
if (darkAmbienceStimFrame.has_value()) {
|
|
darkAmbienceStimFrame->get().lock.writeRelease();
|
|
}
|
|
|
|
{
|
|
sscl::SpinLock::Guard guard(stimulusProducerCanceler.s.lock);
|
|
if (stimulusProducerCanceler.isCancellationRequestedUnlocked())
|
|
{ co_return; }
|
|
|
|
if (!compactCollateSuccess) {
|
|
std::cerr << "produceFrameReq3_compactCollateDone"
|
|
<< ": Failed to compact and collate frame" << std::endl;
|
|
} else
|
|
{
|
|
guard.unlockPrematurely();
|
|
if (pcloudFrameDumper.isEnabled())
|
|
{
|
|
try
|
|
{
|
|
pcloudFrameDumper.dumpProducedFrame(
|
|
*device, collationBuffer,
|
|
frameAssemblyResult);
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
std::cerr << __func__ << ": Failed to dump pcloud frame: "
|
|
<< e.what() << std::endl;
|
|
}
|
|
}
|
|
|
|
#if SMO_DEBUG_PCLOUD_AMBIENCE_INTRIN
|
|
if (logLightAmbience)
|
|
{
|
|
auto lightBuff =
|
|
lightAmbienceStimulusBuffer.load(
|
|
std::memory_order_acquire);
|
|
if (lightBuff)
|
|
{
|
|
std::cerr << __func__ << ": pcloudLightAmbience "
|
|
<< "passbandCount=" << logLightPassbandCount
|
|
<< " (per-slot avg intensity "
|
|
<< ambienceComparatorOpChar(
|
|
lightBuff->passbandCountGtComparator.op)
|
|
<< " " << lightBuff->passbandCountGtComparator.value
|
|
<< ")";
|
|
if (lightBuff->negtrinInterestConfig.has_value())
|
|
{
|
|
const auto& nc = *lightBuff->negtrinInterestConfig;
|
|
std::cerr << " negtrinInterestThr=" << nc.threshold;
|
|
if (nc.percentage != 0U)
|
|
{
|
|
std::cerr << " (from " << nc.percentage << "%)";
|
|
}
|
|
std::cerr << " meetsNegtrinInterest="
|
|
<< (lightBuff->shouldTriggerNegtrinEvent(
|
|
logLightPassbandCount)
|
|
? "yes" : "no");
|
|
}
|
|
else
|
|
{
|
|
std::cerr << " negtrinInterest(n/a)";
|
|
}
|
|
std::cerr << std::endl;
|
|
}
|
|
}
|
|
if (logDarkAmbience)
|
|
{
|
|
auto darkBuff =
|
|
darkAmbienceStimulusBuffer.load(
|
|
std::memory_order_acquire);
|
|
if (darkBuff)
|
|
{
|
|
std::cerr << __func__ << ": pcloudDarkAmbience "
|
|
<< "passbandCount=" << logDarkPassbandCount
|
|
<< " (per-slot avg intensity "
|
|
<< ambienceComparatorOpChar(
|
|
darkBuff->passbandCountLtComparator.op)
|
|
<< " " << darkBuff->passbandCountLtComparator.value
|
|
<< ")";
|
|
if (darkBuff->postrinInterestConfig.has_value())
|
|
{
|
|
const auto& pc = *darkBuff->postrinInterestConfig;
|
|
std::cerr << " postrinInterestThr=" << pc.threshold;
|
|
if (pc.percentage != 0U)
|
|
{
|
|
std::cerr << " (from " << pc.percentage << "%)";
|
|
}
|
|
std::cerr << " meetsPostrinInterest="
|
|
<< (darkBuff->shouldTriggerPostrinEvent(
|
|
logDarkPassbandCount)
|
|
? "yes" : "no");
|
|
}
|
|
else
|
|
{
|
|
std::cerr << " postrinInterest(n/a)";
|
|
}
|
|
std::cerr << std::endl;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if SMO_PRINT_PCLOUD_STAGE_DURATIONS
|
|
const auto logNow = std::chrono::system_clock::now();
|
|
const std::time_t logTime =
|
|
std::chrono::system_clock::to_time_t(logNow);
|
|
const auto logSubsecMs =
|
|
std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
logNow.time_since_epoch()) % 1000;
|
|
auto assemblyDuration =
|
|
ioUringAssemblyEngine.getAssemblyDuration();
|
|
auto compactDuration =
|
|
openClCollatingAndMeshingEngine
|
|
.getCompactKernelDuration();
|
|
auto collateDuration =
|
|
openClCollatingAndMeshingEngine
|
|
.getCollateKernelDuration();
|
|
std::cout << std::put_time(std::localtime(&logTime), "%T")
|
|
<< '.' << std::setfill('0') << std::setw(3)
|
|
<< logSubsecMs.count() << ' '
|
|
<< __func__ << ": stage durations: assembly="
|
|
<< assemblyDuration.count()
|
|
<< "ms, compactKernel=" << compactDuration.count()
|
|
<< "ms, collateKernel=" << collateDuration.count()
|
|
<< "ms" << std::endl;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
co_return;
|
|
}
|
|
|
|
} // namespace stim_buff
|
|
} // namespace smo
|