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:
+17
-12
@@ -4,16 +4,21 @@
|
||||
|
||||
+edev|avia0|mesh()|livoxGen1()|livoxProto1(SMO_IP)|3JEDK380010Z39||
|
||||
+edev|avia0|pcloudIntensity()|livoxGen1()|livoxProto1(SMO_IP)|3JEDK380010Z39||
|
||||
/* pcloudAmbience with:
|
||||
* - postrin: be positively disposed to dim ambience (low passband counts),
|
||||
* but don't be so positively drawn that your eyelids droop and your pupils
|
||||
* dilate, in human terms (i.e: no distraction). And no stupefaction either.
|
||||
* - negtrin: be negatively disposed to high ambience (high passband counts),
|
||||
* to the point of feeling un-ignorable pain when it's sufficiently high.
|
||||
|
||||
/* pcloudLightAmbience with negtrin: be negatively disposed to high ambience
|
||||
* (high passband counts above passband-count-gt-val), to the point of feeling
|
||||
* un-ignorable pain when it's sufficiently high.
|
||||
*/
|
||||
+edev|avia0|
|
||||
postrin(interest-pc=85)|
|
||||
negtrin(interest-pc=85|distraction-pc=90|intolerable-pc=95)|
|
||||
pcloudAmbience(passband-count-lt-val=8|passband-count-gt-val=120)|
|
||||
livoxGen1()|livoxProto1(SMO_IP)|
|
||||
3JEDK380010Z39||
|
||||
+edev|avia0
|
||||
|negtrin(interest-pc=85|distraction-pc=90|intolerable-pc=95)
|
||||
|pcloudLightAmbience(passband-count-gt-val=120)
|
||||
|livoxGen1()|livoxProto1(SMO_IP)|3JEDK380010Z39||
|
||||
|
||||
/* pcloudDarkAmbience with postrin: be positively disposed to dim ambience
|
||||
* (passband counts below passband-count-lt-val), but not so drawn that eyelids
|
||||
* droop — no distraction, no stupefaction.
|
||||
*/
|
||||
+edev|avia0
|
||||
|postrin(interest-pc=85)
|
||||
|pcloudDarkAmbience(passband-count-lt-val=8)
|
||||
|livoxGen1()|livoxProto1(SMO_IP)|3JEDK380010Z39||
|
||||
|
||||
@@ -18,8 +18,9 @@ negtrin is free.
|
||||
Intrinsic threshold params (and the deprecated `from-stimbuff` marker)
|
||||
must not appear on the qualeIfaceApi params themselves — policy
|
||||
validation rejects them there. The nontrin qualeIfaceApi
|
||||
(e.g. `pcloudAmbience`) still owns its own sensory params (such as
|
||||
passband comparators); only the threshold classifications (`interest-*`,
|
||||
(e.g. `pcloudLightAmbience` / `pcloudDarkAmbience`) still owns its own
|
||||
sensory params (such as passband comparators); only the threshold
|
||||
classifications (`interest-*`,
|
||||
`distraction-*`, `stupefaction-*` / `stupefying-*`, `intolerable-*`) live
|
||||
in the postrin/negtrin segments.
|
||||
|
||||
@@ -35,7 +36,7 @@ Example (negtrin segment attached to ambience, with passband comparator
|
||||
on the nontrin qualeIfaceApi):
|
||||
|
||||
````
|
||||
+edev|avia0|negtrin(interest-pc=85)|pcloudAmbience(passband-count-gt-val=120)|livoxGen1()|livoxProto1(SMO_IP)|3JEDK380010Z39||
|
||||
+edev|avia0|negtrin(interest-pc=85)|pcloudLightAmbience(passband-count-gt-val=120)|livoxGen1()|livoxProto1(SMO_IP)|3JEDK380010Z39||
|
||||
````
|
||||
|
||||
## Unit Suffix Rules
|
||||
@@ -83,7 +84,7 @@ with the "importance" argument set to "INTERESTING".
|
||||
|
||||
**Example (negtrin segment attached to ambience):**
|
||||
````
|
||||
+edev|avia0|negtrin(interest-pc=85)|pcloudAmbience(passband-count-gt-val=120)|livoxGen1()|livoxProto1(SMO_IP)|3JEDK380010Z39||
|
||||
+edev|avia0|negtrin(interest-pc=85)|pcloudLightAmbience(passband-count-gt-val=120)|livoxGen1()|livoxProto1(SMO_IP)|3JEDK380010Z39||
|
||||
````
|
||||
|
||||
## Distraction Threshold Parameters
|
||||
|
||||
@@ -19,7 +19,8 @@ descriptors tell it exactly which body spots are raising it.
|
||||
This direct information also assists SMO in narrowing down the scope of its
|
||||
DB searches for methods to handle (increase or decrease) the stimval. For
|
||||
example, for a negtrin raised from a `negtrin(...)` segment attached to a
|
||||
nontrin DAP line (e.g. `pcloudAmbience`), we don't search DB by trying to
|
||||
nontrin DAP line (e.g. `pcloudLightAmbience` / `pcloudDarkAmbience`),
|
||||
we don't search DB by trying to
|
||||
match all possible body spots with their stimvals. Rather, we search for
|
||||
all the body spots that are described in the stencil. This optimizes DB
|
||||
searches and also makes negtrin relieving/postrin satisfying searches
|
||||
@@ -90,15 +91,15 @@ raising new intrins.
|
||||
|livoxProto1()|SERIAL
|
||||
```
|
||||
|
||||
The Livox Gen1 **`pcloudAmbience`** sensory line does **not** use
|
||||
`n-stencils`; ambience floats are delivered in the stimulus frame buffer.
|
||||
If Livox adds `n-stencils` for its intrinsic pipelines, it would appear
|
||||
inside the `postrin(...)` / `negtrin(...)` segments attached to
|
||||
`pcloudAmbience`, not on `pcloudAmbience` itself.
|
||||
The Livox Gen1 **`pcloudLightAmbience`** / **`pcloudDarkAmbience`** sensory
|
||||
lines do **not** use `n-stencils`; each emits one `uint32` passband count
|
||||
per stimframe. If Livox adds `n-stencils` for its intrinsic pipelines, it
|
||||
would appear inside the `postrin(...)` / `negtrin(...)` segments attached to
|
||||
the ambience line, not on the ambience qualeIfaceApi itself.
|
||||
|
||||
**Invalid (sensory qualeIfaceApi must not carry intrin-oriented params):**
|
||||
```
|
||||
+idev|my-device|pcloudAmbience(n-stencils=4)|livoxGen1-pcloud()|livoxProto1()|3JEDK380010Z39
|
||||
+idev|my-device|pcloudLightAmbience(n-stencils=4)|livoxGen1-pcloud()|livoxProto1()|3JEDK380010Z39
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
@@ -31,24 +31,44 @@ Each stim-buff-api is designed to work with specific stim-iface libraries that u
|
||||
**Stim-Buff-API**: `livoxGen1-pcloudIntensity`
|
||||
**Quale-Iface-API**: `pcloudIntensity` - Processes intensity/reflectivity data from point clouds
|
||||
|
||||
### 2. Point Cloud Ambience Data Device (Interoceptor)
|
||||
### 2. Point Cloud Ambience Data Devices (Interoceptors)
|
||||
|
||||
**Purpose**: Provides ambience data from the LiDAR point cloud as a **vector of per-dagram average intensities** (one `float` per UDP datagram slot in the staging frame, length `n-dgrams-per-frame`). The OpenCL collate kernel writes these values directly into the acquired ambience `StimulusFrame` buffer.
|
||||
Ambience is split into two qualeIfaceApis, each producing a single `uint32`
|
||||
per stimframe — the count of per-frame slots whose average intensity passes
|
||||
the qualeIface's comparator. The OpenCL collate kernel stages per-slot
|
||||
averages into an internal buffer; each attached ambience stimbuff reads that
|
||||
buffer and applies its own comparator.
|
||||
|
||||
#### 2a. `pcloudLightAmbience` (pairs with `negtrin`)
|
||||
|
||||
**Syntax**:
|
||||
```
|
||||
+idev | avia0 | pcloudAmbience | livoxGen1-pcloud() | livoxProto1(command-timeout-ms=1000,retry-delay-ms=3000,smo-ip=192.168.1.50,smo-subnet-nbits=24) | 3JEDK380010Z39
|
||||
+idev | avia0 | negtrin(...) | pcloudLightAmbience(passband-count-gt-val=120) | livoxGen1-pcloud() | livoxProto1(...) | 3JEDK380010Z39
|
||||
```
|
||||
|
||||
**Stim-Buff-API**: `livoxGen1-pcloud`
|
||||
**Quale-Iface-API**: `pcloudAmbience` - Delivers per-dagram average intensity floats (sensory stream only).
|
||||
**Quale-Iface-API**: `pcloudLightAmbience` — Requires exactly one
|
||||
`passband-count-gt-val` on its params. Rejects `passband-count-lt-val`. The
|
||||
stimframe stimspot is the count of per-frame slots whose average intensity
|
||||
exceeds `passband-count-gt-val`. Scene is "unbearably much, get away" — pairs
|
||||
with `negtrin(...)`; `postrin(...)` on this line is rejected.
|
||||
|
||||
Passband comparators (`passband-count-lt-val`, `passband-count-gt-val`) belong on
|
||||
`pcloudAmbience(...)` itself, and both may appear together — `lt` drives the
|
||||
postrin path, `gt` drives the negtrin path. Intrinsic threshold params
|
||||
(`interest-*`, `distraction-*`, `stupefaction-*`/`stupefying-*`, `intolerable-*`)
|
||||
live inside `postrin(...)` / `negtrin(...)` segments attached to the same DAP
|
||||
line. See `docs/design/intrin-thresholds.md`.
|
||||
#### 2b. `pcloudDarkAmbience` (pairs with `postrin`)
|
||||
|
||||
**Syntax**:
|
||||
```
|
||||
+idev | avia0 | postrin(...) | pcloudDarkAmbience(passband-count-lt-val=8) | livoxGen1-pcloud() | livoxProto1(...) | 3JEDK380010Z39
|
||||
```
|
||||
|
||||
**Quale-Iface-API**: `pcloudDarkAmbience` — Requires exactly one
|
||||
`passband-count-lt-val` on its params. Rejects `passband-count-gt-val`. The
|
||||
stimframe stimspot is the count of per-frame slots whose average intensity
|
||||
falls below `passband-count-lt-val`. Scene is "too good, stay here" — pairs
|
||||
with `postrin(...)`; `negtrin(...)` on this line is rejected.
|
||||
|
||||
Intrinsic threshold params (`interest-*`, `distraction-*`,
|
||||
`stupefaction-*`/`stupefying-*`, `intolerable-*`) live inside `postrin(...)` /
|
||||
`negtrin(...)` segments on the same DAP line. See
|
||||
`docs/design/intrin-thresholds.md`.
|
||||
|
||||
### 3. Point Cloud Coordinate Data Device (Extrospector)
|
||||
|
||||
@@ -158,7 +178,8 @@ The `livoxProto1` provider accepts the following parameters:
|
||||
| Stim Feature | Stim-Buff-API | Quale-Iface-API | Description |
|
||||
|--------------|---------------|----------------|-------------|
|
||||
| Point Cloud Intensity | `livoxGen1-pcloudIntensity` | `pcloudIntensity` | Light intensity/reflectivity data |
|
||||
| Point Cloud Ambience | `livoxGen1-pcloud` | `pcloudAmbience` | Per-dagram average intensity vector (`float` × `n-dgrams-per-frame`). Accepts `postrin(...)` / `negtrin(...)` segments on the same DAP line for intrin thresholds; see `docs/design/intrin-thresholds.md`. |
|
||||
| Point Cloud Light Ambience | `livoxGen1-pcloud` | `pcloudLightAmbience` | One `uint32` per stimframe: count of slots whose average intensity exceeds `passband-count-gt-val`. Pairs with `negtrin(...)`; rejects `postrin(...)` and `passband-count-lt-val`. |
|
||||
| Point Cloud Dark Ambience | `livoxGen1-pcloud` | `pcloudDarkAmbience` | One `uint32` per stimframe: count of slots whose average intensity falls below `passband-count-lt-val`. Pairs with `postrin(...)`; rejects `negtrin(...)` and `passband-count-gt-val`. |
|
||||
| Point Cloud Coordinates | `livoxGen1-pcloud` | `pcloud` | Spatial coordinate data |
|
||||
| Gyroscope | `livoxGen1-gyro` | `gyro` | Angular velocity measurements |
|
||||
| Accelerometer | `livoxGen1-accel` | `accel` | Linear acceleration measurements |
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace smo {
|
||||
namespace device {
|
||||
|
||||
/* Carrier used by the DAP spec parser to pass one parenthesized segment
|
||||
* (e.g. postrin(interest-pc=85) or pcloudAmbience(...)) up the reduction
|
||||
* (e.g. postrin(interest-pc=85) or pcloudLightAmbience(...)) up the reduction
|
||||
* stack; the spec_body reduction classifies segments and populates the
|
||||
* DeviceAttachmentSpec. Defined here so both the parser header and consumers
|
||||
* of the generated header see the type.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user