Lg1: Implement both light|darkAmbience stimBuffs & their production

We now produce both light and dark ambience stimframes into
stimbuffs for the LivoxGen1 lidar devices.
This commit is contained in:
2026-04-18 14:54:14 -04:00
parent 632a227985
commit 27a5d48451
15 changed files with 668 additions and 336 deletions
+4 -2
View File
@@ -513,7 +513,8 @@ static const StimBuffApiDesc livoxGen1ApiDesc = {
.exportedQualeIfaceApis = {
{.name = "mesh"},
{.name = "pcloudIntensity"},
{.name = "pcloudAmbience"},
{.name = "pcloudLightAmbience"},
{.name = "pcloudDarkAmbience"},
{.name = "gyro"},
{.name = "accel"}
},
@@ -662,7 +663,8 @@ extern "C" void livoxGen1_attachDeviceReq(
// Unknown qualeIfaceApi
std::cerr << __func__ << ": Unsupported qualeIfaceApi '"
<< qualeIfaceApi << "' for LivoxGen1. "
"Supported values: mesh, pcloudIntensity, pcloudAmbience"
"Supported values: mesh, pcloudIntensity, "
"pcloudLightAmbience, pcloudDarkAmbience"
<< std::endl;
cb.callbackFn(false, desc);
return;
+2 -2
View File
@@ -15,8 +15,8 @@ class StimulusProducer;
/**
* MeshStimulusBuffer is a specialized StimulusBuffer for mesh data.
* Intrinsic threshold params are not allowed on mesh qualeIfaceApi lines;
* attach postrin(...) / negtrin(...) specifiers to a pcloudAmbience nontrin
* spec instead.
* attach postrin(...) specifiers to a pcloudDarkAmbience line or
* negtrin(...) specifiers to a pcloudLightAmbience line instead.
*/
class MeshStimulusBuffer
: public StimulusBuffer
@@ -35,8 +35,10 @@ OpenClCollatingAndMeshingEngine::OpenClCollatingAndMeshingEngine(
computeDevice(nullptr),
clAssemblyBufferClBuffer(nullptr),
clCollationBufferClBuffer(nullptr),
clAverageIntensityBufferClBuffer(nullptr),
clAssemblyBuffer(nullptr),
clCollationBuffer(nullptr),
clAverageIntensityBuffer(nullptr),
shouldAcceptRequests(false),
compactIsRunning(false),
collateIsRunning(false),
@@ -45,8 +47,11 @@ assemblyBufferPtr(nullptr),
assemblyBufferSize(0),
collationBufferPtr(nullptr),
collationBufferSize(0),
averageIntensityBufferPtr(nullptr),
averageIntensityBufferSize(0),
mappedAssemblyBuffer(nullptr),
mappedCollationBuffer(nullptr),
mappedAverageIntensityBuffer(nullptr),
frameAssemblyDesc(nullptr)
{
}
@@ -85,11 +90,15 @@ bool OpenClCollatingAndMeshingEngine::setup()
// Get StagingBuffer memory pointers from parent
struct iovec assemblyIov = parent.assemblyBuffer.getClEngineIovec();
struct iovec collationIov = parent.collationBuffer.getClEngineIovec();
struct iovec averageIntensityIov = parent.averageIntensityBuffer
.getClEngineIovec();
assemblyBufferPtr = assemblyIov.iov_base;
assemblyBufferSize = assemblyIov.iov_len;
collationBufferPtr = collationIov.iov_base;
collationBufferSize = collationIov.iov_len;
averageIntensityBufferPtr = averageIntensityIov.iov_base;
averageIntensityBufferSize = averageIntensityIov.iov_len;
// Get FrameAssemblyDesc from assembly buffer
frameAssemblyDesc = static_cast<std::shared_ptr<FrameAssemblyDesc>>(
@@ -131,13 +140,33 @@ bool OpenClCollatingAndMeshingEngine::setup()
return false;
}
/* CL_MEM_WRITE_ONLY describes *kernel* access: the collate kernel only
* writes per-slot averages, never reads them. Host-side reads in
* produceAmbienceStimulusFrame go through clEnqueueMapBuffer(CL_MAP_READ)
* which is independent of this flag.
*/
auto wip_clAverageIntensityBufferClBuffer = smoHooksPtr
->ComputeManager_createUseHostPtrBuffer(
averageIntensityBufferPtr, averageIntensityBufferSize,
CL_MEM_WRITE_ONLY);
if (!wip_clAverageIntensityBufferClBuffer)
{
std::cerr << __func__ << ": failed to create average intensity buffer"
<< std::endl;
return false;
}
// Cache cl_mem handles for the device we're using
cl_mem wip_clAssemblyBuffer = wip_clAssemblyBufferClBuffer
->getAssociatedBufferHandleForDevice(wip_computeDevice);
cl_mem wip_clCollationBuffer = wip_clCollationBufferClBuffer
->getAssociatedBufferHandleForDevice(wip_computeDevice);
cl_mem wip_clAverageIntensityBuffer = wip_clAverageIntensityBufferClBuffer
->getAssociatedBufferHandleForDevice(wip_computeDevice);
if (!wip_clAssemblyBuffer || !wip_clCollationBuffer)
if (!wip_clAssemblyBuffer || !wip_clCollationBuffer
|| !wip_clAverageIntensityBuffer)
{
std::cerr << __func__ << ": failed to get buffer handles for device"
<< std::endl;
@@ -162,8 +191,10 @@ bool OpenClCollatingAndMeshingEngine::setup()
computeDevice = wip_computeDevice;
clAssemblyBufferClBuffer = wip_clAssemblyBufferClBuffer;
clCollationBufferClBuffer = wip_clCollationBufferClBuffer;
clAverageIntensityBufferClBuffer = wip_clAverageIntensityBufferClBuffer;
clAssemblyBuffer = wip_clAssemblyBuffer;
clCollationBuffer = wip_clCollationBuffer;
clAverageIntensityBuffer = wip_clAverageIntensityBuffer;
slotCompactorProgram = std::move(wip_slotCompactorProgram);
collateProgram = std::move(wip_collateProgram);
slotCompactorKernel = std::move(wip_slotCompactorKernel);
@@ -184,7 +215,7 @@ void OpenClCollatingAndMeshingEngine::finalize()
// Complete any running kernels
if (compactIsRunning) { compactKernelComplete(true); }
if (collateIsRunning) {
collateKernelComplete(std::nullopt, std::nullopt, true);
collateKernelComplete(std::nullopt, false, true);
}
{
@@ -227,6 +258,12 @@ void OpenClCollatingAndMeshingEngine::finalize()
// Release OpenCL buffers via smo hooks
if (smoHooksPtr && smoHooksPtr->ComputeManager_releaseUseHostPtrBuffer)
{
if (clAverageIntensityBufferClBuffer)
{
smoHooksPtr->ComputeManager_releaseUseHostPtrBuffer(
clAverageIntensityBufferClBuffer);
clAverageIntensityBufferClBuffer.reset();
}
if (clCollationBufferClBuffer)
{
smoHooksPtr->ComputeManager_releaseUseHostPtrBuffer(
@@ -242,6 +279,7 @@ void OpenClCollatingAndMeshingEngine::finalize()
}
// Reset cached cl_mem handles
clAverageIntensityBuffer = nullptr;
clCollationBuffer = nullptr;
clAssemblyBuffer = nullptr;
@@ -268,6 +306,8 @@ void OpenClCollatingAndMeshingEngine::finalize()
assemblyBufferSize = 0;
collationBufferPtr = nullptr;
collationBufferSize = 0;
averageIntensityBufferPtr = nullptr;
averageIntensityBufferSize = 0;
frameAssemblyDesc = nullptr;
}
@@ -364,7 +404,7 @@ bool OpenClCollatingAndMeshingEngine::startCompactKernel(
bool OpenClCollatingAndMeshingEngine::startCollateKernel(
std::optional<std::reference_wrapper<StimulusFrame>> intensityStimFrame,
std::optional<std::reference_wrapper<StimulusFrame>> ambienceStimFrame,
bool anyAmbienceAttached,
collateKernelCbFn callback)
{
// Store the caller's callback
@@ -374,11 +414,15 @@ bool OpenClCollatingAndMeshingEngine::startCollateKernel(
auto validateBuffers = [this]() {
struct iovec assemblyIov = parent.assemblyBuffer.getClEngineIovec();
struct iovec collationIov = parent.collationBuffer.getClEngineIovec();
struct iovec averageIntensityIov = parent.averageIntensityBuffer
.getClEngineIovec();
if (assemblyIov.iov_base != assemblyBufferPtr
|| assemblyIov.iov_len != assemblyBufferSize
|| collationIov.iov_base != collationBufferPtr
|| collationIov.iov_len != collationBufferSize)
|| collationIov.iov_len != collationBufferSize
|| averageIntensityIov.iov_base != averageIntensityBufferPtr
|| averageIntensityIov.iov_len != averageIntensityBufferSize)
{
throw std::runtime_error(
std::string(__func__) + ": buffer mismatch - buffers have changed");
@@ -386,9 +430,9 @@ bool OpenClCollatingAndMeshingEngine::startCollateKernel(
};
// Setup args callable
auto setupArgs = [this, intensityStimFrame, ambienceStimFrame]()
auto setupArgs = [this, intensityStimFrame, anyAmbienceAttached]()
{
return setupCollateDgramsArgs(intensityStimFrame, ambienceStimFrame);
return setupCollateDgramsArgs(intensityStimFrame, anyAmbienceAttached);
};
/** EXPLANATION:
@@ -439,27 +483,17 @@ bool OpenClCollatingAndMeshingEngine::startCollateKernel(
}
}
// Map/unmap ambience stim frame buffer (collate writes per-slot averages here)
if (ambienceStimFrame.has_value())
// Map/unmap average intensity staging buffer (collate writes per-slot
// averages here when any ambience stimbuff is attached).
if (anyAmbienceAttached)
{
StimulusFrame& ambienceFrame = ambienceStimFrame->get();
cl_mem ambienceClBuffer = ambienceFrame.clBuffer
->getAssociatedBufferHandleForDevice(computeDevice);
if (ambienceClBuffer)
if (!mapAverageIntensityBuffer(CL_MAP_WRITE_INVALIDATE_REGION))
{
void* mappedAmbienceBuffer = nullptr;
if (!mapBuffer(
ambienceClBuffer, ambienceFrame.slotDesc.nBytes,
CL_MAP_WRITE_INVALIDATE_REGION, mappedAmbienceBuffer))
{
std::cerr << __func__ << ": failed to map ambience buffer"
<< std::endl;
return false;
}
unmapBuffer(ambienceClBuffer, mappedAmbienceBuffer);
std::cerr << __func__ << ": failed to map average intensity buffer"
<< std::endl;
return false;
}
unmapAverageIntensityBuffer();
}
// Calculate global work size (just num slots in the frame)
@@ -630,7 +664,7 @@ bool OpenClCollatingAndMeshingEngine::setupSlotCompactorsArgs(
bool OpenClCollatingAndMeshingEngine::setupCollateDgramsArgs(
std::optional<std::reference_wrapper<StimulusFrame>> intensityStimFrame,
std::optional<std::reference_wrapper<StimulusFrame>> ambienceStimFrame)
bool anyAmbienceAttached)
{
// Extract parameters for collateDgrams kernel
uint32_t slotStride = static_cast<uint32_t>(
@@ -684,26 +718,20 @@ bool OpenClCollatingAndMeshingEngine::setupCollateDgramsArgs(
return false;
}
// Set ambience buffer argument (arg 3): acquired PcloudAmbience StimulusFrame
cl_mem ambienceClBufferArg = nullptr;
if (ambienceStimFrame.has_value())
// Set ambience buffer argument (arg 3): per-slot average intensity
// staging buffer. Set when any ambience stimbuff is attached.
cl_mem averageIntensityClBufferArg =
anyAmbienceAttached ? clAverageIntensityBuffer : nullptr;
const size_t needBytes = static_cast<size_t>(nDgramsPerFrame)
* sizeof(float);
if (anyAmbienceAttached && averageIntensityBufferSize < needBytes)
{
StimulusFrame& ambienceFrame = ambienceStimFrame->get();
const size_t needBytes = static_cast<size_t>(nDgramsPerFrame)
* sizeof(float);
if (ambienceFrame.slotDesc.nBytes < needBytes)
{
std::cerr << __func__ << ": ambience stim frame slot too small: "
<< ambienceFrame.slotDesc.nBytes << " < " << needBytes
<< std::endl;
return false;
}
ambienceClBufferArg = ambienceFrame.clBuffer
->getAssociatedBufferHandleForDevice(computeDevice);
std::cerr << __func__ << ": average intensity buffer too small: "
<< averageIntensityBufferSize << " < " << needBytes << std::endl;
return false;
}
err = clSetKernelArg(
collateKernel.get(), 3, sizeof(cl_mem), &ambienceClBufferArg);
collateKernel.get(), 3, sizeof(cl_mem), &averageIntensityClBufferArg);
if (err != CL_SUCCESS)
{
@@ -782,7 +810,7 @@ void OpenClCollatingAndMeshingEngine::compactKernelComplete(bool isFinalizing)
void OpenClCollatingAndMeshingEngine::collateKernelComplete(
std::optional<std::reference_wrapper<StimulusFrame>> intensityStimFrame,
std::optional<std::reference_wrapper<StimulusFrame>> ambienceStimFrame,
bool anyAmbienceAttached,
bool isFinalizing)
{
cl_map_flags mapFlags;
@@ -816,22 +844,12 @@ void OpenClCollatingAndMeshingEngine::collateKernelComplete(
}
}
// Sync GPU writes into ambience stim frame host backing store
if (ambienceStimFrame.has_value())
// Sync GPU writes into average intensity staging buffer host backing
// store so attached ambience stimbuffs can read the per-slot averages.
if (anyAmbienceAttached)
{
StimulusFrame& ambienceFrame = ambienceStimFrame->get();
cl_mem ambienceClBuffer = ambienceFrame.clBuffer
->getAssociatedBufferHandleForDevice(computeDevice);
if (ambienceClBuffer)
{
void* mappedAmbienceBuffer = nullptr;
if (mapBuffer(
ambienceClBuffer, ambienceFrame.slotDesc.nBytes,
CL_MAP_READ, mappedAmbienceBuffer))
{
unmapBuffer(ambienceClBuffer, mappedAmbienceBuffer);
}
if (mapAverageIntensityBuffer(mapFlags)) {
unmapAverageIntensityBuffer();
}
}
@@ -956,6 +974,39 @@ bool OpenClCollatingAndMeshingEngine::unmapCollationBuffer()
return true;
}
bool OpenClCollatingAndMeshingEngine::mapAverageIntensityBuffer(
cl_map_flags mapFlags)
{
return mapBuffer(
clAverageIntensityBuffer, averageIntensityBufferSize, mapFlags,
mappedAverageIntensityBuffer);
}
bool OpenClCollatingAndMeshingEngine::unmapAverageIntensityBuffer()
{
unmapBuffer(clAverageIntensityBuffer, mappedAverageIntensityBuffer);
mappedAverageIntensityBuffer = nullptr;
return true;
}
void OpenClCollatingAndMeshingEngine::produceAmbienceStimulusFrame(
StimulusFrame& ambienceFrame, const ParamComparator& comparator,
uint32_t nSucceeded)
{
const float* averages =
static_cast<const float*>(averageIntensityBufferPtr);
uint32_t passbandCount = 0;
for (uint32_t i = 0; i < nSucceeded; ++i) {
const float& average = averages[i];
if (comparator(average)) { ++passbandCount; }
}
uint32_t& passbandCountOut =
*reinterpret_cast<uint32_t*>(ambienceFrame.slotDesc.vaddr);
passbandCountOut = passbandCount;
}
class OpenClCollatingAndMeshingEngine::CompactCollateAndMeshFrameReq
: public sscl::PostedAsynchronousContinuation<compactCollateAndMeshFrameReqCbFn>
{
@@ -964,7 +1015,8 @@ private:
sscl::AsynchronousLoop frameAssemblyResult;
StimulusFrame& stimulusFrame;
std::optional<std::reference_wrapper<StimulusFrame>> intensityStimFrame;
std::optional<std::reference_wrapper<StimulusFrame>> ambienceStimFrame;
std::optional<AmbienceProductionDesc> lightAmbienceProductionDesc;
std::optional<AmbienceProductionDesc> darkAmbienceProductionDesc;
public:
CompactCollateAndMeshFrameReq(
@@ -972,7 +1024,8 @@ public:
sscl::AsynchronousLoop& asyncLoop,
StimulusFrame& stimulusFrame_,
std::optional<std::reference_wrapper<StimulusFrame>> intensityStimFrame_,
std::optional<std::reference_wrapper<StimulusFrame>> ambienceStimFrame_,
std::optional<AmbienceProductionDesc> lightAmbienceProductionDesc_,
std::optional<AmbienceProductionDesc> darkAmbienceProductionDesc_,
const std::shared_ptr<sscl::ComponentThread>& caller,
sscl::Callback<compactCollateAndMeshFrameReqCbFn> cb)
: sscl::PostedAsynchronousContinuation<compactCollateAndMeshFrameReqCbFn>(
@@ -980,9 +1033,16 @@ public:
engine(engine_),
frameAssemblyResult(asyncLoop), stimulusFrame(stimulusFrame_),
intensityStimFrame(intensityStimFrame_),
ambienceStimFrame(ambienceStimFrame_)
lightAmbienceProductionDesc(std::move(lightAmbienceProductionDesc_)),
darkAmbienceProductionDesc(std::move(darkAmbienceProductionDesc_))
{}
bool anyAmbienceAttached() const
{
return lightAmbienceProductionDesc.has_value()
|| darkAmbienceProductionDesc.has_value();
}
public:
void callOriginalCallback(bool success)
{ callOriginalCb(success, std::ref(stimulusFrame)); }
@@ -1074,7 +1134,7 @@ public:
engine.collateKernelStartTime = std::chrono::high_resolution_clock::now();
bool success = engine.startCollateKernel(
context->intensityStimFrame, context->ambienceStimFrame,
context->intensityStimFrame, context->anyAmbienceAttached(),
std::bind(
&CompactCollateAndMeshFrameReq
::compactCollateAndMeshFrameReq4_collateDone_maybePosted,
@@ -1084,7 +1144,7 @@ public:
if (!success)
{
engine.collateKernelComplete(
context->intensityStimFrame, context->ambienceStimFrame);
context->intensityStimFrame, context->anyAmbienceAttached());
callOriginalCallback(false);
return;
@@ -1115,7 +1175,28 @@ public:
* completes/cleans up any in-flight operations.
*/
engine.collateKernelComplete(
context->intensityStimFrame, context->ambienceStimFrame);
context->intensityStimFrame, context->anyAmbienceAttached());
// Produce each attached ambience stimbuff's passband count from
// the per-slot averages the collate kernel staged.
uint32_t nSucceededForAmbience =
context->frameAssemblyResult.nSucceeded.load();
if (context->lightAmbienceProductionDesc.has_value())
{
engine.produceAmbienceStimulusFrame(
context->lightAmbienceProductionDesc->frame.get(),
context->lightAmbienceProductionDesc->comparator,
nSucceededForAmbience);
}
if (context->darkAmbienceProductionDesc.has_value())
{
engine.produceAmbienceStimulusFrame(
context->darkAmbienceProductionDesc->frame.get(),
context->darkAmbienceProductionDesc->comparator,
nSucceededForAmbience);
}
// Record collate kernel end time
engine.collateKernelEndTime = std::chrono::high_resolution_clock::now();
@@ -1154,13 +1235,9 @@ public:
(void)highIntensityCount;
#if 0
// Legacy debug: ambience floats live in ambienceStimFrame after collate
std::cout << __func__ << ": intensityRingBufferIndex="
<< (context->intensityStimFrame.has_value() ?
context->intensityStimFrame->get().ringBufferIndex : SIZE_MAX)
<< ", ambienceRingBufferIndex="
<< (context->ambienceStimFrame.has_value() ?
context->ambienceStimFrame->get().ringBufferIndex : SIZE_MAX)
<< ", pointsPerDgram=" << pointsPerDgram
<< ", nSucceeded=" << nSucceeded
<< ", totalPoints=" << totalPoints
@@ -1174,7 +1251,8 @@ public:
void OpenClCollatingAndMeshingEngine::compactCollateAndMeshFrameReq(
sscl::AsynchronousLoop& asyncLoop, StimulusFrame& stimulusFrame,
std::optional<std::reference_wrapper<StimulusFrame>> intensityStimFrame,
std::optional<std::reference_wrapper<StimulusFrame>> ambienceStimFrame,
std::optional<AmbienceProductionDesc> lightAmbienceProductionDesc,
std::optional<AmbienceProductionDesc> darkAmbienceProductionDesc,
sscl::Callback<compactCollateAndMeshFrameReqCbFn> callback)
{
{
@@ -1188,7 +1266,8 @@ void OpenClCollatingAndMeshingEngine::compactCollateAndMeshFrameReq(
auto caller = smoHooksPtr->ComponentThread_getSelf();
auto request = std::make_shared<CompactCollateAndMeshFrameReq>(
*this, asyncLoop, stimulusFrame, intensityStimFrame, ambienceStimFrame,
*this, asyncLoop, stimulusFrame, intensityStimFrame,
std::move(lightAmbienceProductionDesc), std::move(darkAmbienceProductionDesc),
caller,
std::move(callback));
@@ -21,12 +21,24 @@
#include <user/frameAssemblyDesc.h>
#include <user/compute.h>
#include <user/senseApiDesc.h>
#include "pcloudAmbienceQualeIfaceApi.h"
#define OCLCOLLMESH_ENGN_FINALIZE_DELAY_MS 1
namespace smo {
namespace stim_buff {
/* One "job" per attached ambience stimbuff: the StimulusFrame to write the
* uint32 passband count into, and the comparator to apply to the per-slot
* averages the collate kernel staged into averageIntensityBuffer. A job is
* only constructed when its corresponding ambience stimbuff is attached.
*/
struct AmbienceProductionDesc
{
std::reference_wrapper<StimulusFrame> frame;
ParamComparator comparator;
};
// Custom deleters for OpenCL handles
struct ClProgramDeleter
{
@@ -80,7 +92,8 @@ public:
void compactCollateAndMeshFrameReq(
sscl::AsynchronousLoop& asyncLoop, StimulusFrame& stimulusFrame,
std::optional<std::reference_wrapper<StimulusFrame>> intensityStimFrame,
std::optional<std::reference_wrapper<StimulusFrame>> ambienceStimFrame,
std::optional<AmbienceProductionDesc> lightAmbienceProductionDesc,
std::optional<AmbienceProductionDesc> darkAmbienceProductionDesc,
sscl::Callback<compactCollateAndMeshFrameReqCbFn> callback);
private:
@@ -93,16 +106,25 @@ private:
compactKernelCbFn callback);
bool startCollateKernel(
std::optional<std::reference_wrapper<StimulusFrame>> intensityStimFrame,
std::optional<std::reference_wrapper<StimulusFrame>> ambienceStimFrame,
bool anyAmbienceAttached,
collateKernelCbFn callback);
void compactKernelComplete(bool isFinalizing=false);
void collateKernelComplete(
std::optional<std::reference_wrapper<StimulusFrame>> intensityStimFrame,
std::optional<std::reference_wrapper<StimulusFrame>> ambienceStimFrame,
bool anyAmbienceAttached,
bool isFinalizing=false);
bool stop();
/* Apply `comparator` to the nSucceeded per-slot averages the collate
* kernel wrote into averageIntensityBuffer, and write the resulting
* uint32 passband count as the single stimspot of `ambienceFrame`.
*/
void produceAmbienceStimulusFrame(
StimulusFrame& ambienceFrame,
const ParamComparator& comparator,
uint32_t nSucceeded);
public:
// Get kernel execution durations in milliseconds
std::chrono::milliseconds getCompactKernelDuration() const;
@@ -121,9 +143,11 @@ private:
// OpenCL buffers (managed by ComputeManager)
std::shared_ptr<smo::compute::ClBuffer> clAssemblyBufferClBuffer;
std::shared_ptr<smo::compute::ClBuffer> clCollationBufferClBuffer;
std::shared_ptr<smo::compute::ClBuffer> clAverageIntensityBufferClBuffer;
// Cached cl_mem handles for the device we're using
cl_mem clAssemblyBuffer;
cl_mem clCollationBuffer;
cl_mem clAverageIntensityBuffer;
// State tracking
sscl::SpinLock shouldAcceptRequestsLock;
@@ -138,9 +162,12 @@ private:
size_t assemblyBufferSize;
void* collationBufferPtr;
size_t collationBufferSize;
void* averageIntensityBufferPtr;
size_t averageIntensityBufferSize;
// Mapped buffer pointers (for zero-copy synchronization)
void* mappedAssemblyBuffer;
void* mappedCollationBuffer;
void* mappedAverageIntensityBuffer;
// Frame descriptor (cached from setup)
std::shared_ptr<FrameAssemblyDesc> frameAssemblyDesc;
@@ -174,7 +201,7 @@ private:
StagingBuffer& assemblyBuff, uint32_t nSucceeded);
bool setupCollateDgramsArgs(
std::optional<std::reference_wrapper<StimulusFrame>> intensityStimFrame,
std::optional<std::reference_wrapper<StimulusFrame>> ambienceStimFrame);
bool anyAmbienceAttached);
// Generic buffer mapping/unmapping for zero-copy synchronization
bool mapBuffer(
@@ -186,6 +213,8 @@ private:
bool unmapAssemblyBuffer();
bool mapCollationBuffer(cl_map_flags mapFlags = CL_MAP_READ);
bool unmapCollationBuffer();
bool mapAverageIntensityBuffer(cl_map_flags mapFlags = CL_MAP_READ);
bool unmapAverageIntensityBuffer();
// Forward declaration for continuation class
class CompactCollateAndMeshFrameReq;
@@ -1,12 +1,15 @@
#ifndef _LIVOX_GEN1_PCLOUD_AMBIENCE_QUALE_IFACE_API_H
#define _LIVOX_GEN1_PCLOUD_AMBIENCE_QUALE_IFACE_API_H
#include <algorithm>
#include <cstdint>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
#include <string_view>
#include <user/deviceAttachmentSpec.h>
#include <user/intrin.h>
#include <user/intrinThresholdParams.h>
namespace smo {
namespace stim_buff {
@@ -36,45 +39,110 @@ struct ParamComparator
}
};
struct PcloudAmbiencePassbandComparators
inline bool paramsContain(
const std::vector<std::pair<std::string, std::string>>& params,
const std::string& name)
{
std::optional<ParamComparator> lt;
std::optional<ParamComparator> gt;
};
return std::any_of(
params.begin(), params.end(),
[&name](const auto& p) { return p.first == name; });
}
/* Both `passband-count-lt-val` and `passband-count-gt-val` are permitted
* simultaneously on a pcloudAmbience qualeIfaceApi: the lt comparator
* typically feeds a postrin(...) segment (triggering on unusually low
* counts), and the gt comparator typically feeds a negtrin(...) segment
* (triggering on unusually high counts).
/* pcloudLightAmbience requires exactly one `passband-count-gt-val` on its
* qualeIfaceApi params; `passband-count-lt-val` is a hard error. Feeds a
* negtrin(...) segment (scene is "unbearably much, get away").
*/
inline PcloudAmbiencePassbandComparators parsePcloudAmbiencePassbandComparators(
inline ParamComparator parsePcloudLightAmbienceGtComparator(
const std::shared_ptr<device::DeviceAttachmentSpec>& deviceAttachmentSpec)
{
const auto& params = deviceAttachmentSpec->qualeIfaceApiParams;
if (paramsContain(params, "passband-count-lt-val"))
{
throw std::runtime_error(
"pcloudLightAmbience qualeIfaceApi does not accept "
"'passband-count-lt-val'; use pcloudDarkAmbience for lt-val "
"pipelines.");
}
constexpr int kParamNotSpecified = -1;
const int gtVal = device::DeviceAttachmentSpec::parseOptionalParamAsInt(
params, "passband-count-gt-val", kParamNotSpecified);
if (gtVal == kParamNotSpecified)
{
throw std::runtime_error(
"pcloudLightAmbience qualeIfaceApi requires "
"'passband-count-gt-val' on its params.");
}
return ParamComparator{
.op = OP_CMP_GT,
.value = static_cast<uint32_t>(gtVal),
};
}
/* pcloudDarkAmbience requires exactly one `passband-count-lt-val` on its
* qualeIfaceApi params; `passband-count-gt-val` is a hard error. Feeds a
* postrin(...) segment (scene is "too good, stay here").
*/
inline ParamComparator parsePcloudDarkAmbienceLtComparator(
const std::shared_ptr<device::DeviceAttachmentSpec>& deviceAttachmentSpec)
{
const auto& params = deviceAttachmentSpec->qualeIfaceApiParams;
if (paramsContain(params, "passband-count-gt-val"))
{
throw std::runtime_error(
"pcloudDarkAmbience qualeIfaceApi does not accept "
"'passband-count-gt-val'; use pcloudLightAmbience for gt-val "
"pipelines.");
}
constexpr int kParamNotSpecified = -1;
const int ltVal = device::DeviceAttachmentSpec::parseOptionalParamAsInt(
params, "passband-count-lt-val", kParamNotSpecified);
PcloudAmbiencePassbandComparators out;
if (gtVal != kParamNotSpecified)
if (ltVal == kParamNotSpecified)
{
out.gt = ParamComparator{
.op = OP_CMP_GT,
.value = static_cast<uint32_t>(gtVal),
};
}
if (ltVal != kParamNotSpecified)
{
out.lt = ParamComparator{
.op = OP_CMP_LT,
.value = static_cast<uint32_t>(ltVal),
};
throw std::runtime_error(
"pcloudDarkAmbience qualeIfaceApi requires "
"'passband-count-lt-val' on its params.");
}
return out;
return ParamComparator{
.op = OP_CMP_LT,
.value = static_cast<uint32_t>(ltVal),
};
}
/* Shared parser used by both pcloudLightAmbience and pcloudDarkAmbience
* stimbuffs to decode a postrin(...) / negtrin(...) segment's threshold
* params into an IntrinConfig. Kept with the qualeIfaceApi helpers because
* it's ambience-specific (nDgramsPerFrame is the percentage base).
*/
inline intrin::IntrinConfig parseAmbienceIntrinConfigFromParams(
std::string_view intrinKind,
const std::vector<std::pair<std::string, std::string>>& params,
size_t nDgramsPerFrame)
{
intrin::validateIntrinSegmentParams(intrinKind, params);
const auto threshold = intrin::parseOptionalThresholdParam(
params,
intrin::kIntrinInterestPcNames,
intrin::kIntrinInterestThrNames,
/*defaultValue=*/0,
/*defaultUnit=*/intrin::ThresholdUnit::Absolute);
return intrin::IntrinConfig{
.percentage =
threshold.unit == intrin::ThresholdUnit::Percentage
? static_cast<uint32_t>(threshold.value)
: 0U,
.threshold = intrin::resolveThresholdValue(
threshold, nDgramsPerFrame),
};
}
} // namespace stim_buff
@@ -1,150 +0,0 @@
#ifndef _LIVOX_GEN1_PCLOUD_AMBIENCE_STIMULUS_BUFFER_H
#define _LIVOX_GEN1_PCLOUD_AMBIENCE_STIMULUS_BUFFER_H
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <user/deviceAttachmentSpec.h>
#include <user/intrin.h>
#include <user/intrinThresholdParams.h>
#include <user/stagingBuffer.h>
#include <user/stimulusBuffer.h>
#include "pcloudAmbienceQualeIfaceApi.h"
namespace smo {
namespace stim_buff {
class StimulusProducer;
inline intrin::IntrinConfig parseAmbienceIntrinConfigFromParams(
std::string_view intrinKind,
const std::vector<std::pair<std::string, std::string>>& params,
size_t nDgramsPerFrame)
{
intrin::validateIntrinSegmentParams(intrinKind, params);
const auto threshold = intrin::parseOptionalThresholdParam(
params,
intrin::kIntrinInterestPcNames,
intrin::kIntrinInterestThrNames,
/*defaultValue=*/0,
/*defaultUnit=*/intrin::ThresholdUnit::Absolute);
return intrin::IntrinConfig{
.percentage =
threshold.unit == intrin::ThresholdUnit::Percentage
? static_cast<uint32_t>(threshold.value)
: 0U,
.threshold = intrin::resolveThresholdValue(
threshold, nDgramsPerFrame),
};
}
/**
* Sensory PcloudAmbience buffer: per-dgram ambience floats. A DAP spec may
* optionally attach a postrin(...) and/or a negtrin(...) specifier to this
* qualeIfaceApi; when present, interest thresholds from those specifiers and
* passband-count comparators from this spec's own qualeIfaceApi params are
* combined to decide when an intrin event should fire.
*
* Convention: the postrin pipeline pairs with passband-count-lt-val (a sparse
* ambient scene being "too good, stay here"); the negtrin pipeline pairs with
* passband-count-gt-val (a dense ambient scene being "unbearably much, get
* away"). Both comparators may be specified simultaneously on this qualeIface.
*/
class PcloudAmbienceStimulusBuffer
: public StimulusBuffer
{
public:
explicit PcloudAmbienceStimulusBuffer(
StimulusProducer& parent,
const std::shared_ptr<device::DeviceAttachmentSpec>& deviceAttachmentSpec,
int histbuffMs,
const StagingBuffer::IOEngineConstraints& inputEngineConstraints,
const StagingBuffer::IOEngineConstraints& outputEngineConstraints,
const SmoCallbacks& callbacks,
cl_mem_flags flags,
size_t nDgramsPerFrame_)
: StimulusBuffer(
parent, deviceAttachmentSpec, histbuffMs,
inputEngineConstraints, outputEngineConstraints,
callbacks, flags),
nDgramsPerFrame(nDgramsPerFrame_)
{
intrin::validateNoIntrinParamsOnQualeIface(
deviceAttachmentSpec->qualeIfaceApi,
deviceAttachmentSpec->qualeIfaceApiParams);
const auto passbandComparators =
parsePcloudAmbiencePassbandComparators(deviceAttachmentSpec);
passbandCountLtComparator = passbandComparators.lt;
passbandCountGtComparator = passbandComparators.gt;
if (!deviceAttachmentSpec->postrin.empty())
{
postrinInterestConfig = parseAmbienceIntrinConfigFromParams(
"postrin",
deviceAttachmentSpec->postrinParams,
nDgramsPerFrame_);
if (!passbandCountLtComparator.has_value())
{
throw std::runtime_error(
"pcloudAmbience DAP spec declares a postrin(...) but no "
"'passband-count-lt-val' on the pcloudAmbience qualeIface "
"params to feed it.");
}
}
if (!deviceAttachmentSpec->negtrin.empty())
{
negtrinInterestConfig = parseAmbienceIntrinConfigFromParams(
"negtrin",
deviceAttachmentSpec->negtrinParams,
nDgramsPerFrame_);
if (!passbandCountGtComparator.has_value())
{
throw std::runtime_error(
"pcloudAmbience DAP spec declares a negtrin(...) but no "
"'passband-count-gt-val' on the pcloudAmbience qualeIface "
"params to feed it.");
}
}
}
~PcloudAmbienceStimulusBuffer() = default;
PcloudAmbienceStimulusBuffer(const PcloudAmbienceStimulusBuffer&) = delete;
PcloudAmbienceStimulusBuffer& operator=(
const PcloudAmbienceStimulusBuffer&) = delete;
PcloudAmbienceStimulusBuffer(PcloudAmbienceStimulusBuffer&&) = delete;
PcloudAmbienceStimulusBuffer& operator=(
PcloudAmbienceStimulusBuffer&&) = delete;
bool shouldTriggerPostrinEvent(uint32_t ambiencePassbandCount) const
{
if (!postrinInterestConfig.has_value()) { return false; }
return ambiencePassbandCount >= postrinInterestConfig->threshold;
}
bool shouldTriggerNegtrinEvent(uint32_t ambiencePassbandCount) const
{
if (!negtrinInterestConfig.has_value()) { return false; }
return ambiencePassbandCount >= negtrinInterestConfig->threshold;
}
public:
size_t nDgramsPerFrame;
std::optional<intrin::IntrinConfig> postrinInterestConfig;
std::optional<intrin::IntrinConfig> negtrinInterestConfig;
std::optional<ParamComparator> passbandCountLtComparator;
std::optional<ParamComparator> passbandCountGtComparator;
};
} // namespace stim_buff
} // namespace smo
#endif // _LIVOX_GEN1_PCLOUD_AMBIENCE_STIMULUS_BUFFER_H
@@ -0,0 +1,97 @@
#ifndef _LIVOX_GEN1_PCLOUD_DARK_AMBIENCE_STIMULUS_BUFFER_H
#define _LIVOX_GEN1_PCLOUD_DARK_AMBIENCE_STIMULUS_BUFFER_H
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <user/deviceAttachmentSpec.h>
#include <user/intrin.h>
#include <user/intrinThresholdParams.h>
#include <user/stagingBuffer.h>
#include <user/stimulusBuffer.h>
#include "pcloudAmbienceQualeIfaceApi.h"
namespace smo {
namespace stim_buff {
class StimulusProducer;
/**
* Sensory pcloudDarkAmbience buffer: one uint32 stimspot per stimframe —
* the count of per-frame slots whose average intensity falls below the
* qualeIface's passband-count-lt-val. A DAP spec may optionally attach a
* postrin(...) specifier (scene is "too good, stay here"); negtrin is not
* valid on this qualeIfaceApi.
*/
class PcloudDarkAmbienceStimulusBuffer
: public StimulusBuffer
{
public:
explicit PcloudDarkAmbienceStimulusBuffer(
StimulusProducer& parent,
const std::shared_ptr<device::DeviceAttachmentSpec>& deviceAttachmentSpec,
int histbuffMs,
const StagingBuffer::IOEngineConstraints& inputEngineConstraints,
const StagingBuffer::IOEngineConstraints& outputEngineConstraints,
const SmoCallbacks& callbacks,
cl_mem_flags flags,
size_t nDgramsPerFrame_)
: StimulusBuffer(
parent, deviceAttachmentSpec, histbuffMs,
inputEngineConstraints, outputEngineConstraints,
callbacks, flags),
nDgramsPerFrame(nDgramsPerFrame_)
{
intrin::validateNoIntrinParamsOnQualeIface(
deviceAttachmentSpec->qualeIfaceApi,
deviceAttachmentSpec->qualeIfaceApiParams);
passbandCountLtComparator =
parsePcloudDarkAmbienceLtComparator(deviceAttachmentSpec);
if (!deviceAttachmentSpec->negtrin.empty())
{
throw std::runtime_error(
"pcloudDarkAmbience DAP spec for device '"
+ deviceAttachmentSpec->deviceIdentifier
+ "' declares a negtrin(...); negtrin belongs on a "
"pcloudLightAmbience line, not pcloudDarkAmbience.");
}
if (!deviceAttachmentSpec->postrin.empty())
{
postrinInterestConfig = parseAmbienceIntrinConfigFromParams(
"postrin",
deviceAttachmentSpec->postrinParams,
nDgramsPerFrame_);
}
}
~PcloudDarkAmbienceStimulusBuffer() = default;
PcloudDarkAmbienceStimulusBuffer(
const PcloudDarkAmbienceStimulusBuffer&) = delete;
PcloudDarkAmbienceStimulusBuffer& operator=(
const PcloudDarkAmbienceStimulusBuffer&) = delete;
PcloudDarkAmbienceStimulusBuffer(
PcloudDarkAmbienceStimulusBuffer&&) = delete;
PcloudDarkAmbienceStimulusBuffer& operator=(
PcloudDarkAmbienceStimulusBuffer&&) = delete;
bool shouldTriggerPostrinEvent(uint32_t ambiencePassbandCount) const
{
if (!postrinInterestConfig.has_value()) { return false; }
return ambiencePassbandCount >= postrinInterestConfig->threshold;
}
public:
size_t nDgramsPerFrame;
ParamComparator passbandCountLtComparator;
std::optional<intrin::IntrinConfig> postrinInterestConfig;
};
} // namespace stim_buff
} // namespace smo
#endif // _LIVOX_GEN1_PCLOUD_DARK_AMBIENCE_STIMULUS_BUFFER_H
@@ -0,0 +1,97 @@
#ifndef _LIVOX_GEN1_PCLOUD_LIGHT_AMBIENCE_STIMULUS_BUFFER_H
#define _LIVOX_GEN1_PCLOUD_LIGHT_AMBIENCE_STIMULUS_BUFFER_H
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <user/deviceAttachmentSpec.h>
#include <user/intrin.h>
#include <user/intrinThresholdParams.h>
#include <user/stagingBuffer.h>
#include <user/stimulusBuffer.h>
#include "pcloudAmbienceQualeIfaceApi.h"
namespace smo {
namespace stim_buff {
class StimulusProducer;
/**
* Sensory pcloudLightAmbience buffer: one uint32 stimspot per stimframe —
* the count of per-frame slots whose average intensity exceeds the
* qualeIface's passband-count-gt-val. A DAP spec may optionally attach a
* negtrin(...) specifier (scene is "unbearably much, get away"); postrin
* is not valid on this qualeIfaceApi.
*/
class PcloudLightAmbienceStimulusBuffer
: public StimulusBuffer
{
public:
explicit PcloudLightAmbienceStimulusBuffer(
StimulusProducer& parent,
const std::shared_ptr<device::DeviceAttachmentSpec>& deviceAttachmentSpec,
int histbuffMs,
const StagingBuffer::IOEngineConstraints& inputEngineConstraints,
const StagingBuffer::IOEngineConstraints& outputEngineConstraints,
const SmoCallbacks& callbacks,
cl_mem_flags flags,
size_t nDgramsPerFrame_)
: StimulusBuffer(
parent, deviceAttachmentSpec, histbuffMs,
inputEngineConstraints, outputEngineConstraints,
callbacks, flags),
nDgramsPerFrame(nDgramsPerFrame_)
{
intrin::validateNoIntrinParamsOnQualeIface(
deviceAttachmentSpec->qualeIfaceApi,
deviceAttachmentSpec->qualeIfaceApiParams);
passbandCountGtComparator =
parsePcloudLightAmbienceGtComparator(deviceAttachmentSpec);
if (!deviceAttachmentSpec->postrin.empty())
{
throw std::runtime_error(
"pcloudLightAmbience DAP spec for device '"
+ deviceAttachmentSpec->deviceIdentifier
+ "' declares a postrin(...); postrin belongs on a "
"pcloudDarkAmbience line, not pcloudLightAmbience.");
}
if (!deviceAttachmentSpec->negtrin.empty())
{
negtrinInterestConfig = parseAmbienceIntrinConfigFromParams(
"negtrin",
deviceAttachmentSpec->negtrinParams,
nDgramsPerFrame_);
}
}
~PcloudLightAmbienceStimulusBuffer() = default;
PcloudLightAmbienceStimulusBuffer(
const PcloudLightAmbienceStimulusBuffer&) = delete;
PcloudLightAmbienceStimulusBuffer& operator=(
const PcloudLightAmbienceStimulusBuffer&) = delete;
PcloudLightAmbienceStimulusBuffer(
PcloudLightAmbienceStimulusBuffer&&) = delete;
PcloudLightAmbienceStimulusBuffer& operator=(
PcloudLightAmbienceStimulusBuffer&&) = delete;
bool shouldTriggerNegtrinEvent(uint32_t ambiencePassbandCount) const
{
if (!negtrinInterestConfig.has_value()) { return false; }
return ambiencePassbandCount >= negtrinInterestConfig->threshold;
}
public:
size_t nDgramsPerFrame;
ParamComparator passbandCountGtComparator;
std::optional<intrin::IntrinConfig> negtrinInterestConfig;
};
} // namespace stim_buff
} // namespace smo
#endif // _LIVOX_GEN1_PCLOUD_LIGHT_AMBIENCE_STIMULUS_BUFFER_H
+120 -44
View File
@@ -54,20 +54,29 @@ static StagingBuffer::IOEngineConstraints openClIntensityInputConstraints(
// framePadToNBytes (pointer size)
static_cast<size_t>(sysconf(_SC_PAGE_SIZE)));
/* IOEngineConstraints for PcloudAmbienceStimulusBuffer's StagingBuffer, which
* backs SpMcRingBuffer (one StimulusFrame per ring slot). Not the OpenCL
* collating engine's assembly/collation buffers — those use assemblyBuffer /
* collationBuffer above. slotPadToNBytes here is the byte size of each ringbuff
* slot: nDgramsPerStagingBufferFrame floats (set in ctor).
/* 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(float),
sizeof(float),
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,
@@ -90,6 +99,11 @@ collationBuffer(
StagingBuffer::IOEngineConstraints::openClInputConstraints,
nDgramsPerStagingBufferFrame),
collationBufferMlockPinner(collationBuffer.makeMlockPinner()),
averageIntensityBuffer(
openClAverageIntensityConstraints,
openClAverageIntensityConstraints,
nDgramsPerStagingBufferFrame),
averageIntensityBufferMlockPinner(averageIntensityBuffer.makeMlockPinner()),
pcloudFrameDumper(deviceAttachmentSpec),
tempStimulusFrameMem(0),
tempStimulusFrame(
@@ -99,10 +113,6 @@ tempStimulusFrame(
sizeof(tempStimulusFrameMem)},
*smoHooksPtr, 0, SIZE_MAX)
{
// See comment in openClAmbienceInputConstraints above.
openClAmbienceInputConstraints.slotPadToNBytes =
nDgramsPerStagingBufferFrame * sizeof(float);
if (smoHooksPtr->OptionParser_getOptions().verbose)
{
std::cout << __func__ << ": assembly buffer : "
@@ -133,7 +143,8 @@ bool PcloudStimulusProducer::supportsQualeIfaceApi(
const std::string& qualeIfaceApi)
{
return qualeIfaceApi == "mesh" || qualeIfaceApi == "pcloudIntensity" ||
qualeIfaceApi == "pcloudAmbience";
qualeIfaceApi == "pcloudLightAmbience" ||
qualeIfaceApi == "pcloudDarkAmbience";
}
bool PcloudStimulusProducer::exportsQualeIfaceApi(
@@ -224,9 +235,14 @@ PcloudStimulusProducer::getAttachedStimulusBuffer(
if (std::dynamic_pointer_cast<PcloudIntensityStimulusBuffer>(buffer))
{ return buffer; }
}
else if (qualeIfaceApi == "pcloudAmbience")
else if (qualeIfaceApi == "pcloudLightAmbience")
{
if (std::dynamic_pointer_cast<PcloudAmbienceStimulusBuffer>(buffer))
if (std::dynamic_pointer_cast<PcloudLightAmbienceStimulusBuffer>(buffer))
{ return buffer; }
}
else if (qualeIfaceApi == "pcloudDarkAmbience")
{
if (std::dynamic_pointer_cast<PcloudDarkAmbienceStimulusBuffer>(buffer))
{ return buffer; }
}
@@ -254,11 +270,19 @@ void PcloudStimulusProducer::destroyAttachedStimulusBuffer(
intensityBuff.reset();
intensityStimulusBuffer.store(nullptr, std::memory_order_release);
}
auto ambienceBuff = ambienceStimulusBuffer.load(std::memory_order_acquire);
if (ambienceBuff == buffer)
auto lightAmbienceBuff = lightAmbienceStimulusBuffer.load(
std::memory_order_acquire);
if (lightAmbienceBuff == buffer)
{
ambienceBuff.reset();
ambienceStimulusBuffer.store(nullptr, std::memory_order_release);
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
@@ -330,26 +354,45 @@ PcloudStimulusProducer::getOrCreateAttachedStimulusBuffer(
this->start();
return intensityBuffer;
}
else if (qualeIfaceApi == "pcloudAmbience")
else if (qualeIfaceApi == "pcloudLightAmbience")
{
auto ambienceStimBuff = std::make_shared<PcloudAmbienceStimulusBuffer>(
*this, deviceAttachmentSpec, histbuffMs,
openClAmbienceInputConstraints, openClAmbienceInputConstraints,
*smoHooksPtr, CL_MEM_READ_WRITE,
this->nDgramsPerStagingBufferFrame);
auto lightAmbienceStimBuff =
std::make_shared<PcloudLightAmbienceStimulusBuffer>(
*this, deviceAttachmentSpec, histbuffMs,
openClAmbienceInputConstraints, openClAmbienceInputConstraints,
*smoHooksPtr, CL_MEM_READ_WRITE,
this->nDgramsPerStagingBufferFrame);
this->stop();
addAttachedStimulusBufferIfNotExists(ambienceStimBuff);
ambienceStimulusBuffer.store(ambienceStimBuff, std::memory_order_release);
addAttachedStimulusBufferIfNotExists(lightAmbienceStimBuff);
lightAmbienceStimulusBuffer.store(
lightAmbienceStimBuff, std::memory_order_release);
this->start();
return ambienceStimBuff;
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, pcloudAmbience");
"Supported values: mesh, pcloudIntensity, "
"pcloudLightAmbience, pcloudDarkAmbience");
}
}
@@ -366,7 +409,8 @@ private:
sscl::AsynchronousLoop frameAssemblyResult;
StimulusFrame& stimulusFrame;
std::optional<std::reference_wrapper<StimulusFrame>> intensityStimFrame;
std::optional<std::reference_wrapper<StimulusFrame>> ambienceStimFrame;
std::optional<std::reference_wrapper<StimulusFrame>> lightAmbienceStimFrame;
std::optional<std::reference_wrapper<StimulusFrame>> darkAmbienceStimFrame;
public:
ProduceFrameReq(
@@ -446,28 +490,57 @@ public:
context->intensityStimFrame = std::nullopt;
}
// Check if ambience buffer is attached and acquire frame if so
if (auto ambienceBuff = pcloudProducer.ambienceStimulusBuffer.load(
std::memory_order_acquire))
// Check if light ambience buffer is attached and acquire frame if so
std::optional<AmbienceProductionDesc> lightAmbienceProductionDescDesc;
if (auto lightAmbienceBuff =
pcloudProducer.lightAmbienceStimulusBuffer.load(
std::memory_order_acquire))
{
size_t ambienceRingbuffIndex = ambienceBuff
size_t lightAmbienceRingbuffIndex = lightAmbienceBuff
->ringBuffer.getIndexToProduceInto();
StimulusFrame& ambienceStimFrame = ambienceBuff
->ringBuffer.getDataAtSlot(
ambienceRingbuffIndex);
StimulusFrame& lightAmbienceStimFrame = lightAmbienceBuff
->ringBuffer.getDataAtSlot(lightAmbienceRingbuffIndex);
ambienceStimFrame.lock.writeAcquire();
context->ambienceStimFrame = std::make_optional(
std::ref(ambienceStimFrame));
lightAmbienceStimFrame.lock.writeAcquire();
context->lightAmbienceStimFrame = std::make_optional(
std::ref(lightAmbienceStimFrame));
lightAmbienceProductionDescDesc = AmbienceProductionDesc{
std::ref(lightAmbienceStimFrame),
lightAmbienceBuff->passbandCountGtComparator};
}
else {
context->ambienceStimFrame = std::nullopt;
context->lightAmbienceStimFrame = std::nullopt;
}
// Check if dark ambience buffer is attached and acquire frame if so
std::optional<AmbienceProductionDesc> darkAmbienceProductionDescDesc;
if (auto darkAmbienceBuff =
pcloudProducer.darkAmbienceStimulusBuffer.load(
std::memory_order_acquire))
{
size_t darkAmbienceRingbuffIndex = darkAmbienceBuff
->ringBuffer.getIndexToProduceInto();
StimulusFrame& darkAmbienceStimFrame = darkAmbienceBuff
->ringBuffer.getDataAtSlot(darkAmbienceRingbuffIndex);
darkAmbienceStimFrame.lock.writeAcquire();
context->darkAmbienceStimFrame = std::make_optional(
std::ref(darkAmbienceStimFrame));
darkAmbienceProductionDescDesc = AmbienceProductionDesc{
std::ref(darkAmbienceStimFrame),
darkAmbienceBuff->passbandCountLtComparator};
}
else {
context->darkAmbienceStimFrame = std::nullopt;
}
pcloudProducer.openClCollatingAndMeshingEngine.compactCollateAndMeshFrameReq(
loop, stimulusFrame,
context->intensityStimFrame, context->ambienceStimFrame,
context->intensityStimFrame,
std::move(lightAmbienceProductionDescDesc),
std::move(darkAmbienceProductionDescDesc),
{context, std::bind(
&ProduceFrameReq::produceFrameReq3_compactCollateDone,
context.get(), context,
@@ -482,9 +555,12 @@ public:
if (context->intensityStimFrame.has_value()) {
context->intensityStimFrame->get().lock.writeRelease();
}
// Release ambience frame if it was used
if (context->ambienceStimFrame.has_value()) {
context->ambienceStimFrame->get().lock.writeRelease();
// Release ambience frames if they were used
if (context->lightAmbienceStimFrame.has_value()) {
context->lightAmbienceStimFrame->get().lock.writeRelease();
}
if (context->darkAmbienceStimFrame.has_value()) {
context->darkAmbienceStimFrame->get().lock.writeRelease();
}
sscl::SpinLock::Guard lock(pcloudProducer.shouldContinueLock);
@@ -14,7 +14,8 @@
#include "openClCollatingAndMeshingEngine.h"
#include "meshStimulusBuffer.h"
#include "pcloudIntensityStimulusBuffer.h"
#include "pcloudAmbienceStimulusBuffer.h"
#include "pcloudLightAmbienceStimulusBuffer.h"
#include "pcloudDarkAmbienceStimulusBuffer.h"
namespace smo {
namespace stim_buff {
@@ -96,14 +97,19 @@ public:
IoUringAssemblyEngine ioUringAssemblyEngine;
StagingBuffer collationBuffer;
std::unique_ptr<StagingBuffer::MlockPinner> collationBufferMlockPinner;
StagingBuffer averageIntensityBuffer;
std::unique_ptr<StagingBuffer::MlockPinner>
averageIntensityBufferMlockPinner;
LivoxPcloudFrameDumper pcloudFrameDumper;
size_t tempStimulusFrameMem;
StimulusFrame tempStimulusFrame;
std::atomic<std::shared_ptr<MeshStimulusBuffer>> meshStimulusBuffer;
std::atomic<std::shared_ptr<PcloudIntensityStimulusBuffer>>
intensityStimulusBuffer;
std::atomic<std::shared_ptr<PcloudAmbienceStimulusBuffer>>
ambienceStimulusBuffer;
std::atomic<std::shared_ptr<PcloudLightAmbienceStimulusBuffer>>
lightAmbienceStimulusBuffer;
std::atomic<std::shared_ptr<PcloudDarkAmbienceStimulusBuffer>>
darkAmbienceStimulusBuffer;
private:
class ProduceFrameReq;