Cogs.Core
SinglePingIsoSurfacesTasks.cpp
1#include "Resources/MeshManager.h"
2#include "Platform/Instrumentation.h"
3#include "Resources/VertexFormats.h"
4#include "Context.h"
5
6#include "../Extensions/GeometryProcessing/GeometryProcessing.h"
7#include "../Extensions/IsoSurfaces/IsoSurfaces.h"
8
9#include "../Components/DataSetComponent.h"
10#include "../Components/PingIsoComponent.h"
11#include "../Components/BeamGroupComponent.h"
12#include "../Systems/PingIsoSystem.h"
13#include "../Systems/DataSetSystem.h"
14#include "../BeamUtils.h"
15#include "../BoundingBox.h"
16#include "dBToLinearTask.h"
17#include "DepthResampleTask.h"
18#include "BeamResampleTask.h"
19#include "SinglePingIsoSurfacesTasks.h"
20
21#include "Foundation/Logging/Logger.h"
22#include "Foundation/Memory/MemoryBuffer.h"
23#include "Foundation/Platform/Timer.h"
24
25#include <glm/gtc/type_ptr.hpp>
26
27using std::min;
28using std::max;
29using std::numeric_limits;
30using std::vector;
31
32using glm::vec2;
33using glm::vec3;
34using glm::ivec3;
35using glm::angleAxis;
36
37using namespace Cogs::Core;
38
40
41
42namespace {
43
44 const int taskSize_Linearize = 5000;
45 const int taskSize_ResampleDepth = 20;
46 const int taskSize_InterpolateDirs = 500;
47 const int taskSize_InterpolateMinor = 100;
48 const int taskSize_InterpolateMajor = 100;
49 const ivec3 taskSize_Classify = ivec3(32, 16, 16);
50 const int taskSize_PopCnt = 10000;
51 const int taskSize_ExtractVtx = 10000;
52 const int taskSize_ExtractIdx = 10000;
53 const int taskSize_Normals = 10000;
54 const int taskSize_BBox = 10000;
55
56 const size_t granularity = 1024;
57
58 int elapsed_Count = 0;
59 double elapsed_Total = 0.0;
60 double elapsed_Resample = 0.0;
61 double elapsed_Linearize = 0.0;
62 double elapsed_DepthResample = 0.0;
63 double elapsed_BeamResample = 0.0;
64 double elapsed_Analyze = 0.0;
65 double elapsed_Extract = 0.0;
66 double elapsed_Normals = 0.0;
67 double elapsed_SetupMesh = 0.0;
68 double elapsed_Store = 0.0;
69
70 Cogs::Logging::Log logger = Cogs::Logging::getLogger("EchoPingIsoTasks");
71
72 static const float factorA = (float)(log2(10.0) / 10.0);
73 static const float factorAe = (float)(log(10.0) / 10.0);
74 static const float scale_dB = 100.0f; // Constant added to dB value to utilize both positive and negative exponents.
75
76
77 template<typename T>
78 struct WrapFunctorPointer
79 {
80 T* pointer;
81
82 WrapFunctorPointer(T* pointer) : pointer(pointer) {}
83
84 void operator()() { (*pointer)(); }
85
86 };
87
88
89 struct VertexEmit
90 {
92 uint32_t* slicesToMerge = nullptr;
93 size_t slicesToMergeModulo = 0;
94 glm::vec3* P = nullptr;
95 glm::vec2* T = nullptr;
96 size_t vertexOffset = 0;
97 float linearThreshold = 0.f;
98 float normalizedLayer = 0.f;
99 float separation = 0.f;
100 ivec3 maxFieldIndex;
101
102 void operator()(int32_t index, ivec3 aSample, ivec3 bSample)
103 {
104 ivec3 I[2] = { aSample, bSample };
105
106 const size_t beamMinorCount = main->beamMinorCount;
107 const size_t sampleCount = main->sampleCount;
108
109 float linearValue[2];
110 vec3 positions[2];
111 for (int m = 0; m < 2; m++) {
112 ivec3 Ir = I[m];
113 ivec3 Ic = glm::clamp(Ir, ivec3(0), maxFieldIndex);
114
115 size_t linearIndex = (Ic.z*beamMinorCount + Ic.y)*sampleCount + Ic.x;
116
117 linearValue[m] = main->persistent->linearValues[linearIndex] - linearThreshold;
118
119 float depth = Ic.x*main->depthStep + main->depthOffset;
120 vec3 o = main->metaPing.arrayPositionVessel;
121 vec3 d = main->rayDir[Ic.z*beamMinorCount + Ic.y];
122 vec3 dd = d;
123
124 if (Ic.x != Ir.x) {
125 int signed_one = Ic.x - Ir.x < 0 ? -1 : 1;
126 depth = max(0.f, depth - separation * signed_one);
127 }
128
129 if (Ic.y != Ir.y) {
130 int signed_one = Ic.y - Ir.y < 0 ? -1 : 1;
131 // Verify that signed_one pushes the value inside the valid range
132 assert(0 <= Ic.y + signed_one);
133 assert(Ic.y + signed_one <= maxFieldIndex.y);
134 d += separation * glm::normalize(dd - main->rayDir[Ic.z * beamMinorCount + Ic.y + signed_one]);
135 }
136 if (Ic.z != Ir.z) {
137 int signed_one = Ic.z - Ir.z < 0 ? -1 : 1;
138 int ic_z = Ic.z + signed_one;
139 // Verify that signed_one pushes the value inside the valid range
140 assert(0 <= Ic.z + signed_one);
141 assert(Ic.z + signed_one <= maxFieldIndex.z);
142 d += separation * glm::normalize(dd - main->rayDir[ic_z * beamMinorCount + Ic.y]);
143 }
144
145 positions[m] = o + depth*d;
146 }
147
148 float den = (linearValue[1] - linearValue[0]);
149 float t = abs(den) < numeric_limits<float>::min() ? 0.5f : -linearValue[0] / den;
150
151 size_t vo = vertexOffset + index;
152 if (slicesToMerge && (I[0].y == I[1].y) && (I[0].y == 0 || I[0].y == maxFieldIndex.y)) {
153
154 // If we are wrapping along-Y (slicesToMerge != nullptr), and we're on a vertex that
155 // lies on an Y-side, record vertex index.
156
157 const size_t slice = (I[0].y == 0) ? 0 : 1;
158 const size_t axis = (I[0].x + 1 == I[1].x) ? 0 : 2;
159
160 assert((!axis && (I[0].z == I[1].z)) || ((I[0].z + 1 == I[1].z) && (I[0].x == I[1].x)));
161 assert((I[0].x + 1) <= sampleCount);
162
163 assert(0 <= I[0].z + 1);
164 assert(0 <= I[0].x + 1);
165 const size_t cell = (I[0].z + 1) * (sampleCount + 1) + (I[0].x + 1);
166 const size_t ix = cell * 4 + slice + axis;
167
168 assert(ix < slicesToMergeModulo);
169 assert(slicesToMerge[ix] == uint32_t(~0));
170
171 slicesToMerge[ix] = uint32_t(vo);
172 }
173 P[vo] = (1.f - t)*positions[0] + t*positions[1];
174 T[vo] = vec2(normalizedLayer, 0.5f);
175 }
176
177 void operator()(int32_t ixIndex, glm::ivec4* samples, const uint32_t ixN)
178 {
179 for (uint32_t k = 0; k < ixN; k++) {
180 this->operator()(ixIndex + k,
181 glm::ivec3(samples[0][0],
182 samples[1][0],
183 samples[2][0]),
184 glm::ivec3(samples[0][1 + k],
185 samples[1][1 + k],
186 samples[2][1 + k]));
187 }
188 }
189 };
190
191
192 struct VerticalMaskTask
193 {
195 const size_t a;
196 const size_t b;
197
198 VerticalMaskTask(EchoSounder::SinglePingIsoSurfacesMainTask* parent, size_t a, size_t b) : parent(parent), a(a), b(b) { }
199
200 void operator()()
201 {
202 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "VertMask");
203
204 const size_t minorCount = parent->beamMinorCount;
205 //const size_t majorCount = parent->beamMajorCount;
206 const size_t sampleCount = parent->sampleCount;
207 const float doff = parent->depthOffset;
208 const float dstp = parent->depthStep;
209 const float maxRange = doff + dstp*sampleCount;
210
211 float minVerticalDepth = std::isfinite(parent->minVerticalDepth) ? std::max(0.f, parent->minVerticalDepth) : 0.f;
212 float maxVerticalDepth = std::isfinite(parent->maxVerticalDepth) ? std::max(minVerticalDepth, parent->maxVerticalDepth) : 10000.f;
213
214 EchoSounder::clipVertical(parent->persistent->linearValues, a * minorCount * sampleCount,
215 parent->metaPing.arrayPositionVessel, parent->rayDir, a * minorCount,
216 minVerticalDepth, maxVerticalDepth,
217 parent->depthOffset, parent->depthStep, maxRange,
218 minorCount * (b - a), sampleCount);
219 }
220
221 };
222}
223
225{
227 const size_t majorIndexStart;
228 const size_t majorIndexEnd;
229
230 ClipToSeabedTask(EchoSounder::SinglePingIsoSurfacesMainTask* parent, size_t majorIndexStart, size_t majorIndexEnd) : parent(parent), majorIndexStart(majorIndexStart), majorIndexEnd(majorIndexEnd) { }
231
232 void operator()()
233 {
234 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "ClipToSeabedTask");
235
236 const size_t minorCount = parent->beamMinorCount;
237 //const size_t majorCount = parent->beamMajorCount;
238 const size_t sampleCount = parent->sampleCount;
239 const float depthOffset = parent->depthOffset;
240 const float depthStep = parent->depthStep;
241
242 auto & output = parent->persistent->linearValues;
243 for (size_t k = majorIndexStart; k < majorIndexEnd; k++) {
244 for (size_t j = 0; j < minorCount; j++) {
245
246 size_t out = (k*minorCount + j)*sampleCount;
247
248 auto bottomDepth = parent->depths[k*minorCount +j];
249 auto clipDist = bottomDepth - parent->seabedClipOffset;
250 auto N = (bottomDepth != 0.f && std::isfinite(parent->seabedClipOffset)) ? std::min(static_cast<size_t>(std::max(0.f, std::floor((clipDist - depthOffset) / depthStep))), sampleCount) : sampleCount;
251 for (size_t i = N; i < sampleCount; ++i) {
252 output[out + i] = 0.f;
253 }
254 }
255 }
256 }
257};
258
259EchoSounder::SinglePingIsoSurfacesMainTask::SinglePingIsoSurfacesMainTask(Context* context,
260 const PingIsoComponent* isoComp, const SinglePingIsoSurfacesData* isoData,
261 const BeamGroupComponent* groupComp,
262 const DataSetComponent* /*dataComp*/, const DataSetData* dataData)
263 :
264 persistent(isoData->persistent),
265 context(context),
266 index(isoData->index),
267 thresholds(isoData->thresholds),
268 flipOrientation(isoComp->flipOrientation),
269 beamMinorClosed(groupComp->minorClosed),
270 metaPing(dataData->persistent->buffer.metaPings[index]),
271 layers(static_cast<int>(isoData->thresholds.size())),
272 sampleCount(dataData->persistent->config.sampleCount),
273 coordSys(dataData->persistent->config.coordSys),
274 capSeparation(isoComp->capSeparation),
275 seabedClipOffset(isoData->seabedClipOffset),
276 depthOffset(dataData->persistent->config.depthOffset),
277 depthStep(dataData->persistent->config.depthStep),
278 logarithmicUnit(dataData->persistent->config.useDecibel),
279 depthStepResample(isoComp->depthSpacing),
280 beamStepResample(isoComp->beamSpacing),
281 maxBeamUpsample(isoComp->beamMaxUpsample),
282 overflowThreshold(isoComp->overflowThreshold),
283 minVerticalDepth(isoComp->minVerticalDepth),
284 maxVerticalDepth(isoComp->maxVerticalDepth)
285{
286 const auto srcMajNum = groupComp->majorCount;
287 const auto srcMinNum = groupComp->minorCount;
288
289 beamMajorCount = max(2u, srcMajNum);
290 beamMinorCount = max(2u, srcMinNum + (beamMinorClosed ? 1u : 0u));
291 beamCount = beamMajorCount*beamMinorCount;
292 persistent->values.resize(beamCount*sampleCount + beamMajorCount);
293 depths.resize(beamCount);
294
295 directionX.clear();
296 directionX.resize(beamCount);
297 directionY.clear();
298 directionY.resize(beamCount);
299
300 const auto & config = dataData->persistent->config;
301 auto * src = dataData->persistent->buffer.values.data() + index*static_cast<size_t>(dataData->persistent->config.beamCount*sampleCount);
302 for (uint32_t major = 0; major < beamMajorCount; major++) {
303 for (uint32_t minor = 0; minor < beamMinorCount; minor++) {
304
305 unsigned k = minor;
306 if (srcMinNum <= minor) {
307 if (beamMinorClosed) {
308 k -= srcMinNum;
309 }
310 else {
311 k = srcMinNum - 1;
312 }
313 }
314 const auto ixDst = major*(beamMinorCount) + minor;
315 const auto ixSrc = groupComp->beams[min(srcMajNum - 1, major)*beamMinorCount + k];
316
317 directionX[ixDst] = dataData->persistent->config.directionX[ixSrc];
318 directionY[ixDst] = dataData->persistent->config.directionY[ixSrc];
319 depths[ixDst] = dataData->persistent->buffer.bottomDepths[ixSrc];
320
321 memcpy(persistent->values.data() + sampleCount*ixDst, src + sampleCount*ixSrc, sizeof(float)*sampleCount);
322 }
323 }
324
325 if (srcMajNum == 1) {
326
327 unsigned srcMinNumPadded = srcMinNum + (beamMinorClosed ? 1u : 0u);
328
329 std::vector<uint32_t> beams(srcMinNumPadded);
330 for (unsigned i = 0; i < srcMinNum; i++) {
331 beams[i] = groupComp->beams[i];
332 }
333 if (beamMinorClosed) {
334 beams[srcMinNum] = beams[0];
335 }
336
337 inflateFans(directionX, directionY,
338 config.directionX, config.beamWidthX,
339 config.directionY, config.beamWidthY,
340 beams, groupComp->topology, srcMinNumPadded);
341
342 }
343}
344
345void EchoSounder::SinglePingIsoSurfacesMainTask::operator()()
346{
347 auto & tm = context->taskManager;
348
349 Timer timerTotal, timerPass;
350
351 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "EchoGridMain");
352 timerTotal.start();
353
354 {
355 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "PassResize1");
356 timerPass.start();
357
358 linearThresholds.resize(thresholds.size());
359 persistent->linearValues.resize(persistent->values.size());
360 if (depthStepResample != 0.0f) {
361 sampleCountResample = min(10000, static_cast<int>(floor((depthStep * sampleCount) / depthStepResample)));
362 persistent->tmpValues.resize(beamCount*sampleCountResample);
363 }
364
365 elapsed_Resample += timerPass.elapsedSeconds();
366 }
367
368 if (logarithmicUnit) {
369 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "PassLinearize");
370 timerPass.start();
371
372 auto group = context->taskManager->createGroup();
373
374 transform(thresholds.begin(), thresholds.end(), linearThresholds.begin(), dBToLinear);
375
376 size_t N = persistent->values.size();
377 for (size_t o = 0; o < N; o += taskSize_Linearize) {
378 dBToLinearTask task;
379 task.overflowThreshold = overflowThreshold;
380 task.in = persistent->values.data() + o;
381 task.out = persistent->linearValues.data() + o;
382 task.N = min(N, o + taskSize_Linearize) - o;
383 context->taskManager->enqueueChild(group, task);
384 }
385 context->taskManager->wait(group);
386 context->taskManager->destroy(group);
387
388 elapsed_Linearize += timerPass.elapsedSeconds();
389 }
390 else {
391 linearThresholds = thresholds;
392 persistent->linearValues.swap(persistent->values);
393 }
394
395
396 if (true) {
397 assert(directionX.size() == beamMajorCount*beamMinorCount);
398 assert(directionY.size() == beamMajorCount*beamMinorCount);
399
400 // Calculate ray directions.
401 int total = beamMajorCount*beamMinorCount;
402 rayDir.resize(total);
403 auto group = context->taskManager->createGroup();
404 for (int b = 0; b < total; b += taskSize_InterpolateDirs) {
405 context->taskManager->enqueueChild(group,
406 CalculateBeamDirectionsTask(rayDir.data(),
407 coordSys,
408 directionX.data(), directionY.data(),
409 beamMajorCount, beamMinorCount, metaPing.arrayOrientationVessel,
410 b, min(b + taskSize_InterpolateDirs, total)));
411 }
412 context->taskManager->wait(group);
413 context->taskManager->destroy(group);
414 }
415
416
417 if (std::isfinite(seabedClipOffset)) {
418 //clip againts bottom detection
419 int step = (beamMajorCount + 7) / 8; //just to divide task into subtask. Step is how many major beams that are treated in one task
420 auto group = context->taskManager->createGroup();
421
422 for (uint32_t b = 0; b < beamMajorCount; b += step) {
423 context->taskManager->enqueueChild(group,
424 ClipToSeabedTask(this,
425 b,
426 min(b + step, beamMajorCount)));
427
428 }
429 context->taskManager->wait(group);
430 context->taskManager->destroy(group);
431 }
432
433
434 // PASS: Resample along rays
435 if (depthStepResample != 0.0f) {
436 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "DepthResample");
437 timerPass.start();
438
439 auto depthResampleGroup = context->taskManager->createGroup();
440 for (uint32_t b = 0; b < beamCount; b += taskSize_ResampleDepth) {
441 context->taskManager->enqueueChild(depthResampleGroup, DepthResampleTask(persistent->tmpValues.data(),
442 depthStepResample,
443 sampleCountResample,
444 persistent->linearValues.data(),
445 depthStep,
446 sampleCount,
447 b, min(b + taskSize_ResampleDepth, beamCount)));
448 }
449 context->taskManager->wait(depthResampleGroup);
450 context->taskManager->destroy(depthResampleGroup);
451
452 persistent->linearValues.swap(persistent->tmpValues);
453 depthStep = depthStepResample;
454 sampleCount = sampleCountResample;
455
456 elapsed_DepthResample += timerPass.elapsedSeconds();
457 }
458
459 // PASS: Resample between beams
460 if(beamStepResample != 0.0f) {
461 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "BeamResample");
462 timerPass.start();
463
464 float angularStep = std::atan(beamStepResample / (depthOffset + sampleCount*depthStep));
465
466 std::vector<InterpolationSamplePos> iSamplesOut;
467 std::vector<InterpolationSamplePos> jSamplesOut;
468 SetupBeamFilter(iSamplesOut, jSamplesOut, rayDir,
469 angularStep, maxBeamUpsample,
470 beamMinorCount, beamMajorCount);
471
472 uint32_t beamMajorCountNew = static_cast<uint32_t>(jSamplesOut.size());
473 uint32_t beamMinorCountNew = static_cast<uint32_t>(iSamplesOut.size());
474
475 auto interpolateGroup1 = context->taskManager->createGroup();
476 int total = beamMajorCountNew*beamMinorCountNew;
477
478 // FIXME: Check if the following needs to be split into tasks.
479 std::vector<glm::vec3> rayDirNew(total);
480 for (uint32_t j = 0; j < beamMajorCountNew; j++) {
481 for (uint32_t i = 0; i < beamMinorCountNew; i++) {
482 const auto & d00 = rayDir[(jSamplesOut[j].i + 0)*beamMinorCount + (iSamplesOut[i].i + 0)];
483 const auto & d01 = rayDir[(jSamplesOut[j].i + 0)*beamMinorCount + (iSamplesOut[i].i + 1)];
484 const auto & d10 = rayDir[(jSamplesOut[j].i + 1)*beamMinorCount + (iSamplesOut[i].i + 0)];
485 const auto & d11 = rayDir[(jSamplesOut[j].i + 1)*beamMinorCount + (iSamplesOut[i].i + 1)];
486
487 // Bi-spherical linear interpolation
488 const auto t0 = iSamplesOut[i].t;
489 const auto G0 = std::acos(glm::dot(d00, d01));
490 const auto d0 = (1.f / std::sin(G0))*(std::sin(G0*(1.f - t0))*d00 + std::sin(G0*t0)*d01);
491
492 const auto G1 = std::acos(glm::dot(d10, d11));
493 const auto d1 = (1.f / std::sin(G1))*(std::sin(G1*(1.f - t0))*d10 + std::sin(G1*t0)*d11);
494
495 const auto G = std::acos(glm::dot(d0, d1));
496 const auto t = jSamplesOut[j].t;
497 const auto d = (1.f / std::sin(G))*(std::sin(G*(1.f - t))*d0 + std::sin(G*t)*d1);
498
499 rayDirNew[j*beamMinorCountNew + i] = d;
500 }
501 }
502 rayDir.swap(rayDirNew);
503
504 // Separable pass 1, interpolate values between minor beams.
505 persistent->tmpValues.resize(beamMajorCount * beamMinorCountNew * sampleCount);
506 total = beamMajorCount*beamMinorCountNew;
507 for (int b = 0; b < total; b += taskSize_InterpolateMinor) {
508 context->taskManager->enqueueChild(interpolateGroup1,
509 InterpolateBeamDataMinorTask(persistent->tmpValues.data(),
510 beamMajorCount, beamMinorCountNew, beamMinorCount, sampleCount,
511 persistent->linearValues.data(), iSamplesOut.data(),
512 b, min(b + taskSize_InterpolateMinor, total)));
513 }
514 context->taskManager->wait(interpolateGroup1);
515 context->taskManager->destroy(interpolateGroup1);
516
517 persistent->linearValues.swap(persistent->tmpValues);
518 beamMinorCount = beamMinorCountNew;
519
520 // Separable pass 2, interpolate values between major beams.
521 auto interpolateGroup2 = context->taskManager->createGroup();
522 persistent->tmpValues.resize(beamMajorCountNew * beamMinorCount * sampleCount);
523 total = beamMajorCountNew * beamMinorCount;
524 for (int b = 0; b < total; b += taskSize_InterpolateMajor) {
525 context->taskManager->enqueueChild(interpolateGroup2,
526 InterpolateBeamDataMajorTask(persistent->tmpValues.data(),
527 beamMajorCountNew, beamMinorCount, beamMinorCount, sampleCount,
528 persistent->linearValues.data(), jSamplesOut.data(),
529 b, min(b + taskSize_InterpolateMajor, total)));
530 }
531
532 context->taskManager->wait(interpolateGroup2);
533 context->taskManager->destroy(interpolateGroup2);
534 persistent->linearValues.swap(persistent->tmpValues);
535 beamMajorCount = beamMajorCountNew;
536
537 elapsed_BeamResample += timerPass.elapsedSeconds();
538 }
539
540
541 //not sure why clipping agains vertical depth is not done before resampling (we clip agains bottom before resampling), philipb
542 if (std::isfinite(minVerticalDepth) || std::isfinite(maxVerticalDepth)) {
543 // Mask according to vertical depth.
544 int step = (beamMajorCount + 7) / 8;
545 auto group = context->taskManager->createGroup();
546
547 for (uint32_t b = 0; b < beamMajorCount; b += step) {
548 context->taskManager->enqueueChild(group,
549 VerticalMaskTask(this,
550 b,
551 min(b + step, beamMajorCount)));
552
553 }
554 context->taskManager->wait(group);
555 context->taskManager->destroy(group);
556 }
557
558
559 timerPass.start();
560 ivec3 Ns(sampleCount, beamMinorCount, beamMajorCount);
561 persistent->volumeCases.resize(layers * Ns.x*Ns.y*Ns.z);
562 persistent->volumeOffsets.resize(persistent->volumeCases.size());
563 persistent->wallCases.resize(layers * 2 * (Ns.x*Ns.y + Ns.x*Ns.z + Ns.y*Ns.z));
564 persistent->wallOffsets.resize(persistent->wallCases.size());
565 elapsed_Resample += timerPass.elapsedSeconds();
566
567
568 ivec3 fieldDim(sampleCount, beamMinorCount, beamMajorCount);
569 ivec3 gridA(-1, beamMinorClosed ? 0 : -1, -1);
570 ivec3 gridB = fieldDim + ivec3(1, beamMinorClosed ? 0 : 1, 1);
571
572 const auto M = gridB - gridA;
573
574 vector<int32_t> cellOffsets;
575 TypedBuffer<uint8_t> activeCellCases;
576 TypedBuffer<int32_t> cellMap;
577 TypedBuffer<int32_t> activeCellVertexIndexOffsets;
578 TypedBuffer<int32_t> activeCellTriangleIndexOffsets;
579 TypedBuffer<int32_t> activeCellIndices;
581 std::vector<TaskId> tasks;
582
583
584 // Fire away initializing memory needed in vertexExtract.
585 TaskId initSlicesToMergeGroup = NoTask;
586 const size_t slicesToMergeModulo = beamMinorClosed ? 4 * (beamMajorCount + 1) * (sampleCount + 1) : 0;
587 TypedBuffer<uint32_t> slicesToMerge(layers* slicesToMergeModulo);
588 if (beamMinorClosed) {
589 initSlicesToMergeGroup = context->taskManager->createGroup();
590 const size_t chunk = std::max(slicesToMerge.size() / Threads::hardwareConcurrency(), 64 * granularity);
591 for (size_t i = 0; i < slicesToMerge.size(); i += chunk) {
592 size_t n = std::min(chunk, slicesToMerge.size() - i);
593 context->taskManager->enqueueChild(initSlicesToMergeGroup,
594 [ptr = slicesToMerge.data() + i, n]()
595 {
596 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "InitSlicesToMerge");
597 std::memset(ptr, ~0u, sizeof(uint32_t)* n);
598 });
599 }
600 }
601
602 // Analyze pass
603 {
604 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "Analyze");
605 timerPass.start();
606
607 analyze(context,
608 vertexOffsets, indexOffsets, cellOffsets,
609 cellMap,
610 activeCellCases,
611 activeCellVertexIndexOffsets,
612 activeCellTriangleIndexOffsets,
613 activeCellIndices,
614 activeCellIJK,
615 linearThresholds,
616 true,
617 persistent->linearValues.data(),
618 fieldDim, gridA, gridB,
619 nullptr);
620
621 elapsed_Analyze += timerPass.elapsedSeconds();
622 }
623
624 auto vertexCount = vertexOffsets.back();
625 auto indexCount = indexOffsets.back();
626
627 auto mesh = context->meshManager->createLocked();
628
629
630 // Initialize beamMinorClosed-remapping array
631 TaskId initIndexRemappingGroup = NoTask;
632 TypedBuffer<uint32_t> indexRemapping;
633 if (vertexCount && beamMinorClosed) {
634 initIndexRemappingGroup = context->taskManager->createGroup();
635 indexRemapping.resize(vertexCount, false);
636 const size_t chunk = std::max(indexRemapping.size() / Threads::hardwareConcurrency(), 64 * granularity);
637 for (size_t i = 0; i < indexRemapping.size(); i += chunk) {
638 size_t j = std::min(i + chunk, indexRemapping.size());
639 tm->enqueueChild(initIndexRemappingGroup,
640 [ptr = indexRemapping.data(), i, j]()
641 {
642 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "InitIndexRemapping");
643 for (size_t k = i; k < j; k++) {
644 ptr[k] = static_cast<uint32_t>(k);
645 }
646 });
647 }
648 }
649
650 // Wait for memory slicesToMerge is finished with initializion.
651 if (initSlicesToMergeGroup.isValid()) {
652 tm->wait(initSlicesToMergeGroup);
653 tm->destroy(initSlicesToMergeGroup);
654 }
655
656 if (0 < vertexCount) {
657 TypedBuffer<uint32_t> indices;
658 Geometry::BoundingBox bbox;
659
660 auto P = mesh->mapPositions(0, vertexCount+1); // TODO: Fix out of bound SSE access (+1)
661 auto N = mesh->map<vec3>(VertexDataType::Normals, VertexFormats::Norm3f, 0, vertexCount);
662 auto T = mesh->map<vec2>(VertexDataType::TexCoords0, VertexFormats::Tex2f, 0, vertexCount);
663
664 indices.resize(indexCount, false);
665
666
667
668 // PASS: Extract vertices and indices
669 {
670 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "Extract");
671 timerPass.start();
672
673 TaskId vertexExtractGroup = context->taskManager->createGroup();
674 for (size_t i = 0; i < layers; i++) {
675 VertexEmit vertexEmit;
676 vertexEmit.main = this;
677 vertexEmit.slicesToMerge = beamMinorClosed ? slicesToMerge.data() + i * slicesToMergeModulo : nullptr;
678 vertexEmit.slicesToMergeModulo = slicesToMergeModulo;
679 vertexEmit.vertexOffset = vertexOffsets[i];
680 vertexEmit.linearThreshold = linearThresholds[i];
681 vertexEmit.normalizedLayer = (i + 0.5f) / layers;
682 vertexEmit.maxFieldIndex = glm::max(ivec3(0), fieldDim - ivec3(1));
683 vertexEmit.P = P.data;
684 vertexEmit.T = T.data;
685 vertexEmit.separation = 2.f * capSeparation * (layers - i - 1); // Factor 2 is due to we put the vertex on edge midpoint.
686 extractVertices(context,
687 vertexExtractGroup,
688 IsoSurfaces::VertexEmitFunc(vertexEmit),
689 activeCellCases.data() + cellOffsets[i],
690 activeCellVertexIndexOffsets.data() + cellOffsets[i] + i,
691 activeCellIndices.data() + cellOffsets[i],
692 activeCellIJK.data() + cellOffsets[i],
693 cellOffsets[i + 1] - cellOffsets[i],
694 gridA, gridB,
695 nullptr);
696 }
697
698 TaskId indexExtractGroup = context->taskManager->createGroup();
699 for (size_t i = 0; i < layers; i++) {
700 Cogs::Core::IsoSurfaces::IndexEmitFunc emitter;
701 if (flipOrientation == true) {
702 emitter =
703 [vertexOffset = vertexOffsets[i],
704 indices = indices.data() + indexOffsets[i]]
705 (uint32_t ixIndex, glm::ivec3 /*cell*/, const uint32_t* cellIndices, const uint32_t ixN)
706 {
707 for (uint32_t k = 0; k < ixN; k += 3) {
708 indices[ixIndex + k + 0] = cellIndices[k + 0] + vertexOffset;
709 indices[ixIndex + k + 1] = cellIndices[k + 1] + vertexOffset;
710 indices[ixIndex + k + 2] = cellIndices[k + 2] + vertexOffset;
711 }
712 };
713 }
714 else {
715 emitter =
716 [vertexOffset = vertexOffsets[i],
717 indices = indices.data() + indexOffsets[i]]
718 (uint32_t ixIndex, glm::ivec3 /*cell*/, const uint32_t* cellIndices, const uint32_t ixN)
719 {
720 for (uint32_t k = 0; k < ixN; k += 3) {
721 indices[ixIndex + k + 0] = cellIndices[k + 0] + vertexOffset;
722 indices[ixIndex + k + 1] = cellIndices[k + 2] + vertexOffset;
723 indices[ixIndex + k + 2] = cellIndices[k + 1] + vertexOffset;
724 }
725 };
726 }
727 extractIndices(context,
728 indexExtractGroup,
729 emitter,
730 cellMap.data() + i * M.x*M.y*M.z,
731 activeCellCases.data() + cellOffsets[i],
732 activeCellVertexIndexOffsets.data() + cellOffsets[i] + i,
733 activeCellTriangleIndexOffsets.data() + cellOffsets[i] + i,
734 activeCellIndices.data() + cellOffsets[i],
735 activeCellIJK.data() + cellOffsets[i],
736 cellOffsets[i + 1] - cellOffsets[i],
737 gridA, gridB,
738 nullptr);
739
740 }
741 tm->wait(vertexExtractGroup);
742 tm->destroy(vertexExtractGroup);
743 if (initIndexRemappingGroup.isValid()) {
744 tm->wait(initIndexRemappingGroup);
745 tm->destroy(initIndexRemappingGroup);
746 }
747 if (beamMinorClosed) {
748 size_t NN = slicesToMerge.size() / 2;
749 const size_t chunk = std::max(NN / Threads::hardwareConcurrency(), 64 * granularity);
750
751 for (size_t i = 0; i < NN; i += chunk) {
752 size_t j = std::min(i + chunk, NN);
753 tm->enqueueChild(indexExtractGroup,
754 [&slicesToMerge, &indexRemapping, i, j]() {
755 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "SetIndexRemapping");
756 for (size_t k = i; k < j; k++) {
757 if ((slicesToMerge[2 * k + 0] != ~0u) && (slicesToMerge[2 * k + 1] != ~0u)) {
758 indexRemapping[slicesToMerge[2 * k + 1]] = slicesToMerge[2 * k + 0];
759 }
760 }
761 });
762 }
763 }
764
765 tm->wait(indexExtractGroup);
766 tm->destroy(indexExtractGroup);
767
768 elapsed_Extract += timerPass.elapsedSeconds();
769 }
770
771
772 if (beamMinorClosed) {
773 TaskId remapGroup = tm->createGroup();
774 const size_t NN = indexCount;
775 const size_t chunk = std::max(indexCount / Threads::hardwareConcurrency(), size_t(16 * granularity));
776 for (size_t i = 0; i < NN; i += chunk) {
777 size_t j = std::min(i + chunk, NN);
778 tm->enqueueChild(remapGroup,
779 [&indices, &indexRemapping, i, j]() {
780 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "DoIndexRemapping");
781 for (size_t k = i; k < j; k++) {
782 indices[k] = indexRemapping[indices[k]];
783 }
784 });
785 }
786 tm->wait(remapGroup);
787 tm->destroy(remapGroup);
788 }
789
790 // PASS: Normals and bounding box
791 {
792 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "NormalsBBox");
793 timerPass.start();
794
795 TaskId group = tm->createGroup();
796 tm->enqueueChild(group, [&]
797 {
798 auto * indicesPtr = indices.data();
799 GeometryProcessing::normalsFromIndexedTriangles(context,
800 reinterpret_cast<float*>(N.data), 3,
801 reinterpret_cast<const float*>(P.data), 3,
802 vertexOffsets.back(),
803 indicesPtr,
804 indexOffsets.back(),
805 taskSize_Normals);
806 });
807
808 tm->enqueueChild(group, [&]
809 {
810 bbox = Cogs::Geometry::makeEmptyBoundingBox<Cogs::Geometry::BoundingBox>();
811 includeInBBox(context,
812 bbox,
813 reinterpret_cast<const float*>(P.data), 3,
814 vertexOffsets.back(),
815 taskSize_BBox);
816 });
817
818 tm->wait(group);
819 tm->destroy(group);
820
821 elapsed_Normals += timerPass.elapsedSeconds();
822 }
823
824 // PASS: Setup mesh
825 {
826 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "SetupMesh");
827 timerPass.start();
828
829 //mesh->set(VertexDataType::Interleaved0, VertexFormats::Pos3fNorm3fTex2f, PNT.data(), PNT.data() + PNT.size());
830 //mesh->setCount(PNT.size());
831 mesh->setBounds(bbox);
832 mesh->setIndexData(indices.data(), indexOffsets.back());
833 auto subMeshes = mesh->mapSubMeshes(layers);
834 for (uint32_t l = 0; l < layers; l++) {
835 auto & subMesh = subMeshes[l];
836 subMesh.startIndex = indexOffsets[l];
837 subMesh.numIndexes = indexOffsets[l + 1] - indexOffsets[l];
838 subMesh.primitiveType = Cogs::PrimitiveType::TriangleList;
839 }
840 mesh->setMeshFlag(MeshFlags::ClockwiseWinding);
841
842 elapsed_SetupMesh += timerPass.elapsedSeconds();
843 }
844 }
845
846
847 // PASS: Store mesh.
848 {
849 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "Store");
850 timerPass.start();
851
852 std::lock_guard<std::mutex> lock(persistent->mutex);
853 persistent->values.clear();
854 persistent->linearValues.clear();
855 persistent->volumeCases.clear();
856 persistent->volumeOffsets.clear();
857 persistent->wallCases.clear();
858 persistent->wallOffsets.clear();
859 persistent->tmpValues.clear();
860 persistent->issuedMesh = mesh.getHandle();
861 persistent->issuedPosition = metaPing.vesselPositionGlobal;
862 persistent->issuedOrientation = metaPing.vesselOrientationGlobal;
863 persistent->runningTasks--;
864
865 elapsed_Store += timerPass.elapsedSeconds();
866 }
867
868 elapsed_Total += timerTotal.elapsedSeconds();
869 elapsed_Count++;
870
871#ifdef COGS_AUTO_PROFILE
872 if (2.0 < elapsed_Total) {
873 double total = elapsed_Total / elapsed_Count;
874 double resize = elapsed_Resample / elapsed_Count;
875 double linearize = elapsed_Linearize / elapsed_Count;
876 double depthResample = elapsed_DepthResample / elapsed_Count;
877 double beamResample = elapsed_BeamResample / elapsed_Count;
878 double analyze = elapsed_Analyze / elapsed_Count;
879 double extract = elapsed_Extract / elapsed_Count;
880 double normals = elapsed_Normals / elapsed_Count;
881 double setupmesh = elapsed_SetupMesh / elapsed_Count;
882 double store = elapsed_Store / elapsed_Count;
883 LOG_DEBUG(logger, "N=%d TOT=%.1f RS=%.1f L=%.1f DR=%.1f BR=%.1f A=%.1f E=%.1f N=%.3f M=%.1f S=%.1f",
884 elapsed_Count,
885 1000.0*total,
886 1000.0*resize,
887 1000.0*linearize,
888 1000.0*depthResample,
889 1000.0*beamResample,
890 1000.0*analyze,
891 1000.0*extract,
892 1000.0*normals,
893 1000.0*setupmesh,
894 1000.0*store);
895 elapsed_Count = 0;
896 elapsed_Total = 0.0;
897 elapsed_Resample = 0.0;
898 elapsed_Linearize = 0.0;
899 elapsed_DepthResample = 0.0;
900 elapsed_BeamResample = 0.0;
901 elapsed_Analyze = 0.0;
902 elapsed_Extract = 0.0;
903 elapsed_Normals = 0.0;
904 elapsed_SetupMesh = 0.0;
905 elapsed_Store = 0.0;
906 }
907#endif
908}
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
std::unique_ptr< class TaskManager > taskManager
TaskManager service instance.
Definition: Context.h:186
Log implementation class.
Definition: LogManager.h:139
Old timer class.
Definition: Timer.h:37
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
void COGSFOUNDATION_API log(const char *message, const char *source, const Category category, uint32_t errorNumber)
Logs the given message with source and category.
Definition: LogManager.cpp:306
@ ClockwiseWinding
The mesh uses clockwise winding order for it's triangles as opposed to the counter-clockwise default.
Definition: Mesh.h:63
Task id struct used to identify unique Task instances.
Definition: TaskManager.h:20
bool isValid() const
Check if the task id is valid.
Definition: TaskManager.h:29
@ TriangleList
List of triangles.
Definition: Common.h:116