3#include "ExtensionRegistry.h"
4#include "Services/TaskManager.h"
5#include "Components/Geometry/MarkerPointSetComponent.h"
6#include "Components/Core/SceneComponent.h"
8#include "../Components/DataRefComponent.h"
9#include "../Components/BeamGroupComponent.h"
10#include "../Tasks/dBToLinearTask.h"
11#include "../Tasks/OctProviderBuildTileTask.h"
13#include "OctProviderSystem.h"
14#include "DataSetSystem.h"
15#include "../BeamUtils.h"
16#include "../../../Volumetric/Source/Components/OctComponent.h"
18#include "Foundation/Logging/Logger.h"
28 std::shared_ptr<EchoSounder::OctProviderPersistent> persistent;
32 if (!persistent->needsLinearization.empty()) {
35 for (
auto * item : persistent->needsLinearization) {
36 assert(item->linear.size() == item->decibel.size());
38 task.overflowThreshold = std::numeric_limits<float>::quiet_NaN();
39 task.in = item->decibel.data();
40 task.out = item->linear.data();
41 task.N = item->linear.size();
42 context->
taskManager->enqueueChild(linearizeGroup, task);
43 item->linearized =
true;
49 for (
auto & it : persistent->pingCache) {
50 assert(it.second->linearized);
52 persistent->needsLinearization.clear();
56 for (
size_t i = 0; i < persistent->responses.size(); i++) {
58 if (persistent->responses[i]->regionKeys.empty())
continue;
63 persistent->tasksRunning =
false;
71 auto * persistent = providerData.persistent.get();
72 persistent->needsLinearization.clear();
75 if (persistent->tainted) {
76 for (
auto & it : persistent->pingCache) {
77 persistent->pingCacheUnused.push_back(std::move(it.second));
79 persistent->pingCache.clear();
82 if(persistent->responses.empty())
return;
86 persistent->groupCache.resize(providerData.sources.size());
87 for (
size_t s = 0; s < providerData.sources.size(); s++) {
88 auto source = providerData.sources[s];
91 assert(dataEntity !=
nullptr);
93 persistent->groupCache[s].dataId = uint32_t(dataEntity->getId());
94 persistent->groupCache[s].majorCount = grpComp->majorCount;
95 persistent->groupCache[s].minorCount = grpComp->minorCount;
96 persistent->groupCache[s].directionX = grpComp->directionX;
97 persistent->groupCache[s].directionY = grpComp->directionY;
98 persistent->groupCache[s].minDirectionX = grpComp->minDirectionX;
99 persistent->groupCache[s].maxDirectionX = grpComp->maxDirectionX;
100 persistent->groupCache[s].minDirectionY = grpComp->minDirectionY;
101 persistent->groupCache[s].maxDirectionY = grpComp->maxDirectionY;
102 persistent->groupCache[s].maxBeamWidthX = grpComp->maxBeamWidthX;
103 persistent->groupCache[s].maxBeamWidthY = grpComp->maxBeamWidthY;
108 for (
auto & it : persistent->pingCache) {
113 unsigned newSlices = 0;
114 unsigned recycledSlices = 0;
117 for (
auto * resp : persistent->responses) {
118 for (
auto & regionKey : resp->regionKeys) {
119 uint32_t sourceIndex, pingIndex;
120 EchoSounder::decodeKey2(sourceIndex, pingIndex, regionKey);
121 assert(sourceIndex < providerData.sources.size());
123 auto source = providerData.sources[sourceIndex];
126 uint64_t cacheKey = EchoSounder::encodeKey2(persistent->groupCache[sourceIndex].dataId, pingIndex);
127 auto it = persistent->pingCache.find(cacheKey);
128 if (it != persistent->pingCache.end()) {
132 std::unique_ptr<EchoSounder::CachedPing> entry;
133 if (!persistent->pingCacheUnused.empty()) {
134 entry = std::move(persistent->pingCacheUnused.back());
135 persistent->pingCacheUnused.pop_back();
139 entry = std::make_unique<EchoSounder::CachedPing>();
144 const auto & metaPing = buffer.metaPings[pingIndex];
146 entry->timestamp = buffer.timestamps[pingIndex];
147 entry->metaPing = metaPing;
148 entry->beamCount = config.beamCount;
149 entry->sampleCount = config.sampleCount;
150 entry->depthOffset = config.depthOffset;
151 entry->depthStep = config.depthStep;
152 entry->transducerAlpha = config.transducerAlpha;
153 entry->transducerOffset = config.transducerOffset;
156 entry->linearized =
false;
157 entry->decibel.resize(config.beamCount*config.sampleCount,
false);
158 std::memcpy(entry->decibel.data(), buffer.values.data() + pingIndex * config.beamCount * config.sampleCount,
sizeof(
float)*config.beamCount*config.sampleCount);
159 entry->bottomDepths.resize(config.beamCount,
false);
160 std::memcpy(entry->bottomDepths.data(), buffer.bottomDepths.data() + pingIndex * config.beamCount,
sizeof(
float)*config.beamCount);
161 entry->linear.resize(config.beamCount*config.sampleCount,
false);
162 persistent->needsLinearization.push_back(entry.get());
164 persistent->pingCache[cacheKey] = std::move(entry);
171 unsigned expiredSlices = 0;
172 for (
auto it = persistent->pingCache.begin(); it != persistent->pingCache.end(); ) {
173 if constexpr (
false && 10 < it->second->age) {
174 persistent->pingCacheUnused.push_back(std::move(it->second));
175 it = persistent->pingCache.erase(it);
184 for (
auto & it : persistent->pingCache) {
185 if (!it.second->linearized) {
187 for (
auto jt : persistent->needsLinearization) {
188 if (jt == it.second.get()) { found =
true;
break; }
190 assert(found &&
"ping is neither already linearized nor is queued for linearization.");
194 if (newSlices || expiredSlices) {
202 assert(providerData.callbackCount == 0);
204 auto * dataSystem = ExtensionRegistry::getExtensionSystem<EchoSounder::DataSetSystem>(context);
207 for (
auto & src : providerData.sources) {
209 if (!grpComp->sane) {
210 if (!src.sane) providerData.doFlush =
true;
216 if (src.grpGen != grpComp->gen) {
217 src.grpGen = grpComp->gen;
218 providerData.doFlush =
true;
222 if (providerData.doFlush) {
223 providerData.doFlush =
false;
224 providerData.persistent->tainted =
true;
225 for (
auto & src : providerData.sources) {
228 auto & dataData = dataSystem->getData(dataComp);
229 src.dataGen = dataData.dataGen - 1;
230 src.sliceBegin = dataData.persistent->buffer.sliceBegin;
234 LOG_DEBUG(logger,
"Performing flush");
235 octComp->clearAllRegions =
true;
236 octComp->setChanged();
239 providerData.mostRecentTimestamp = 0;
240 for (
size_t s = 0; s < providerData.sources.size(); s++) {
241 auto & src = providerData.sources[s];
243 if (!src.sane)
continue;
247 auto & dataData = dataSystem->getData(dataComp);
248 if (src.dataGen == dataData.dataGen)
continue;
250 const auto & config = dataData.persistent->config;
251 const auto & buffer = dataData.persistent->buffer;
253 if (0 < buffer.sliceCount) {
254 auto last = buffer.sliceBegin + buffer.sliceCount - 1;
255 last = std::min(last, last - config.capacity);
256 providerData.mostRecentTimestamp = std::max(providerData.mostRecentTimestamp,
257 uint64_t(buffer.timestamps[last]));
260 auto sliceCount = std::min(providerData.history, buffer.sliceCount);
261 auto sliceBegin = buffer.sliceBegin + buffer.sliceCount - sliceCount;
262 sliceBegin = std::min(sliceBegin, sliceBegin - config.capacity);
265 if (!providerData.doFlush) {
266 src.sliceBegin = std::min(src.sliceBegin, src.sliceBegin - config.capacity);
267 while (src.sliceBegin != sliceBegin) {
269 octComp->regionsToRemove.push_back(EchoSounder::encodeKey2(uint32_t(s), src.sliceBegin));
270 octComp->setChanged();
271 src.sliceBegin = std::min(src.sliceBegin + 1, src.sliceBegin + 1 - config.capacity);
272 src.sliceCount = std::max(1u, src.sliceCount) - 1u;
275 src.sliceBegin = sliceBegin;
279 for (; src.sliceCount < sliceCount; src.sliceCount++) {
280 auto slice = src.sliceCount + src.sliceBegin;
281 slice = std::min(slice, slice - config.capacity);
283 const auto & metaPing = buffer.metaPings[slice];
285 glm::vec3 minCorner, maxCorner;
286 EchoSounder::getAxisAlignedBoundingBox(minCorner, maxCorner,
287 metaPing.arrayOrientationGlobal,
288 metaPing.arrayPositionGlobal,
290 grpComp->minDirectionX, grpComp->maxDirectionX,
291 grpComp->minDirectionY, grpComp->maxDirectionY,
292 grpComp->minDistance, grpComp->maxDistance);
294 octComp->regionsToAdd.push_back(
Volumetric::Region{ EchoSounder::encodeKey2(uint32_t(s), slice), minCorner, maxCorner });
295 octComp->setChanged();
310 for (
auto & providerComp :
pool) {
311 auto & providerData = getData(&providerComp);
312 if (!providerData.persistent) {
313 providerData.persistent = std::make_shared<OctProviderPersistent>();
314 providerData.persistent->context =
context;
317 if (providerData.history != providerComp.history) {
318 providerData.history = providerComp.history;
319 providerData.doFlush =
true;
323 octComp->
valueMin = dBToLinear(providerComp.decibelMin);
324 octComp->valueMax = dBToLinear(providerComp.decibelMax);
325 octComp->source = Volumetric::OctSource::ValueAge;
326 octComp->alphaCallback.func = alphaCallback;
327 octComp->alphaCallback.data = &providerData;
331 LOG_DEBUG(logger,
"Repopulating list of providers");
332 providerData.sources.clear();
333 providerData.persistent->tainted =
true;
334 for (
auto child : sceneComp->children) {
339 providerData.doFlush =
true;
342 for (
auto & source : providerData.sources) {
345 providerData.callbackCount =
static_cast<unsigned>(providerData.sources.size());
351 auto & providerData = getData(providerComp);
352 assert(providerData.callbackCount != 0);
353 if (--providerData.callbackCount == 0) {
355 addAndRemoveRegions(context, providerComp, providerData);
359float Cogs::Core::EchoSounder::OctProviderSystem::alphaCallback(
void* data, uint64_t clientData)
361 const auto * providerData =
reinterpret_cast<OctProviderData*
>(data);
362 return float(10e-7*(providerData->mostRecentTimestamp - clientData));
367 auto * dataSystem = ExtensionRegistry::getExtensionSystem<DataSetSystem>(context);
369 for (
auto & providerComp : pool) {
370 auto & providerData = getData(&providerComp);
374 if(providerData.persistent->tasksRunning)
continue;
376 auto * persistent = providerData.persistent.get();
380 while (!providerData.persistent->responses.empty()) {
381 submitTileResponse->
call(octComp, std::move(persistent->responses.back()), persistent->tainted ==
false);
382 providerData.persistent->responses.pop_back();
388 assert(providerData.persistent->responses.empty());
389 providerData.persistent->taskCount.clear();
391 unsigned regionsPerTask = 1;
392 unsigned targetParallelism = 2*std::max(1u, std::thread::hardware_concurrency());
393 unsigned currentParallelism = 0;
394 for (
const auto reqTileKey : octComp->tileRequests) {
395 if (targetParallelism < currentParallelism)
break;
398 res = initTileResponse->callWithReturn(octComp, res, &reqTileKey);
402 LOG_WARNING(logger,
"Tile request with no regions.");
405 unsigned maxTasks = std::max(1u, std::min(targetParallelism, res->
N.z));
407 unsigned taskCount = std::max(1u, std::min(maxTasks,
408 ((
unsigned)res->
regionKeys.size() + regionsPerTask - 1u) / regionsPerTask));
410 providerData.persistent->responses.push_back(std::move(res));
411 providerData.persistent->taskCount.push_back(taskCount);
412 currentParallelism += taskCount;
415 populatePingCache(dataSystem, providerData);
417 persistent->tainted =
false;
418 persistent->tasksRunning =
true;
ComponentType * getComponent() const
Context * context
Pointer to the Context instance the system lives in.
void update()
Updates the system state to that of the current frame.
void preUpdate()
Run the pre-update method of the system.
ComponentPool< ComponentType > pool
Pool of components managed by the system.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
std::unique_ptr< class TaskManager > taskManager
TaskManager service instance.
Contains information on how the entity behaves in the scene.
std::vector< EntityPtr > children
Contains all child entities owned by this component.
static constexpr TaskQueueId ResourceQueue
Resource task queue.
Log implementation class.
void call(Class *object, Arg... arg) const
Call the method named name on the given object, with the given arguments.
static const Type & getType()
Get the Type of the given template argument.
const Method * getMethod(const Name &name) const
Get a pointer to the method with the given name.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
constexpr Log getLogger(const char(&name)[LEN]) noexcept
glm::uvec3 N
Number of samples expected along each dimension (total=N^3).
std::set< RegionKey > regionKeys
Regions present in that tile.